Example #1
0
int
main(int argc, char * argv[])
{
    bool got_stdin = false;
    bool if_given = false;
    bool lba_given = false;
    bool num_given = false;
    bool prot_en;
    int res, c, infd, act_cdb_len, vb, err;
    int sg_fd = -1;
    int ret = -1;
    uint32_t block_size;
    int64_t ll;
    const char * device_name = NULL;
    struct opts_t * op;
    uint8_t * wBuff = NULL;
    uint8_t * free_wBuff = NULL;
    char ebuff[EBUFF_SZ];
    char b[80];
    uint8_t resp_buff[RCAP16_RESP_LEN];
    struct opts_t opts;
    struct stat a_stat;

    op = &opts;
    memset(op, 0, sizeof(opts));
    op->numblocks = DEF_WS_NUMBLOCKS;
    op->pref_cdb_size = DEF_WS_CDB_SIZE;
    op->timeout = DEF_TIMEOUT_SECS;
    while (1) {
        int option_index = 0;

        c = getopt_long(argc, argv, "ag:hi:l:Ln:NPRSt:TUvVw:x:",
                        long_options, &option_index);
        if (c == -1)
            break;

        switch (c) {
        case 'a':
            op->anchor = true;
            break;
        case 'g':
            op->grpnum = sg_get_num(optarg);
            if ((op->grpnum < 0) || (op->grpnum > 63))  {
                pr2serr("bad argument to '--grpnum'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'h':
        case '?':
            usage();
            return 0;
        case 'i':
            strncpy(op->ifilename, optarg, sizeof(op->ifilename) - 1);
            op->ifilename[sizeof(op->ifilename) - 1] = '\0';
            if_given = true;
            break;
        case 'l':
            ll = sg_get_llnum(optarg);
            if (-1 == ll) {
                pr2serr("bad argument to '--lba'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            op->lba = (uint64_t)ll;
            lba_given = true;
            break;
        case 'L':
            op->lbdata = true;
            break;
        case 'n':
            op->numblocks = sg_get_num(optarg);
            if (op->numblocks < 0)  {
                pr2serr("bad argument to '--num'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            num_given = true;
            break;
        case 'N':
            op->ndob = true;
            break;
        case 'P':
            op->pbdata = true;
            break;
        case 'R':
            op->want_ws10 = true;
            break;
        case 'S':
            if (DEF_WS_CDB_SIZE != op->pref_cdb_size) {
                pr2serr("only one '--10', '--16' or '--32' please\n");
                return SG_LIB_CONTRADICT;
            }
            op->pref_cdb_size = 16;
            break;
        case 't':
            op->timeout = sg_get_num(optarg);
            if (op->timeout < 0)  {
                pr2serr("bad argument to '--timeout'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'T':
            if (DEF_WS_CDB_SIZE != op->pref_cdb_size) {
                pr2serr("only one '--10', '--16' or '--32' please\n");
                return SG_LIB_CONTRADICT;
            }
            op->pref_cdb_size = 32;
            break;
        case 'U':
            op->unmap = true;
            break;
        case 'v':
            op->verbose_given = true;
            ++op->verbose;
            break;
        case 'V':
            op->version_given = true;
            break;
        case 'w':
            op->wrprotect = sg_get_num(optarg);
            if ((op->wrprotect < 0) || (op->wrprotect > 7))  {
                pr2serr("bad argument to '--wrprotect'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'x':
            op->xfer_len = sg_get_num(optarg);
            if (op->xfer_len < 0) {
                pr2serr("bad argument to '--xferlen'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        default:
            pr2serr("unrecognised option code 0x%x ??\n", c);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }
    if (optind < argc) {
        if (NULL == device_name) {
            device_name = argv[optind];
            ++optind;
        }
        if (optind < argc) {
            for (; optind < argc; ++optind)
                pr2serr("Unexpected extra argument: %s\n", argv[optind]);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }
    if (op->want_ws10 && (DEF_WS_CDB_SIZE != op->pref_cdb_size)) {
        pr2serr("only one '--10', '--16' or '--32' please\n");
        return SG_LIB_CONTRADICT;
    }

#ifdef DEBUG
    pr2serr("In DEBUG mode, ");
    if (op->verbose_given && op->version_given) {
        pr2serr("but override: '-vV' given, zero verbose and continue\n");
        op->verbose_given = false;
        op->version_given = false;
        op->verbose = 0;
    } else if (! op->verbose_given) {
        pr2serr("set '-vv'\n");
        op->verbose = 2;
    } else
        pr2serr("keep verbose=%d\n", op->verbose);
#else
    if (op->verbose_given && op->version_given)
        pr2serr("Not in DEBUG mode, so '-vV' has no special action\n");
#endif
    if (op->version_given) {
        pr2serr(ME "version: %s\n", version_str);
        return 0;
    }

    if (NULL == device_name) {
        pr2serr("Missing device name!\n\n");
        usage();
        return SG_LIB_SYNTAX_ERROR;
    }
    vb = op->verbose;

    if ((! if_given) && (! lba_given) && (! num_given)) {
        pr2serr("As a precaution, one of '--in=', '--lba=' or '--num=' is "
                "required\n");
        return SG_LIB_CONTRADICT;
    }

    if (op->ndob) {
        if (if_given) {
            pr2serr("Can't have both --ndob and '--in='\n");
            return SG_LIB_CONTRADICT;
        }
        if (0 != op->xfer_len) {
            pr2serr("With --ndob only '--xferlen=0' (or not given) is "
                    "acceptable\n");
            return SG_LIB_CONTRADICT;
        }
    } else if (op->ifilename[0]) {
        got_stdin = (0 == strcmp(op->ifilename, "-"));
        if (! got_stdin) {
            memset(&a_stat, 0, sizeof(a_stat));
            if (stat(op->ifilename, &a_stat) < 0) {
                err = errno;
                if (vb)
                    pr2serr("unable to stat(%s): %s\n", op->ifilename,
                            safe_strerror(err));
                return sg_convert_errno(err);
            }
            if (op->xfer_len <= 0)
                op->xfer_len = (int)a_stat.st_size;
        }
    }

    sg_fd = sg_cmds_open_device(device_name, false /* rw */, vb);
    if (sg_fd < 0) {
        if (op->verbose)
            pr2serr(ME "open error: %s: %s\n", device_name,
                    safe_strerror(-sg_fd));
        ret = sg_convert_errno(-sg_fd);
        goto err_out;
    }

    if (! op->ndob) {
        prot_en = false;
        if (0 == op->xfer_len) {
            res = sg_ll_readcap_16(sg_fd, false /* pmi */, 0 /* llba */,
                                   resp_buff, RCAP16_RESP_LEN, true,
                                   (vb ? (vb - 1): 0));
            if (SG_LIB_CAT_UNIT_ATTENTION == res) {
                pr2serr("Read capacity(16) unit attention, try again\n");
                res = sg_ll_readcap_16(sg_fd, false, 0, resp_buff,
                                       RCAP16_RESP_LEN, true,
                                       (vb ? (vb - 1): 0));
            }
            if (0 == res) {
                if (vb > 3)
                    hex2stderr(resp_buff, RCAP16_RESP_LEN, 1);
                block_size = sg_get_unaligned_be32(resp_buff + 8);
                prot_en = !!(resp_buff[12] & 0x1);
                op->xfer_len = block_size;
                if (prot_en && (op->wrprotect > 0))
                    op->xfer_len += 8;
            } else if ((SG_LIB_CAT_INVALID_OP == res) ||
                       (SG_LIB_CAT_ILLEGAL_REQ == res)) {
                if (vb)
                    pr2serr("Read capacity(16) not supported, try Read "
                            "capacity(10)\n");
                res = sg_ll_readcap_10(sg_fd, false /* pmi */, 0 /* lba */,
                                       resp_buff, RCAP10_RESP_LEN, true,
                                       (vb ? (vb - 1): 0));
                if (0 == res) {
                    if (vb > 3)
                        hex2stderr(resp_buff, RCAP10_RESP_LEN, 1);
                    block_size = sg_get_unaligned_be32(resp_buff + 4);
                    op->xfer_len = block_size;
                } else {
                    sg_get_category_sense_str(res, sizeof(b), b, vb);
                    pr2serr("Read capacity(10): %s\n", b);
                    pr2serr("Unable to calculate block size\n");
                }
            } else if (vb) {
                sg_get_category_sense_str(res, sizeof(b), b, vb);
                pr2serr("Read capacity(16): %s\n", b);
                pr2serr("Unable to calculate block size\n");
            }
        }
        if (op->xfer_len < 1) {
            pr2serr("unable to deduce block size, please give '--xferlen=' "
                    "argument\n");
            ret = SG_LIB_SYNTAX_ERROR;
            goto err_out;
        }
        if (op->xfer_len > MAX_XFER_LEN) {
            pr2serr("'--xferlen=%d is out of range ( want <= %d)\n",
                    op->xfer_len, MAX_XFER_LEN);
            ret = SG_LIB_SYNTAX_ERROR;
            goto err_out;
        }
        wBuff = (uint8_t *)sg_memalign(op->xfer_len, 0, &free_wBuff, vb > 3);
        if (NULL == wBuff) {
            pr2serr("unable to allocate %d bytes of memory with "
                    "sg_memalign()\n", op->xfer_len);
            ret = sg_convert_errno(ENOMEM);
            goto err_out;
        }
        if (op->ifilename[0]) {
            if (got_stdin) {
                infd = STDIN_FILENO;
                if (sg_set_binary_mode(STDIN_FILENO) < 0)
                    perror("sg_set_binary_mode");
            } else {
                if ((infd = open(op->ifilename, O_RDONLY)) < 0) {
                    ret = sg_convert_errno(errno);
                    snprintf(ebuff, EBUFF_SZ, ME "could not open %.400s for "
                             "reading", op->ifilename);
                    perror(ebuff);
                    goto err_out;
                } else if (sg_set_binary_mode(infd) < 0)
                    perror("sg_set_binary_mode");
            }
            res = read(infd, wBuff, op->xfer_len);
            if (res < 0) {
                ret = sg_convert_errno(errno);
                snprintf(ebuff, EBUFF_SZ, ME "couldn't read from %.400s",
                         op->ifilename);
                perror(ebuff);
                if (! got_stdin)
                    close(infd);
                goto err_out;
            }
            if (res < op->xfer_len) {
                pr2serr("tried to read %d bytes from %s, got %d bytes\n",
                        op->xfer_len, op->ifilename, res);
                pr2serr("  so pad with 0x0 bytes and continue\n");
            }
            if (! got_stdin)
                close(infd);
        } else {
            if (vb)
                pr2serr("Default data-out buffer set to %d zeros\n",
                        op->xfer_len);
            if (prot_en && (op->wrprotect > 0)) {
               /* default for protection is 0xff, rest get 0x0 */
                memset(wBuff + op->xfer_len - 8, 0xff, 8);
                if (vb)
                    pr2serr(" ... apart from last 8 bytes which are set to "
                            "0xff\n");
            }
        }
    }

    ret = do_write_same(sg_fd, op, wBuff, &act_cdb_len);
    if (ret) {
        sg_get_category_sense_str(ret, sizeof(b), b, vb);
        pr2serr("Write same(%d): %s\n", act_cdb_len, b);
    }

err_out:
    if (free_wBuff)
        free(free_wBuff);
    if (sg_fd >= 0) {
        res = sg_cmds_close_device(sg_fd);
        if (res < 0) {
            pr2serr("close error: %s\n", safe_strerror(-res));
            if (0 == ret)
                ret = sg_convert_errno(-res);
        }
    }
    if (0 == op->verbose) {
        if (! sg_if_can2stderr("sg_write_same failed: ", ret))
            pr2serr("Some error occurred, try again with '-v' "
                    "or '-vv' for more information\n");
    }
    return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
}
int
main(int argc, char * argv[])
{
    bool bpw_then_activate = false;
    bool dry_run = false;
    bool got_stdin = false;
    bool wb_len_given = false;
    int sg_fd, infd, res, c, len, k, n;
    int bpw = 0;
    int do_help = 0;
    int ret = 0;
    int verbose = 0;
    int wb_id = 0;
    int wb_len = 0;
    int wb_mode = 0;
    int wb_offset = 0;
    int wb_skip = 0;
    int wb_timeout = DEF_PT_TIMEOUT;
    int wb_mspec = 0;
    const char * device_name = NULL;
    const char * file_name = NULL;
    unsigned char * dop = NULL;
    char * cp;
    const struct mode_s * mp;
    char ebuff[EBUFF_SZ];

    while (1) {
        int option_index = 0;

        c = getopt_long(argc, argv, "b:dhi:I:l:m:o:rs:S:t:vV", long_options,
                        &option_index);
        if (c == -1)
            break;

        switch (c) {
        case 'b':
            bpw = sg_get_num(optarg);
            if (bpw < 0) {
                pr2serr("argument to '--bpw' should be in a positive "
                        "number\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            if ((cp = strchr(optarg, ','))) {
                if (0 == strncmp("act", cp + 1, 3))
                    bpw_then_activate = true;
            }
            break;
        case 'd':
            dry_run = true;
            break;
        case 'h':
        case '?':
            ++do_help;
            break;
        case 'i':
            wb_id = sg_get_num(optarg);
            if ((wb_id < 0) || (wb_id > 255)) {
                pr2serr("argument to '--id' should be in the range 0 to "
                        "255\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'I':
            file_name = optarg;
            break;
        case 'l':
            wb_len = sg_get_num(optarg);
            if (wb_len < 0) {
                pr2serr("bad argument to '--length'\n");
                return SG_LIB_SYNTAX_ERROR;
             }
             wb_len_given = true;
             break;
        case 'm':
            if (isdigit(*optarg)) {
                wb_mode = sg_get_num(optarg);
                if ((wb_mode < 0) || (wb_mode > 31)) {
                    pr2serr("argument to '--mode' should be in the range 0 "
                            "to 31\n");
                    return SG_LIB_SYNTAX_ERROR;
                }
            } else {
                len = strlen(optarg);
                for (mp = mode_arr; mp->mode_string; ++mp) {
                    if (0 == strncmp(mp->mode_string, optarg, len)) {
                        wb_mode = mp->mode;
                        break;
                    }
                }
                if (! mp->mode_string) {
                    print_modes();
                    return SG_LIB_SYNTAX_ERROR;
                }
            }
            break;
        case 'o':
           wb_offset = sg_get_num(optarg);
           if (wb_offset < 0) {
                pr2serr("bad argument to '--offset'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'r':       /* --read-stdin and --raw (previous name) */
            file_name = "-";
            break;
        case 's':
           wb_skip = sg_get_num(optarg);
           if (wb_skip < 0) {
                pr2serr("bad argument to '--skip'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'S':
            wb_mspec = sg_get_num(optarg);
            if ((wb_mspec < 0) || (wb_mspec > 7)) {
                pr2serr("expected argument to '--specific' to be 0 to 7\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 't':
            wb_timeout = sg_get_num(optarg);
            if (wb_timeout < 0) {
                pr2serr("Invalid argument to '--timeout'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'v':
            ++verbose;
            break;
        case 'V':
            pr2serr(ME "version: %s\n", version_str);
            return 0;
        default:
            pr2serr("unrecognised option code 0x%x ??\n", c);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }
    if (do_help) {
        if (do_help > 1) {
            usage();
            pr2serr("\n");
            print_modes();
        } else
            usage();
        return 0;
    }
    if (optind < argc) {
        if (NULL == device_name) {
            device_name = argv[optind];
            ++optind;
        }
        if (optind < argc) {
            for (; optind < argc; ++optind)
                pr2serr("Unexpected extra argument: %s\n", argv[optind]);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }

    if (NULL == device_name) {
        pr2serr("missing device name!\n");
        usage();
        return SG_LIB_SYNTAX_ERROR;
    }

    if ((wb_len > 0) && (bpw > wb_len)) {
        pr2serr("trim chunk size (CS) to be the same as LEN\n");
        bpw = wb_len;
    }

#ifdef SG_LIB_WIN32
#ifdef SG_LIB_WIN32_DIRECT
    if (verbose > 4)
        pr2serr("Initial win32 SPT interface state: %s\n",
                scsi_pt_win32_spt_state() ? "direct" : "indirect");
    scsi_pt_win32_direct(SG_LIB_WIN32_DIRECT /* SPT pt interface */);
#endif
#endif

    sg_fd = sg_cmds_open_device(device_name, false /* rw */, verbose);
    if (sg_fd < 0) {
        pr2serr(ME "open error: %s: %s\n", device_name,
                safe_strerror(-sg_fd));
        return SG_LIB_FILE_ERROR;
    }
    if (file_name || (wb_len > 0)) {
        if (0 == wb_len)
            wb_len = DEF_XFER_LEN;
        if (NULL == (dop = (unsigned char *)malloc(wb_len))) {
            pr2serr(ME "out of memory\n");
            ret = SG_LIB_SYNTAX_ERROR;
            goto err_out;
        }
        memset(dop, 0xff, wb_len);
        if (file_name) {
            got_stdin = (0 == strcmp(file_name, "-"));
            if (got_stdin) {
                if (wb_skip > 0) {
                    pr2serr("Can't skip on stdin\n");
                    ret = SG_LIB_FILE_ERROR;
                    goto err_out;
                }
                infd = STDIN_FILENO;
            } else {
                if ((infd = open(file_name, O_RDONLY)) < 0) {
                    snprintf(ebuff, EBUFF_SZ,
                             ME "could not open %s for reading", file_name);
                    perror(ebuff);
                    ret = SG_LIB_FILE_ERROR;
                    goto err_out;
                } else if (sg_set_binary_mode(infd) < 0)
                    perror("sg_set_binary_mode");
                if (wb_skip > 0) {
                    if (lseek(infd, wb_skip, SEEK_SET) < 0) {
                        snprintf(ebuff,  EBUFF_SZ, ME "couldn't skip to "
                                 "required position on %s", file_name);
                        perror(ebuff);
                        close(infd);
                        ret = SG_LIB_FILE_ERROR;
                        goto err_out;
                    }
                }
            }
            res = read(infd, dop, wb_len);
            if (res < 0) {
                snprintf(ebuff, EBUFF_SZ, ME "couldn't read from %s",
                         file_name);
                perror(ebuff);
                if (! got_stdin)
                    close(infd);
                ret = SG_LIB_FILE_ERROR;
                goto err_out;
            }
            if (res < wb_len) {
                if (wb_len_given) {
                    pr2serr("tried to read %d bytes from %s, got %d bytes\n",
                            wb_len, file_name, res);
                    pr2serr("pad with 0xff bytes and continue\n");
                } else {
                    if (verbose) {
                        pr2serr("tried to read %d bytes from %s, got %d "
                                "bytes\n", wb_len, file_name, res);
                        pr2serr("will write %d bytes", res);
                        if ((bpw > 0) && (bpw < wb_len))
                            pr2serr(", %d bytes per WRITE BUFFER command\n",
                                    bpw);
                        else
                            pr2serr("\n");
                    }
                    wb_len = res;
                }
            }
            if (! got_stdin)
                close(infd);
        }
    }

    res = 0;
    if (bpw > 0) {
        for (k = 0; k < wb_len; k += n) {
            n = wb_len - k;
            if (n > bpw)
                n = bpw;
            if (verbose)
                pr2serr("sending write buffer, mode=0x%x, mspec=%d, id=%d, "
                        " offset=%d, len=%d\n", wb_mode, wb_mspec, wb_id,
                        wb_offset + k, n);
            if (dry_run) {
                if (verbose)
                    pr2serr("skipping WRITE BUFFER command due to "
                            "--dry-run\n");
                res = 0;
            } else
                res = sg_ll_write_buffer_v2(sg_fd, wb_mode, wb_mspec, wb_id,
                                            wb_offset + k, dop + k, n,
                                            wb_timeout, true, verbose);
            if (res)
                break;
        }
        if (bpw_then_activate) {
            if (verbose)
                pr2serr("sending Activate deferred microcode [0xf]\n");
            if (dry_run) {
                if (verbose)
                    pr2serr("skipping WRITE BUFFER(ACTIVATE) command due to "
                            "--dry-run\n");
                res = 0;
            } else
                res = sg_ll_write_buffer_v2(sg_fd, MODE_ACTIVATE_MC,
                                            0 /* buffer_id */,
                                            0 /* buffer_offset */, 0,
                                            NULL, 0, wb_timeout, true,
                                            verbose);
        }
    } else {
        if (verbose)
            pr2serr("sending single write buffer, mode=0x%x, mpsec=%d, "
                    "id=%d, offset=%d, len=%d\n", wb_mode, wb_mspec, wb_id,
                    wb_offset, wb_len);
        if (dry_run) {
            if (verbose)
                pr2serr("skipping WRITE BUFFER(all in one) command due to "
                        "--dry-run\n");
            res = 0;
        } else
            res = sg_ll_write_buffer_v2(sg_fd, wb_mode, wb_mspec, wb_id,
                                        wb_offset, dop, wb_len, wb_timeout,
                                        true, verbose);
    }
    if (0 != res) {
        char b[80];

        ret = res;
        sg_get_category_sense_str(res, sizeof(b), b, verbose);
        pr2serr("Write buffer failed: %s\n", b);
    }

err_out:
    if (dop)
        free(dop);
    res = sg_cmds_close_device(sg_fd);
    if (res < 0) {
        pr2serr("close error: %s\n", safe_strerror(-res));
        if (0 == ret)
            return SG_LIB_FILE_ERROR;
    }
    return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
}
Example #3
0
int
main(int argc, char * argv[])
{
    bool do_long = false;
    bool o_readonly = false;
    bool do_raw = false;
    bool verbose_given = false;
    bool version_given = false;
    int res, c, len, k;
    int sg_fd = -1;
    int do_help = 0;
    int do_hex = 0;
    int rb_id = 0;
    int rb_len = 4;
    int rb_mode = 0;
    int rb_mode_sp = 0;
    int resid = 0;
    int verbose = 0;
    int ret = 0;
    int64_t ll;
    uint64_t rb_offset = 0;
    const char * device_name = NULL;
    uint8_t * resp;
    const struct mode_s * mp;

    while (1) {
        int option_index = 0;

        c = getopt_long(argc, argv, "hHi:l:Lm:o:rRS:vV", long_options,
                        &option_index);
        if (c == -1)
            break;

        switch (c) {
        case 'h':
        case '?':
            ++do_help;
            break;
        case 'H':
            ++do_hex;
            break;
        case 'i':
            rb_id = sg_get_num(optarg);
            if ((rb_id < 0) || (rb_id > 255)) {
                pr2serr("argument to '--id' should be in the range 0 to "
                        "255\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'l':
            rb_len = sg_get_num(optarg);
            if (rb_len < 0) {
                pr2serr("bad argument to '--length'\n");
                return SG_LIB_SYNTAX_ERROR;
             }
             if (rb_len > 0xffffff) {
                pr2serr("argument to '--length' must be <= 0xffffff\n");
                return SG_LIB_SYNTAX_ERROR;
             }
             break;
        case 'L':
            do_long = true;
            break;
        case 'm':
            if (isdigit(*optarg)) {
                rb_mode = sg_get_num(optarg);
                if ((rb_mode < 0) || (rb_mode > 31)) {
                    pr2serr("argument to '--mode' should be in the range 0 "
                            "to 31\n");
                    return SG_LIB_SYNTAX_ERROR;
                }
            } else {
                len = strlen(optarg);
                for (mp = modes; mp->mode_string; ++mp) {
                    if (0 == strncmp(mp->mode_string, optarg, len)) {
                        rb_mode = mp->mode;
                        break;
                    }
                }
                if (NULL == mp->mode_string) {
                    print_modes();
                    return SG_LIB_SYNTAX_ERROR;
                }
            }
            break;
        case 'o':
           ll = sg_get_llnum(optarg);
           if (ll < 0) {
                pr2serr("bad argument to '--offset'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            rb_offset = ll;
            break;
        case 'r':
            do_raw = true;
            break;
        case 'R':
            o_readonly = true;
            break;
        case 'S':
           rb_mode_sp = sg_get_num(optarg);
           if ((rb_mode_sp < 0) || (rb_mode_sp > 7)) {
                pr2serr("expected argument to '--specific' to be 0 to 7\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'v':
            verbose_given = true;
            ++verbose;
            break;
        case 'V':
            version_given = true;
            break;
        default:
            pr2serr("unrecognised option code 0x%x ??\n", c);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }
    if (do_help) {
        if (do_help > 1) {
            usage();
            pr2serr("\n");
            print_modes();
        } else
            usage();
        return 0;
    }
    if (optind < argc) {
        if (NULL == device_name) {
            device_name = argv[optind];
            ++optind;
        }
        if (optind < argc) {
            for (; optind < argc; ++optind)
                pr2serr("Unexpected extra argument: %s\n", argv[optind]);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }

#ifdef DEBUG
    pr2serr("In DEBUG mode, ");
    if (verbose_given && version_given) {
        pr2serr("but override: '-vV' given, zero verbose and continue\n");
        verbose_given = false;
        version_given = false;
        verbose = 0;
    } else if (! verbose_given) {
        pr2serr("set '-vv'\n");
        verbose = 2;
    } else
        pr2serr("keep verbose=%d\n", verbose);
#else
    if (verbose_given && version_given)
        pr2serr("Not in DEBUG mode, so '-vV' has no special action\n");
#endif
    if (version_given) {
        pr2serr("version: %s\n", version_str);
        return 0;
    }

    if (NULL == device_name) {
        pr2serr("Missing device name!\n\n");
        usage();
        return SG_LIB_SYNTAX_ERROR;
    }

    len = rb_len ? rb_len : 8;
    resp = (uint8_t *)malloc(len);
    if (NULL == resp) {
        pr2serr("unable to allocate %d bytes on the heap\n", len);
        return SG_LIB_CAT_OTHER;
    }
    memset(resp, 0, len);

    if (do_raw) {
        if (sg_set_binary_mode(STDOUT_FILENO) < 0) {
            perror("sg_set_binary_mode");
            ret = SG_LIB_FILE_ERROR;
            goto fini;
        }
    }

#ifdef SG_LIB_WIN32
#ifdef SG_LIB_WIN32_DIRECT
    if (verbose > 4)
        pr2serr("Initial win32 SPT interface state: %s\n",
                scsi_pt_win32_spt_state() ? "direct" : "indirect");
    scsi_pt_win32_direct(SG_LIB_WIN32_DIRECT /* SPT pt interface */);
#endif
#endif

    sg_fd = sg_cmds_open_device(device_name, o_readonly, verbose);
    if (sg_fd < 0) {
        if (verbose)
            pr2serr("open error: %s: %s\n", device_name,
                    safe_strerror(-sg_fd));
        ret = sg_convert_errno(-sg_fd);
        goto fini;
    }

    if (do_long)
        res = sg_ll_read_buffer_16(sg_fd, rb_mode, rb_mode_sp, rb_id,
                                   rb_offset, resp, rb_len, &resid, true,
                                   verbose);
    else if (rb_offset > 0xffffff) {
        pr2serr("--offset value is too large for READ BUFFER(10), try "
                "--16\n");
        ret = SG_LIB_SYNTAX_ERROR;
        goto fini;
    } else
        res = sg_ll_read_buffer_10(sg_fd, rb_mode, rb_mode_sp, rb_id,
                                   (uint32_t)rb_offset, resp, rb_len, &resid,
                                   true, verbose);
    if (0 != res) {
        char b[80];

        ret = res;
        if (res > 0) {
            sg_get_category_sense_str(res, sizeof(b), b, verbose);
            pr2serr("Read buffer(%d) failed: %s\n", (do_long ? 16 : 10), b);
        }
        goto fini;
    }
    if (resid > 0)
        rb_len -= resid;        /* got back less than requested */
    if (rb_len > 0) {
        if (do_raw)
            dStrRaw(resp, rb_len);
        else if (do_hex || (rb_len < 4))
            hex2stdout((const uint8_t *)resp, rb_len, ((do_hex > 1) ? 0 : 1));
        else {
            switch (rb_mode) {
            case MODE_DESCRIPTOR:
                k = sg_get_unaligned_be24(resp + 1);
                printf("OFFSET BOUNDARY: %d, Buffer offset alignment: "
                       "%d-byte\n", resp[0], (1 << resp[0]));
                printf("BUFFER CAPACITY: %d (0x%x)\n", k, k);
                break;
            case MODE_ECHO_BDESC:
                k = sg_get_unaligned_be16(resp + 2) & 0x1fff;
                printf("EBOS:%d\n", resp[0] & 1 ? 1 : 0);
                printf("Echo buffer capacity: %d (0x%x)\n", k, k);
                break;
            default:
                hex2stdout((const uint8_t *)resp, rb_len,
                           (verbose > 1 ? 0 : 1));
                break;
            }
        }
    }

fini:
    if (resp)
        free(resp);
    if (sg_fd >= 0) {
        res = sg_cmds_close_device(sg_fd);
        if (res < 0) {
            pr2serr("close error: %s\n", safe_strerror(-res));
            if (0 == ret)
                ret = sg_convert_errno(-res);
        }
    }
    if (0 == verbose) {
        if (! sg_if_can2stderr("sg_read_buffer failed: ", ret))
            pr2serr("Some error occurred, try again with '-v' "
                    "or '-vv' for more information\n");
    }
    return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
}
Example #4
0
/* Processes command line options according to new option format. Returns
 * 0 is ok, else SG_LIB_SYNTAX_ERROR is returned. */
static int
process_cl_new(struct opts_t * optsp, int argc, char * argv[])
{
    int c, n, nn;
    char * cp;

    while (1) {
        int option_index = 0;

        c = getopt_long(argc, argv, "6aAc:dDefhHlLm:NOp:rRsvV", long_options,
                        &option_index);
        if (c == -1)
            break;

        switch (c) {
        case '6':
            ++optsp->do_six;
            break;
        case 'a':
            ++optsp->do_all;
            break;
        case 'A':
            optsp->do_all += 2;
            break;
        case 'c':
            n = sg_get_num(optarg);
            if ((n < 0) || (n > 3)) {
                fprintf(stderr, "bad argument to '--control='\n");
                usage();
                return SG_LIB_SYNTAX_ERROR;
            }
            optsp->page_control = n;
            break;
        case 'd':
            ++optsp->do_dbd;
            break;
        case 'D':
            ++optsp->do_dbout;
            break;
        case 'e':
            ++optsp->do_examine;
            break;
        case 'f':
            ++optsp->do_flexible;
            break;
        case 'h':
        case '?':
            ++optsp->do_help;
            break;
        case 'H':
            ++optsp->do_hex;
            break;
        case 'l':
            ++optsp->do_list;
            break;
        case 'L':
            ++optsp->do_llbaa;
            break;
        case 'm':
            n = sg_get_num(optarg);
            if ((n < 0) || (n > 65535)) {
                fprintf(stderr, "bad argument to '--maxlen='\n");
                usage();
                return SG_LIB_SYNTAX_ERROR;
            }
            optsp->maxlen = n;
            break;
        case 'N':
            break;      /* ignore */
        case 'O':
            optsp->opt_new = 0;
            return 0;
        case 'p':
            cp = strchr(optarg, ',');
            n = sg_get_num_nomult(optarg);
            if ((n < 0) || (n > 63)) {
                fprintf(stderr, "Bad argument to '--page='\n");
                usage();
                return SG_LIB_SYNTAX_ERROR;
            }
            if (cp) {
                nn = sg_get_num_nomult(cp + 1);
                if ((nn < 0) || (nn > 255)) {
                    fprintf(stderr, "Bad second value in argument to "
                            "'--page='\n");
                    usage();
                    return SG_LIB_SYNTAX_ERROR;
                }
                optsp->subpg_code = nn;
                optsp->subpg_code_set = 1;
            } else
                nn = 0;
            optsp->pg_code = n;
            break;
        case 'r':
            ++optsp->do_raw;
            break;
        case 'R':
            optsp->do_raw += 2;
            break;
        case 's':
            ++optsp->do_six;
            break;
        case 'v':
            ++optsp->do_verbose;
            break;
        case 'V':
            ++optsp->do_version;
            break;
        default:
            fprintf(stderr, "unrecognised option code %c [0x%x]\n", c, c);
            if (optsp->do_help)
                break;
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }
    if (optind < argc) {
        if (NULL == optsp->device_name) {
            optsp->device_name = argv[optind];
            ++optind;
        }
        if (optind < argc) {
            for (; optind < argc; ++optind)
                fprintf(stderr, "Unexpected extra argument: %s\n",
                        argv[optind]);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }
    return 0;
}
Example #5
0
int
main(int argc, char * argv[])
{
    bool do_16 = false;
    bool dpo = false;
    bool first_time;
    bool given_do_16 = false;
    bool has_filename = false;
    bool lba_given = false;
    bool repeat = false;
    bool verbose_given = false;
    bool version_given = false;
    int sg_fd, res, c, n;
    int bytchk = 0;
    int group = 0;
    int ilen = -1;
    int ifd = -1;
    int b_p_lb = 512;
    int ret = 1;
    int timeout = DEF_TIMEOUT_SECS;
    int tnum_lb_wr = 0;
    int verbose = 0;
    int wrprotect = 0;
    uint32_t num_lb = 1;
    uint32_t snum_lb = 1;
    uint64_t llba = 0;
    int64_t ll;
    uint8_t * wvb = NULL;
    uint8_t * wrkBuff = NULL;
    uint8_t * free_wrkBuff = NULL;
    const char * device_name = NULL;
    const char * ifnp;
    char cmd_name[32];

    ifnp = "";          /* keep MinGW quiet */
    while (1) {
        int option_index = 0;

        c = getopt_long(argc, argv, "b:dg:hi:I:l:n:RSt:w:vV", long_options,
                       &option_index);
        if (c == -1)
            break;

        switch (c) {
        case 'b':
            /* Only bytchk=0 and =1 are meaningful for this command in
             * sbc4r02 (not =2 nor =3) but that may change in the future. */
            bytchk = sg_get_num(optarg);
            if ((bytchk < 0) || (bytchk > 3))  {
                pr2serr("argument to '--bytchk' expected to be 0 to 3\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'd':
            dpo = true;
            break;
        case 'g':
            group = sg_get_num(optarg);
            if ((group < 0) || (group > 63))  {
                pr2serr("argument to '--group' expected to be 0 to 63\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'h':
        case '?':
            usage();
            return 0;
        case 'i':
            ifnp = optarg;
            has_filename = true;
            break;
        case 'I':
            ilen = sg_get_num(optarg);
            if (-1 == ilen) {
                pr2serr("bad argument to '--ilen'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'l':
            if (lba_given) {
                pr2serr("must have one and only one '--lba'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            ll = sg_get_llnum(optarg);
            if (ll < 0) {
                pr2serr("bad argument to '--lba'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            llba = (uint64_t)ll;
            lba_given = true;
            break;
        case 'n':
            n = sg_get_num(optarg);
            if (-1 == n) {
                pr2serr("bad argument to '--num'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            num_lb = (uint32_t)n;
            break;
        case 'R':
            repeat = true;
            break;
        case 'S':
            do_16 = true;
            given_do_16 = true;
            break;
        case 't':
            timeout = sg_get_num(optarg);
            if (timeout < 1) {
                pr2serr("bad argument to '--timeout'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'v':
            verbose_given = true;
            ++verbose;
            break;
        case 'V':
            version_given = true;
            break;
        case 'w':
            wrprotect = sg_get_num(optarg);
            if ((wrprotect < 0) || (wrprotect > 7))  {
                pr2serr("wrprotect (%d) is out of range ( < %d)\n", wrprotect,
                        7);
                return SG_LIB_SYNTAX_ERROR;
            }

            break;
        default:
            pr2serr("unrecognised option code 0x%x ??\n", c);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }
    if (optind < argc) {
        if (NULL == device_name) {
            device_name = argv[optind];
            ++optind;
        }
        if (optind < argc) {
            for (; optind < argc; ++optind)
                pr2serr("Unexpected extra argument: %s\n", argv[optind]);
            usage();
            return SG_LIB_SYNTAX_ERROR;
       }
    }

#ifdef DEBUG
    pr2serr("In DEBUG mode, ");
    if (verbose_given && version_given) {
        pr2serr("but override: '-vV' given, zero verbose and continue\n");
        verbose_given = false;
        version_given = false;
        verbose = 0;
    } else if (! verbose_given) {
        pr2serr("set '-vv'\n");
        verbose = 2;
    } else
        pr2serr("keep verbose=%d\n", verbose);
#else
    if (verbose_given && version_given)
        pr2serr("Not in DEBUG mode, so '-vV' has no special action\n");
#endif
    if (version_given) {
        pr2serr(ME "version: %s\n", version_str);
        return 0;
    }

    if (NULL == device_name) {
        pr2serr("Missing device name!\n\n");
        usage();
        return SG_LIB_SYNTAX_ERROR;
    }
    if (! lba_given) {
        pr2serr("need a --lba=LBA option\n");
        usage();
        return SG_LIB_SYNTAX_ERROR;
    }
    if (repeat) {
        if (! has_filename) {
            pr2serr("with '--repeat' need '--in=IF' option\n");
            usage();
            return SG_LIB_CONTRADICT;
        }
        if (ilen < 1) {
            pr2serr("with '--repeat' need '--ilen=ILEN' option\n");
            usage();
            return SG_LIB_CONTRADICT;
        } else {
            b_p_lb = ilen / num_lb;
            if (b_p_lb < 64) {
                pr2serr("calculated %d bytes per logical block, too small\n",
                        b_p_lb);
                usage();
                return SG_LIB_SYNTAX_ERROR;
            }
        }
    }

    sg_fd = sg_cmds_open_device(device_name, false /* rw */, verbose);
    if (sg_fd < 0) {
        ret = sg_convert_errno(-sg_fd);
        pr2serr(ME "open error: %s: %s\n", device_name, safe_strerror(-sg_fd));
        goto err_out;
    }

    if ((! do_16) && (llba > UINT_MAX))
        do_16 = true;
    if ((! do_16) && (num_lb > 0xffff))
        do_16 = true;
    snprintf(cmd_name, sizeof(cmd_name), "Write and verify(%d)",
             (do_16 ? 16 : 10));
    if (verbose && (! given_do_16) && do_16)
        pr2serr("Switching to %s because LBA or NUM too large\n", cmd_name);
    if (verbose) {
        pr2serr("Issue %s to device %s\n\tilen=%d", cmd_name, device_name,
                ilen);
        if (ilen > 0)
            pr2serr(" [0x%x]", ilen);
        pr2serr(", lba=%" PRIu64 " [0x%" PRIx64 "]\n\twrprotect=%d, dpo=%d, "
                "bytchk=%d, group=%d, repeat=%d\n", llba, llba, wrprotect,
                (int)dpo, bytchk, group, (int)repeat);
    }

    first_time = true;
    do {
        if (first_time) {
            //If a file with data to write has been provided
            if (has_filename) {
                struct stat a_stat;

                if ((1 == strlen(ifnp)) && ('-' == ifnp[0])) {
                    ifd = STDIN_FILENO;
                    ifnp = "<stdin>";
                    if (verbose > 1)
                        pr2serr("Reading input data from stdin\n");
                } else {
                    ifd = open_if(ifnp, 0);
                    if (ifd < 0) {
                        ret = -ifd;
                        goto err_out;
                    }
                }
                if (ilen < 1) {
                    if (fstat(ifd, &a_stat) < 0) {
                        pr2serr("Could not fstat(%s)\n", ifnp);
                        goto err_out;
                    }
                    if (! S_ISREG(a_stat.st_mode)) {
                        pr2serr("Cannot determine IF size, please give "
                                "'--ilen='\n");
                        goto err_out;
                    }
                    ilen = (int)a_stat.st_size;
                    if (ilen < 1) {
                        pr2serr("%s file size too small\n", ifnp);
                        goto err_out;
                    } else if (verbose)
                        pr2serr("Using file size of %d bytes\n", ilen);
                }
                if (NULL == (wrkBuff = (uint8_t *)sg_memalign(ilen, 0,
                                           &free_wrkBuff, verbose > 3))) {
                    pr2serr(ME "out of memory\n");
                    ret = sg_convert_errno(ENOMEM);
                    goto err_out;
                }
                wvb = (uint8_t *)wrkBuff;
                res = read(ifd, wvb, ilen);
                if (res < 0) {
                    pr2serr("Could not read from %s", ifnp);
                    goto err_out;
                }
                if (res < ilen) {
                    pr2serr("Read only %d bytes (expected %d) from %s\n", res,
                            ilen, ifnp);
                    if (repeat)
                        pr2serr("Will scale subsequent pieces when "
                                "repeat=true, but this is first\n");
                    goto err_out;
                }
            } else {
                if (ilen < 1) {
                    if (verbose)
                        pr2serr("Default write length to %d*%d=%d bytes\n",
                                num_lb, 512, 512 * num_lb);
                    ilen = 512 * num_lb;
                }
                if (NULL == (wrkBuff = (uint8_t *)sg_memalign(ilen, 0,
                                           &free_wrkBuff, verbose > 3))) {
                    pr2serr(ME "out of memory\n");
                    ret = sg_convert_errno(ENOMEM);
                    goto err_out;
                }
                wvb = (uint8_t *)wrkBuff;
                /* Not sure about this: default contents to 0xff bytes */
                memset(wrkBuff, 0xff, ilen);
            }
            first_time = false;
            snum_lb = num_lb;
        } else {    /* repeat=true, first_time=false, must be reading file */
            llba += snum_lb;
            res = read(ifd, wvb, ilen);
            if (res < 0) {
                pr2serr("Could not read from %s", ifnp);
                goto err_out;
            } else {
                if (verbose > 1)
                pr2serr("Subsequent read from %s got %d bytes\n", ifnp, res);
                if (0 == res)
                    break;
                if (res < ilen) {
                    snum_lb = (uint32_t)(res / b_p_lb);
                    n = res % b_p_lb;
                    if (0 != n)
                        pr2serr(">>> warning: ignoring last %d bytes of %s\n",
                                n, ifnp);
                    if (snum_lb < 1)
                        break;
                }
            }
        }
        if (do_16)
            res = sg_ll_write_verify16(sg_fd, wrprotect, dpo, bytchk, llba,
                                       snum_lb, group, wvb, ilen, timeout,
                                       verbose > 0, verbose);
        else
            res = sg_ll_write_verify10(sg_fd, wrprotect, dpo, bytchk,
                                       (unsigned int)llba, snum_lb, group,
                                       wvb, ilen, timeout, verbose > 0,
                                       verbose);
        ret = res;
        if (repeat && (0 == ret))
            tnum_lb_wr += snum_lb;
        if (ret || (snum_lb != num_lb))
            break;
    } while (repeat);

err_out:
    if (repeat)
        pr2serr("%d [0x%x] logical blocks written, in total\n", tnum_lb_wr,
                tnum_lb_wr);
    if (free_wrkBuff)
        free(free_wrkBuff);
    if ((ifd >= 0) && (STDIN_FILENO != ifd))
        close(ifd);
    res = sg_cmds_close_device(sg_fd);
    if (res < 0) {
        pr2serr("close error: %s\n", safe_strerror(-res));
        if (0 == ret)
            ret = sg_convert_errno(-res);
    }
    if (ret && (0 == verbose)) {
        if (! sg_if_can2stderr("sg_write_verify failed: ", ret))
            pr2serr("Some error occurred, try again with '-v' "
                    "or '-vv' for more information\n");
    }
    return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
}
Example #6
0
static int process_cl_new(struct opts_t * optsp, int argc, char * argv[])
{
    int c, n;

    while (1) {
        int option_index = 0;

        c = getopt_long(argc, argv, "dehHlNOpr:s:tuvV", long_options,
                        &option_index);
        if (c == -1)
            break;

        switch (c) {
        case 'd':
            optsp->do_doff = 1;
            break;
        case 'e':
            optsp->do_extdur = 1;
            break;
        case 'h':
        case '?':
            ++optsp->do_help;
            break;
        case 'H':
            ++optsp->do_hex;
            break;
        case 'l':
            ++optsp->do_list;
            break;
        case 'N':
            break;      /* ignore */
        case 'O':
            optsp->opt_new = 0;
            return 0;
        case 'p':
            optsp->do_pf = 1;
            break;
        case 'r':
            optsp->raw_arg = optarg;
            optsp->do_raw = 1;
            break;
        case 's':
            n = sg_get_num(optarg);
            if ((n < 0) || (n > 7)) {
                fprintf(stderr, "bad argument to '--selftest='\n");
                usage();
                return SG_LIB_SYNTAX_ERROR;
            }
            optsp->do_selftest = n;
            break;
        case 't':
            optsp->do_deftest = 1;
            break;
        case 'u':
            optsp->do_uoff = 1;
            break;
        case 'v':
            ++optsp->do_verbose;
            break;
        case 'V':
            ++optsp->do_version;
            break;
        default:
            fprintf(stderr, "unrecognised option code %c [0x%x]\n", c, c);
            if (optsp->do_help)
                break;
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }
    if (optind < argc) {
        if (NULL == optsp->device_name) {
            optsp->device_name = argv[optind];
            ++optind;
        }
        if (optind < argc) {
            for (; optind < argc; ++optind)
                fprintf(stderr, "Unexpected extra argument: %s\n",
                        argv[optind]);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }
    return 0;
}
Example #7
0
int
main(int argc, char * argv[])
{
    int sg_fd, outfd, res, c;
    unsigned char * readLongBuff = NULL;
    void * rawp = NULL;
    int correct = 0;
    int xfer_len = 520;
    int do_16 = 0;
    int pblock = 0;
    uint64_t llba = 0;
    int readonly = 0;
    int verbose = 0;
    int64_t ll;
    int got_stdout;
    const char * device_name = NULL;
    char out_fname[256];
    char ebuff[EBUFF_SZ];
    int ret = 0;

    memset(out_fname, 0, sizeof out_fname);
    while (1) {
        int option_index = 0;

        c = getopt_long(argc, argv, "chl:o:prSvVx:", long_options,
                        &option_index);
        if (c == -1)
            break;

        switch (c) {
        case 'c':
            correct = 1;
            break;
        case 'h':
        case '?':
            usage();
            return 0;
        case 'l':
            ll = sg_get_llnum(optarg);
            if (-1 == ll) {
                fprintf(stderr, "bad argument to '--lba'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            llba = (uint64_t)ll;
            break;
        case 'o':
            strncpy(out_fname, optarg, sizeof(out_fname) - 1);
            break;
        case 'p':
            pblock = 1;
            break;
        case 'r':
            ++readonly;
            break;
        case 'S':
            do_16 = 1;
            break;
        case 'v':
            ++verbose;
            break;
        case 'V':
            fprintf(stderr, ME "version: %s\n", version_str);
            return 0;
        case 'x':
            xfer_len = sg_get_num(optarg);
           if (-1 == xfer_len) {
                fprintf(stderr, "bad argument to '--xfer_len'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        default:
            fprintf(stderr, "unrecognised option code 0x%x ??\n", c);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }
    if (optind < argc) {
        if (NULL == device_name) {
            device_name = argv[optind];
            ++optind;
        }
        if (optind < argc) {
            for (; optind < argc; ++optind)
                fprintf(stderr, "Unexpected extra argument: %s\n",
                        argv[optind]);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }

    if (NULL == device_name) {
        fprintf(stderr, "missing device name!\n");
        usage();
        return SG_LIB_SYNTAX_ERROR;
    }
    if (xfer_len >= MAX_XFER_LEN){
        fprintf(stderr, "xfer_len (%d) is out of range ( < %d)\n",
                xfer_len, MAX_XFER_LEN);
        usage();
        return SG_LIB_SYNTAX_ERROR;
    }
    sg_fd = sg_cmds_open_device(device_name, readonly, verbose);
    if (sg_fd < 0) {
        fprintf(stderr, ME "open error: %s: %s\n", device_name,
                safe_strerror(-sg_fd));
        return SG_LIB_FILE_ERROR;
    }

    if (NULL == (rawp = malloc(MAX_XFER_LEN))) {
        fprintf(stderr, ME "out of memory\n");
        sg_cmds_close_device(sg_fd);
        return SG_LIB_SYNTAX_ERROR;
    }
    readLongBuff = (unsigned char *)rawp;
    memset(rawp, 0x0, MAX_XFER_LEN);

    fprintf(stderr, ME "issue read long (%s) to device %s\n    xfer_len=%d "
            "(0x%x), lba=%" PRIu64 " (0x%" PRIx64 "), correct=%d\n",
            (do_16 ? "16" : "10"), device_name, xfer_len, xfer_len, llba,
            llba, correct);

    if ((ret = process_read_long(sg_fd, do_16, pblock, correct, llba,
                                 readLongBuff, xfer_len, verbose)))
        goto err_out;

    if ('\0' == out_fname[0])
        dStrHex((const char *)rawp, xfer_len, 0);
    else {
        got_stdout = (0 == strcmp(out_fname, "-")) ? 1 : 0;
        if (got_stdout)
            outfd = STDOUT_FILENO;
        else {
            if ((outfd = open(out_fname, O_WRONLY | O_CREAT | O_TRUNC,
                              0666)) < 0) {
                snprintf(ebuff, EBUFF_SZ,
                         ME "could not open %s for writing", out_fname);
                perror(ebuff);
                goto err_out;
            }
        }
        if (sg_set_binary_mode(outfd) < 0) {
            perror("sg_set_binary_mode");
            goto err_out;
        }
        res = write(outfd, readLongBuff, xfer_len);
        if (res < 0) {
            snprintf(ebuff, EBUFF_SZ, ME "couldn't write to %s", out_fname);
            perror(ebuff);
            goto err_out;
        }
        if (! got_stdout)
            close(outfd);
    }

err_out:
    if (rawp) free(rawp);
    res = sg_cmds_close_device(sg_fd);
    if (res < 0) {
        fprintf(stderr, "close error: %s\n", safe_strerror(-res));
        if (0 == ret)
            return SG_LIB_FILE_ERROR;
    }
    return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
}
Example #8
0
int main(int argc, char * argv[])
{
    int sg_fd, res, c;
    int64_t count = 0;
    unsigned int num_lb = 0;
    int do_16 = 0;
    int group = 0;
    int64_t lba = 0;
    int immed = 0;
    int sync_nv = 0;
    int to_secs = DEF_PT_TIMEOUT;
    int verbose = 0;
    const char * device_name = NULL;
    int ret = 0;

    while (1) {
        int option_index = 0;

        c = getopt_long(argc, argv, "c:g:hil:sSt:vV", long_options,
                        &option_index);
        if (c == -1)
            break;

        switch (c) {
        case 'c':
            count = sg_get_llnum(optarg);
            if ((count < 0) || (count > UINT_MAX)) {
                pr2serr("bad argument to '--count'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            num_lb = (unsigned int)count;
            break;
        case 'g':
            group = sg_get_num(optarg);
            if ((group < 0) || (group > 31)) {
                pr2serr("bad argument to '--group'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'h':
        case '?':
            usage();
            return 0;
        case 'i':
            immed = 1;
            break;
        case 'l':
            lba = sg_get_llnum(optarg);
            if (lba < 0) {
                pr2serr("bad argument to '--lba'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 's':
            sync_nv = 1;
            break;
        case 'S':
            do_16 = 1;
            break;
        case 't':
            to_secs = sg_get_num(optarg);
            if (to_secs < 0) {
                pr2serr("bad argument to '--timeout'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'v':
            ++verbose;
            break;
        case 'V':
            pr2serr("version: %s\n", version_str);
            return 0;
        default:
            pr2serr("unrecognised option code 0x%x ??\n", c);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }
    if (optind < argc) {
        if (NULL == device_name) {
            device_name = argv[optind];
            ++optind;
        }
        if (optind < argc) {
            for (; optind < argc; ++optind)
                pr2serr("Unexpected extra argument: %s\n", argv[optind]);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }

    if (NULL == device_name) {
        pr2serr("missing device name!\n");
        usage();
        return SG_LIB_SYNTAX_ERROR;
    }
    sg_fd = sg_cmds_open_device(device_name, 0 /* rw */, verbose);
    if (sg_fd < 0) {
        pr2serr("open error: %s: %s\n", device_name,
                safe_strerror(-sg_fd));
        return SG_LIB_FILE_ERROR;
    }

    if (do_16)
        res = ll_sync_cache_16(sg_fd, sync_nv, immed, group, lba, num_lb,
                               to_secs, 1, verbose);
    else
        res = sg_ll_sync_cache_10(sg_fd, sync_nv, immed, group,
                                  (unsigned int)lba, num_lb, 1, verbose);
    ret = res;
    if (res) {
        char b[80];

        sg_get_category_sense_str(res, sizeof(b), b, verbose);
        pr2serr("Synchronize cache failed: %s\n", b);
    }

    res = sg_cmds_close_device(sg_fd);
    if (res < 0) {
        pr2serr("close error: %s\n", safe_strerror(-res));
        if (0 == ret)
            return SG_LIB_FILE_ERROR;
    }
    return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
}
Example #9
0
static int process_cl_old(struct opts_t * optsp, int argc, char * argv[])
{
    int k, jmp_out, plen;
    const char * cp;

    for (k = 1; k < argc; ++k) {
        cp = argv[k];
        plen = strlen(cp);
        if (plen <= 0)
            continue;
        if ('-' == *cp) {
            for (--plen, ++cp, jmp_out = 0; plen > 0; --plen, ++cp) {
                switch (*cp) {
                case 'N':
                    optsp->opt_new = 1;
                    return 0;
                case 'O':
                    break;
                case 'p':
                    ++optsp->do_progress;
                    break;
                case 't':
                    ++optsp->do_time;
                    break;
                case 'v':
                    ++optsp->do_verbose;
                    break;
                case 'V':
                    ++optsp->do_verbose;
                    break;
                case '?':
                    usage_old();
                    return 0;
                default:
                    jmp_out = 1;
                    break;
                }
                if (jmp_out)
                    break;
            }
            if (plen <= 0)
                continue;
            if (0 == strncmp("n=", cp, 2)) {
                optsp->do_number = sg_get_num(cp + 2);
                if (optsp->do_number <= 0) {
                    printf("Couldn't decode number after 'n=' option\n");
                    usage_old();
                    return SG_LIB_SYNTAX_ERROR;
                }
            } else if (0 == strncmp("-old", cp, 4))
                ;
            else if (jmp_out) {
                fprintf(stderr, "Unrecognized option: %s\n", cp);
                usage_old();
                return SG_LIB_SYNTAX_ERROR;
            }
        } else if (0 == optsp->device_name)
            optsp->device_name = cp;
        else {
            fprintf(stderr, "too many arguments, got: %s, not expecting: "
                    "%s\n", optsp->device_name, cp);
            usage_old();
            return SG_LIB_SYNTAX_ERROR;
        }
    }
    return 0;
}
Example #10
0
int main(int argc, char * argv[])
{
    int sg_fd, res, c;
    int allow = 0;
    int prevent = -1;
    int verbose = 0;
    const char * device_name = NULL;
    int ret = 0;

    while (1) {
        int option_index = 0;

        c = getopt_long(argc, argv, "ahp:vV", long_options,
                        &option_index);
        if (c == -1)
            break;

        switch (c) {
        case 'a':
            allow = 1;
            break;
        case 'h':
        case '?':
            usage();
            return 0;
        case 'p':
           prevent = sg_get_num(optarg);
           if ((prevent < 0) || (prevent > 3)) {
                fprintf(stderr, "bad argument to '--prevent'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'v':
            ++verbose;
            break;
        case 'V':
            fprintf(stderr, ME "version: %s\n", version_str);
            return 0;
        default:
            fprintf(stderr, "unrecognised option code 0x%x ??\n", c);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }
    if (optind < argc) {
        if (NULL == device_name) {
            device_name = argv[optind];
            ++optind;
        }
        if (optind < argc) {
            for (; optind < argc; ++optind)
                fprintf(stderr, "Unexpected extra argument: %s\n",
                        argv[optind]);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }
    if (NULL == device_name) {
        fprintf(stderr, "missing device name!\n");
        usage();
        return SG_LIB_SYNTAX_ERROR;
    }
    if (allow && (prevent >= 0)) {
        fprintf(stderr, "can't give both '--allow' and '--prevent='\n");
        usage();
        return SG_LIB_SYNTAX_ERROR;
    }
    if (allow)
        prevent = 0;
    else if (prevent < 0)
        prevent = 1;    /* default is to prevent, as utility name suggests */

    sg_fd = sg_cmds_open_device(device_name, 0 /* rw */, verbose);
    if (sg_fd < 0) {
        fprintf(stderr, ME "open error: %s: %s\n", device_name,
                safe_strerror(-sg_fd));
        return SG_LIB_FILE_ERROR;
    }
    res = sg_ll_prevent_allow(sg_fd, prevent, 1, verbose);
    ret = res;
    if (0 == res)
        ;
    else if (SG_LIB_CAT_NOT_READY == res)
        fprintf(stderr, "Device not ready\n");
    else if (SG_LIB_CAT_UNIT_ATTENTION == res)
        fprintf(stderr, "Unit attention\n");
    else if (SG_LIB_CAT_ABORTED_COMMAND == res)
        fprintf(stderr, "Aborted command\n");
    else if (SG_LIB_CAT_INVALID_OP == res)
        fprintf(stderr, "Prevent allow medium removal command not "
                "supported\n");
    else if (SG_LIB_CAT_ILLEGAL_REQ == res)
        fprintf(stderr, "Prevent allow medium removal, bad field in "
                "command\n");
    else
        fprintf(stderr, "Prevent allow medium removal command failed\n");

    res = sg_cmds_close_device(sg_fd);
    if (res < 0) {
        fprintf(stderr, "close error: %s\n", safe_strerror(-res));
        if (0 == ret)
            return SG_LIB_FILE_ERROR;
    }
    return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
}
Example #11
0
static int process_cl_new(struct opts_t * optsp, int argc, char * argv[])
{
    int c, n;

    while (1) {
        int option_index = 0;

        c = getopt_long(argc, argv, "hn:NOptvV", long_options,
                        &option_index);
        if (c == -1)
            break;

        switch (c) {
        case 'h':
        case '?':
            ++optsp->do_help;
            break;
        case 'n':
            n = sg_get_num(optarg);
            if (n < 0) {
                fprintf(stderr, "bad argument to '--number='\n");
                usage();
                return SG_LIB_SYNTAX_ERROR;
            }
            optsp->do_number = n;
            break;
        case 'N':
            break;      /* ignore */
        case 'O':
            optsp->opt_new = 0;
            return 0;
        case 'p':
            ++optsp->do_progress;
            break;
        case 't':
            ++optsp->do_time;
            break;
        case 'v':
            ++optsp->do_verbose;
            break;
        case 'V':
            ++optsp->do_version;
            break;
        default:
            fprintf(stderr, "unrecognised option code %c [0x%x]\n", c, c);
            if (optsp->do_help)
                break;
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }
    if (optind < argc) {
        if (NULL == optsp->device_name) {
            optsp->device_name = argv[optind];
            ++optind;
        }
        if (optind < argc) {
            for (; optind < argc; ++optind)
                fprintf(stderr, "Unexpected extra argument: %s\n",
                        argv[optind]);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }
    return 0;
}
Example #12
0
int
main(int argc, char * argv[])
{
    int sg_fd, res, c, num, nread, infd;
    int64_t ll;
    int dpo = 0;
    int bytchk = 0;
    int ndo = 0;
    char *ref_data = NULL;
    int vrprotect = 0;
    int64_t count = 1;
    int64_t orig_count;
    int bpc = 128;
    int bpc_given = 0;
    int got_stdin = 0;
    int group = 0;
    uint64_t lba = 0;
    uint64_t orig_lba;
    int quiet = 0;
    int readonly = 0;
    int verbose = 0;
    int verify16 = 0;
    const char * device_name = NULL;
    const char * file_name = NULL;
    const char * vc;
    int ret = 0;
    unsigned int info = 0;
    uint64_t info64 = 0;
    char ebuff[EBUFF_SZ];

    while (1) {
        int option_index = 0;

        c = getopt_long(argc, argv, "b:B:c:dE:g:hi:l:n:P:qrSvV", long_options,
                        &option_index);
        if (c == -1)
            break;

        switch (c) {
        case 'b':
            bpc = sg_get_num(optarg);
            if (bpc < 1) {
                fprintf(stderr, "bad argument to '--bpc'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            ++bpc_given;
            break;
        case 'c':
            count = sg_get_llnum(optarg);
            if (count < 0) {
                fprintf(stderr, "bad argument to '--count'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'd':
            dpo = 1;
            break;
        case 'E':
            bytchk = sg_get_num(optarg);
            if ((bytchk < 1) || (bytchk > 3)) {
                fprintf(stderr, "bad argument to '--ebytchk'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'g':
            group = sg_get_num(optarg);
            if ((group < 0) || (group > 31)) {
                fprintf(stderr, "bad argument to '--group'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'h':
        case '?':
            usage();
            return 0;
        case 'i':
            file_name = optarg;
            break;
        case 'l':
            ll = sg_get_llnum(optarg);
            if (-1 == ll) {
                fprintf(stderr, "bad argument to '--lba'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            lba = (uint64_t)ll;
            break;
        case 'n':
        case 'B':       /* undocumented, old --bytchk=NDO option */
            ndo = sg_get_num(optarg);
            if (ndo < 1) {
                fprintf(stderr, "bad argument to '--ndo'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'P':
            vrprotect = sg_get_num(optarg);
            if (-1 == vrprotect) {
                fprintf(stderr, "bad argument to '--vrprotect'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            if ((vrprotect < 0) || (vrprotect > 7)) {
                fprintf(stderr, "'--vrprotect' requires a value from 0 to "
                        "7 (inclusive)\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'q':
            ++quiet;
            break;
        case 'r':
            ++readonly;
            break;
        case 'S':
            ++verify16;
            break;
        case 'v':
            ++verbose;
            break;
        case 'V':
            fprintf(stderr, ME "version: %s\n", version_str);
            return 0;
        default:
            fprintf(stderr, "unrecognised option code 0x%x ??\n", c);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }
    if (optind < argc) {
        if (NULL == device_name) {
            device_name = argv[optind];
            ++optind;
        }
        if (optind < argc) {
            for (; optind < argc; ++optind)
                fprintf(stderr, "Unexpected extra argument: %s\n",
                        argv[optind]);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }
    if (ndo > 0) {
        if (0 == bytchk)
            bytchk = 1;
        if (bpc_given && (bpc != count))
            fprintf(stderr, "'bpc' argument ignored, using --bpc=%"
                    PRIu64 "\n", count);
        if (count > 0x7fffffffLL) {
            fprintf(stderr, "count exceed 31 bits, way too large\n");
            return SG_LIB_SYNTAX_ERROR;
        }
        if ((3 == bytchk) && (1 != count)) {
            fprintf(stderr, "count must be 1 when bytchk=3\n");
            return SG_LIB_SYNTAX_ERROR;
        }
        bpc = (int)count;
    } else if (bytchk > 0) {
        fprintf(stderr, "when the 'ebytchk=BCH' option is given, "
                "then '--bytchk=NDO' must also be given\n");
        return SG_LIB_SYNTAX_ERROR;
    }

    if ((bpc > 0xffff) && (0 == verify16)) {
        fprintf(stderr, "'%s' exceeds 65535, so use VERIFY(16)\n",
                (ndo > 0) ? "count" : "bpc");
        ++verify16;
    }
    if (((lba + count - 1) > 0xffffffffLLU) && (0 == verify16)) {
        fprintf(stderr, "'lba' exceed 32 bits, so use VERIFY(16)\n");
        ++verify16;
    }
    if ((group > 0) && (0 == verify16))
        fprintf(stderr, "group number ignored with VERIFY(10) command, "
                "use the --16 option\n");

    orig_count = count;
    orig_lba = lba;

    if (ndo > 0) {
        ref_data = (char *)malloc(ndo);
        if (NULL == ref_data) {
            fprintf(stderr, "failed to allocate %d byte buffer\n", ndo);
            return SG_LIB_FILE_ERROR;
        }
        if ((NULL == file_name) || (0 == strcmp(file_name, "-"))) {
            ++got_stdin;
            infd = STDIN_FILENO;
            if (sg_set_binary_mode(STDIN_FILENO) < 0)
                perror("sg_set_binary_mode");
        } else {
            if ((infd = open(file_name, O_RDONLY)) < 0) {
                snprintf(ebuff, EBUFF_SZ,
                         ME "could not open %s for reading", file_name);
                perror(ebuff);
                ret = SG_LIB_FILE_ERROR;
                goto err_out;
            } else if (sg_set_binary_mode(infd) < 0)
                perror("sg_set_binary_mode");
        }
        if (verbose && got_stdin)
                fprintf(stderr, "about to wait on STDIN\n");
        for (nread = 0; nread < ndo; nread += res) {
            res = read(infd, ref_data + nread, ndo - nread);
            if (res <= 0) {
                fprintf(stderr, "reading from %s failed at file offset=%d\n",
                        (got_stdin ? "stdin" : file_name), nread);
                ret = SG_LIB_FILE_ERROR;
                goto err_out;
            }
        }
        if (! got_stdin)
            close(infd);
    }

    if (NULL == device_name) {
        fprintf(stderr, "missing device name!\n");
        usage();
        ret = SG_LIB_SYNTAX_ERROR;
        goto err_out;
    }
    sg_fd = sg_cmds_open_device(device_name, readonly, verbose);
    if (sg_fd < 0) {
        fprintf(stderr, ME "open error: %s: %s\n", device_name,
                safe_strerror(-sg_fd));
        ret = SG_LIB_FILE_ERROR;
        goto err_out;
    }

    vc = verify16 ? "VERIFY(16)" : "VERIFY(10)";
    for (; count > 0; count -= bpc, lba += bpc) {
        num = (count > bpc) ? bpc : count;
        if (verify16)
            res = sg_ll_verify16(sg_fd, vrprotect, dpo, bytchk,
                                 lba, num, group, ref_data,
                                 ndo, &info64, !quiet , verbose);
        else
            res = sg_ll_verify10(sg_fd, vrprotect, dpo, bytchk,
                                 (unsigned int)lba, num, ref_data,
                                 ndo, &info, !quiet, verbose);
        if (0 != res) {
            char b[80];

            ret = res;
            switch (res) {
            case SG_LIB_CAT_ILLEGAL_REQ:
                fprintf(stderr, "bad field in %s cdb, near lba=0x%" PRIx64
                        "\n", vc, lba);
                break;
            case SG_LIB_CAT_MEDIUM_HARD:
                fprintf(stderr, "%s medium or hardware error near "
                        "lba=0x%" PRIx64 "\n", vc, lba);
                break;
            case SG_LIB_CAT_MEDIUM_HARD_WITH_INFO:
                if (verify16)
                    fprintf(stderr, "%s medium or hardware error, reported "
                            "lba=0x%" PRIx64 "\n", vc, info64);
                else
                    fprintf(stderr, "%s medium or hardware error, reported "
                            "lba=0x%x\n", vc, info);
                break;
            case SG_LIB_CAT_MISCOMPARE:
                if ((0 == quiet) || verbose)
                    fprintf(stderr, "%s reported MISCOMPARE\n", vc);
                break;
            default:
                sg_get_category_sense_str(res, sizeof(b), b, verbose);
                fprintf(stderr, "%s: %s\n", vc, b);
                fprintf(stderr, "    failed near lba=%" PRIu64 " [0x%" PRIx64
                        "]\n", lba, lba);
                break;
            }
            break;
        }
    }

    if (verbose && (0 == ret) && (orig_count > 1))
        fprintf(stderr, "Verified %" PRId64 " [0x%" PRIx64 "] blocks from "
                "lba %" PRIu64 " [0x%" PRIx64 "]\n    without error\n",
                orig_count, (uint64_t)orig_count, orig_lba, orig_lba);

    res = sg_cmds_close_device(sg_fd);
    if (res < 0) {
        fprintf(stderr, "close error: %s\n", safe_strerror(-res));
        if (0 == ret)
            ret = SG_LIB_FILE_ERROR;
    }

 err_out:
    if (ref_data)
        free(ref_data);
    return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
}
Example #13
0
static int
process_cl(struct opts_t * op, int argc, char *argv[])
{
    while (1) {
        int c, n;

        c = getopt_long(argc, argv, "bhi:k:no:r:Rs:t:vV", long_options, NULL);
        if (c == -1)
            break;

        switch (c) {
        case 'b':
            op->datain_binary = 1;
            break;
        case 'h':
        case '?':
            op->do_help = 1;
            return 0;
        case 'i':
            if (op->dataout_file) {
                fprintf(stderr, "Too many '--infile=' options\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            op->dataout_file = optarg;
            break;
        case 'k':
            n = sg_get_num(optarg);
            if (n < 0) {
                fprintf(stderr, "Invalid argument to '--skip'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            op->dataout_offset = n;
            break;
        case 'n':
            op->no_sense = 1;
            break;
        case 'o':
            if (op->datain_file) {
                fprintf(stderr, "Too many '--outfile=' options\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            op->datain_file = optarg;
            break;
        case 'r':
            op->do_datain = 1;
            n = sg_get_num(optarg);
            if (n < 0 || n > MAX_SCSI_DXLEN) {
                fprintf(stderr, "Invalid argument to '--request'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            op->datain_len = n;
            break;
        case 'R':
            ++op->readonly;
            break;
        case 's':
            op->do_dataout = 1;
            n = sg_get_num(optarg);
            if (n < 0 || n > MAX_SCSI_DXLEN) {
                fprintf(stderr, "Invalid argument to '--send'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            op->dataout_len = n;
            break;
        case 't':
            n = sg_get_num(optarg);
            if (n < 0) {
                fprintf(stderr, "Invalid argument to '--timeout'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            op->timeout = n;
            break;
        case 'v':
            ++op->do_verbose;
            break;
        case 'V':
            op->do_version = 1;
            return 0;
        default:
            return SG_LIB_SYNTAX_ERROR;
        }
    }

    if (optind >= argc) {
        fprintf(stderr, "No device specified\n");
        return SG_LIB_SYNTAX_ERROR;
    }
    op->device_name = argv[optind];
    ++optind;

    while (optind < argc) {
        char *opt = argv[optind++];
        char *endptr;
        int cmd = strtol(opt, &endptr, 16);
        if (*opt == '\0' || *endptr != '\0' || cmd < 0x00 || cmd > 0xff) {
            fprintf(stderr, "Invalid command byte '%s'\n", opt);
            return SG_LIB_SYNTAX_ERROR;
        }

        if (op->cdb_length > MAX_SCSI_CDBSZ) {
            fprintf(stderr, "CDB too long (max. %d bytes)\n", MAX_SCSI_CDBSZ);
            return SG_LIB_SYNTAX_ERROR;
        }
        op->cdb[op->cdb_length] = cmd;
        ++op->cdb_length;
    }

    if (op->cdb_length < MIN_SCSI_CDBSZ) {
        fprintf(stderr, "CDB too short (min. %d bytes)\n", MIN_SCSI_CDBSZ);
        return SG_LIB_SYNTAX_ERROR;
    }
    if (op->do_verbose > 2) {
        int sa;
        char b[80];

        if (op->cdb_length > 16) {
            sa = (op->cdb[8] << 8) + op->cdb[9];
            if (0x7f != op->cdb[0])
                printf(">>> Unlikely to be SCSI CDB since all over 16 "
                       "bytes long should\n>>> start with 0x7f\n");
        } else
            sa = op->cdb[1] & 0x1f;
        sg_get_opcode_sa_name(op->cdb[0], sa, 0, sizeof(b), b);
        printf("Attempt to decode cdb name: %s\n", b);
    }
    return 0;
}
Example #14
0
int
main(int argc, char * argv[])
{
    bool correct = false;
    bool do_16 = false;
    bool pblock = false;
    bool readonly = false;
    bool got_stdout;
    bool verbose_given = false;
    bool version_given = false;
    int outfd, res, c;
    int sg_fd = -1;
    int ret = 0;
    int xfer_len = 520;
    int verbose = 0;
    uint64_t llba = 0;
    int64_t ll;
    uint8_t * readLongBuff = NULL;
    uint8_t * rawp = NULL;
    uint8_t * free_rawp = NULL;
    const char * device_name = NULL;
    char out_fname[256];
    char ebuff[EBUFF_SZ];

    memset(out_fname, 0, sizeof out_fname);
    while (1) {
        int option_index = 0;

        c = getopt_long(argc, argv, "chl:o:prSvVx:", long_options,
                        &option_index);
        if (c == -1)
            break;

        switch (c) {
        case 'c':
            correct = true;
            break;
        case 'h':
        case '?':
            usage();
            return 0;
        case 'l':
            ll = sg_get_llnum(optarg);
            if (-1 == ll) {
                pr2serr("bad argument to '--lba'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            llba = (uint64_t)ll;
            break;
        case 'o':
            strncpy(out_fname, optarg, sizeof(out_fname) - 1);
            break;
        case 'p':
            pblock = true;
            break;
        case 'r':
            readonly = true;
            break;
        case 'S':
            do_16 = true;
            break;
        case 'v':
            verbose_given = true;
            ++verbose;
            break;
        case 'V':
            version_given = true;
            break;
        case 'x':
            xfer_len = sg_get_num(optarg);
           if (-1 == xfer_len) {
                pr2serr("bad argument to '--xfer_len'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        default:
            pr2serr("unrecognised option code 0x%x ??\n", c);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }
    if (optind < argc) {
        if (NULL == device_name) {
            device_name = argv[optind];
            ++optind;
        }
        if (optind < argc) {
            for (; optind < argc; ++optind)
                pr2serr("Unexpected extra argument: %s\n", argv[optind]);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }

#ifdef DEBUG
    pr2serr("In DEBUG mode, ");
    if (verbose_given && version_given) {
        pr2serr("but override: '-vV' given, zero verbose and continue\n");
        verbose_given = false;
        version_given = false;
        verbose = 0;
    } else if (! verbose_given) {
        pr2serr("set '-vv'\n");
        verbose = 2;
    } else
        pr2serr("keep verbose=%d\n", verbose);
#else
    if (verbose_given && version_given)
        pr2serr("Not in DEBUG mode, so '-vV' has no special action\n");
#endif
    if (version_given) {
        pr2serr(ME "version: %s\n", version_str);
        return 0;
    }

    if (NULL == device_name) {
        pr2serr("Missing device name!\n\n");
        usage();
        return SG_LIB_SYNTAX_ERROR;
    }
    if (xfer_len >= MAX_XFER_LEN){
        pr2serr("xfer_len (%d) is out of range ( < %d)\n", xfer_len,
                MAX_XFER_LEN);
        usage();
        return SG_LIB_SYNTAX_ERROR;
    }
    sg_fd = sg_cmds_open_device(device_name, readonly, verbose);
    if (sg_fd < 0) {
        if (verbose)
            pr2serr(ME "open error: %s: %s\n", device_name,
                    safe_strerror(-sg_fd));
        ret = sg_convert_errno(-sg_fd);
        goto err_out;
    }

    if (NULL == (rawp = (uint8_t *)sg_memalign(MAX_XFER_LEN, 0, &free_rawp,
                                               false))) {
        if (verbose)
            pr2serr(ME "out of memory\n");
        ret = sg_convert_errno(ENOMEM);
        goto err_out;
    }
    readLongBuff = (uint8_t *)rawp;
    memset(rawp, 0x0, MAX_XFER_LEN);

    pr2serr(ME "issue read long (%s) to device %s\n    xfer_len=%d (0x%x), "
            "lba=%" PRIu64 " (0x%" PRIx64 "), correct=%d\n",
            (do_16 ? "16" : "10"), device_name, xfer_len, xfer_len, llba,
            llba, (int)correct);

    if ((ret = process_read_long(sg_fd, do_16, pblock, correct, llba,
                                 readLongBuff, xfer_len, verbose)))
        goto err_out;

    if ('\0' == out_fname[0])
        hex2stdout((const uint8_t *)rawp, xfer_len, 0);
    else {
        got_stdout = (0 == strcmp(out_fname, "-"));
        if (got_stdout)
            outfd = STDOUT_FILENO;
        else {
            if ((outfd = open(out_fname, O_WRONLY | O_CREAT | O_TRUNC,
                              0666)) < 0) {
                snprintf(ebuff, EBUFF_SZ,
                         ME "could not open %s for writing", out_fname);
                perror(ebuff);
                goto err_out;
            }
        }
        if (sg_set_binary_mode(outfd) < 0) {
            perror("sg_set_binary_mode");
            goto err_out;
        }
        res = write(outfd, readLongBuff, xfer_len);
        if (res < 0) {
            snprintf(ebuff, EBUFF_SZ, ME "couldn't write to %s", out_fname);
            perror(ebuff);
            goto err_out;
        }
        if (! got_stdout)
            close(outfd);
    }

err_out:
    if (free_rawp)
        free(free_rawp);
    if (sg_fd >= 0) {
        res = sg_cmds_close_device(sg_fd);
        if (res < 0) {
            pr2serr("close error: %s\n", safe_strerror(-res));
            if (0 == ret)
                ret = sg_convert_errno(-res);
        }
    }
    if (0 == verbose) {
        if (! sg_if_can2stderr("sg_read_long failed: ", ret))
            pr2serr("Some error occurred, try again with '-v' "
                    "or '-vv' for more information\n");
    }
    return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
}
Example #15
0
int main(int argc, char * argv[])
{
    int sg_fd, c, res;
    const char * device_name = NULL;
    int cdb_len = SAT_ATA_PASS_THROUGH16_LEN;
    int do_packet = 0;
    int do_hex = 0;
    int do_indent = 0;
    int do_raw = 0;
    int o_readonly = 0;
    int verbose = 0;
    int ck_cond = 0;   /* set to 1 to read register(s) back */
    int extend = 0;    /* set to 1 to send 48 bit LBA with command */
    int ret = 0;

    while (1) {
        int option_index = 0;

        c = getopt_long(argc, argv, "cehHil:prRvV", long_options,
                        &option_index);
        if (c == -1)
            break;

        switch (c) {
        case 'c':
            ++ck_cond;
            break;
        case 'e':
            ++extend;
            break;
        case 'h':
        case '?':
            usage();
            return 0;
        case 'H':
            ++do_hex;
            break;
        case 'i':
            ++do_indent;
            break;
        case 'l':
            cdb_len = sg_get_num(optarg);
            if (! ((cdb_len == 12) || (cdb_len == 16))) {
                pr2serr("argument to '--len' should be 12 or 16\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'p':
            ++do_packet;
            break;
        case 'r':
            ++do_raw;
            break;
        case 'R':
            ++o_readonly;
            break;
        case 'v':
            ++verbose;
            break;
        case 'V':
            pr2serr("version: %s\n", version_str);
            return 0;
        default:
            pr2serr("unrecognised option code 0x%x ??\n", c);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }
    if (optind < argc) {
        if (NULL == device_name) {
            device_name = argv[optind];
            ++optind;
        }
        if (optind < argc) {
            for (; optind < argc; ++optind)
                pr2serr("Unexpected extra argument: %s\n", argv[optind]);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }

    if (NULL == device_name) {
        pr2serr("missing device name!\n");
        usage();
        return 1;
    }
    if (do_raw) {
        if (sg_set_binary_mode(STDOUT_FILENO) < 0) {
            perror("sg_set_binary_mode");
            return SG_LIB_FILE_ERROR;
        }
    }

    if ((sg_fd = sg_cmds_open_device(device_name, o_readonly, verbose)) < 0) {
        pr2serr("error opening file: %s: %s\n", device_name,
                safe_strerror(-sg_fd));
        return SG_LIB_FILE_ERROR;
    }

    ret = do_identify_dev(sg_fd, do_packet, cdb_len, ck_cond, extend,
                          do_indent, do_hex, do_raw, verbose);

    res = sg_cmds_close_device(sg_fd);
    if (res < 0) {
        pr2serr("close error: %s\n", safe_strerror(-res));
        if (0 == ret)
            return SG_LIB_FILE_ERROR;
    }
    return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
}
Example #16
0
int
main(int argc, char * argv[])
{
    bool do_packet = false;
    bool do_ident = false;
    bool do_raw = false;
    bool o_readonly = false;
    bool ck_cond = false;    /* set to true to read register(s) back */
    bool extend = false;    /* set to true to send 48 bit LBA with command */
    bool verbose_given = false;
    bool version_given = false;
    int c, res;
    int sg_fd = -1;
    int cdb_len = SAT_ATA_PASS_THROUGH16_LEN;
    int do_hex = 0;
    int verbose = 0;
    int ret = 0;
    const char * device_name = NULL;

    while (1) {
        int option_index = 0;

        c = getopt_long(argc, argv, "cehHil:prRvV", long_options,
                        &option_index);
        if (c == -1)
            break;

        switch (c) {
        case 'c':
            ck_cond = true;
            break;
        case 'e':
            extend = true;
            break;
        case 'h':
        case '?':
            usage();
            return 0;
        case 'H':
            ++do_hex;
            break;
        case 'i':
            do_ident = true;
            break;
        case 'l':
            cdb_len = sg_get_num(optarg);
            switch (cdb_len) {
            case 12:
            case 16:
            case 32:
                break;
            default:
                pr2serr("argument to '--len' should be 12, 16 or 32\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'p':
            do_packet = true;
            break;
        case 'r':
            do_raw = true;
            break;
        case 'R':
            o_readonly = true;
            break;
        case 'v':
            verbose_given = true;
            ++verbose;
            break;
        case 'V':
            version_given = true;
            break;
        default:
            pr2serr("unrecognised option code 0x%x ??\n", c);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }
    if (optind < argc) {
        if (NULL == device_name) {
            device_name = argv[optind];
            ++optind;
        }
        if (optind < argc) {
            for (; optind < argc; ++optind)
                pr2serr("Unexpected extra argument: %s\n", argv[optind]);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }
#ifdef DEBUG
    pr2serr("In DEBUG mode, ");
    if (verbose_given && version_given) {
        pr2serr("but override: '-vV' given, zero verbose and continue\n");
        verbose_given = false;
        version_given = false;
        verbose = 0;
    } else if (! verbose_given) {
        pr2serr("set '-vv'\n");
        verbose = 2;
    } else
        pr2serr("keep verbose=%d\n", verbose);
#else
    if (verbose_given && version_given)
        pr2serr("Not in DEBUG mode, so '-vV' has no special action\n");
#endif
    if (version_given) {
        pr2serr("version: %s\n", version_str);
        return 0;
    }

    if (NULL == device_name) {
        pr2serr("Missing device name!\n\n");
        usage();
        return 1;
    }
    if (do_raw) {
        if (sg_set_binary_mode(STDOUT_FILENO) < 0) {
            perror("sg_set_binary_mode");
            return SG_LIB_FILE_ERROR;
        }
    }

    if ((sg_fd = sg_cmds_open_device(device_name, o_readonly, verbose)) < 0) {
        if (verbose)
            pr2serr("error opening file: %s: %s\n", device_name,
                    safe_strerror(-sg_fd));
        ret = sg_convert_errno(-sg_fd);
        goto fini;
    }

    ret = do_identify_dev(sg_fd, do_packet, cdb_len, ck_cond, extend,
                          do_ident, do_hex, do_raw, verbose);

fini:
    if (sg_fd >= 0) {
        res = sg_cmds_close_device(sg_fd);
        if (res < 0) {
            pr2serr("close error: %s\n", safe_strerror(-res));
            if (0 == ret)
                ret = sg_convert_errno(-res);
        }
    }
    if (0 == verbose) {
        if (! sg_if_can2stderr("sg_sat_identify failed: ", ret))
            pr2serr("Some error occurred, try again with '-v' "
                    "or '-vv' for more information\n");
    }
    return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
}
Example #17
0
int
main(int argc, char * argv[])
{
    bool do_one_segment = false;
    bool o_readonly = false;
    bool do_raw = false;
    bool verbose_given = false;
    bool version_given = false;
    int k, res, c, rlen;
    int sg_fd = -1;
    int do_hex = 0;
    int maxlen = DEF_REFER_BUFF_LEN;
    int verbose = 0;
    int desc = 0;
    int ret = 0;
    int64_t ll;
    uint64_t lba = 0;
    const char * device_name = NULL;
    const uint8_t * bp;
    uint8_t * referralBuffp = referralBuff;
    uint8_t * free_referralBuffp = NULL;

    while (1) {
        int option_index = 0;

        c = getopt_long(argc, argv, "hHl:m:rRsvV", long_options,
                        &option_index);
        if (c == -1)
            break;

        switch (c) {
        case 'h':
        case '?':
            usage();
            return 0;
        case 'H':
            ++do_hex;
            break;
        case 'l':
            ll = sg_get_llnum(optarg);
            if (-1 == ll) {
                pr2serr("bad argument to '--lba'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            lba = (uint64_t)ll;
            break;
        case 'm':
            maxlen = sg_get_num(optarg);
            if ((maxlen < 0) || (maxlen > MAX_REFER_BUFF_LEN)) {
                pr2serr("argument to '--maxlen' should be %d or less\n",
                        MAX_REFER_BUFF_LEN);
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 's':
            do_one_segment = true;
            break;
        case 'r':
            do_raw = true;
            break;
        case 'R':
            o_readonly = true;
            break;
        case 'v':
            verbose_given = true;
            ++verbose;
            break;
        case 'V':
            version_given = true;
            break;
        default:
            pr2serr("unrecognised option code 0x%x ??\n", c);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }
    if (optind < argc) {
        if (NULL == device_name) {
            device_name = argv[optind];
            ++optind;
        }
        if (optind < argc) {
            for (; optind < argc; ++optind)
                pr2serr("Unexpected extra argument: %s\n", argv[optind]);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }
#ifdef DEBUG
    pr2serr("In DEBUG mode, ");
    if (verbose_given && version_given) {
        pr2serr("but override: '-vV' given, zero verbose and continue\n");
        verbose_given = false;
        version_given = false;
        verbose = 0;
    } else if (! verbose_given) {
        pr2serr("set '-vv'\n");
        verbose = 2;
    } else
        pr2serr("keep verbose=%d\n", verbose);
#else
    if (verbose_given && version_given)
        pr2serr("Not in DEBUG mode, so '-vV' has no special action\n");
#endif
    if (version_given) {
        pr2serr("version: %s\n", version_str);
        return 0;
    }

    if (NULL == device_name) {
        pr2serr("No DEVICE argument given\n\n");
        usage();
        return SG_LIB_SYNTAX_ERROR;
    }
    if (maxlen > DEF_REFER_BUFF_LEN) {
        referralBuffp = (uint8_t *)sg_memalign(maxlen, 0,
                                               &free_referralBuffp,
                                               verbose > 3);
        if (NULL == referralBuffp) {
            pr2serr("unable to allocate %d bytes on heap\n", maxlen);
            return sg_convert_errno(ENOMEM);
        }
    }
    if (do_raw) {
        if (sg_set_binary_mode(STDOUT_FILENO) < 0) {
            perror("sg_set_binary_mode");
            ret = SG_LIB_FILE_ERROR;
            goto free_buff;
        }
    }

    sg_fd = sg_cmds_open_device(device_name, o_readonly, verbose);
    if (sg_fd < 0) {
        if (verbose)
            pr2serr("open error: %s: %s\n", device_name,
                    safe_strerror(-sg_fd));
        ret = sg_convert_errno(-sg_fd);
        goto free_buff;
    }

    res = sg_ll_report_referrals(sg_fd, lba, do_one_segment, referralBuffp,
                                 maxlen, true, verbose);
    ret = res;
    if (0 == res) {
        if (maxlen >= 4)
            /*
             * This is strictly speaking incorrect. However, the
             * spec reserved bytes 0 and 1, so some implementations
             * might want to use them to increase the number of
             * possible user segments.
             * And maybe someone takes a pity and updates the spec ...
             */
            rlen = sg_get_unaligned_be32(referralBuffp + 0) + 4;
        else
            rlen = maxlen;
        k = (rlen > maxlen) ? maxlen : rlen;
        if (do_raw) {
            dStrRaw(referralBuffp, k);
            goto the_end;
        }
        if (do_hex) {
            hex2stdout(referralBuffp, k, 1);
            goto the_end;
        }
        if (maxlen < 4) {
            if (verbose)
                pr2serr("Exiting because allocation length (maxlen)  less "
                        "than 4\n");
            goto the_end;
        }
        if ((verbose > 1) || (verbose && (rlen > maxlen))) {
            pr2serr("response length %d bytes\n", rlen);
            if (rlen > maxlen)
                pr2serr("  ... which is greater than maxlen (allocation "
                        "length %d), truncation\n", maxlen);
        }
        if (rlen > maxlen)
            rlen = maxlen;

        bp = referralBuffp + 4;
        k = 0;
        printf("Report referrals:\n");
        while (k < rlen - 4) {
            printf("  descriptor %d:\n", desc);
            res = decode_referral_desc(bp + k, rlen - 4 - k);
            if (res < 0) {
                pr2serr("bad user data segment referral descriptor\n");
                break;
            }
            k += res;
            desc++;
        }
    } else {
        char b[80];

        sg_get_category_sense_str(res, sizeof(b), b, verbose);
        pr2serr("Report Referrals command failed: %s\n", b);
    }

the_end:
    res = sg_cmds_close_device(sg_fd);
    if (res < 0) {
        pr2serr("close error: %s\n", safe_strerror(-res));
        if (0 == ret)
            ret = sg_convert_errno(-res);
    }
free_buff:
    if (free_referralBuffp)
        free(free_referralBuffp);
    if (0 == verbose) {
        if (! sg_if_can2stderr("sg_referrals failed: ", ret))
            pr2serr("Some error occurred, try again with '-v' "
                    "or '-vv' for more information\n");
    }
    return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
}
Example #18
0
int main (int argc, char * argv[])
{
        bool verbose_given = true;
        bool version_given = true;
        int sg_fd, res;
        const char * device_name = NULL;
        int times = 1;
        int ret = 0;
        int k = 0;
        int err;

        while (1) {
                int option_index = 0;
                int c;

                c = getopt_long(argc, argv, "hqr:s:t:w:vV",
                                long_options, &option_index);
                if (c == -1)
                        break;

                switch (c) {
                case 'h':
                        usage();
                        return 0;
                case 'q':
                        do_quick = true;
                        break;
                case 'r':
                        addread = sg_get_num(optarg);
                        if (-1 == addread) {
                                pr2serr("bad argument to '--addrd'\n");
                                return SG_LIB_SYNTAX_ERROR;
                        }
                        break;
                case 's':
                        size = sg_get_num(optarg);
                        if (-1 == size) {
                                pr2serr("bad argument to '--size'\n");
                                return SG_LIB_SYNTAX_ERROR;
                        }
                        break;
                case 't':
                        times = sg_get_num(optarg);
                        if (-1 == times) {
                                pr2serr("bad argument to '--times'\n");
                                return SG_LIB_SYNTAX_ERROR;
                        }
                        break;
                case 'v':
                        verbose_given = true;
                        verbose++;
                        break;
                case 'V':
                        version_given = true;
                        break;
                case 'w':
                        addwrite = sg_get_num(optarg);
                        if (-1 == addwrite) {
                                pr2serr("bad argument to '--addwr'\n");
                                return SG_LIB_SYNTAX_ERROR;
                        }
                        break;
                default:
                        usage();
                        return SG_LIB_SYNTAX_ERROR;
                }
        }
        if (optind < argc) {
                if (NULL == device_name) {
                        device_name = argv[optind];
                        ++optind;
                }
        }
        if (optind < argc) {
                if (-1 == size) {
                        size = sg_get_num(argv[optind]);
                        if (-1 == size) {
                                pr2serr("bad <sz>\n");
                                usage();
                                return SG_LIB_SYNTAX_ERROR;
                        }
                        if (++optind < argc) {
                                addwrite = sg_get_num(argv[optind]);
                                if (-1 == addwrite) {
                                        pr2serr("bad [addwr]\n");
                                        usage();
                                        return SG_LIB_SYNTAX_ERROR;
                                }
                                if (++optind < argc) {
                                        addread = sg_get_num(argv[optind]);
                                        if (-1 == addread) {
                                                pr2serr("bad [addrd]\n");
                                                usage();
                                                return SG_LIB_SYNTAX_ERROR;
                                        }
                                }
                        }

                }
                if (optind < argc) {
                        for (; optind < argc; ++optind)
                                pr2serr("Unexpected extra argument" ": %s\n",
                                        argv[optind]);
                        usage();
                        return SG_LIB_SYNTAX_ERROR;
                }
        }

#ifdef DEBUG
        pr2serr("In DEBUG mode, ");
        if (verbose_given && version_given) {
                pr2serr("but override: '-vV' given, zero verbose and "
                        "continue\n");
                verbose_given = false;
                version_given = false;
                verbose = 0;
        } else if (! verbose_given) {
                pr2serr("set '-vv'\n");
                verbose = 2;
        } else
                pr2serr("keep verbose=%d\n", verbose);
#else
        if (verbose_given && version_given)
                pr2serr("Not in DEBUG mode, so '-vV' has no special action\n");
#endif
        if (version_given) {
                pr2serr(ME "version: %s\n", version_str);
                return 0;
        }

        if (NULL == device_name) {
                pr2serr("no device name given\n");
                usage();
                return SG_LIB_SYNTAX_ERROR;
        }
        if ((size <= 0) && (! do_quick)) {
                pr2serr("must give '--size' or '--quick' options or <sz> "
                        "argument\n");
                usage();
                return SG_LIB_SYNTAX_ERROR;
        }

        sg_fd = open(device_name, O_RDWR | O_NONBLOCK);
        if (sg_fd < 0) {
                err = errno;
                perror("sg_test_rwbuf: open error");
                return sg_convert_errno(err);
        }
        ret = find_out_about_buffer(sg_fd);
        if (ret)
                goto err_out;
        if (do_quick) {
                printf ("READ BUFFER read descriptor reports a buffer "
                        "of %d bytes [%d KiB]\n", buf_capacity,
                        buf_capacity / 1024);
                goto err_out;
        }
        if (size > buf_capacity) {
                pr2serr (ME "sz=%i > buf_capacity=%i\n", size, buf_capacity);
                ret = SG_LIB_CAT_OTHER;
                goto err_out;
        }

        cmpbuf = (uint8_t *)sg_memalign(size, 0, &free_cmpbuf, false);
        for (k = 0; k < times; ++k) {
                ret = write_buffer (sg_fd, size);
                if (ret) {
                        goto err_out;
                }
                ret = read_buffer (sg_fd, size);
                if (ret) {
                        if (2222 == ret)
                                ret = SG_LIB_CAT_MALFORMED;
                        goto err_out;
                }
        }

err_out:
        if (free_cmpbuf)
                free(free_cmpbuf);
        res = close(sg_fd);
        if (res < 0) {
                perror(ME "close error");
                if (0 == ret)
                        ret = sg_convert_errno(errno);
        }
        if ((0 == ret) && (! do_quick))
                printf ("Success\n");
        else if (times > 1)
                printf ("Failed after %d successful cycles\n", k);
        return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
}
Example #19
0
static int
new_parse_cmd_line(struct opts_t * op, int argc, char * argv[])
{
    int c, n;

    while (1) {
        int option_index = 0;

        c = getopt_long(argc, argv, "hln:NOptvV", long_options,
                        &option_index);
        if (c == -1)
            break;

        switch (c) {
        case 'h':
        case '?':
            ++op->do_help;
            break;
        case 'l':
            op->do_low = true;
            break;
        case 'n':
            n = sg_get_num(optarg);
            if (n < 0) {
                pr2serr("bad argument to '--number='\n");
                usage();
                return SG_LIB_SYNTAX_ERROR;
            }
            op->do_number = n;
            break;
        case 'N':
            break;      /* ignore */
        case 'O':
            op->opts_new = false;
            return 0;
        case 'p':
            op->do_progress = true;
            break;
        case 't':
            op->do_time = true;
            break;
        case 'v':
            op->verbose_given = true;
            ++op->verbose;
            break;
        case 'V':
            op->version_given = true;
            break;
        default:
            pr2serr("unrecognised option code %c [0x%x]\n", c, c);
            if (op->do_help)
                break;
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }
    if (optind < argc) {
        if (NULL == op->device_name) {
            op->device_name = argv[optind];
            ++optind;
        }
        if (optind < argc) {
            for (; optind < argc; ++optind)
                pr2serr("Unexpected extra argument: %s\n", argv[optind]);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }
    return 0;
}
Example #20
0
int
main(int argc, char * argv[])
{
    int sg_fd, res, c, len, k, n, got_stdin, is_reg, rsp_len, verb, last;
    int infd = -1;
    int do_help = 0;
    const char * device_name = NULL;
    const char * file_name = NULL;
    unsigned char * dmp = NULL;
    unsigned char * dip = NULL;
    char * cp;
    char ebuff[EBUFF_SZ];
    struct stat a_stat;
    struct dout_buff_t dout;
    struct opts_t opts;
    struct opts_t * op;
    const struct mode_s * mp;
    uint32_t gen_code = 0;
    int ret = 0;

    op = &opts;
    memset(op, 0, sizeof(opts));
    memset(&dout, 0, sizeof(dout));
    while (1) {
        int option_index = 0;

        c = getopt_long(argc, argv, "b:hi:I:l:m:No:s:S:t:vV", long_options,
                        &option_index);
        if (c == -1)
            break;

        switch (c) {
        case 'b':
            op->bpw = sg_get_num(optarg);
            if (op->bpw < 0) {
                pr2serr("argument to '--bpw' should be in a positive "
                        "number\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            if ((cp = strchr(optarg, ','))) {
                if (0 == strncmp("act", cp + 1, 3))
                    ++op->bpw_then_activate;
            }
            break;
        case 'h':
        case '?':
            ++do_help;
            break;
        case 'i':
            op->mc_id = sg_get_num(optarg);
            if ((op->mc_id < 0) || (op->mc_id > 255)) {
                pr2serr("argument to '--id' should be in the range 0 to "
                        "255\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'I':
            file_name = optarg;
            break;
        case 'l':
            op->mc_len = sg_get_num(optarg);
            if (op->mc_len < 0) {
                pr2serr("bad argument to '--length'\n");
                return SG_LIB_SYNTAX_ERROR;
             }
             op->mc_len_given = 1;
             break;
        case 'm':
            if (isdigit(*optarg)) {
                op->mc_mode = sg_get_num(optarg);
                if ((op->mc_mode < 0) || (op->mc_mode > 255)) {
                    pr2serr("argument to '--mode' should be in the range 0 "
                            "to 255\n");
                    return SG_LIB_SYNTAX_ERROR;
                }
            } else {
                len = strlen(optarg);
                for (mp = mode_arr; mp->mode_string; ++mp) {
                    if (0 == strncmp(mp->mode_string, optarg, len)) {
                        op->mc_mode = mp->mode;
                        break;
                    }
                }
                if (! mp->mode_string) {
                    print_modes();
                    return SG_LIB_SYNTAX_ERROR;
                }
            }
            break;
        case 'N':
            ++op->mc_non;
            break;
        case 'o':
           op->mc_offset = sg_get_num(optarg);
           if (op->mc_offset < 0) {
                pr2serr("bad argument to '--offset'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            if (0 != (op->mc_offset % 4)) {
                pr2serr("'--offset' value needs to be a multiple of 4\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 's':
           op->mc_skip = sg_get_num(optarg);
           if (op->mc_skip < 0) {
                pr2serr("bad argument to '--skip'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'S':
           op->mc_subenc = sg_get_num(optarg);
           if ((op->mc_subenc < 0) || (op->mc_subenc > 255)) {
                pr2serr("expected argument to '--subenc' to be 0 to 255\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 't':
           op->mc_tlen = sg_get_num(optarg);
           if (op->mc_tlen < 0) {
                pr2serr("bad argument to '--tlength'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'v':
            ++op->verbose;
            break;
        case 'V':
            pr2serr(ME "version: %s\n", version_str);
            return 0;
        default:
            pr2serr("unrecognised option code 0x%x ??\n", c);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }
    if (do_help) {
        if (do_help > 1) {
            usage();
            pr2serr("\n");
            print_modes();
        } else
            usage();
        return 0;
    }
    if (optind < argc) {
        if (NULL == device_name) {
            device_name = argv[optind];
            ++optind;
        }
        if (optind < argc) {
            for (; optind < argc; ++optind)
                pr2serr("Unexpected extra argument: %s\n", argv[optind]);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }

    if (NULL == device_name) {
        pr2serr("missing device name!\n");
        usage();
        return SG_LIB_SYNTAX_ERROR;
    }

    if ((op->mc_len > 0) && (op->bpw > op->mc_len)) {
        pr2serr("trim chunk size (CS) to be the same as LEN\n");
        op->bpw = op->mc_len;
    }

#ifdef SG_LIB_WIN32
#ifdef SG_LIB_WIN32_DIRECT
    if (op->verbose > 4)
        pr2serr("Initial win32 SPT interface state: %s\n",
                scsi_pt_win32_spt_state() ? "direct" : "indirect");
    scsi_pt_win32_direct(SG_LIB_WIN32_DIRECT /* SPT pt interface */);
#endif
#endif

    sg_fd = sg_cmds_open_device(device_name, 0 /* rw */, op->verbose);
    if (sg_fd < 0) {
        pr2serr(ME "open error: %s: %s\n", device_name,
                safe_strerror(-sg_fd));
        return SG_LIB_FILE_ERROR;
    }

    if (file_name && ((MODE_DNLD_STATUS == op->mc_mode) ||
                      (MODE_ACTIVATE_MC == op->mc_mode)))
        pr2serr("ignoring --in=FILE option\n");
    else if (file_name) {
        got_stdin = (0 == strcmp(file_name, "-")) ? 1 : 0;
        if (got_stdin)
            infd = STDIN_FILENO;
        else {
            if ((infd = open(file_name, O_RDONLY)) < 0) {
                snprintf(ebuff, EBUFF_SZ,
                         ME "could not open %s for reading", file_name);
                perror(ebuff);
                ret = SG_LIB_FILE_ERROR;
                goto fini;
            } else if (sg_set_binary_mode(infd) < 0)
                perror("sg_set_binary_mode");
        }
        if ((0 == fstat(infd, &a_stat)) && S_ISREG(a_stat.st_mode)) {
            is_reg = 1;
            if (0 == op->mc_len) {
                if (op->mc_skip >= a_stat.st_size) {
                    pr2serr("skip exceeds file size of %d bytes\n",
                            (int)a_stat.st_size);
                    ret = SG_LIB_FILE_ERROR;
                    goto fini;
                }
                op->mc_len = (int)(a_stat.st_size) - op->mc_skip;
            }
        } else {
            is_reg = 0;
            if (0 == op->mc_len)
                op->mc_len = DEF_XFER_LEN;
        }
        if (op->mc_len > MAX_XFER_LEN) {
            pr2serr("file size or requested length (%d) exceeds "
                    "MAX_XFER_LEN of %d bytes\n", op->mc_len,
                    MAX_XFER_LEN);
            ret = SG_LIB_FILE_ERROR;
            goto fini;
        }
        if (NULL == (dmp = (unsigned char *)malloc(op->mc_len))) {
            pr2serr(ME "out of memory (to hold microcode)\n");
            ret = SG_LIB_CAT_OTHER;
            goto fini;
        }
        /* Don't remember why this is preset to 0xff, from write_buffer */
        memset(dmp, 0xff, op->mc_len);
        if (op->mc_skip > 0) {
            if (! is_reg) {
                if (got_stdin)
                    pr2serr("Can't skip on stdin\n");
                else
                    pr2serr(ME "not a 'regular' file so can't apply skip\n");
                ret = SG_LIB_FILE_ERROR;
                goto fini;
            }
            if (lseek(infd, op->mc_skip, SEEK_SET) < 0) {
                snprintf(ebuff,  EBUFF_SZ, ME "couldn't skip to "
                         "required position on %s", file_name);
                perror(ebuff);
                ret = SG_LIB_FILE_ERROR;
                goto fini;
            }
        }
        res = read(infd, dmp, op->mc_len);
        if (res < 0) {
            snprintf(ebuff, EBUFF_SZ, ME "couldn't read from %s",
                     file_name);
            perror(ebuff);
            ret = SG_LIB_FILE_ERROR;
            goto fini;
        }
        if (res < op->mc_len) {
            if (op->mc_len_given) {
                pr2serr("tried to read %d bytes from %s, got %d bytes\n",
                        op->mc_len, file_name, res);
                pr2serr("pad with 0xff bytes and continue\n");
            } else {
                if (op->verbose) {
                    pr2serr("tried to read %d bytes from %s, got %d "
                            "bytes\n", op->mc_len, file_name, res);
                    pr2serr("will send %d bytes", res);
                    if ((op->bpw > 0) && (op->bpw < op->mc_len))
                        pr2serr(", %d bytes per WRITE BUFFER command\n",
                                op->bpw);
                    else
                        pr2serr("\n");
                }
                op->mc_len = res;
            }
        }
        if (! got_stdin)
            close(infd);
        infd = -1;
    } else if (! ((MODE_DNLD_STATUS == op->mc_mode) ||
                  (MODE_ACTIVATE_MC == op->mc_mode))) {
        pr2serr("need --in=FILE option with given mode\n");
        ret = SG_LIB_SYNTAX_ERROR;
        goto fini;
    }
    if (op->mc_tlen < op->mc_len)
        op->mc_tlen = op->mc_len;
    if (op->mc_non && (MODE_DNLD_STATUS == op->mc_mode)) {
        pr2serr("Do nothing because '--non' given so fetching the Download "
                "microcode status\ndpage might be dangerous\n");
        goto fini;
    }

    if (NULL == (dip = (unsigned char *)malloc(DEF_DI_LEN))) {
        pr2serr(ME "out of memory (data-in buffer)\n");
        ret = SG_LIB_CAT_OTHER;
        goto fini;
    }
    memset(dip, 0, DEF_DI_LEN);
    verb = (op->verbose > 1) ? op->verbose - 1 : 0;
    /* Fetch Download microcode status dpage for generation code ++ */
    res = sg_ll_receive_diag(sg_fd, 1 /* pcv */, DPC_DOWNLOAD_MICROCODE, dip,
                             DEF_DI_LEN, 1, verb);
    if (0 == res) {
        rsp_len = sg_get_unaligned_be16(dip + 2) + 4;
        if (rsp_len > DEF_DI_LEN) {
            pr2serr("<<< warning response buffer too small [%d but need "
                    "%d]>>>\n", DEF_DI_LEN, rsp_len);
            rsp_len = DEF_DI_LEN;
        }
        if (rsp_len < 8) {
            pr2serr("Download microcode status dpage too short\n");
            ret = SG_LIB_CAT_OTHER;
            goto fini;
        }
    } else {
        ret = res;
        goto fini;
    }
    gen_code = sg_get_unaligned_be32(dip + 4);

    if (MODE_DNLD_STATUS == op->mc_mode) {
        ses_download_code_sdg(dip, rsp_len, gen_code);
        goto fini;
    } else if (MODE_ACTIVATE_MC == op->mc_mode) {
        res = send_then_receive(sg_fd, gen_code, 0, NULL, 0, &dout, dip, 1,
                                op);
        ret = res;
        goto fini;
    }

    res = 0;
    if (op->bpw > 0) {
        for (k = 0, last = 0; k < op->mc_len; k += n) {
            n = op->mc_len - k;
            if (n > op->bpw)
                n = op->bpw;
            else
                last = 1;
            if (op->verbose)
                pr2serr("bpw loop: mode=0x%x, id=%d, off_off=%d, len=%d, "
                        "last=%d\n", op->mc_mode, op->mc_id, k, n, last);
            res = send_then_receive(sg_fd, gen_code, k, dmp + k, n, &dout,
                                    dip, last, op);
            if (res)
                break;
        }
        if (op->bpw_then_activate && (0 == res)) {
            op->mc_mode = MODE_ACTIVATE_MC;
            if (op->verbose)
                pr2serr("sending Activate deferred microcode [0xf]\n");
            res = send_then_receive(sg_fd, gen_code, 0, NULL, 0, &dout,
                                    dip, 1, op);
        }
    } else {
        if (op->verbose)
            pr2serr("single: mode=0x%x, id=%d, offset=%d, len=%d\n",
                    op->mc_mode, op->mc_id, op->mc_offset, op->mc_len);
        res = send_then_receive(sg_fd, gen_code, 0, dmp, op->mc_len, &dout,
                                dip, 1, op);
    }
    if (res)
        ret = res;

fini:
    if ((infd >= 0) && (! got_stdin))
        close(infd);
    if (dmp)
        free(dmp);
    if (dout.doutp)
        free(dout.doutp);
    res = sg_cmds_close_device(sg_fd);
    if (res < 0) {
        pr2serr("close error: %s\n", safe_strerror(-res));
        if (0 == ret)
            return SG_LIB_FILE_ERROR;
    }
    if (ret && (0 == op->verbose)) {
        if (SG_LIB_CAT_INVALID_OP == ret)
            pr2serr("%sRECEIVE DIAGNOSTIC RESULTS command not supported\n",
                    ((MODE_DNLD_STATUS == op->mc_mode) ?
                     "" : "SEND DIAGNOSTIC or "));
        else if (ret > 0)
            pr2serr("Failed, exit status %d\n", ret);
        else if (ret < 0)
            pr2serr("Some error occurred\n");
    }
    return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
}
Example #21
0
static int
old_parse_cmd_line(struct opts_t * op, int argc, char * argv[])
{
    bool jmp_out;
    int k, plen;
    const char * cp;

    for (k = 1; k < argc; ++k) {
        cp = argv[k];
        plen = strlen(cp);
        if (plen <= 0)
            continue;
        if ('-' == *cp) {
            for (--plen, ++cp, jmp_out = false; plen > 0; --plen, ++cp) {
                switch (*cp) {
                case 'l':
                    op->do_low = true;
                    return 0;
                case 'N':
                    op->opts_new = true;
                    return 0;
                case 'O':
                    break;
                case 'p':
                    op->do_progress = true;
                    break;
                case 't':
                    op->do_time = true;
                    break;
                case 'v':
                    op->verbose_given = true;
                    ++op->verbose;
                    break;
                case 'V':
                    op->version_given = true;
                    break;
                case '?':
                    usage_old();
                    return 0;
                default:
                    jmp_out = true;
                    break;
                }
                if (jmp_out)
                    break;
            }
            if (plen <= 0)
                continue;
            if (0 == strncmp("n=", cp, 2)) {
                op->do_number = sg_get_num(cp + 2);
                if (op->do_number <= 0) {
                    printf("Couldn't decode number after 'n=' option\n");
                    usage_old();
                    return SG_LIB_SYNTAX_ERROR;
                }
            } else if (0 == strncmp("-old", cp, 4))
                ;
            else if (jmp_out) {
                pr2serr("Unrecognized option: %s\n", cp);
                usage_old();
                return SG_LIB_SYNTAX_ERROR;
            }
        } else if (0 == op->device_name)
            op->device_name = cp;
        else {
            pr2serr("too many arguments, got: %s, not expecting: %s\n",
                    op->device_name, cp);
            usage_old();
            return SG_LIB_SYNTAX_ERROR;
        }
    }
    return 0;
}
Example #22
0
int
main(int argc, char * argv[])
{
    int sg_fd, c, ret, res, n;
    int ata_cmd = ATA_READ_LOG_EXT;
    unsigned char *inbuff;
    struct opts_t opts;
    struct opts_t * op;

    op = &opts;
    memset(op, 0, sizeof(opts));
    op->cdb_len = SAT_ATA_PASS_THROUGH16_LEN;
    op->count = 1;
    while (1) {
        int option_index = 0;

        c = getopt_long(argc, argv, "c:CdhHl:L:p:rvV", long_options,
                        &option_index);
        if (c == -1)
            break;

        switch (c) {
        case 'c':
            op->count = sg_get_num(optarg);
            if ((op->count < 1) || (op->count > 0xffff)) {
                pr2serr("bad argument for '--count'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'C':
            op->ck_cond = 1;
            break;
        case 'd':
            ata_cmd = ATA_READ_LOG_DMA_EXT;
            break;
        case 'h':
        case '?':
            usage();
            return 0;
        case 'H':
            ++op->hex;
            break;
        case 'l':
           op->cdb_len = sg_get_num(optarg);
           if (! ((op->cdb_len == 12) || (op->cdb_len == 16))) {
                pr2serr("argument to '--len' should be 12 or 16\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'L':
            op->la = sg_get_num(optarg);
            if (op->la < 0 || op->la > 0xff) {
                pr2serr("bad argument for '--log'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'p':
            op->pn = sg_get_num(optarg);
            if ((op->pn < 0) || (op->pn > 0xffff)) {
                pr2serr("bad argument for '--page'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'r':
            ++op->rdonly;
            break;
        case 'v':
            ++op->verbose;
            break;
        case 'V':
            pr2serr("version: %s\n", version_str);
            return 0;
        default:
            pr2serr("unrecognised option code 0x%x ??\n", c);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }
    if (optind < argc) {
        if (NULL == op->device_name) {
            op->device_name = argv[optind];
            ++optind;
        }
        if (optind < argc) {
            for (; optind < argc; ++optind)
                pr2serr("Unexpected extra argument: %s\n",
                        argv[optind]);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }

    if (NULL == op->device_name) {
        pr2serr("missing device name!\n");
        usage();
        return 1;
    }

    if ((op->count > 0xff) && (12 == op->cdb_len)) {
        op->cdb_len = 16;
        if (op->verbose)
            pr2serr("Since count > 0xff, forcing cdb length to "
                    "16\n");
    }

    n = op->count * 512;
    inbuff = (unsigned char *)malloc(n);
    if (!inbuff) {
        pr2serr("Cannot allocate output buffer of size %d\n", n);
        return SG_LIB_CAT_OTHER;
    }

    if ((sg_fd = sg_cmds_open_device(op->device_name, op->rdonly,
                                     op->verbose)) < 0) {
        pr2serr("error opening file: %s: %s\n", op->device_name,
                safe_strerror(-sg_fd));
        ret = SG_LIB_FILE_ERROR;
        goto fini;
    }

    ret = do_read_gplog(sg_fd, ata_cmd, inbuff, op);

    res = sg_cmds_close_device(sg_fd);
    if (res < 0) {
        pr2serr("close error: %s\n", safe_strerror(-res));
        if (0 == ret)
            ret = SG_LIB_FILE_ERROR;
    }
fini:
    free(inbuff);
    return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
}
Example #23
0
int
main(int argc, char * argv[])
{
    int sg_fd, res, c, len, resid, rlen, in_len;
    unsigned int ra_len;
    int ret = 0;
    const char * device_name = NULL;
    const char * fname = NULL;
    unsigned char * rabp = NULL;
    struct opts_t opts;
    struct opts_t * op;
    char b[80];

    op = &opts;
    memset(op, 0, sizeof(opts));
    op->filter = -1;
    while (1) {
        int option_index = 0;

        c = getopt_long(argc, argv, "ceE:f:F:hHi:l:m:p:qrRs:vV",
                        long_options, &option_index);
        if (c == -1)
            break;

        switch (c) {
        case 'c':
            ++op->cache;
            break;
        case 'e':
            ++op->enumerate;
            break;
        case 'E':
           op->ea = sg_get_num(optarg);
           if ((op->ea < 0) || (op->ea > 65535)) {
                pr2serr("bad argument to '--ea=EA', expect 0 to 65535\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'f':
           op->filter = sg_get_num(optarg);
           if ((op->filter < -3) || (op->filter > 65535)) {
                pr2serr("bad argument to '--filter=FL', expect -3 to "
                        "65535\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'F':
           op->fai = sg_get_num(optarg);
           if ((op->fai < 0) || (op->fai > 65535)) {
                pr2serr("bad argument to '--first=FAI', expect 0 to 65535\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'h':
        case '?':
            usage();
            return 0;
        case 'H':
            ++op->do_hex;
            break;
        case 'i':
            fname = optarg;
            break;
        case 'l':
           op->lvn = sg_get_num(optarg);
           if ((op->lvn < 0) || (op->lvn > 255)) {
                pr2serr("bad argument to '--lvn=LVN', expect 0 to 255\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'm':
            op->maxlen = sg_get_num(optarg);
            if ((op->maxlen < 0) || (op->maxlen > MAX_RATTR_BUFF_LEN)) {
                pr2serr("argument to '--maxlen' should be %d or "
                        "less\n", MAX_RATTR_BUFF_LEN);
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'p':
           op->pn = sg_get_num(optarg);
           if ((op->pn < 0) || (op->pn > 255)) {
                pr2serr("bad argument to '--pn=PN', expect 0 to 255\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'q':
            ++op->quiet;
            break;
        case 'r':
            ++op->do_raw;
            break;
        case 'R':
            ++op->o_readonly;
            break;
        case 's':
           if (isdigit(*optarg)) {
               op->sa = sg_get_num(optarg);
               if ((op->sa < 0) || (op->sa > 63)) {
                    pr2serr("bad argument to '--sa=SA', expect 0 to 63\n");
                    return SG_LIB_SYNTAX_ERROR;
                }
            } else {
                res = find_sa_acron(optarg);
                if (res < 0) {
                    enum_sa_acrons();
                    return SG_LIB_SYNTAX_ERROR;
                }
                op->sa = res;
            }
            break;
        case 'v':
            ++op->verbose;
            break;
        case 'V':
            pr2serr("version: %s\n", version_str);
            return 0;
        default:
            pr2serr("unrecognised option code 0x%x ??\n", c);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }
    if (optind < argc) {
        if (NULL == device_name) {
            device_name = argv[optind];
            ++optind;
        }
        if (optind < argc) {
            for (; optind < argc; ++optind)
                pr2serr("Unexpected extra argument: %s\n", argv[optind]);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }

    if (op->enumerate) {
        enum_attributes();
        printf("\n");
        enum_sa_acrons();
        return 0;
    }

    if (fname && device_name) {
        pr2serr("since '--in=FN' given, ignoring DEVICE\n");
        device_name = NULL;
    }

    if (0 == op->maxlen)
        op->maxlen = DEF_RATTR_BUFF_LEN;
    rabp = (unsigned char *)calloc(1, op->maxlen);
    if (NULL == rabp) {
        pr2serr("unable to calloc %d bytes\n", op->maxlen);
        return SG_LIB_CAT_OTHER;
    }

    if (NULL == device_name) {
        if (fname) {
            if (f2hex_arr(fname, op->do_raw, 0, rabp, &in_len, op->maxlen)) {
                ret = SG_LIB_FILE_ERROR;
                goto clean_up;
            }
            if (op->do_raw)
                op->do_raw = 0;    /* can interfere on decode */
            if (in_len < 4) {
                pr2serr("--in=%s only decoded %d bytes (needs 4 at least)\n",
                        fname, in_len);
                ret = SG_LIB_SYNTAX_ERROR;
                goto clean_up;
            }
            decode_all_sa_s(rabp, in_len, op);
            goto clean_up;
        }
        pr2serr("missing device name!\n");
        usage();
        ret = SG_LIB_SYNTAX_ERROR;
        goto clean_up;
    }

    if (op->do_raw) {
        if (sg_set_binary_mode(STDOUT_FILENO) < 0) {
            perror("sg_set_binary_mode");
            ret = SG_LIB_FILE_ERROR;
                goto clean_up;
        }
    }

    sg_fd = sg_cmds_open_device(device_name, op->o_readonly, op->verbose);
    if (sg_fd < 0) {
        pr2serr("open error: %s: %s\n", device_name,
                safe_strerror(-sg_fd));
        ret = SG_LIB_FILE_ERROR;
        goto clean_up;
    }

    res = sg_ll_read_attr(sg_fd, rabp, &resid, op);
    ret = res;
    if (0 == res) {
        rlen = op->maxlen - resid;
        if (rlen < 4) {
            pr2serr("Response length (%d) too short\n", rlen);
            ret = SG_LIB_CAT_MALFORMED;
            goto close_then_end;
        }
        if ((op->sa <= RA_HIGHEST_SA) && (op->sa != RA_SMC2_SA)) {
            ra_len = ((RA_LV_LIST_SA == op->sa) ||
                      (RA_PART_LIST_SA == op->sa)) ?
                        (unsigned int)sg_get_unaligned_be16(rabp + 0) :
                        sg_get_unaligned_be32(rabp + 0) + 2;
            ra_len += 2;
        } else
            ra_len = rlen;
        if ((int)ra_len > rlen) {
            if (op->verbose)
                pr2serr("ra_len available is %d, response length is %d\n",
                        ra_len, rlen);
            len = rlen;
        } else
            len = (int)ra_len;
        if (op->do_raw) {
            dStrRaw((const char *)rabp, len);
            goto close_then_end;
        }
        decode_all_sa_s(rabp, len, op);
    } else if (SG_LIB_CAT_INVALID_OP == res)
        pr2serr("Read attribute command not supported\n");
    else {
        sg_get_category_sense_str(res, sizeof(b), b, op->verbose);
        pr2serr("Read attribute command: %s\n", b);
    }

close_then_end:
    res = sg_cmds_close_device(sg_fd);
    if (res < 0) {
        pr2serr("close error: %s\n", safe_strerror(-res));
        if (0 == ret)
            ret = SG_LIB_FILE_ERROR;
    }
clean_up:
    if (rabp)
        free(rabp);
    return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
}
Example #24
0
int
main(int argc, char * argv[])
{
    bool last, got_stdin, is_reg;
    bool want_file = false;
    bool verbose_given = false;
    bool version_given = false;
    int res, c, len, k, n, rsp_len, resid, act_len, din_len, verb;
    int sg_fd = -1;
    int infd = -1;
    int do_help = 0;
    int ret = 0;
    uint32_t gen_code = 0;
    const char * device_name = NULL;
    const char * file_name = NULL;
    uint8_t * dmp = NULL;
    uint8_t * dip = NULL;
    uint8_t * free_dip = NULL;
    char * cp;
    char ebuff[EBUFF_SZ];
    struct stat a_stat;
    struct dout_buff_t dout;
    struct opts_t opts;
    struct opts_t * op;
    const struct mode_s * mp;

    op = &opts;
    memset(op, 0, sizeof(opts));
    memset(&dout, 0, sizeof(dout));
    din_len = DEF_DIN_LEN;
    while (1) {
        int option_index = 0;

        c = getopt_long(argc, argv, "b:dehi:I:l:m:No:s:S:t:vV", long_options,
                        &option_index);
        if (c == -1)
            break;

        switch (c) {
        case 'b':
            op->bpw = sg_get_num(optarg);
            if (op->bpw < 0) {
                pr2serr("argument to '--bpw' should be in a positive "
                        "number\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            if ((cp = strchr(optarg, ','))) {
                if (0 == strncmp("act", cp + 1, 3))
                    op->bpw_then_activate = true;
            }
            break;
        case 'd':
            op->dry_run = true;
            break;
        case 'e':
            op->ealsd = true;
            break;
        case 'h':
        case '?':
            ++do_help;
            break;
        case 'i':
            op->mc_id = sg_get_num_nomult(optarg);
            if ((op->mc_id < 0) || (op->mc_id > 255)) {
                pr2serr("argument to '--id' should be in the range 0 to "
                        "255\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'I':
            file_name = optarg;
            break;
        case 'l':
            op->mc_len = sg_get_num(optarg);
            if (op->mc_len < 0) {
                pr2serr("bad argument to '--length'\n");
                return SG_LIB_SYNTAX_ERROR;
             }
             op->mc_len_given = true;
             break;
        case 'm':
            if (isdigit(*optarg)) {
                op->mc_mode = sg_get_num_nomult(optarg);
                if ((op->mc_mode < 0) || (op->mc_mode > 255)) {
                    pr2serr("argument to '--mode' should be in the range 0 "
                            "to 255\n");
                    return SG_LIB_SYNTAX_ERROR;
                }
            } else {
                len = strlen(optarg);
                for (mp = mode_arr; mp->mode_string; ++mp) {
                    if (0 == strncmp(mp->mode_string, optarg, len)) {
                        op->mc_mode = mp->mode;
                        break;
                    }
                }
                if (! mp->mode_string) {
                    print_modes();
                    return SG_LIB_SYNTAX_ERROR;
                }
            }
            break;
        case 'N':
            op->mc_non = true;
            break;
        case 'o':
           op->mc_offset = sg_get_num(optarg);
           if (op->mc_offset < 0) {
                pr2serr("bad argument to '--offset'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            if (0 != (op->mc_offset % 4)) {
                pr2serr("'--offset' value needs to be a multiple of 4\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 's':
           op->mc_skip = sg_get_num(optarg);
           if (op->mc_skip < 0) {
                pr2serr("bad argument to '--skip'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'S':
           op->mc_subenc = sg_get_num_nomult(optarg);
           if ((op->mc_subenc < 0) || (op->mc_subenc > 255)) {
                pr2serr("expected argument to '--subenc' to be 0 to 255\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 't':
           op->mc_tlen = sg_get_num(optarg);
           if (op->mc_tlen < 0) {
                pr2serr("bad argument to '--tlength'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'v':
            verbose_given = true;
            ++op->verbose;
            break;
        case 'V':
            version_given = true;
            break;
        default:
            pr2serr("unrecognised option code 0x%x ??\n", c);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }
    if (do_help) {
        if (do_help > 1) {
            usage();
            pr2serr("\n");
            print_modes();
        } else
            usage();
        return 0;
    }
    if (optind < argc) {
        if (NULL == device_name) {
            device_name = argv[optind];
            ++optind;
        }
        if (optind < argc) {
            for (; optind < argc; ++optind)
                pr2serr("Unexpected extra argument: %s\n", argv[optind]);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }

#ifdef DEBUG
    pr2serr("In DEBUG mode, ");
    if (verbose_given && version_given) {
        pr2serr("but override: '-vV' given, zero verbose and continue\n");
        verbose_given = false;
        version_given = false;
        op->verbose = 0;
    } else if (! verbose_given) {
        pr2serr("set '-vv'\n");
        op->verbose = 2;
    } else
        pr2serr("keep verbose=%d\n", op->verbose);
#else
    if (verbose_given && version_given)
        pr2serr("Not in DEBUG mode, so '-vV' has no special action\n");
#endif
    if (version_given) {
        pr2serr(ME "version: %s\n", version_str);
        return 0;
    }

    if (NULL == device_name) {
        pr2serr("missing device name!\n\n");
        usage();
        return SG_LIB_SYNTAX_ERROR;
    }
    switch (op->mc_mode) {
    case MODE_DNLD_MC_OFFS:
    case MODE_DNLD_MC_OFFS_SAVE:
    case MODE_DNLD_MC_OFFS_DEFER:
        want_file = true;
        break;
    case MODE_DNLD_STATUS:
    case MODE_ACTIVATE_MC:
    case MODE_ABORT_MC:
        want_file = false;
        break;
    default:
        pr2serr("%s: mc_mode=0x%x, continue for now\n", __func__,
                op->mc_mode);
        break;
    }

    if ((op->mc_len > 0) && (op->bpw > op->mc_len)) {
        pr2serr("trim chunk size (CS) to be the same as LEN\n");
        op->bpw = op->mc_len;
    }
    if ((op->mc_offset > 0) && (op->bpw > 0)) {
        op->mc_offset = 0;
        pr2serr("WARNING: --offset= ignored (set back to 0) when --bpw= "
                "argument given (and > 0)\n");
    }

#ifdef SG_LIB_WIN32
#ifdef SG_LIB_WIN32_DIRECT
    if (op->verbose > 4)
        pr2serr("Initial win32 SPT interface state: %s\n",
                scsi_pt_win32_spt_state() ? "direct" : "indirect");
    scsi_pt_win32_direct(SG_LIB_WIN32_DIRECT /* SPT pt interface */);
#endif
#endif

    sg_fd = sg_cmds_open_device(device_name, false /* rw */, op->verbose);
    if (sg_fd < 0) {
        if (op->verbose)
            pr2serr(ME "open error: %s: %s\n", device_name,
                    safe_strerror(-sg_fd));
        ret = sg_convert_errno(-sg_fd);
        goto fini;
    }

    if (file_name && (! want_file))
        pr2serr("ignoring --in=FILE option\n");
    else if (file_name) {
        got_stdin = (0 == strcmp(file_name, "-"));
        if (got_stdin)
            infd = STDIN_FILENO;
        else {
            if ((infd = open(file_name, O_RDONLY)) < 0) {
                ret = sg_convert_errno(errno);
                snprintf(ebuff, EBUFF_SZ,
                         ME "could not open %s for reading", file_name);
                perror(ebuff);
                goto fini;
            } else if (sg_set_binary_mode(infd) < 0)
                perror("sg_set_binary_mode");
        }
        if ((0 == fstat(infd, &a_stat)) && S_ISREG(a_stat.st_mode)) {
            is_reg = true;
            if (0 == op->mc_len) {
                if (op->mc_skip >= a_stat.st_size) {
                    pr2serr("skip exceeds file size of %d bytes\n",
                            (int)a_stat.st_size);
                    ret = SG_LIB_FILE_ERROR;
                    goto fini;
                }
                op->mc_len = (int)(a_stat.st_size) - op->mc_skip;
            }
        } else {
            is_reg = false;
            if (0 == op->mc_len)
                op->mc_len = DEF_XFER_LEN;
        }
        if (op->mc_len > MAX_XFER_LEN) {
            pr2serr("file size or requested length (%d) exceeds "
                    "MAX_XFER_LEN of %d bytes\n", op->mc_len,
                    MAX_XFER_LEN);
            ret = SG_LIB_FILE_ERROR;
            goto fini;
        }
        if (NULL == (dmp = (uint8_t *)malloc(op->mc_len))) {
            pr2serr(ME "out of memory to hold microcode read from FILE\n");
            ret = SG_LIB_CAT_OTHER;
            goto fini;
        }
        /* Don't remember why this is preset to 0xff, from write_buffer */
        memset(dmp, 0xff, op->mc_len);
        if (op->mc_skip > 0) {
            if (! is_reg) {
                if (got_stdin)
                    pr2serr("Can't skip on stdin\n");
                else
                    pr2serr(ME "not a 'regular' file so can't apply skip\n");
                ret = SG_LIB_FILE_ERROR;
                goto fini;
            }
            if (lseek(infd, op->mc_skip, SEEK_SET) < 0) {
                ret = sg_convert_errno(errno);
                snprintf(ebuff,  EBUFF_SZ, ME "couldn't skip to "
                         "required position on %s", file_name);
                perror(ebuff);
                goto fini;
            }
        }
        res = read(infd, dmp, op->mc_len);
        if (res < 0) {
            ret = sg_convert_errno(errno);
            snprintf(ebuff, EBUFF_SZ, ME "couldn't read from %s",
                     file_name);
            perror(ebuff);
            goto fini;
        }
        if (res < op->mc_len) {
            if (op->mc_len_given) {
                pr2serr("tried to read %d bytes from %s, got %d bytes\n",
                        op->mc_len, file_name, res);
                pr2serr("pad with 0xff bytes and continue\n");
            } else {
                if (op->verbose) {
                    pr2serr("tried to read %d bytes from %s, got %d "
                            "bytes\n", op->mc_len, file_name, res);
                    pr2serr("will send %d bytes", res);
                    if ((op->bpw > 0) && (op->bpw < op->mc_len))
                        pr2serr(", %d bytes per WRITE BUFFER command\n",
                                op->bpw);
                    else
                        pr2serr("\n");
                }
                op->mc_len = res;
            }
        }
        if (! got_stdin)
            close(infd);
        infd = -1;
    } else if (want_file) {
        pr2serr("need --in=FILE option with given mode\n");
        ret = SG_LIB_CONTRADICT;
        goto fini;
    }
    if (op->mc_tlen < op->mc_len)
        op->mc_tlen = op->mc_len;
    if (op->mc_non && (MODE_DNLD_STATUS == op->mc_mode)) {
        pr2serr("Do nothing because '--non' given so fetching the Download "
                "microcode status\ndpage might be dangerous\n");
        goto fini;
    }

    dip = sg_memalign(din_len, 0, &free_dip, op->verbose > 3);
    if (NULL == dip) {
        pr2serr(ME "out of memory (data-in buffer)\n");
        ret = SG_LIB_CAT_OTHER;
        goto fini;
    }
    verb = (op->verbose > 1) ? op->verbose - 1 : 0;
    /* Fetch Download microcode status dpage for generation code ++ */
    if (op->dry_run) {
        n = sizeof(dummy_rd_resp);
        n = (n < din_len) ? n : din_len;
        memcpy(dip, dummy_rd_resp, n);
        resid = din_len - n;
        res = 0;
    } else
        res = sg_ll_receive_diag_v2(sg_fd, true /* pcv */,
                                    DPC_DOWNLOAD_MICROCODE, dip, din_len,
                                    0 /*default timeout */, &resid, true,
                                    verb);
    if (0 == res) {
        rsp_len = sg_get_unaligned_be16(dip + 2) + 4;
        act_len = din_len - resid;
        if (rsp_len > din_len) {
            pr2serr("<<< warning response buffer too small [%d but need "
                    "%d]>>>\n", din_len, rsp_len);
            rsp_len = din_len;
        }
        if (rsp_len > act_len) {
            pr2serr("<<< warning response too short [actually got %d but "
                    "need %d]>>>\n", act_len, rsp_len);
            rsp_len = act_len;
        }
        if (rsp_len < 8) {
            pr2serr("Download microcode status dpage too short\n");
            ret = SG_LIB_CAT_OTHER;
            goto fini;
        }
        if ((op->verbose > 2) || (op->dry_run && op->verbose))
            pr2serr("rec diag(ini): rsp_len=%d, num_sub-enc=%u "
                    "rec_gen_code=%u\n", rsp_len, dip[1],
                    sg_get_unaligned_be32(dip + 4));
    } else {
        ret = res;
        goto fini;
    }
    gen_code = sg_get_unaligned_be32(dip + 4);

    if (MODE_DNLD_STATUS == op->mc_mode) {
        show_download_mc_sdg(dip, rsp_len, gen_code);
        goto fini;
    } else if (! want_file) {   /* ACTIVATE and ABORT */
        res = send_then_receive(sg_fd, gen_code, 0, NULL, 0, &dout, dip,
                                din_len, true, op);
        ret = res;
        goto fini;
    }

    res = 0;
    if (op->bpw > 0) {
        for (k = 0, last = false; k < op->mc_len; k += n) {
            n = op->mc_len - k;
            if (n > op->bpw)
                n = op->bpw;
            else
                last = true;
            if (op->verbose)
                pr2serr("bpw loop: mode=0x%x, id=%d, off_off=%d, len=%d, "
                        "last=%d\n", op->mc_mode, op->mc_id, k, n, last);
            res = send_then_receive(sg_fd, gen_code, k, dmp + k, n, &dout,
                                    dip, din_len, last, op);
            if (res)
                break;
        }
        if (op->bpw_then_activate && (0 == res)) {
            op->mc_mode = MODE_ACTIVATE_MC;
            if (op->verbose)
                pr2serr("sending Activate deferred microcode [0xf]\n");
            res = send_then_receive(sg_fd, gen_code, 0, NULL, 0, &dout,
                                    dip, din_len, true, op);
        }
    } else {
        if (op->verbose)
            pr2serr("single: mode=0x%x, id=%d, offset=%d, len=%d\n",
                    op->mc_mode, op->mc_id, op->mc_offset, op->mc_len);
        res = send_then_receive(sg_fd, gen_code, 0, dmp, op->mc_len, &dout,
                                dip, din_len, true, op);
    }
    if (res)
        ret = res;

fini:
    if ((infd >= 0) && (! got_stdin))
        close(infd);
    if (dmp)
        free(dmp);
    if (dout.free_doutp)
        free(dout.free_doutp);
    if (free_dip)
        free(free_dip);
    if (sg_fd >= 0) {
        res = sg_cmds_close_device(sg_fd);
        if (res < 0) {
            pr2serr("close error: %s\n", safe_strerror(-res));
            if (0 == ret)
                ret = sg_convert_errno(-res);
        }
    }
    if (0 == op->verbose) {
        if (! sg_if_can2stderr("sg_ses_mocrocode failed: ", ret))
            pr2serr("Some error occurred, try again with '-v' "
                    "or '-vv' for more information\n");
    }
    return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
}
Example #25
0
int
main(int argc, char * argv[])
{
    int res, c, len, k;
    int sg_fd = -1;
    int do_help = 0;
    int do_hex = 0;
    int do_long = 0;
    int o_readonly = 0;
    int rb_id = 0;
    int rb_len = 4;
    int rb_mode = 0;
    int rb_mode_sp = 0;
    int64_t ll;
    uint64_t rb_offset = 0;
    int do_raw = 0;
    int resid = 0;
    int verbose = 0;
    int ret = 0;
    const char * device_name = NULL;
    unsigned char * resp;
    const struct mode_s * mp;

    while (1) {
        int option_index = 0;

        c = getopt_long(argc, argv, "hHi:l:Lm:o:rRS:vV", long_options,
                        &option_index);
        if (c == -1)
            break;

        switch (c) {
        case 'h':
        case '?':
            ++do_help;
            break;
        case 'H':
            ++do_hex;
            break;
        case 'i':
            rb_id = sg_get_num(optarg);
            if ((rb_id < 0) || (rb_id > 255)) {
                fprintf(stderr, "argument to '--id' should be in the range "
                        "0 to 255\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'l':
            rb_len = sg_get_num(optarg);
            if (rb_len < 0) {
                fprintf(stderr, "bad argument to '--length'\n");
                return SG_LIB_SYNTAX_ERROR;
             }
             if (rb_len > 0xffffff) {
                fprintf(stderr, "argument to '--length' must be <= "
                        "0xffffff\n");
                return SG_LIB_SYNTAX_ERROR;
             }
             break;
        case 'L':
            ++do_long;
            break;
        case 'm':
            if (isdigit(*optarg)) {
                rb_mode = sg_get_num(optarg);
                if ((rb_mode < 0) || (rb_mode > 31)) {
                    fprintf(stderr, "argument to '--mode' should be in the "
                            "range 0 to 31\n");
                    return SG_LIB_SYNTAX_ERROR;
                }
            } else {
                len = strlen(optarg);
                for (mp = modes; mp->mode_string; ++mp) {
                    if (0 == strncmp(mp->mode_string, optarg, len)) {
                        rb_mode = mp->mode;
                        break;
                    }
                }
                if (NULL == mp) {
                    print_modes();
                    return SG_LIB_SYNTAX_ERROR;
                }
            }
            break;
        case 'o':
           ll = sg_get_llnum(optarg);
           if (ll < 0) {
                fprintf(stderr, "bad argument to '--offset'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            rb_offset = ll;
            break;
        case 'r':
            ++do_raw;
            break;
        case 'R':
            ++o_readonly;
            break;
        case 'S':
           rb_mode_sp = sg_get_num(optarg);
           if ((rb_mode_sp < 0) || (rb_mode_sp > 7)) {
                fprintf(stderr, "expected argument to '--specific' to be 0 "
                        "to 7\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'v':
            ++verbose;
            break;
        case 'V':
            fprintf(stderr, "version: %s\n", version_str);
            return 0;
        default:
            fprintf(stderr, "unrecognised option code 0x%x ??\n", c);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }
    if (do_help) {
        if (do_help > 1) {
            usage();
            fprintf(stderr, "\n");
            print_modes();
        } else
            usage();
        return 0;
    }
    if (optind < argc) {
        if (NULL == device_name) {
            device_name = argv[optind];
            ++optind;
        }
        if (optind < argc) {
            for (; optind < argc; ++optind)
                fprintf(stderr, "Unexpected extra argument: %s\n",
                        argv[optind]);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }

    if (NULL == device_name) {
        fprintf(stderr, "missing device name!\n");
        usage();
        return SG_LIB_SYNTAX_ERROR;
    }

    if (rb_len > 0) {
        resp = (unsigned char *)malloc(rb_len);
        if (NULL == resp) {
            fprintf(stderr, "unable to allocate %d bytes on the heap\n",
                    rb_len);
            return SG_LIB_CAT_OTHER;
        }
        memset(resp, 0, rb_len);
    } else
        resp = NULL;

    if (do_raw) {
        if (sg_set_binary_mode(STDOUT_FILENO) < 0) {
            perror("sg_set_binary_mode");
            ret = SG_LIB_FILE_ERROR;
            goto fini;
        }
    }

#ifdef SG_LIB_WIN32
#ifdef SG_LIB_WIN32_DIRECT
    if (verbose > 4)
        fprintf(stderr, "Initial win32 SPT interface state: %s\n",
                scsi_pt_win32_spt_state() ? "direct" : "indirect");
    scsi_pt_win32_direct(SG_LIB_WIN32_DIRECT /* SPT pt interface */);
#endif
#endif

    sg_fd = sg_cmds_open_device(device_name, o_readonly, verbose);
    if (sg_fd < 0) {
        fprintf(stderr, "open error: %s: %s\n", device_name,
                safe_strerror(-sg_fd));
        ret = SG_LIB_FILE_ERROR;
        goto fini;
    }

    if (do_long)
        res = ll_read_buffer_16(sg_fd, rb_mode, rb_mode_sp, rb_id, rb_offset,
                                resp, rb_len, &resid, 1, verbose);
    else if (rb_offset > 0xffffff) {
        fprintf(stderr, "--offset value is too large for READ BUFFER(10), "
                "try --16\n");
        ret = SG_LIB_SYNTAX_ERROR;
        goto fini;
    } else
        res = ll_read_buffer_10(sg_fd, rb_mode, rb_mode_sp, rb_id,
                                (uint32_t)rb_offset, resp, rb_len, &resid, 1,
                                verbose);
    if (0 != res) {
        char b[80];

        ret = res;
        if (res > 0) {
            sg_get_category_sense_str(res, sizeof(b), b, verbose);
            fprintf(stderr, "Read buffer(%d) failed: %s\n",
                    (do_long ? 16 : 10), b);
        }
        goto fini;
    }
    if (resid > 0)
        rb_len -= resid;        /* got back less than requested */
    if (rb_len > 0) {
        if (do_raw)
            dStrRaw((const char *)resp, rb_len);
        else if (do_hex || (rb_len < 4))
            dStrHex((const char *)resp, rb_len, ((do_hex > 1) ? 0 : 1));
        else {
            switch (rb_mode) {
            case MODE_DESCRIPTOR:
                k = (resp[1] << 16) | (resp[2] << 8) | resp[3];
                printf("OFFSET BOUNDARY: %d, Buffer offset alignment: "
                       "%d-byte\n", resp[0], (1 << resp[0]));
                printf("BUFFER CAPACITY: %d (0x%x)\n", k, k);
                break;
            case MODE_ECHO_BDESC:
                k = ((resp[2] & 0x1F) << 8) | resp[3];

                printf("EBOS:%d\n", resp[0] & 1 ? 1 : 0);
                printf("Echo buffer capacity: %d (0x%x)\n", k, k);
                break;
            default:
                dStrHex((const char *)resp, rb_len, (verbose > 1 ? 0 : 1));
                break;
            }
        }
    }

fini:
    if (resp)
        free(resp);
    if (sg_fd >= 0) {
        res = sg_cmds_close_device(sg_fd);
        if (res < 0) {
            fprintf(stderr, "close error: %s\n", safe_strerror(-res));
            if (0 == ret)
                return SG_LIB_FILE_ERROR;
        }
    }
    return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
}
Example #26
0
int
main(int argc, char * argv[])
{
    int sg_fd, k, j, res, c, rlen, num_descs;
    int do_brief = 0;
    int do_hex = 0;
    int64_t ll;
    uint64_t lba = 0;
    uint64_t d_lba = 0;
    uint32_t d_blocks = 0;
    int maxlen = DEF_GLBAS_BUFF_LEN;
    int do_raw = 0;
    int o_readonly = 0;
    int verbose = 0;
    const char * device_name = NULL;
    const unsigned char * ucp;
    int ret = 0;

    while (1) {
        int option_index = 0;

        c = getopt_long(argc, argv, "bhHl:m:rRvV", long_options,
                        &option_index);
        if (c == -1)
            break;

        switch (c) {
        case 'b':
            ++do_brief;
            break;
        case 'h':
        case '?':
            usage();
            return 0;
        case 'H':
            ++do_hex;
            break;
        case 'l':
            ll = sg_get_llnum(optarg);
            if (-1 == ll) {
                fprintf(stderr, "bad argument to '--lba'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            lba = (uint64_t)ll;
            break;
        case 'm':
            maxlen = sg_get_num(optarg);
            if ((maxlen < 0) || (maxlen > MAX_GLBAS_BUFF_LEN)) {
                fprintf(stderr, "argument to '--maxlen' should be %d or "
                        "less\n", MAX_GLBAS_BUFF_LEN);
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'r':
            ++do_raw;
            break;
        case 'R':
            ++o_readonly;
            break;
        case 'v':
            ++verbose;
            break;
        case 'V':
            fprintf(stderr, "version: %s\n", version_str);
            return 0;
        default:
            fprintf(stderr, "unrecognised option code 0x%x ??\n", c);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }
    if (optind < argc) {
        if (NULL == device_name) {
            device_name = argv[optind];
            ++optind;
        }
        if (optind < argc) {
            for (; optind < argc; ++optind)
                fprintf(stderr, "Unexpected extra argument: %s\n",
                        argv[optind]);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }

    if (NULL == device_name) {
        fprintf(stderr, "missing device name!\n");
        usage();
        return SG_LIB_SYNTAX_ERROR;
    }
    if (maxlen > DEF_GLBAS_BUFF_LEN) {
        glbasBuffp = (unsigned char *)calloc(maxlen, 1);
        if (NULL == glbasBuffp) {
            fprintf(stderr, "unable to allocate %d bytes on heap\n", maxlen);
            return SG_LIB_SYNTAX_ERROR;
        }
    }
    if (do_raw) {
        if (sg_set_binary_mode(STDOUT_FILENO) < 0) {
            perror("sg_set_binary_mode");
            ret = SG_LIB_FILE_ERROR;
            goto free_buff;
        }
    }

    sg_fd = sg_cmds_open_device(device_name, o_readonly, verbose);
    if (sg_fd < 0) {
        fprintf(stderr, "open error: %s: %s\n", device_name,
                safe_strerror(-sg_fd));
        ret = SG_LIB_FILE_ERROR;
        goto free_buff;
    }

    res = sg_ll_get_lba_status(sg_fd, lba, glbasBuffp, maxlen, 1,
                               verbose);
    ret = res;
    if (0 == res) {
        /* in sbc3r25 offset for calculating the 'parameter data length'
         * (rlen variable below) was reduced from 8 to 4. */
        if (maxlen >= 4)
            rlen = (glbasBuffp[0] << 24) + (glbasBuffp[1] << 16) +
                   (glbasBuffp[2] << 8) + glbasBuffp[3] + 4;
        else
            rlen = maxlen;
        k = (rlen > maxlen) ? maxlen : rlen;
        if (do_raw) {
            dStrRaw((const char *)glbasBuffp, k);
            goto the_end;
        }
        if (do_hex) {
            dStrHex((const char *)glbasBuffp, k, 1);
            goto the_end;
        }
        if (maxlen < 4) {
            if (verbose)
                fprintf(stderr, "Exiting because allocation length (maxlen) "
                        " less than 4\n");
            goto the_end;
        }
        if ((verbose > 1) || (verbose && (rlen > maxlen))) {
            fprintf(stderr, "response length %d bytes\n", rlen);
            if (rlen > maxlen)
                fprintf(stderr, "  ... which is greater than maxlen "
                        "(allocation length %d), truncation\n", maxlen);
        }
        if (rlen > maxlen)
            rlen = maxlen;

        if (do_brief > 1) {
            if (rlen < 24) {
                fprintf(stderr, "Need maxlen and response length to "
                        " be at least 24, have %d bytes\n", rlen);
                ret = SG_LIB_CAT_OTHER;
                goto the_end;
            }
            res = decode_lba_status_desc(glbasBuffp + 8, &d_lba, &d_blocks);
            if ((res < 0) || (res > 15)) {
                fprintf(stderr, "first LBA status descriptor returned %d "
                        "??\n", res);
                ret = SG_LIB_CAT_OTHER;
                goto the_end;
            }
            if ((lba < d_lba) || (lba >= (d_lba + d_blocks))) {
                fprintf(stderr, "given LBA not in range of first "
                        "descriptor:\n" "  descriptor LBA: 0x");
                for (j = 0; j < 8; ++j)
                    fprintf(stderr, "%02x", glbasBuffp[8 + j]);
                fprintf(stderr, "  blocks: 0x%x  p_status: %d\n",
                        (unsigned int)d_blocks, res);
                ret = SG_LIB_CAT_OTHER;
                goto the_end;
            }
            printf("%d\n", res);
            goto the_end;
        }

        if (rlen < 24) {
            printf("No complete LBA status descriptors available\n");
            goto the_end;
        }
        num_descs = (rlen - 8) / 16;
        if (verbose)
            fprintf(stderr, "%d complete LBA status descriptors found\n",
                    num_descs);
        for (ucp = glbasBuffp + 8, k = 0; k < num_descs; ucp += 16, ++k) {
            res = decode_lba_status_desc(ucp, &d_lba, &d_blocks);
            if ((res < 0) || (res > 15))
                fprintf(stderr, "descriptor %d: bad LBA status descriptor "
                        "returned %d\n", k + 1, res);
            if (do_brief) {
                printf("0x");
                for (j = 0; j < 8; ++j)
                    printf("%02x", ucp[j]);
                printf("  0x%x  %d\n", (unsigned int)d_blocks, res);
            } else {
                printf("descriptor LBA: 0x");
                for (j = 0; j < 8; ++j)
                    printf("%02x", ucp[j]);
                printf("  blocks: %u", (unsigned int)d_blocks);
                switch (res) {
                case 0:
                    printf("  mapped\n");
                    break;
                case 1:
                    printf("  deallocated\n");
                    break;
                case 2:
                    printf("  anchored\n");
                    break;
                default:
                    printf("  Provisioning status: %d\n", res);
                    break;
                }
            }
        }
        if ((num_descs * 16) + 8 < rlen)
            fprintf(stderr, "incomplete trailing LBA status descriptors "
                    "found\n");
    } else if (SG_LIB_CAT_INVALID_OP == res)
        fprintf(stderr, "Get LBA Status command not supported\n");
    else if (SG_LIB_CAT_ILLEGAL_REQ == res)
        fprintf(stderr, "Get LBA Status command: bad field in cdb\n");
    else {
        char b[80];

        sg_get_category_sense_str(res, sizeof(b), b, verbose);
        fprintf(stderr, "Get LBA Status command: %s\n", b);
    }

the_end:
    res = sg_cmds_close_device(sg_fd);
    if (res < 0) {
        fprintf(stderr, "close error: %s\n", safe_strerror(-res));
        if (0 == ret)
            ret = SG_LIB_FILE_ERROR;
    }
free_buff:
    if (glbasBuffp && (glbasBuffp != glbasBuff))
        free(glbasBuffp);
    return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
}
Example #27
0
int
main(int argc, char * argv[])
{
    int skip = 0;
    int seek = 0;
    int ibs = 0;
    int obs = 0;
    char str[STR_SZ];
    char * key;
    char * buf;
    char inf[INOUTF_SZ];
    char outf[INOUTF_SZ];
    int res, k;
    int in_num_sect = 0;
    int out_num_sect = 0;
    int num_threads = DEF_NUM_THREADS;
    int gen = 0;
    int do_time = 0;
    int in_sect_sz, out_sect_sz, first_xfer, qstate, req_index, seek_skip;
    int blocks, stop_after_write, terminate;
    char ebuff[EBUFF_SZ];
    Rq_elem * rep;
    struct timeval start_tm, end_tm;

    memset(&rcoll, 0, sizeof(Rq_coll));
    rcoll.bpt = DEF_BLOCKS_PER_TRANSFER;
    rcoll.in_type = FT_OTHER;
    rcoll.out_type = FT_OTHER;
    inf[0] = '\0';
    outf[0] = '\0';
    if (argc < 2) {
        usage();
        return 1;
    }

    for(k = 1; k < argc; k++) {
        if (argv[k])
            strncpy(str, argv[k], STR_SZ);
        else
            continue;
        for(key = str, buf = key; *buf && *buf != '=';)
            buf++;
        if (*buf)
            *buf++ = '\0';
        if (strcmp(key,"if") == 0)
            strncpy(inf, buf, INOUTF_SZ);
        else if (strcmp(key,"of") == 0)
            strncpy(outf, buf, INOUTF_SZ);
        else if (0 == strcmp(key,"ibs"))
            ibs = sg_get_num(buf);
        else if (0 == strcmp(key,"obs"))
            obs = sg_get_num(buf);
        else if (0 == strcmp(key,"bs"))
            rcoll.bs = sg_get_num(buf);
        else if (0 == strcmp(key,"bpt"))
            rcoll.bpt = sg_get_num(buf);
        else if (0 == strcmp(key,"skip"))
            skip = sg_get_num(buf);
        else if (0 == strcmp(key,"seek"))
            seek = sg_get_num(buf);
        else if (0 == strcmp(key,"count"))
            dd_count = sg_get_num(buf);
        else if (0 == strcmp(key,"dio"))
            rcoll.dio = sg_get_num(buf);
        else if (0 == strcmp(key,"thr"))
            num_threads = sg_get_num(buf);
        else if (0 == strcmp(key,"coe"))
            rcoll.coe = sg_get_num(buf);
        else if (0 == strcmp(key,"gen"))
            gen = sg_get_num(buf);
        else if (0 == strncmp(key,"deb", 3))
            rcoll.debug = sg_get_num(buf);
        else if (0 == strcmp(key,"time"))
            do_time = sg_get_num(buf);
        else if (0 == strncmp(key, "--vers", 6)) {
            fprintf(stderr, "sgq_dd for sg version 3 driver: %s\n",
                    version_str);
            return 0;
        }
        else {
            fprintf(stderr, "Unrecognized argument '%s'\n", key);
            usage();
            return 1;
        }
    }
    if (rcoll.bs <= 0) {
        rcoll.bs = DEF_BLOCK_SIZE;
        fprintf(stderr, "Assume default 'bs' (block size) of %d bytes\n",
                rcoll.bs);
    }
    if ((ibs && (ibs != rcoll.bs)) || (obs && (obs != rcoll.bs))) {
        fprintf(stderr, "If 'ibs' or 'obs' given must be same as 'bs'\n");
        usage();
        return 1;
    }
    if ((skip < 0) || (seek < 0)) {
        fprintf(stderr, "skip and seek cannot be negative\n");
        return 1;
    }
    if ((num_threads < 1) || (num_threads > MAX_NUM_THREADS)) {
        fprintf(stderr, "too few or too many threads requested\n");
        usage();
        return 1;
    }
    if (rcoll.debug)
        fprintf(stderr, "sgq_dd: if=%s skip=%d of=%s seek=%d count=%d\n",
               inf, skip, outf, seek, dd_count);
    install_handler (SIGINT, interrupt_handler);
    install_handler (SIGQUIT, interrupt_handler);
    install_handler (SIGPIPE, interrupt_handler);
    install_handler (SIGUSR1, siginfo_handler);

    rcoll.infd = STDIN_FILENO;
    rcoll.outfd = STDOUT_FILENO;
    if (inf[0] && ('-' != inf[0])) {
        rcoll.in_type = dd_filetype(inf);

        if (FT_SG == rcoll.in_type) {
            if ((rcoll.infd = open(inf, O_RDWR)) < 0) {
                snprintf(ebuff, EBUFF_SZ,
                         "sgq_dd: could not open %s for sg reading", inf);
                perror(ebuff);
                return 1;
            }
        }
        if (FT_SG != rcoll.in_type) {
            if ((rcoll.infd = open(inf, O_RDONLY)) < 0) {
                snprintf(ebuff, EBUFF_SZ,
                         "sgq_dd: could not open %s for reading", inf);
                perror(ebuff);
                return 1;
            }
            else if (skip > 0) {
                loff_t offset = skip;

                offset *= rcoll.bs;       /* could exceed 32 here! */
                if (lseek(rcoll.infd, offset, SEEK_SET) < 0) {
                    snprintf(ebuff, EBUFF_SZ,
                "sgq_dd: couldn't skip to required position on %s", inf);
                    perror(ebuff);
                    return 1;
                }
            }
        }
    }
    if (outf[0] && ('-' != outf[0])) {
        rcoll.out_type = dd_filetype(outf);

        if (FT_SG == rcoll.out_type) {
            if ((rcoll.outfd = open(outf, O_RDWR)) < 0) {
                snprintf(ebuff, EBUFF_SZ,
                        "sgq_dd: could not open %s for sg writing", outf);
                perror(ebuff);
                return 1;
            }
        }
        else {
            if (FT_OTHER == rcoll.out_type) {
                if ((rcoll.outfd = open(outf, O_WRONLY | O_CREAT, 0666)) < 0) {
                    snprintf(ebuff, EBUFF_SZ,
                            "sgq_dd: could not open %s for writing", outf);
                    perror(ebuff);
                    return 1;
                }
            }
            else {
                if ((rcoll.outfd = open(outf, O_WRONLY)) < 0) {
                    snprintf(ebuff, EBUFF_SZ,
                            "sgq_dd: could not open %s for raw writing", outf);
                    perror(ebuff);
                    return 1;
                }
            }
            if (seek > 0) {
                loff_t offset = seek;

                offset *= rcoll.bs;       /* could exceed 32 bits here! */
                if (lseek(rcoll.outfd, offset, SEEK_SET) < 0) {
                    snprintf(ebuff, EBUFF_SZ,
                "sgq_dd: couldn't seek to required position on %s", outf);
                    perror(ebuff);
                    return 1;
                }
            }
        }
    }
    if ((STDIN_FILENO == rcoll.infd) && (STDOUT_FILENO == rcoll.outfd)) {
        fprintf(stderr, "Disallow both if and of to be stdin and stdout");
        return 1;
    }
    if ((FT_OTHER == rcoll.in_type) && (FT_OTHER == rcoll.out_type) && !gen) {
        fprintf(stderr, "Either 'if' or 'of' must be a sg or raw device\n");
        return 1;
    }
    if (0 == dd_count)
        return 0;
    else if (dd_count < 0) {
        if (FT_SG == rcoll.in_type) {
            res = read_capacity(rcoll.infd, &in_num_sect, &in_sect_sz);
            if (2 == res) {
                fprintf(stderr, "Unit attention, media changed(in), repeat\n");
                res = read_capacity(rcoll.infd, &in_num_sect, &in_sect_sz);
            }
            if (0 != res) {
                fprintf(stderr, "Unable to read capacity on %s\n", inf);
                in_num_sect = -1;
            }
            else {
                if (in_num_sect > skip)
                    in_num_sect -= skip;
            }
        }
        if (FT_SG == rcoll.out_type) {
            res = read_capacity(rcoll.outfd, &out_num_sect, &out_sect_sz);
            if (2 == res) {
                fprintf(stderr, "Unit attention, media changed(out), "
                        "repeat\n");
                res = read_capacity(rcoll.outfd, &out_num_sect, &out_sect_sz);
            }
            if (0 != res) {
                fprintf(stderr, "Unable to read capacity on %s\n", outf);
                out_num_sect = -1;
            }
            else {
                if (out_num_sect > seek)
                    out_num_sect -= seek;
            }
        }
        if (in_num_sect > 0) {
            if (out_num_sect > 0)
                dd_count = (in_num_sect > out_num_sect) ? out_num_sect :
                                                       in_num_sect;
            else
                dd_count = in_num_sect;
        }
        else
            dd_count = out_num_sect;
    }
    if (rcoll.debug > 1)
        fprintf(stderr, "Start of loop, count=%d, in_num_sect=%d, "
                "out_num_sect=%d\n", dd_count, in_num_sect, out_num_sect);
    if (dd_count <= 0) {
        fprintf(stderr, "Couldn't calculate count, please give one\n");
        return 1;
    }

    rcoll.in_count = dd_count;
    rcoll.in_done_count = dd_count;
    rcoll.skip = skip;
    rcoll.in_blk = skip;
    rcoll.out_count = dd_count;
    rcoll.out_done_count = dd_count;
    rcoll.seek = seek;
    rcoll.out_blk = seek;

    if ((FT_SG == rcoll.in_type) || (FT_SG == rcoll.out_type))
        rcoll.num_rq_elems = num_threads;
    else
        rcoll.num_rq_elems = 1;
    if (prepare_rq_elems(&rcoll, inf, outf)) {
        fprintf(stderr, "Setup failure, perhaps no memory\n");
        return 1;
    }

    first_xfer = 1;
    stop_after_write = 0;
    terminate = 0;
    seek_skip =  rcoll.seek - rcoll.skip;
    if (do_time) {
        start_tm.tv_sec = 0;
        start_tm.tv_usec = 0;
        gettimeofday(&start_tm, NULL);
    }
    while (rcoll.out_done_count > 0) { /* >>>>>>>>> main loop */
        req_index = -1;
        qstate = decider(&rcoll, first_xfer, &req_index);
        rep = (req_index < 0) ? NULL : (rcoll.req_arr + req_index);
        switch (qstate) {
        case QS_IDLE:
            if ((NULL == rep) || (rcoll.in_count <= 0)) {
                /* usleep(1000); */
                /* do_poll(&rcoll, 10, NULL); */
                /* do_poll(&rcoll, 0, NULL); */
                break;
            }
            if (rcoll.debug > 8)
                fprintf(stderr, "    sgq_dd: non-sleeping QS_IDLE state, "
                                "req_index=%d\n", req_index);
            if (first_xfer >= 2)
                first_xfer = 0;
            else if (1 == first_xfer)
                ++first_xfer;
            if (stop_after_write) {
                terminate = 1;
                break;
            }
            blocks = (rcoll.in_count > rcoll.bpt) ? rcoll.bpt : rcoll.in_count;
            rep->wr = 0;
            rep->blk = rcoll.in_blk;
            rep->num_blks = blocks;
            rcoll.in_blk += blocks;
            rcoll.in_count -= blocks;

            if (FT_SG == rcoll.in_type) {
                res = sg_start_io(rep);
                if (0 != res) {
                    if (1 == res)
                        fprintf(stderr, "Out of memory starting sg io\n");
                    terminate = 1;
                }
            }
            else {
                res = normal_in_operation(&rcoll, rep, blocks);
                if (res < 0)
                    terminate = 1;
                else if (res > 0)
                    stop_after_write = 1;
            }
            break;
        case QS_IN_FINISHED:
            if (rcoll.debug > 8)
                fprintf(stderr, "    sgq_dd: state is QS_IN_FINISHED, "
                                "req_index=%d\n", req_index);
            if ((rep->blk + seek_skip) != rcoll.out_blk) {
                /* if write would be out of sequence then wait */
                if (rcoll.debug > 4)
                    fprintf(stderr, "    sgq_dd: QS_IN_FINISHED, "
                            "out of sequence\n");
                usleep(200);
                break;
            }
            rep->wr = 1;
            rep->blk = rcoll.out_blk;
            blocks = rep->num_blks;
            rcoll.out_blk += blocks;
            rcoll.out_count -= blocks;

            if (FT_SG == rcoll.out_type) {
                res = sg_start_io(rep);
                if (0 != res) {
                    if (1 == res)
                        fprintf(stderr, "Out of memory starting sg io\n");
                    terminate = 1;
                }
            }
            else {
                if (normal_out_operation(&rcoll, rep, blocks) < 0)
                    terminate = 1;
            }
            break;
        case QS_IN_POLL:
            if (rcoll.debug > 8)
                fprintf(stderr, "    sgq_dd: state is QS_IN_POLL, "
                                "req_index=%d\n", req_index);
            res = sg_fin_in_operation(&rcoll, rep);
            if (res < 0)
                terminate = 1;
            else if (res > 1) {
                if (first_xfer) {
                    /* only retry on first xfer */
                    if (0 != sg_start_io(rep))
                        terminate = 1;
                }
                else
                    terminate = 1;
            }
            break;
        case QS_OUT_POLL:
            if (rcoll.debug > 8)
                fprintf(stderr, "    sgq_dd: state is QS_OUT_POLL, "
                                "req_index=%d\n", req_index);
            res = sg_fin_out_operation(&rcoll, rep);
            if (res < 0)
                terminate = 1;
            else if (res > 1) {
                if (first_xfer) {
                    /* only retry on first xfer */
                    if (0 != sg_start_io(rep))
                        terminate = 1;
                }
                else
                    terminate = 1;
            }
            break;
        default:
            if (rcoll.debug > 8)
                fprintf(stderr, "    sgq_dd: state is ?????\n");
            terminate = 1;
            break;
        }
        if (terminate)
            break;
    } /* >>>>>>>>>>>>> end of main loop */

    if ((do_time) && (start_tm.tv_sec || start_tm.tv_usec)) {
        struct timeval res_tm;
        double a, b;

        gettimeofday(&end_tm, NULL);
        res_tm.tv_sec = end_tm.tv_sec - start_tm.tv_sec;
        res_tm.tv_usec = end_tm.tv_usec - start_tm.tv_usec;
        if (res_tm.tv_usec < 0) {
            --res_tm.tv_sec;
            res_tm.tv_usec += 1000000;
        }
        a = res_tm.tv_sec;
        a += (0.000001 * res_tm.tv_usec);
        b = (double)rcoll.bs * (dd_count - rcoll.out_done_count);
        printf("time to transfer data was %d.%06d secs",
               (int)res_tm.tv_sec, (int)res_tm.tv_usec);
        if ((a > 0.00001) && (b > 511))
            printf(", %.2f MB/sec\n", b / (a * 1000000.0));
        else
            printf("\n");
    }

    if (STDIN_FILENO != rcoll.infd)
        close(rcoll.infd);
    if (STDOUT_FILENO != rcoll.outfd)
        close(rcoll.outfd);
    res = 0;
    if (0 != rcoll.out_count) {
        fprintf(stderr, ">>>> Some error occurred,\n");
        res = 2;
    }
    print_stats();
    if (rcoll.dio_incomplete) {
        int fd;
        char c;

        fprintf(stderr, ">> Direct IO requested but incomplete %d times\n",
                rcoll.dio_incomplete);
        if ((fd = open(proc_allow_dio, O_RDONLY)) >= 0) {
            if (1 == read(fd, &c, 1)) {
                if ('0' == c)
                    fprintf(stderr, ">>> %s set to '0' but should be set "
                            "to '1' for direct IO\n", proc_allow_dio);
            }
            close(fd);
        }
    }
    if (rcoll.sum_of_resids)
        fprintf(stderr, ">> Non-zero sum of residual counts=%d\n",
               rcoll.sum_of_resids);
    return res;
}
Example #28
0
int
main(int argc, char * argv[])
{
    int64_t skip = 0;
    int64_t seek = 0;
    int ibs = 0;
    int obs = 0;
    int bpt = DEF_BLOCKS_PER_TRANSFER;
    int bpt_given = 0;
    char str[STR_SZ];
    char * key;
    char * buf;
    char inf[INOUTF_SZ];
    int in_type = FT_OTHER;
    char outf[INOUTF_SZ];
    int out_type = FT_OTHER;
    int res, k, t;
    int infd, outfd, blocks;
    unsigned char * wrkPos;
    unsigned char * wrkBuff = NULL;
    unsigned char * wrkMmap = NULL;
    int64_t in_num_sect = -1;
    int in_res_sz = 0;
    int64_t out_num_sect = -1;
    int out_res_sz = 0;
    int scsi_cdbsz_in = DEF_SCSI_CDBSZ;
    int scsi_cdbsz_out = DEF_SCSI_CDBSZ;
    int cdbsz_given = 0;
    int do_coe = 0;     /* dummy, just accept + ignore */
    int do_sync = 0;
    int num_dio_not_done = 0;
    int in_sect_sz, out_sect_sz;
    int n, flags;
    char ebuff[EBUFF_SZ];
    char b[80];
    int blocks_per;
    size_t psz;
    struct flags_t in_flags;
    struct flags_t out_flags;
    int ret = 0;

#if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
    psz = sysconf(_SC_PAGESIZE); /* POSIX.1 (was getpagesize()) */
#else
    psz = 4096;     /* give up, pick likely figure */
#endif
    inf[0] = '\0';
    outf[0] = '\0';
    memset(&in_flags, 0, sizeof(in_flags));
    memset(&out_flags, 0, sizeof(out_flags));

    for (k = 1; k < argc; k++) {
        if (argv[k])
            strncpy(str, argv[k], STR_SZ);
        else
            continue;
        for (key = str, buf = key; *buf && *buf != '=';)
            buf++;
        if (*buf)
            *buf++ = '\0';
        if (0 == strcmp(key,"bpt")) {
            bpt = sg_get_num(buf);
            if (-1 == bpt) {
                pr2serr(ME "bad argument to 'bpt'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            bpt_given = 1;
        } else if (0 == strcmp(key,"bs")) {
            blk_sz = sg_get_num(buf);
            if (-1 == blk_sz) {
                pr2serr(ME "bad argument to 'bs'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
        } else if (0 == strcmp(key,"cdbsz")) {
            scsi_cdbsz_in = sg_get_num(buf);
            scsi_cdbsz_out = scsi_cdbsz_in;
            cdbsz_given = 1;
        } else if (0 == strcmp(key,"coe")) {
            do_coe = sg_get_num(buf);   /* dummy, just accept + ignore */
            if (do_coe) {
                ;    /* unused, dummy to suppress warning */
            }
        } else if (0 == strcmp(key,"count")) {
            if (0 != strcmp("-1", buf)) {
                dd_count = sg_get_llnum(buf);
                if (-1LL == dd_count) {
                    pr2serr(ME "bad argument to 'count'\n");
                    return SG_LIB_SYNTAX_ERROR;
                }
            }   /* treat 'count=-1' as calculate count (same as not given) */
        } else if (0 == strcmp(key,"dio"))
            out_flags.dio = sg_get_num(buf);
        else if (0 == strcmp(key,"fua")) {
            n = sg_get_num(buf);
            if (n & 1)
                out_flags.fua = 1;
            if (n & 2)
                in_flags.fua = 1;
        } else if (0 == strcmp(key,"ibs")) {
            ibs = sg_get_num(buf);
            if (-1 == ibs) {
                pr2serr(ME "bad argument to 'ibs'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
        } else if (strcmp(key,"if") == 0) {
            if ('\0' != inf[0]) {
                pr2serr("Second 'if=' argument??\n");
                return SG_LIB_SYNTAX_ERROR;
            } else
                strncpy(inf, buf, INOUTF_SZ);
        } else if (0 == strcmp(key, "iflag")) {
            if (process_flags(buf, &in_flags)) {
                pr2serr(ME "bad argument to 'iflag'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
        } else if (strcmp(key,"of") == 0) {
            if ('\0' != outf[0]) {
                pr2serr("Second 'of=' argument??\n");
                return SG_LIB_SYNTAX_ERROR;
            } else
                strncpy(outf, buf, INOUTF_SZ);
        } else if (0 == strcmp(key, "oflag")) {
            if (process_flags(buf, &out_flags)) {
                pr2serr(ME "bad argument to 'oflag'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
        } else if (0 == strcmp(key,"obs")) {
            obs = sg_get_num(buf);
            if (-1 == obs) {
                pr2serr(ME "bad argument to 'obs'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
        } else if (0 == strcmp(key,"seek")) {
            seek = sg_get_llnum(buf);
            if (-1LL == seek) {
                pr2serr(ME "bad argument to 'seek'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
        } else if (0 == strcmp(key,"skip")) {
            skip = sg_get_llnum(buf);
            if (-1LL == skip) {
                pr2serr(ME "bad argument to 'skip'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
        } else if (0 == strcmp(key,"sync"))
            do_sync = sg_get_num(buf);
        else if (0 == strcmp(key,"time"))
            do_time = sg_get_num(buf);
        else if (0 == strncmp(key, "verb", 4))
            verbose = sg_get_num(buf);
        else if ((0 == strncmp(key, "--help", 7)) ||
                 (0 == strcmp(key, "-h")) || (0 == strcmp(key, "-?"))) {
            usage();
            return 0;
        } else if ((0 == strncmp(key, "--vers", 6)) ||
                   (0 == strcmp(key, "-V"))) {
            pr2serr(ME ": %s\n", version_str);
            return 0;
        }
        else {
            pr2serr("Unrecognized option '%s'\n", key);
            pr2serr("For more information use '--help'\n");
            return SG_LIB_SYNTAX_ERROR;
        }
    }
    if (blk_sz <= 0) {
        blk_sz = DEF_BLOCK_SIZE;
        pr2serr("Assume default 'bs' (block size) of %d bytes\n", blk_sz);
    }
    if ((ibs && (ibs != blk_sz)) || (obs && (obs != blk_sz))) {
        pr2serr("If 'ibs' or 'obs' given must be same as 'bs'\n");
        usage();
        return SG_LIB_SYNTAX_ERROR;
    }
    if ((skip < 0) || (seek < 0)) {
        pr2serr("skip and seek cannot be negative\n");
        return SG_LIB_SYNTAX_ERROR;
    }
    if ((out_flags.append > 0) && (seek > 0)) {
        pr2serr("Can't use both append and seek switches\n");
        return SG_LIB_SYNTAX_ERROR;
    }
    if (bpt < 1) {
        pr2serr("bpt must be greater than 0\n");
        return SG_LIB_SYNTAX_ERROR;
    }
    /* defaulting transfer size to 128*2048 for CD/DVDs is too large
       for the block layer in lk 2.6 and results in an EIO on the
       SG_IO ioctl. So reduce it in that case. */
    if ((blk_sz >= 2048) && (0 == bpt_given))
        bpt = DEF_BLOCKS_PER_2048TRANSFER;

#ifdef SG_DEBUG
    pr2serr(ME "if=%s skip=%" PRId64 " of=%s seek=%" PRId64 " count=%" PRId64
            "\n", inf, skip, outf, seek, dd_count);
#endif
    install_handler (SIGINT, interrupt_handler);
    install_handler (SIGQUIT, interrupt_handler);
    install_handler (SIGPIPE, interrupt_handler);
    install_handler (SIGUSR1, siginfo_handler);

    infd = STDIN_FILENO;
    outfd = STDOUT_FILENO;
    if (inf[0] && ('-' != inf[0])) {
        in_type = dd_filetype(inf);
        if (verbose)
            pr2serr(" >> Input file type: %s\n",
                    dd_filetype_str(in_type, ebuff));

        if (FT_ERROR == in_type) {
            pr2serr(ME "unable to access %s\n", inf);
            return SG_LIB_FILE_ERROR;
        } else if (FT_ST == in_type) {
            pr2serr(ME "unable to use scsi tape device %s\n", inf);
            return SG_LIB_FILE_ERROR;
        } else if (FT_SG == in_type) {
            flags = O_RDWR | O_NONBLOCK;
            if (in_flags.direct)
                flags |= O_DIRECT;
            if (in_flags.excl)
                flags |= O_EXCL;
            if (in_flags.dsync)
                flags |= O_SYNC;
            if ((infd = open(inf, flags)) < 0) {
                snprintf(ebuff, EBUFF_SZ,
                         ME "could not open %s for sg reading", inf);
                perror(ebuff);
                return SG_LIB_FILE_ERROR;
            }
            res = ioctl(infd, SG_GET_VERSION_NUM, &t);
            if ((res < 0) || (t < 30122)) {
                pr2serr(ME "sg driver prior to 3.1.22\n");
                return SG_LIB_FILE_ERROR;
            }
            in_res_sz = blk_sz * bpt;
            if (0 != (in_res_sz % psz)) /* round up to next page */
                in_res_sz = ((in_res_sz / psz) + 1) * psz;
            if (ioctl(infd, SG_GET_RESERVED_SIZE, &t) < 0) {
                perror(ME "SG_GET_RESERVED_SIZE error");
                return SG_LIB_FILE_ERROR;
            }
            if (t < MIN_RESERVED_SIZE)
                t = MIN_RESERVED_SIZE;
            if (in_res_sz > t) {
                if (ioctl(infd, SG_SET_RESERVED_SIZE, &in_res_sz) < 0) {
                    perror(ME "SG_SET_RESERVED_SIZE error");
                    return SG_LIB_FILE_ERROR;
                }
            }
            wrkMmap = (unsigned char *)mmap(NULL, in_res_sz,
                                            PROT_READ | PROT_WRITE, MAP_SHARED, infd, 0);
            if (MAP_FAILED == wrkMmap) {
                snprintf(ebuff, EBUFF_SZ,
                         ME "error using mmap() on file: %s", inf);
                perror(ebuff);
                return SG_LIB_FILE_ERROR;
            }
        } else {
            flags = O_RDONLY;
            if (in_flags.direct)
                flags |= O_DIRECT;
            if (in_flags.excl)
                flags |= O_EXCL;
            if (in_flags.dsync)
                flags |= O_SYNC;
            if ((infd = open(inf, flags)) < 0) {
                snprintf(ebuff, EBUFF_SZ,
                         ME "could not open %s for reading", inf);
                perror(ebuff);
                return SG_LIB_FILE_ERROR;
            }
            else if (skip > 0) {
                off64_t offset = skip;

                offset *= blk_sz;       /* could exceed 32 bits here! */
                if (lseek64(infd, offset, SEEK_SET) < 0) {
                    snprintf(ebuff, EBUFF_SZ, ME "couldn't skip to "
                             "required position on %s", inf);
                    perror(ebuff);
                    return SG_LIB_FILE_ERROR;
                }
                if (verbose)
                    pr2serr("  >> skip: lseek64 SEEK_SET, byte offset=0x%"
                            PRIx64 "\n", (uint64_t)offset);
            }
        }
    }

    if (outf[0] && ('-' != outf[0])) {
        out_type = dd_filetype(outf);
        if (verbose)
            pr2serr(" >> Output file type: %s\n",
                    dd_filetype_str(out_type, ebuff));

        if (FT_ST == out_type) {
            pr2serr(ME "unable to use scsi tape device %s\n", outf);
            return SG_LIB_FILE_ERROR;
        }
        else if (FT_SG == out_type) {
            flags = O_RDWR | O_NONBLOCK;
            if (out_flags.direct)
                flags |= O_DIRECT;
            if (out_flags.excl)
                flags |= O_EXCL;
            if (out_flags.dsync)
                flags |= O_SYNC;
            if ((outfd = open(outf, flags)) < 0) {
                snprintf(ebuff, EBUFF_SZ, ME "could not open %s for "
                         "sg writing", outf);
                perror(ebuff);
                return SG_LIB_FILE_ERROR;
            }
            res = ioctl(outfd, SG_GET_VERSION_NUM, &t);
            if ((res < 0) || (t < 30122)) {
                pr2serr(ME "sg driver prior to 3.1.22\n");
                return SG_LIB_FILE_ERROR;
            }
            if (ioctl(outfd, SG_GET_RESERVED_SIZE, &t) < 0) {
                perror(ME "SG_GET_RESERVED_SIZE error");
                return SG_LIB_FILE_ERROR;
            }
            if (t < MIN_RESERVED_SIZE)
                t = MIN_RESERVED_SIZE;
            out_res_sz = blk_sz * bpt;
            if (out_res_sz > t) {
                if (ioctl(outfd, SG_SET_RESERVED_SIZE, &out_res_sz) < 0) {
                    perror(ME "SG_SET_RESERVED_SIZE error");
                    return SG_LIB_FILE_ERROR;
                }
            }
            if (NULL == wrkMmap) {
                wrkMmap = (unsigned char *)mmap(NULL, out_res_sz,
                                                PROT_READ | PROT_WRITE, MAP_SHARED, outfd, 0);
                if (MAP_FAILED == wrkMmap) {
                    snprintf(ebuff, EBUFF_SZ,
                             ME "error using mmap() on file: %s", outf);
                    perror(ebuff);
                    return SG_LIB_FILE_ERROR;
                }
            }
        }
        else if (FT_DEV_NULL == out_type)
            outfd = -1; /* don't bother opening */
        else {
            if (FT_RAW != out_type) {
                flags = O_WRONLY | O_CREAT;
                if (out_flags.direct)
                    flags |= O_DIRECT;
                if (out_flags.excl)
                    flags |= O_EXCL;
                if (out_flags.dsync)
                    flags |= O_SYNC;
                if (out_flags.append)
                    flags |= O_APPEND;
                if ((outfd = open(outf, flags, 0666)) < 0) {
                    snprintf(ebuff, EBUFF_SZ,
                             ME "could not open %s for writing", outf);
                    perror(ebuff);
                    return SG_LIB_FILE_ERROR;
                }
            }
            else {
                if ((outfd = open(outf, O_WRONLY)) < 0) {
                    snprintf(ebuff, EBUFF_SZ, ME "could not open %s "
                             "for raw writing", outf);
                    perror(ebuff);
                    return SG_LIB_FILE_ERROR;
                }
            }
            if (seek > 0) {
                off64_t offset = seek;

                offset *= blk_sz;       /* could exceed 32 bits here! */
                if (lseek64(outfd, offset, SEEK_SET) < 0) {
                    snprintf(ebuff, EBUFF_SZ, ME "couldn't seek to "
                             "required position on %s", outf);
                    perror(ebuff);
                    return SG_LIB_FILE_ERROR;
                }
                if (verbose)
                    pr2serr("   >> seek: lseek64 SEEK_SET, byte offset=0x%"
                            PRIx64 "\n", (uint64_t)offset);
            }
        }
    }
    if ((STDIN_FILENO == infd) && (STDOUT_FILENO == outfd)) {
        pr2serr("Won't default both IFILE to stdin _and_ OFILE to as "
                "stdout\n");
        pr2serr("For more information use '--help'\n");
        return SG_LIB_SYNTAX_ERROR;
    }
    if (dd_count < 0) {
        in_num_sect = -1;
        if (FT_SG == in_type) {
            res = scsi_read_capacity(infd, &in_num_sect, &in_sect_sz);
            if (SG_LIB_CAT_UNIT_ATTENTION == res) {
                pr2serr("Unit attention(in), continuing\n");
                res = scsi_read_capacity(infd, &in_num_sect, &in_sect_sz);
            } else if (SG_LIB_CAT_ABORTED_COMMAND == res) {
                pr2serr("Aborted command(in), continuing\n");
                res = scsi_read_capacity(infd, &in_num_sect, &in_sect_sz);
            }
            if (0 != res) {
                sg_get_category_sense_str(res, sizeof(b), b, verbose);
                pr2serr("Read capacity (if=%s): %s\n", inf, b);
                in_num_sect = -1;
            }
        } else if (FT_BLOCK == in_type) {
            if (0 != read_blkdev_capacity(infd, &in_num_sect, &in_sect_sz)) {
                pr2serr("Unable to read block capacity on %s\n", inf);
                in_num_sect = -1;
            }
            if (blk_sz != in_sect_sz) {
                pr2serr("block size on %s confusion; bs=%d, from device=%d\n",
                        inf, blk_sz, in_sect_sz);
                in_num_sect = -1;
            }
        }
        if (in_num_sect > skip)
            in_num_sect -= skip;

        out_num_sect = -1;
        if (FT_SG == out_type) {
            res = scsi_read_capacity(outfd, &out_num_sect, &out_sect_sz);
            if (SG_LIB_CAT_UNIT_ATTENTION == res) {
                pr2serr("Unit attention(out), continuing\n");
                res = scsi_read_capacity(outfd, &out_num_sect, &out_sect_sz);
            } else if (SG_LIB_CAT_ABORTED_COMMAND == res) {
                pr2serr("Aborted command(out), continuing\n");
                res = scsi_read_capacity(outfd, &out_num_sect, &out_sect_sz);
            }
            if (0 != res) {
                sg_get_category_sense_str(res, sizeof(b), b, verbose);
                pr2serr("Read capacity (of=%s): %s\n", inf, b);
                out_num_sect = -1;
            }
        } else if (FT_BLOCK == out_type) {
            if (0 != read_blkdev_capacity(outfd, &out_num_sect,
                                          &out_sect_sz)) {
                pr2serr("Unable to read block capacity on %s\n", outf);
                out_num_sect = -1;
            }
            if (blk_sz != out_sect_sz) {
                pr2serr("block size on %s confusion: bs=%d, from device=%d\n",
                        outf, blk_sz, out_sect_sz);
                out_num_sect = -1;
            }
        }
        if (out_num_sect > seek)
            out_num_sect -= seek;
#ifdef SG_DEBUG
        pr2serr("Start of loop, count=%" PRId64 ", in_num_sect=%" PRId64 ", "
                "out_num_sect=%" PRId64 "\n", dd_count, in_num_sect,
                out_num_sect);
#endif
        if (in_num_sect > 0) {
            if (out_num_sect > 0)
                dd_count = (in_num_sect > out_num_sect) ? out_num_sect :
                           in_num_sect;
            else
                dd_count = in_num_sect;
        }
        else
            dd_count = out_num_sect;
    }

    if (dd_count < 0) {
        pr2serr("Couldn't calculate count, please give one\n");
        return SG_LIB_SYNTAX_ERROR;
    }
    if (! cdbsz_given) {
        if ((FT_SG == in_type) && (MAX_SCSI_CDBSZ != scsi_cdbsz_in) &&
                (((dd_count + skip) > UINT_MAX) || (bpt > USHRT_MAX))) {
            pr2serr("Note: SCSI command size increased to 16 bytes (for "
                    "'if')\n");
            scsi_cdbsz_in = MAX_SCSI_CDBSZ;
        }
        if ((FT_SG == out_type) && (MAX_SCSI_CDBSZ != scsi_cdbsz_out) &&
                (((dd_count + seek) > UINT_MAX) || (bpt > USHRT_MAX))) {
            pr2serr("Note: SCSI command size increased to 16 bytes (for "
                    "'of')\n");
            scsi_cdbsz_out = MAX_SCSI_CDBSZ;
        }
    }

    if (out_flags.dio && (FT_SG != in_type)) {
        out_flags.dio = 0;
        pr2serr(">>> dio only performed on 'of' side when 'if' is an sg "
                "device\n");
    }
    if (out_flags.dio) {
        int fd;
        char c;

        if ((fd = open(proc_allow_dio, O_RDONLY)) >= 0) {
            if (1 == read(fd, &c, 1)) {
                if ('0' == c)
                    pr2serr(">>> %s set to '0' but should be set to '1' for "
                            "direct IO\n", proc_allow_dio);
            }
            close(fd);
        }
    }

    if (wrkMmap) {
        wrkPos = wrkMmap;
    } else {
        if ((FT_RAW == in_type) || (FT_RAW == out_type)) {
            wrkBuff = (unsigned char *)malloc(blk_sz * bpt + psz);
            if (0 == wrkBuff) {
                pr2serr("Not enough user memory for raw\n");
                return SG_LIB_FILE_ERROR;
            }
            /* perhaps use posix_memalign() instead */
            wrkPos = (unsigned char *)(((uintptr_t)wrkBuff + psz - 1) &
                                       (~(psz - 1)));
        }
        else {
            wrkBuff = (unsigned char *)malloc(blk_sz * bpt);
            if (0 == wrkBuff) {
                pr2serr("Not enough user memory\n");
                return SG_LIB_FILE_ERROR;
            }
            wrkPos = wrkBuff;
        }
    }

    blocks_per = bpt;
#ifdef SG_DEBUG
    pr2serr("Start of loop, count=%" PRId64 ", blocks_per=%d\n", dd_count,
            blocks_per);
#endif
    if (do_time) {
        start_tm.tv_sec = 0;
        start_tm.tv_usec = 0;
        gettimeofday(&start_tm, NULL);
        start_tm_valid = 1;
    }
    req_count = dd_count;

    if (verbose && (dd_count > 0) && (0 == out_flags.dio) &&
            (FT_SG == in_type) && (FT_SG == out_type))
        pr2serr("Since both 'if' and 'of' are sg devices, only do mmap-ed "
                "transfers on 'if'\n");

    while (dd_count > 0) {
        blocks = (dd_count > blocks_per) ? blocks_per : dd_count;
        if (FT_SG == in_type) {
            ret = sg_read(infd, wrkPos, blocks, skip, blk_sz, scsi_cdbsz_in,
                          in_flags.fua, in_flags.dpo, 1);
            if ((SG_LIB_CAT_UNIT_ATTENTION == ret) ||
                    (SG_LIB_CAT_ABORTED_COMMAND == ret)) {
                pr2serr("Unit attention or aborted command, continuing "
                        "(r)\n");
                ret = sg_read(infd, wrkPos, blocks, skip, blk_sz,
                              scsi_cdbsz_in, in_flags.fua, in_flags.dpo, 1);
            }
            if (0 != ret) {
                pr2serr("sg_read failed, skip=%" PRId64 "\n", skip);
                break;
            }
            else
                in_full += blocks;
        }
        else {
            while (((res = read(infd, wrkPos, blocks * blk_sz)) < 0) &&
                    ((EINTR == errno) || (EAGAIN == errno)))
                ;
            if (verbose > 2)
                pr2serr("read(unix): count=%d, res=%d\n", blocks * blk_sz,
                        res);
            if (ret < 0) {
                snprintf(ebuff, EBUFF_SZ, ME "reading, skip=%" PRId64 " ",
                         skip);
                perror(ebuff);
                ret = -1;
                break;
            }
            else if (res < blocks * blk_sz) {
                dd_count = 0;
                blocks = res / blk_sz;
                if ((res % blk_sz) > 0) {
                    blocks++;
                    in_partial++;
                }
            }
            in_full += blocks;
        }

        if (0 == blocks)
            break;      /* read nothing so leave loop */

        if (FT_SG == out_type) {
            int do_mmap = (FT_SG == in_type) ? 0 : 1;
            int dio_res = out_flags.dio;

            ret = sg_write(outfd, wrkPos, blocks, seek, blk_sz, scsi_cdbsz_out,
                           out_flags.fua, out_flags.dpo, do_mmap, &dio_res);
            if ((SG_LIB_CAT_UNIT_ATTENTION == ret) ||
                    (SG_LIB_CAT_ABORTED_COMMAND == ret)) {
                pr2serr("Unit attention or aborted command, continuing (w)\n");
                dio_res = out_flags.dio;
                ret = sg_write(outfd, wrkPos, blocks, seek, blk_sz,
                               scsi_cdbsz_out, out_flags.fua, out_flags.dpo,
                               do_mmap, &dio_res);
            }
            if (0 != ret) {
                pr2serr("sg_write failed, seek=%" PRId64 "\n", seek);
                break;
            }
            else {
                out_full += blocks;
                if (out_flags.dio && (0 == dio_res))
                    num_dio_not_done++;
            }
        }
        else if (FT_DEV_NULL == out_type)
            out_full += blocks; /* act as if written out without error */
        else {
            while (((res = write(outfd, wrkPos, blocks * blk_sz)) < 0) &&
                    ((EINTR == errno) || (EAGAIN == errno)))
                ;
            if (verbose > 2)
                pr2serr("write(unix): count=%d, res=%d\n", blocks * blk_sz,
                        res);
            if (res < 0) {
                snprintf(ebuff, EBUFF_SZ, ME "writing, seek=%" PRId64 " ",
                         seek);
                perror(ebuff);
                break;
            }
            else if (res < blocks * blk_sz) {
                pr2serr("output file probably full, seek=%" PRId64 " ", seek);
                blocks = res / blk_sz;
                out_full += blocks;
                if ((res % blk_sz) > 0)
                    out_partial++;
                break;
            }
            else
                out_full += blocks;
        }
        if (dd_count > 0)
            dd_count -= blocks;
        skip += blocks;
        seek += blocks;
    }

    if (do_time)
        calc_duration_throughput(0);
    if (do_sync) {
        if (FT_SG == out_type) {
            pr2serr(">> Synchronizing cache on %s\n", outf);
            res = sg_ll_sync_cache_10(outfd, 0, 0, 0, 0, 0, 0, 0);
            if (SG_LIB_CAT_UNIT_ATTENTION == res) {
                pr2serr("Unit attention(out), continuing\n");
                res = sg_ll_sync_cache_10(outfd, 0, 0, 0, 0, 0, 0, 0);
            }
            if (0 != res) {
                sg_get_category_sense_str(res, sizeof(b), b, verbose);
                pr2serr("Synchronize cache(out): %s\n", b);
            }
        }
    }

    if (wrkBuff) free(wrkBuff);
    if (STDIN_FILENO != infd)
        close(infd);
    if ((STDOUT_FILENO != outfd) && (FT_DEV_NULL != out_type))
        close(outfd);
    if (0 != dd_count) {
        pr2serr("Some error occurred,");
        if (0 == ret)
            ret = SG_LIB_CAT_OTHER;
    }
    print_stats();
    if (sum_of_resids)
        pr2serr(">> Non-zero sum of residual counts=%d\n", sum_of_resids);
    if (num_dio_not_done)
        pr2serr(">> dio requested but _not_ done %d times\n",
                num_dio_not_done);
    return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
}
Example #29
0
int
main(int argc, char * argv[])
{
    bool allow = false;
    bool verbose_given = false;
    bool version_given = false;
    int sg_fd, res, c;
    int prevent = -1;
    int verbose = 0;
    const char * device_name = NULL;
    int ret = 0;

    while (1) {
        int option_index = 0;

        c = getopt_long(argc, argv, "ahp:vV", long_options,
                        &option_index);
        if (c == -1)
            break;

        switch (c) {
        case 'a':
            allow = true;
            break;
        case 'h':
        case '?':
            usage();
            return 0;
        case 'p':
           prevent = sg_get_num(optarg);
           if ((prevent < 0) || (prevent > 3)) {
                pr2serr("bad argument to '--prevent'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'v':
            verbose_given = true;
            ++verbose;
            break;
        case 'V':
            version_given = true;
            break;
        default:
            pr2serr("unrecognised option code 0x%x ??\n", c);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }
    if (optind < argc) {
        if (NULL == device_name) {
            device_name = argv[optind];
            ++optind;
        }
        if (optind < argc) {
            for (; optind < argc; ++optind)
                pr2serr("Unexpected extra argument: %s\n", argv[optind]);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }
#ifdef DEBUG
    pr2serr("In DEBUG mode, ");
    if (verbose_given && version_given) {
        pr2serr("but override: '-vV' given, zero verbose and continue\n");
        verbose_given = false;
        version_given = false;
        verbose = 0;
    } else if (! verbose_given) {
        pr2serr("set '-vv'\n");
        verbose = 2;
    } else
        pr2serr("keep verbose=%d\n", verbose);
#else
    if (verbose_given && version_given)
        pr2serr("Not in DEBUG mode, so '-vV' has no special action\n");
#endif
    if (version_given) {
        pr2serr(ME "version: %s\n", version_str);
        return 0;
    }

    if (NULL == device_name) {
        pr2serr("missing device name!\n");
        usage();
        return SG_LIB_SYNTAX_ERROR;
    }
    if (allow && (prevent >= 0)) {
        pr2serr("can't give both '--allow' and '--prevent='\n");
        usage();
        return SG_LIB_CONTRADICT;
    }
    if (allow)
        prevent = 0;
    else if (prevent < 0)
        prevent = 1;    /* default is to prevent, as utility name suggests */

    sg_fd = sg_cmds_open_device(device_name, false /* rw */, verbose);
    if (sg_fd < 0) {
        if (verbose)
            pr2serr(ME "open error: %s: %s\n", device_name,
                    safe_strerror(-sg_fd));
        ret = sg_convert_errno(-sg_fd);
        goto fini;
    }
    res = sg_ll_prevent_allow(sg_fd, prevent, true, verbose);
    ret = res;
    if (res) {
        char b[80];

        sg_get_category_sense_str(res, sizeof(b), b, verbose);
        pr2serr("Prevent allow medium removal: %s\n", b);
    }
    res = sg_cmds_close_device(sg_fd);
    if (res < 0) {
        pr2serr("close error: %s\n", safe_strerror(-res));
        if (0 == ret)
            ret = sg_convert_errno(-res);
    }
fini:
    if (0 == verbose) {
        if (! sg_if_can2stderr("sg_prevent failed: ", ret))
            pr2serr("Some error occurred, try again with '-v' "
                    "or '-vv' for more information\n");
    }
    return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
}