From 67051b0f710f7ffb39cd55e052f5864bbac59b15 Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 12 Jun 2003 04:46:27 +0000 Subject: [PATCH] Make GNU/Linux smarter about finding a default device -- code sort of from SDL. Better error checking all around. --- lib/_cdio_generic.c | 19 ++++- lib/_cdio_linux.c | 176 ++++++++++++++++++++++++++++++++++++++++++-- lib/cdio_private.h | 8 +- src/cd-info.c | 39 ++++++++-- 4 files changed, 225 insertions(+), 17 deletions(-) diff --git a/lib/_cdio_generic.c b/lib/_cdio_generic.c index a1e12a0b..c5f2b761 100644 --- a/lib/_cdio_generic.c +++ b/lib/_cdio_generic.c @@ -1,5 +1,5 @@ /* - $Id: _cdio_generic.c,v 1.9 2003/06/07 16:49:50 rocky Exp $ + $Id: _cdio_generic.c,v 1.10 2003/06/12 04:46:27 rocky Exp $ Copyright (C) 2001 Herbert Valerio Riedel Copyright (C) 2002,2003 Rocky Bernstein @@ -27,7 +27,7 @@ # include "config.h" #endif -static const char _rcsid[] = "$Id: _cdio_generic.c,v 1.9 2003/06/07 16:49:50 rocky Exp $"; +static const char _rcsid[] = "$Id: _cdio_generic.c,v 1.10 2003/06/12 04:46:27 rocky Exp $"; #include #include @@ -148,9 +148,22 @@ cdio_is_device_generic(const char *source_name) { struct stat buf; if (0 != stat(source_name, &buf)) { - cdio_error ("Can't get file status for %s:\n%s", source_name, + cdio_warn ("Can't get file status for %s:\n%s", source_name, strerror(errno)); return false; } return (S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode)); } + +/*! + Like above, but don't give a warning device doesn't exist. +*/ +bool +cdio_is_device_quiet_generic(const char *source_name) +{ + struct stat buf; + if (0 != stat(source_name, &buf)) { + return false; + } + return (S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode)); +} diff --git a/lib/_cdio_linux.c b/lib/_cdio_linux.c index 61a1f9fa..ac5f1e7f 100644 --- a/lib/_cdio_linux.c +++ b/lib/_cdio_linux.c @@ -1,5 +1,5 @@ /* - $Id: _cdio_linux.c,v 1.12 2003/05/16 07:18:27 rocky Exp $ + $Id: _cdio_linux.c,v 1.13 2003/06/12 04:46:27 rocky Exp $ Copyright (C) 2001 Herbert Valerio Riedel Copyright (C) 2002,2003 Rocky Bernstein @@ -27,7 +27,7 @@ # include "config.h" #endif -static const char _rcsid[] = "$Id: _cdio_linux.c,v 1.12 2003/05/16 07:18:27 rocky Exp $"; +static const char _rcsid[] = "$Id: _cdio_linux.c,v 1.13 2003/06/12 04:46:27 rocky Exp $"; #include @@ -36,8 +36,6 @@ static const char _rcsid[] = "$Id: _cdio_linux.c,v 1.12 2003/05/16 07:18:27 rock #include "cdio_assert.h" #include "cdio_private.h" -#define DEFAULT_CDIO_DEVICE "/dev/cdrom" - #ifdef HAVE_LINUX_CDROM #if defined(HAVE_LINUX_VERSION_H) @@ -56,6 +54,7 @@ static const char _rcsid[] = "$Id: _cdio_linux.c,v 1.12 2003/05/16 07:18:27 rock #include #include #include +#include #include #include @@ -88,6 +87,109 @@ typedef struct { } _img_private_t; +/* Some ioctl() errno values which occur when the tray is empty */ +#define ERRNO_TRAYEMPTY(errno) \ + ((errno == EIO) || (errno == ENOENT) || (errno == EINVAL)) + + +/* Check a drive to see if it is a CD-ROM + Return 1 if a CD-ROM. 0 if it exists but isn't a CD-ROM drive + and -1 if no device exists . +*/ +static int +cdio_is_cdrom(char *drive, char *mnttype) +{ + bool is_cd=false; + int cdfd; + struct cdrom_tochdr tochdr; + + /* If it doesn't exist, return -1 */ + if ( !cdio_is_device_quiet_generic(drive) ) { + return(false); + } + + /* If it does exist, verify that it's an available CD-ROM */ + cdfd = open(drive, (O_RDONLY|O_EXCL|O_NONBLOCK), 0); + if ( cdfd >= 0 ) { + if ( ioctl(cdfd, CDROMREADTOCHDR, &tochdr) != -1 ) { + is_cd = true; + } + close(cdfd); + } + /* Even if we can't read it, it might be mounted */ + else if ( mnttype && (strcmp(mnttype, "iso9660") == 0) ) { + is_cd = true; + } + return(is_cd); +} + +static char * +cdio_check_mounts(const char *mtab) +{ + FILE *mntfp; + struct mntent *mntent; + + mntfp = setmntent(mtab, "r"); + if ( mntfp != NULL ) { + char *tmp; + char *mnt_type; + char *mnt_dev; + + while ( (mntent=getmntent(mntfp)) != NULL ) { + mnt_type = malloc(strlen(mntent->mnt_type) + 1); + if (mnt_type == NULL) + continue; /* maybe you'll get lucky next time. */ + + mnt_dev = malloc(strlen(mntent->mnt_fsname) + 1); + if (mnt_dev == NULL) { + free(mnt_type); + continue; + } + + strcpy(mnt_type, mntent->mnt_type); + strcpy(mnt_dev, mntent->mnt_fsname); + + /* Handle "supermount" filesystem mounts */ + if ( strcmp(mnt_type, "supermount") == 0 ) { + tmp = strstr(mntent->mnt_opts, "fs="); + if ( tmp ) { + free(mnt_type); + mnt_type = strdup(tmp + strlen("fs=")); + if ( mnt_type ) { + tmp = strchr(mnt_type, ','); + if ( tmp ) { + *tmp = '\0'; + } + } + } + tmp = strstr(mntent->mnt_opts, "dev="); + if ( tmp ) { + free(mnt_dev); + mnt_dev = strdup(tmp + strlen("dev=")); + if ( mnt_dev ) { + tmp = strchr(mnt_dev, ','); + if ( tmp ) { + *tmp = '\0'; + } + } + } + } + if ( strcmp(mnt_type, "iso9660") == 0 ) { + if (cdio_is_cdrom(mnt_dev, mnt_type) > 0) { + free(mnt_dev); + free(mnt_type); + endmntent(mntfp); + return strdup(mnt_dev); + } + } + free(mnt_dev); + free(mnt_type); + } + endmntent(mntfp); + } + return NULL; +} + static int _set_bsize (int fd, unsigned int bsize) { @@ -766,7 +868,59 @@ _cdio_get_track_msf(void *user_data, track_t track_num, msf_t *msf) char * cdio_get_default_device_linux(void) { - return strdup(DEFAULT_CDIO_DEVICE); +#ifndef HAVE_LINUX_CDROM + return NULL; + +#else + /* checklist: /dev/cdrom, /dev/dvd /dev/hd?, /dev/scd? /dev/sr? */ + static char checklist1[][40] = { + {"cdrom"}, {"dvd"}, {""} + }; + static char checklist2[][40] = { + {"?a hd?"}, {"?0 scd?"}, {"?0 sr?"}, {""} + }; + unsigned int i; + char drive[40]; + int exists; + char *ret_drive; + + /* Scan the system for CD-ROM drives. + */ + for ( i=0; strlen(checklist1[i]) > 0; ++i ) { + sprintf(drive, "/dev/%s", checklist1[i]); + if ( (exists=cdio_is_cdrom(drive, NULL)) > 0 ) { + return strdup(drive); + } + } + + /* Now check the currently mounted CD drives */ + if (NULL != (ret_drive = cdio_check_mounts("/etc/mtab"))) + return ret_drive; + + /* Finally check possible mountable drives in /etc/fstab */ + if (NULL != (ret_drive = cdio_check_mounts("/etc/fstab"))) + return ret_drive; + + /* Scan the system for CD-ROM drives. + Not always 100% reliable, so use the USE_MNTENT code above first. + */ + for ( i=0; strlen(checklist2[i]) > 0; ++i ) { + unsigned int j; + char *insert; + exists = 1; + for ( j=checklist2[i][1]; exists; ++j ) { + sprintf(drive, "/dev/%s", &checklist2[i][3]); + insert = strchr(drive, '?'); + if ( insert != NULL ) { + *insert = j; + } + if ( (exists=cdio_is_cdrom(drive, NULL)) > 0 ) { + return(strdup(drive)); + } + } + } + return NULL; +#endif /*HAVE_LINUX_CDROM*/ } /*! Initialization routine. This is the only thing that doesn't @@ -774,12 +928,13 @@ cdio_get_default_device_linux(void) ones to set that up. */ CdIo * -cdio_open_linux (const char *source_name) +cdio_open_linux (const char *orig_source_name) { #ifdef HAVE_LINUX_CDROM CdIo *ret; _img_private_t *_data; + char *source_name; cdio_funcs _funcs = { .eject_media = _cdio_eject_media, @@ -806,8 +961,13 @@ cdio_open_linux (const char *source_name) _data->gen.init = false; _data->gen.fd = -1; - _cdio_set_arg(_data, "source", (NULL == source_name) - ? DEFAULT_CDIO_DEVICE: source_name); + if (NULL == orig_source_name) { + source_name=cdio_get_default_device_linux(); + if (NULL == source_name) return NULL; + _cdio_set_arg(_data, "source", source_name); + free(source_name); + } else + _cdio_set_arg(_data, "source", orig_source_name); ret = cdio_new (_data, &_funcs); if (ret == NULL) return NULL; diff --git a/lib/cdio_private.h b/lib/cdio_private.h index 17246e58..234909fb 100644 --- a/lib/cdio_private.h +++ b/lib/cdio_private.h @@ -1,5 +1,5 @@ /* - $Id: cdio_private.h,v 1.9 2003/06/07 16:48:33 rocky Exp $ + $Id: cdio_private.h,v 1.10 2003/06/12 04:46:27 rocky Exp $ Copyright (C) 2003 Rocky Bernstein @@ -272,6 +272,12 @@ extern "C" { bool cdio_is_device_generic(const char *source_name); + /*! + Like above, but don't give a warning device doesn't exist. + */ + bool cdio_is_device_quiet_generic(const char *source_name); + + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/src/cd-info.c b/src/cd-info.c index df921f54..070280aa 100644 --- a/src/cd-info.c +++ b/src/cd-info.c @@ -1,5 +1,5 @@ /* - $Id: cd-info.c,v 1.11 2003/06/07 22:16:10 rocky Exp $ + $Id: cd-info.c,v 1.12 2003/06/12 04:46:27 rocky Exp $ Copyright (C) 2003 Rocky Bernstein Copyright (C) 1996,1997,1998 Gerd Knorr @@ -95,8 +95,9 @@ #endif #define err_exit(fmt, args...) \ - fprintf(stderr, "%s: "fmt, program_name, ##args); \ - myexit(EXIT_FAILURE) + { fprintf(stderr, "%s: "fmt, program_name, ##args); \ + myexit(EXIT_FAILURE); \ + } /* Subject: -65- How can I read an IRIX (EFS) CD-ROM on a machine which @@ -469,12 +470,17 @@ PARTICULAR PURPOSE.\n\ ")); if (version_only) { + char *default_device; for (driver_id=DRIVER_UNKNOWN+1; driver_id<=MAX_DRIVER; driver_id++) { if (cdio_have_driver(driver_id)) { printf("Have driver: %s\n", cdio_driver_describe(driver_id)); } } - printf("Default CD-ROM device: %s\n", cdio_get_default_device(NULL)); + default_device=cdio_get_default_device(NULL); + if (default_device) + printf("Default CD-ROM device: %s\n", default_device); + else + printf("No CD-ROM device found.\n"); exit(100); } @@ -1033,23 +1039,43 @@ main(int argc, const char *argv[]) case IMAGE_UNKNOWN: case IMAGE_AUTO: cdio = cdio_open (source_name, DRIVER_UNKNOWN); + if (cdio==NULL) { + err_exit("%s: Error in automatically selecting driver with input\n", + program_name); + } break; case IMAGE_DEVICE: cdio = cdio_open (source_name, DRIVER_DEVICE); + if (cdio==NULL) { + err_exit("%s: Error in automatically selecting device with input\n", + program_name); + } break; case IMAGE_BIN: cdio = cdio_open (source_name, DRIVER_BINCUE); + if (cdio==NULL) { + err_exit("%s: Error in opeing bin/cue\n", + program_name); + } break; case IMAGE_CUE: cdio = cdio_open_cue(source_name); + if (cdio==NULL) { + err_exit("%s: Error in opening cue/bin with input\n", + program_name); + } break; case IMAGE_NRG: cdio = cdio_open (source_name, DRIVER_NRG); + if (cdio==NULL) { + err_exit("%s: Error in opening NRG with input\n", + program_name); + } break; } if (cdio==NULL) { - err_exit("%s: Error in finding a usable device driver\n", program_name); + err_exit("%s: Error in opening device driver\n", program_name); } if (opts.debug_level > 0) { @@ -1058,6 +1084,9 @@ main(int argc, const char *argv[]) if (source_name==NULL) { source_name=strdup(cdio_get_arg(cdio, "source")); + if (NULL == source_name) { + err_exit("%s: No input device given/found\n", program_name); + } } first_track_num = cdio_get_first_track_num(cdio);