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.
This commit is contained in:
R. Bernstein
2009-12-31 18:51:50 -05:00
parent 7e14578ffe
commit cf882cfd20
4 changed files with 118 additions and 13 deletions

View File

@@ -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 <rocky@gnu.org>
@@ -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);
}

View File

@@ -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;
/*!

View File

@@ -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);

View File

@@ -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);
}
}