int main(int argc, char *argv[]) { int k; int ret = 0; unsigned int ui; size_t s; struct opts_t opts; struct opts_t * op; char b[2048]; FILE * fp = NULL; const char * cp; op = &opts; memset(op, 0, sizeof(opts)); memset(b, 0, sizeof(b)); ret = process_cl(op, argc, argv); if (ret != 0) { usage(); return ret; } else if (op->do_help) { usage(); return 0; } else if (op->do_version) { pr2serr("version: %s\n", version_str); return 0; } if (op->do_status) { sg_get_scsi_status_str(op->sstatus, sizeof(b) - 1, b); printf("SCSI status: %s\n", b); } if ((0 == op->sense_len) && op->no_space_str) { if (op->do_verbose > 2) pr2serr("no_space str: %s\n", op->no_space_str); cp = op->no_space_str; for (k = 0; isxdigit(cp[k]) && isxdigit(cp[k + 1]); k += 2) { if (1 != sscanf(cp + k, "%2x", &ui)) { pr2serr("bad no_space hex string: %s\n", cp); return SG_LIB_SYNTAX_ERROR; } op->sense[op->sense_len++] = (unsigned char)ui; } } if ((0 == op->sense_len) && (! op->do_binary) && (! op->do_file)) { if (op->do_status) return 0; pr2serr(">> Need sense data on the command line or in a file\n\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (op->sense_len && (op->do_binary || op->do_file)) { pr2serr(">> Need sense data on command line or in a file, not " "both\n\n"); return SG_LIB_SYNTAX_ERROR; } if (op->do_binary && op->do_file) { pr2serr(">> Either a binary file or a ASCII hexadecimal, file not " "both\n\n"); return SG_LIB_SYNTAX_ERROR; } if (op->do_binary) { fp = fopen(op->fname, "r"); if (NULL == fp) { pr2serr("unable to open file: %s\n", op->fname); return SG_LIB_SYNTAX_ERROR; } s = fread(op->sense, 1, MAX_SENSE_LEN, fp); fclose(fp); if (0 == s) { pr2serr("read nothing from file: %s\n", op->fname); return SG_LIB_SYNTAX_ERROR; } op->sense_len = s; } else if (op->do_file) { ret = f2hex_arr(op->fname, op->no_space, op->sense, &op->sense_len, MAX_SENSE_LEN); if (ret) { pr2serr("unable to decode ASCII hex from file: %s\n", op->fname); return SG_LIB_SYNTAX_ERROR; } } if (op->sense_len) { if (op->wfname) { if ((fp = fopen(op->wfname, "w"))) { write2wfn(fp, op); fclose(fp); } else { perror("open"); pr2serr("trying to write to %s\n", op->wfname); } } if (op->do_cdb) { int sa, opcode; opcode = op->sense[0]; if ((0x75 == opcode) || (0x7e == opcode) || (op->sense_len > 16)) sa = sg_get_unaligned_be16(op->sense + 8); else if (op->sense_len > 1) sa = op->sense[1] & 0x1f; else sa = 0; sg_get_opcode_sa_name(opcode, sa, 0, sizeof(b), b); } else sg_get_sense_str(NULL, op->sense, op->sense_len, op->do_verbose, sizeof(b) - 1, b); printf("%s\n", b); } return 0; }
static int process_cl(struct opts_t * op, int argc, char *argv[]) { while (1) { int c, n; c = getopt_long(argc, argv, "bhi:k:no:r:Rs:t:vV", long_options, NULL); if (c == -1) break; switch (c) { case 'b': op->datain_binary = 1; break; case 'h': case '?': op->do_help = 1; return 0; case 'i': if (op->dataout_file) { fprintf(stderr, "Too many '--infile=' options\n"); return SG_LIB_SYNTAX_ERROR; } op->dataout_file = optarg; break; case 'k': n = sg_get_num(optarg); if (n < 0) { fprintf(stderr, "Invalid argument to '--skip'\n"); return SG_LIB_SYNTAX_ERROR; } op->dataout_offset = n; break; case 'n': op->no_sense = 1; break; case 'o': if (op->datain_file) { fprintf(stderr, "Too many '--outfile=' options\n"); return SG_LIB_SYNTAX_ERROR; } op->datain_file = optarg; break; case 'r': op->do_datain = 1; n = sg_get_num(optarg); if (n < 0 || n > MAX_SCSI_DXLEN) { fprintf(stderr, "Invalid argument to '--request'\n"); return SG_LIB_SYNTAX_ERROR; } op->datain_len = n; break; case 'R': ++op->readonly; break; case 's': op->do_dataout = 1; n = sg_get_num(optarg); if (n < 0 || n > MAX_SCSI_DXLEN) { fprintf(stderr, "Invalid argument to '--send'\n"); return SG_LIB_SYNTAX_ERROR; } op->dataout_len = n; break; case 't': n = sg_get_num(optarg); if (n < 0) { fprintf(stderr, "Invalid argument to '--timeout'\n"); return SG_LIB_SYNTAX_ERROR; } op->timeout = n; break; case 'v': ++op->do_verbose; break; case 'V': op->do_version = 1; return 0; default: return SG_LIB_SYNTAX_ERROR; } } if (optind >= argc) { fprintf(stderr, "No device specified\n"); return SG_LIB_SYNTAX_ERROR; } op->device_name = argv[optind]; ++optind; while (optind < argc) { char *opt = argv[optind++]; char *endptr; int cmd = strtol(opt, &endptr, 16); if (*opt == '\0' || *endptr != '\0' || cmd < 0x00 || cmd > 0xff) { fprintf(stderr, "Invalid command byte '%s'\n", opt); return SG_LIB_SYNTAX_ERROR; } if (op->cdb_length > MAX_SCSI_CDBSZ) { fprintf(stderr, "CDB too long (max. %d bytes)\n", MAX_SCSI_CDBSZ); return SG_LIB_SYNTAX_ERROR; } op->cdb[op->cdb_length] = cmd; ++op->cdb_length; } if (op->cdb_length < MIN_SCSI_CDBSZ) { fprintf(stderr, "CDB too short (min. %d bytes)\n", MIN_SCSI_CDBSZ); return SG_LIB_SYNTAX_ERROR; } if (op->do_verbose > 2) { int sa; char b[80]; if (op->cdb_length > 16) { sa = (op->cdb[8] << 8) + op->cdb[9]; if (0x7f != op->cdb[0]) printf(">>> Unlikely to be SCSI CDB since all over 16 " "bytes long should\n>>> start with 0x7f\n"); } else sa = op->cdb[1] & 0x1f; sg_get_opcode_sa_name(op->cdb[0], sa, 0, sizeof(b), b); printf("Attempt to decode cdb name: %s\n", b); } return 0; }