"Fossies" - the Fresh Open Source Software Archive

Member "xorriso-1.5.4/libburn/sg-linux.c" (30 Jan 2021, 73971 Bytes) of package /linux/misc/xorriso-1.5.4.pl02.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "sg-linux.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.5.2_vs_1.5.4.

    1 /* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
    2 
    3 /* Copyright (c) 2004 - 2006 Derek Foreman, Ben Jansens
    4    Copyright (c) 2006 - 2020 Thomas Schmitt <scdbackup@gmx.net>
    5    Provided under GPL version 2 or later.
    6 */
    7 
    8 
    9 
   10 /* <<< ts A91112 : experiments to get better speed with USB
   11 #define Libburn_sgio_as_growisofS 1
   12 */
   13 
   14 
   15 /*
   16 
   17 This is the main operating system dependent SCSI part of libburn. It implements
   18 the transport level aspects of SCSI control and command i/o.
   19 
   20 Present implementation: GNU/Linux SCSI Generic (sg)
   21 
   22 
   23 PORTING:
   24 
   25 Porting libburn typically will consist of adding a new operating system case
   26 to the following switcher files:
   27   os.h    Operating system specific libburn definitions and declarations.
   28   sg.c    Operating system dependent transport level modules.
   29 and of deriving the following system specific files from existing examples:
   30   os-*.h  Included by os.h. You will need some general system knowledge
   31           about signals and knowledge about the storage object needs of your
   32           transport level module sg-*.c.
   33 
   34   sg-*.c  This source module. You will need special system knowledge about
   35           how to detect all potentially available drives, how to open them,
   36           eventually how to exclusively reserve them, how to perform
   37           SCSI transactions, how to inquire the (pseudo-)SCSI driver. 
   38           You will not need to care about CD burning, MMC or other high-level
   39           SCSI aspects.
   40 
   41 Said sg-*.c operations are defined by a public function interface, which has
   42 to be implemented in a way that provides libburn with the desired services:
   43  
   44 sg_id_string()          returns an id string of the SCSI transport adapter.
   45                         It may be called before initialization but then may
   46                         return only a preliminary id.
   47 
   48 sg_initialize()         performs global initialization of the SCSI transport
   49                         adapter and eventually needed operating system
   50                         facilities. Checks for compatibility of supporting
   51                         software components.
   52 
   53 sg_shutdown()           performs global finalizations and releases globally
   54                         acquired resources.
   55 
   56 sg_give_next_adr()      iterates over the set of potentially useful drive 
   57                         address strings.
   58 
   59 scsi_enumerate_drives() brings all available, not-whitelist-banned, and
   60                         accessible drives into libburn's list of drives.
   61 
   62 sg_dispose_drive()      finalizes adapter specifics of struct burn_drive
   63                         on destruction. Releases resources which were acquired
   64                         underneath scsi_enumerate_drives().
   65 
   66 sg_drive_is_open()      tells whether libburn has the given drive in use.
   67 
   68 sg_grab()               opens the drive for SCSI commands and ensures
   69                         undisturbed access.
   70 
   71 sg_release()            closes a drive opened by sg_grab()
   72 
   73 sg_issue_command()      sends a SCSI command to the drive, receives reply,
   74                         and evaluates whether the command succeeded or shall
   75                         be retried or finally failed.
   76 
   77 sg_obtain_scsi_adr()    tries to obtain SCSI address parameters.
   78 
   79 
   80 burn_os_is_2k_seekrw()  tells whether the given path leads to a file object
   81                         that can be used in 2 kB granularity by lseek(2) and
   82                         read(2), and possibly write(2) if not read-only.
   83                         E.g. a USB stick or a hard disk.
   84 
   85 burn_os_stdio_capacity()  estimates the emulated media space of stdio-drives.
   86 
   87 burn_os_open_track_src()  opens a disk file in a way that offers best
   88                         throughput with file reading and/or SCSI write command
   89                         transmission.
   90 
   91 burn_os_alloc_buffer()  allocates a memory area that is suitable for file
   92                         descriptors issued by burn_os_open_track_src().
   93                         The buffer size may be rounded up for alignment
   94                         reasons.
   95 
   96 burn_os_free_buffer()   delete a buffer obtained by burn_os_alloc_buffer().
   97 
   98 
   99 Porting hints are marked by the text "PORTING:".
  100 Send feedback to libburn-hackers@pykix.org .
  101 
  102 Hint: You should also look into sg-freebsd-port.c, which is a younger and
  103       in some aspects more straightforward implementation of this interface.
  104 
  105 */
  106 
  107 #ifdef HAVE_CONFIG_H
  108 #include "../config.h"
  109 #endif
  110 
  111 
  112 /** PORTING : ------- OS dependent headers and definitions ------ */
  113 
  114 #ifdef Libburn_read_o_direcT
  115 /* ts B91124:
  116    DISABLED, because this spoils multi-track burning of cdrskin by a hard to
  117    fix bug in cdrskin/cdrfifo.c
  118    DO NOT ENABLE before the wait code in that source file is fixed.
  119 */
  120 #undef Libburn_read_o_direcT
  121 #endif
  122 
  123 
  124 #ifdef Libburn_read_o_direcT
  125 # ifndef _GNU_SOURCE
  126 #  define _GNU_SOURCE
  127 # endif
  128 #endif /* Libburn_read_o_direcT */
  129 
  130 #include <errno.h>
  131 #include <unistd.h>
  132 #include <stdio.h>
  133 #include <sys/types.h>
  134 #include <sys/stat.h>
  135 #include <fcntl.h>
  136 #include <sys/ioctl.h>
  137 #include <string.h>
  138 #include <sys/poll.h>
  139 #include <linux/hdreg.h>
  140 #include <stdlib.h>
  141 #include <sys/utsname.h>
  142 #include <scsi/scsi.h>
  143 #include <sys/statvfs.h>
  144 
  145 /* for ioctl(BLKGETSIZE) */
  146 #include <linux/fs.h>
  147 
  148 /* for mmap() */
  149 #include <sys/mman.h>
  150 
  151 
  152 #include <scsi/sg.h>
  153 /* Values within sg_io_hdr_t indicating success after ioctl(SG_IO) : */
  154 /* .host_status : from http://tldp.org/HOWTO/SCSI-Generic-HOWTO/x291.html */
  155 #define Libburn_sg_host_oK 0
  156 /* .driver_status : from http://tldp.org/HOWTO/SCSI-Generic-HOWTO/x322.html */
  157 #define Libburn_sg_driver_oK 0
  158 
  159 
  160 /* ts A61211 : to eventually recognize CD devices on /dev/sr* */
  161 #include <limits.h>
  162 #include <linux/cdrom.h>
  163 
  164 
  165 /** Indication of the Linux kernel this software is running on */
  166 /* -1 = not evaluated , 0 = unrecognizable , 1 = 2.4 , 2 = 2.6 */
  167 static int sg_kernel_age = -1;
  168 
  169 
  170 /** PORTING : Device file families for bus scanning and drive access.
  171     Both device families must support the following ioctls:
  172       SG_IO,
  173       SG_GET_SCSI_ID
  174       SCSI_IOCTL_GET_BUS_NUMBER
  175       SCSI_IOCTL_GET_IDLUN
  176     as well as mutual exclusively locking with open(O_EXCL).
  177     If a device family is left empty, then it will not be used.
  178 
  179     To avoid misunderstandings: both families are used via identical
  180     transport methods as soon as a device file is accepted as CD drive
  181     by the family specific function <family>_enumerate().
  182     One difference remains throughout usage: Host,Channel,Id,Lun and Bus
  183     address parameters of ATA devices are considered invalid.
  184 */
  185 
  186 /* Set this to 1 in order to get on stderr messages from sg_enumerate() */
  187 static int linux_sg_enumerate_debug = 0;
  188 
  189 
  190 /* The device file family to use for (emulated) generic SCSI transport.
  191    This must be a printf formatter with one single placeholder for int
  192    in the range of 0 to 31 . The resulting addresses must provide SCSI
  193    address parameters Host, Channel, Id, Lun and also Bus.
  194    E.g.: "/dev/sg%d"
  195    sr%d is supposed to map only CD-ROM style devices. Additionally a test
  196    with ioctl(CDROM_DRIVE_STATUS) is made to assert that it is such a drive,
  197    If no such assertion is made, then this adapter performs INQUIRE and
  198    looks for first reply byte 0x05.
  199 
  200    This initial setting may be overridden in sg_select_device_family() by 
  201    settings made via burn_preset_device_open().
  202 */
  203 static char linux_sg_device_family[80] = {"/dev/sg%d"};
  204 
  205 /* Set this to 1 if you want the default linux_sg_device_family chosen
  206    depending on kernel release: sg for <2.6 , sr for >=2.6
  207 */
  208 static int linux_sg_auto_family = 1;
  209 
  210 
  211 /* Set this to 1 in order to accept any TYPE_* (see scsi/scsi.h) */
  212 /* But try with 0 first. There is hope via CDROM_DRIVE_STATUS. */
  213 /* !!! DO NOT SET TO 1 UNLESS YOU PROTECTED ALL INDISPENSABLE DEVICES
  214        chmod -rw !!! */
  215 static int linux_sg_accept_any_type = 0;
  216 
  217 
  218 /* The device file family to use for SCSI transport over ATA.
  219    This must be a printf formatter with one single placeholder for a
  220    _single_ char in the range of 'a' to 'z'. This placeholder _must_ be
  221    at the end of the formatter string.
  222    E.g. "/dev/hd%c"
  223 */
  224 static char linux_ata_device_family[80] = {"/dev/hd%c"};
  225 
  226 /* Set this to 1 in order to get on stderr messages from ata_enumerate()
  227 */
  228 static int linux_ata_enumerate_verbose = 0;
  229 
  230 
  231 /** PORTING : ------ libburn portable headers and definitions ----- */
  232 
  233 #include "libburn.h"
  234 #include "transport.h"
  235 #include "drive.h"
  236 #include "sg.h"
  237 #include "spc.h"
  238 #include "mmc.h"
  239 #include "sbc.h"
  240 #include "debug.h"
  241 #include "toc.h"
  242 #include "util.h"
  243 #include "init.h"
  244 
  245 #include "libdax_msgs.h"
  246 extern struct libdax_msgs *libdax_messenger;
  247 
  248 /* ts A51221 */
  249 int burn_drive_is_banned(char *device_address);
  250 
  251 
  252 /* ------------------------------------------------------------------------ */
  253 /* PORTING:   Private definitions. Port only if needed by public functions. */
  254 /*            (Public functions are listed below)                           */
  255 /* ------------------------------------------------------------------------ */
  256 
  257 
  258 static void enumerate_common(char *fname, int fd_in, int bus_no, int host_no,
  259                  int channel_no, int target_no, int lun_no);
  260 
  261 static int sg_obtain_scsi_adr_fd(char *path, int fd_in,
  262                  int *bus_no, int *host_no, int *channel_no,
  263                  int *target_no, int *lun_no);
  264 
  265 
  266 /* ts A60813 : storage objects are in libburn/init.c
  267    whether to use O_EXCL with open(2) of devices
  268    whether to use fcntl(,F_SETLK,) after open(2) of devices
  269    what device family to use : 0=default, 1=sr, 2=scd, (3=st), 4=sg
  270    whether to use O_NOBLOCK with open(2) on devices
  271    whether to take O_EXCL rejection as fatal error
  272 */
  273 extern int burn_sg_open_o_excl;
  274 extern int burn_sg_fcntl_f_setlk;
  275 extern int burn_sg_use_family;
  276 extern int burn_sg_open_o_nonblock;
  277 extern int burn_sg_open_abort_busy;
  278 
  279 /* ts A91111 :
  280    whether to log SCSI commands:
  281    bit0= log in /tmp/libburn_sg_command_log
  282    bit1= log to stderr
  283    bit2= flush every line
  284 */
  285 extern int burn_sg_log_scsi;
  286 
  287 /* ts A60821
  288    debug: for tracing calls which might use open drive fds
  289           or for catching SCSI usage of emulated drives. */
  290 int mmc_function_spy(struct burn_drive *d, char * text);
  291 
  292 
  293 /* ------------------------------------------------------------------------ */
  294 /* PORTING:   Private functions. Port only if needed by public functions    */
  295 /*            (Public functions are listed below)                           */
  296 /* ------------------------------------------------------------------------ */
  297 
  298 /* ts A70413 */
  299 /* This finds out whether the software is running on kernel >= 2.6
  300 */
  301 static void sg_evaluate_kernel(void)
  302 {
  303     struct utsname buf;
  304     if (sg_kernel_age >= 0)
  305         return;
  306 
  307     sg_kernel_age = 0;
  308     if (uname(&buf) == -1)
  309         return;
  310     sg_kernel_age = 1;
  311     if (strcmp(buf.release, "2.6") >= 0)
  312         sg_kernel_age = 2;
  313 }
  314 
  315 
  316 /* ts A70314 */
  317 /* This installs the device file family if one was chosen explicitly
  318    by burn_preset_device_open()
  319 */
  320 static void sg_select_device_family(void)
  321 {
  322 
  323     /* >>> ??? do we need a mutex here ? */
  324     /* >>> (It might be concurrent but is supposed to have always
  325             the same effect. Any race condition should be harmless.) */
  326 
  327     if (burn_sg_use_family == 1)
  328         strcpy(linux_sg_device_family, "/dev/sr%d");
  329     else if (burn_sg_use_family == 2)
  330         strcpy(linux_sg_device_family, "/dev/scd%d");
  331     else if (burn_sg_use_family == 3)
  332         strcpy(linux_sg_device_family, "/dev/st%d");
  333     else if (burn_sg_use_family == 4)
  334         strcpy(linux_sg_device_family, "/dev/sg%d");
  335     else if (linux_sg_auto_family) {
  336         sg_evaluate_kernel();
  337         if (sg_kernel_age >= 2)
  338             strcpy(linux_sg_device_family, "/dev/sr%d");
  339         else
  340             strcpy(linux_sg_device_family, "/dev/sg%d");
  341         linux_sg_auto_family = 0;
  342     }
  343 }
  344 
  345 
  346 /* ts A80701 */
  347 /* This cares for the case that no /dev/srNN but only /dev/scdNN exists.
  348    A theoretical case which has its complement in SuSE 10.2 having
  349    /dev/sr but not /dev/scd.
  350 */
  351 static int sg_exchange_scd_for_sr(char *fname, int flag)
  352 {
  353     struct stat stbuf;
  354     char scd[17], *msg = NULL;
  355 
  356     if (burn_sg_use_family != 0 || strncmp(fname, "/dev/sr", 7)!=0 ||
  357         strlen(fname)>9 || strlen(fname)<8)
  358         return 2;
  359     if (fname[7] < '0' || fname[7] > '9')
  360         return 2;
  361     if (fname [8] != 0 && (fname[7] < '0' || fname[7] > '9'))
  362         return 2;
  363     if (stat(fname, &stbuf) != -1)
  364         return 2;
  365     strcpy(scd, "/dev/scd");
  366     strcpy(scd + 8, fname + 7);
  367     if (stat(scd, &stbuf) == -1)
  368         return 2;
  369     msg = calloc(strlen(scd) + strlen(fname) + 80, 1);
  370     if (msg != NULL) {
  371         sprintf(msg, "%s substitutes for non-existent %s", scd, fname);
  372         libdax_msgs_submit(libdax_messenger, -1, 0x00000002,
  373             LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
  374             msg, 0, 0);
  375         free(msg);
  376     }
  377     strcpy(fname, scd);
  378     return 1;
  379 }
  380 
  381 
  382 /* ts B11110 */
  383 /* This is an early stage version of scsi_log_cmd.
  384    >>> It will become obsolete when the /tmp file handler is moved into
  385    >>> scsi_log_command().
  386    @param flag  bit0= data direction is FROM_DRIVE
  387 */
  388 static int sgio_log_cmd(unsigned char *cmd, int cmd_len, FILE *fp_in, int flag)
  389 {
  390     FILE *fp = fp_in;
  391     int ret = 0;
  392     int data_dir = NO_TRANSFER;
  393 
  394     if (flag & 1)
  395         data_dir = FROM_DRIVE;
  396 
  397     /* >>> ts B11110 : move this into scsi_log_command() */
  398     if (fp == NULL && (burn_sg_log_scsi & 1)) {
  399         fp= fopen("/tmp/libburn_sg_command_log", "a");
  400         if (fp != NULL)
  401             fprintf(fp,
  402                 "\n=========================================\n");
  403     }
  404 
  405     if (fp != NULL)
  406         ret = scsi_log_command(cmd, cmd_len, data_dir, NULL, 0,
  407                     fp, flag);
  408     if (fp_in == NULL && fp != NULL)
  409         fclose(fp);
  410     if (fp == stderr || !(burn_sg_log_scsi & 2))
  411         return ret;
  412     ret = scsi_log_command(cmd, cmd_len, data_dir, NULL, 0, stderr, 0);
  413     return ret;
  414 }
  415 
  416 
  417 /* ts B11110 */
  418 static int sgio_log_reply(unsigned char *opcode, int data_dir,
  419                           unsigned char *data, int dxfer_len,
  420                           void *fp_in, unsigned char sense[18], int sense_len,
  421                           double duration, int flag)
  422 {
  423     int ret;
  424 
  425     ret = scsi_log_reply(opcode, data_dir, data, dxfer_len, fp_in,
  426                        sense, sense_len, duration, flag);
  427     return ret;
  428 }
  429 
  430 
  431 static int sgio_test(int fd)
  432 {
  433     unsigned char test_ops[] = { 0, 0, 0, 0, 0, 0 };
  434     sg_io_hdr_t s;
  435     int ret;
  436     double c_start_time, c_end_time;
  437 
  438     memset(&s, 0, sizeof(sg_io_hdr_t));
  439     s.interface_id = 'S';
  440     s.dxfer_direction = SG_DXFER_NONE;
  441     s.cmd_len = 6;
  442     s.cmdp = test_ops;
  443     s.timeout = 12345;
  444 
  445     sgio_log_cmd(s.cmdp, s.cmd_len, NULL, 0);
  446 
  447     c_start_time = burn_get_time(0);
  448     ret= ioctl(fd, SG_IO, &s);
  449     c_end_time = burn_get_time(0);
  450 
  451     sgio_log_reply(s.cmdp, NO_TRANSFER, NULL, 0, NULL,
  452                    (unsigned char *) (s.sbp),
  453                    s.sb_len_wr, c_end_time - c_start_time, 0);
  454     return ret;
  455 }
  456 
  457 
  458 static int sgio_inquiry_cd_drive(int fd, char *fname)
  459 {
  460     unsigned char test_ops[] = { 0x12, 0, 0, 0, 36, 0 };
  461     sg_io_hdr_t s;
  462     struct buffer *buf = NULL;
  463     unsigned char *sense = NULL;
  464     char *msg = NULL, *msg_pt;
  465     int ret = 0, i;
  466     double c_start_time, c_end_time;
  467 
  468     BURN_ALLOC_MEM(buf, struct buffer, 1);
  469     BURN_ALLOC_MEM(sense, unsigned char, 128);
  470     BURN_ALLOC_MEM(msg, char, strlen(fname) + 1024);
  471 
  472     memset(&s, 0, sizeof(sg_io_hdr_t));
  473     s.interface_id = 'S';
  474     s.dxfer_direction = SG_DXFER_FROM_DEV;
  475     s.cmd_len = 6;
  476     s.cmdp = test_ops;
  477     s.mx_sb_len = 32;
  478     s.sbp = sense;
  479     s.timeout = 30000;
  480     s.dxferp = buf;
  481     s.dxfer_len = 36;
  482     s.usr_ptr = NULL;
  483 
  484     sgio_log_cmd(s.cmdp, s.cmd_len, NULL, 1);
  485 
  486     c_start_time = burn_get_time(0);
  487     ret = ioctl(fd, SG_IO, &s);
  488     c_end_time = burn_get_time(0);
  489     if (ret == -1) {
  490         sprintf(msg,
  491              "INQUIRY on '%s' : ioctl(SG_IO) failed , errno= %d",
  492              fname, errno);
  493         libdax_msgs_submit(libdax_messenger, -1, 0x00000002,
  494             LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
  495             msg, 0, 0);
  496         goto ex;
  497     }
  498 
  499     sgio_log_reply(s.cmdp, FROM_DRIVE, buf->data, s.dxfer_len, NULL,
  500                    (unsigned char *) (s.sbp),
  501                    s.sb_len_wr, c_end_time - c_start_time, 0);
  502 
  503     if (s.sb_len_wr > 0 || s.host_status != Libburn_sg_host_oK ||
  504         s.driver_status != Libburn_sg_driver_oK) {
  505         sprintf(msg, "INQUIRY failed on '%s' : host_status= %hd , driver_status= %hd", fname, s.host_status, s.driver_status);
  506         if (s.sb_len_wr > 0) {
  507             sprintf(msg + strlen(msg), " , sense data=");
  508             msg_pt = msg + strlen(msg);
  509             for (i = 0 ; i < s.sb_len_wr; i++)
  510                 sprintf(msg_pt + i * 3, " %2.2X",
  511                         ((unsigned char *) (s.sbp))[i]);
  512         }
  513         libdax_msgs_submit(libdax_messenger, -1, 0x00000002,
  514             LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
  515             msg, 0, 0);
  516         ret = -1;
  517         goto ex;
  518     }
  519     ret = 0;
  520     if (buf->data[0] == 0x5) {
  521         /* Peripheral qualifier 0, device type 0x5 = CD/DVD device.
  522            SPC-3 tables 82 and 83  */
  523         ret = 1;
  524     } else {
  525         sprintf(msg, "INQUIRY on '%s' : byte 0 = 0x%2.2X",
  526              fname, buf->data[0]);
  527         libdax_msgs_submit(libdax_messenger, -1, 0x00000002,
  528             LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
  529             msg, 0, 0);
  530     }
  531 
  532 ex:;
  533     BURN_FREE_MEM(msg);
  534     BURN_FREE_MEM(sense);
  535     BURN_FREE_MEM(buf);
  536     return ret;
  537 }
  538 
  539 
  540 /* ts A60924 */
  541 static int sg_handle_busy_device(char *fname, int os_errno)
  542 {
  543     char *msg = NULL;
  544     struct stat stbuf;
  545     int looks_like_hd= 0, fd, ret;
  546 
  547     BURN_ALLOC_MEM(msg, char, 4096);
  548 
  549     /* ts A80713 :
  550        check existence of /dev/hdX1 as hint for hard disk rather than CD
  551        Hint by Giulio Orsero: check /proc/ide/hdX/media for "disk"
  552     */
  553     if (strncmp(fname, "/dev/hd", 7)==0) {
  554         sprintf(msg, "%s1", fname);
  555         if (stat(msg, &stbuf) != -1)
  556             looks_like_hd= 1;
  557         sprintf(msg, "/proc/ide/hd%c/media", fname[7]);
  558         fd = open(msg, O_RDONLY);
  559         if (fd != -1) {
  560             ret = read(fd, msg, 10);
  561             if (ret < 0)
  562                 ret = 0;
  563             msg[ret]= 0;
  564             close(fd);
  565             if (strncmp(msg, "disk\n", 5) == 0 ||
  566                 strcmp(msg, "disk") == 0)
  567                 looks_like_hd= 2;
  568             else if (strncmp(msg, "cdrom\n", 6) == 0 ||
  569                      strcmp(msg, "cdrom") == 0)
  570                 looks_like_hd= 0;
  571         }
  572     }
  573 
  574     /* ts A60814 : i saw no way to do this more nicely */ 
  575     if (burn_sg_open_abort_busy) {
  576         fprintf(stderr,
  577     "\nlibburn: FATAL : Application triggered abort on busy device '%s'\n",
  578             fname);
  579 
  580         /* ts A61007 */
  581         abort();
  582         /* a ssert("drive busy" == "non fatal"); */
  583     }
  584 
  585     /* ts A60924 : now reporting to libdax_msgs */
  586     if (looks_like_hd == 2) { /* is surely hard disk */
  587         ;
  588     } else if (looks_like_hd) {
  589         sprintf(msg, "Could not examine busy device '%s'", fname);
  590         libdax_msgs_submit(libdax_messenger, -1, 0x0002015a,
  591                 LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_LOW,
  592                 msg, os_errno, 0);
  593         sprintf(msg,
  594     "Busy '%s' seems to be a hard disk, as '%s1' exists. But better check.",
  595                 fname, fname);
  596         libdax_msgs_submit(libdax_messenger, -1, 0x0002015b,
  597                 LIBDAX_MSGS_SEV_HINT, LIBDAX_MSGS_PRIO_LOW,
  598                 msg, 0, 0);
  599 
  600     } else {
  601         sprintf(msg, "Cannot open busy device '%s'", fname);
  602         libdax_msgs_submit(libdax_messenger, -1, 0x00020001,
  603                 LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_LOW,
  604                 msg, os_errno, 0);
  605     }
  606     ret = 1;
  607 ex:;
  608     BURN_FREE_MEM(msg);
  609     return ret;
  610 }
  611 
  612 
  613 /* ts A60925 : ticket 74 */
  614 static int sg_close_drive_fd(char *fname, int driveno, int *fd, int sorry)
  615 {
  616     int ret, os_errno, sevno= LIBDAX_MSGS_SEV_DEBUG;
  617     char *msg = NULL;
  618 
  619     if(*fd < 0)
  620         {ret = 0; goto ex;}
  621     BURN_ALLOC_MEM(msg, char, 4096 + 100);
  622 
  623 #ifdef CDROM_MEDIA_CHANGED_disabled_because_not_helpful
  624 #ifdef CDSL_CURRENT
  625     /* ts A80217 : wondering whether the os knows about our activities */
  626     ret = ioctl(*fd, CDROM_MEDIA_CHANGED, CDSL_CURRENT);
  627     sprintf(msg, "ioctl(CDROM_MEDIA_CHANGED) == %d", ret);
  628     libdax_msgs_submit(libdax_messenger, driveno, 0x00000002,
  629         LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH, msg, 0, 0);
  630 
  631 #ifdef BLKFLSBUF_disabled_because_not_helpful
  632     ret = ioctl(*fd, BLKFLSBUF, 0);
  633     sprintf(msg, "ioctl(BLKFLSBUF) == %d", ret);
  634     os_errno = 0;
  635     if(ret == -1)
  636         os_errno = errno;
  637     libdax_msgs_submit(libdax_messenger, driveno, 0x00000002,
  638         LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH, msg, os_errno,0);
  639 #endif /* BLKFLSBUF */
  640 
  641 #endif /* CDSL_CURRENT */
  642 #endif /* CDROM_MEDIA_CHANGED */
  643 
  644     ret = close(*fd);
  645     *fd = -1337;
  646     if(ret != -1) {
  647         /* ts A70409 : DDLP-B */
  648         /* >>> release single lock on fname */
  649         {ret = 1; goto ex;}
  650     }
  651     os_errno= errno;
  652 
  653     sprintf(msg, "Encountered error when closing drive '%s'", fname);
  654     if (sorry)
  655         sevno = LIBDAX_MSGS_SEV_SORRY;
  656     libdax_msgs_submit(libdax_messenger, driveno, 0x00020002,
  657             sevno, LIBDAX_MSGS_PRIO_HIGH, msg, os_errno, 0);
  658     ret = 0;
  659 ex:;
  660     BURN_FREE_MEM(msg);
  661     return ret; 
  662 }
  663 
  664 
  665 /* ts A70401 : 
  666    fcntl() has the unappealing property to work only after open().
  667    So libburn will by default use open(O_EXCL) first and afterwards
  668    as second assertion will use fcntl(F_SETLK). One lock more should not harm.
  669 */
  670 static int sg_fcntl_lock(int *fd, char *fd_name, int l_type, int verbose)
  671 {
  672     struct flock lockthing;
  673     char msg[81];
  674     int ret;
  675 
  676     if (!burn_sg_fcntl_f_setlk)
  677         return 1;
  678 
  679     memset(&lockthing, 0, sizeof(lockthing));
  680     lockthing.l_type = l_type;
  681     lockthing.l_whence = SEEK_SET;
  682     lockthing.l_start = 0;
  683     lockthing.l_len = 0;
  684 /*
  685         fprintf(stderr,"LIBBURN_EXPERIMENTAL: fcntl(%d, F_SETLK, %s)\n",
  686                 *fd, l_type == F_WRLCK ? "F_WRLCK" : "F_RDLCK");
  687 */
  688 
  689     ret = fcntl(*fd, F_SETLK, &lockthing);
  690     if (ret == -1) {
  691         if (verbose) {
  692             sprintf(msg, "Device busy. Failed to fcntl-lock '%s'",
  693                     fd_name);
  694             libdax_msgs_submit(libdax_messenger, -1, 0x00020008,
  695                 LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
  696                 msg, errno, 0);
  697         }
  698         close(*fd);
  699         *fd = -1;
  700 
  701         /* ts A70409 : DDLP-B */
  702         /* >>> release single lock on fd_name */
  703 
  704         return(0);
  705     }
  706     return 1;
  707 }
  708 
  709 
  710 /* ts A60926 */
  711 /* @param scan_mode  0= open for drivce aquiration
  712                      1= open for scanning with guessed names
  713                      2= open for scanning with /proc/sys/dev/cdrom/info names
  714 */
  715 static int sg_open_drive_fd(char *fname, int scan_mode)
  716 {
  717     int open_mode = O_RDWR, fd, tries= 0, is_std_adr, report_as_note = 0;
  718     char msg[81];
  719     struct stat stbuf;
  720 
  721     /* ts A70409 : DDLP-B */
  722     /* >>> obtain single lock on fname */
  723 
  724     /* ts A60813 - A60927
  725        O_EXCL with devices is a non-POSIX feature
  726        of Linux kernels. Possibly introduced 2002.
  727        Mentioned in "The Linux SCSI Generic (sg) HOWTO" */
  728     if(burn_sg_open_o_excl)
  729         open_mode |= O_EXCL;
  730     /* ts A60813
  731        O_NONBLOCK was already hardcoded in ata_ but not in sg_.
  732        There must be some reason for this. So O_NONBLOCK is
  733        default mode for both now. Disable on own risk.
  734            ts B10904: O_NONBLOCK is prescribed by <linux/cdrom.h>
  735        ts A70411
  736            Switched to O_NDELAY for LKML statement 2007/4/11/141 by Alan Cox:
  737        "open() has side effects. The CD layer allows you to open
  738             with O_NDELAY if you want to avoid them." 
  739     */
  740     if(burn_sg_open_o_nonblock)
  741         open_mode |= O_NDELAY;
  742 
  743 /* <<< debugging
  744     fprintf(stderr,
  745         "\nlibburn: experimental: o_excl= %d , o_nonblock= %d, abort_on_busy= %d\n",
  746     burn_sg_open_o_excl,burn_sg_open_o_nonblock,burn_sg_open_abort_busy);
  747     fprintf(stderr,
  748         "libburn: experimental: O_EXCL= %d , O_NDELAY= %d\n",
  749         !!(open_mode&O_EXCL),!!(open_mode&O_NDELAY));
  750 */
  751 
  752 try_open:;
  753     fd = open(fname, open_mode);
  754     if (fd == -1) {
  755 /* <<< debugging
  756         fprintf(stderr,
  757         "\nlibburn: experimental: fname= %s , errno= %d\n",
  758             fname,errno);
  759 */
  760         if (errno == EBUSY) {
  761             tries++;
  762 
  763 /* <<< debugging
  764             fprintf(stderr,
  765                 "\nlibburn_DEBUG: EBUSY , tries= %d\n", tries);
  766 */
  767 
  768             if (tries < 4) {
  769                 usleep(2000000);
  770                 goto try_open;
  771             }
  772             sg_handle_busy_device(fname, errno);
  773             return -1;
  774             
  775         }
  776         sprintf(msg, "Failed to open device '%s'",fname);
  777         if (scan_mode) {
  778             is_std_adr = (strncmp(fname, "/dev/sr", 7) == 0 ||
  779                           strncmp(fname, "/dev/scd", 8) == 0);
  780             if(scan_mode == 1 && is_std_adr &&
  781                stat(fname, &stbuf) != -1)
  782                 report_as_note = 1;
  783             else if(scan_mode == 2 && (!is_std_adr) &&
  784                     stat(fname, &stbuf) != -1)
  785                 report_as_note = 1;
  786             if (report_as_note)
  787                 libdax_msgs_submit(libdax_messenger, -1,
  788                    0x0002000e,
  789                    LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH,
  790                    msg, errno, 0);
  791         } else {
  792             libdax_msgs_submit(libdax_messenger, -1, 0x00020005,
  793                 LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
  794                 msg, errno, 0);
  795         }
  796         return -1;
  797     }
  798     sg_fcntl_lock(&fd, fname, F_WRLCK, 1);
  799     return fd;
  800 }
  801 
  802 
  803 /* ts A60926 */
  804 static int sg_release_siblings(int sibling_fds[],
  805                 char sibling_fnames[][BURN_OS_SG_MAX_NAMELEN],
  806                 int *sibling_count)
  807 {
  808     int i;
  809     char msg[81];
  810 
  811     for(i= 0; i < *sibling_count; i++)
  812         sg_close_drive_fd(sibling_fnames[i], -1, &(sibling_fds[i]), 0);
  813     if(*sibling_count > 0) {
  814         sprintf(msg, "Closed %d O_EXCL scsi siblings", *sibling_count);
  815         libdax_msgs_submit(libdax_messenger, -1, 0x00020007,
  816             LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH, msg, 0,0);
  817     }
  818     *sibling_count = 0;
  819     return 1;
  820 }
  821 
  822 
  823 /* ts C00806 */
  824 /** Urges the operating system to re-assess drive and medium state
  825 */
  826 static int sg_os_revalidate_disc(struct burn_drive *d)
  827 {
  828 
  829 #ifdef Libburn_use_linux_ioctl_simul_changE
  830 
  831 /* <<< only for compiler tests */
  832 #ifndef CDROM_SIMUL_CHANGE
  833 /* # def ine CDROM_SIMUL_CHANGE 0x5332 */
  834 #endif
  835 
  836 #ifdef CDROM_SIMUL_CHANGE
  837 
  838     int fd, ret;
  839     long old_blocks, new_blocks;
  840     char *msg = NULL;
  841 
  842     BURN_ALLOC_MEM(msg, char, 161);
  843 
  844     ret = ioctl(d->fd, BLKGETSIZE, &old_blocks);
  845     if (ret == -1)
  846         old_blocks = -1;
  847 
  848     /* Schedule a simulated medium change event.
  849        Although the implemented ioctl cannot fail, the kernel might be too
  850        old to know it and then throw errors like ENOTTY.
  851      */
  852     ret = ioctl(d->fd, CDROM_SIMUL_CHANGE, 0);
  853     if (ret == -1) {
  854         libdax_msgs_submit(libdax_messenger, d->global_index,
  855             0x02, LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
  856             "ioctl(CDROM_SIMUL_CHANGE) failed", errno, 0);
  857         ret = 0; goto ex;
  858     }
  859     libdax_msgs_submit(libdax_messenger, d->global_index,
  860         0x02, LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
  861         "ioctl(CDROM_SIMUL_CHANGE) was performed", 0, 0);
  862     /* Try to trigger actual device assessment by a open(2) call */
  863     fd = open(d->devname, O_RDONLY | O_NDELAY);
  864     if (fd == -1) {
  865         libdax_msgs_submit(libdax_messenger, d->global_index,
  866             0x02, LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
  867           "Failed to open device file after ioctl(CDROM_SIMUL_CHANGE)",
  868             errno, 0);
  869         ret = 0; goto ex;
  870     }
  871     close(fd);
  872     ret = ioctl(d->fd, BLKGETSIZE, &new_blocks);
  873     if (ret == -1) {
  874         libdax_msgs_submit(libdax_messenger, d->global_index,
  875             0x02, LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
  876             "BLKGETSIZE failed after ioctl(CDROM_SIMUL_CHANGE)",
  877             errno, 0);
  878     } else if (old_blocks != new_blocks) {
  879         sprintf(msg,
  880             "BLKGETSIZE indicates size change from %ld to %ld blocks",
  881             old_blocks , new_blocks);
  882         libdax_msgs_submit(libdax_messenger, d->global_index,
  883             0x02, LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
  884             msg, 0, 0);
  885     }
  886 ex:
  887     BURN_FREE_MEM(msg);
  888     return ret;
  889 
  890 #else /* CDROM_SIMUL_CHANGE */
  891 
  892     return 0;
  893 
  894 #endif /* ! CDROM_SIMUL_CHANGE */
  895 
  896 #else /* Libburn_use_linux_ioctl_simul_changE */
  897 
  898     return 0;
  899 
  900 #endif /* ! Libburn_use_linux_ioctl_simul_changE */
  901 
  902 }
  903 
  904 
  905 /* ts A60926 */
  906 static int sg_close_drive(struct burn_drive *d)
  907 {
  908     int ret;
  909 
  910     if (!burn_drive_is_open(d))
  911         return 0;
  912     sg_release_siblings(d->sibling_fds, d->sibling_fnames,
  913                 &(d->sibling_count));
  914     if(d->medium_state_changed > 0)
  915         sg_os_revalidate_disc(d);
  916     d->medium_state_changed = -1;
  917     ret = sg_close_drive_fd(d->devname, d->global_index, &(d->fd), 0);
  918     return ret;
  919 }
  920 
  921 
  922 /* ts A60926 */
  923 static int sg_open_scsi_siblings(char *path, int driveno,
  924             int sibling_fds[],
  925             char sibling_fnames[][BURN_OS_SG_MAX_NAMELEN],
  926             int *sibling_count,
  927             int host_no, int channel_no, int id_no, int lun_no)
  928 {
  929     int tld, i, ret, fd, i_bus_no = -1;
  930     int i_host_no = -1, i_channel_no = -1, i_target_no = -1, i_lun_no = -1;
  931     char *msg = NULL, fname[40];
  932     struct stat stbuf;
  933     dev_t last_rdev = 0, path_rdev;
  934 
  935     static char tldev[][20]= {"/dev/sr%d", "/dev/scd%d", "/dev/sg%d", ""};
  936                     /* ts A70609: removed "/dev/st%d" */
  937 
  938     if (strlen(path) > BURN_MSGS_MESSAGE_LEN - 160)
  939         {ret = 0; goto ex;}
  940 
  941     BURN_ALLOC_MEM(msg, char, BURN_MSGS_MESSAGE_LEN);
  942 
  943     if(stat(path, &stbuf) == -1)
  944         {ret = 0; goto ex;}
  945     path_rdev = stbuf.st_rdev;
  946 
  947         sg_select_device_family();
  948     if (linux_sg_device_family[0] == 0)
  949         {ret = 1; goto ex;}
  950 
  951     if(host_no < 0 || id_no < 0 || channel_no < 0 || lun_no < 0)
  952         {ret = 2; goto ex;}
  953     if(*sibling_count > 0)
  954         sg_release_siblings(sibling_fds, sibling_fnames,
  955                     sibling_count);
  956         
  957     for (tld = 0; tldev[tld][0] != 0; tld++) {
  958         if (strcmp(tldev[tld], linux_sg_device_family)==0)
  959     continue;
  960         for (i = 0; i < 32; i++) {
  961             sprintf(fname, tldev[tld], i);
  962             if(stat(fname, &stbuf) == -1)
  963         continue;
  964             if (path_rdev == stbuf.st_rdev)
  965         continue;
  966             if (*sibling_count > 0 && last_rdev == stbuf.st_rdev)
  967         continue;
  968             ret = sg_obtain_scsi_adr(fname, &i_bus_no, &i_host_no,
  969                 &i_channel_no, &i_target_no, &i_lun_no);
  970             if (ret <= 0)
  971         continue;
  972             if (i_host_no != host_no || i_channel_no != channel_no)
  973         continue;
  974             if (i_target_no != id_no || i_lun_no != lun_no)
  975         continue;
  976 
  977             fd = sg_open_drive_fd(fname, 0);
  978             if (fd < 0)
  979                 goto failed;
  980 
  981             if (*sibling_count>=BURN_OS_SG_MAX_SIBLINGS) {
  982                 sprintf(msg, "Too many scsi siblings of '%s'",
  983                     path);
  984                 libdax_msgs_submit(libdax_messenger,
  985                     driveno, 0x00020006,
  986                     LIBDAX_MSGS_SEV_FATAL,
  987                     LIBDAX_MSGS_PRIO_HIGH, msg, 0, 0);
  988                 goto failed;
  989             }
  990             sprintf(msg, "Opened O_EXCL scsi sibling '%s' of '%s'",
  991                 fname, path);
  992             libdax_msgs_submit(libdax_messenger, driveno,
  993                 0x00020004,
  994                 LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH,
  995                 msg, 0, 0);
  996             sibling_fds[*sibling_count] = fd;
  997             strcpy(sibling_fnames[*sibling_count], fname);
  998             (*sibling_count)++;
  999             last_rdev= stbuf.st_rdev;
 1000         }
 1001     }
 1002     ret = 1;
 1003 ex:;
 1004     BURN_FREE_MEM(msg);
 1005     return ret;
 1006 failed:;
 1007     sg_release_siblings(sibling_fds, sibling_fnames, sibling_count);
 1008     ret = 0;
 1009     goto ex;
 1010 }
 1011 
 1012 
 1013 /* ts A80731 */
 1014 static int is_ata_drive(char *fname, int fd_in)
 1015 {
 1016     int fd;
 1017     struct hd_driveid tm;
 1018 
 1019     if (fd_in >= 0)
 1020         fd = fd_in;
 1021     else
 1022         fd = sg_open_drive_fd(fname, 1);
 1023     if (fd == -1) {
 1024         if (linux_ata_enumerate_verbose)
 1025             fprintf(stderr,"open failed, errno=%d  '%s'\n",
 1026                 errno, strerror(errno));
 1027         return 0;
 1028     }
 1029 
 1030     memset(&tm, 0, sizeof(tm));
 1031     ioctl(fd, HDIO_GET_IDENTITY, &tm);
 1032 
 1033         /* not atapi */
 1034     if (!(tm.config & 0x8000) || (tm.config & 0x4000)) {
 1035         if (linux_ata_enumerate_verbose)
 1036             fprintf(stderr, "not marked as ATAPI\n");
 1037         if (fd_in < 0)
 1038             sg_close_drive_fd(fname, -1, &fd, 0);
 1039         return 0;
 1040     }
 1041 
 1042     /* if SG_IO fails on an atapi device, we should stop trying to 
 1043        use hd* devices */
 1044     if (sgio_test(fd) == -1) {
 1045         if (linux_ata_enumerate_verbose)
 1046           fprintf(stderr,
 1047              "FATAL: sgio_test() failed: errno=%d  '%s'\n",
 1048              errno, strerror(errno));
 1049         if (fd_in < 0)
 1050             sg_close_drive_fd(fname, -1, &fd, 0);
 1051         return 0;
 1052     }
 1053     if (fd_in >= 0)
 1054         return 1;
 1055     if (sg_close_drive_fd(fname, -1, &fd, 1) <= 0) {
 1056         if (linux_ata_enumerate_verbose)
 1057             fprintf(stderr,
 1058                 "cannot close properly, errno=%d  '%s'\n",
 1059                 errno, strerror(errno));
 1060         return 0;
 1061     }
 1062     return 1;
 1063 }
 1064 
 1065 
 1066 static int is_scsi_drive(char *fname, int fd_in, int *bus_no, int *host_no,
 1067              int *channel_no, int *target_no, int *lun_no)
 1068 {
 1069     int fd = -1, sid_ret = 0, ret, fail_sev_sorry = 0;
 1070     struct sg_scsi_id sid;
 1071     int *sibling_fds = NULL, sibling_count= 0;
 1072     typedef char burn_sg_sibling_fname[BURN_OS_SG_MAX_NAMELEN];
 1073     burn_sg_sibling_fname *sibling_fnames = NULL;
 1074 
 1075     BURN_ALLOC_MEM(sibling_fds, int, BURN_OS_SG_MAX_SIBLINGS);
 1076     BURN_ALLOC_MEM(sibling_fnames, burn_sg_sibling_fname,
 1077             BURN_OS_SG_MAX_SIBLINGS);
 1078 
 1079     if (fd_in >= 0)
 1080         fd = fd_in;
 1081     else
 1082         fd = sg_open_drive_fd(fname, 1);
 1083     if (fd == -1) {
 1084         if (linux_sg_enumerate_debug)
 1085             fprintf(stderr, "open failed, errno=%d  '%s'\n",
 1086                 errno, strerror(errno));
 1087         {ret = 0; goto ex;}
 1088     }
 1089     sid_ret = ioctl(fd, SG_GET_SCSI_ID, &sid);
 1090     if (sid_ret == -1) {
 1091         sid.scsi_id = -1; /* mark SCSI address as invalid */
 1092         if(linux_sg_enumerate_debug) 
 1093             fprintf(stderr,
 1094             "ioctl(SG_GET_SCSI_ID) failed, errno=%d  '%s' , ",
 1095             errno, strerror(errno));
 1096 
 1097         if (sgio_test(fd) == -1) {
 1098             if (linux_sg_enumerate_debug)
 1099                 fprintf(stderr,
 1100                  "FATAL: sgio_test() failed: errno=%d  '%s'",
 1101                 errno, strerror(errno));
 1102 
 1103             {ret = 0; goto ex;}
 1104         }
 1105 
 1106 #ifdef CDROM_DRIVE_STATUS
 1107         /* http://developer.osdl.org/dev/robustmutexes/
 1108               src/fusyn.hg/Documentation/ioctl/cdrom.txt */
 1109         sid_ret = ioctl(fd, CDROM_DRIVE_STATUS, 0);
 1110         if(linux_sg_enumerate_debug)
 1111               fprintf(stderr,
 1112                 "ioctl(CDROM_DRIVE_STATUS) = %d , ",
 1113                 sid_ret);
 1114         if (sid_ret != -1 && sid_ret != CDS_NO_INFO)
 1115             sid.scsi_type = TYPE_ROM;
 1116         else
 1117             sid_ret = -1;
 1118 #endif /* CDROM_DRIVE_STATUS */
 1119 
 1120     }
 1121 
 1122     if (sid_ret == -1) {
 1123         /* ts B11109 : Try device type from INQUIRY byte 0 */
 1124         if (sgio_inquiry_cd_drive(fd, fname) == 1) {
 1125             sid_ret = 0;
 1126             sid.scsi_type = TYPE_ROM;
 1127         }
 1128     }
 1129 
 1130 
 1131 #ifdef SCSI_IOCTL_GET_BUS_NUMBER
 1132     /* Hearsay A61005 */
 1133     if (ioctl(fd, SCSI_IOCTL_GET_BUS_NUMBER, bus_no) == -1)
 1134         *bus_no = -1;
 1135 #endif
 1136 
 1137     fail_sev_sorry = (sid.scsi_type == TYPE_ROM);
 1138     if ( (sid_ret == -1 || sid.scsi_type != TYPE_ROM)
 1139          && !linux_sg_accept_any_type) {
 1140         if (linux_sg_enumerate_debug)
 1141             fprintf(stderr, "sid.scsi_type = %d (!= TYPE_ROM)\n",
 1142                 sid.scsi_type); 
 1143         {ret = 0; goto ex;}
 1144     }
 1145 
 1146     /* ts A61211 : employ a more general ioctl */
 1147     /* ts B11001 : re-use fd */
 1148     /* ts B80902 : call unconditionally because host_no differs
 1149                    between SG_GET_SCSI_ID and SCSI_IOCTL_GET_IDLUN
 1150     */
 1151     ret = sg_obtain_scsi_adr_fd(fname, fd, bus_no, host_no,
 1152                     channel_no, target_no, lun_no);
 1153     if (ret <= 0) {
 1154         if (linux_sg_enumerate_debug)
 1155             fprintf(stderr,
 1156                 "sg_obtain_scsi_adr_fd() failed\n");
 1157         {ret = 0; goto ex;}
 1158     }
 1159 
 1160     /* ts A60927 : trying to do locking with growisofs */
 1161     if(burn_sg_open_o_excl>1) {
 1162         ret = sg_open_scsi_siblings(
 1163                 fname, -1, sibling_fds, sibling_fnames,
 1164                 &sibling_count,
 1165                 sid.host_no, sid.channel,
 1166                 sid.scsi_id, sid.lun);
 1167         if (ret<=0) {
 1168             if (linux_sg_enumerate_debug)
 1169                 fprintf(stderr, "cannot lock siblings\n"); 
 1170             sg_handle_busy_device(fname, 0);
 1171             {ret = 0; goto ex;}
 1172         }
 1173         /* the final occupation will be done in sg_grab() */
 1174         sg_release_siblings(sibling_fds, sibling_fnames,
 1175                             &sibling_count);
 1176     }
 1177     ret = 1;
 1178 ex:;
 1179     if (fd_in < 0 && fd >= 0) {
 1180         if (sg_close_drive_fd(fname, -1, &fd, fail_sev_sorry) <= 0) {
 1181             if (linux_sg_enumerate_debug)
 1182                 fprintf(stderr,
 1183                 "cannot close properly, errno=%d  '%s'\n",
 1184                 errno, strerror(errno)); 
 1185             if (ret > 0)
 1186                 ret = 0;
 1187         }
 1188     }
 1189     BURN_FREE_MEM(sibling_fds);
 1190     BURN_FREE_MEM(sibling_fnames);
 1191     return ret;
 1192 }   
 1193 
 1194 
 1195 /* @param flag bit0= do not complain about failure to open /dev/sr /dev/scd */
 1196 static int sg_open_for_enumeration(char *fname, int flag)
 1197 {
 1198     int fd;
 1199 
 1200     fd = sg_open_drive_fd(fname, 1 + (flag & 1));
 1201     if (fd < 0) {
 1202         if (linux_sg_enumerate_debug || linux_ata_enumerate_verbose)
 1203             fprintf(stderr, "open failed, errno=%d  '%s'\n",
 1204                 errno, strerror(errno));
 1205         return -1;
 1206     }
 1207     return fd;
 1208 }
 1209 
 1210 
 1211 /** Speciality of GNU/Linux: detect non-SCSI ATAPI (EIDE) which will from
 1212    then on used used via generic SCSI as is done with (emulated) SCSI drives */ 
 1213 static void ata_enumerate(void)
 1214 {
 1215     int ret, i, fd = -1;
 1216     char fname[10];
 1217 
 1218     if (linux_ata_enumerate_verbose)
 1219       fprintf(stderr, "libburn_debug: linux_ata_device_family = %s\n",
 1220           linux_ata_device_family);
 1221 
 1222     if (linux_ata_device_family[0] == 0)
 1223         return;
 1224 
 1225     for (i = 0; i < 26; i++) {
 1226         sprintf(fname, linux_ata_device_family, 'a' + i);
 1227         if (linux_ata_enumerate_verbose)
 1228           fprintf(stderr, "libburn_debug: %s : ", fname);
 1229 
 1230         /* ts A51221 */
 1231         if (burn_drive_is_banned(fname)) {
 1232             if (linux_ata_enumerate_verbose)
 1233                 fprintf(stderr, "not in whitelist\n");
 1234     continue;
 1235         }
 1236         fd = sg_open_for_enumeration(fname, 0);
 1237         if (fd < 0)
 1238     continue;
 1239         ret = is_ata_drive(fname, fd);
 1240         if (ret < 0)
 1241     break;
 1242         if (ret == 0)
 1243     continue;
 1244         if (linux_ata_enumerate_verbose)
 1245           fprintf(stderr, "accepting as drive without SCSI address\n");
 1246         enumerate_common(fname, fd, -1, -1, -1, -1, -1);
 1247     }
 1248 }
 1249 
 1250 
 1251 /** Detects (probably emulated) SCSI drives */
 1252 static void sg_enumerate(void)
 1253 {
 1254     int i, ret, fd = -1;
 1255     int bus_no= -1, host_no= -1, channel_no= -1, target_no= -1, lun_no= -1;
 1256     char fname[17];
 1257 
 1258         sg_select_device_family();
 1259 
 1260     if (linux_sg_enumerate_debug)
 1261       fprintf(stderr, "libburn_debug: linux_sg_device_family = %s\n",
 1262           linux_sg_device_family);
 1263 
 1264     if (linux_sg_device_family[0] == 0)
 1265         return;
 1266 
 1267     for (i = 0; i < 32; i++) {
 1268         sprintf(fname, linux_sg_device_family, i);
 1269 
 1270         /* ts A80702 */
 1271         sg_exchange_scd_for_sr(fname, 0);
 1272 
 1273         if (linux_sg_enumerate_debug)
 1274           fprintf(stderr, "libburn_debug: %s : ", fname);
 1275 
 1276         /* ts A51221 */
 1277         if (burn_drive_is_banned(fname)) {
 1278             if (linux_sg_enumerate_debug)
 1279               fprintf(stderr, "not in whitelist\n"); 
 1280     continue;
 1281         }
 1282         fd = sg_open_for_enumeration(fname, 0);
 1283         if (fd < 0)
 1284     continue;
 1285 
 1286         ret = is_scsi_drive(fname, fd, &bus_no, &host_no, &channel_no,
 1287                             &target_no, &lun_no);
 1288         if (ret < 0)
 1289     break;
 1290         if (ret == 0)
 1291     continue;
 1292         if (linux_sg_enumerate_debug)
 1293           fprintf(stderr, "accepting as SCSI %d,%d,%d,%d bus=%d\n",
 1294               host_no, channel_no, target_no, lun_no, bus_no);
 1295         enumerate_common(fname, fd, bus_no, host_no, channel_no, 
 1296                 target_no, lun_no);
 1297 
 1298     }
 1299 }
 1300 
 1301 
 1302 
 1303 /* ts A80805 : eventually produce the other official name of a device file */
 1304 static int fname_other_name(char *fname, char other_name[80], int flag)
 1305 {
 1306     if(strncmp(fname, "/dev/sr", 7) == 0 &&
 1307        (fname[7] >= '0' && fname[7] <= '9') &&
 1308            (fname[8] == 0 ||
 1309         (fname[8] >= '0' && fname[8] <= '9' && fname[9] == 0))) {
 1310         sprintf(other_name, "/dev/scd%s", fname + 7);
 1311         return 1;
 1312     }
 1313     if(strncmp(fname, "/dev/scd", 8) == 0 &&
 1314        (fname[8] >= '0' && fname[8] <= '9') &&
 1315            (fname[9] == 0 ||
 1316         (fname[9] >= '0' && fname[9] <= '9' && fname[10] == 0))) {
 1317         sprintf(other_name, "/dev/sr%s", fname + 8);
 1318         return 1;
 1319     }
 1320     return 0;
 1321 }
 1322 
 1323 
 1324 /* ts A80805 */
 1325 static int fname_drive_is_listed(char *fname, int flag)
 1326 {
 1327     char other_fname[80];
 1328 
 1329     if (burn_drive_is_listed(fname, NULL, 0))
 1330         return 1;
 1331     if (fname_other_name(fname, other_fname, 0) > 0)
 1332         if (burn_drive_is_listed(other_fname, NULL, 0))
 1333             return 2;
 1334     return 0;
 1335 }
 1336 
 1337 
 1338 /* ts A80731 : Directly open the given address.
 1339    @param flag bit0= do not complain about missing file
 1340                bit1= do not check whether drive is already listed
 1341                bit2= do not complain about failure to open /dev/sr /dev/scd
 1342 */
 1343 static int fname_enumerate(char *fname, int flag)
 1344 {
 1345     int is_ata= 0, is_scsi= 0, ret, fd = -1;
 1346     int bus_no= -1, host_no= -1, channel_no= -1, target_no= -1, lun_no= -1;
 1347     char *msg = NULL;
 1348     struct stat stbuf;
 1349 
 1350     BURN_ALLOC_MEM(msg, char, BURN_DRIVE_ADR_LEN + 80);
 1351 
 1352     if (!(flag & 2))
 1353         if (fname_drive_is_listed(fname, 0))
 1354             {ret = 2; goto ex;}
 1355     if (stat(fname, &stbuf) == -1) {
 1356         sprintf(msg, "File object '%s' not found", fname);
 1357         if (!(flag & 1))
 1358             libdax_msgs_submit(libdax_messenger, -1, 0x0002000b,
 1359               LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
 1360               msg, 0, 0);
 1361         {ret = -1; goto ex;}
 1362     }
 1363 
 1364     fd = sg_open_for_enumeration(fname, !!(flag & 4));
 1365     if (fd < 0)
 1366         {ret = 0; goto ex;}
 1367     is_ata = is_ata_drive(fname, fd);
 1368     if (is_ata < 0)
 1369         {ret = -1; goto ex;}
 1370     if (!is_ata)
 1371         is_scsi = is_scsi_drive(fname, fd, &bus_no, &host_no,
 1372                     &channel_no, &target_no, &lun_no);
 1373     if (is_scsi < 0)
 1374         {ret = -1; goto ex;}
 1375     if (is_ata == 0 && is_scsi == 0)
 1376         {ret = 0; goto ex;}
 1377 
 1378     if (linux_sg_enumerate_debug)
 1379           fprintf(stderr,
 1380             "(single) accepting as SCSI %d,%d,%d,%d bus=%d\n",
 1381             host_no, channel_no, target_no, lun_no, bus_no);
 1382 
 1383     enumerate_common(fname, fd, bus_no, host_no, channel_no, 
 1384                 target_no, lun_no);
 1385     ret = 1;
 1386 ex:;
 1387     BURN_FREE_MEM(msg);
 1388     return ret;
 1389 }
 1390 
 1391 
 1392 /* ts A80731 : Directly open the given address from a single-item whitlist */
 1393 static int single_enumerate(int flag)
 1394 {
 1395     int ret, wl_count;
 1396     char *fname, *msg = NULL;
 1397 
 1398         wl_count= burn_drive_whitelist_count();
 1399     if (wl_count != 1)
 1400         {ret = 0; goto ex;}
 1401     fname= burn_drive_whitelist_item(0, 0);
 1402     if (fname == NULL)
 1403         {ret = 0; goto ex;}
 1404     ret = fname_enumerate(fname, 2);
 1405     if (ret <= 0) {
 1406         BURN_ALLOC_MEM(msg, char, BURN_DRIVE_ADR_LEN + 80);
 1407         sprintf(msg, "Cannot access '%s' as SG_IO CDROM drive", fname);
 1408         libdax_msgs_submit(libdax_messenger, -1, 0x0002000a,
 1409             LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
 1410             msg, 0, 0);
 1411         ret = -1;
 1412     }
 1413 ex:;
 1414     BURN_FREE_MEM(msg);
 1415     return ret;
 1416 }
 1417 
 1418 
 1419 /* ts A80801 : looking up drives listed in /proc/sys/dev/cdrom/info line like:
 1420                 drive name:             sr1     hdc     hda     sr0
 1421    @parm flag bit0= release list memory and exit
 1422 */
 1423 static int proc_sys_dev_cdrom_info(char ***list, int *count, int flag)
 1424 {
 1425     FILE *fp;
 1426     char *line = NULL, *fname = NULL, *cpt, *retpt, *list_data;
 1427     int maxl= 0, pass, i, line_size = 1024, ret;
 1428 
 1429     BURN_ALLOC_MEM(line, char, line_size);
 1430     BURN_ALLOC_MEM(fname, char, line_size + 5);
 1431 
 1432     if (*list != NULL) {
 1433         if ((*list)[0] != NULL)
 1434             free((*list)[0]);
 1435         free(*list);
 1436         *list = NULL;
 1437         *count = 0;
 1438     }
 1439     if (flag & 1) 
 1440         {ret = 1; goto ex;}
 1441 
 1442     *count = 0;
 1443     sg_evaluate_kernel();
 1444     if (sg_kernel_age < 2) /* addresses are not suitable for kernel 2.4 */
 1445         {ret = 1; goto ex;}
 1446     fp = fopen("/proc/sys/dev/cdrom/info", "r");
 1447     if (fp == NULL)
 1448         {ret = 0; goto ex;}
 1449     while (1) {
 1450         retpt = fgets(line, line_size, fp);
 1451         if (retpt == NULL)
 1452     break;
 1453         if(strncmp(line, "drive name:", 11) == 0)
 1454     break;
 1455     }
 1456     fclose(fp);
 1457     if (retpt == NULL)
 1458         {ret = 0; goto ex;}
 1459     strcpy(fname, "/dev/");
 1460     for(pass = 0; pass < 2; pass++) {
 1461         *count = 0;
 1462         cpt = line + 11;
 1463         while (*cpt != 0) {
 1464             for(; *cpt == ' ' || *cpt == '\t'; cpt++);
 1465             if (*cpt == 0 || *cpt == '\n')
 1466         break;
 1467             sscanf(cpt, "%s", fname + 5);
 1468             if ((int) strlen(fname) > maxl)
 1469                 maxl = strlen(fname);
 1470             if (pass == 1)
 1471                 strcpy((*list)[*count], fname);
 1472             (*count)++;
 1473             for(cpt++; *cpt != ' ' && *cpt != '\t'
 1474                      && *cpt != 0 && *cpt != '\n'; cpt++);
 1475         }
 1476         if (pass == 0) {
 1477             list_data = calloc(*count + 1, maxl+1);
 1478             *list = calloc(*count + 1, sizeof(char *));
 1479             if(list_data == NULL || *list == NULL) {
 1480                 libdax_msgs_submit(libdax_messenger, -1,
 1481                 0x00000003,
 1482                 LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
 1483                 "Out of virtual memory", 0, 0);
 1484                 if (list_data != NULL)
 1485                     free(list_data);
 1486                 if (*list != NULL)
 1487                     free((char *) *list);
 1488                 {ret = -1; goto ex;}
 1489             }
 1490             for (i = 0; i <= *count; i++)
 1491                 (*list)[i] = list_data + i * (maxl + 1);
 1492         }
 1493     }
 1494     ret = 1;
 1495 ex:;
 1496     BURN_FREE_MEM(line);
 1497     BURN_FREE_MEM(fname);
 1498     return ret;
 1499 }
 1500 
 1501 
 1502 static int add_proc_info_drives(int flag)
 1503 {
 1504     int ret, list_count, count = 0, i;
 1505     char **list= NULL;
 1506 
 1507     if (burn_sg_use_family != 0)
 1508         return(1); /* Looking only for sr , scd , sg */
 1509 
 1510     ret = proc_sys_dev_cdrom_info(&list, &list_count, 0);
 1511     if (ret <= 0)
 1512         return ret;
 1513     for (i = 0; i < list_count; i++) {
 1514         if (burn_drive_is_banned(list[i]))
 1515     continue;
 1516         ret = fname_enumerate(list[i], 1 | 4);
 1517         if (ret == 1)
 1518             count++;
 1519     }
 1520     proc_sys_dev_cdrom_info(&list, &list_count, 1); /* free memory */
 1521     return 1 + count;
 1522 }
 1523 
 1524 
 1525 /* ts A61115 */
 1526 /* ----------------------------------------------------------------------- */
 1527 /* PORTING: Private functions which contain publicly needed functionality. */
 1528 /*          Their portable part must be performed. So it is probably best  */
 1529 /*          to replace the non-portable part and to call these functions   */
 1530 /*          in your port, too.                                             */
 1531 /* ----------------------------------------------------------------------- */
 1532 
 1533 
 1534 /** Wraps a detected drive into libburn structures and hands it over to
 1535     libburn drive list.
 1536 */
 1537 /* ts A60923 - A61005 : introduced new SCSI parameters */
 1538 /* ts A61021 : moved non os-specific code to spc,sbc,mmc,drive */
 1539 static void enumerate_common(char *fname, int fd_in, int bus_no, int host_no,
 1540                  int channel_no, int target_no, int lun_no)
 1541 {
 1542     int ret, i;
 1543     struct burn_drive out;
 1544 
 1545     /* General libburn drive setup */
 1546     burn_setup_drive(&out, fname);
 1547 
 1548     /* This transport adapter uses SCSI-family commands and models
 1549            (seems the adapter would know better than its boss, if ever) */
 1550     ret = burn_scsi_setup_drive(&out, bus_no, host_no, channel_no,
 1551                     target_no, lun_no, 0);
 1552     if (ret<=0)
 1553         return;
 1554 
 1555     /* PORTING: ------------------- non portable part --------------- */
 1556 
 1557     /* Operating system adapter is GNU/Linux Generic SCSI (sg) */
 1558     /* Adapter specific handles and data */
 1559     out.fd = -1337;
 1560     out.sibling_count = 0;
 1561     for(i= 0; i<BURN_OS_SG_MAX_SIBLINGS; i++)
 1562         out.sibling_fds[i] = -1337;
 1563 
 1564     /* PORTING: ---------------- end of non portable part ------------ */
 1565 
 1566     /* Adapter specific functions with standardized names */
 1567     out.grab = sg_grab;
 1568     out.release = sg_release;
 1569     out.drive_is_open= sg_drive_is_open;
 1570     out.issue_command = sg_issue_command;
 1571     if (fd_in >= 0)
 1572         out.fd = fd_in;
 1573 
 1574     /* Finally register drive and inquire drive information.
 1575        out is an invalid copy afterwards. Do not use it for anything.
 1576      */
 1577     burn_drive_finish_enum(&out);
 1578 }
 1579 
 1580 
 1581 /* ts A61115 */
 1582 /* ------------------------------------------------------------------------ */
 1583 /* PORTING:           Public functions. These MUST be ported.               */
 1584 /* ------------------------------------------------------------------------ */
 1585 
 1586 
 1587 /** Returns the id string  of the SCSI transport adapter and eventually
 1588     needed operating system facilities.
 1589     This call is usable even if sg_initialize() was not called yet. In that
 1590     case a preliminary constant message might be issued if detailed info is
 1591     not available yet.
 1592     @param msg   returns id string
 1593     @param flag  unused yet, submit 0
 1594     @return      1 = success, <=0 = failure
 1595 */
 1596 int sg_id_string(char msg[1024], int flag)
 1597 {
 1598     strcpy(msg, "internal GNU/Linux SG_IO adapter sg-linux");
 1599     return 1;
 1600 }
 1601 
 1602 
 1603 /** Performs global initialization of the SCSI transport adapter and eventually
 1604     needed operating system facilities. Checks for compatibility supporting
 1605     software components.
 1606     @param msg   returns ids and/or error messages of eventual helpers
 1607     @param flag  unused yet, submit 0
 1608     @return      1 = success, <=0 = failure
 1609 */
 1610 int sg_initialize(char msg[1024], int flag)
 1611 {
 1612     return sg_id_string(msg, 0);
 1613 }
 1614 
 1615 
 1616 /** Performs global finalization of the SCSI transport adapter and eventually
 1617     needed operating system facilities. Releases globally acquired resources.
 1618     @param flag  unused yet, submit 0
 1619     @return      1 = success, <=0 = failure
 1620 */  
 1621 int sg_shutdown(int flag)
 1622 {
 1623     return 1;
 1624 }
 1625 
 1626 
 1627 /** Finalizes BURN_OS_TRANSPORT_DRIVE_ELEMENTS, the components of
 1628     struct burn_drive which are defined in os-*.h.
 1629     The eventual initialization of those components was made underneath
 1630     scsi_enumerate_drives().
 1631     This will be called when a burn_drive gets disposed.
 1632     @param d     the drive to be finalized
 1633     @param flag  unused yet, submit 0
 1634     @return      1 = success, <=0 = failure
 1635 */
 1636 int sg_dispose_drive(struct burn_drive *d, int flag)
 1637 {
 1638         return 1;
 1639 }
 1640 
 1641 
 1642 /** PORTING:
 1643     In this GNU/Linux implementation, this function mirrors the enumeration
 1644     done in sg_enumerate and ata_enumerate(). It would be better to base those
 1645     functions on this sg_give_next_adr() but the situation is not inviting. 
 1646 */
 1647 /* ts A60922 ticket 33 : called from drive.c */
 1648 /** Returns the next index number and the next enumerated drive address.
 1649     The enumeration has to cover all available and accessible drives. It is
 1650     allowed to return addresses of drives which are not available but under
 1651     some (even exotic) circumstances could be available. It is on the other
 1652     hand allowed, only to hand out addresses which can really be used right
 1653     in the moment of this call. (This implementation chooses the former.)
 1654     @param idx An opaque handle. Make no own theories about it.
 1655     @param adr Takes the reply
 1656     @param adr_size Gives maximum size of reply including final 0
 1657     @param initialize  1 = start new,
 1658                        0 = continue, use no other values for now
 1659                       -1 = finish
 1660     @return 1 = reply is a valid address , 0 = no further address available
 1661            -1 = severe error (e.g. adr_size too small)
 1662 */
 1663 int sg_give_next_adr(burn_drive_enumerator_t *idx,
 1664              char adr[], int adr_size, int initialize)
 1665 {
 1666     /* os-linux.h : typedef int burn_drive_enumerator_t; */
 1667     static int sg_limit = 32, ata_limit = 26;
 1668     int baseno = 0, i;
 1669     char other_name[80];
 1670 
 1671     if (initialize == -1) {
 1672         proc_sys_dev_cdrom_info(&(idx->info_list), &(idx->info_count),
 1673                     1);
 1674         return 0;
 1675     }
 1676 
 1677         sg_select_device_family();
 1678     if (linux_sg_device_family[0] == 0)
 1679         sg_limit = 0;
 1680     if (linux_ata_device_family[0] == 0)
 1681         ata_limit = 0;
 1682 
 1683     if (initialize  == 1) {
 1684         idx->pos = -1;
 1685         idx->info_count= 0;
 1686         idx->info_list= NULL;
 1687         proc_sys_dev_cdrom_info(&(idx->info_list), &(idx->info_count),
 1688                     0);
 1689     }
 1690     (idx->pos)++;
 1691     if (idx->pos >= sg_limit)
 1692         goto next_ata;
 1693     if (adr_size < 11)
 1694         return -1;
 1695     sprintf(adr, linux_sg_device_family, idx->pos);
 1696 
 1697     sg_exchange_scd_for_sr(adr, 0);
 1698     goto return_1_pre_proc;
 1699 
 1700 next_ata:;
 1701     baseno += sg_limit;
 1702     if (idx->pos - baseno >= ata_limit)
 1703         goto next_proc_info;
 1704     if (adr_size < 9)
 1705         return -1;
 1706     sprintf(adr, linux_ata_device_family, 'a' + (idx->pos - baseno));
 1707     goto return_1_pre_proc;
 1708 
 1709 next_proc_info:;
 1710     baseno += ata_limit;
 1711     if (burn_sg_use_family != 0) /* Only with default enumeration */
 1712         return 0;
 1713     for (i = 0; i < idx->info_count; i++) {
 1714         if ((idx->info_list)[i][0] == 0)
 1715     continue;
 1716         if (baseno == idx->pos) {
 1717             if (adr_size < (int) strlen((idx->info_list)[i]) + 1)
 1718                 return -1;
 1719             strcpy(adr, (idx->info_list)[i]);
 1720             return 1;
 1721         }
 1722         baseno++;
 1723     }
 1724     return 0;
 1725 
 1726 return_1_pre_proc:;
 1727     for (i = 0; i < idx->info_count; i++) {
 1728         if (strcmp((idx->info_list)[i], adr) == 0)
 1729             (idx->info_list)[i][0] = 0;
 1730             if (fname_other_name(adr, other_name, 0) > 0)
 1731             if (strcmp((idx->info_list)[i], other_name) == 0)
 1732                 (idx->info_list)[i][0] = 0;
 1733     }
 1734     return 1;
 1735 }
 1736 
 1737 
 1738 /** Brings all available, not-whitelist-banned, and accessible drives into
 1739     libburn's list of drives.
 1740 */
 1741 /** PORTING:
 1742     If not stricken with an incompletely unified situation like in GNU/Linux
 1743     one would rather implement this by a loop calling sg_give_next_adr().
 1744     If needed with your sg_give_next_adr() results, do a test for existence
 1745     and accessability. If burn activities are prone to external interference
 1746     on your system it is also necessary to obtain exclusive access locks on
 1747     the drives.
 1748     Hand over each accepted drive to enumerate_common() or its replacement
 1749     within your port.
 1750 
 1751     See FreeBSD port sketch sg-freebsd-port.c for such an implementation.
 1752 */
 1753 /* ts A61115: replacing call to sg-implementation internals from drive.c */
 1754 int scsi_enumerate_drives(void)
 1755 {
 1756     int ret;
 1757 
 1758     /* Direct examination of eventually single whitelisted name */
 1759     ret = single_enumerate(0);
 1760     if (ret < 0)
 1761         return -1;
 1762     if (ret > 0)
 1763         return 1;
 1764 
 1765     sg_enumerate();
 1766     ata_enumerate();
 1767     add_proc_info_drives(0);
 1768     return 1;
 1769 }
 1770 
 1771 
 1772 /** Tells whether libburn has the given drive in use or exclusively reserved.
 1773     If it is "open" then libburn will eventually call sg_release() on it when
 1774     it is time to give up usage and reservation.
 1775 */
 1776 /** Published as burn_drive.drive_is_open() */
 1777 int sg_drive_is_open(struct burn_drive * d)
 1778 {
 1779     /* a bit more detailed case distinction than needed */
 1780     if (d->fd == -1337)
 1781         return 0;
 1782     if (d->fd < 0)
 1783         return 0;
 1784     return 1;
 1785 }
 1786 
 1787 
 1788 /** Opens the drive for SCSI commands and - if burn activities are prone
 1789     to external interference on your system - obtains an exclusive access lock
 1790     on the drive. (Note: this is not physical tray locking.)
 1791     A drive that has been opened with sg_grab() will eventually be handed
 1792     over to sg_release() for closing and unreserving.
 1793 */
 1794 int sg_grab(struct burn_drive *d)
 1795 {
 1796     int fd, os_errno= 0, ret;
 1797     int max_tries = 3, tries = 0;
 1798 
 1799     /* ts A60813 */
 1800     int open_mode = O_RDWR;
 1801 
 1802 /* ts A60821
 1803    <<< debug: for tracing calls which might use open drive fds */
 1804     if (mmc_function_spy(d, "sg_grab") <= 0)
 1805         return 0;
 1806 
 1807 
 1808     /* ts A60813 - A60927
 1809        O_EXCL with devices is a non-POSIX feature
 1810        of Linux kernels. Possibly introduced 2002.
 1811        Mentioned in "The Linux SCSI Generic (sg) HOWTO".
 1812     */
 1813     if(burn_sg_open_o_excl)
 1814         open_mode |= O_EXCL;
 1815 
 1816     /* ts A60813
 1817        O_NONBLOCK was hardcoded here. So it should stay default mode.
 1818        ts A70411
 1819            Switched to O_NDELAY for LKML statement 2007/4/11/141
 1820     */
 1821     if(burn_sg_open_o_nonblock)
 1822         open_mode |= O_NDELAY;
 1823 
 1824     /* ts A60813 - A60822
 1825        After enumeration the drive fd is probably still open.
 1826        -1337 is the initial value of burn_drive.fd and the value after
 1827        release of drive. Unclear why not the official error return
 1828        value -1 of open(2) war used. */
 1829     if(! burn_drive_is_open(d)) {
 1830         char msg[120];
 1831 
 1832 /* >>> SINGLE_OPEN : This case should be impossible now, since enumeration
 1833                      transfers the fd from scanning to drive.
 1834                      So if close-wait-open is desired, then it has to
 1835                      be done unconditionally.
 1836 */
 1837 
 1838 #ifndef Libburn_udev_wait_useC
 1839 #define Libburn_udev_wait_useC 100000
 1840 #endif
 1841 
 1842 #ifndef Libburn_udev_extra_open_cyclE
 1843 
 1844     if (Libburn_udev_wait_useC > 0) {
 1845         /* ts B10921 : workaround for udev which might get
 1846                 a kernel event from open() and might
 1847                 remove links if it cannot inspect the
 1848                 drive. This waiting period shall allow udev
 1849                 to act after it was woken up by the drive scan
 1850                 activities.
 1851         */
 1852         sprintf(msg,
 1853         "To avoid collision with udev: Waiting %lu usec before grabbing",
 1854                 (unsigned long) Libburn_udev_wait_useC);
 1855         libdax_msgs_submit(libdax_messenger, -1, 0x00000002,
 1856                 LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
 1857                 msg, 0, 0);
 1858         usleep(Libburn_udev_wait_useC);
 1859     }
 1860 
 1861 #endif /* Libburn_udev_extra_open_cyclE */
 1862 
 1863 
 1864 try_open:;
 1865         /* ts A60821
 1866         <<< debug: for tracing calls which might use open drive fds */
 1867         mmc_function_spy(NULL, "sg_grab ----------- opening");
 1868 
 1869         /* ts A70409 : DDLP-B */
 1870         /* >>> obtain single lock on d->devname */
 1871 
 1872         /* ts A60926 */
 1873         if(burn_sg_open_o_excl>1) {
 1874             fd = -1;
 1875             ret = sg_open_scsi_siblings(d->devname,
 1876                     d->global_index,d->sibling_fds,
 1877                     d->sibling_fnames,&(d->sibling_count),
 1878                     d->host, d->channel, d->id, d->lun);
 1879             if(ret <= 0)
 1880                 goto drive_is_in_use;
 1881         }
 1882         fd = open(d->devname, open_mode);
 1883         os_errno = errno;
 1884 
 1885 #ifdef Libburn_udev_extra_open_cyclE
 1886 
 1887         /* ts B10920 : workaround for udev which might get
 1888                 a kernel event from open() and might
 1889                 remove links if it cannot inspect the
 1890                 drive.
 1891            ts B10921 : this is more obtrusive than above waiting
 1892                 before open(). The drive scan already has
 1893                 opened and closed the drive several times.
 1894                 So it seems to be merely about giving an
 1895                 opportunity to udev, before long term grabbing
 1896                 happens.
 1897         */
 1898         if (fd >= 0 && Libburn_udev_wait_useC > 0) {
 1899             close(fd);
 1900             sprintf(msg,
 1901         "To avoid collision with udev: Waiting %lu usec before re-opening",
 1902                 (unsigned long) Libburn_udev_wait_useC);
 1903             libdax_msgs_submit(libdax_messenger, -1, 0x00000002,
 1904                 LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
 1905                 msg, 0, 0);
 1906             usleep(Libburn_udev_wait_useC);
 1907             fd = open(d->devname, open_mode);
 1908             os_errno = errno;
 1909         }
 1910 #endif /* Libburn_udev_extra_open_cyclE */
 1911 
 1912         if (fd >= 0) {
 1913             sg_fcntl_lock(&fd, d->devname, F_WRLCK, 1);
 1914             if (fd < 0)
 1915                 goto drive_is_in_use;
 1916         }
 1917     } else
 1918         fd= d->fd;
 1919 
 1920     if (fd >= 0) {
 1921         d->fd = fd;
 1922         fcntl(fd, F_SETOWN, getpid());
 1923         d->released = 0;
 1924         return 1;
 1925     } else if (errno == EBUSY)
 1926         goto drive_is_in_use;
 1927     libdax_msgs_submit(libdax_messenger, d->global_index, 0x00020003,
 1928             LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
 1929             "Could not grab drive", os_errno, 0);
 1930     return 0;
 1931 
 1932 drive_is_in_use:;
 1933     tries++;
 1934     if (tries < max_tries) {
 1935         libdax_msgs_submit(libdax_messenger, -1, 0x00000002,
 1936                 LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
 1937             "Drive is in use. Waiting 2 seconds before re-try", 
 1938                 0, 0);
 1939         usleep(2000000);
 1940         goto try_open;
 1941     }
 1942     libdax_msgs_submit(libdax_messenger, d->global_index,
 1943             0x00020003,
 1944             LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
 1945             "Could not grab drive - already in use", 0, 0);
 1946     sg_close_drive(d);
 1947     d->fd = -1337;
 1948     return 0;
 1949 }
 1950 
 1951 
 1952 /** PORTING: Is mainly about the call to sg_close_drive() and whether it
 1953              implements the demanded functionality.
 1954 */
 1955 /** Gives up the drive for SCSI commands and releases eventual access locks.
 1956     (Note: this is not physical tray locking.)
 1957 */
 1958 int sg_release(struct burn_drive *d)
 1959 {
 1960     /* ts A60821
 1961     <<< debug: for tracing calls which might use open drive fds */
 1962     if (mmc_function_spy(d, "sg_release") <= 0)
 1963         return 0;
 1964 
 1965     if (d->fd < 1)
 1966         return 0;
 1967 
 1968     /* ts A60821
 1969     <<< debug: for tracing calls which might use open drive fds */
 1970     mmc_function_spy(NULL, "sg_release ----------- closing");
 1971 
 1972     sg_close_drive(d);
 1973     return 0;
 1974 }
 1975 
 1976 /* @return -1= transport failed, give up drive
 1977             0= transport failed, do not retry
 1978             1= transport succeeded
 1979             2- transport failed, please retry
 1980 */
 1981 static int evaluate_transport_success(struct burn_drive *d, struct command *c,
 1982                                       FILE *fp,
 1983                                       unsigned short host_status,
 1984                                       unsigned short driver_status)
 1985 {
 1986     int ret, do_retry= 0, give_up_drive= 0, sev;
 1987     char *msg = NULL, *host_problem, *driver_problem, *driver_sugg;
 1988 
 1989     BURN_ALLOC_MEM(msg, char, 161);
 1990 
 1991     if ((host_status == Libburn_sg_host_oK &&
 1992              (driver_status & 0xf7) == Libburn_sg_driver_oK) || c->error)
 1993         {ret = 1; goto ex;} /* No transport problems */
 1994 
 1995     /* See http://www.tldp.org/HOWTO/SCSI-Generic-HOWTO/x291.html */
 1996 
 1997     switch(host_status) {
 1998     case 0x00:
 1999         host_problem =
 2000         "SG_ERR_DID_OK (No error)";
 2001     break; case 0x01:
 2002         host_problem =
 2003         "SG_ERR_DID_NO_CONNECT (Could not connect before timeout period)";
 2004         give_up_drive= 1;
 2005     break; case 0x02:
 2006         host_problem =
 2007         "SG_ERR_DID_BUS_BUSY (Bus stayed busy through time out period)";
 2008     break; case 0x03:
 2009         host_problem =
 2010         "SG_ERR_DID_TIME_OUT (Timed out for miscellaneous reasons)";
 2011     break; case 0x04:
 2012         host_problem =
 2013         "SG_ERR_DID_BAD_TARGET (Bad target, device not responding ?)";
 2014         give_up_drive= 1;
 2015     break; case 0x05:
 2016         host_problem =
 2017         "SG_ERR_DID_ABORT (Told to abort)";
 2018     break; case 0x06:
 2019         host_problem =
 2020         "SG_ERR_DID_PARITY (Parity error)";
 2021     break; case 0x07:
 2022         host_problem =
 2023         "SG_ERR_DID_ERROR (Internal error detected in the host adapter)";
 2024         give_up_drive= 1;
 2025     break; case 0x08:
 2026         host_problem =
 2027         "SG_ERR_DID_RESET (The SCSI bus or the device have been reset)";
 2028         give_up_drive= 1;
 2029     break; case 0x09:
 2030         host_problem =
 2031         "SG_ERR_DID_BAD_INTR (Got an unexpected interrupt)";
 2032     break; case 0x0a:
 2033         host_problem =
 2034         "SG_ERR_DID_PASSTHROUGH (Force command past mid-layer)";
 2035     break; case 0x0b:
 2036         host_problem =
 2037         "SG_ERR_DID_SOFT_ERROR (The low level driver wants a retry)";
 2038         do_retry = 1;
 2039     break; default:
 2040         host_problem =
 2041         "? (unknown host_status code)";
 2042     }
 2043     if (host_status != Libburn_sg_host_oK) {
 2044         sprintf(msg, "SCSI command %2.2Xh yielded host problem: ",
 2045             (unsigned int) c->opcode[0]);
 2046         sprintf(msg+strlen(msg), "0x%x %s",
 2047             (unsigned int) host_status, host_problem);
 2048         sev = LIBDAX_MSGS_SEV_FAILURE;
 2049         if (do_retry && !give_up_drive)
 2050             sev = LIBDAX_MSGS_SEV_NOTE;
 2051         libdax_msgs_submit(libdax_messenger, d->global_index,
 2052             0x000201a7, sev, LIBDAX_MSGS_PRIO_HIGH, msg, 0, 0);
 2053         strcpy(msg, "Command: ");
 2054         if (spc_human_readable_cmd(c, msg + strlen(msg),
 2055                        160 - strlen(msg), 0) > 0)
 2056             libdax_msgs_submit(libdax_messenger, d->global_index,
 2057                     0x000201a7, sev, LIBDAX_MSGS_PRIO_HIGH,
 2058                     msg, 0, 0);
 2059         sprintf(msg, "--- SG_IO: host_status= 0x%x %s",
 2060             (unsigned int) host_status, host_problem);
 2061         scsi_log_message(d, fp, msg, 0);
 2062     }
 2063 
 2064     switch (driver_status & 0x07) {
 2065     case 0:
 2066         driver_problem = "SG_ERR_DRIVER_OK";
 2067     break; case 1:
 2068         driver_problem = "SG_ERR_DRIVER_BUSY";
 2069     break; case 2:
 2070         driver_problem = "SG_ERR_DRIVER_SOFT";
 2071     break; case 3:
 2072         driver_problem = "SG_ERR_DRIVER_MEDIA";
 2073     break; case 4:
 2074         driver_problem = "SG_ERR_DRIVER_ERROR";
 2075     break; case 5:
 2076         driver_problem = "SG_ERR_DRIVER_INVALID";
 2077     break; case 6:
 2078         driver_problem = "SG_ERR_DRIVER_TIMEOUT";
 2079     break; case 7:
 2080         driver_problem = "SG_ERR_DRIVER_HARD";
 2081     break; default:
 2082         driver_problem = "(unknown driver_status code)";
 2083     }
 2084     switch (driver_status & 0xf0) {
 2085     case 0:
 2086         driver_sugg = "(no suggestion)";
 2087     break; case 0x10:
 2088         driver_sugg = "SG_ERR_SUGGEST_RETRY";
 2089         do_retry = 1;
 2090     break; case 0x20:
 2091         driver_sugg = "SG_ERR_SUGGEST_ABORT";
 2092         give_up_drive= 1;
 2093     break; case 0x30:
 2094         driver_sugg = "SG_ERR_SUGGEST_REMAP";
 2095         give_up_drive= 1;
 2096     break; case 0x40:
 2097         driver_sugg = "SG_ERR_SUGGEST_DIE";
 2098         give_up_drive= 1;
 2099     break; case 0x80:
 2100         driver_sugg = "SG_ERR_SUGGEST_SENSE";
 2101     break; default:
 2102         driver_sugg = "(unknown driver_status suggestion)";
 2103     }
 2104     if ((driver_status & 0xf7) != Libburn_sg_driver_oK) {
 2105         sprintf(msg, "SCSI command %2.2Xh yielded driver problem: ",
 2106             (unsigned int) c->opcode[0]);
 2107         sprintf(msg+strlen(msg), "driver_status= 0x%x %s / %s",
 2108             (unsigned int) driver_status,
 2109             driver_problem, driver_sugg);
 2110         sev = LIBDAX_MSGS_SEV_FAILURE;
 2111         if (do_retry && !give_up_drive)
 2112             sev = LIBDAX_MSGS_SEV_NOTE;
 2113         libdax_msgs_submit(libdax_messenger, d->global_index,
 2114             0x000201a8, sev, LIBDAX_MSGS_PRIO_HIGH, msg, 0, 0);
 2115         strcpy(msg, "Command: ");
 2116         if (spc_human_readable_cmd(c, msg + strlen(msg),
 2117                        160 - strlen(msg), 0) > 0)
 2118             libdax_msgs_submit(libdax_messenger, d->global_index,
 2119                     0x000201a8, sev, LIBDAX_MSGS_PRIO_HIGH,
 2120                     msg, 0, 0);
 2121         sprintf(msg, "--- SG_IO: driver_status= 0x%x %s / %s",
 2122             (unsigned int) driver_status,
 2123             driver_problem, driver_sugg);
 2124         scsi_log_message(d, fp, msg, 0);
 2125     }
 2126 
 2127     if (! do_retry)
 2128         c->error = 1;
 2129     ret = give_up_drive ? -1 : do_retry ? 2 : 0;
 2130 ex:;
 2131     BURN_FREE_MEM(msg);
 2132     return ret;
 2133 }
 2134 
 2135 static void react_on_drive_loss(struct burn_drive *d, struct command *c,
 2136                                 FILE *fp)
 2137 {
 2138     sg_close_drive(d);
 2139     d->released = 1;
 2140     d->busy = BURN_DRIVE_IDLE;
 2141     d->cancel = 1;
 2142     c->error = 1;
 2143     libdax_msgs_submit(libdax_messenger,
 2144                  d->global_index, 0x000201a6,
 2145                  LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
 2146                  "Lost connection to drive", 0, 0);
 2147     scsi_log_message(d, fp, "--- SG_IO: Gave up connection to drive", 0);
 2148 }
 2149 
 2150 /** Sends a SCSI command to the drive, receives reply and evaluates whether
 2151     the command succeeded or shall be retried or finally failed.
 2152     Returned SCSI errors shall not lead to a return value indicating failure.
 2153     The callers get notified by c->error. An SCSI failure which leads not to
 2154     a retry shall be notified via scsi_notify_error().
 2155     @return: 1 success , <=0 failure
 2156 */
 2157 int sg_issue_command(struct burn_drive *d, struct command *c)
 2158 {
 2159     int done = 0, no_c_page = 0, i, ret;
 2160     int err;
 2161     time_t start_time;
 2162     sg_io_hdr_t s;
 2163     /* ts A61030 */
 2164     static FILE *fp= NULL;
 2165     char *msg = NULL;
 2166 
 2167     BURN_ALLOC_MEM(msg, char, 161);
 2168 
 2169     c->error = 0;
 2170     memset(c->sense, 0, sizeof(c->sense));
 2171 
 2172     /* <<< ts A60821
 2173        debug: for tracing calls which might use open drive fds */
 2174     sprintf(msg, "sg_issue_command   d->fd= %d  d->released= %d\n",
 2175         d->fd, d->released);
 2176     mmc_function_spy(NULL, msg);
 2177 
 2178     /* >>> ts B11110 : move this into scsi_log_cmd() together with the
 2179                         static fp */
 2180     /* ts A61030 */
 2181     if (burn_sg_log_scsi & 1) {
 2182         if (fp == NULL) {
 2183             fp= fopen("/tmp/libburn_sg_command_log", "a");
 2184             fprintf(fp,
 2185                 "\n-----------------------------------------\n");
 2186         }
 2187     }
 2188 
 2189     /* ts A61010 : with no fd there is no chance to send an ioctl */
 2190     if (d->fd < 0) {
 2191         c->error = 1;
 2192         {ret = 0; goto ex;}
 2193     }
 2194 
 2195 
 2196     c->error = 0;
 2197     memset(&s, 0, sizeof(sg_io_hdr_t));
 2198     if (burn_sg_log_scsi & 3)
 2199         scsi_log_cmd(c,fp,0);
 2200 
 2201     s.interface_id = 'S';
 2202 
 2203 #ifdef Libburn_sgio_as_growisofS
 2204     /* ??? ts A91112 : does this speed up USB ? (from growisofs)
 2205     --- did not help
 2206      */
 2207     s.flags = SG_FLAG_DIRECT_IO;
 2208 #endif /* Libburn_sgio_as_growisofS */
 2209 
 2210     if (c->dir == TO_DRIVE)
 2211         s.dxfer_direction = SG_DXFER_TO_DEV;
 2212     else if (c->dir == FROM_DRIVE)
 2213         s.dxfer_direction = SG_DXFER_FROM_DEV;
 2214     else if (c->dir == NO_TRANSFER) {
 2215         s.dxfer_direction = SG_DXFER_NONE;
 2216 
 2217         /* ts A61007 */
 2218         /* a ssert(!c->page); */
 2219         no_c_page = 1;
 2220     }
 2221     s.cmd_len = c->oplen;
 2222     s.cmdp = c->opcode;
 2223     s.mx_sb_len = 32;
 2224     s.sbp = c->sense;
 2225     if (c->timeout > 0)
 2226         s.timeout = c->timeout;
 2227     else
 2228         s.timeout = Libburn_scsi_default_timeouT;
 2229     if (c->page && !no_c_page) {
 2230         s.dxferp = c->page->data;
 2231 
 2232 /* # def ine Libburn_debug_dxferP 1 */
 2233 #ifdef Libburn_debug_dxferP
 2234 
 2235         { char text[1024], *content; int i = c->page->bytes;
 2236             if (c->dir == FROM_DRIVE) {
 2237                 for (i = 0; i < c->page->bytes && c->page->data[i] == 0; i++);
 2238                 content = (i <  c->page->bytes) ?
 2239                       "  (some nonzero)" : "  (all zero)";
 2240             } else {
 2241                 i = c->page->bytes;
 2242                 content = "";
 2243             }
 2244             sprintf(text, "dxferp before = %lx%s",
 2245                     (unsigned long) s.dxferp, content);
 2246             scsi_log_text(text, fp, 0);
 2247         }
 2248 
 2249 #endif
 2250 
 2251         if (c->dir == FROM_DRIVE) {
 2252 
 2253             /* ts A70519 : kernel 2.4 usb-storage seems to
 2254                     expect exact dxfer_len for data
 2255                     fetching commands.
 2256             */
 2257             if (c->dxfer_len >= 0)
 2258                 s.dxfer_len = c->dxfer_len;
 2259             else
 2260                 s.dxfer_len = BUFFER_SIZE;
 2261 /* touch page so we can use valgrind */
 2262             memset(c->page->data, 0, BUFFER_SIZE);
 2263         } else {
 2264 
 2265             /* ts A61010 */
 2266             /* a ssert(c->page->bytes > 0); */
 2267             if (c->page->bytes <= 0) {
 2268                 c->error = 1;
 2269                 {ret = 0; goto ex;}
 2270             }
 2271 
 2272             s.dxfer_len = c->page->bytes;
 2273         }
 2274     } else {
 2275         s.dxferp = NULL;
 2276         s.dxfer_len = 0;
 2277     }
 2278     s.usr_ptr = c;
 2279 
 2280     /* ts B90523 : Record effective transfer length request for debugging*/
 2281     c->dxfer_len = s.dxfer_len;
 2282 
 2283     start_time = time(NULL);
 2284     for(i = 0; !done; i++) {
 2285 
 2286         memset(c->sense, 0, sizeof(c->sense));
 2287         c->start_time = burn_get_time(0);
 2288 
 2289         err = ioctl(d->fd, SG_IO, &s);
 2290 
 2291         c->end_time = burn_get_time(0);
 2292 
 2293 
 2294 #ifdef Libburn_debug_dxferP
 2295         if (c->page && !no_c_page) {
 2296             char text[1024];
 2297             sprintf(text, "dxferp after  = %lx",
 2298                     (unsigned long) s.dxferp);
 2299             scsi_log_text(text, fp, 0);
 2300         }
 2301 
 2302 #endif
 2303 
 2304         /* ts A61010 */
 2305         /* a ssert(err != -1); */
 2306         if (err == -1) {
 2307             libdax_msgs_submit(libdax_messenger,
 2308                  d->global_index, 0x0002010c,
 2309                  LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
 2310                  "Failed to transfer command to drive",
 2311                  errno, 0);
 2312             sprintf(msg, "--- SG_IO: return= -1 , ");
 2313                 sprintf(msg + strlen(msg), "errno= %d , ", errno);
 2314                 sprintf(msg + strlen(msg),
 2315                     "host_status= 0x%x , driver_status= 0x%x",
 2316                     (unsigned int) s.host_status,
 2317                     (unsigned int) s.driver_status);
 2318             scsi_log_message(d, fp, msg, 0);
 2319 
 2320             libdax_msgs_submit(libdax_messenger,
 2321                  d->global_index, 0x0002010c,
 2322                  LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
 2323                  msg, 0, 0);
 2324             sprintf(msg, "Attempted command: ");
 2325             spc_human_readable_cmd(c, msg + strlen(msg),
 2326                            160 - strlen(msg), 0);
 2327             libdax_msgs_submit(libdax_messenger,
 2328                  d->global_index, 0x0002010c,
 2329                  LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
 2330                  msg, 0, 0);
 2331 
 2332             react_on_drive_loss(d, c, fp);
 2333             {ret = -1; goto ex;}
 2334         }
 2335                 done = scsi_eval_cmd_outcome(d, c, fp,
 2336                                      (unsigned char *) (s.sbp),
 2337                                      s.sb_len_wr,
 2338                              start_time, s.timeout, i, 0);
 2339         if (d->cancel)
 2340     break;
 2341         ret = evaluate_transport_success(d, c, fp,
 2342                                        s.host_status, s.driver_status);
 2343         if (ret == -1)
 2344             react_on_drive_loss(d, c, fp);
 2345         if (ret <= 0)
 2346             {ret = -1; goto ex;}
 2347         if (d->cancel)
 2348     break;
 2349         /* if ! done : loop for retry */;
 2350         if (!done) {
 2351             spc_register_retry(c);
 2352             if (burn_sg_log_scsi & 3) {
 2353                 scsi_log_text("+++ Repeating command", fp, 0);
 2354                 scsi_log_cmd(c, fp, 0);
 2355             }
 2356         }
 2357     }
 2358 
 2359     ret = 1;
 2360 ex:;
 2361     BURN_FREE_MEM(msg);
 2362     return ret;
 2363 }
 2364 
 2365 
 2366 /* ts B11001 : outsourced from non-static sg_obtain_scsi_adr() */
 2367 /** Tries to obtain SCSI address parameters.
 2368     @return  1 is success , 0 is failure
 2369 */
 2370 static int sg_obtain_scsi_adr_fd(char *path, int fd_in,
 2371                  int *bus_no, int *host_no, int *channel_no,
 2372                  int *target_no, int *lun_no)
 2373 {
 2374     int fd, ret, l, open_mode = O_RDONLY;
 2375     struct my_scsi_idlun {
 2376         int x;
 2377         int host_unique_id;
 2378     };
 2379     struct my_scsi_idlun idlun;
 2380 
 2381     /* valgrind called idlun uninitialized because it is blind for ioctl */
 2382     idlun.x = 0;
 2383     idlun.host_unique_id = 0;
 2384 
 2385     l = strlen(linux_ata_device_family) - 2;
 2386     if (l > 0 && strncmp(path, linux_ata_device_family, l) == 0 
 2387         && path[7] >= 'a' && path[7] <= 'z' && path[8] == 0)
 2388         return 0; /* on RIP 14 all hdx return SCSI adr 0,0,0,0 */
 2389 
 2390     /* ts A70409 : DDLP-B */
 2391     /* >>> obtain single lock on path */
 2392 
 2393     if(burn_sg_open_o_nonblock)
 2394         open_mode |= O_NDELAY;
 2395     if(burn_sg_open_o_excl) {
 2396         /* O_EXCL | O_RDONLY does not work with /dev/sg* on 
 2397            SuSE 9.0 (kernel 2.4) and SuSE 9.3 (kernel 2.6) */
 2398         /* so skip it for now */;
 2399     }
 2400     if (fd_in >= 0)
 2401         fd = fd_in;
 2402     else
 2403         fd = open(path, open_mode);
 2404     if(fd < 0)
 2405         return 0;
 2406     sg_fcntl_lock(&fd, path, F_RDLCK, 0);
 2407     if(fd < 0)
 2408         return 0;
 2409 
 2410 #ifdef SCSI_IOCTL_GET_BUS_NUMBER
 2411     /* Hearsay A61005 */
 2412     if (ioctl(fd, SCSI_IOCTL_GET_BUS_NUMBER, bus_no) == -1)
 2413         *bus_no = -1;
 2414 #endif
 2415 
 2416     /* http://www.tldp.org/HOWTO/SCSI-Generic-HOWTO/scsi_g_idlun.html */
 2417     ret = ioctl(fd, SCSI_IOCTL_GET_IDLUN, &idlun);
 2418 
 2419     if (fd_in < 0)
 2420         sg_close_drive_fd(path, -1, &fd, 0);
 2421     if (ret == -1)
 2422         return(0);
 2423     *host_no= (idlun.x>>24)&255;
 2424     *channel_no= (idlun.x>>16)&255;
 2425     *target_no= (idlun.x)&255;
 2426     *lun_no= (idlun.x>>8)&255;
 2427 #ifdef SCSI_IOCTL_GET_BUS_NUMBER
 2428     if(*bus_no == -1)
 2429         *bus_no = 1000 * (*host_no + 1) + *channel_no;
 2430 #else
 2431     *bus_no= *host_no;
 2432 #endif
 2433     return 1;
 2434 }
 2435 
 2436 
 2437 /* ts A60922 */
 2438 /** Tries to obtain SCSI address parameters.
 2439     @return  1 is success , 0 is failure
 2440 */
 2441 int sg_obtain_scsi_adr(char *path, int *bus_no, int *host_no, int *channel_no,
 2442                        int *target_no, int *lun_no)
 2443 {
 2444     return sg_obtain_scsi_adr_fd(path, -1, bus_no, host_no, channel_no,
 2445                      target_no, lun_no);
 2446 }
 2447 
 2448 
 2449 /* ts A60922 ticket 33 : called from drive.c */
 2450 /** Tells whether a text is a persistent address as listed by the enumeration
 2451     functions.
 2452 */
 2453 int sg_is_enumerable_adr(char *adr)
 2454 {
 2455     char *fname = NULL;
 2456     int ret = 0, first = 1, fname_size = 4096;
 2457     burn_drive_enumerator_t idx;
 2458 
 2459     BURN_ALLOC_MEM(fname, char, fname_size);
 2460     while (1) {
 2461         ret= sg_give_next_adr(&idx, fname, fname_size, first);
 2462         if(ret <= 0)
 2463     break;
 2464         first = 0;
 2465         if (strcmp(adr, fname) == 0) {
 2466             sg_give_next_adr(&idx, fname, fname_size, -1);
 2467             {ret = 1; goto ex;}
 2468         }
 2469     }
 2470     ret = 0;
 2471 ex:;
 2472     if (first == 0)
 2473         sg_give_next_adr(&idx, fname, fname_size, -1);
 2474     BURN_FREE_MEM(fname);
 2475     return ret;
 2476 }
 2477 
 2478 
 2479 /* ts B00115 */
 2480 /* Return 1 if the given path leads to a regular file or a device that can be
 2481    fseeked, read, and possibly written with 2 kB granularity. 
 2482 */
 2483 int burn_os_is_2k_seekrw(char *path, int flag)
 2484 {
 2485     struct stat stbuf;
 2486 
 2487     if (stat(path, &stbuf) == -1)
 2488         return 0;
 2489     if (S_ISREG(stbuf.st_mode))
 2490         return 1;
 2491     if (S_ISBLK(stbuf.st_mode))
 2492         return 1;
 2493     return 0;
 2494 }
 2495 
 2496 
 2497 /* ts A70909 */
 2498 /** Estimate the potential payload capacity of a file address.
 2499     @param path  The address of the file to be examined. If it does not
 2500                  exist yet, then the directory will be inquired.
 2501     @param bytes The pointed value gets modified, but only if an estimation is
 2502                  possible.
 2503     @return      -2 = cannot perform necessary operations on file object
 2504                  -1 = neither path nor dirname of path exist
 2505                   0 = could not estimate size capacity of file object
 2506                   1 = estimation has been made, bytes was set
 2507 */
 2508 int burn_os_stdio_capacity(char *path, off_t write_start, off_t *bytes)
 2509 {
 2510     struct stat stbuf;
 2511     struct statvfs vfsbuf;
 2512     char *testpath = NULL, *cpt;
 2513     long blocks;
 2514     int open_mode = O_RDONLY, fd, ret;
 2515     off_t add_size = 0;
 2516 
 2517     BURN_ALLOC_MEM(testpath, char, 4096);
 2518     testpath[0] = 0;
 2519     if (stat(path, &stbuf) == -1) {
 2520         strcpy(testpath, path);
 2521         cpt = strrchr(testpath, '/');
 2522         if(cpt == NULL)
 2523             strcpy(testpath, ".");
 2524         else if(cpt == testpath)
 2525             testpath[1] = 0;
 2526         else
 2527             *cpt = 0;
 2528         if (stat(testpath, &stbuf) == -1)
 2529             {ret = -1; goto ex;}
 2530     } else if(S_ISBLK(stbuf.st_mode)) {
 2531         fd = open(path, open_mode);
 2532         if (fd == -1)
 2533             {ret = -2; goto ex;}
 2534         ret = ioctl(fd, BLKGETSIZE, &blocks);
 2535         close(fd);
 2536         if (ret == -1)
 2537             {ret = -2; goto ex;}
 2538         *bytes = ((off_t) blocks) * (off_t) 512;
 2539     } else if(S_ISREG(stbuf.st_mode)) {
 2540         add_size = burn_sparse_file_addsize(write_start, &stbuf);
 2541         strcpy(testpath, path);
 2542     } else
 2543         {ret = 0; goto ex;}
 2544 
 2545     if (testpath[0]) {  
 2546         if (statvfs(testpath, &vfsbuf) == -1)
 2547             {ret = -2; goto ex;}
 2548         *bytes = add_size + ((off_t) vfsbuf.f_frsize) *
 2549                         (off_t) vfsbuf.f_bavail;
 2550     }
 2551 
 2552 #ifdef NIX
 2553 /* <<< */
 2554     fprintf(stderr, "libburn_DEBUG: Faking 4.5 TB of disk space\n");
 2555     *bytes = ((off_t) 2415919104) * (off_t) 2048;
 2556     if (*bytes / (off_t) 2048 > (off_t) 0x7ffffff0) {
 2557         *bytes = ((off_t) 0x7ffffff0) * (off_t) 2048;
 2558         fprintf(stderr, "libburn_DEBUG: Reducing disk space to 4 TB - 2 kB\n");
 2559     }
 2560 /* <<< */
 2561 #endif
 2562 
 2563 
 2564     ret = 1;
 2565 ex:;
 2566     BURN_FREE_MEM(testpath);
 2567     return ret;
 2568 }
 2569 
 2570 
 2571 /* ts A91122 : an interface to open(O_DIRECT) or similar OS tricks. */
 2572 
 2573 #ifdef PROT_READ
 2574 #ifdef PROT_WRITE
 2575 #ifdef MAP_SHARED
 2576 #ifdef MAP_ANONYMOUS
 2577 #ifdef MAP_FAILED
 2578 #define Libburn_linux_do_mmaP 1
 2579 #endif
 2580 #endif
 2581 #endif
 2582 #endif
 2583 #endif
 2584 
 2585 #ifdef Libburn_read_o_direcT
 2586 #ifdef O_DIRECT
 2587 #define Libburn_linux_do_o_direcT 1
 2588 #endif
 2589 #endif /* Libburn_read_o_direcT */
 2590 
 2591 
 2592 int burn_os_open_track_src(char *path, int open_flags, int flag)
 2593 {
 2594     int fd;
 2595 
 2596 #ifdef Libburn_linux_do_o_direcT
 2597     libdax_msgs_submit(libdax_messenger, -1, 0x00000002,
 2598         LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
 2599         "Opening track source with O_DIRECT" , 0, 0);
 2600     fd = open(path, open_flags | O_DIRECT);
 2601 #else
 2602     fd = open(path, open_flags);
 2603 #endif
 2604     return fd;
 2605 }
 2606 
 2607 
 2608 void *burn_os_alloc_buffer(size_t amount, int flag)
 2609 {
 2610     void *buf = NULL;
 2611 
 2612 #ifdef Libburn_linux_do_mmaP
 2613 
 2614     /* >>> check whether size is suitable */;
 2615 
 2616     libdax_msgs_submit(libdax_messenger, -1, 0x00000002,
 2617         LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
 2618         "Allocating buffer via mmap()" , 0, 0);
 2619     buf = mmap(NULL, amount, PROT_READ | PROT_WRITE,
 2620                 MAP_SHARED | MAP_ANONYMOUS, -1, (off_t) 0);
 2621     if (buf == MAP_FAILED)
 2622         buf = NULL;
 2623     else
 2624         memset(buf, 0, amount);
 2625 #else
 2626     buf = calloc(1, amount);
 2627 #endif /* ! Libburn_linux_do_mmaP */
 2628 
 2629     return buf;
 2630 }
 2631 
 2632 
 2633 int burn_os_free_buffer(void *buffer, size_t amount, int flag)
 2634 {
 2635     int ret = 0;
 2636 
 2637     if (buffer == NULL)
 2638         return 0;
 2639 #ifdef Libburn_linux_do_mmaP
 2640     ret = munmap(buffer, amount);
 2641 #else
 2642     free(buffer);
 2643 #endif
 2644     return (ret == 0);
 2645 }
 2646