From cf882cfd20912fed94d1a4a2e057bbcf68c496a1 Mon Sep 17 00:00:00 2001 From: "R. Bernstein" Date: Thu, 31 Dec 2009 18:51:50 -0500 Subject: [PATCH] Add ability to retrieve SCSI tuple for a name and/or fake one up. This helps programs that want to be cd-record compatible. In particular to parameters were added to cdio_get_arg, "scsi-tuple", and "scsi-tuple-linux". Code from Thomas Schmitt. --- lib/driver/_cdio_generic.c | 5 ++- lib/driver/generic.h | 10 +++++ lib/driver/gnu_linux.c | 76 ++++++++++++++++++++++++++++++++++++++ test/driver/gnu_linux.c | 40 ++++++++++++++------ 4 files changed, 118 insertions(+), 13 deletions(-) diff --git a/lib/driver/_cdio_generic.c b/lib/driver/_cdio_generic.c index beefee55..e70bc24e 100644 --- a/lib/driver/_cdio_generic.c +++ b/lib/driver/_cdio_generic.c @@ -1,6 +1,4 @@ /* - $Id: _cdio_generic.c,v 1.27 2008/04/22 15:29:11 karl Exp $ - Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Rocky Bernstein @@ -105,6 +103,9 @@ cdio_generic_free (void *p_user_data) if (p_env->fd >= 0) close (p_env->fd); + if (p_env->scsi_tuple != NULL) + free (p_env->scsi_tuple); + free (p_env); } diff --git a/lib/driver/generic.h b/lib/driver/generic.h index 96285fae..182cbd4d 100644 --- a/lib/driver/generic.h +++ b/lib/driver/generic.h @@ -74,6 +74,16 @@ extern "C" { but 263 bytes possible */ int scsi_mmc_sense_valid; /* Number of valid sense bytes */ + /* Memorized eventual system specific SCSI address tuple text. + Empty text means that there is no such text defined for the drive. + NULL means that the driver does not support "scsi-tuple". + To be read by cdio_get_arg("scsi-tuple"). + System specific suffixes to the key may demand and eventually + guarantee a further specified format. + E.g. "scsi-tuple-linux" guarantees either "Bus,Host,Channel,Target,Lun", + or empty text, or NULL. No other forms. + */ + char *scsi_tuple; } generic_img_private_t; /*! diff --git a/lib/driver/gnu_linux.c b/lib/driver/gnu_linux.c index 70c17007..765fdc0f 100644 --- a/lib/driver/gnu_linux.c +++ b/lib/driver/gnu_linux.c @@ -385,6 +385,10 @@ get_arg_linux (void *env, const char key[]) case _AM_NONE: return "no access method"; } + } else if (!strcmp (key, "scsi-tuple")) { + return _obj->gen.scsi_tuple; + } else if (!strcmp (key, "scsi-tuple-linux")) { + return _obj->gen.scsi_tuple; } return NULL; } @@ -1548,6 +1552,77 @@ close_tray_linux (const char *psz_device) #endif /*HAVE_LINUX_CDROM*/ } +/*! + Produce a text composed from the system SCSI address tuple according to + habits of Linux 2.4 and 2.6 : "Bus,Host,Channel,Target,Lun" and store + it in generic_img_private_t.scsi_tuple. + To be accessed via cdio_get_arg("scsi-tuple-linux") or ("scsi-tuple"). + Drivers which implement this code have to return 5 valid decimal numbers + separated by comma, or empty text if no such numbers are available. + @return 1=success , 0=failure +*/ +static int +set_scsi_tuple_linux(_img_private_t *env) +{ + int bus_no = -1, host_no = -1, channel_no = -1, target_no = -1, lun_no = -1; + int ret, i; + char tuple[160], hdx[10]; +#ifdef SCSI_IOCTL_GET_IDLUN + struct my_scsi_idlun { + int x; + int host_unique_id; + }; + struct my_scsi_idlun idlun; +#endif + struct stat stbuf, env_stbuf; + + /* Check whether this is a hdX and declare tuple unavailable. + /dev/hdX is traditionally for IDE drives and the ioctls here traditionally + return ok and all 0s for all IDE drives. So the tuples are no unique ids. + */ + if (fstat(env->gen.fd, &env_stbuf) == -1) + goto no_tuple; + strcpy(hdx, "/dev/hdX"); + for (i = 'a'; i <= 'z'; i++) { + hdx[7] = i; + if (stat(hdx, &stbuf) == -1) + continue; + if (env_stbuf.st_dev == stbuf.st_dev && env_stbuf.st_ino == stbuf.st_ino) + goto no_tuple; + } + +#ifdef SCSI_IOCTL_GET_BUS_NUMBER + if (ioctl(env->gen.fd, SCSI_IOCTL_GET_BUS_NUMBER, &bus_no) == -1) + bus_no = -1; +#endif + +#ifdef SCSI_IOCTL_GET_IDLUN + /* http://www.tldp.org/HOWTO/SCSI-Generic-HOWTO/scsi_g_idlun.html */ + + ret = ioctl(env->gen.fd, SCSI_IOCTL_GET_IDLUN, &idlun); + if (ret != -1) { + host_no= (idlun.x >> 24) & 255; + channel_no= (idlun.x >> 16) & 255; + target_no= (idlun.x) & 255; + lun_no= (idlun.x >> 8) & 255; + } +#endif + + if (env->gen.scsi_tuple != NULL) + free (env->gen.scsi_tuple); + env->gen.scsi_tuple = NULL; + if (bus_no < 0 || host_no < 0 || channel_no < 0 || target_no < 0 || + lun_no < 0) { +no_tuple:; + env->gen.scsi_tuple = strdup(""); + return 0; + } + sprintf(tuple, "%d,%d,%d,%d,%d", + bus_no, host_no, channel_no, target_no, lun_no); + env->gen.scsi_tuple = strdup(tuple); + return 1; +} + /*! Initialization routine. This is the only thing that doesn't get called via a function pointer. In fact *we* are the @@ -1685,6 +1760,7 @@ cdio_open_am_linux (const char *psz_orig_source, const char *access_mode) else open_access_mode |= O_RDONLY; if (cdio_generic_init(_data, open_access_mode)) { + set_scsi_tuple_linux(_data); return ret; } else { cdio_generic_free (_data); diff --git a/test/driver/gnu_linux.c b/test/driver/gnu_linux.c index f6d645b0..fee74306 100644 --- a/test/driver/gnu_linux.c +++ b/test/driver/gnu_linux.c @@ -43,7 +43,7 @@ main(int argc, const char *argv[]) cdio_loglevel_default = (argc > 1) ? CDIO_LOG_DEBUG : CDIO_LOG_INFO; /* snprintf(psz_nrgfile, sizeof(psz_nrgfile)-1, - "%s/%s", TEST_DIR, cue_file[i]); + "%s/%s", TEST_DIR, cue_file[i]); */ if (!cdio_have_driver(DRIVER_LINUX)) return(77); ppsz_drives = cdio_get_devices(DRIVER_DEVICE); @@ -56,14 +56,32 @@ main(int argc, const char *argv[]) if (p_cdio) { const char *psz_source = cdio_get_arg(p_cdio, "source"); if (0 != strncmp(psz_source, ppsz_drives[0], - strlen(ppsz_drives[0]))) { - fprintf(stderr, - "Got %s; should get back %s, the name we opened.\n", - psz_source, ppsz_drives[0]); - exit(1); + strlen(ppsz_drives[0]))) { + fprintf(stderr, + "Got %s; should get back %s, the name we opened.\n", + psz_source, ppsz_drives[0]); + exit(1); } } - + + { + const char *psz_source = NULL, *scsi_tuple, *scsi_tuple_linux; + + scsi_tuple_linux = cdio_get_arg(p_cdio, "scsi-tuple-linux"); + if (scsi_tuple_linux == NULL) { + fprintf(stderr, "cdio_get_arg(\"scsi-tuple-linux\") returns NULL.\n"); + exit(3); + } + scsi_tuple = cdio_get_arg(p_cdio, "scsi-tuple"); + if (scsi_tuple != scsi_tuple_linux) { + fprintf(stderr, + "cdio_get_arg(\"scsi-tuple\") differs from cdio_get_arg(\"scsi-tuple-linux\").\n"); + exit(4); + } + if (cdio_loglevel_default == CDIO_LOG_DEBUG) + printf("Drive '%s' has cdio_get_arg(\"scsi-tuple\") = '%s'\n", + psz_source, scsi_tuple); + } cdio_destroy(p_cdio); p_cdio = cdio_open_am_linux(ppsz_drives[0], "MMC_RDWR"); @@ -71,10 +89,10 @@ main(int argc, const char *argv[]) const char *psz_access_mode = cdio_get_arg(p_cdio, "access-mode"); if (0 != strncmp(psz_access_mode, "MMC_RDWR", strlen("MMC_RDWR"))) { - fprintf(stderr, - "Got %s; Should get back %s, the access mode requested.\n", - psz_access_mode, "MMC_RDWR"); - exit(2); + fprintf(stderr, + "Got %s; Should get back %s, the access mode requested.\n", + psz_access_mode, "MMC_RDWR"); + exit(2); } }