"Fossies" - the Fresh Open Source Software Archive

Member "xorriso-1.5.4/libburn/sg-solaris.c" (30 Jan 2021, 27969 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-solaris.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) 2010 - 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: Solaris uscsi, e.g. for SunOS 5.11
   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 <stropts.h>
  106 #include <stdio.h>
  107 #include <sys/types.h>
  108 #include <errno.h>
  109 #include <fcntl.h>
  110 #include <sys/stat.h>
  111 #include <string.h>
  112 #include <stdlib.h>
  113 #include <dirent.h>
  114 
  115 #ifdef Libburn_os_has_statvfS
  116 #include <sys/statvfs.h>
  117 #endif /* Libburn_os_has_stavtfS */
  118 
  119 #include <volmgt.h>
  120 #include <sys/dkio.h>
  121 #include <sys/vtoc.h>
  122 
  123 #include <sys/scsi/impl/uscsi.h>
  124 
  125 
  126 /* The waiting time before eventually retrying a failed SCSI command.
  127    Before each retry wait Libburn_sg_linux_retry_incR longer than with
  128    the previous one.
  129 */
  130 #define Libburn_sg_solaris_retry_usleeP 100000
  131 #define Libburn_sg_solaris_retry_incR   100000
  132 
  133 
  134 /** PORTING : ------ libburn portable headers and definitions ----- */
  135 
  136 #include "transport.h"
  137 #include "drive.h"
  138 #include "sg.h"
  139 #include "spc.h"
  140 #include "sbc.h"
  141 #include "debug.h"
  142 #include "toc.h"
  143 #include "util.h"
  144 #include "init.h"
  145 
  146 #include "libdax_msgs.h"
  147 extern struct libdax_msgs *libdax_messenger;
  148 
  149 
  150 /* is in portable part of libburn */
  151 int burn_drive_is_banned(char *device_address);
  152 int burn_drive_resolve_link(char *path, char adr[],
  153              int *recursion_count, int flag); /* drive.c */
  154 
  155 /* Whether to log SCSI commands:
  156    bit0= log in /tmp/libburn_sg_command_log
  157    bit1= log to stderr
  158    bit2= flush every line
  159 */
  160 extern int burn_sg_log_scsi;
  161 
  162 
  163 /* ------------------------------------------------------------------------ */
  164 /* PORTING:   Private definitions. Port only if needed by public functions. */
  165 /*            (Public functions are listed below)                           */
  166 /* ------------------------------------------------------------------------ */
  167 
  168 
  169 /* Storage object is in libburn/init.c
  170    whether to strive for exclusive access to the drive
  171 */
  172 extern int burn_sg_open_o_excl;
  173 
  174 
  175 /* ------------------------------------------------------------------------ */
  176 /* PORTING: Private functions. Port only if needed by public functions      */
  177 /*          (Public functions are listed below)                             */
  178 /* ------------------------------------------------------------------------ */
  179 
  180 
  181 static int sg_close_drive(struct burn_drive * d)
  182 {
  183     if (d->fd != -1) {
  184         close(d->fd);
  185         d->fd = -1;
  186         return 1;
  187     }
  188     return 0;
  189 }
  190 
  191 
  192 static int decode_btl_number(char **cpt, int stopper, int *no)
  193 {
  194   *no = 0;
  195   for ((*cpt)++; **cpt != stopper; (*cpt)++) {
  196     if (**cpt < '0' || **cpt > '9')
  197       return 0;
  198     *no = *no * 10 + **cpt - '0';
  199   }
  200   return 1;
  201 }
  202 
  203 
  204 /* Read bus, target, lun from name "cXtYdZs2" or "cXtYdZ/...".
  205    Return 0 if name is not of the desired form.
  206 */
  207 static int decode_btl_solaris(char *name, int *busno, int *tgtno, int *lunno,
  208                         int flag)
  209 {
  210   char *cpt, *cpt_mem;
  211   int ret;
  212 
  213   *busno = *tgtno = *lunno = -1;
  214   cpt = name;
  215   if (*cpt != 'c')
  216     return 0;
  217   ret = decode_btl_number(&cpt, 't', busno);
  218   if (ret <= 0)
  219     return ret;
  220   ret = decode_btl_number(&cpt, 'd', tgtno);
  221   if (ret <= 0)
  222     return ret;
  223   cpt_mem = cpt;
  224   ret = decode_btl_number(&cpt, 's', lunno);
  225   if (ret <= 0) {
  226     cpt = cpt_mem;
  227     ret = decode_btl_number(&cpt, '/', lunno);
  228     if (ret <= 0)
  229       return ret;
  230     return(1);
  231   }
  232   cpt++;
  233   if (*cpt != '2' || *(cpt + 1) != 0)
  234     return 0;
  235   return 1;
  236 }
  237 
  238 
  239 static int start_enum_cXtYdZs2(burn_drive_enumerator_t *idx, int flag)
  240 {
  241     DIR *dir;
  242 
  243     idx->dir = NULL;
  244     dir = opendir("/dev/rdsk");
  245     if (dir == NULL) {
  246         libdax_msgs_submit(libdax_messenger, -1,
  247             0x0002000c, LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
  248     "Cannot start device file enumeration. opendir(\"/dev/rdsk\") failed.",
  249             errno, 0);
  250         return 0;
  251     }
  252     idx->dir = dir;
  253     return 1;
  254 }
  255 
  256 
  257 static int sg_solaris_convert_devname(char *path, char **dev_to_open, int flag)
  258 {
  259     char *sym_name = NULL, *media_name = NULL, *curr_name, *msg = NULL;
  260     int ret;
  261 
  262     BURN_ALLOC_MEM(msg, char, 4096);
  263 
  264     BURN_FREE_MEM(*dev_to_open);
  265     *dev_to_open = NULL;
  266     curr_name = path;
  267 
  268     if (! volmgt_running())
  269         goto set_name;
  270     sym_name = volmgt_symname(path); 
  271     sprintf(msg, "Volume Management symbolic name: '%s' -> %s",
  272             path, sym_name == NULL ? "NULL" : sym_name);
  273     libdax_msgs_submit(libdax_messenger, -1,
  274             0x00000002,
  275             LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
  276             msg, 0, 0);
  277     if (sym_name != NULL)
  278         media_name = media_findname(sym_name);
  279     else
  280         media_name = media_findname(path);
  281     if (media_name != NULL)
  282         curr_name = media_name;
  283     sprintf(msg, "Media name: %s -> %s",
  284             sym_name == NULL ? path : sym_name,
  285             media_name == NULL ? "NULL" : media_name);
  286     libdax_msgs_submit(libdax_messenger, -1,
  287             0x00000002,
  288             LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
  289             msg, 0, 0);
  290 set_name:
  291     BURN_ALLOC_MEM(*dev_to_open, char, strlen(curr_name) + 1);
  292     strcpy(*dev_to_open, curr_name);
  293     ret = 1;
  294 ex:
  295     if (media_name != NULL)
  296         free(media_name);
  297     if (sym_name != NULL)
  298         free(sym_name);
  299     BURN_FREE_MEM(msg);
  300     return(ret);
  301 }
  302 
  303 
  304 static int next_enum_cXtYdZs2(burn_drive_enumerator_t *idx,
  305                 char adr[], int adr_size, int flag)
  306 { 
  307     int busno, tgtno, lunno, ret, fd = -1, volpath_size = 160, os_errno;
  308     char *volpath = NULL, *msg = NULL, *dev_to_open = NULL;
  309     struct dirent *entry;
  310     struct dk_cinfo cinfo;
  311     DIR *dir;
  312 
  313     BURN_ALLOC_MEM(volpath, char, volpath_size);
  314     BURN_ALLOC_MEM(msg, char, 4096);
  315 
  316     dir = idx->dir;
  317     while (1) {
  318         errno = 0;
  319         entry = readdir(dir);
  320         if (entry == NULL) {
  321             if (errno) {
  322                 libdax_msgs_submit(libdax_messenger,
  323                         -1, 0x0002000d,
  324                 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
  325     "Cannot enumerate next device. readdir() from \"/dev/rdsk\" failed.",
  326                         errno, 0);
  327                 {ret = -1; goto ex;}
  328             }
  329     break;
  330         }
  331         if (strlen(entry->d_name) > (size_t) (volpath_size - 11))
  332     continue;
  333         ret = decode_btl_solaris(entry->d_name,
  334                     &busno, &tgtno, &lunno, 0);
  335         if (ret <= 0)
  336     continue; /* not cXtYdZs2 */
  337 
  338         sprintf(volpath, "/dev/rdsk/%s", entry->d_name);
  339         if (burn_drive_is_banned(volpath))
  340     continue;
  341         ret = sg_solaris_convert_devname(volpath, &dev_to_open, 0);
  342         if (ret <= 0)
  343     continue;
  344         fd = open(dev_to_open, O_RDONLY | O_NDELAY);
  345         if (fd < 0) {
  346             os_errno = errno;
  347             sprintf(msg, "Could not open '%s' , errno = %d",
  348                 dev_to_open, os_errno);
  349             libdax_msgs_submit(libdax_messenger, -1,
  350                 0x00000002,
  351                 LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
  352                 msg, os_errno, 0);
  353     continue;
  354         }
  355         /* See man dkio */
  356         ret = ioctl(fd, DKIOCINFO, &cinfo);
  357         close(fd);
  358         if (ret < 0) {
  359             os_errno = errno;
  360             sprintf(msg,
  361                "ioctl(DKIOCINFO) failed on drive '%s', errno = %d",
  362                 volpath, os_errno);
  363             libdax_msgs_submit(libdax_messenger, -1,
  364                 0x00000002,
  365                 LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
  366                 msg, os_errno, 0);
  367     continue;
  368         }
  369         if (cinfo.dki_ctype != DKC_CDROM) {
  370             sprintf(msg,
  371                 "ioctl(DKIOCINFO) classifies drive '%s' as dki_ctype %ld, not as DKC_CDROM = %ld",
  372                 volpath, (long int) cinfo.dki_ctype,
  373                 (long int) DKC_CDROM);
  374             libdax_msgs_submit(libdax_messenger, -1,
  375                 0x00000002,
  376                 LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
  377                 msg, 0, 0);
  378     continue;
  379         }
  380         if (adr_size <= (int) strlen(volpath)) {
  381             sprintf(msg,
  382                 "Device path '%s' too long. (Max. %d)",
  383                 volpath, adr_size - 1);
  384             libdax_msgs_submit(libdax_messenger, -1,
  385                 0x00000002,
  386                 LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
  387                 msg, 0, 0);
  388             {ret = -1; goto ex;}
  389         }
  390         strcpy(adr, volpath);
  391         sprintf(msg, "Accepted as valid drive '%s'", volpath);
  392         libdax_msgs_submit(libdax_messenger, -1,
  393                 0x00000002,
  394                 LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
  395                 msg, 0, 0);
  396         {ret = 1; goto ex;}
  397     }
  398     ret = 0;
  399 ex:;
  400     BURN_FREE_MEM(dev_to_open);
  401     BURN_FREE_MEM(msg);
  402     BURN_FREE_MEM(volpath);
  403     return ret;
  404 }
  405 
  406 
  407 static int end_enum_cXtYdZs2(burn_drive_enumerator_t *idx, int flag)
  408 {
  409     DIR *dir;
  410 
  411     dir = idx->dir;
  412     if(dir != NULL)
  413         closedir(dir);
  414     idx->dir = NULL;
  415     return 1;
  416 }
  417 
  418 
  419 /* ----------------------------------------------------------------------- */
  420 /* PORTING: Private functions which contain publicly needed functionality. */
  421 /*          Their portable part must be performed. So it is probably best  */
  422 /*          to replace the non-portable part and to call these functions   */
  423 /*          in your port, too.                                             */
  424 /* ----------------------------------------------------------------------- */
  425 
  426 
  427 /** Wraps a detected drive into libburn structures and hands it over to
  428     libburn drive list.
  429 */
  430 static void enumerate_common(char *fname,
  431                 int bus_no, int host_no,
  432                 int channel_no, int target_no, int lun_no)
  433 {
  434     int ret;
  435     struct burn_drive out;
  436 
  437     /* General libburn drive setup */
  438     burn_setup_drive(&out, fname);
  439 
  440     /* This transport adapter uses SCSI-family commands and models
  441        (seems the adapter would know better than its boss, if ever) */
  442     ret = burn_scsi_setup_drive(&out, bus_no, host_no, channel_no,
  443                                  target_no, lun_no, 0);
  444         if (ret <= 0)
  445                 return;
  446 
  447     /* PORTING: ------------------- non portable part --------------- */
  448 
  449     /* Transport adapter is Solaris uscsi */
  450     /* Adapter specific handles and data */
  451     out.fd = -1;
  452 
  453     /* PORTING: ---------------- end of non portable part ------------ */
  454 
  455     /* Adapter specific functions with standardized names */
  456     out.grab = sg_grab;
  457     out.release = sg_release;
  458     out.drive_is_open = sg_drive_is_open;
  459     out.issue_command = sg_issue_command;
  460     /* Finally register drive and inquire drive information */
  461     burn_drive_finish_enum(&out);
  462 }
  463 
  464 
  465 /* ------------------------------------------------------------------------ */
  466 /* PORTING:           Public functions. These MUST be ported.               */
  467 /* ------------------------------------------------------------------------ */
  468 
  469 
  470 /** Returns the id string  of the SCSI transport adapter and eventually
  471     needed operating system facilities.
  472     This call is usable even if sg_initialize() was not called yet. In that
  473     case a preliminary constant message might be issued if detailed info is
  474     not available yet.
  475     @param msg   returns id string
  476     @param flag  unused yet, submit 0
  477     @return      1 = success, <=0 = failure
  478 */
  479 int sg_id_string(char msg[1024], int flag)
  480 {
  481     sprintf(msg, "internal Solaris uscsi adapter sg-solaris");
  482     return 1;
  483 }
  484 
  485 
  486 /** Performs global initialization of the SCSI transport adapter and eventually
  487     needed operating system facilities. Checks for compatibility of supporting
  488     software components.
  489     @param msg   returns ids and/or error messages of eventual helpers
  490     @param flag  unused yet, submit 0
  491     @return      1 = success, <=0 = failure
  492 */ 
  493 int sg_initialize(char msg[1024], int flag)
  494 {
  495     return sg_id_string(msg, 0);
  496 }
  497 
  498 
  499 /** Performs global finalization of the SCSI transport adapter and eventually
  500     needed operating system facilities. Releases globally acquired resources.
  501     @param flag  unused yet, submit 0
  502     @return      1 = success, <=0 = failure
  503 */ 
  504 int sg_shutdown(int flag)
  505 {
  506     return 1;
  507 }
  508 
  509 
  510 /** Finalizes BURN_OS_TRANSPORT_DRIVE_ELEMENTS, the components of
  511     struct burn_drive which are defined in os-*.h.
  512     The eventual initialization of those components was made underneath
  513     scsi_enumerate_drives().
  514     This will be called when a burn_drive gets disposed.
  515     @param d     the drive to be finalized
  516     @param flag  unused yet, submit 0
  517     @return      1 = success, <=0 = failure
  518 */
  519 int sg_dispose_drive(struct burn_drive *d, int flag)
  520 {
  521     return 1;
  522 }
  523 
  524 
  525 /** Returns the next index number and the next enumerated drive address.
  526     The enumeration has to cover all available and accessible drives. It is
  527     allowed to return addresses of drives which are not available but under
  528     some (even exotic) circumstances could be available. It is on the other
  529     hand allowed, only to hand out addresses which can really be used right
  530     in the moment of this call. (This implementation chooses the latter.)
  531     @param idx An opaque handle. Make no own theories about it.
  532     @param adr Takes the reply
  533     @param adr_size Gives maximum size of reply including final 0
  534     @param initialize  1 = start new,
  535                        0 = continue, use no other values for now
  536                       -1 = finish
  537     @return 1 = reply is a valid address , 0 = no further address available
  538            -1 = severe error (e.g. adr_size too small)
  539 */
  540 int sg_give_next_adr(burn_drive_enumerator_t *idx,
  541              char adr[], int adr_size, int initialize)
  542 {
  543     int ret;
  544 
  545     if (initialize == 1) {
  546         ret = start_enum_cXtYdZs2(idx, 0);
  547         if (ret <= 0)
  548             return ret;
  549     } else if (initialize == -1) {
  550         ret = end_enum_cXtYdZs2(idx, 0);
  551         return 0;
  552     }
  553     ret = next_enum_cXtYdZs2(idx, adr, adr_size, 0);
  554     return ret;
  555 }
  556 
  557 
  558 /** Brings all available, not-whitelist-banned, and accessible drives into
  559     libburn's list of drives.
  560 */
  561 int scsi_enumerate_drives(void)
  562 {
  563     burn_drive_enumerator_t idx;
  564     int initialize = 1, ret, i_bus_no = -1, buf_size = 4096;
  565         int i_host_no = -1, i_channel_no = -1, i_target_no = -1, i_lun_no = -1;
  566     char *buf = NULL;
  567 
  568     BURN_ALLOC_MEM(buf, char, buf_size);
  569 
  570     while(1) {
  571         ret = sg_give_next_adr(&idx, buf, buf_size, initialize);
  572         initialize = 0;
  573         if (ret <= 0)
  574     break;
  575         if (burn_drive_is_banned(buf))
  576     continue; 
  577         sg_obtain_scsi_adr(buf, &i_bus_no, &i_host_no,
  578                 &i_channel_no, &i_target_no, &i_lun_no);
  579         enumerate_common(buf,
  580                 i_bus_no, i_host_no, i_channel_no,
  581                 i_target_no, i_lun_no);
  582     }
  583     sg_give_next_adr(&idx, buf, buf_size, -1);
  584     ret = 1;
  585 ex:;
  586     BURN_FREE_MEM(buf);
  587     return ret;
  588 }
  589 
  590 
  591 /** Tells whether libburn has the given drive in use or exclusively reserved.
  592     If it is "open" then libburn will eventually call sg_release() on it when
  593     it is time to give up usage and reservation.
  594 */
  595 /** Published as burn_drive.drive_is_open() */
  596 int sg_drive_is_open(struct burn_drive * d)
  597 {
  598     return (d->fd != -1);
  599 }
  600 
  601 
  602 /** Opens the drive for SCSI commands and - if burn activities are prone
  603     to external interference on your system - obtains an exclusive access lock
  604     on the drive. (Note: this is not physical tray locking.)
  605     A drive that has been opened with sg_grab() will eventually be handed
  606     over to sg_release() for closing and unreserving. 
  607 */  
  608 int sg_grab(struct burn_drive *d)
  609 {
  610     char *msg = NULL, *dev_to_open = NULL;
  611     int os_errno, ret;
  612     struct dk_cinfo cinfo;
  613 
  614     BURN_ALLOC_MEM(msg, char, 4096);
  615 
  616     if (d->fd != -1) {
  617         d->released = 0;
  618         {ret = 1; goto ex;}
  619     }
  620     ret = sg_solaris_convert_devname(d->devname, &dev_to_open, 0);
  621     if (ret <= 0)
  622         goto ex;
  623     d->fd = open(dev_to_open, O_RDONLY | O_NDELAY);
  624     if (d->fd == -1) {
  625         os_errno = errno;
  626         sprintf(msg, "Could not grab drive '%s'",
  627             d->devname);
  628         if (strcmp(d->devname, dev_to_open))
  629             sprintf(msg + strlen(msg), " via '%s'", dev_to_open);
  630         libdax_msgs_submit(libdax_messenger, d->global_index,
  631             0x00020003,
  632             LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
  633             msg, os_errno, 0);
  634         {ret = 0; goto ex;}
  635     }
  636     ret = ioctl(d->fd, DKIOCINFO, &cinfo);
  637     if (ret < 0) {
  638         os_errno = errno;
  639         sprintf(msg, "ioctl(DKIOCINFO) failed on drive '%s'",
  640             d->devname);
  641         libdax_msgs_submit(libdax_messenger, d->global_index,
  642             0x00000002,
  643             LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
  644             msg, os_errno, 0);
  645         goto revoke;
  646     }
  647     if (cinfo.dki_ctype != DKC_CDROM) {
  648         sprintf(msg,
  649             "ioctl(DKIOCINFO) classifies drive '%s' as dki_ctype %ld, not as DKC_CDROM = %ld",
  650             d->devname, (long int) cinfo.dki_ctype,
  651             (long int) DKC_CDROM);
  652         libdax_msgs_submit(libdax_messenger, d->global_index,
  653             0x00000002,
  654             LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
  655             msg, 0, 0);
  656         goto revoke;
  657     }
  658 
  659     /* >>> obtain eventual locks */;
  660 
  661     d->released = 0;
  662     {ret = 1; goto ex;}
  663 revoke:;
  664     sprintf(msg, "Could not grab drive '%s'. Not a CDROM device.",
  665          d->devname);
  666     libdax_msgs_submit(libdax_messenger, d->global_index,
  667             0x00020003,
  668             LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
  669             msg, 0, 0);
  670     ret = 0;
  671 ex:;
  672     BURN_FREE_MEM(dev_to_open);
  673     BURN_FREE_MEM(msg);
  674     return ret;
  675 }
  676 
  677 
  678 /** PORTING: Is mainly about the call to sg_close_drive() and whether it
  679              implements the demanded functionality.
  680 */
  681 /** Gives up the drive for SCSI commands and releases eventual access locks.
  682     (Note: this is not physical tray locking.) 
  683 */
  684 int sg_release(struct burn_drive *d)
  685 {
  686     if (d->fd < 0)
  687         return 0;
  688     sg_close_drive(d);
  689     return 0;
  690 }
  691 
  692 
  693 /** Sends a SCSI command to the drive, receives reply and evaluates whether
  694     the command succeeded or shall be retried or finally failed.
  695     Returned SCSI errors shall not lead to a return value indicating failure.
  696     The callers get notified by c->error. An SCSI failure which leads not to
  697     a retry shall be notified via scsi_notify_error().
  698     The Libburn_log_sg_commandS facility might be of help when problems with
  699     a drive have to be examined. It shall stay disabled for normal use.
  700     @return: 1 success , <=0 failure
  701 */
  702 int sg_issue_command(struct burn_drive *d, struct command *c)
  703 {
  704     int i, timeout_ms, ret, key, asc, ascq, done = 0, sense_len;
  705     time_t start_time;
  706     struct uscsi_cmd cgc;
  707     char msg[80];
  708         static FILE *fp = NULL;
  709 
  710     c->error = 0;
  711     memset(c->sense, 0, sizeof(c->sense));
  712 
  713     if (d->fd == -1)
  714         return 0;
  715 
  716     if (burn_sg_log_scsi & 1) {
  717         if (fp == NULL) {
  718             fp= fopen("/tmp/libburn_sg_command_log", "a");
  719             fprintf(fp,
  720                 "\n-----------------------------------------\n");
  721         }
  722     }
  723     if (burn_sg_log_scsi & 3)
  724         scsi_log_cmd(c,fp,0);
  725 
  726     if (c->timeout > 0)
  727         timeout_ms = c->timeout;
  728     else
  729         timeout_ms = 200000;
  730     memset (&cgc, 0, sizeof (struct uscsi_cmd));
  731     /* No error messages, no retries,
  732            do not execute with other commands, request sense data
  733     */
  734     cgc.uscsi_flags = USCSI_SILENT | USCSI_DIAGNOSE | USCSI_ISOLATE
  735                 | USCSI_RQENABLE;
  736     cgc.uscsi_timeout = timeout_ms / 1000;
  737     cgc.uscsi_cdb = (caddr_t) c->opcode;
  738     cgc.uscsi_bufaddr = (caddr_t) c->page->data;
  739     if (c->dir == TO_DRIVE) {
  740         cgc.uscsi_flags |= USCSI_WRITE;
  741         cgc.uscsi_buflen = c->page->bytes;
  742     } else if (c->dir == FROM_DRIVE) {
  743         cgc.uscsi_flags |= USCSI_READ;
  744         if (c->dxfer_len >= 0)
  745             cgc.uscsi_buflen = c->dxfer_len;
  746         else
  747             cgc.uscsi_buflen = BUFFER_SIZE;
  748         /* touch page so we can use valgrind */
  749         memset(c->page->data, 0, BUFFER_SIZE);
  750     } else {
  751         cgc.uscsi_buflen = 0;
  752     }
  753     cgc.uscsi_cdblen  = c->oplen;
  754     cgc.uscsi_rqlen = sizeof(c->sense);
  755     cgc.uscsi_rqbuf = (caddr_t) c->sense;
  756 
  757     /* ts B90523 : Record effective transfer length request for debugging*/
  758     c->dxfer_len = cgc.uscsi_buflen;
  759 
  760     /* retry-loop */
  761     start_time = time(NULL);
  762     for(i = 0; !done; i++) {
  763 
  764         memset(c->sense, 0, sizeof(c->sense));
  765         c->start_time = burn_get_time(0);
  766 
  767         ret = ioctl(d->fd, USCSICMD, &cgc);
  768 
  769         c->end_time = burn_get_time(0);
  770 
  771         /* For cgc.uscsi_status see SAM-3 5.3.1, Table 22
  772            0 = GOOD , 2 = CHECK CONDITION : Sense Data are delivered
  773            8 = BUSY
  774         */
  775         if (ret != 0 && cgc.uscsi_status != 2) {
  776             sprintf(msg,
  777         "Failed to transfer command to drive. (uscsi_status = 0x%X)",
  778                 (unsigned int) cgc.uscsi_status),
  779             libdax_msgs_submit(libdax_messenger,
  780                 d->global_index, 0x0002010c,
  781                 LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
  782                 msg, errno, 0);
  783             sg_close_drive(d);
  784             d->released = 1;
  785             d->busy = BURN_DRIVE_IDLE;
  786             c->error = 1;
  787             return -1;
  788         }
  789 
  790 
  791         /* >>> Should replace "18" by realistic sense length.
  792                What's about following older remark ?
  793         */
  794         /* >>> valid sense:  cgc.uscsi_rqlen - cgc.uscsi_rqresid */;
  795 
  796         spc_decode_sense(c->sense, 0, &key, &asc, &ascq);
  797         if (key || asc || ascq)
  798             sense_len = 18;
  799         else
  800             sense_len = 0;
  801         done = scsi_eval_cmd_outcome(d, c, fp, c->sense, sense_len,
  802                         start_time, timeout_ms, i, 0);
  803         if (d->cancel)
  804             done = 1;
  805         if (!done)
  806             spc_register_retry(c);
  807                     
  808     } /* end of retry-loop */
  809 
  810     return 1;
  811 }
  812 
  813 
  814 /** Tries to obtain SCSI address parameters.
  815     @return  1 is success , 0 is failure
  816 */
  817 int sg_obtain_scsi_adr(char *path, int *bus_no, int *host_no, int *channel_no,
  818                        int *target_no, int *lun_no)
  819 {
  820     int ret;
  821 
  822     /* Try to guess from path */
  823     if (strncmp("/dev/rdsk/", path, 10) == 0) {
  824         ret = decode_btl_solaris(path + 10,
  825                     bus_no, target_no, lun_no, 0);
  826         if (ret > 0) {
  827             *host_no = *bus_no;
  828             *channel_no = 0;
  829             return 1;
  830         }
  831     }
  832     *bus_no = *host_no = *channel_no = *target_no = *lun_no = -1;
  833 
  834     /* >>> Could need a ioctl which gives SCSI numbers */;
  835 
  836     return (0);
  837 }
  838 
  839 
  840 /** Tells whether a text is a persistent address as listed by the enumeration
  841     functions.
  842 */
  843 
  844 #ifndef NIX
  845 
  846 int sg_is_enumerable_adr(char* path)
  847 {
  848     int ret;
  849     int bus_no, target_no, lun_no;
  850     struct stat stbuf;
  851 
  852     if (strncmp("/dev/rdsk/", path, 10) != 0)
  853         return 0;
  854     ret = decode_btl_solaris(path + 10, &bus_no, &target_no, &lun_no, 0);
  855     if (ret <= 0)
  856         return 0;
  857     if (stat(path, &stbuf) == -1)
  858         return 0;
  859     return 1;
  860 }
  861 
  862 #else /* ! NIX */
  863 
  864 int sg_is_enumerable_adr(char* adr)
  865 {
  866     burn_drive_enumerator_t idx;
  867     int initialize = 1, ret;
  868     char buf[64];
  869 
  870     while(1) {
  871         ret = sg_give_next_adr(&idx, buf, sizeof(buf), initialize);
  872         initialize = 0;
  873         if (ret <= 0)
  874     break;
  875         if (strcmp(adr, buf) == 0) {
  876             sg_give_next_adr(&idx, buf, sizeof(buf), -1);
  877             return 1;
  878         }
  879     }
  880     sg_give_next_adr(&idx, buf, sizeof(buf), -1);
  881     return (0);
  882 }
  883 #endif /* NIX */
  884 
  885 
  886 
  887 
  888 /* Return 1 if the given path leads to a regular file or a device that can be
  889    fseeked, read, and possibly written with 2 kB granularity. 
  890 */
  891 int burn_os_is_2k_seekrw(char *path, int flag)
  892 {
  893     struct stat stbuf;
  894 
  895     if (stat(path, &stbuf) == -1)
  896         return 0;
  897     if (S_ISREG(stbuf.st_mode))
  898         return 1;
  899     if (S_ISBLK(stbuf.st_mode))
  900         return 1;
  901     return 0;
  902 }
  903 
  904 
  905 /** Estimate the potential payload capacity of a file address.
  906     @param path  The address of the file to be examined. If it does not
  907                  exist yet, then the directory will be inquired.
  908     @param bytes The pointed value gets modified, but only if an estimation is
  909                  possible.
  910     @return      -2 = cannot perform necessary operations on file object
  911                  -1 = neither path nor dirname of path exist
  912                   0 = could not estimate size capacity of file object
  913                   1 = estimation has been made, bytes was set
  914 */
  915 int burn_os_stdio_capacity(char *path, off_t write_start, off_t *bytes)
  916 {
  917     struct stat stbuf;
  918     int ret;
  919 
  920 #ifdef Libburn_os_has_statvfS
  921     struct statvfs vfsbuf;
  922 #endif
  923 
  924     char *testpath = NULL, *cpt;
  925     off_t add_size = 0;
  926 
  927     BURN_ALLOC_MEM(testpath, char, 4096);
  928 
  929     testpath[0] = 0;
  930     if (stat(path, &stbuf) == -1) {
  931         strcpy(testpath, path);
  932         cpt = strrchr(testpath, '/');
  933         if(cpt == NULL)
  934             strcpy(testpath, ".");
  935         else if(cpt == testpath)
  936             testpath[1] = 0;
  937         else
  938             *cpt = 0;
  939         if (stat(testpath, &stbuf) == -1)
  940             {ret = -1; goto ex;}
  941 
  942     } else if(S_ISBLK(stbuf.st_mode)) {
  943         int open_mode = O_RDONLY, fd;
  944 
  945         fd = open(path, open_mode);
  946         if (fd == -1)
  947             {ret = -2; goto ex;}
  948         *bytes = lseek(fd, 0, SEEK_END);
  949         close(fd);
  950         if (*bytes == -1) {
  951             *bytes = 0;
  952             {ret = 0; goto ex;}
  953         }
  954 
  955     } else if(S_ISREG(stbuf.st_mode)) {
  956         add_size = burn_sparse_file_addsize(write_start, &stbuf);
  957         strcpy(testpath, path);
  958     } else
  959         {ret = 0; goto ex;}
  960 
  961     if (testpath[0]) {  
  962 
  963 #ifdef Libburn_os_has_statvfS
  964 
  965         if (statvfs(testpath, &vfsbuf) == -1)
  966             {ret = -2; goto ex;}
  967         *bytes = add_size + ((off_t) vfsbuf.f_frsize) *
  968                         (off_t) vfsbuf.f_bavail;
  969 
  970 #else /* Libburn_os_has_statvfS */
  971 
  972         {ret = 0; goto ex;}
  973 
  974 #endif /* ! Libburn_os_has_stavtfS */
  975 
  976     }
  977     ret = 1;
  978 ex:;
  979     BURN_FREE_MEM(testpath);
  980     return ret;
  981 }
  982 
  983 
  984 /* ts A91122 : an interface to open(O_DIRECT) or similar OS tricks. */
  985 
  986 #ifdef Libburn_read_o_direcT
  987 
  988     /* No special O_DIRECT-like precautions are implemented here */
  989 
  990 #endif /* Libburn_read_o_direcT */
  991 
  992 
  993 int burn_os_open_track_src(char *path, int open_flags, int flag)
  994 {
  995     int fd;
  996 
  997     fd = open(path, open_flags);
  998     return fd;
  999 }
 1000 
 1001 
 1002 void *burn_os_alloc_buffer(size_t amount, int flag)
 1003 {
 1004     void *buf = NULL;
 1005 
 1006     buf = calloc(1, amount);
 1007     return buf;
 1008 }
 1009 
 1010 
 1011 int burn_os_free_buffer(void *buffer, size_t amount, int flag)
 1012 {
 1013     if (buffer == NULL)
 1014         return 0;
 1015     free(buffer);
 1016     return 1;
 1017 }
 1018