"Fossies" - the Fresh Open Source Software Archive

Member "xorriso-1.5.4/libburn/sg-libcdio.c" (30 Jan 2021, 28383 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-libcdio.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 /*
    4    Copyright (c) 2009 - 2016 Thomas Schmitt <scdbackup@gmx.net>
    5    Provided under GPL version 2 or later.
    6 */
    7 
    8 
    9 /*
   10 
   11 This is the main operating system dependent SCSI part of libburn. It implements
   12 the transport level aspects of SCSI control and command i/o.
   13 
   14 Present implementation: GNU libcdio , for X/Open compliant operating systems
   15 
   16 
   17 PORTING:
   18 
   19 Porting libburn typically will consist of adding a new operating system case
   20 to the following switcher files:
   21   os.h    Operating system specific libburn definitions and declarations.
   22   sg.c    Operating system dependent transport level modules.
   23 and of deriving the following system specific files from existing examples:
   24   os-*.h  Included by os.h. You will need some general system knowledge
   25           about signals and knowledge about the storage object needs of your
   26           transport level module sg-*.c.
   27 
   28   sg-*.c  This source module. You will need special system knowledge about
   29           how to detect all potentially available drives, how to open them,
   30           eventually how to exclusively reserve them, how to perform
   31           SCSI transactions, how to inquire the (pseudo-)SCSI driver.
   32           You will not need to care about CD burning, MMC or other high-level
   33           SCSI aspects.
   34 
   35 Said sg-*.c operations are defined by a public function interface, which has
   36 to be implemented in a way that provides libburn with the desired services:
   37 
   38 sg_id_string()          returns an id string of the SCSI transport adapter.
   39                         It may be called before initialization but then may
   40                         return only a preliminary id.
   41 
   42 sg_initialize()         performs global initialization of the SCSI transport
   43                         adapter and eventually needed operating system
   44                         facilities. Checks for compatibility of supporting
   45                         software components.
   46 
   47 sg_shutdown()           performs global finalizations and releases globally
   48                         acquired resources.
   49 
   50 sg_give_next_adr()      iterates over the set of potentially useful drive 
   51                         address strings.
   52 
   53 scsi_enumerate_drives() brings all available, not-whitelist-banned, and
   54                         accessible drives into libburn's list of drives.
   55 
   56 sg_dispose_drive()      finalizes adapter specifics of struct burn_drive
   57                         on destruction. Releases resources which were acquired
   58                         underneath scsi_enumerate_drives().
   59  
   60 sg_drive_is_open()      tells whether libburn has the given drive in use.
   61 
   62 sg_grab()               opens the drive for SCSI commands and ensures
   63                         undisturbed access.
   64 
   65 sg_release()            closes a drive opened by sg_grab()
   66 
   67 sg_issue_command()      sends a SCSI command to the drive, receives reply,
   68                         and evaluates whether the command succeeded or shall
   69                         be retried or finally failed.
   70 
   71 sg_obtain_scsi_adr()    tries to obtain SCSI address parameters.
   72 
   73 
   74 burn_os_is_2k_seekrw()  tells whether the given path leads to a file object
   75                         that can be used in 2 kB granularity by lseek(2),
   76                         read(2), and possibly write(2) if not read-only..
   77                         E.g. a USB stick or a hard disk.
   78 
   79 burn_os_stdio_capacity()  estimates the emulated media space of stdio-drives.
   80 
   81 burn_os_open_track_src()  opens a disk file in a way that offers best
   82                         throughput with file reading and/or SCSI write command
   83                         transmission.
   84 
   85 burn_os_alloc_buffer()  allocates a memory area that is suitable for file
   86                         descriptors issued by burn_os_open_track_src().
   87                         The buffer size may be rounded up for alignment
   88                         reasons.
   89 
   90 burn_os_free_buffer()   delete a buffer obtained by burn_os_alloc_buffer().
   91 
   92 Porting hints are marked by the text "PORTING:".
   93 Send feedback to libburn-hackers@pykix.org .
   94 
   95 */
   96 
   97 #ifdef HAVE_CONFIG_H
   98 #include "../config.h"
   99 #endif
  100 
  101 
  102 /** PORTING : ------- OS dependent headers and definitions ------ */
  103 
  104 #include <unistd.h>
  105 #include <stdio.h>
  106 #include <sys/types.h>
  107 #include <errno.h>
  108 #include <fcntl.h>
  109 #include <sys/stat.h>
  110 #include <string.h>
  111 #include <stdlib.h>
  112 
  113 #ifdef Libburn_os_has_statvfS
  114 #include <sys/statvfs.h>
  115 #endif /* Libburn_os_has_stavtfS */
  116 
  117 #ifdef __linux
  118 /* for ioctl(BLKGETSIZE) */
  119 #include <sys/ioctl.h>
  120 #include <linux/fs.h>
  121 #endif
  122 
  123 #ifdef __FreeBSD__
  124 #define Libburn_is_on_freebsD 1
  125 #endif
  126 #ifdef __FreeBSD_kernel__
  127 #define Libburn_is_on_freebsD 1
  128 #endif
  129 #ifdef Libburn_is_on_freebsD
  130 /* To avoid ATAPI devices */
  131 #define Libburn_guess_freebsd_atapi_devicE 1
  132 /* To obtain size of disk-like devices */
  133 #include <sys/disk.h> /* DIOCGMEDIASIZE */
  134 #endif /* Libburn_is_on_freebsD */
  135 
  136 #define Libburn_guess_freebsd_atapi_devicE 1
  137 
  138 #ifdef sun
  139 #define Libburn_is_on_solariS 1
  140 #endif
  141 #ifdef __sun
  142 #define Libburn_is_on_solariS 1
  143 #endif
  144 
  145 /* Proposal by Rocky Bernstein to avoid macro clashes with cdio_config.h */
  146 #define __CDIO_CONFIG_H__ 1
  147 
  148 #include <cdio/cdio.h>
  149 #include <cdio/logging.h>
  150 #include <cdio/mmc.h>
  151 
  152 /* ts B41126 : O_BINARY is needed for Cygwin but undefined elsewhere */
  153 #ifndef O_BINARY
  154 #define O_BINARY 0
  155 #endif
  156 
  157 
  158 /* The waiting time before eventually retrying a failed SCSI command.
  159    Before each retry wait Libburn_sg_linux_retry_incR longer than with
  160    the previous one.
  161 */
  162 #define Libburn_sg_libcdio_retry_usleeP 100000
  163 #define Libburn_sg_libcdio_retry_incR   100000
  164 
  165 
  166 /** PORTING : ------ libburn portable headers and definitions ----- */
  167 
  168 #include "transport.h"
  169 #include "drive.h"
  170 #include "sg.h"
  171 #include "spc.h"
  172 /* collides with symbols of <cdio/mmc.h>
  173  #include "mmc.h"
  174 */
  175 #include "sbc.h"
  176 #include "debug.h"
  177 #include "toc.h"
  178 #include "util.h"
  179 #include "init.h"
  180 
  181 #include "libdax_msgs.h"
  182 extern struct libdax_msgs *libdax_messenger;
  183 
  184 
  185 /* is in portable part of libburn */
  186 int burn_drive_is_banned(char *device_address);
  187 int burn_drive_resolve_link(char *path, char adr[],
  188              int *recursion_count, int flag); /* drive.c */
  189 
  190 /* Whether to log SCSI commands:
  191    bit0= log in /tmp/libburn_sg_command_log
  192    bit1= log to stderr
  193    bit2= flush every line
  194 */
  195 extern int burn_sg_log_scsi;
  196 
  197 
  198 /* ------------------------------------------------------------------------ */
  199 /* PORTING:   Private definitions. Port only if needed by public functions. */
  200 /*            (Public functions are listed below)                           */
  201 /* ------------------------------------------------------------------------ */
  202 
  203 
  204 /* Storage object is in libburn/init.c
  205    whether to strive for exclusive access to the drive
  206 */
  207 extern int burn_sg_open_o_excl;
  208 
  209 
  210 /* ------------------------------------------------------------------------ */
  211 /* PORTING: Private functions. Port only if needed by public functions      */
  212 /*          (Public functions are listed below)                             */
  213 /* ------------------------------------------------------------------------ */
  214 
  215 
  216 static int sg_close_drive(struct burn_drive * d)
  217 {
  218     CdIo_t *p_cdio;
  219 
  220     if (d->p_cdio != NULL) {
  221         p_cdio = (CdIo_t *) d->p_cdio;
  222         cdio_destroy(p_cdio);
  223         d->p_cdio = NULL;
  224     }
  225     return 0;
  226 }
  227 
  228 
  229 static int sg_give_next_adr_raw(burn_drive_enumerator_t *idx,
  230                      char adr[], int adr_size, int initialize)
  231 {
  232     char **pos;
  233     int count = 0;
  234 
  235     if (initialize == 1) {
  236         idx->pos = idx->ppsz_cd_drives =
  237                     cdio_get_devices(DRIVER_DEVICE);
  238         if (idx->ppsz_cd_drives == NULL)
  239             return 0;
  240 
  241         for (pos = idx->ppsz_cd_drives ; pos != NULL; pos++) {
  242             if (*pos == NULL)
  243         break;
  244             count++;
  245         }
  246 
  247     } else if (initialize == -1) {
  248         if (idx->ppsz_cd_drives != NULL)
  249             if (*(idx->ppsz_cd_drives) != NULL)
  250                 cdio_free_device_list(idx->ppsz_cd_drives);
  251         idx->ppsz_cd_drives = NULL;
  252     }
  253 
  254 #ifdef Libburn_guess_freebsd_atapi_devicE
  255 try_next:;
  256 #endif
  257 
  258     if (idx->pos == NULL)
  259         return 0;
  260     if (*(idx->pos) == NULL)
  261         return 0;
  262 
  263 #ifdef Libburn_guess_freebsd_atapi_devicE
  264     if (strncmp(*(idx->pos), "/dev/acd", 8) == 0) {
  265         (idx->pos)++;
  266         goto try_next;
  267     }
  268 #endif
  269 
  270     if ((ssize_t) strlen(*(idx->pos)) >= adr_size)
  271         return -1;
  272     strcpy(adr, *(idx->pos));
  273     (idx->pos)++;
  274     return 1;
  275 }
  276 
  277 
  278 /* ----------------------------------------------------------------------- */
  279 /* PORTING: Private functions which contain publicly needed functionality. */
  280 /*          Their portable part must be performed. So it is probably best  */
  281 /*          to replace the non-portable part and to call these functions   */
  282 /*          in your port, too.                                             */
  283 /* ----------------------------------------------------------------------- */
  284 
  285 
  286 /** Wraps a detected drive into libburn structures and hands it over to
  287     libburn drive list.
  288 */
  289 static void enumerate_common(char *fname, char *cdio_name,
  290                 int bus_no, int host_no,
  291                 int channel_no, int target_no, int lun_no)
  292 {
  293     int ret;
  294     struct burn_drive out;
  295 
  296     /* General libburn drive setup */
  297     burn_setup_drive(&out, fname);
  298 
  299     /* This transport adapter uses SCSI-family commands and models
  300        (seems the adapter would know better than its boss, if ever) */
  301     ret = burn_scsi_setup_drive(&out, bus_no, host_no, channel_no,
  302                                  target_no, lun_no, 0);
  303         if (ret <= 0)
  304                 return;
  305 
  306     /* PORTING: ------------------- non portable part --------------- */
  307 
  308     /* Transport adapter is libcdio */
  309     /* Adapter specific handles and data */
  310     out.p_cdio = NULL;
  311     strcpy(out.libcdio_name, fname);
  312     if (strlen(cdio_name) < sizeof(out.libcdio_name))
  313         strcpy(out.libcdio_name, cdio_name);
  314 
  315     /* PORTING: ---------------- end of non portable part ------------ */
  316 
  317     /* Adapter specific functions with standardized names */
  318     out.grab = sg_grab;
  319     out.release = sg_release;
  320     out.drive_is_open = sg_drive_is_open;
  321     out.issue_command = sg_issue_command;
  322     /* Finally register drive and inquire drive information */
  323     burn_drive_finish_enum(&out);
  324 }
  325 
  326 
  327 /* ------------------------------------------------------------------------ */
  328 /* PORTING:           Public functions. These MUST be ported.               */
  329 /* ------------------------------------------------------------------------ */
  330 
  331 
  332 /** Returns the id string  of the SCSI transport adapter and eventually
  333     needed operating system facilities.
  334     This call is usable even if sg_initialize() was not called yet. In that
  335     case a preliminary constant message might be issued if detailed info is
  336     not available yet.
  337     @param msg   returns id string
  338     @param flag  unused yet, submit 0
  339     @return      1 = success, <=0 = failure
  340 */
  341 int sg_id_string(char msg[1024], int flag)
  342 {
  343     char *version_text;
  344 
  345     sprintf(msg, "sg-libcdio h%d with libcdio ", LIBCDIO_VERSION_NUM);
  346 
  347  #if LIBCDIO_VERSION_NUM < 83 
  348 
  349 LIBBURN_MISCONFIGURATION = 0;
  350 INTENTIONAL_ABORT_OF_COMPILATION__HEADERFILE_cdio_version_dot_h_TOO_OLD__NEED_libcdio_VERSION_NUM_83 = 0;
  351 LIBBURN_MISCONFIGURATION_ = 0;
  352 
  353  #endif /* LIBCDIO_VERSION_NUM < 83  */
  354 
  355     version_text = (char *) cdio_version_string;
  356     strncat(msg, version_text, 800);
  357     return 1;
  358 }
  359 
  360 
  361 /** Performs global initialization of the SCSI transport adapter and eventually
  362     needed operating system facilities. Checks for compatibility of supporting
  363     software components.
  364     @param msg   returns ids and/or error messages of eventual helpers
  365     @param flag  unused yet, submit 0
  366     @return      1 = success, <=0 = failure
  367 */ 
  368 int sg_initialize(char msg[1024], int flag)
  369 {
  370     int cdio_ver;
  371     char *msg_pt;
  372 
  373     cdio_loglevel_default = CDIO_LOG_ASSERT;
  374 
  375     msg[0] = 0;
  376     sg_id_string(msg, 0);
  377     cdio_ver = libcdio_version_num;
  378     libdax_msgs_submit(libdax_messenger, -1, 0x00000002,
  379         LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
  380         msg , 0, 0);
  381     if (cdio_ver < LIBCDIO_VERSION_NUM) {
  382         strcat(msg, " ---> ");
  383         msg_pt = msg + strlen(msg);
  384         sprintf(msg_pt,
  385             "libcdio TOO OLD: numeric version %d , need at least %d",
  386             cdio_ver, LIBCDIO_VERSION_NUM);
  387         libdax_msgs_submit(libdax_messenger, -1,
  388             0x00000002,
  389             LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
  390             msg_pt, 0, 0);
  391         return 0;
  392     }
  393     return 1;
  394 }
  395 
  396 
  397 /** Performs global finalization of the SCSI transport adapter and eventually
  398     needed operating system facilities. Releases globally acquired resources.
  399     @param flag  unused yet, submit 0
  400     @return      1 = success, <=0 = failure
  401 */ 
  402 int sg_shutdown(int flag)
  403 {
  404     return 1;
  405 }
  406 
  407 
  408 /** Finalizes BURN_OS_TRANSPORT_DRIVE_ELEMENTS, the components of
  409     struct burn_drive which are defined in os-*.h.
  410     The eventual initialization of those components was made underneath
  411     scsi_enumerate_drives().
  412     This will be called when a burn_drive gets disposed.
  413     @param d     the drive to be finalized
  414     @param flag  unused yet, submit 0
  415     @return      1 = success, <=0 = failure
  416 */
  417 int sg_dispose_drive(struct burn_drive *d, int flag)
  418 {
  419     return 1;
  420 }
  421 
  422 
  423 /** Returns the next index number and the next enumerated drive address.
  424     The enumeration has to cover all available and accessible drives. It is
  425     allowed to return addresses of drives which are not available but under
  426     some (even exotic) circumstances could be available. It is on the other
  427     hand allowed, only to hand out addresses which can really be used right
  428     in the moment of this call. (This implementation chooses the latter.)
  429     @param idx An opaque handle. Make no own theories about it.
  430     @param adr Takes the reply
  431     @param adr_size Gives maximum size of reply including final 0
  432     @param initialize  1 = start new,
  433                        0 = continue, use no other values for now
  434                       -1 = finish
  435     @return 1 = reply is a valid address , 0 = no further address available
  436            -1 = severe error (e.g. adr_size too small)
  437 */
  438 int sg_give_next_adr(burn_drive_enumerator_t *idx,
  439              char adr[], int adr_size, int initialize)
  440 {
  441     int ret, recursion_count = 0, path_size = 4096;
  442     char *path = NULL;
  443 #ifdef Libburn_is_on_solariS
  444     int l;
  445 #endif
  446     BURN_ALLOC_MEM(path, char, path_size);
  447 
  448     ret = sg_give_next_adr_raw(idx, adr, adr_size, initialize);
  449     if (ret <= 0)
  450         goto ex;
  451     if ((ssize_t) strlen(adr) >= path_size)
  452         goto ex;
  453 
  454 #ifdef Libburn_is_on_solariS
  455     /* >>> provisory : preserve Solaris /dev/rdsk/cXtYdZs2 addresses */
  456     l = strlen(adr);
  457     if (l >= 18)
  458         if (strncmp(adr, "/dev/rdsk/c", 11) == 0 && adr[11] >= '0' &&
  459             adr[11] <= '9' && strcmp(adr + (l - 2), "s2") == 0)
  460             {ret = 1; goto ex;}
  461 #endif /* Libburn_is_on_solariS */
  462 
  463     ret = burn_drive_resolve_link(adr, path, &recursion_count, 2);
  464         if(ret > 0 && (ssize_t) strlen(path) < adr_size)
  465         strcpy(adr, path);
  466     ret = (ret >= 0);
  467 ex:
  468     BURN_FREE_MEM(path);
  469     return ret;
  470 }
  471 
  472 
  473 /** Brings all available, not-whitelist-banned, and accessible drives into
  474     libburn's list of drives.
  475 */
  476 int scsi_enumerate_drives(void)
  477 {
  478     burn_drive_enumerator_t idx;
  479     int initialize = 1, ret, i_bus_no = -1, recursion_count = 0;
  480         int i_host_no = -1, i_channel_no = -1, i_target_no = -1, i_lun_no = -1;
  481     int buf_size = 4096;
  482     char *buf = NULL, *target = NULL;
  483 #ifdef Libburn_is_on_solariS
  484     int l;
  485 #endif
  486 
  487     BURN_ALLOC_MEM(buf, char, buf_size);
  488     BURN_ALLOC_MEM(target, char, buf_size);
  489 
  490     while(1) {
  491         ret = sg_give_next_adr_raw(&idx, buf, buf_size, initialize);
  492         initialize = 0;
  493         if (ret <= 0)
  494     break;
  495         ret = 1;
  496 
  497 #ifdef Libburn_is_on_solariS 
  498         /* >>> provisory : preserve Solaris /dev/rdsk/cXtYdZs2 */
  499         l = strlen(buf);
  500         if (l >= 18)
  501             if (strncmp(buf, "/dev/rdsk/c", 11) == 0 &&
  502                 buf[11] >= '0' && buf[11] <= '9' &&
  503                 strcmp(buf + (l - 2), "s2") == 0)
  504                 ret = 0;
  505 #endif /* Libburn_is_on_solariS */
  506 
  507         if (ret == 1) {
  508             ret = burn_drive_resolve_link(buf, target,
  509                              &recursion_count,2);
  510         }
  511         if (ret <= 0)
  512             strcpy(target, buf);
  513         if (burn_drive_is_banned(target))
  514     continue; 
  515         sg_obtain_scsi_adr(buf, &i_bus_no, &i_host_no,
  516                 &i_channel_no, &i_target_no, &i_lun_no);
  517         enumerate_common(target, buf,
  518                 i_bus_no, i_host_no, i_channel_no,
  519                 i_target_no, i_lun_no);
  520     }
  521     sg_give_next_adr(&idx, buf, buf_size, -1);
  522     ret = 1;
  523 ex:;
  524     BURN_FREE_MEM(buf);
  525     BURN_FREE_MEM(target);
  526     return ret;
  527 }
  528 
  529 
  530 /** Tells whether libburn has the given drive in use or exclusively reserved.
  531     If it is "open" then libburn will eventually call sg_release() on it when
  532     it is time to give up usage and reservation.
  533 */
  534 /** Published as burn_drive.drive_is_open() */
  535 int sg_drive_is_open(struct burn_drive * d)
  536 {
  537     return (d->p_cdio != NULL);
  538 }
  539 
  540 
  541 /** Opens the drive for SCSI commands and - if burn activities are prone
  542     to external interference on your system - obtains an exclusive access lock
  543     on the drive. (Note: this is not physical tray locking.)
  544     A drive that has been opened with sg_grab() will eventually be handed
  545     over to sg_release() for closing and unreserving. 
  546 */  
  547 int sg_grab(struct burn_drive *d)
  548 {
  549     CdIo_t *p_cdio;
  550     char *am_eff, *msg = NULL, *am_wanted;
  551     int os_errno, second_try = 0, ret;
  552 
  553     if (d->p_cdio != NULL) {
  554         d->released = 0;
  555         {ret = 1; goto ex;}
  556     }
  557     if (d->libcdio_name[0] == 0) /* just to be sure it is initialized */
  558         strcpy(d->libcdio_name, d->devname);
  559     am_wanted = (burn_sg_open_o_excl & 63) ?  "MMC_RDWR_EXCL" : "MMC_RDWR";
  560 try_to_open:;
  561     p_cdio = cdio_open_am(d->libcdio_name, DRIVER_DEVICE, am_wanted);
  562     if (p_cdio == NULL) {
  563         BURN_ALLOC_MEM(msg, char, 4096);
  564         os_errno = errno;
  565         sprintf(msg, "Could not grab drive '%s'", d->devname);
  566         libdax_msgs_submit(libdax_messenger, d->global_index,
  567             0x00020003,
  568             LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
  569             msg, os_errno, 0);
  570         {ret = 0; goto ex;}
  571     }
  572     am_eff = (char *) cdio_get_arg(p_cdio, "access-mode");
  573         if (strncmp(am_eff, "MMC_RDWR", 8) != 0) {
  574         cdio_destroy(p_cdio);
  575         if (!second_try) {
  576             am_wanted = (burn_sg_open_o_excl & 63) ?
  577                         "MMC_RDWR" : "MMC_RDWR_EXCL";
  578             second_try = 1;
  579             goto try_to_open;
  580         }
  581         libdax_msgs_submit(libdax_messenger, d->global_index,
  582             0x00020003,
  583             LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
  584             "libcdio provides no MMC_RDWR access mode", 0, 0);
  585         {ret = 0; goto ex;}
  586         }
  587 
  588     d->p_cdio = p_cdio;
  589     d->released = 0;
  590     ret = 1;
  591 ex:;
  592     BURN_FREE_MEM(msg);
  593     return ret;
  594 }
  595 
  596 
  597 /** PORTING: Is mainly about the call to sg_close_drive() and whether it
  598              implements the demanded functionality.
  599 */
  600 /** Gives up the drive for SCSI commands and releases eventual access locks.
  601     (Note: this is not physical tray locking.) 
  602 */
  603 int sg_release(struct burn_drive *d)
  604 {
  605     if (d->p_cdio == NULL)
  606         return 0;
  607     sg_close_drive(d);
  608     return 0;
  609 }
  610 
  611 
  612 /** Sends a SCSI command to the drive, receives reply and evaluates whether
  613     the command succeeded or shall be retried or finally failed.
  614     Returned SCSI errors shall not lead to a return value indicating failure.
  615     The callers get notified by c->error. An SCSI failure which leads not to
  616     a retry shall be notified via scsi_notify_error().
  617     The Libburn_log_sg_commandS facility might be of help when problems with
  618     a drive have to be examined. It shall stay disabled for normal use.
  619     @return: 1 success , <=0 failure
  620 */
  621 int sg_issue_command(struct burn_drive *d, struct command *c)
  622 {
  623     int sense_valid = 0, i, timeout_ms, sense_len;
  624     int key = 0, asc = 0, ascq = 0, done = 0;
  625     time_t start_time;
  626         driver_return_code_t i_status;
  627     unsigned int dxfer_len;
  628         static FILE *fp = NULL;
  629     mmc_cdb_t cdb = {{0, }};
  630     cdio_mmc_direction_t e_direction;
  631     CdIo_t *p_cdio;
  632     cdio_mmc_request_sense_t *sense_pt = NULL;
  633 
  634     c->error = 0;
  635     memset(c->sense, 0, sizeof(c->sense));
  636 
  637     if (d->p_cdio == NULL) {
  638         return 0;
  639     }
  640     p_cdio = (CdIo_t *) d->p_cdio;
  641     if (burn_sg_log_scsi & 1) {
  642         if (fp == NULL) {
  643             fp= fopen("/tmp/libburn_sg_command_log", "a");
  644             fprintf(fp,
  645                 "\n-----------------------------------------\n");
  646         }
  647     }
  648     if (burn_sg_log_scsi & 3)
  649         scsi_log_cmd(c,fp,0);
  650 
  651     memcpy(cdb.field, c->opcode, c->oplen);
  652     if (c->dir == TO_DRIVE) {
  653         dxfer_len = c->page->bytes;
  654         e_direction = SCSI_MMC_DATA_WRITE;
  655     } else if (c->dir == FROM_DRIVE) {
  656         if (c->dxfer_len >= 0)
  657             dxfer_len = c->dxfer_len;
  658         else
  659             dxfer_len = BUFFER_SIZE;
  660         e_direction = SCSI_MMC_DATA_READ;
  661         /* touch page so we can use valgrind */
  662         memset(c->page->data, 0, BUFFER_SIZE);
  663     } else {
  664         dxfer_len = 0;
  665         e_direction = SCSI_MMC_DATA_NONE;
  666     }
  667         
  668     /* ts B90523 : Record effective transfer length request for debugging*/
  669     c->dxfer_len = dxfer_len;
  670 
  671     /* retry-loop */
  672     start_time = time(NULL);
  673     if (c->timeout > 0)
  674         timeout_ms = c->timeout;
  675     else
  676         timeout_ms = 200000;
  677     for(i = 0; !done; i++) {
  678 
  679         memset(c->sense, 0, sizeof(c->sense));
  680         c->start_time = burn_get_time(0);
  681 
  682         i_status = mmc_run_cmd(p_cdio, timeout_ms, &cdb, e_direction,
  683                     dxfer_len, c->page->data);
  684 
  685         c->end_time = burn_get_time(0);
  686         sense_valid = mmc_last_cmd_sense(p_cdio, &sense_pt);
  687         if (sense_valid >= 18) {
  688             memcpy(c->sense, (unsigned char *) sense_pt,
  689                 (size_t) sense_valid >= sizeof(c->sense) ?
  690                 sizeof(c->sense) : (size_t) sense_valid );
  691             spc_decode_sense(c->sense, 0, &key, &asc, &ascq);
  692         } else
  693             key = asc = ascq = 0;
  694         if (sense_pt != NULL)
  695             free(sense_pt);
  696 
  697 /* Regrettably mmc_run_cmd() does not clearly distinguish between transport
  698    failure and SCSI error reply.
  699    This reaction here would be for transport failure:
  700 
  701         if (i_status != 0 && i_status != DRIVER_OP_ERROR) {
  702             libdax_msgs_submit(libdax_messenger,
  703                 d->global_index, 0x0002010c,
  704                 LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
  705                 "Failed to transfer command to drive",
  706                 errno, 0);
  707             sg_close_drive(d);
  708             d->released = 1;
  709             d->busy = BURN_DRIVE_IDLE;
  710             c->error = 1;
  711             return -1;
  712         }
  713 */
  714 
  715         if ((!sense_valid) || (key == 0 && asc == 0 && ascq == 0)) {
  716             memset(c->sense, 0, sizeof(c->sense));
  717             if (i_status != 0) { /* set dummy sense */
  718                 /*LOGICAL UNIT NOT READY,
  719                     CAUSE NOT REPORTABLE*/
  720                 c->sense[0] = 0x70; /*Fixed format sense data*/
  721                 c->sense[2] = 0x02;
  722                 c->sense[12] = 0x04;
  723                 done = 1;
  724             }
  725         } 
  726         if (key || asc || ascq)
  727             sense_len = 18;
  728         else
  729             sense_len = 0;
  730         done = scsi_eval_cmd_outcome(d, c, fp,  c->sense, sense_len,
  731                          start_time, timeout_ms, i, 0);
  732         if (d->cancel)
  733             done = 1;
  734         if (!done)
  735             spc_register_retry(c);
  736 
  737     } /* end of retry-loop */
  738 
  739     return 1;
  740 }
  741 
  742 
  743 /** Tries to obtain SCSI address parameters.
  744     @return  1 is success , 0 is failure
  745 */
  746 int sg_obtain_scsi_adr(char *path, int *bus_no, int *host_no, int *channel_no,
  747                        int *target_no, int *lun_no)
  748 {
  749     CdIo_t *p_cdio;
  750     char *tuple;
  751 
  752     *bus_no = *host_no = *channel_no = *target_no = *lun_no = -1;
  753 
  754     p_cdio = cdio_open(path, DRIVER_DEVICE);
  755     if (p_cdio == NULL)
  756         return 0;
  757 
  758     /* Try whether a bus,host,channel,target,lun address tuple is
  759        available */
  760     tuple = (char *) cdio_get_arg(p_cdio, "scsi-tuple");
  761         if (tuple != NULL) if (tuple[0]) {
  762         sscanf(tuple, "%d,%d,%d,%d,%d",
  763             bus_no, host_no, channel_no, target_no, lun_no);
  764     }
  765 
  766     cdio_destroy(p_cdio);
  767     return (*bus_no >= 0);
  768 }
  769 
  770 
  771 /** Tells whether a text is a persistent address as listed by the enumeration
  772     functions.
  773 */
  774 int sg_is_enumerable_adr(char* adr)
  775 {
  776     burn_drive_enumerator_t idx;
  777     int initialize = 1, ret;
  778     char buf[64];
  779 
  780     while(1) {
  781         ret = sg_give_next_adr(&idx, buf, sizeof(buf), initialize);
  782         initialize = 0;
  783         if (ret <= 0)
  784     break;
  785         if (strcmp(adr, buf) == 0) {
  786             sg_give_next_adr(&idx, buf, sizeof(buf), -1);
  787             return 1;
  788         }
  789     }
  790     sg_give_next_adr(&idx, buf, sizeof(buf), -1);
  791     return (0);
  792 }
  793 
  794 
  795 #ifdef __FreeBSD__
  796 #define Libburn_guess_block_devicE 1
  797 #endif
  798 #ifdef __FreeBSD_kernel__
  799 #define Libburn_guess_block_devicE 1
  800 #endif
  801 
  802 #ifdef Libburn_guess_block_devicE
  803 
  804 /* ts B00115 */
  805 /* The FreeBSD implementation of burn_os_is_2k_seekrw().
  806    On FreeBSD there are no block devices.
  807 */
  808 static int freebsd_is_2k_seekrw(char *path, int flag)
  809 {
  810         struct stat stbuf;
  811     char *spt;
  812     int i, e;
  813 
  814         if (stat(path, &stbuf) == -1)
  815                 return 0;
  816         if (S_ISREG(stbuf.st_mode))
  817                 return 1;
  818     if (!S_ISCHR(stbuf.st_mode))
  819         return 0;
  820     spt = strrchr(path, '/');
  821     if (spt == NULL)
  822             spt = path;
  823     else
  824             spt++;
  825     e = strlen(spt);
  826     for (i = strlen(spt) - 1; i > 0; i--)
  827         if (spt[i] >= '0' && spt[i] <= '9')
  828             e = i;
  829     if (strncmp(spt, "da", e) == 0) /* SCSI disk. E.g. USB stick. */
  830         return 1;
  831     if (strncmp(spt, "cd", e) == 0) /* SCSI CD drive might be writeable. */
  832         return 1;
  833     if (strncmp(spt, "ad", e) == 0) /* IDE hard drive */
  834         return 1;
  835     if (strncmp(spt, "acd", e) == 0) /* IDE CD drive might be writeable */
  836         return 1;
  837     if (strncmp(spt, "fd", e) == 0) /* Floppy disk */
  838         return 1;
  839     if (strncmp(spt, "fla", e) == 0) /* Flash drive */
  840         return 1;
  841     return 0;
  842 }
  843 
  844 #endif /* Libburn_guess_block_devicE */
  845 
  846 
  847 /* Return 1 if the given path leads to a regular file or a device that can be
  848    fseeked, read, and possibly written with 2 kB granularity. 
  849 */
  850 int burn_os_is_2k_seekrw(char *path, int flag)
  851 {
  852 #ifdef Libburn_guess_block_devicE
  853     return freebsd_is_2k_seekrw(path, flag);
  854 #else 
  855     struct stat stbuf;
  856 
  857     if (stat(path, &stbuf) == -1)
  858         return 0;
  859     if (S_ISREG(stbuf.st_mode))
  860         return 1;
  861     if (S_ISBLK(stbuf.st_mode))
  862         return 1;
  863     return 0;
  864 #endif /* ! Libburn_guess_block_devicE */
  865 }
  866 
  867 
  868 /** Estimate the potential payload capacity of a file address.
  869     @param path  The address of the file to be examined. If it does not
  870                  exist yet, then the directory will be inquired.
  871     @param bytes The pointed value gets modified, but only if an estimation is
  872                  possible.
  873     @return      -2 = cannot perform necessary operations on file object
  874                  -1 = neither path nor dirname of path exist
  875                   0 = could not estimate size capacity of file object
  876                   1 = estimation has been made, bytes was set
  877 */
  878 int burn_os_stdio_capacity(char *path, off_t write_start, off_t *bytes)
  879 {
  880     struct stat stbuf;
  881 
  882 #ifdef Libburn_os_has_statvfS
  883     struct statvfs vfsbuf;
  884 #endif
  885 
  886     char *testpath = NULL, *cpt;
  887     off_t add_size = 0;
  888     int ret;
  889 
  890     BURN_ALLOC_MEM(testpath, char, 4096);
  891     testpath[0] = 0;
  892     if (stat(path, &stbuf) == -1) {
  893         strcpy(testpath, path);
  894         cpt = strrchr(testpath, '/');
  895         if(cpt == NULL)
  896             strcpy(testpath, ".");
  897         else if(cpt == testpath)
  898             testpath[1] = 0;
  899         else
  900             *cpt = 0;
  901         if (stat(testpath, &stbuf) == -1)
  902             {ret = -1; goto ex;}
  903 
  904 #ifdef __linux
  905 
  906     /* GNU/Linux specific determination of block device size */
  907     } else if(S_ISBLK(stbuf.st_mode)) {
  908         int open_mode = O_RDONLY | O_BINARY, fd;
  909         long blocks;
  910 
  911         blocks = *bytes / 512;
  912         fd = open(path, open_mode);
  913         if (fd == -1)
  914             {ret = -2; goto ex;}
  915         ret = ioctl(fd, BLKGETSIZE, &blocks);
  916         close(fd);
  917         if (ret == -1)
  918             {ret = -2; goto ex;}
  919         *bytes = ((off_t) blocks) * (off_t) 512;
  920 
  921 #endif /* __linux */
  922 
  923 #ifdef Libburn_is_on_freebsD
  924 
  925     } else if(S_ISCHR(stbuf.st_mode)) {
  926         int fd;
  927 
  928         fd = open(path, O_RDONLY | O_BINARY);
  929         if (fd == -1)
  930             {ret = -2; goto ex;}
  931         ret = ioctl(fd, DIOCGMEDIASIZE, &add_size);
  932         close(fd);
  933         if (ret == -1)
  934             {ret = -2; goto ex;}
  935         *bytes = add_size;
  936 
  937 #endif /* Libburn_is_on_freebsD */
  938 
  939 #ifdef Libburn_is_on_solariS
  940 
  941     } else if(S_ISBLK(stbuf.st_mode)) {
  942         int open_mode = O_RDONLY | O_BINARY, fd;
  943         
  944         fd = open(path, open_mode);
  945         if (fd == -1)
  946             {ret = -2; goto ex;}
  947         *bytes = lseek(fd, 0, SEEK_END);
  948         close(fd);
  949         if (*bytes == -1) {
  950             *bytes = 0;
  951             {ret = 0; goto ex;}
  952         }
  953         
  954 #endif /* Libburn_is_on_solariS */
  955 
  956     } else if(S_ISREG(stbuf.st_mode)) {
  957         add_size = burn_sparse_file_addsize(write_start, &stbuf);
  958         strcpy(testpath, path);
  959     } else
  960         {ret = 0; goto ex;}
  961 
  962     if (testpath[0]) {  
  963 
  964 #ifdef Libburn_os_has_statvfS
  965 
  966         if (statvfs(testpath, &vfsbuf) == -1)
  967             {ret = -2; goto ex;}
  968         *bytes = add_size + ((off_t) vfsbuf.f_frsize) *
  969                         (off_t) vfsbuf.f_bavail;
  970 
  971 #else /* Libburn_os_has_statvfS */
  972 
  973         {ret = 0; goto ex;}
  974 
  975 #endif /* ! Libburn_os_has_stavtfS */
  976 
  977     }
  978     ret = 1;
  979 ex:;
  980     BURN_FREE_MEM(testpath);
  981     return ret;
  982 }
  983 
  984 
  985 /* ts A91122 : an interface to open(O_DIRECT) or similar OS tricks. */
  986 
  987 #ifdef Libburn_read_o_direcT
  988 
  989     /* No special O_DIRECT-like precautions are implemented here */
  990 
  991 #endif /* Libburn_read_o_direcT */
  992 
  993 
  994 int burn_os_open_track_src(char *path, int open_flags, int flag)
  995 {
  996     int fd;
  997 
  998     fd = open(path, open_flags | O_BINARY);
  999     return fd;
 1000 }
 1001 
 1002 
 1003 void *burn_os_alloc_buffer(size_t amount, int flag)
 1004 {
 1005     void *buf = NULL;
 1006 
 1007     buf = calloc(1, amount);
 1008     return buf;
 1009 }
 1010 
 1011 
 1012 int burn_os_free_buffer(void *buffer, size_t amount, int flag)
 1013 {
 1014     if (buffer == NULL)
 1015         return 0;
 1016     free(buffer);
 1017     return 1;
 1018 }
 1019