/*
Copyright (C) 2011, 2014, 2017 Rocky Bernstein <rocky@gnu.org>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* Program to show drivers installed and capabilities of CD drives. */
#include "util.h"
#ifdef HAVE_STDIO_H
#include <stdio.h>
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include "getopt.h"
#include <cdio/cdio.h>
#include <cdio/mmc.h>
/* Used by `main' to communicate with `parse_opt'. And global options
*/
static struct arguments
{
uint32_t debug_level;
int version_only;
int silent;
source_image_t source_image;
} opts;
/* Configuration option codes */
enum {
OP_HANDLED,
OP_SOURCE_DEVICE,
OP_USAGE,
/* These are the remaining configuration options */
OP_VERSION,
};
/* Parse all options. */
static bool
parse_options (int argc, char *argv[])
{
int opt;
int rc = EXIT_FAILURE;
static const char helpText[] =
"Usage: %s [OPTION...]\n"
" -d, --debug=INT Set debugging to LEVEL\n"
" -i, --cdrom-device[=DEVICE] show only info about CD-ROM device\n"
" -q, --quiet Don't produce warning output\n"
" -V, --version display version and copyright information\n"
" and exit\n"
"\n"
"Help options:\n"
" -?, --help Show this help message\n"
" --usage Display brief usage message\n";
static const char usageText[] =
"Usage: %s [-d|--debug INT] [-i|--cdrom-device DEVICE] [-q|--quiet]\n"
" [-V|--version] [-?|--help] [--usage]\n";
static const char optionsString[] = "d:i::qV?";
static const struct option optionsTable[] = {
{"debug", required_argument, NULL, 'd' },
{"cdrom-device", optional_argument, NULL, 'i' },
{"quiet", no_argument, NULL, 'q' },
{"version", no_argument, NULL, 'V' },
{"help", no_argument, NULL, '?' },
{"usage", no_argument, NULL, OP_USAGE },
{NULL, 0, NULL, 0 }
};
program_name = strrchr(argv[0],'/');
program_name = program_name ? strdup(program_name+1) : strdup(argv[0]);
while ((opt = getopt_long(argc, argv, optionsString, optionsTable, NULL)) != -1) {
switch (opt) {
case 'd':
opts.debug_level = atoi(optarg);
break;
case 'i':
if (opts.source_image != (source_image_t) DRIVER_UNKNOWN) {
/* NOTE: The libpopt version already set source_name by this time.
To restore this behavior, fall through to the else{} block.
*/
report( stderr, "%s: another source type option given before.\n",
program_name );
report( stderr, "%s: give only one source type option.\n",
program_name );
break;
} else {
opts.source_image = (source_image_t) DRIVER_DEVICE;
if (optarg != NULL) {
source_name = fillout_device_name(optarg);
}
break;
}
break;
case 'q':
opts.silent = 1;
break;
case 'V':
opts.version_only = 1;
break;
case '?':
fprintf(stdout, helpText, program_name);
rc = EXIT_INFO;
goto error_exit;
case OP_USAGE:
fprintf(stderr, usageText, program_name);
rc = EXIT_INFO;
goto error_exit;
case OP_HANDLED:
break;
default:
return false;
}
}
if (optind < argc) {
const char *remaining_arg = argv[optind++];
/* NOTE: A bug in the libpopt version checked source_image, which
rendered the subsequent source_image test useless.
*/
if (source_name != NULL) {
report( stderr, "%s: Source specified in option %s and as %s\n",
program_name, source_name, remaining_arg);
goto error_exit;
}
if (opts.source_image == (source_image_t) DRIVER_DEVICE)
source_name = fillout_device_name(remaining_arg);
else
source_name = strdup(remaining_arg);
if (optind < argc) {
report( stderr, "%s: Source specified in previously %s and %s\n",
program_name, source_name, remaining_arg);
goto error_exit;
}
}
return true;
error_exit:
if (source_name != NULL) {
free(source_name);
}
free(program_name);
exit(rc);
}
/* CDIO logging routines */
static void
_log_handler (cdio_log_level_t level, const char message[])
{
if (level == CDIO_LOG_DEBUG && opts.debug_level < 2)
return;
if (level == CDIO_LOG_INFO && opts.debug_level < 1)
return;
if (level == CDIO_LOG_WARN && opts.silent)
return;
gl_default_cdio_log_handler (level, message);
}
/*! Prints out SCSI-MMC drive features */
static void
print_mmc_drive_level(CdIo_t *p_cdio)
{
cdio_mmc_level_t mmc_level = mmc_get_drive_mmc_cap(p_cdio);
printf( "CD-ROM drive supports " );
switch(mmc_level) {
case CDIO_MMC_LEVEL_WEIRD:
printf("some nonstandard or degenerate set of MMC\n");
break;
case CDIO_MMC_LEVEL_1:
printf("MMC 1\n");
break;
case CDIO_MMC_LEVEL_2:
printf("MMC 2\n");
break;
case CDIO_MMC_LEVEL_3:
printf("MMC 3\n");
break;
case CDIO_MMC_LEVEL_NONE:
printf("no MMC\n");
break;
}
printf("\n");
}
/* Initialize global variables. */
static void
init(void)
{
gl_default_cdio_log_handler = cdio_log_set_handler (_log_handler);
/* Default option values. */
opts.silent = false;
opts.debug_level = 0;
opts.source_image = (source_image_t) DRIVER_UNKNOWN;
}
int
main(int argc, char *argv[])
{
CdIo_t *p_cdio=NULL;
init();
/* Parse our arguments; every option seen by `parse_opt' will
be reflected in `arguments'. */
parse_options(argc, argv);
print_version(program_name, CDIO_VERSION, false, opts.version_only);
if (opts.debug_level == 3) {
cdio_loglevel_default = CDIO_LOG_INFO;
} else if (opts.debug_level >= 4) {
cdio_loglevel_default = CDIO_LOG_DEBUG;
}
if (NULL == source_name) {
char *default_device;
p_cdio = cdio_open (NULL, DRIVER_DEVICE);
if (NULL == p_cdio) {
printf("No loaded CD-ROM device accessible.\n");
} else {
default_device = cdio_get_default_device(p_cdio);
printf("The driver selected is %s\n", cdio_get_driver_name(p_cdio));
if (default_device) {
printf("The default device for this driver is %s\n", default_device);
}
free(default_device);
cdio_destroy(p_cdio);
p_cdio=NULL;
printf("\n");
}
}
/* Print out a drivers available */
{
const driver_id_t *driver_id_p;
printf("Drivers available...\n");
for (driver_id_p=cdio_drivers; *driver_id_p!=DRIVER_UNKNOWN; driver_id_p++)
if (cdio_have_driver(*driver_id_p)) {
printf(" %-35s\n", cdio_driver_describe(*driver_id_p));
}
printf("\n");
}
if (NULL == source_name) {
/* Print out a list of CD-drives */
char **ppsz_cdrives=NULL, **ppsz_cd;
driver_id_t driver_id = DRIVER_DEVICE;
ppsz_cdrives = cdio_get_devices_ret(&driver_id);
if (NULL != ppsz_cdrives)
for( ppsz_cd = ppsz_cdrives; *ppsz_cd != NULL; ppsz_cd++ ) {
cdio_drive_read_cap_t i_read_cap;
cdio_drive_write_cap_t i_write_cap;
cdio_drive_misc_cap_t i_misc_cap;
cdio_hwinfo_t hwinfo;
p_cdio = cdio_open(*ppsz_cd, driver_id);
print_mmc_drive_level(p_cdio);
printf("%28s: %s\n", "Drive", *ppsz_cd);
if (p_cdio) {
if (cdio_get_hwinfo(p_cdio, &hwinfo)) {
printf("%-28s: %s\n%-28s: %s\n%-28s: %s\n",
"Vendor" , hwinfo.psz_vendor,
"Model" , hwinfo.psz_model,
"Revision", hwinfo.psz_revision);
}
print_mmc_drive_features(p_cdio);
cdio_get_drive_cap(p_cdio, &i_read_cap, &i_write_cap,
&i_misc_cap);
print_drive_capabilities(i_read_cap, i_write_cap, i_misc_cap);
}
printf("\n");
if (p_cdio) cdio_destroy(p_cdio);
p_cdio = NULL;
}
cdio_free_device_list(ppsz_cdrives);
ppsz_cdrives = NULL;
} else {
/* Print CD-drive info for given source */
cdio_drive_read_cap_t i_read_cap;
cdio_drive_write_cap_t i_write_cap;
cdio_drive_misc_cap_t i_misc_cap;
cdio_hwinfo_t hwinfo;
printf("Drive %s\n", source_name);
p_cdio = cdio_open (source_name, DRIVER_UNKNOWN);
if (p_cdio) {
print_mmc_drive_level(p_cdio);
if (cdio_get_hwinfo(p_cdio, &hwinfo)) {
printf("%-28s: %s\n%-28s: %s\n%-28s: %s\n",
"Vendor" , hwinfo.psz_vendor,
"Model" , hwinfo.psz_model,
"Revision", hwinfo.psz_revision);
}
print_mmc_drive_features(p_cdio);
}
cdio_get_drive_cap_dev(source_name, &i_read_cap, &i_write_cap,
&i_misc_cap);
print_drive_capabilities(i_read_cap, i_write_cap, i_misc_cap);
printf("\n");
}
myexit(p_cdio, EXIT_SUCCESS);
/* Not reached:*/
return(EXIT_SUCCESS);
}