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; }
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; }
/* 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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }