diff --git a/Makefile.am b/Makefile.am
index b0d4f19..8d9c87d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -203,10 +203,12 @@ EXTRA_DIST = \
libburn/os-freebsd.h \
libburn/os-linux.h \
libburn/os-libcdio.h \
+ libburn/os-solaris.h \
libburn/sg-dummy.c \
libburn/sg-freebsd.c \
libburn/sg-linux.c \
libburn/sg-libcdio.c \
+ libburn/sg-solaris.c \
COPYING \
NEWS \
ChangeLog \
diff --git a/README b/README
index 7fd4206..75fe376 100644
--- a/README
+++ b/README
@@ -105,8 +105,9 @@ The project comprises of several more or less interdependent parts which
together strive to be a usable foundation for application development.
These are libraries, language bindings, and middleware binaries which emulate
classical (and valuable) Linux tools.
-Currently it is supported on Linux with kernels >= 2.4 and on FreeBSD versions
-with ATAPI/CAM support enabled in the kernel, see atapicam(4).
+Currently it is supported on GNU/Linux with kernels >= 2.4,
+on FreeBSD with ATAPI/CAM enabled in the kernel (see man atapicam),
+and on OpenSolaris (tested with kernel 5.11).
On other X/Open compliant systems there will only be pseudo drives, but no
direct MMC operation on real CD/DVD/BD drives.
diff --git a/cdrskin/README b/cdrskin/README
index 55088b8..7c9fd1e 100644
--- a/cdrskin/README
+++ b/cdrskin/README
@@ -13,7 +13,8 @@ Copyright (C) 2006-2010 Thomas Schmitt, provided under GPL version 2 or later.
cdrskin is a limited cdrecord compatibility wrapper which allows to use
most of the libburn features from the command line.
-Currently it is supported on Linux with kernels >= 2.4 and on FreeBSD.
+Currently it is supported on GNU/Linux with kernels >= 2.4,
+on FreeBSD and on OpenSolaris.
IDE drives under Linux 2.4. need kernel module ide-scsi.
ATA and SATA drives under FreeBSD need kernel module atapicam.
On other X/Open compliant systems there will only be emulated drives, but no
diff --git a/cdrskin/cdrskin_eng.html b/cdrskin/cdrskin_eng.html
index dcc4b51..ed906f7 100644
--- a/cdrskin/cdrskin_eng.html
+++ b/cdrskin/cdrskin_eng.html
@@ -269,8 +269,9 @@ Bug fixes towards cdrskin-0.7.8.pl00:
Development snapshot, version 0.8.1 :
Enhancements towards current stable version 0.8.0.pl00:
-- none yet
+- A new system adapter allows to burn CD, DVD and BD on OpenSolaris
@@ -278,8 +279,14 @@ Bug fixes towards cdrskin-0.7.8.pl00:
Bug fixes towards cdrskin-0.8.0.pl00:
-- none yet
+-
+CD TOC was not read if the first track did not start at LBA 0
+
+-
+CD-ROM media got attributed random lead-in and lead-out adresses
+
diff --git a/cdrskin/cdrskin_timestamp.h b/cdrskin/cdrskin_timestamp.h
index 9f7f569..9929168 100644
--- a/cdrskin/cdrskin_timestamp.h
+++ b/cdrskin/cdrskin_timestamp.h
@@ -1 +1 @@
-#define Cdrskin_timestamP "2010.06.07.171706"
+#define Cdrskin_timestamP "2010.06.07.172925"
diff --git a/libburn/libdax_msgs.h b/libburn/libdax_msgs.h
index 061bd7c..1b34b85 100644
--- a/libburn/libdax_msgs.h
+++ b/libburn/libdax_msgs.h
@@ -434,6 +434,8 @@ Range "scdbackup" : 0x00020000 to 0x0002ffff
0x00020009 (SORRY,HIGH) = Neither stdio-path nor its directory exist
0x0002000a (FAILURE,HIGH) = Cannot accept '...' as SG_IO CDROM drive
0x0002000b (FAILURE,HIGH) = File object '...' not found
+ 0x0002000c (FAILURE,HIGH) = Cannot start device file enumeration
+ 0x0002000d (FAILURE,HIGH) = Cannot enumerate next device
General library operations:
diff --git a/libburn/os-solaris.h b/libburn/os-solaris.h
new file mode 100644
index 0000000..f0b1847
--- /dev/null
+++ b/libburn/os-solaris.h
@@ -0,0 +1,68 @@
+
+/* os-libcdio.h
+ Operating system specific libburn definitions and declarations. Included
+ by os.h in case of compilation for
+ Solaris based systems, e.g. SunOS 5.11
+ with Solaris uscsi MMC transport adapter sg-solaris.c
+
+ Copyright (C) 2010 Thomas Schmitt , provided under GPLv2+
+*/
+
+
+/** List of all signals which shall be caught by signal handlers and trigger
+ a graceful abort of libburn. (See man signal.h)
+*/
+/* Once as system defined macros */
+#define BURN_OS_SIGNAL_MACRO_LIST \
+ SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT, \
+ SIGFPE, SIGSEGV, SIGPIPE, SIGALRM, SIGTERM, \
+ SIGUSR1, SIGUSR2, SIGXCPU, SIGTSTP, SIGTTIN, \
+ SIGTTOU
+
+/* Once as text 1:1 list of strings for messages and interpreters */
+#define BURN_OS_SIGNAL_NAME_LIST \
+ "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", "SIGABRT", \
+ "SIGFPE", "SIGSEGV", "SIGPIPE", "SIGALRM", "SIGTERM", \
+ "SIGUSR1", "SIGUSR2", "SIGXCPU", "SIGTSTP", "SIGTTIN", \
+ "SIGTTOU"
+
+/* The number of above list items */
+#define BURN_OS_SIGNAL_COUNT 16
+
+/** To list all signals which shall surely not be caught */
+#define BURN_OS_NON_SIGNAL_MACRO_LIST \
+SIGKILL, SIGCHLD, SIGSTOP, SIGURG, SIGWINCH
+
+/* The number of above list items */
+#define BURN_OS_NON_SIGNAL_COUNT 5
+
+
+/* The maximum size for a (SCSI) i/o transaction */
+/* Important : MUST be at least 32768 ! */
+/* My Blu-ray burner LG GGW-H20 writes junk if stream recording is combined
+ with buffer size 32 kB. So stream recording is allowed only with size 64k.
+
+ >>> ??? is 64 kB ok for Solaris uscsi ?
+*/
+#define BURN_OS_TRANSPORT_BUFFER_SIZE 65536
+
+
+/* >>> */
+
+/* To hold the position of the most recently delivered address from
+ device enumeration.
+*/
+struct burn_drive_enumerator_struct {
+ void *dir;
+};
+
+#define BURN_OS_DEFINE_DRIVE_ENUMERATOR_T \
+typedef struct burn_drive_enumerator_struct burn_drive_enumerator_t;
+
+
+/* The list of operating system dependent elements in struct burn_drive.
+ Usually they are initialized in sg-*.c:enumerate_common().
+*/
+#define BURN_OS_TRANSPORT_DRIVE_ELEMENTS \
+ int fd;
+
diff --git a/libburn/os.h b/libburn/os.h
index 376650a..9fc6149 100644
--- a/libburn/os.h
+++ b/libburn/os.h
@@ -14,6 +14,14 @@
*/
+#ifdef Libburn_use_sg_dummY
+
+
+/* --------- Any other system. With dummy MMC transport sg-dummy.c --------- */
+#include "os-dummy.h"
+
+
+#else
#ifdef Libburn_use_libcdiO
@@ -45,6 +53,14 @@
#include "os-linux.h"
+#else
+#ifdef __sun
+
+
+/* ------- Solaris (e.g. SunOS 5.11) with uscsi ------ */
+#include "os-solaris.h"
+
+
#else
@@ -52,10 +68,12 @@
#include "os-dummy.h"
+#endif /* ! __sun*/
#endif /* ! __linux */
#endif /* ! __FreeBSD__kernel__ */
#endif /* ! __FreeBSD__ */
#endif /* ! Libburn_use_libcdiO */
+#endif /* ! Libburn_use_sg_dummY */
#endif /* ! BURN_OS_H_INCLUDED */
diff --git a/libburn/sg-solaris.c b/libburn/sg-solaris.c
new file mode 100644
index 0000000..784f565
--- /dev/null
+++ b/libburn/sg-solaris.c
@@ -0,0 +1,892 @@
+/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
+
+/*
+ Copyright (c) 2010 Thomas Schmitt
+ Provided under GPL version 2 or later.
+*/
+
+
+/*
+
+This is the main operating system dependent SCSI part of libburn. It implements
+the transport level aspects of SCSI control and command i/o.
+
+Present implementation: Solaris uscsi, e.g. for SunOS 5.11
+
+
+PORTING:
+
+Porting libburn typically will consist of adding a new operating system case
+to the following switcher files:
+ os.h Operating system specific libburn definitions and declarations.
+ sg.c Operating system dependent transport level modules.
+and of deriving the following system specific files from existing examples:
+ os-*.h Included by os.h. You will need some general system knowledge
+ about signals and knowledge about the storage object needs of your
+ transport level module sg-*.c.
+
+ sg-*.c This source module. You will need special system knowledge about
+ how to detect all potentially available drives, how to open them,
+ eventually how to exclusively reserve them, how to perform
+ SCSI transactions, how to inquire the (pseudo-)SCSI driver.
+ You will not need to care about CD burning, MMC or other high-level
+ SCSI aspects.
+
+Said sg-*.c operations are defined by a public function interface, which has
+to be implemented in a way that provides libburn with the desired services:
+
+sg_id_string() returns an id string of the SCSI transport adapter.
+ It may be called before initialization but then may
+ return only a preliminary id.
+
+sg_initialize() performs global initialization of the SCSI transport
+ adapter and eventually needed operating system
+ facilities. Checks for compatibility of supporting
+ software components.
+
+sg_shutdown() performs global finalizations and releases golbally
+ aquired resources.
+
+sg_give_next_adr() iterates over the set of potentially useful drive
+ address strings.
+
+scsi_enumerate_drives() brings all available, not-whitelist-banned, and
+ accessible drives into libburn's list of drives.
+
+sg_dispose_drive() finalizes adapter specifics of struct burn_drive
+ on destruction. Releases resources which were aquired
+ underneath scsi_enumerate_drives().
+
+sg_drive_is_open() tells wether libburn has the given drive in use.
+
+sg_grab() opens the drive for SCSI commands and ensures
+ undisturbed access.
+
+sg_release() closes a drive opened by sg_grab()
+
+sg_issue_command() sends a SCSI command to the drive, receives reply,
+ and evaluates wether the command succeeded or shall
+ be retried or finally failed.
+
+sg_obtain_scsi_adr() tries to obtain SCSI address parameters.
+
+
+burn_os_is_2k_seekrw() tells whether the given path leads to a file object
+ that can be used in 2 kB granularity by lseek(2),
+ read(2), and possibly write(2) if not read-only..
+ E.g. a USB stick or a hard disk.
+
+burn_os_stdio_capacity() estimates the emulated media space of stdio-drives.
+
+burn_os_open_track_src() opens a disk file in a way that allows best
+ throughput with file reading and/or SCSI write command
+ transmission.
+
+burn_os_alloc_buffer() allocates a memory area that is suitable for file
+ descriptors issued by burn_os_open_track_src().
+ The buffer size may be rounded up for alignment
+ reasons.
+
+burn_os_free_buffer() delete a buffer obtained by burn_os_alloc_buffer().
+
+Porting hints are marked by the text "PORTING:".
+Send feedback to libburn-hackers@pykix.org .
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "../config.h"
+#endif
+
+
+/** PORTING : ------- OS dependent headers and definitions ------ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifdef Libburn_os_has_statvfS
+#include
+#endif /* Libburn_os_has_stavtfS */
+
+#include
+#include
+
+#include
+
+/* >>> need a size determination call for random access devices.
+ e.g. USB sticks.
+*/
+#ifdef __linux
+/* for ioctl(BLKGETSIZE) */
+#include
+#include
+#endif
+
+
+/* The waiting time before eventually retrying a failed SCSI command.
+ Before each retry wait Libburn_sg_linux_retry_incR longer than with
+ the previous one.
+*/
+#define Libburn_sg_solaris_retry_usleeP 100000
+#define Libburn_sg_solaris_retry_incR 100000
+
+
+/** PORTING : ------ libburn portable headers and definitions ----- */
+
+#include "transport.h"
+#include "drive.h"
+#include "sg.h"
+#include "spc.h"
+#include "sbc.h"
+#include "debug.h"
+#include "toc.h"
+#include "util.h"
+
+#include "libdax_msgs.h"
+extern struct libdax_msgs *libdax_messenger;
+
+
+/* is in portable part of libburn */
+int burn_drive_is_banned(char *device_address);
+int burn_drive_resolve_link(char *path, char adr[],
+ int *recursion_count, int flag); /* drive.c */
+
+/* Whether to log SCSI commands:
+ bit0= log in /tmp/libburn_sg_command_log
+ bit1= log to stderr
+ bit2= flush every line
+*/
+extern int burn_sg_log_scsi;
+
+
+/* ------------------------------------------------------------------------ */
+/* PORTING: Private definitions. Port only if needed by public functions. */
+/* (Public functions are listed below) */
+/* ------------------------------------------------------------------------ */
+
+
+/* Storage object is in libburn/init.c
+ whether to strive for exclusive access to the drive
+*/
+extern int burn_sg_open_o_excl;
+
+
+/* ------------------------------------------------------------------------ */
+/* PORTING: Private functions. Port only if needed by public functions */
+/* (Public functions are listed below) */
+/* ------------------------------------------------------------------------ */
+
+
+static int sg_close_drive(struct burn_drive * d)
+{
+ if (d->fd != -1) {
+ close(d->fd);
+ d->fd = -1;
+ return 1;
+ }
+ return 0;
+}
+
+
+static int decode_btl_number(char **cpt, int stopper, int *no)
+{
+ *no = 0;
+ for ((*cpt)++; **cpt != stopper; (*cpt)++) {
+ if (**cpt < '0' || **cpt > '9')
+ return 0;
+ *no = *no * 10 + **cpt - '0';
+ }
+ return 1;
+}
+
+
+/* Read bus, target, lun from name "cXtYdZs2".
+ Return 0 if name is not of the desired form.
+*/
+static int decode_btl_solaris(char *name, int *busno, int *tgtno, int *lunno,
+ int flag)
+{
+ char *cpt;
+ int ret;
+
+ *busno = *tgtno = *lunno = -1;
+ cpt = name;
+ if (*cpt != 'c')
+ return 0;
+ ret = decode_btl_number(&cpt, 't', busno);
+ if (ret <= 0)
+ return ret;
+ ret = decode_btl_number(&cpt, 'd', tgtno);
+ if (ret <= 0)
+ return ret;
+ ret = decode_btl_number(&cpt, 's', lunno);
+ if (ret <= 0)
+ return ret;
+ cpt++;
+ if (*cpt != '2' || *(cpt + 1) != 0)
+ return 0;
+ return 1;
+}
+
+
+static int start_enum_cXtYdZs2(burn_drive_enumerator_t *idx, int flag)
+{
+ DIR *dir;
+
+ idx->dir = NULL;
+ dir = opendir("/dev/rdsk");
+ if (dir == NULL) {
+ libdax_msgs_submit(libdax_messenger, -1,
+ 0x0002000c, LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
+ "Cannot start device file enumeration. opendir(\"/dev/rdsk\") failed.",
+ errno, 0);
+ return 0;
+ }
+ idx->dir = dir;
+ return 1;
+}
+
+
+static int next_enum_cXtYdZs2(burn_drive_enumerator_t *idx,
+ char adr[], int adr_size, int flag)
+{
+ int busno, tgtno, lunno, ret, fd = -1;
+ char volpath[160];
+ struct dirent *entry;
+ struct dk_cinfo cinfo;
+ DIR *dir;
+
+ dir = idx->dir;
+ while (1) {
+ errno = 0;
+ entry = readdir(dir);
+ if (entry == NULL) {
+ if (errno) {
+ libdax_msgs_submit(libdax_messenger,
+ -1, 0x0002000d,
+ LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
+ "Cannot enumerate next device. readdir() from \"/dev/rdsk\" failed.",
+ errno, 0);
+ return -1;
+ }
+ break;
+ }
+ if (strlen(entry->d_name) > sizeof(volpath) - 11)
+ continue;
+ ret = decode_btl_solaris(entry->d_name,
+ &busno, &tgtno, &lunno, 0);
+ if (ret <= 0)
+ continue; /* not cXtYdZs2 */
+
+ sprintf(volpath, "/dev/rdsk/%s", entry->d_name);
+ if (burn_drive_is_banned(volpath))
+ continue;
+
+ fd = open(volpath, O_RDONLY | O_NDELAY);
+ if (fd < 0)
+ continue;
+ /* See man dkio */
+ ret = ioctl(fd, DKIOCINFO, &cinfo);
+ close(fd);
+ if (ret < 0)
+ continue;
+ if (cinfo.dki_ctype != DKC_CDROM)
+ continue;
+ if (adr_size <= strlen(volpath))
+ return -1;
+ strcpy(adr, volpath);
+ return 1;
+ }
+ return 0;
+}
+
+
+static int end_enum_cXtYdZs2(burn_drive_enumerator_t *idx, int flag)
+{
+ DIR *dir;
+
+ dir = idx->dir;
+ if(dir != NULL)
+ closedir(dir);
+ idx->dir = NULL;
+ return 1;
+}
+
+
+/* ----------------------------------------------------------------------- */
+/* PORTING: Private functions which contain publicly needed functionality. */
+/* Their portable part must be performed. So it is probably best */
+/* to replace the non-portable part and to call these functions */
+/* in your port, too. */
+/* ----------------------------------------------------------------------- */
+
+
+/** Wraps a detected drive into libburn structures and hands it over to
+ libburn drive list.
+*/
+static void enumerate_common(char *fname,
+ int bus_no, int host_no,
+ int channel_no, int target_no, int lun_no)
+{
+ int ret;
+ struct burn_drive out;
+
+ /* General libburn drive setup */
+ burn_setup_drive(&out, fname);
+
+ /* This transport adapter uses SCSI-family commands and models
+ (seems the adapter would know better than its boss, if ever) */
+ ret = burn_scsi_setup_drive(&out, bus_no, host_no, channel_no,
+ target_no, lun_no, 0);
+ if (ret <= 0)
+ return;
+
+ /* PORTING: ------------------- non portable part --------------- */
+
+ /* Transport adapter is Solaris uscsi */
+ /* Adapter specific handles and data */
+ out.fd = -1;
+
+ /* PORTING: ---------------- end of non portable part ------------ */
+
+ /* Adapter specific functions with standardized names */
+ out.grab = sg_grab;
+ out.release = sg_release;
+ out.drive_is_open = sg_drive_is_open;
+ out.issue_command = sg_issue_command;
+ /* Finally register drive and inquire drive information */
+ burn_drive_finish_enum(&out);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* PORTING: Public functions. These MUST be ported. */
+/* ------------------------------------------------------------------------ */
+
+
+/** Returns the id string of the SCSI transport adapter and eventually
+ needed operating system facilities.
+ This call is usable even if sg_initialize() was not called yet. In that
+ case a preliminary constant message might be issued if detailed info is
+ not available yet.
+ @param msg returns id string
+ @param flag unused yet, submit 0
+ @return 1 = success, <=0 = failure
+*/
+int sg_id_string(char msg[1024], int flag)
+{
+ sprintf(msg, "internal Solaris uscsi adapter sg-solaris");
+ return 1;
+}
+
+
+/** Performs global initialization of the SCSI transport adapter and eventually
+ needed operating system facilities. Checks for compatibility of supporting
+ software components.
+ @param msg returns ids and/or error messages of eventual helpers
+ @param flag unused yet, submit 0
+ @return 1 = success, <=0 = failure
+*/
+int sg_initialize(char msg[1024], int flag)
+{
+ return sg_id_string(msg, 0);
+}
+
+
+/** Performs global finalization of the SCSI transport adapter and eventually
+ needed operating system facilities. Releases globally aquired resources.
+ @param flag unused yet, submit 0
+ @return 1 = success, <=0 = failure
+*/
+int sg_shutdown(int flag)
+{
+ return 1;
+}
+
+
+/** Finalizes BURN_OS_TRANSPORT_DRIVE_ELEMENTS, the components of
+ struct burn_drive which are defined in os-*.h.
+ The eventual initialization of those components was made underneath
+ scsi_enumerate_drives().
+ This will be called when a burn_drive gets disposed.
+ @param d the drive to be finalized
+ @param flag unused yet, submit 0
+ @return 1 = success, <=0 = failure
+*/
+int sg_dispose_drive(struct burn_drive *d, int flag)
+{
+ return 1;
+}
+
+
+/** Returns the next index number and the next enumerated drive address.
+ The enumeration has to cover all available and accessible drives. It is
+ allowed to return addresses of drives which are not available but under
+ some (even exotic) circumstances could be available. It is on the other
+ hand allowed, only to hand out addresses which can really be used right
+ in the moment of this call. (This implementation chooses the latter.)
+ @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)
+*/
+int sg_give_next_adr(burn_drive_enumerator_t *idx,
+ char adr[], int adr_size, int initialize)
+{
+ int ret;
+
+ if (initialize == 1) {
+ ret = start_enum_cXtYdZs2(idx, 0);
+ if (ret <= 0)
+ return ret;
+ } else if (initialize == -1) {
+ ret = end_enum_cXtYdZs2(idx, 0);
+ return 0;
+ }
+ ret = next_enum_cXtYdZs2(idx, adr, adr_size, 0);
+ return ret;
+}
+
+
+/** Brings all available, not-whitelist-banned, and accessible drives into
+ libburn's list of drives.
+*/
+int scsi_enumerate_drives(void)
+{
+ burn_drive_enumerator_t idx;
+ int initialize = 1, ret, i_bus_no = -1;
+ int i_host_no = -1, i_channel_no = -1, i_target_no = -1, i_lun_no = -1;
+ char buf[4096];
+
+ while(1) {
+ ret = sg_give_next_adr(&idx, buf, sizeof(buf), initialize);
+ initialize = 0;
+ if (ret <= 0)
+ break;
+ if (burn_drive_is_banned(buf))
+ continue;
+ sg_obtain_scsi_adr(buf, &i_bus_no, &i_host_no,
+ &i_channel_no, &i_target_no, &i_lun_no);
+ enumerate_common(buf,
+ i_bus_no, i_host_no, i_channel_no,
+ i_target_no, i_lun_no);
+ }
+ sg_give_next_adr(&idx, buf, sizeof(buf), -1);
+ return 1;
+}
+
+
+/** Tells whether libburn has the given drive in use or exclusively reserved.
+ If it is "open" then libburn will eventually call sg_release() on it when
+ it is time to give up usage resp. reservation.
+*/
+/** Published as burn_drive.drive_is_open() */
+int sg_drive_is_open(struct burn_drive * d)
+{
+ return (d->fd != -1);
+}
+
+
+/** Opens the drive for SCSI commands and - if burn activities are prone
+ to external interference on your system - obtains an exclusive access lock
+ on the drive. (Note: this is not physical tray locking.)
+ A drive that has been opened with sg_grab() will eventually be handed
+ over to sg_release() for closing and unreserving.
+*/
+int sg_grab(struct burn_drive *d)
+{
+ char msg[4096];
+ int os_errno, ret;
+ struct dk_cinfo cinfo;
+
+ if (d->fd != -1) {
+ d->released = 0;
+ return 1;
+ }
+ d->fd = open(d->devname, O_RDONLY | O_NDELAY);
+ if (d->fd == -1) {
+ os_errno = errno;
+ sprintf(msg, "Could not grab drive '%s'", d->devname);
+ libdax_msgs_submit(libdax_messenger, d->global_index,
+ 0x00020003,
+ LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
+ msg, os_errno, 0);
+ return 0;
+ }
+ ret = ioctl(d->fd, DKIOCINFO, &cinfo);
+ if (ret < 0)
+ goto revoke;
+ if (cinfo.dki_ctype != DKC_CDROM)
+ goto revoke;
+
+ /* >>> obtain eventual locks */;
+
+ d->released = 0;
+ return 1;
+revoke:;
+ sprintf(msg, "Could not grab drive '%s'. Not a CDROM device.",
+ d->devname);
+ libdax_msgs_submit(libdax_messenger, d->global_index,
+ 0x00020003,
+ LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
+ msg, 0, 0);
+ return 0;
+}
+
+
+/** PORTING: Is mainly about the call to sg_close_drive() and whether it
+ implements the demanded functionality.
+*/
+/** Gives up the drive for SCSI commands and releases eventual access locks.
+ (Note: this is not physical tray locking.)
+*/
+int sg_release(struct burn_drive *d)
+{
+ if (d->fd < 0) {
+ burn_print(1, "release an ungrabbed drive. die\n");
+ return 0;
+ }
+ sg_close_drive(d);
+ return 0;
+}
+
+
+/** Sends a SCSI command to the drive, receives reply and evaluates wether
+ the command succeeded or shall be retried or finally failed.
+ Returned SCSI errors shall not lead to a return value indicating failure.
+ The callers get notified by c->error. An SCSI failure which leads not to
+ a retry shall be notified via scsi_notify_error().
+ The Libburn_log_sg_commandS facility might be of help when problems with
+ a drive have to be examined. It shall stay disabled for normal use.
+ @return: 1 success , <=0 failure
+*/
+int sg_issue_command(struct burn_drive *d, struct command *c)
+{
+ int i, usleep_time, timeout_ms, no_retry = 0, ret;
+ time_t start_time;
+ struct uscsi_cmd cgc;
+ static FILE *fp = NULL;
+
+ c->error = 0;
+ memset(c->sense, 0, sizeof(c->sense));
+ if (d->fd == -1)
+ return 0;
+
+ if (burn_sg_log_scsi & 1) {
+ if (fp == NULL) {
+ fp= fopen("/tmp/libburn_sg_command_log", "a");
+ fprintf(fp,
+ "\n-----------------------------------------\n");
+ }
+ }
+ if (burn_sg_log_scsi & 3)
+ scsi_log_cmd(c,fp,0);
+
+ memset (&cgc, 0, sizeof (struct uscsi_cmd));
+ /* No error messages, no retries,
+ do not execute with other commands, request sense data
+ */
+ cgc.uscsi_flags = USCSI_SILENT | USCSI_DIAGNOSE | USCSI_ISOLATE
+ | USCSI_RQENABLE;
+ cgc.uscsi_timeout = 200;
+ cgc.uscsi_cdb = (caddr_t) c->opcode;
+ cgc.uscsi_bufaddr = (caddr_t) c->page->data;
+ if (c->dir == TO_DRIVE) {
+ cgc.uscsi_flags |= USCSI_WRITE;
+ cgc.uscsi_buflen = c->page->bytes;
+ } else if (c->dir == FROM_DRIVE) {
+ cgc.uscsi_flags |= USCSI_READ;
+ if (c->dxfer_len >= 0)
+ cgc.uscsi_buflen = c->dxfer_len;
+ else
+ cgc.uscsi_buflen = BUFFER_SIZE;
+ /* touch page so we can use valgrind */
+ memset(c->page->data, 0, BUFFER_SIZE);
+ } else {
+ cgc.uscsi_buflen = 0;
+ }
+ cgc.uscsi_cdblen = c->oplen;
+ cgc.uscsi_rqlen = sizeof(c->sense);
+ cgc.uscsi_rqbuf = (caddr_t) c->sense;
+
+ /* retry-loop */
+ start_time = time(NULL);
+ timeout_ms = 200000;
+ for(i = 0; ; i++) {
+
+ ret = ioctl(d->fd, USCSICMD, &cgc);
+
+ /* For cgc.uscsi_status see SAM-3 5.3.1, Table 22
+ 0 = GOOD , 2 = CHECK CONDITION : Sense Data are delivered
+ 8 = BUSY
+ */
+ if (ret != 0 &&
+ cgc.uscsi_status != 2 && cgc.uscsi_status != 8) {
+ libdax_msgs_submit(libdax_messenger,
+ d->global_index, 0x0002010c,
+ LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
+ "Failed to transfer command to drive",
+ errno, 0);
+ sg_close_drive(d);
+ d->released = 1;
+ d->busy = BURN_DRIVE_IDLE;
+ c->error = 1;
+ return -1;
+ }
+
+ c->sense[2] &= 15;
+
+ if (cgc.uscsi_status == 8) {
+ /* >>> fake BUSY sense */;
+ }
+
+ /* >>> valid sense: cgc.uscsi_rqlen - cgc.uscsi_rqresid */;
+
+ if (c->sense[2] || c->sense[12] || c->sense[13]) {
+ if (no_retry || !c->retry) {
+ c->error = 1;
+ goto ex;
+ }
+ switch (scsi_error(d, c->sense, 18)) {
+ case RETRY:
+ if (burn_sg_log_scsi & 3) {
+ /* >>> Need own duration time
+ measurement. Then remove bit1 */
+ scsi_log_err(c, fp, c->sense, 0,
+ (c->error != 0) | 2);
+ scsi_log_cmd(c,fp,0);
+ }
+ break;
+ case FAIL:
+ c->error = 1;
+ goto ex;
+ }
+ /*
+ Calming down retries and breaking up endless cycle
+ */
+ usleep_time = Libburn_sg_solaris_retry_usleeP +
+ i * Libburn_sg_solaris_retry_incR;
+ if (time(NULL) + usleep_time / 1000000 - start_time >
+ timeout_ms / 1000 + 1) {
+ c->error = 1;
+ goto ex;
+ }
+ usleep(usleep_time);
+ } else
+ break; /* retry-loop */
+ } /* end of retry-loop */
+
+ex:;
+ if (c->error)
+ scsi_notify_error(d, c, c->sense, 18, 0);
+
+ if (burn_sg_log_scsi & 3)
+ /* >>> Need own duration time measurement. Then remove bit1 */
+ scsi_log_err(c, fp, c->sense, 0, (c->error != 0) | 2);
+ return 1;
+}
+
+/* >>> */
+
+/** Tries to obtain SCSI address parameters.
+ @return 1 is success , 0 is failure
+*/
+int sg_obtain_scsi_adr(char *path, int *bus_no, int *host_no, int *channel_no,
+ int *target_no, int *lun_no)
+{
+ int ret;
+
+ /* Try to guess from path */
+ if (strncmp("/dev/rdsk/", path, 10) == 0) {
+ ret = decode_btl_solaris(path + 10,
+ bus_no, target_no, lun_no, 0);
+ if (ret > 0) {
+ *host_no = *bus_no;
+ *channel_no = 0;
+ return 1;
+ }
+ }
+ *bus_no = *host_no = *channel_no = *target_no = *lun_no = -1;
+
+ /* >>> Could need a ioctl which gives SCSI numbers */;
+
+ return (0);
+}
+
+
+/** Tells wether a text is a persistent address as listed by the enumeration
+ functions.
+*/
+int sg_is_enumerable_adr(char* adr)
+{
+ burn_drive_enumerator_t idx;
+ int initialize = 1, ret;
+ char buf[64];
+
+ while(1) {
+ ret = sg_give_next_adr(&idx, buf, sizeof(buf), initialize);
+ initialize = 0;
+ if (ret <= 0)
+ break;
+ if (strcmp(adr, buf) == 0) {
+ sg_give_next_adr(&idx, buf, sizeof(buf), -1);
+ return 1;
+ }
+ }
+ sg_give_next_adr(&idx, buf, sizeof(buf), -1);
+ return (0);
+}
+
+
+
+/* Return 1 if the given path leads to a regular file or a device that can be
+ seeked, read, and possibly written with 2 kB granularity.
+*/
+int burn_os_is_2k_seekrw(char *path, int flag)
+{
+ struct stat stbuf;
+
+ if (stat(path, &stbuf) == -1)
+ return 0;
+ if (S_ISREG(stbuf.st_mode))
+ return 1;
+ if (S_ISBLK(stbuf.st_mode))
+ return 1;
+ return 0;
+}
+
+
+/** Estimate the potential payload capacity of a file address.
+ @param path The address of the file to be examined. If it does not
+ exist yet, then the directory will be inquired.
+ @param bytes The pointed value gets modified, but only if an estimation is
+ possible.
+ @return -2 = cannot perform necessary operations on file object
+ -1 = neither path nor dirname of path exist
+ 0 = could not estimate size capacity of file object
+ 1 = estimation has been made, bytes was set
+*/
+int burn_os_stdio_capacity(char *path, off_t *bytes)
+{
+ struct stat stbuf;
+
+#ifdef Libburn_os_has_statvfS
+ struct statvfs vfsbuf;
+#endif
+
+ char testpath[4096], *cpt;
+ long blocks;
+ off_t add_size = 0;
+
+ testpath[0] = 0;
+ blocks = *bytes / 512;
+ if (stat(path, &stbuf) == -1) {
+ strcpy(testpath, path);
+ cpt = strrchr(testpath, '/');
+ if(cpt == NULL)
+ strcpy(testpath, ".");
+ else if(cpt == testpath)
+ testpath[1] = 0;
+ else
+ *cpt = 0;
+ if (stat(testpath, &stbuf) == -1)
+ return -1;
+
+#ifdef __linux
+
+ /* GNU/Linux specific determination of block device size */
+ } else if(S_ISBLK(stbuf.st_mode)) {
+ int open_mode = O_RDONLY, fd, ret;
+
+ fd = open(path, open_mode);
+ if (fd == -1)
+ return -2;
+ ret = ioctl(fd, BLKGETSIZE, &blocks);
+ close(fd);
+ if (ret == -1)
+ return -2;
+ *bytes = ((off_t) blocks) * (off_t) 512;
+
+#endif /* __linux */
+
+
+ /* >>> ioctl to determine capacity of block device
+ ? DKIOCGEXTVTOC , man dkio ?
+ ? DKIOCEXTPARTINFO ,
+ struct extpart_info.p_length * 512, man dkio ?
+ */;
+
+
+ } else if(S_ISREG(stbuf.st_mode)) {
+ add_size = stbuf.st_blocks * (off_t) 512;
+ strcpy(testpath, path);
+ } else
+ return 0;
+
+ if (testpath[0]) {
+
+#ifdef Libburn_os_has_statvfS
+
+ if (statvfs(testpath, &vfsbuf) == -1)
+ return -2;
+ *bytes = add_size + ((off_t) vfsbuf.f_frsize) *
+ (off_t) vfsbuf.f_bavail;
+
+#else /* Libburn_os_has_statvfS */
+
+ return 0;
+
+#endif /* ! Libburn_os_has_stavtfS */
+
+ }
+ return 1;
+}
+
+
+/* ts A91122 : an interface to open(O_DIRECT) or similar OS tricks. */
+
+#ifdef Libburn_read_o_direcT
+
+ /* No special O_DIRECT-like precautions are implemented here */
+
+#endif /* Libburn_read_o_direcT */
+
+
+int burn_os_open_track_src(char *path, int open_flags, int flag)
+{
+ int fd;
+
+ fd = open(path, open_flags);
+ return fd;
+}
+
+
+void *burn_os_alloc_buffer(size_t amount, int flag)
+{
+ void *buf = NULL;
+
+ buf = calloc(1, amount);
+ return buf;
+}
+
+
+int burn_os_free_buffer(void *buffer, size_t amount, int flag)
+{
+ if (buffer == NULL)
+ return 0;
+ free(buffer);
+ return 1;
+}
+
diff --git a/libburn/sg.c b/libburn/sg.c
index e855b39..1ee17e6 100644
--- a/libburn/sg.c
+++ b/libburn/sg.c
@@ -1,7 +1,8 @@
/* sg.c
Switcher for operating system dependent transport level modules of libburn.
- Copyright (C) 2009 Thomas Schmitt , provided under GPLv2+
+ Copyright (C) 2009 - 2010 Thomas Schmitt ,
+ provided under GPLv2+
*/
#ifdef HAVE_CONFIG_H
@@ -10,6 +11,11 @@
#endif
+#ifdef Libburn_use_sg_dummY
+
+#include "sg-dummy.c"
+
+#else
#ifdef Libburn_use_libcdiO
#include "sg-libcdio.c"
@@ -29,6 +35,11 @@
#include "sg-linux.c"
+#else
+#ifdef __sun
+
+#include "sg-solaris.c"
+
#else
/* The dummy adapter formally fulfills the expectations of libburn towards
@@ -51,8 +62,10 @@ static int intentional_compiler_warning(void)
#include "sg-dummy.c"
+#endif /* ! __sun */
#endif /* ! __linux */
#endif /* ! __FreeBSD_kernel__ */
#endif /* ! __FreeBSD__ */
#endif /* ! Libburn_use_libcdiO */
+#endif /* ! Libburn_use_sg_dummY */