"Fossies" - the Fresh Open Source Software Archive

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