FreeBSD read/write and most-recent scsi sense access courtesy of Thomas Schmitt.
This commit is contained in:
6
NEWS
6
NEWS
@@ -1,8 +1,10 @@
|
|||||||
version 0.83 (git)
|
version 0.83 (git)
|
||||||
|
|
||||||
- Add Recording and retrieval of SCSI sense reply.
|
- Add retrieval SCSI sense reply from the most-recent MMC command.
|
||||||
- Add Write/burning interface.
|
- Add exclusive read/write access for devices which is used for experimental
|
||||||
|
writing/burning. Currently only on GNU/Linux and FreeBSD.
|
||||||
- MMC bug fixes
|
- MMC bug fixes
|
||||||
|
- FreeBSD drive list now shows empty drives.
|
||||||
- Add ability to retrieve SCSI tuple for a name and/or fake one up for
|
- Add ability to retrieve SCSI tuple for a name and/or fake one up for
|
||||||
programs that wanto to cd-record compatible.
|
programs that wanto to cd-record compatible.
|
||||||
- Tolerance for OS's without timezone in their struct tm (e.g. Solaris)
|
- Tolerance for OS's without timezone in their struct tm (e.g. Solaris)
|
||||||
|
|||||||
@@ -37,6 +37,19 @@ static const char _rcsid[] = "$Id: freebsd.c,v 1.38 2009/10/22 18:30:20 rocky Ex
|
|||||||
|
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
|
|
||||||
|
/* For freebsd_dev_lock() */
|
||||||
|
#include <sys/file.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_SYS_TYPES_H
|
||||||
|
# include <sys/types.h>
|
||||||
|
#endif
|
||||||
|
#ifdef _HAVE_SYS_STAT_H
|
||||||
|
# include <sys/stat.h>
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_FCNTL_H
|
||||||
|
# include <fcntl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <cdio/sector.h>
|
#include <cdio/sector.h>
|
||||||
|
|
||||||
static lba_t get_track_lba_freebsd(void *p_user_data, track_t i_track);
|
static lba_t get_track_lba_freebsd(void *p_user_data, track_t i_track);
|
||||||
@@ -52,10 +65,12 @@ str_to_access_mode_freebsd(const char *psz_access_mode)
|
|||||||
return _AM_IOCTL;
|
return _AM_IOCTL;
|
||||||
else if (!strcmp(psz_access_mode, "CAM"))
|
else if (!strcmp(psz_access_mode, "CAM"))
|
||||||
return _AM_CAM;
|
return _AM_CAM;
|
||||||
|
else if (!strcmp(psz_access_mode, "MMC_RDWR"))
|
||||||
|
return _AM_MMC_RDWR;
|
||||||
else if (!strcmp(psz_access_mode, "MMC_RDWR_EXCL"))
|
else if (!strcmp(psz_access_mode, "MMC_RDWR_EXCL"))
|
||||||
return _AM_MMC_RDWR_EXCL;
|
return _AM_MMC_RDWR_EXCL;
|
||||||
else {
|
else {
|
||||||
cdio_warn ("unknown access type: %s. Default ioctl used.",
|
cdio_warn ("unknown access type: %s. Default used.",
|
||||||
psz_access_mode);
|
psz_access_mode);
|
||||||
return default_access_mode;
|
return default_access_mode;
|
||||||
}
|
}
|
||||||
@@ -72,6 +87,7 @@ free_freebsd (void *p_obj)
|
|||||||
|
|
||||||
switch (p_env->access_mode) {
|
switch (p_env->access_mode) {
|
||||||
case _AM_CAM:
|
case _AM_CAM:
|
||||||
|
case _AM_MMC_RDWR:
|
||||||
case _AM_MMC_RDWR_EXCL:
|
case _AM_MMC_RDWR_EXCL:
|
||||||
free_freebsd_cam(p_env);
|
free_freebsd_cam(p_env);
|
||||||
break;
|
break;
|
||||||
@@ -104,6 +120,7 @@ read_audio_sectors_freebsd (void *p_user_data, void *p_buf, lsn_t i_lsn,
|
|||||||
_img_private_t *p_env = p_user_data;
|
_img_private_t *p_env = p_user_data;
|
||||||
switch (p_env->access_mode) {
|
switch (p_env->access_mode) {
|
||||||
case _AM_CAM:
|
case _AM_CAM:
|
||||||
|
case _AM_MMC_RDWR:
|
||||||
case _AM_MMC_RDWR_EXCL:
|
case _AM_MMC_RDWR_EXCL:
|
||||||
return mmc_read_sectors( p_env->gen.cdio, p_buf, i_lsn,
|
return mmc_read_sectors( p_env->gen.cdio, p_buf, i_lsn,
|
||||||
CDIO_MMC_READ_TYPE_CDDA, i_blocks);
|
CDIO_MMC_READ_TYPE_CDDA, i_blocks);
|
||||||
@@ -129,6 +146,7 @@ read_mode2_sector_freebsd (void *p_user_data, void *data, lsn_t i_lsn,
|
|||||||
|
|
||||||
switch (p_env->access_mode) {
|
switch (p_env->access_mode) {
|
||||||
case _AM_CAM:
|
case _AM_CAM:
|
||||||
|
case _AM_MMC_RDWR:
|
||||||
case _AM_MMC_RDWR_EXCL:
|
case _AM_MMC_RDWR_EXCL:
|
||||||
return read_mode2_sector_freebsd_cam(p_env, data, i_lsn, b_form2);
|
return read_mode2_sector_freebsd_cam(p_env, data, i_lsn, b_form2);
|
||||||
case _AM_IOCTL:
|
case _AM_IOCTL:
|
||||||
@@ -151,6 +169,7 @@ read_mode2_sectors_freebsd (void *p_user_data, void *p_data, lsn_t i_lsn,
|
|||||||
_img_private_t *p_env = p_user_data;
|
_img_private_t *p_env = p_user_data;
|
||||||
|
|
||||||
if ( (p_env->access_mode == _AM_CAM ||
|
if ( (p_env->access_mode == _AM_CAM ||
|
||||||
|
p_env->access_mode == _AM_MMC_RDWR ||
|
||||||
p_env->access_mode == _AM_MMC_RDWR_EXCL)
|
p_env->access_mode == _AM_MMC_RDWR_EXCL)
|
||||||
&& b_form2 ) {
|
&& b_form2 ) {
|
||||||
/* We have a routine that covers this case without looping. */
|
/* We have a routine that covers this case without looping. */
|
||||||
@@ -184,6 +203,7 @@ get_disc_last_lsn_freebsd (void *p_obj)
|
|||||||
|
|
||||||
switch (p_env->access_mode) {
|
switch (p_env->access_mode) {
|
||||||
case _AM_CAM:
|
case _AM_CAM:
|
||||||
|
case _AM_MMC_RDWR:
|
||||||
case _AM_MMC_RDWR_EXCL:
|
case _AM_MMC_RDWR_EXCL:
|
||||||
return get_disc_last_lsn_mmc(p_env);
|
return get_disc_last_lsn_mmc(p_env);
|
||||||
case _AM_IOCTL:
|
case _AM_IOCTL:
|
||||||
@@ -455,6 +475,7 @@ eject_media_freebsd (void *p_user_data)
|
|||||||
|
|
||||||
switch (p_env->access_mode) {
|
switch (p_env->access_mode) {
|
||||||
case _AM_CAM:
|
case _AM_CAM:
|
||||||
|
case _AM_MMC_RDWR:
|
||||||
case _AM_MMC_RDWR_EXCL:
|
case _AM_MMC_RDWR_EXCL:
|
||||||
return eject_media_freebsd_cam(p_env);
|
return eject_media_freebsd_cam(p_env);
|
||||||
case _AM_IOCTL:
|
case _AM_IOCTL:
|
||||||
@@ -479,6 +500,63 @@ audio_stop_freebsd (void *p_user_data)
|
|||||||
return ioctl(p_env->gen.fd, CDIOCSTOP);
|
return ioctl(p_env->gen.fd, CDIOCSTOP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
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.
|
||||||
|
Channel has no meaning on FreeBSD. Expect it to be 0. It is only in
|
||||||
|
the text to avoid an unnecessary difference in format.
|
||||||
|
Bus and Host will always be the same.
|
||||||
|
To be accessed via cdio_get_arg("scsi-tuple-freebsd") or "scsi-tuple".
|
||||||
|
For simplicity the FreeBSD driver also replies on "scsi-tuple-linux".
|
||||||
|
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_freebsd(_img_private_t *env)
|
||||||
|
{
|
||||||
|
int bus_no = -1, host_no = -1, channel_no = -1, target_no = -1, lun_no = -1;
|
||||||
|
int ret;
|
||||||
|
char tuple[160];
|
||||||
|
|
||||||
|
ret = obtain_scsi_adr_freebsd_cam(env->gen.source_name,
|
||||||
|
&bus_no, &host_no, &channel_no,
|
||||||
|
&target_no, &lun_no);
|
||||||
|
if (ret != 1)
|
||||||
|
return 0;
|
||||||
|
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) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
is_mmc_supported(void *user_data)
|
||||||
|
{
|
||||||
|
_img_private_t *env = user_data;
|
||||||
|
switch (env->access_mode) {
|
||||||
|
case _AM_IOCTL:
|
||||||
|
case _AM_NONE:
|
||||||
|
return false;
|
||||||
|
case _AM_CAM:
|
||||||
|
case _AM_MMC_RDWR:
|
||||||
|
case _AM_MMC_RDWR_EXCL:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/* Not reached. */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Return the value associated with the key "arg".
|
Return the value associated with the key "arg".
|
||||||
*/
|
*/
|
||||||
@@ -495,11 +573,19 @@ get_arg_freebsd (void *user_data, const char key[])
|
|||||||
return "ioctl";
|
return "ioctl";
|
||||||
case _AM_CAM:
|
case _AM_CAM:
|
||||||
return "CAM";
|
return "CAM";
|
||||||
|
case _AM_MMC_RDWR:
|
||||||
|
return "MMC_RDWR";
|
||||||
case _AM_MMC_RDWR_EXCL:
|
case _AM_MMC_RDWR_EXCL:
|
||||||
return "MMC_RDWR_EXCL";
|
return "MMC_RDWR_EXCL";
|
||||||
case _AM_NONE:
|
case _AM_NONE:
|
||||||
return "no access method";
|
return "no access method";
|
||||||
}
|
}
|
||||||
|
} else if (strcmp (key, "scsi-tuple") == 0) {
|
||||||
|
if (env->gen.scsi_tuple == NULL)
|
||||||
|
set_scsi_tuple_freebsd(env);
|
||||||
|
return env->gen.scsi_tuple;
|
||||||
|
} else if (!strcmp (key, "mmc-supported?")) {
|
||||||
|
is_mmc_supported(user_data) ? "true" : "false";
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -519,6 +605,7 @@ get_mcn_freebsd (const void *p_user_data) {
|
|||||||
|
|
||||||
switch (p_env->access_mode) {
|
switch (p_env->access_mode) {
|
||||||
case _AM_CAM:
|
case _AM_CAM:
|
||||||
|
case _AM_MMC_RDWR:
|
||||||
case _AM_MMC_RDWR_EXCL:
|
case _AM_MMC_RDWR_EXCL:
|
||||||
return mmc_get_mcn(p_env->gen.cdio);
|
return mmc_get_mcn(p_env->gen.cdio);
|
||||||
case _AM_IOCTL:
|
case _AM_IOCTL:
|
||||||
@@ -540,6 +627,7 @@ get_drive_cap_freebsd (const void *p_user_data,
|
|||||||
|
|
||||||
switch (p_env->access_mode) {
|
switch (p_env->access_mode) {
|
||||||
case _AM_CAM:
|
case _AM_CAM:
|
||||||
|
case _AM_MMC_RDWR:
|
||||||
case _AM_MMC_RDWR_EXCL:
|
case _AM_MMC_RDWR_EXCL:
|
||||||
get_drive_cap_mmc (p_user_data, p_read_cap, p_write_cap, p_misc_cap);
|
get_drive_cap_mmc (p_user_data, p_read_cap, p_write_cap, p_misc_cap);
|
||||||
case _AM_IOCTL:
|
case _AM_IOCTL:
|
||||||
@@ -571,12 +659,17 @@ run_mmc_cmd_freebsd( void *p_user_data, unsigned int i_timeout_ms,
|
|||||||
unsigned int i_buf, /*in/out*/ void *p_buf )
|
unsigned int i_buf, /*in/out*/ void *p_buf )
|
||||||
{
|
{
|
||||||
const _img_private_t *p_env = p_user_data;
|
const _img_private_t *p_env = p_user_data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
switch (p_env->access_mode) {
|
switch (p_env->access_mode) {
|
||||||
case _AM_CAM:
|
case _AM_CAM:
|
||||||
|
case _AM_MMC_RDWR:
|
||||||
case _AM_MMC_RDWR_EXCL:
|
case _AM_MMC_RDWR_EXCL:
|
||||||
return run_mmc_cmd_freebsd_cam( p_user_data, i_timeout_ms, i_cdb, p_cdb,
|
ret = run_mmc_cmd_freebsd_cam( p_user_data, i_timeout_ms, i_cdb, p_cdb,
|
||||||
e_direction, i_buf, p_buf );
|
e_direction, i_buf, p_buf );
|
||||||
|
if (ret != 0)
|
||||||
|
return DRIVER_OP_ERROR;
|
||||||
|
return 0;
|
||||||
case _AM_IOCTL:
|
case _AM_IOCTL:
|
||||||
return DRIVER_OP_UNSUPPORTED;
|
return DRIVER_OP_UNSUPPORTED;
|
||||||
case _AM_NONE:
|
case _AM_NONE:
|
||||||
@@ -680,7 +773,7 @@ cdio_get_devices_freebsd (void)
|
|||||||
char drive[40];
|
char drive[40];
|
||||||
char **drives = NULL;
|
char **drives = NULL;
|
||||||
unsigned int num_drives=0;
|
unsigned int num_drives=0;
|
||||||
bool exists=true;
|
bool exists = true, have_cam_drive = false;
|
||||||
char c;
|
char c;
|
||||||
|
|
||||||
/* Scan the system for CD-ROM drives.
|
/* Scan the system for CD-ROM drives.
|
||||||
@@ -705,15 +798,31 @@ cdio_get_devices_freebsd (void)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* Scan SCSI and CAM devices */
|
/* Scan SCSI and CAM devices */
|
||||||
|
exists = true;
|
||||||
for ( c='0'; exists && c <='9'; c++ ) {
|
for ( c='0'; exists && c <='9'; c++ ) {
|
||||||
sprintf(drive, "/dev/cd%c%s", c, DEVICE_POSTFIX);
|
sprintf(drive, "/dev/cd%c%s", c, DEVICE_POSTFIX);
|
||||||
exists = cdio_is_cdrom(drive, NULL);
|
exists = cdio_is_cdrom(drive, NULL);
|
||||||
if ( exists ) {
|
if ( exists ) {
|
||||||
cdio_add_device_list(&drives, drive, &num_drives);
|
cdio_add_device_list(&drives, drive, &num_drives);
|
||||||
|
have_cam_drive = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Scan are ATAPI devices */
|
/* Scan ATAPI devices */
|
||||||
|
|
||||||
|
/* ??? ts 9 Jan 2009
|
||||||
|
For now i assume atapicam running if a cdN device was found.
|
||||||
|
man atapicam strongly discourages to mix usage of CAM and ATAPI device.
|
||||||
|
So on the risk to sabotage systems without atapicam but with real old
|
||||||
|
SCSI drives, i list no ATAPI addresses if there was a CAM/SCSI address.
|
||||||
|
|
||||||
|
exists = !have_cam_drive;
|
||||||
|
|
||||||
|
ts 13 Jan 2009
|
||||||
|
Regrettably USB drives appear as SCSI drives. We rather need to determine
|
||||||
|
whether atapicam runs, or to make pairs of cd and acd.
|
||||||
|
|
||||||
|
*/
|
||||||
exists = true;
|
exists = true;
|
||||||
|
|
||||||
for ( c='0'; exists && c <='9'; c++ ) {
|
for ( c='0'; exists && c <='9'; c++ ) {
|
||||||
@@ -854,6 +963,108 @@ get_access_mode(const char *psz_source)
|
|||||||
}
|
}
|
||||||
return "CAM";
|
return "CAM";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Lock the inode associated to dev_fd and the inode associated to devname.
|
||||||
|
Return OS errno, number of pass device of dev_fd, locked fd to devname,
|
||||||
|
error message.
|
||||||
|
A return value of > 0 means success, <= 0 means failure.
|
||||||
|
*/
|
||||||
|
static int freebsd_dev_lock(int dev_fd, char *devname,
|
||||||
|
int *os_errno, int *pass_dev_no, int *lock_fd, char msg[4096],
|
||||||
|
int flag)
|
||||||
|
{
|
||||||
|
int lock_denied = 0, fd_stbuf_valid, name_stbuf_valid, i, pass_l = 100;
|
||||||
|
int max_retry = 3, tries;
|
||||||
|
struct stat fd_stbuf, name_stbuf;
|
||||||
|
char pass_name[16], *lock_name;
|
||||||
|
|
||||||
|
*os_errno = 0;
|
||||||
|
*pass_dev_no = -1;
|
||||||
|
*lock_fd = -1;
|
||||||
|
msg[0] = 0;
|
||||||
|
|
||||||
|
fd_stbuf_valid = !fstat(dev_fd, &fd_stbuf);
|
||||||
|
|
||||||
|
/* Try to find name of pass device by inode number */
|
||||||
|
lock_name = (char *) "effective device";
|
||||||
|
if(fd_stbuf_valid) {
|
||||||
|
for (i = 0; i < pass_l; i++) {
|
||||||
|
sprintf(pass_name, "/dev/pass%d", i);
|
||||||
|
if (stat(pass_name, &name_stbuf) != -1)
|
||||||
|
if(fd_stbuf.st_ino == name_stbuf.st_ino &&
|
||||||
|
fd_stbuf.st_dev == name_stbuf.st_dev)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (i < pass_l) {
|
||||||
|
lock_name = pass_name;
|
||||||
|
*pass_dev_no = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
name_stbuf_valid = !stat(devname, &name_stbuf);
|
||||||
|
for (tries= 0; tries <= max_retry; tries++) {
|
||||||
|
lock_denied = flock(dev_fd, LOCK_EX | LOCK_NB);
|
||||||
|
*os_errno = errno;
|
||||||
|
if (lock_denied) {
|
||||||
|
if (errno == EAGAIN && tries < max_retry) {
|
||||||
|
/* <<< debugging
|
||||||
|
fprintf(stderr, "\nlibcdio_DEBUG: EAGAIN , tries= %d\n", tries);
|
||||||
|
*/
|
||||||
|
usleep(2000000);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
sprintf(msg,
|
||||||
|
"Device busy. flock(LOCK_EX) failed on %s of %s",
|
||||||
|
strlen(lock_name) > 2000 || *pass_dev_no < 0 ?
|
||||||
|
"pass device" : lock_name,
|
||||||
|
strlen(devname) > 2000 ? "drive" : devname);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
fprintf(stderr, "libburn_DEBUG: flock obtained on %s of %s\n",
|
||||||
|
lock_name, devname);
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Eventually lock the official device node too */
|
||||||
|
if (fd_stbuf_valid && name_stbuf_valid &&
|
||||||
|
(fd_stbuf.st_ino != name_stbuf.st_ino ||
|
||||||
|
fd_stbuf.st_dev != name_stbuf.st_dev)) {
|
||||||
|
|
||||||
|
*lock_fd = open(devname, O_RDONLY);
|
||||||
|
if (*lock_fd == 0) {
|
||||||
|
close(*lock_fd);
|
||||||
|
*lock_fd = -1;
|
||||||
|
} if (*lock_fd > 0) {
|
||||||
|
for (tries = 0; tries <= max_retry; tries++) {
|
||||||
|
lock_denied = flock(*lock_fd, LOCK_EX | LOCK_NB);
|
||||||
|
if (lock_denied) {
|
||||||
|
if (errno == EAGAIN && tries < max_retry) {
|
||||||
|
usleep(2000000);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
close(*lock_fd);
|
||||||
|
*lock_fd = -1;
|
||||||
|
sprintf(msg, "Device busy. flock(LOCK_EX) failed on %s",
|
||||||
|
strlen(devname) > 4000 ? "drive" : devname);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
fprintf(stderr, "libburn_DEBUG: flock obtained on %s\n",
|
||||||
|
devname);
|
||||||
|
*/
|
||||||
|
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /*HAVE_FREEBSD_CDROM*/
|
#endif /*HAVE_FREEBSD_CDROM*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -882,6 +1093,7 @@ cdio_open_am_freebsd (const char *psz_orig_source_name,
|
|||||||
CdIo *ret;
|
CdIo *ret;
|
||||||
_img_private_t *_data;
|
_img_private_t *_data;
|
||||||
char *psz_source_name;
|
char *psz_source_name;
|
||||||
|
int open_access_mode; /* Access mode passed to cdio_generic_init. */
|
||||||
|
|
||||||
if (!psz_access_mode)
|
if (!psz_access_mode)
|
||||||
psz_access_mode = get_access_mode(psz_orig_source_name);
|
psz_access_mode = get_access_mode(psz_orig_source_name);
|
||||||
@@ -959,7 +1171,39 @@ cdio_open_am_freebsd (const char *psz_orig_source_name,
|
|||||||
ret = cdio_new ((void *)_data, &_funcs);
|
ret = cdio_new ((void *)_data, &_funcs);
|
||||||
if (ret == NULL) return NULL;
|
if (ret == NULL) return NULL;
|
||||||
|
|
||||||
if (cdio_generic_init(_data, O_RDONLY))
|
open_access_mode = 0;
|
||||||
|
if (_AM_MMC_RDWR == _data->access_mode) {
|
||||||
|
open_access_mode |= O_RDWR;
|
||||||
|
} else if (_AM_MMC_RDWR_EXCL == _data->access_mode) {
|
||||||
|
open_access_mode |= O_RDWR;
|
||||||
|
} else {
|
||||||
|
open_access_mode |= O_RDONLY;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
fprintf(stderr,
|
||||||
|
"libcdio_DEBUG: am = %d (MMC_RDWR_EXCL = %d), open = %d (O_RDWR = %d)\n",
|
||||||
|
_data->access_mode, _AM_MMC_RDWR_EXCL, open_access_mode, O_RDWR);
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (cdio_generic_init(_data, open_access_mode)) {
|
||||||
|
if (_AM_MMC_RDWR_EXCL == _data->access_mode) {
|
||||||
|
int os_errno, pass_dev_no = -1, flock_fd = -1, lock_result;
|
||||||
|
char msg[4096];
|
||||||
|
|
||||||
|
lock_result = freebsd_dev_lock(_data->gen.fd, _data->gen.source_name,
|
||||||
|
&os_errno, &pass_dev_no, &flock_fd, msg, 0);
|
||||||
|
if (lock_result <= 0) {
|
||||||
|
cdio_warn ("%s", msg);
|
||||||
|
cdio_generic_free (_data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/* One should rather keep this fd open until _data->gen.fd gets closed.
|
||||||
|
It eventually locks a device sibling of _data->gen.source_name.
|
||||||
|
*/
|
||||||
|
if (flock_fd > 0)
|
||||||
|
close(flock_fd);
|
||||||
|
}
|
||||||
|
|
||||||
if ( _data->access_mode == _AM_IOCTL ) {
|
if ( _data->access_mode == _AM_IOCTL ) {
|
||||||
return ret;
|
return ret;
|
||||||
} else {
|
} else {
|
||||||
@@ -970,7 +1214,7 @@ cdio_open_am_freebsd (const char *psz_orig_source_name,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
} else {
|
||||||
cdio_generic_free (_data);
|
cdio_generic_free (_data);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -114,6 +114,7 @@ typedef enum {
|
|||||||
_AM_NONE,
|
_AM_NONE,
|
||||||
_AM_IOCTL,
|
_AM_IOCTL,
|
||||||
_AM_CAM,
|
_AM_CAM,
|
||||||
|
_AM_MMC_RDWR,
|
||||||
_AM_MMC_RDWR_EXCL,
|
_AM_MMC_RDWR_EXCL,
|
||||||
} access_mode_t;
|
} access_mode_t;
|
||||||
|
|
||||||
@@ -212,7 +213,7 @@ bool read_toc_freebsd_ioctl (_img_private_t *env);
|
|||||||
|
|
||||||
Return 0 if no error.
|
Return 0 if no error.
|
||||||
*/
|
*/
|
||||||
int run_mmc_cmd_freebsd_cam( const void *p_user_data,
|
int run_mmc_cmd_freebsd_cam( void *p_user_data,
|
||||||
unsigned int i_timeout_ms,
|
unsigned int i_timeout_ms,
|
||||||
unsigned int i_cdb,
|
unsigned int i_cdb,
|
||||||
const mmc_cdb_t *p_cdb,
|
const mmc_cdb_t *p_cdb,
|
||||||
@@ -228,4 +229,12 @@ lsn_t get_disc_last_lsn_freebsd_ioctl (_img_private_t *_obj);
|
|||||||
bool init_freebsd_cam (_img_private_t *env);
|
bool init_freebsd_cam (_img_private_t *env);
|
||||||
void free_freebsd_cam (void *user_data);
|
void free_freebsd_cam (void *user_data);
|
||||||
|
|
||||||
|
/** Try to obtain SCSI address tuple of path.
|
||||||
|
@return 1 is success , 0 is failure
|
||||||
|
*/
|
||||||
|
int obtain_scsi_adr_freebsd_cam(char *path,
|
||||||
|
int *bus_no, int *host_no, int *channel_no,
|
||||||
|
int *target_no, int *lun_no);
|
||||||
|
|
||||||
|
|
||||||
#endif /*HAVE_FREEBSD_CDROM*/
|
#endif /*HAVE_FREEBSD_CDROM*/
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
$Id: freebsd_cam.c,v 1.12 2008/04/21 18:30:20 karl Exp $
|
Copyright (C) 2004, 2005, 2008, 2009, 2010 Rocky Bernstein <rocky@gnu.org>
|
||||||
|
|
||||||
Copyright (C) 2004, 2005, 2008, 2009 Rocky Bernstein <rocky@gnu.org>
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -52,16 +50,17 @@ static const char _rcsid[] = "$Id: freebsd_cam.c,v 1.12 2008/04/21 18:30:20 karl
|
|||||||
Return 0 if no error.
|
Return 0 if no error.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
run_mmc_cmd_freebsd_cam( const void *p_user_data, unsigned int i_timeout_ms,
|
run_mmc_cmd_freebsd_cam( void *p_user_data, unsigned int i_timeout_ms,
|
||||||
unsigned int i_cdb, const mmc_cdb_t *p_cdb,
|
unsigned int i_cdb, const mmc_cdb_t *p_cdb,
|
||||||
cdio_mmc_direction_t e_direction,
|
cdio_mmc_direction_t e_direction,
|
||||||
unsigned int i_buf, /*in/out*/ void *p_buf )
|
unsigned int i_buf, /*in/out*/ void *p_buf )
|
||||||
{
|
{
|
||||||
const _img_private_t *p_env = p_user_data;
|
_img_private_t *p_env = p_user_data;
|
||||||
int i_status;
|
int i_status, sense_size;
|
||||||
int direction = CAM_DEV_QFRZDIS;
|
int direction = CAM_DEV_QFRZDIS;
|
||||||
union ccb ccb;
|
union ccb ccb;
|
||||||
|
|
||||||
|
p_env->gen.scsi_mmc_sense_valid = 0;
|
||||||
if (!p_env || !p_env->cam) return -2;
|
if (!p_env || !p_env->cam) return -2;
|
||||||
|
|
||||||
memset(&ccb, 0, sizeof(ccb));
|
memset(&ccb, 0, sizeof(ccb));
|
||||||
@@ -71,6 +70,8 @@ run_mmc_cmd_freebsd_cam( const void *p_user_data, unsigned int i_timeout_ms,
|
|||||||
ccb.ccb_h.target_lun = p_env->cam->target_lun;
|
ccb.ccb_h.target_lun = p_env->cam->target_lun;
|
||||||
ccb.ccb_h.timeout = i_timeout_ms;
|
ccb.ccb_h.timeout = i_timeout_ms;
|
||||||
|
|
||||||
|
if (SCSI_MMC_DATA_NONE == e_direction)
|
||||||
|
i_buf = 0;
|
||||||
if (!i_buf)
|
if (!i_buf)
|
||||||
direction |= CAM_DIR_NONE;
|
direction |= CAM_DIR_NONE;
|
||||||
else
|
else
|
||||||
@@ -94,13 +95,28 @@ run_mmc_cmd_freebsd_cam( const void *p_user_data, unsigned int i_timeout_ms,
|
|||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Record SCSI sense reply for API call mmc_last_cmd_sense().
|
||||||
|
*/
|
||||||
|
sense_size = ccb.csio.sense_len;
|
||||||
|
if (sense_size > sizeof(p_env->gen.scsi_mmc_sense))
|
||||||
|
sense_size = sizeof(p_env->gen.scsi_mmc_sense);
|
||||||
|
memcpy((void *) p_env->gen.scsi_mmc_sense, &ccb.csio.sense_data, sense_size);
|
||||||
|
p_env->gen.scsi_mmc_sense_valid = sense_size;
|
||||||
|
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
i_status = ERRCODE(((unsigned char *)&ccb.csio.sense_data));
|
i_status = ERRCODE(((unsigned char *)&ccb.csio.sense_data));
|
||||||
if (i_status == 0)
|
if (i_status == 0)
|
||||||
i_status = -1;
|
i_status = -1;
|
||||||
else
|
else
|
||||||
CREAM_ON_ERRNO(((unsigned char *)&ccb.csio.sense_data));
|
CREAM_ON_ERRNO(((unsigned char *)&ccb.csio.sense_data));
|
||||||
cdio_warn ("transport failed: %d", i_status);
|
|
||||||
|
/* There are many harmless or intentional reasons why to get an SCSI
|
||||||
|
error condition. Higher levels should decide whether this is an incident
|
||||||
|
or just a normal outcome.
|
||||||
|
|
||||||
|
cdio_warn ("scsi error condition detected : 0x%X", i_status);
|
||||||
|
*/
|
||||||
return i_status;
|
return i_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,4 +273,243 @@ eject_media_freebsd_cam (_img_private_t *p_env)
|
|||||||
SCSI_MMC_DATA_WRITE, 0, &buf);
|
SCSI_MMC_DATA_WRITE, 0, &buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* This is a CAM based device enumerator.
|
||||||
|
Currently its only purpose is to eventually obtain the info needed for
|
||||||
|
cdio_get_arg("scsi-tuple")
|
||||||
|
*/
|
||||||
|
/* Stemming from code in libburn/sg-freebsd.c ,
|
||||||
|
originally contributed by Alexander Nedotsukov <bland@FreeBSD.org>,
|
||||||
|
without copyright claim to libburn in October 2006.
|
||||||
|
Contributed by libburn and adapted to libcdio without copyright claim
|
||||||
|
in January 2010.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct burn_drive_enumeration_state {
|
||||||
|
int fd;
|
||||||
|
union ccb ccb;
|
||||||
|
unsigned int i;
|
||||||
|
int skip_device;
|
||||||
|
};
|
||||||
|
typedef struct burn_drive_enumeration_state *burn_drive_enumerator_t;
|
||||||
|
|
||||||
|
|
||||||
|
/* Some helper functions for scsi_give_next_adr() */
|
||||||
|
|
||||||
|
static int sg_init_enumerator(burn_drive_enumerator_t *idx_)
|
||||||
|
{
|
||||||
|
struct burn_drive_enumeration_state *idx;
|
||||||
|
int bufsize;
|
||||||
|
|
||||||
|
idx = malloc(sizeof(*idx));
|
||||||
|
if (idx == NULL) {
|
||||||
|
cdio_warn("cannot malloc memory for CAM based drive enumerator");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
idx->skip_device = 0;
|
||||||
|
|
||||||
|
if ((idx->fd = open(XPT_DEVICE, O_RDWR)) == -1) {
|
||||||
|
cdio_warn("could not open %s (errno = %d \"%s\")",
|
||||||
|
XPT_DEVICE, errno, strerror(errno));
|
||||||
|
free(idx);
|
||||||
|
idx = NULL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bzero(&(idx->ccb), sizeof(union ccb));
|
||||||
|
|
||||||
|
idx->ccb.ccb_h.path_id = CAM_XPT_PATH_ID;
|
||||||
|
idx->ccb.ccb_h.target_id = CAM_TARGET_WILDCARD;
|
||||||
|
idx->ccb.ccb_h.target_lun = CAM_LUN_WILDCARD;
|
||||||
|
|
||||||
|
idx->ccb.ccb_h.func_code = XPT_DEV_MATCH;
|
||||||
|
bufsize = sizeof(struct dev_match_result) * 100;
|
||||||
|
idx->ccb.cdm.match_buf_len = bufsize;
|
||||||
|
idx->ccb.cdm.matches = (struct dev_match_result *)malloc(bufsize);
|
||||||
|
if (idx->ccb.cdm.matches == NULL) {
|
||||||
|
cdio_warn("cannot malloc memory for CAM enumerator matches");
|
||||||
|
close(idx->fd);
|
||||||
|
free(idx);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
idx->ccb.cdm.num_matches = 0;
|
||||||
|
idx->i = idx->ccb.cdm.num_matches; /* to trigger buffer load */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We fetch all nodes, since we display most of them in the default
|
||||||
|
* case, and all in the verbose case.
|
||||||
|
*/
|
||||||
|
idx->ccb.cdm.num_patterns = 0;
|
||||||
|
idx->ccb.cdm.pattern_buf_len = 0;
|
||||||
|
|
||||||
|
*idx_ = idx;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void sg_destroy_enumerator(burn_drive_enumerator_t *idx_)
|
||||||
|
{
|
||||||
|
struct burn_drive_enumeration_state *idx = *idx_;
|
||||||
|
|
||||||
|
if(idx->fd != -1)
|
||||||
|
close(idx->fd);
|
||||||
|
|
||||||
|
free(idx->ccb.cdm.matches);
|
||||||
|
free(idx);
|
||||||
|
|
||||||
|
*idx_ = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int sg_next_enumeration_buffer(burn_drive_enumerator_t *idx_)
|
||||||
|
{
|
||||||
|
struct burn_drive_enumeration_state *idx = *idx_;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We do the ioctl multiple times if necessary, in case there are
|
||||||
|
* more than 100 nodes in the EDT.
|
||||||
|
*/
|
||||||
|
if (ioctl(idx->fd, CAMIOCOMMAND, &(idx->ccb)) == -1) {
|
||||||
|
cdio_warn("error sending CAMIOCOMMAND ioctl, (errno = %d \"%s\")",
|
||||||
|
errno, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((idx->ccb.ccb_h.status != CAM_REQ_CMP)
|
||||||
|
|| ((idx->ccb.cdm.status != CAM_DEV_MATCH_LAST)
|
||||||
|
&& (idx->ccb.cdm.status != CAM_DEV_MATCH_MORE))) {
|
||||||
|
cdio_warn("got CAM error %#x, CDM error %d\n",
|
||||||
|
idx->ccb.ccb_h.status, idx->ccb.cdm.status);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Returns the next index object state and the next enumerated drive address.
|
||||||
|
@param idx An opaque handle. Make no own theories about it.
|
||||||
|
@param adr Takes the reply
|
||||||
|
@param adr_size Gives maximum size of reply including final 0
|
||||||
|
@param initialize 1 = start new,
|
||||||
|
0 = continue, use no other values for now
|
||||||
|
-1 = finish
|
||||||
|
@return 1 = reply is a valid address , 0 = no further address available
|
||||||
|
-1 = severe error (e.g. adr_size too small)
|
||||||
|
*/
|
||||||
|
/* This would be the public interface of the enumerator.
|
||||||
|
In libcdio it is private for now.
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
int give_next_adr_freebsd_cam(burn_drive_enumerator_t *idx_,
|
||||||
|
char adr[], int adr_size, int initialize)
|
||||||
|
{
|
||||||
|
struct burn_drive_enumeration_state *idx;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (initialize == 1) {
|
||||||
|
ret = sg_init_enumerator(idx_);
|
||||||
|
if (ret<=0)
|
||||||
|
return ret;
|
||||||
|
} else if (initialize == -1) {
|
||||||
|
sg_destroy_enumerator(idx_);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
idx = *idx_;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (idx->i >= idx->ccb.cdm.num_matches) {
|
||||||
|
ret = sg_next_enumeration_buffer(idx_);
|
||||||
|
if (ret<=0)
|
||||||
|
return -1;
|
||||||
|
idx->i = 0;
|
||||||
|
} else
|
||||||
|
(idx->i)++;
|
||||||
|
|
||||||
|
while (idx->i < idx->ccb.cdm.num_matches) {
|
||||||
|
switch (idx->ccb.cdm.matches[idx->i].type) {
|
||||||
|
case DEV_MATCH_BUS:
|
||||||
|
break;
|
||||||
|
case DEV_MATCH_DEVICE: {
|
||||||
|
struct device_match_result* result;
|
||||||
|
|
||||||
|
result = &(idx->ccb.cdm.matches[idx->i].result.device_result);
|
||||||
|
if (result->flags & DEV_RESULT_UNCONFIGURED)
|
||||||
|
idx->skip_device = 1;
|
||||||
|
else
|
||||||
|
idx->skip_device = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DEV_MATCH_PERIPH: {
|
||||||
|
struct periph_match_result* result;
|
||||||
|
|
||||||
|
result = &(idx->ccb.cdm.matches[idx->i].result.periph_result);
|
||||||
|
|
||||||
|
/* A specialized CD drive enumerator would have to test for
|
||||||
|
strcmp(result->periph_name, "cd") != 0
|
||||||
|
rather than
|
||||||
|
strcmp(result->periph_name, "pass") == 0
|
||||||
|
*/
|
||||||
|
if (idx->skip_device ||
|
||||||
|
strcmp(result->periph_name, "pass") == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
ret = snprintf(adr, adr_size, "/dev/%s%d",
|
||||||
|
result->periph_name, result->unit_number);
|
||||||
|
if(ret >= adr_size)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Found next enumerable address */
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
/* fprintf(stderr, "unknown match type\n"); */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
(idx->i)++;
|
||||||
|
}
|
||||||
|
} while ((idx->ccb.ccb_h.status == CAM_REQ_CMP)
|
||||||
|
&& (idx->ccb.cdm.status == CAM_DEV_MATCH_MORE));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Try to obtain SCSI address tuple of path.
|
||||||
|
@return 1 is success , 0 is failure
|
||||||
|
*/
|
||||||
|
int obtain_scsi_adr_freebsd_cam(char *path,
|
||||||
|
int *bus_no, int *host_no, int *channel_no,
|
||||||
|
int *target_no, int *lun_no)
|
||||||
|
{
|
||||||
|
burn_drive_enumerator_t idx;
|
||||||
|
int ret;
|
||||||
|
char buf[64];
|
||||||
|
struct periph_match_result* result;
|
||||||
|
|
||||||
|
ret = sg_init_enumerator(&idx);
|
||||||
|
if (ret <= 0)
|
||||||
|
return 0;
|
||||||
|
while(1) {
|
||||||
|
ret = give_next_adr_freebsd_cam(&idx, buf, sizeof(buf), 0);
|
||||||
|
if (ret <= 0)
|
||||||
|
break;
|
||||||
|
if (strcmp(path, buf) == 0) {
|
||||||
|
result = &(idx->ccb.cdm.matches[idx->i].result.periph_result);
|
||||||
|
*bus_no = result->path_id;
|
||||||
|
*host_no = result->path_id;
|
||||||
|
*channel_no = 0;
|
||||||
|
*target_no = result->target_id;
|
||||||
|
*lun_no = result->target_lun;
|
||||||
|
sg_destroy_enumerator(&idx);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sg_destroy_enumerator(&idx);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* HAVE_FREEBSD_CDROM */
|
#endif /* HAVE_FREEBSD_CDROM */
|
||||||
|
|||||||
@@ -48,6 +48,17 @@ cdio_is_cdrom_freebsd_ioctl(char *drive, char *mnttype)
|
|||||||
return(false);
|
return(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ts 13 Jan 2009
|
||||||
|
The ioctl below seems to be of little significance if one does not insist
|
||||||
|
in readable media.
|
||||||
|
Various of its failures are not caused by not being a CD drive
|
||||||
|
but by unreadable media situations. A burn program must handle these
|
||||||
|
situations rather than refusing to see the drive.
|
||||||
|
*/
|
||||||
|
return(true);
|
||||||
|
|
||||||
|
#ifndef Libcdio_on_freeBSD_unsuitable_code
|
||||||
|
|
||||||
/* If it does exist, verify that it's an available CD-ROM */
|
/* If it does exist, verify that it's an available CD-ROM */
|
||||||
cdfd = open(drive, (O_RDONLY|O_EXCL|O_NONBLOCK), 0);
|
cdfd = open(drive, (O_RDONLY|O_EXCL|O_NONBLOCK), 0);
|
||||||
|
|
||||||
@@ -56,16 +67,41 @@ cdio_is_cdrom_freebsd_ioctl(char *drive, char *mnttype)
|
|||||||
ENODEV means there's no drive present. */
|
ENODEV means there's no drive present. */
|
||||||
|
|
||||||
if ( cdfd >= 0 ) {
|
if ( cdfd >= 0 ) {
|
||||||
if ( ioctl(cdfd, CDIOREADTOCHEADER, &tochdr) != -1 ) {
|
int ret;
|
||||||
|
|
||||||
|
ret = ioctl(cdfd, CDIOREADTOCHEADER, &tochdr);
|
||||||
|
|
||||||
|
/*
|
||||||
|
fprintf(stderr, "libcdio_DEBUG: ioctl(\"%s\", (O_RDONLY|O_EXCL|O_NONBLOCK) = %d (errno= %d)\n", drive, ret, errno);
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ( ret != -1 ) {
|
||||||
|
is_cd = true;
|
||||||
|
} else if ( errno == ENXIO ) { /* Device not configured */
|
||||||
|
/* ts 9 Jan 2010 , FreeBSD 8.0
|
||||||
|
This error is issued with CAM device cd0 if no media is loaded.
|
||||||
|
*/
|
||||||
|
is_cd = true;
|
||||||
|
} else if ( errno == EIO ) { /* I/O error */
|
||||||
|
/* ts 9 Jan 2010 , FreeBSD 8.0
|
||||||
|
This error is issued with ATAPI device acd0 if no media is loaded.
|
||||||
|
*/
|
||||||
|
is_cd = true;
|
||||||
|
} else if ( errno == EINVAL ) { /* Invalid argument */
|
||||||
|
/* ts 13 Jan 2010 , FreeBSD 8.0
|
||||||
|
This error is issued with USB device cd1 if a blank CD-RW is loaded.
|
||||||
|
*/
|
||||||
is_cd = true;
|
is_cd = true;
|
||||||
}
|
}
|
||||||
close(cdfd);
|
close(cdfd);
|
||||||
}
|
} else if ( mnttype && (strcmp(mnttype, "iso9660") == 0) ) {
|
||||||
/* Even if we can't read it, it might be mounted */
|
/* Even if we can't read it, it might be mounted */
|
||||||
else if ( mnttype && (strcmp(mnttype, "iso9660") == 0) ) {
|
|
||||||
is_cd = true;
|
is_cd = true;
|
||||||
}
|
}
|
||||||
return(is_cd);
|
return(is_cd);
|
||||||
|
|
||||||
|
#endif /* Libcdio_on_freeBSD_unsuitable_codE */
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|||||||
@@ -387,8 +387,6 @@ get_arg_linux (void *env, const char key[])
|
|||||||
}
|
}
|
||||||
} else if (!strcmp (key, "scsi-tuple")) {
|
} else if (!strcmp (key, "scsi-tuple")) {
|
||||||
return _obj->gen.scsi_tuple;
|
return _obj->gen.scsi_tuple;
|
||||||
} else if (!strcmp (key, "scsi-tuple-linux")) {
|
|
||||||
return _obj->gen.scsi_tuple;
|
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -566,6 +566,10 @@ tmmc_test(char *drive_path, int flag)
|
|||||||
insufficient access mode "IOCTL" */
|
insufficient access mode "IOCTL" */
|
||||||
static int emul_lack_of_wperm = 0;
|
static int emul_lack_of_wperm = 0;
|
||||||
|
|
||||||
|
/* If non-0 then demand that cdio_get_arg(,"scsi-tuple") return non-NULL */
|
||||||
|
static int demand_scsi_tuple = 0;
|
||||||
|
|
||||||
|
const char *scsi_tuple;
|
||||||
|
|
||||||
old_log_level = cdio_loglevel_default;
|
old_log_level = cdio_loglevel_default;
|
||||||
verbose = flag & 1;
|
verbose = flag & 1;
|
||||||
@@ -589,6 +593,44 @@ tmmc_test(char *drive_path, int flag)
|
|||||||
*/
|
*/
|
||||||
cdio_loglevel_default = CDIO_LOG_WARN;
|
cdio_loglevel_default = CDIO_LOG_WARN;
|
||||||
|
|
||||||
|
/* Test availability of info for cdrecord style adresses .
|
||||||
|
*/
|
||||||
|
scsi_tuple = cdio_get_arg(p_cdio, "scsi-tuple");
|
||||||
|
if (scsi_tuple == NULL) {
|
||||||
|
if (demand_scsi_tuple) {
|
||||||
|
fprintf(stderr, "Error: cdio_get_arg(\"scsi-tuple\") returns NULL.\n");
|
||||||
|
{ret = 6; goto ex;}
|
||||||
|
} else if (flag & 1)
|
||||||
|
fprintf(stderr, "cdio_get_arg(\"scsi-tuple\") returns NULL.\n");
|
||||||
|
} else if (flag & 1)
|
||||||
|
printf("Drive '%s' has cdio_get_arg(\"scsi-tuple\") = '%s'\n",
|
||||||
|
drive_path, scsi_tuple);
|
||||||
|
|
||||||
|
|
||||||
|
/* Test availability of sense reply in case of unready drive.
|
||||||
|
E.g. if the tray is already ejected.
|
||||||
|
*/
|
||||||
|
ret = tmmc_test_unit_ready(p_cdio, &sense_avail, sense, !!verbose);
|
||||||
|
if (ret != 0 && sense_avail < 18) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"Error: Drive not ready. Only %d sense bytes. Expected >= 18.\n",
|
||||||
|
sense_avail);
|
||||||
|
{ret = 2; goto ex;}
|
||||||
|
}
|
||||||
|
/* Provoke sense reply by requesting inappropriate mode page 3Eh */
|
||||||
|
ret = tmmc_mode_sense(p_cdio, &sense_avail, sense,
|
||||||
|
0x3e, 0, alloc_len, buf, &buf_fill, !!verbose);
|
||||||
|
if (ret != 0 && sense_avail < 18) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"Error: Deliberately illegal command yields only %d sense bytes. Expected >= 18.\n",
|
||||||
|
sense_avail);
|
||||||
|
{ret = 2; goto ex;}
|
||||||
|
} else if(ret == 0) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"Warning: tmmc_mode_sense() cannot provoke failure by mode page 3Eh\n");
|
||||||
|
fprintf(stderr,
|
||||||
|
"Hint: Consider to set in tmmc_test(): with_tray_dance = 1\n");
|
||||||
|
}
|
||||||
|
|
||||||
/* Test availability of sense reply in case of unready drive.
|
/* Test availability of sense reply in case of unready drive.
|
||||||
E.g. if the tray is already ejected.
|
E.g. if the tray is already ejected.
|
||||||
@@ -687,6 +729,7 @@ ex:;
|
|||||||
int
|
int
|
||||||
main(int argc, const char *argv[])
|
main(int argc, const char *argv[])
|
||||||
{
|
{
|
||||||
|
const char *scsi_tuple;
|
||||||
CdIo_t *p_cdio;
|
CdIo_t *p_cdio;
|
||||||
char **ppsz_drives=NULL;
|
char **ppsz_drives=NULL;
|
||||||
const char *psz_source = NULL;
|
const char *psz_source = NULL;
|
||||||
@@ -705,6 +748,8 @@ main(int argc, const char *argv[])
|
|||||||
|
|
||||||
p_cdio = cdio_open(ppsz_drives[0], DRIVER_DEVICE);
|
p_cdio = cdio_open(ppsz_drives[0], DRIVER_DEVICE);
|
||||||
if (p_cdio) {
|
if (p_cdio) {
|
||||||
|
const char *psz_have_mmc = cdio_get_arg(p_cdio, "mmc-supported?");
|
||||||
|
|
||||||
psz_source = cdio_get_arg(p_cdio, "source");
|
psz_source = cdio_get_arg(p_cdio, "source");
|
||||||
if (0 != strncmp(psz_source, ppsz_drives[0],
|
if (0 != strncmp(psz_source, ppsz_drives[0],
|
||||||
strlen(ppsz_drives[0]))) {
|
strlen(ppsz_drives[0]))) {
|
||||||
@@ -713,19 +758,29 @@ main(int argc, const char *argv[])
|
|||||||
psz_source, ppsz_drives[0]);
|
psz_source, ppsz_drives[0]);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (psz_have_mmc && 0 == strncmp("true", psz_have_mmc, sizeof("true"))) {
|
||||||
|
scsi_tuple = cdio_get_arg(p_cdio, "scsi-tuple");
|
||||||
|
if (scsi_tuple == NULL) {
|
||||||
|
fprintf(stderr, "cdio_get_arg(\"scsi-tuple\") returns NULL.\n");
|
||||||
|
exit(3);
|
||||||
|
} else if (cdio_loglevel_default == CDIO_LOG_DEBUG)
|
||||||
|
printf("Drive '%s' has cdio_get_arg(\"scsi-tuple\") = '%s'\n",
|
||||||
|
psz_source, scsi_tuple);
|
||||||
|
|
||||||
|
/* Test the MMC enhancements of version 0.83 in december 2009 */
|
||||||
|
ret = tmmc_test(ppsz_drives[0],
|
||||||
|
cdio_loglevel_default == CDIO_LOG_DEBUG);
|
||||||
|
if (ret != 0) exit(ret + 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
cdio_destroy(p_cdio);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "cdio_open_linux('%s') failed\n", ppsz_drives[0]);
|
fprintf(stderr, "cdio_open('%s') failed\n", ppsz_drives[0]);
|
||||||
exit(2);
|
exit(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
cdio_destroy(p_cdio);
|
|
||||||
|
|
||||||
|
|
||||||
/* Test the MMC enhancements of version 0.83 in december 2009 */
|
|
||||||
ret = tmmc_test(ppsz_drives[0], cdio_loglevel_default == CDIO_LOG_DEBUG);
|
|
||||||
if (ret != 0)
|
|
||||||
exit(ret + 16);
|
|
||||||
|
|
||||||
cdio_free_device_list(ppsz_drives);
|
cdio_free_device_list(ppsz_drives);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user