"Fossies" - the Fresh Open Source Software Archive

Member "xorriso-1.5.4/libburn/sg-freebsd.c" (30 Jan 2021, 29175 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-freebsd.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.5.1_vs_1.5.2.

    1 /* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
    2 
    3 /* 
    4    Copyright (c) 2006 - 2013 Thomas Schmitt <scdbackup@gmx.net>
    5    Provided under GPL version 2 or later
    6         and under FreeBSD license revised, i.e. without advertising clause.
    7 */
    8 
    9 #ifdef HAVE_CONFIG_H
   10 #include "../config.h"
   11 #endif
   12 
   13 #include <errno.h>
   14 #include <unistd.h>
   15 #include <stdio.h>
   16 #include <sys/types.h>
   17 #include <sys/stat.h>
   18 #include <fcntl.h>
   19 #include <sys/ioctl.h>
   20 #include <sys/file.h>
   21 #include <stdlib.h>
   22 #include <string.h>
   23 #include <sys/poll.h>
   24 #include <camlib.h>
   25 #include <cam/scsi/scsi_message.h>
   26 #include <cam/scsi/scsi_pass.h>
   27 
   28 #include <err.h> /* XXX */
   29 
   30 /* ts A70909 */
   31 #include <sys/statvfs.h>
   32 
   33 /* ts B00121 */
   34 #include <sys/disk.h> /* DIOCGMEDIASIZE */
   35 
   36 
   37 /* ts B00326 : For use of CAM_PASS_ERR_RECOVER with ahci */
   38 #define Libburn_for_freebsd_ahcI yes
   39 
   40 /* ts B00327 : for debugging of cam_send_cdb() failures
   41  # define Libburn_ahci_verbouS yes
   42 */
   43 
   44 /* ts B00327 : Apply CAM_PASS_ERR_RECOVER to drives even if not ahci
   45  # define libburn_ahci_style_for_alL yes
   46 */
   47 
   48 
   49 #include "transport.h"
   50 #include "drive.h"
   51 #include "sg.h"
   52 #include "spc.h"
   53 #include "mmc.h"
   54 #include "sbc.h"
   55 #include "debug.h"
   56 #include "toc.h"
   57 #include "util.h"
   58 #include "init.h"
   59 
   60 #include "libdax_msgs.h"
   61 extern struct libdax_msgs *libdax_messenger;
   62 
   63 struct burn_drive_enumeration_state {
   64     int fd;
   65     union ccb ccb;
   66     unsigned int i;
   67     int skip_device;
   68 };
   69 
   70 static void enumerate_common(char *fname, int bus_no, int host_no,
   71                  int channel_no, int target_no, int lun_no);
   72 
   73 /* ts A51221 */
   74 int burn_drive_is_banned(char *device_address);
   75 
   76 
   77 /* ts A60821
   78    debug: for tracing calls which might use open drive fds
   79           or for catching SCSI usage of emulated drives. */
   80 int mmc_function_spy(struct burn_drive *d, char * text);
   81 
   82 
   83 /* ts B00113
   84    Whether to log SCSI commands:
   85    bit0= log in /tmp/libburn_sg_command_log
   86    bit1= log to stderr
   87    bit2= flush every line
   88 */
   89 extern int burn_sg_log_scsi;
   90 
   91 /* ts B00114 */
   92 /* Storage object is in libburn/init.c
   93    whether to strive for exclusive access to the drive
   94 */
   95 extern int burn_sg_open_o_excl;
   96 
   97 
   98 /* ts A91227 */
   99 /** Returns the id string  of the SCSI transport adapter and eventually
  100     needed operating system facilities.
  101     This call is usable even if sg_initialize() was not called yet. In that
  102     case a preliminary constant message might be issued if detailed info is
  103     not available yet.
  104     @param msg   returns id string
  105     @param flag  unused yet, submit 0
  106     @return      1 = success, <=0 = failure
  107 */
  108 int sg_id_string(char msg[1024], int flag)
  109 {
  110     strcpy(msg, "internal FreeBSD CAM adapter sg-freebsd");
  111     return 1;
  112 }
  113 
  114 
  115 /* ts A91227 */
  116 /** Performs global initialization of the SCSI transport adapter and eventually
  117     needed operating system facilities. Checks for compatibility supporting
  118     software components.
  119     @param msg   returns ids and/or error messages of eventual helpers
  120     @param flag  unused yet, submit 0
  121     @return      1 = success, <=0 = failure
  122 */
  123 int sg_initialize(char msg[1024], int flag)
  124 {
  125     return sg_id_string(msg, 0);
  126 }
  127 
  128 
  129 /* ts A91227 */
  130 /** Performs global finalization of the SCSI transport adapter and eventually
  131     needed operating system facilities. Releases globally acquired resources.
  132     @param flag  unused yet, submit 0
  133     @return      1 = success, <=0 = failure
  134 */  
  135 int sg_shutdown(int flag)
  136 {
  137     return 1;
  138 }
  139 
  140 
  141 /** Finalizes BURN_OS_TRANSPORT_DRIVE_ELEMENTS, the components of
  142     struct burn_drive which are defined in os-*.h.
  143     The eventual initialization of those components was made underneath
  144     scsi_enumerate_drives().
  145     This will be called when a burn_drive gets disposed.
  146     @param d     the drive to be finalized
  147     @param flag  unused yet, submit 0
  148     @return      1 = success, <=0 = failure
  149 */
  150 int sg_dispose_drive(struct burn_drive *d, int flag)
  151 {
  152         return 1;
  153 }
  154 
  155 
  156 /* ts A61021 : Moved most code from scsi_enumerate_drives under
  157                sg_give_next_adr() */
  158 /* Some helper functions for scsi_give_next_adr() */
  159 
  160 static int sg_init_enumerator(burn_drive_enumerator_t *idx_)
  161 {
  162     struct burn_drive_enumeration_state *idx;
  163     int bufsize;
  164 
  165     idx = calloc(1, sizeof(*idx));
  166     if (idx == NULL) {
  167         warnx("cannot allocate memory for enumerator");
  168         return -1;
  169     }
  170     idx->skip_device = 0;
  171 
  172     if ((idx->fd = open(XPT_DEVICE, O_RDWR)) == -1) {
  173         warn("could not open %s", XPT_DEVICE);
  174         free(idx);
  175         idx = NULL;
  176         return -1;
  177     }
  178 
  179     memset(&(idx->ccb), 0, sizeof(union ccb));
  180 
  181     idx->ccb.ccb_h.path_id = CAM_XPT_PATH_ID;
  182     idx->ccb.ccb_h.target_id = CAM_TARGET_WILDCARD;
  183     idx->ccb.ccb_h.target_lun = CAM_LUN_WILDCARD;
  184 
  185     idx->ccb.ccb_h.func_code = XPT_DEV_MATCH;
  186     bufsize = sizeof(struct dev_match_result) * 100;
  187     idx->ccb.cdm.match_buf_len = bufsize;
  188     idx->ccb.cdm.matches = (struct dev_match_result *) calloc(1, bufsize);
  189     if (idx->ccb.cdm.matches == NULL) {
  190         warnx("cannot allocate memory for matches");
  191         close(idx->fd);
  192         free(idx);
  193         return -1;
  194     }
  195     idx->ccb.cdm.num_matches = 0;
  196     idx->i = idx->ccb.cdm.num_matches; /* to trigger buffer load */
  197 
  198     /*
  199      * We fetch all nodes, since we display most of them in the default
  200      * case, and all in the verbose case.
  201      */
  202     idx->ccb.cdm.num_patterns = 0;
  203     idx->ccb.cdm.pattern_buf_len = 0;
  204 
  205     *idx_ = idx;
  206 
  207     return 1;
  208 }
  209 
  210 static void sg_destroy_enumerator(burn_drive_enumerator_t *idx_)
  211 {
  212     struct burn_drive_enumeration_state *idx = *idx_;
  213 
  214     if(idx->fd != -1)
  215         close(idx->fd);
  216 
  217     free(idx->ccb.cdm.matches);
  218     free(idx);
  219 
  220     *idx_ = NULL;
  221 }
  222 
  223 static int sg_next_enumeration_buffer(burn_drive_enumerator_t *idx_)
  224 {
  225     struct burn_drive_enumeration_state *idx = *idx_;
  226 
  227     /*
  228      * We do the ioctl multiple times if necessary, in case there are
  229      * more than 100 nodes in the EDT.
  230      */
  231     if (ioctl(idx->fd, CAMIOCOMMAND, &(idx->ccb)) == -1) {
  232         warn("error sending CAMIOCOMMAND ioctl");
  233         return -1;
  234     }
  235 
  236     if ((idx->ccb.ccb_h.status != CAM_REQ_CMP)
  237         || ((idx->ccb.cdm.status != CAM_DEV_MATCH_LAST)
  238         && (idx->ccb.cdm.status != CAM_DEV_MATCH_MORE))) {
  239         warnx("got CAM error %#x, CDM error %d\n",
  240               idx->ccb.ccb_h.status, idx->ccb.cdm.status);
  241         return -1;
  242     }
  243     return 1;
  244 }
  245 
  246 
  247 /** Returns the next index object state and the next enumerated drive address.
  248     @param idx An opaque handle. Make no own theories about it.
  249     @param adr Takes the reply
  250     @param adr_size Gives maximum size of reply including final 0
  251     @param initialize  1 = start new,
  252                        0 = continue, use no other values for now
  253                       -1 = finish
  254     @return 1 = reply is a valid address , 0 = no further address available
  255            -1 = severe error (e.g. adr_size too small)
  256 */
  257 int sg_give_next_adr(burn_drive_enumerator_t *idx_,
  258              char adr[], int adr_size, int initialize)
  259 {
  260     struct burn_drive_enumeration_state *idx;
  261     int ret;
  262 
  263     if (initialize == 1) {
  264         ret = sg_init_enumerator(idx_);
  265         if (ret<=0)
  266             return ret;
  267     } else if (initialize == -1) {
  268         sg_destroy_enumerator(idx_);
  269         return 0;
  270     }
  271 
  272     idx = *idx_;
  273 
  274     do {
  275         if (idx->i >= idx->ccb.cdm.num_matches) {
  276             ret = sg_next_enumeration_buffer(idx_);
  277             if (ret<=0)
  278                 return -1;
  279             idx->i = 0;
  280         } else
  281             (idx->i)++;
  282 
  283         while (idx->i < idx->ccb.cdm.num_matches) {
  284             switch (idx->ccb.cdm.matches[idx->i].type) {
  285             case DEV_MATCH_BUS:
  286                 break;
  287             case DEV_MATCH_DEVICE: {
  288                 struct device_match_result* result;
  289 
  290                 result = &(idx->ccb.cdm.matches[idx->i].result.device_result);
  291                 if (result->flags & DEV_RESULT_UNCONFIGURED)
  292                     idx->skip_device = 1;
  293                 else
  294                     idx->skip_device = 0;
  295                 break;
  296             }
  297             case DEV_MATCH_PERIPH: {
  298                 struct periph_match_result* result;
  299 
  300                 result = &(idx->ccb.cdm.matches[idx->i].result.periph_result);
  301 /* ts B00112 : we really want only "cd" devices.
  302 
  303                 if (idx->skip_device || 
  304                     strcmp(result->periph_name, "pass") == 0)
  305                     break;
  306 */
  307                 if (idx->skip_device || 
  308                     strcmp(result->periph_name, "cd") != 0)
  309                     break;
  310                 ret = snprintf(adr, adr_size, "/dev/%s%d",
  311                      result->periph_name, result->unit_number);
  312                 if(ret >= adr_size)
  313                     return -1;
  314 
  315                 /* Found next enumerable address */
  316                 return 1;
  317 
  318             }
  319             default:
  320                 /* fprintf(stderr, "unknown match type\n"); */
  321                 break;
  322             }
  323             (idx->i)++;
  324         }
  325     } while ((idx->ccb.ccb_h.status == CAM_REQ_CMP)
  326         && (idx->ccb.cdm.status == CAM_DEV_MATCH_MORE));
  327 
  328     return 0;
  329 }
  330 
  331 
  332 int sg_is_enumerable_adr(char* adr)
  333 {
  334     burn_drive_enumerator_t idx;
  335     int ret;
  336     char buf[64];
  337 
  338     ret = sg_init_enumerator(&idx);
  339     if (ret <= 0)
  340         return 0;
  341     while(1) {
  342         ret = sg_give_next_adr(&idx, buf, sizeof(buf), 0);
  343         if (ret <= 0)
  344             break;
  345         if (strcmp(adr, buf) == 0) {
  346             sg_destroy_enumerator(&idx);
  347             return 1;
  348         }
  349     }
  350     sg_destroy_enumerator(&idx);
  351     return (0);
  352 }
  353 
  354 
  355 /** Try to obtain SCSI address parameters.
  356     @return  1 is success , 0 is failure
  357 */
  358 int sg_obtain_scsi_adr(char *path, int *bus_no, int *host_no, int *channel_no,
  359                        int *target_no, int *lun_no)
  360 {
  361     burn_drive_enumerator_t idx;
  362     int ret;
  363     char buf[64];
  364     struct periph_match_result* result;
  365 
  366     ret = sg_init_enumerator(&idx);
  367     if (ret <= 0)
  368         return 0;
  369     while(1) {
  370         ret = sg_give_next_adr(&idx, buf, sizeof(buf), 0);
  371         if (ret <= 0)
  372             break;
  373         if (strcmp(path, buf) == 0) {
  374             result = &(idx->ccb.cdm.matches[idx->i].result.periph_result);
  375             *bus_no = result->path_id;
  376             *host_no = result->path_id;
  377             *channel_no = 0;
  378             *target_no = result->target_id;
  379             *lun_no = result->target_lun;
  380             sg_destroy_enumerator(&idx);
  381             return 1;
  382         }
  383     }
  384     sg_destroy_enumerator(&idx);
  385     return (0);
  386 }
  387 
  388 
  389 int sg_close_drive(struct burn_drive * d)
  390 {
  391     if (d->cam != NULL) {
  392         cam_close_device(d->cam);
  393         d->cam = NULL;
  394     }
  395     if (d->lock_fd > 0) {
  396         close(d->lock_fd);
  397         d->lock_fd = -1;
  398     }
  399     return 0;
  400 }
  401 
  402 int sg_drive_is_open(struct burn_drive * d)
  403 {
  404     return (d->cam != NULL);
  405 }
  406 
  407 int scsi_enumerate_drives(void)
  408 {
  409     burn_drive_enumerator_t idx;
  410     int ret;
  411     char buf[64];
  412     struct periph_match_result* result;
  413 
  414     ret = sg_init_enumerator(&idx);
  415     if (ret <= 0)
  416         return 0;
  417     while(1) {
  418         ret = sg_give_next_adr(&idx, buf, sizeof(buf), 0);
  419         if (ret <= 0)
  420             break;
  421         if (burn_drive_is_banned(buf))
  422             continue; 
  423         result = &idx->ccb.cdm.matches[idx->i].result.periph_result;
  424         enumerate_common(buf, result->path_id, result->path_id,
  425                 0, result->target_id, 
  426                 result->target_lun);
  427     }
  428     sg_destroy_enumerator(&idx);
  429 
  430     return 1;
  431 }
  432 
  433 
  434 #ifdef Scsi_freebsd_make_own_enumeratE
  435 
  436 /* ts A61021: The old version which mixes SCSI and operating system adapter
  437 */
  438 static void enumerate_common(char *fname, int bus_no, int host_no,
  439                  int channel_no, int target_no, int lun_no)
  440 {
  441     struct burn_drive *t;
  442     struct burn_drive out;
  443 
  444     /* Initialize pointers to managed memory */
  445     out.devname = NULL;
  446     out.idata = NULL;
  447     out.mdata = NULL;
  448 
  449     /* ts A60923 */
  450     out.bus_no = bus_no;
  451     out.host = host_no;
  452     out.id = target_no;
  453     out.channel = channel_no;
  454     out.lun = lun_no;
  455 
  456     out.devname = strdup(fname);
  457     if (out.devname == NULL)
  458         goto could_not_allocate;
  459 
  460     out.cam = NULL;
  461     out.lock_fd = -1;
  462     out.is_ahci = 0;
  463 
  464     out.start_lba= -2000000000;
  465     out.end_lba= -2000000000;
  466     out.read_atip = mmc_read_atip;
  467 
  468     out.grab = sg_grab;
  469     out.release = sg_release;
  470     out.drive_is_open= sg_drive_is_open;
  471     out.issue_command = sg_issue_command;
  472     out.getcaps = spc_getcaps;
  473     out.released = 1;
  474     out.status = BURN_DISC_UNREADY;
  475 
  476     out.eject = sbc_eject;
  477     out.load = sbc_load;
  478     out.lock = spc_prevent;
  479     out.unlock = spc_allow;
  480     out.read_disc_info = spc_sense_write_params;
  481     out.get_erase_progress = spc_get_erase_progress;
  482     out.test_unit_ready = spc_test_unit_ready;
  483     out.probe_write_modes = spc_probe_write_modes;
  484     out.read_toc = mmc_read_toc;
  485     out.write = mmc_write;
  486     out.erase = mmc_erase;
  487     out.read_cd = mmc_read_cd;
  488     out.perform_opc = mmc_perform_opc;
  489     out.set_speed = mmc_set_speed;
  490     out.send_parameters = spc_select_error_params;
  491     out.send_write_parameters = spc_select_write_params;
  492     out.send_cue_sheet = mmc_send_cue_sheet;
  493     out.sync_cache = mmc_sync_cache;
  494     out.get_nwa = mmc_get_nwa;
  495     out.close_disc = mmc_close_disc;
  496     out.close_session = mmc_close_session;
  497     out.close_track_session = mmc_close;
  498     out.read_buffer_capacity = mmc_read_buffer_capacity;
  499     out.idata = calloc(1, sizeof(struct burn_scsi_inquiry_data));
  500     out.idata->valid = 0;
  501     out.mdata = calloc(1, sizeof(struct scsi_mode_data));
  502     if (out.idata == NULL || out.mdata == NULL) {
  503 could_not_allocate:;
  504         libdax_msgs_submit(libdax_messenger, -1, 0x00020108,
  505             LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
  506             "Could not allocate new drive object", 0, 0);
  507         if (out.devname != NULL)
  508             free(out.devname);
  509         out.devname = NULL;
  510         if (out.idata != NULL)
  511             free(out.idata);
  512         out.idata = NULL;
  513         if (out.mdata != NULL)
  514             free(out.mdata);
  515         out.mdata = NULL;
  516         return;
  517     }
  518     out.mdata->p2a_valid = 0;
  519     memset(&out.params, 0, sizeof(struct params));
  520     t = burn_drive_register(&out);
  521 
  522 /* ts A60821
  523    <<< debug: for tracing calls which might use open drive fds */
  524     mmc_function_spy(NULL, "enumerate_common : -------- doing grab");
  525 
  526 /* try to get the drive info */
  527     if (t->grab(t)) {
  528         t->getcaps(t);
  529         t->unlock(t);
  530         t->released = 1;
  531     }
  532 
  533 /* ts A60821
  534    <<< debug: for tracing calls which might use open drive fds */
  535     mmc_function_spy(NULL, "enumerate_common : ----- would release ");
  536 
  537 }
  538 
  539 #else /* Scsi_freebsd_make_own_enumeratE */
  540 
  541 /* The new, more concise version of enumerate_common */
  542 static void enumerate_common(char *fname, int bus_no, int host_no,
  543                  int channel_no, int target_no, int lun_no)
  544 {
  545     int ret;
  546     struct burn_drive out;
  547 
  548     /* General libburn drive setup */
  549     burn_setup_drive(&out, fname);
  550 
  551     /* This transport adapter uses SCSI-family commands and models
  552        (seems the adapter would know better than its boss, if ever) */
  553     ret = burn_scsi_setup_drive(&out, bus_no, host_no, channel_no,
  554                                  target_no, lun_no, 0);
  555         if (ret<=0)
  556                 return;
  557 
  558     /* Operating system adapter is CAM */
  559     /* Adapter specific handles and data */
  560     out.cam = NULL;
  561     out.lock_fd = -1;
  562     out.is_ahci = 0;
  563 
  564     /* Adapter specific functions */
  565     out.grab = sg_grab;
  566     out.release = sg_release;
  567     out.drive_is_open = sg_drive_is_open;
  568     out.issue_command = sg_issue_command;
  569 
  570     /* Finally register drive and inquire drive information */
  571     burn_drive_finish_enum(&out);
  572 }
  573 
  574 #endif /* ! Scsi_freebsd_make_own_enumeratE */
  575 
  576 
  577 /* Lock the inode associated to dev_fd and the inode associated to devname.
  578    Return OS errno, number of pass device of dev_fd, locked fd to devname,
  579    error message.
  580    A return value of > 0 means success, <= 0 means failure.
  581 */
  582 static int freebsd_dev_lock(int dev_fd, char *devname,
  583      int *os_errno, int *pass_dev_no, int *lock_fd, char msg[4096],
  584      int flag)
  585 {
  586     int lock_denied = 0, fd_stbuf_valid, name_stbuf_valid, i, pass_l = 100;
  587     int max_retry = 3, tries = 0;
  588     struct stat fd_stbuf, name_stbuf;
  589     char pass_name[16], *lock_name;
  590 
  591     *os_errno = 0;
  592     *pass_dev_no = -1;
  593     *lock_fd = -1;
  594     msg[0] = 0;
  595 
  596     fd_stbuf_valid = !fstat(dev_fd, &fd_stbuf);
  597 
  598     /* Try to find name of pass device by inode number */
  599     lock_name = (char *) "effective device";
  600     if(fd_stbuf_valid) {
  601         for (i = 0; i < pass_l; i++) {
  602             sprintf(pass_name, "/dev/pass%d", i);
  603             if (stat(pass_name, &name_stbuf) != -1)
  604                 if(fd_stbuf.st_ino == name_stbuf.st_ino &&
  605                 fd_stbuf.st_dev == name_stbuf.st_dev)   
  606         break;
  607         }
  608         if (i < pass_l) {
  609             lock_name = pass_name;
  610             *pass_dev_no = i;
  611         }
  612     }
  613 
  614     name_stbuf_valid = !stat(devname, &name_stbuf);
  615     for (tries= 0; tries <= max_retry; tries++) {
  616         lock_denied = flock(dev_fd, LOCK_EX | LOCK_NB);
  617         *os_errno = errno;
  618         if (lock_denied) {
  619             if (errno == EAGAIN && tries < max_retry) {
  620                 /* <<< debugging
  621                 fprintf(stderr,
  622                 "\nlibcdio_DEBUG: EAGAIN pass, tries= %d\n",
  623                     tries);
  624                 */
  625                 usleep(2000000);
  626     continue;
  627             }
  628             sprintf(msg,
  629                 "Device busy. flock(LOCK_EX) failed on %s of %s",
  630                 strlen(lock_name) > 2000 || *pass_dev_no < 0 ?
  631                          "pass device" : lock_name,
  632                 strlen(devname) > 2000 ? "drive" : devname);
  633             return 0;
  634         }
  635     break;
  636     }
  637 
  638     /*
  639     fprintf(stderr, "libburn_DEBUG: flock obtained on %s of %s\n",
  640             lock_name, devname);
  641     */
  642 
  643     /* Eventually lock the official device node too */
  644     if (fd_stbuf_valid && name_stbuf_valid &&
  645         (fd_stbuf.st_ino != name_stbuf.st_ino ||
  646          fd_stbuf.st_dev != name_stbuf.st_dev)) {
  647 
  648         *lock_fd = open(devname, O_RDONLY);
  649         if (*lock_fd == 0) {
  650             close(*lock_fd);
  651             *lock_fd = -1;
  652         } if (*lock_fd > 0) {
  653             for (tries = 0; tries <= max_retry; tries++) {
  654                 lock_denied = 
  655                     flock(*lock_fd, LOCK_EX | LOCK_NB);
  656                 if (lock_denied) {
  657                     if (errno == EAGAIN &&
  658                              tries < max_retry) {
  659                         /* <<< debugging
  660                         fprintf(stderr,
  661                 "\nlibcdio_DEBUG: EAGAIN dev, tries= %d\n",
  662                             tries);
  663                         */
  664 
  665                         usleep(2000000);
  666             continue;
  667                     }
  668                     close(*lock_fd);
  669                     *lock_fd = -1;
  670                     sprintf(msg,
  671                  "Device busy. flock(LOCK_EX) failed on %s",
  672                  strlen(devname) > 4000 ? "drive" : devname);
  673                     return 0;
  674                 }
  675             break;
  676             }
  677         }
  678 
  679 /*
  680         fprintf(stderr, "libburn_DEBUG: flock obtained on %s\n",
  681                 devname);
  682 */
  683 
  684     }
  685     return 1;
  686 }
  687 
  688 
  689 static int sg_lock(struct burn_drive *d, int flag)
  690 {
  691     int ret, os_errno, pass_dev_no = -1, flock_fd = -1;
  692     char *msg = NULL;
  693 
  694     BURN_ALLOC_MEM(msg, char, 4096);
  695     ret = freebsd_dev_lock(d->cam->fd, d->devname,
  696                 &os_errno, &pass_dev_no, &flock_fd, msg, 0);
  697     if (ret <= 0) {
  698         libdax_msgs_submit(libdax_messenger, d->global_index,
  699             0x00020008,
  700             LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
  701             msg, os_errno, 0);
  702         sg_close_drive(d);
  703         {ret = 0; goto ex;}
  704     }
  705     if (d->lock_fd > 0)
  706         close(d->lock_fd);
  707     d->lock_fd = flock_fd;
  708     ret = 1;
  709 ex:;
  710     BURN_FREE_MEM(msg);
  711     return ret;
  712 }
  713 
  714 
  715 int sg_grab(struct burn_drive *d)
  716 {
  717     struct cam_device *cam;
  718     char path_string[80];
  719 
  720     if (mmc_function_spy(d, "sg_grab") <= 0)
  721         return 0;
  722 
  723     if (burn_drive_is_open(d)) {
  724         d->released = 0;
  725         return 1;
  726     }
  727 
  728     cam = cam_open_device(d->devname, O_RDWR);
  729     if (cam == NULL) {
  730         libdax_msgs_submit(libdax_messenger, d->global_index,
  731                 0x00020003,
  732                 LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
  733                 "Could not grab drive", errno, 0);
  734         return 0;
  735     }
  736     d->cam = cam;
  737     if (burn_sg_open_o_excl & 63)
  738         if (sg_lock(d, 0) <= 0)
  739             return 0;
  740     fcntl(cam->fd, F_SETOWN, getpid());
  741 
  742     cam_path_string(d->cam, path_string, sizeof(path_string));
  743 
  744 #ifdef Libburn_ahci_verbouS
  745     fprintf(stderr, "libburn_EXPERIMENTAL: CAM path = %s\n", path_string);
  746 #endif
  747 
  748     if (strstr(path_string, ":ahcich") != NULL)
  749         d->is_ahci = 1;
  750     else
  751         d->is_ahci = -1;
  752 
  753     d->released = 0;
  754     return 1;
  755 }
  756 
  757 
  758 /*
  759     non zero return means you still have the drive and it's not
  760     in a state to be released? (is that even possible?)
  761 */
  762 
  763 int sg_release(struct burn_drive *d)
  764 {
  765     if (mmc_function_spy(d, "sg_release") <= 0)
  766         return 0;
  767 
  768     if (d->cam == NULL)
  769         return 0;
  770 
  771     mmc_function_spy(NULL, "sg_release ----------- closing.");
  772 
  773     sg_close_drive(d);
  774     d->released = 1;
  775     return 0;
  776 }
  777 
  778 int sg_issue_command(struct burn_drive *d, struct command *c)
  779 {
  780     int done = 0, err, sense_len = 0, ret, ignore_error, i;
  781     int cam_pass_err_recover = 0, key, asc, ascq, timeout_ms;
  782     union ccb *ccb;
  783     static FILE *fp = NULL;
  784     time_t start_time;
  785 
  786     mmc_function_spy(NULL, "sg_issue_command");
  787 
  788     c->error = 0;
  789     memset(c->sense, 0, sizeof(c->sense));
  790 
  791     if (d->cam == NULL)
  792         return 0;
  793     if (burn_sg_log_scsi & 1) {
  794         if (fp == NULL) {
  795             fp= fopen("/tmp/libburn_sg_command_log", "a");
  796             fprintf(fp,
  797                 "\n-----------------------------------------\n");
  798         }
  799     }
  800     if (burn_sg_log_scsi & 3)
  801         scsi_log_cmd(c,fp,0);
  802 
  803     c->error = 0;
  804     if (c->timeout > 0)
  805         timeout_ms = c->timeout;
  806     else
  807         timeout_ms = 200000;
  808 
  809     ccb = cam_getccb(d->cam);
  810     cam_fill_csio(&ccb->csio,
  811                   1,                              /* retries */
  812                   NULL,                           /* cbfncp */
  813                   CAM_DEV_QFRZDIS,                /* flags */
  814                   MSG_SIMPLE_Q_TAG,               /* tag_action */
  815                   NULL,                           /* data_ptr */
  816                   0,                              /* dxfer_len */
  817                   sizeof (ccb->csio.sense_data),  /* sense_len */
  818                   0,                              /* cdb_len */
  819                   timeout_ms);                    /* timeout */
  820     switch (c->dir) {
  821     case TO_DRIVE:
  822         ccb->csio.ccb_h.flags |= CAM_DIR_OUT;
  823         break;
  824     case FROM_DRIVE:
  825         ccb->csio.ccb_h.flags |= CAM_DIR_IN;
  826         break;
  827     case NO_TRANSFER:
  828         ccb->csio.ccb_h.flags |= CAM_DIR_NONE;
  829         break;
  830     }
  831 
  832 #ifdef Libburn_for_freebsd_ahcI
  833     /* ts B00325 : Advise by Alexander Motin */
  834         /* Runs well on 8-STABLE (23 Mar 2003)
  835        But on 8-RELEASE cam_send_ccb() returns non-zero with errno 6
  836            on eject. Long lasting TEST UNIT READY cycles break with
  837            errno 16.
  838         */
  839 #ifdef Libburn_ahci_style_for_alL
  840     {
  841 #else
  842     if (d->is_ahci > 0) {
  843 #endif
  844         ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
  845         cam_pass_err_recover = 1;
  846     }
  847 #endif /* Libburn_for_freebsd_ahcI */
  848 
  849     ccb->csio.cdb_len = c->oplen;
  850     memcpy(&ccb->csio.cdb_io.cdb_bytes, &c->opcode, c->oplen);
  851     
  852     if (c->page) {
  853         ccb->csio.data_ptr  = c->page->data;
  854         if (c->dir == FROM_DRIVE) {
  855 
  856             /* ts A90430 : Ticket 148 , by jwehle :
  857                "On ... FreeBSD 6.4 which has a usb memory reader in
  858                 addition to a ATAPI DVD burner sg_issue_command
  859                 will hang while the SCSI bus is being scanned"
  860             */
  861             if (c->dxfer_len >= 0)
  862                 ccb->csio.dxfer_len = c->dxfer_len;
  863             else
  864                 ccb->csio.dxfer_len = BUFFER_SIZE;
  865 
  866 /* touch page so we can use valgrind */
  867             memset(c->page->data, 0, BUFFER_SIZE);
  868         } else {
  869             ccb->csio.dxfer_len = c->page->bytes;
  870         }
  871     } else {
  872         ccb->csio.data_ptr  = NULL;
  873         ccb->csio.dxfer_len = 0;
  874     }
  875 
  876     /* ts B90523 : Record effective transfer length request for debugging*/
  877     c->dxfer_len = ccb->csio.dxfer_len;
  878 
  879     start_time = time(NULL);
  880     for (i = 0; !done; i++) {
  881 
  882         memset(&ccb->csio.sense_data, 0, sizeof(ccb->csio.sense_data));
  883         memset(c->sense, 0, sizeof(c->sense));
  884         c->start_time = burn_get_time(0);
  885 
  886         err = cam_send_ccb(d->cam, ccb);
  887 
  888         c->end_time = burn_get_time(0);
  889         ignore_error = sense_len = 0;
  890         /* ts B00325 : CAM_AUTOSNS_VALID advised by Alexander Motin */
  891         if (ccb->ccb_h.status & CAM_AUTOSNS_VALID) {
  892             /* ts B00110 */
  893             /* Better curb sense_len */
  894             sense_len = ccb->csio.sense_len;
  895             if (sense_len > (int) sizeof(c->sense))
  896                 sense_len = sizeof(c->sense);
  897             memcpy(c->sense, &ccb->csio.sense_data, sense_len);
  898             spc_decode_sense(c->sense, sense_len,
  899                             &key, &asc, &ascq);
  900             if (sense_len >= 14 && cam_pass_err_recover && key)
  901                 ignore_error = 1;
  902         }
  903 
  904         if (err == -1 && cam_pass_err_recover && ! ignore_error) {
  905 
  906 #ifdef Libburn_ahci_verbouS
  907             fprintf(stderr, "libburn_EXPERIMENTAL: errno = %d . cam_errbuf = '%s'\n", errno, cam_errbuf);
  908 #endif
  909 
  910             if (errno == ENXIO && c->opcode[0] != 0) {
  911                 /* Operations on empty or ejected tray */
  912                 /* MEDIUM NOT PRESENT */
  913 
  914 #ifdef Libburn_ahci_verbouS
  915                 fprintf(stderr, "libburn_EXPERIMENTAL: Emulating [2,3A,00] MEDIUM NOT PRESENT\n");
  916 #endif
  917 
  918                 c->sense[0] = 0x70; /*Fixed format sense data*/
  919                 c->sense[2] = 0x02;
  920                 c->sense[12] = 0x3A;
  921                 c->sense[13] = 0x00;
  922                 sense_len = 14;
  923                 ignore_error = 1;
  924             } else if (c->opcode[0] == 0 && 
  925                     (errno == EBUSY || errno == ENXIO)) {
  926                 /* Timeout of TEST UNIT READY loop */
  927                 /* Inquiries while tray is being loaded */
  928                 /*LOGICAL UNIT NOT READY,CAUSE NOT REPORTABLE*/
  929 
  930 #ifdef Libburn_ahci_verbouS
  931                 fprintf(stderr, "libburn_EXPERIMENTAL: Emulating [2,04,00] LOGICAL UNIT NOT READY,CAUSE NOT REPORTABLE\n");
  932 #endif
  933 
  934                 c->sense[0] = 0x70; /*Fixed format sense data*/
  935                 c->sense[2] = 0x02;
  936                 c->sense[12] = 0x04;
  937                 c->sense[13] = 0x00;
  938                 sense_len = 14;
  939                 ignore_error = 1;
  940             } else if (errno == EINVAL) {
  941                 /* Inappropriate MODE SENSE */
  942                 /* INVALID FIELD IN CDB */
  943 
  944 #ifdef Libburn_ahci_verbouS
  945                 fprintf(stderr, "libburn_EXPERIMENTAL: Emulating [5,24,00] INVALID FIELD IN CDB\n");
  946 #endif
  947 
  948                 c->sense[0] = 0x70; /*Fixed format sense data*/
  949                 c->sense[2] = 0x05;
  950                 c->sense[12] = 0x24;
  951                 c->sense[13] = 0x00;
  952                 sense_len = 14;
  953                 ignore_error = 1;
  954             }
  955         }
  956 
  957         if (err == -1 && !ignore_error) {
  958             libdax_msgs_submit(libdax_messenger,
  959                 d->global_index, 0x0002010c,
  960                 LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
  961                 "Failed to transfer command to drive",
  962                 errno, 0);
  963             sg_close_drive(d);
  964             d->released = 1;
  965             d->busy = BURN_DRIVE_IDLE;
  966             c->error = 1;
  967             {ret = -1; goto ex;}
  968         }
  969         /* XXX */
  970 
  971         if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
  972             if (sense_len < 14) {
  973                 /*LOGICAL UNIT NOT READY,CAUSE NOT REPORTABLE*/
  974 
  975 #ifdef Libburn_ahci_verbouS
  976                 fprintf(stderr, "libburn_EXPERIMENTAL: CAM_STATUS= %d .Emulating [2,04,00] LOGICAL UNIT NOT READY,CAUSE NOT REPORTABLE\n", (ccb->ccb_h.status & CAM_STATUS_MASK));
  977 #endif
  978 
  979                 c->sense[0] = 0x70; /*Fixed format sense data*/
  980                 c->sense[2] = 0x02;
  981                 c->sense[12] = 0x04;
  982                 c->sense[13] = 0x00;
  983                 done = 1;
  984             }
  985         }
  986         done = scsi_eval_cmd_outcome(d, c, fp, c->sense,
  987                         sense_len, start_time,
  988                         timeout_ms, i, !!ignore_error);
  989         if (d->cancel)
  990             done = 1;
  991         if (!done)
  992             spc_register_retry(c);
  993     } while (!done);
  994     ret = 1;
  995 ex:;
  996     cam_freeccb(ccb);
  997     return ret;
  998 }
  999 
 1000 
 1001 /* ts B00115 */
 1002 /* Return 1 if the given path leads to a regular file or a device that can be
 1003    fseeked, read and eventually written with 2 kB granularity.
 1004 */
 1005 int burn_os_is_2k_seekrw(char *path, int flag)
 1006 {
 1007         struct stat stbuf;
 1008 #ifdef Libburn_DIOCGMEDIASIZE_ISBLK
 1009     int fd, ret;
 1010     off_t add_size;
 1011 #else
 1012     char *spt;
 1013     int i, e;
 1014 #endif /* ! Libburn_DIOCGMEDIASIZE_ISBLK */
 1015 
 1016         if (stat(path, &stbuf) == -1)
 1017                 return 0;
 1018         if (S_ISREG(stbuf.st_mode))
 1019                 return 1;
 1020     if (!S_ISCHR(stbuf.st_mode))
 1021         return 0;
 1022 
 1023 #ifdef Libburn_DIOCGMEDIASIZE_ISBLK
 1024 
 1025     /* If it throws no error with DIOCGMEDIASIZE then it is a
 1026        'block device'
 1027     */
 1028     fd = open(path, O_RDONLY);
 1029     if (fd == -1)
 1030         return 0;
 1031     ret = ioctl(fd, DIOCGMEDIASIZE, &add_size);
 1032     close(fd);
 1033 
 1034     return (ret != -1);
 1035 
 1036 #else /* Libburn_DIOCGMEDIASIZE_ISBLK */
 1037 
 1038     spt = strrchr(path, '/');
 1039     if (spt == NULL)
 1040             spt = path;
 1041     else
 1042             spt++;
 1043     e = strlen(spt);
 1044     for (i = strlen(spt) - 1; i > 0; i--)
 1045         if (spt[i] >= '0' && spt[i] <= '9')
 1046             e = i;
 1047     if (strncmp(spt, "da", e) == 0) /* SCSI disk. E.g. USB stick. */
 1048         return 1;
 1049     if (strncmp(spt, "cd", e) == 0) /* SCSI CD drive might be writeable. */
 1050         return 1;
 1051     if (strncmp(spt, "ad", e) == 0) /* IDE hard drive */
 1052         return 1;
 1053     if (strncmp(spt, "acd", e) == 0) /* IDE CD drive might be writeable */
 1054         return 1;
 1055     if (strncmp(spt, "fd", e) == 0) /* Floppy disk */
 1056         return 1;
 1057     if (strncmp(spt, "fla", e) == 0) /* Flash drive */
 1058         return 1;
 1059     return 0;
 1060 
 1061 #endif /* ! Libburn_DIOCGMEDIASIZE_ISBLK */
 1062 
 1063 }
 1064 
 1065 
 1066 /* ts A70909 */
 1067 /** Estimate the potential payload capacity of a file address.
 1068     @param path  The address of the file to be examined. If it does not
 1069                  exist yet, then the directory will be inquired.
 1070     @param bytes This value gets modified if an estimation is possible
 1071     @return      -2 = cannot perform necessary operations on file object
 1072                  -1 = neither path nor dirname of path exist
 1073                   0 = could not estimate size capacity of file object
 1074                   1 = estimation has been made, bytes was set
 1075 */
 1076 int burn_os_stdio_capacity(char *path, off_t write_start, off_t *bytes)
 1077 {
 1078     struct stat stbuf;
 1079     struct statvfs vfsbuf;
 1080     char *testpath = NULL, *cpt;
 1081     off_t add_size = 0;
 1082     int fd, ret;
 1083 
 1084     BURN_ALLOC_MEM(testpath, char, 4096);
 1085     testpath[0] = 0;
 1086     if (stat(path, &stbuf) == -1) {
 1087         strcpy(testpath, path);
 1088         cpt = strrchr(testpath, '/');
 1089         if(cpt == NULL)
 1090             strcpy(testpath, ".");
 1091         else if(cpt == testpath)
 1092             testpath[1] = 0;
 1093         else
 1094             *cpt = 0;
 1095         if (stat(testpath, &stbuf) == -1)
 1096             {ret = -1; goto ex;}
 1097 
 1098 #ifdef Libburn_if_this_was_linuX
 1099 
 1100     } else if(S_ISBLK(stbuf.st_mode)) {
 1101         int open_mode = O_RDWR, fd, ret;
 1102         long blocks;
 1103 
 1104         blocks = *bytes / 512;
 1105         if(burn_sg_open_o_excl)
 1106             open_mode |= O_EXCL;
 1107         fd = open(path, open_mode);
 1108         if (fd == -1)
 1109             {ret = -2; goto ex;}
 1110         ret = ioctl(fd, BLKGETSIZE, &blocks);
 1111         close(fd);
 1112         if (ret == -1)
 1113             {ret = -2; goto ex;}
 1114         *bytes = ((off_t) blocks) * (off_t) 512;
 1115 
 1116 #endif /* Libburn_if_this_was_linuX */
 1117 
 1118 
 1119     } else if(S_ISCHR(stbuf.st_mode)) {
 1120         fd = open(path, O_RDONLY);
 1121         if (fd == -1)
 1122             {ret = -2; goto ex;}
 1123         ret = ioctl(fd, DIOCGMEDIASIZE, &add_size);
 1124         close(fd);
 1125         if (ret == -1)
 1126             {ret = -2; goto ex;}
 1127         *bytes = add_size;
 1128     } else if(S_ISREG(stbuf.st_mode)) {
 1129         add_size = burn_sparse_file_addsize(write_start, &stbuf);
 1130         strcpy(testpath, path);
 1131     } else
 1132         {ret = 0; goto ex;}
 1133 
 1134     if (testpath[0]) {  
 1135         if (statvfs(testpath, &vfsbuf) == -1)
 1136             {ret = -2; goto ex;}
 1137         *bytes = add_size + ((off_t) vfsbuf.f_frsize) *
 1138                         (off_t) vfsbuf.f_bavail;
 1139     }
 1140     ret = 1;
 1141 ex:
 1142     BURN_FREE_MEM(testpath);
 1143     return ret;
 1144 }
 1145 
 1146 
 1147 /* ts A91122 : an interface to open(O_DIRECT) or similar OS tricks. */
 1148 
 1149 #ifdef Libburn_read_o_direcT
 1150 
 1151     /* No special O_DIRECT-like precautions are implemented here */
 1152 
 1153 #endif /* Libburn_read_o_direcT */
 1154 
 1155 
 1156 int burn_os_open_track_src(char *path, int open_flags, int flag)
 1157 {
 1158     int fd;
 1159 
 1160     fd = open(path, open_flags);
 1161     return fd;
 1162 }
 1163 
 1164 
 1165 void *burn_os_alloc_buffer(size_t amount, int flag)
 1166 {
 1167     void *buf = NULL;
 1168 
 1169     buf = calloc(1, amount);
 1170     return buf;
 1171 }
 1172 
 1173 
 1174 int burn_os_free_buffer(void *buffer, size_t amount, int flag)
 1175 {
 1176     if (buffer == NULL)
 1177         return 0;
 1178     free(buffer);
 1179     return 1;
 1180 }
 1181