aboutsummaryrefslogtreecommitdiff
path: root/sg_senddiag.c
diff options
context:
space:
mode:
Diffstat (limited to 'sg_senddiag.c')
-rw-r--r--sg_senddiag.c589
1 files changed, 418 insertions, 171 deletions
diff --git a/sg_senddiag.c b/sg_senddiag.c
index 6c596167..1b354219 100644
--- a/sg_senddiag.c
+++ b/sg_senddiag.c
@@ -4,13 +4,14 @@
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
+#include <getopt.h>
#include "sg_lib.h"
#include "sg_cmds_basic.h"
#include "sg_cmds_extra.h"
/* A utility program for the Linux OS SCSI generic ("sg") device driver.
-* Copyright (C) 2003-2006 D. Gilbert
+* Copyright (C) 2003-2007 D. Gilbert
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
@@ -20,12 +21,324 @@
the SCSI RECEIVE DIAGNOSTIC command to list supported diagnostic pages.
*/
-static char * version_str = "0.31 20061012";
+static char * version_str = "0.34 20070127";
#define ME "sg_senddiag: "
#define MX_ALLOC_LEN (1024 * 4)
+static struct option long_options[] = {
+ {"doff", 0, 0, 'd'},
+ {"extdur", 0, 0, 'e'},
+ {"help", 0, 0, 'h'},
+ {"hex", 0, 0, 'H'},
+ {"list", 0, 0, 'l'},
+ {"new", 0, 0, 'N'},
+ {"old", 0, 0, 'O'},
+ {"pf", 0, 0, 'p'},
+ {"raw", 1, 0, 'r'},
+ {"selftest", 1, 0, 's'},
+ {"test", 0, 0, 't'},
+ {"uoff", 0, 0, 'u'},
+ {"verbose", 0, 0, 'v'},
+ {"version", 0, 0, 'V'},
+ {0, 0, 0, 0},
+};
+
+struct opts_t {
+ int do_doff;
+ int do_extdur;
+ int do_help;
+ int do_hex;
+ int do_list;
+ int do_pf;
+ int do_raw;
+ int do_selftest;
+ int do_deftest;
+ int do_uoff;
+ int do_verbose;
+ int do_version;
+ const char * device_name;
+ const char * raw_arg;
+ int opt_new;
+};
+
+static void usage()
+{
+ printf("Usage: sg_senddiag [--doff] [--extdur] [--help] [--hex] "
+ "[--list] [--pf]\n"
+ " [--raw=H,H...] [--selftest=ST] "
+ "[--test] [--uoff]\n"
+ " [--verbose] [--version] "
+ "[DEVICE]\n"
+ " where:\n"
+ " --doff|-d device online (def: 0, only with '--test')\n"
+ " --extdur|-e duration of an extended self-test (from mode "
+ "page 0xa)\n"
+ " --help|-h print usage message then exit\n"
+ " --hex|H output in hex\n"
+ " --list|-l list supported page codes (with or without "
+ "DEVICE)\n"
+ " --pf|-p set PF bit (def: 0)\n"
+ " --raw=H,H...|-r H,H... sequence of hex bytes to form "
+ "diag page to send\n"
+ " --raw=-|-r - read stdin for sequence of bytes to send\n"
+ " --selftest=ST|-s ST self-test code, default: 0 "
+ "(inactive)\n"
+ " 1->background short, 2->background "
+ "extended\n"
+ " 4->abort test\n"
+ " 5->foreground short, 6->foreground "
+ "extended\n"
+ " --test|-t default self-test\n"
+ " --uoff|-u unit offline (def: 0, only with '--test')\n"
+ " --verbose|-v increase verbosity\n"
+ " --version|-V output version string then exit\n\n"
+ "Performs a SCSI SEND DIAGNOSTIC (and/or a RECEIVE DIAGNOSTIC "
+ "RESULTS) command\n"
+ );
+}
+
+static void usage_old()
+{
+ printf("Usage: sg_senddiag [-doff] [-e] [-h] [-H] [-l] [-pf]"
+ " [-raw=H,H...]\n"
+ " [-s=SF] [-t] [-uoff] [-v] [-V] "
+ "[DEVICE]\n"
+ " where:\n"
+ " -doff device online (def: 0, only with '-t')\n"
+ " -e duration of an extended self-test (from mode page "
+ "0xa)\n"
+ " -h output in hex\n"
+ " -H output in hex (same as '-h')\n"
+ " -l list supported page codes\n"
+ " -pf set PF bit (def: 0)\n"
+ " -raw=H,H... sequence of bytes to form diag page to "
+ "send\n"
+ " -raw=- read stdin for sequence of bytes to send\n"
+ " -s=SF self-test code (def: 0)\n"
+ " 1->background short, 2->background extended,"
+ " 4->abort test\n"
+ " 5->foreground short, 6->foreground extended\n"
+ " -t default self-test\n"
+ " -uoff unit offline (def: 0, only with '-t')\n"
+ " -v increase verbosity (print issued SCSI cmds)\n"
+ " -V output version string\n"
+ " -? output this usage message\n\n"
+ "Performs a SCSI SEND DIAGNOSTIC (and/or a RECEIVE DIAGNOSTIC "
+ "RESULTS) command\n"
+ );
+}
+
+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 switch 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;
+}
+
+static int process_cl_old(struct opts_t * optsp, int argc, char * argv[])
+{
+ int k, jmp_out, plen, num;
+ unsigned int u;
+ 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 'd':
+ if (0 == strncmp("doff", cp, 4)) {
+ optsp->do_doff = 1;
+ cp += 3;
+ plen -= 3;
+ } else
+ jmp_out = 1;
+ break;
+ case 'e':
+ optsp->do_extdur = 1;
+ break;
+ case 'h':
+ case 'H':
+ ++optsp->do_hex;
+ break;
+ case 'l':
+ ++optsp->do_list;
+ break;
+ case 'N':
+ optsp->opt_new = 1;
+ return 0;
+ case 'O':
+ break;
+ case 'p':
+ if (0 == strncmp("pf", cp, 2)) {
+ optsp->do_pf = 1;
+ ++cp;
+ --plen;
+ } else
+ jmp_out = 1;
+ break;
+ case 't':
+ optsp->do_deftest = 1;
+ break;
+ case 'u':
+ if (0 == strncmp("uoff", cp, 4)) {
+ optsp->do_uoff = 1;
+ cp += 3;
+ plen -= 3;
+ } else
+ jmp_out = 1;
+ break;
+ case 'v':
+ ++optsp->do_verbose;
+ break;
+ case 'V':
+ ++optsp->do_version;
+ break;
+ case '?':
+ ++optsp->do_help;
+ break;
+ default:
+ jmp_out = 1;
+ break;
+ }
+ if (jmp_out)
+ break;
+ }
+ if (plen <= 0)
+ continue;
+ if (0 == strncmp("raw=", cp, 4)) {
+ optsp->raw_arg = cp + 4;
+ optsp->do_raw = 1;
+ } else if (0 == strncmp("s=", cp, 2)) {
+ num = sscanf(cp + 2, "%x", &u);
+ if ((1 != num) || (u > 7)) {
+ printf("Bad page code after '-s=' option\n");
+ usage_old();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ optsp->do_selftest = u;
+ } else if (0 == strncmp("-old", cp, 5))
+ ;
+ 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;
+}
+
+static int process_cl(struct opts_t * optsp, int argc, char * argv[])
+{
+ int res;
+ char * cp;
+
+ cp = getenv("SG3_UTILS_OLD_OPTS");
+ if (cp) {
+ optsp->opt_new = 0;
+ res = process_cl_old(optsp, argc, argv);
+ if ((0 == res) && optsp->opt_new)
+ res = process_cl_new(optsp, argc, argv);
+ } else {
+ optsp->opt_new = 1;
+ res = process_cl_new(optsp, argc, argv);
+ if ((0 == res) && (0 == optsp->opt_new))
+ res = process_cl_old(optsp, argc, argv);
+ }
+ return res;
+}
/* Return of 0 -> success, otherwise see sg_ll_send_diag() */
static int do_senddiag(int sg_fd, int sf_code, int pf_bit, int sf_bit,
@@ -35,7 +348,7 @@ static int do_senddiag(int sg_fd, int sf_code, int pf_bit, int sf_bit,
int long_duration = 0;
if ((0 == sf_bit) && ((5 == sf_code) || (6 == sf_code)))
- long_duration = 1; /* foreground self tests */
+ long_duration = 1; /* foreground self-tests */
return sg_ll_send_diag(sg_fd, sf_code, pf_bit, sf_bit, devofl_bit,
unitofl_bit, long_duration, outgoing_pg,
outgoing_len, noisy, verbose);
@@ -240,192 +553,120 @@ static void list_page_codes()
(pcdp->desc ? pcdp->desc : "<unknown>"));
}
-static void usage()
-{
- printf("Usage: sg_senddiag [-doff] [-e] [-h] [-H] [-l] [-pf]"
- " [-raw=<h>,<h>...]\n"
- " [-s=<self_test_code>] [-t] [-uoff] [-v] "
- "[-V]\n"
- " [<scsi_device>]\n"
- " where:\n"
- " -doff device online (def: 0, only with '-t')\n"
- " -e duration of an extended test (from mode page 0xa)\n"
- " -h output in hex\n"
- " -H output in hex (same as '-h')\n"
- " -l list supported page codes\n"
- " -pf set PF bit (def: 0)\n"
- " -raw=<h>,<h>... sequence of bytes to form diag page to "
- "send\n"
- " -raw=- read stdin for sequence of bytes to send\n"
- " -s=<self_test_code> (def: 0)\n"
- " 1->background short, 2->background extended,"
- " 4->abort test\n"
- " 5->foreground short, 6->foreground extended\n"
- " -t default self test\n"
- " -uoff unit online (def: 0, only with '-t')\n"
- " -v increase verbosity (print issued SCSI cmds)\n"
- " -V output version string\n"
- " -? output this usage message\n\n"
- "Performs a SEND DIAGNOSTIC (and/or a RECEIVE DIAGNOSTIC RESULTS)"
- " SCSI command\n"
- );
-}
-
int main(int argc, char * argv[])
{
- int sg_fd, k, num, rsp_len, plen, jmp_out, res;
- const char * file_name = 0;
+ int sg_fd, k, num, rsp_len, res;
unsigned char rsp_buff[MX_ALLOC_LEN];
int rsp_buff_size = MX_ALLOC_LEN;
- unsigned int u;
- int self_test_code = 0;
- int do_pf = 0;
- int do_doff = 0;
- int do_hex = 0;
- int do_list = 0;
- int do_def_test = 0;
- int do_uoff = 0;
- int do_ext_time = 0;
- int do_raw = 0;
- int verbose = 0;
int read_in_len = 0;
const char * cp;
unsigned char read_in[MX_ALLOC_LEN];
int ret = 0;
+ struct opts_t opts;
- 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 'd':
- if (0 == strncmp("doff", cp, 4)) {
- do_doff = 1;
- cp += 3;
- plen -= 3;
- } else
- jmp_out = 1;
- break;
- case 'e':
- do_ext_time = 1;
- break;
- case 'h':
- case 'H':
- do_hex = 1;
- break;
- case 'l':
- do_list = 1;
- break;
- case 'p':
- if (0 == strncmp("pf", cp, 2)) {
- do_pf = 1;
- ++cp;
- --plen;
- } else
- jmp_out = 1;
- break;
- case 't':
- do_def_test = 1;
- break;
- case 'u':
- if (0 == strncmp("uoff", cp, 4)) {
- do_uoff = 1;
- cp += 3;
- plen -= 3;
- } else
- jmp_out = 1;
- break;
- case 'v':
- ++verbose;
- break;
- case 'V':
- fprintf(stderr, "Version string: %s\n", version_str);
- exit(0);
- case '?':
- usage();
- return 0;
- default:
- jmp_out = 1;
- break;
- }
- if (jmp_out)
- break;
- }
- if (plen <= 0)
- continue;
- if (0 == strncmp("raw=", cp, 4)) {
- if (build_diag_page(cp + 4, read_in, &read_in_len,
- sizeof(read_in))) {
- printf("Bad sequence after 'raw=' option\n");
- usage();
- return SG_LIB_SYNTAX_ERROR;
- }
- do_raw = 1;
- } else if (0 == strncmp("s=", cp, 2)) {
- num = sscanf(cp + 2, "%x", &u);
- if ((1 != num) || (u > 7)) {
- printf("Bad page code after 's=' option\n");
- usage();
- return SG_LIB_SYNTAX_ERROR;
- }
- self_test_code = u;
- } else if (jmp_out) {
- fprintf(stderr, "Unrecognized option: %s\n", cp);
+ memset(&opts, 0, sizeof(opts));
+ res = process_cl(&opts, argc, argv);
+ if (res)
+ return SG_LIB_SYNTAX_ERROR;
+ if (opts.do_help) {
+ if (opts.opt_new)
+ usage();
+ else
+ usage_old();
+ return 0;
+ }
+ if (opts.do_version) {
+ fprintf(stderr, "Version string: %s\n", version_str);
+ return 0;
+ }
+
+ if (NULL == opts.device_name) {
+ fprintf(stderr, "No DEVICE argument given\n");
+ if (opts.opt_new)
+ usage();
+ else
+ usage_old();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ if (opts.do_raw) {
+ if (build_diag_page(opts.raw_arg, read_in, &read_in_len,
+ sizeof(read_in))) {
+ if (opts.opt_new) {
+ printf("Bad sequence after '--raw=' option\n");
usage();
- return SG_LIB_SYNTAX_ERROR;
+ } else {
+ printf("Bad sequence after '-raw=' option\n");
+ usage_old();
}
- } else if (0 == file_name)
- file_name = cp;
- else {
- fprintf(stderr, "too many arguments, got: %s, not expecting: "
- "%s\n", file_name, cp);
- usage();
return SG_LIB_SYNTAX_ERROR;
}
}
- if ((do_doff || do_uoff) && (! do_def_test)) {
- printf("setting -doff or -uoff only useful when -t is set\n");
- usage();
+ if ((opts.do_doff || opts.do_uoff) && (! opts.do_deftest)) {
+ if (opts.opt_new) {
+ printf("setting --doff or --uoff only useful when -t is set\n");
+ usage();
+ } else {
+ printf("setting -doff or -uoff only useful when -t is set\n");
+ usage_old();
+ }
return SG_LIB_SYNTAX_ERROR;
}
- if ((self_test_code > 0) && do_def_test) {
- printf("either set -s=<num> or -t (not both)\n");
- usage();
+ if ((opts.do_selftest > 0) && opts.do_deftest) {
+ if (opts.opt_new) {
+ printf("either set --selftest=SF or --test (not both)\n");
+ usage();
+ } else {
+ printf("either set -s=SF or -t (not both)\n");
+ usage_old();
+ }
return SG_LIB_SYNTAX_ERROR;
}
- if (do_raw) {
- if ((self_test_code > 0) || do_def_test || do_ext_time || do_list) {
- printf("'--raw=' cannot be used with self tests, '-e' or "
- "'-l'\n");
- usage();
+ if (opts.do_raw) {
+ if ((opts.do_selftest > 0) || opts.do_deftest || opts.do_extdur ||
+ opts.do_list) {
+ if (opts.opt_new) {
+ printf("'--raw=' cannot be used with self-tests, '-e' or "
+ "'-l'\n");
+ usage();
+ } else {
+ printf("'-raw=' cannot be used with self-tests, '-e' or "
+ "'-l'\n");
+ usage_old();
+ }
return SG_LIB_SYNTAX_ERROR;
}
- if (! do_pf)
- printf(">>> warning, '-pf' probably should be used with "
- "'--raw='\n");
+ if (! opts.do_pf) {
+ if (opts.opt_new)
+ printf(">>> warning, '--pf' probably should be used with "
+ "'--raw='\n");
+ else
+ printf(">>> warning, '-pf' probably should be used with "
+ "'-raw='\n");
+ }
}
- if (0 == file_name) {
- if (do_list) {
+ if (NULL == opts.device_name) {
+ if (opts.do_list) {
list_page_codes();
return 0;
}
- fprintf(stderr, "No <scsi_device> argument given\n");
- usage();
+ fprintf(stderr, "No DEVICE argument given\n");
+ if (opts.opt_new)
+ usage();
+ else
+ usage_old();
return SG_LIB_SYNTAX_ERROR;
}
- if ((sg_fd = sg_cmds_open_device(file_name, 0 /* rw */, verbose)) < 0) {
- fprintf(stderr, ME "error opening file: %s: %s\n", file_name,
+ if ((sg_fd = sg_cmds_open_device(opts.device_name, 0 /* rw */,
+ opts.do_verbose)) < 0) {
+ fprintf(stderr, ME "error opening file: %s: %s\n", opts.device_name,
safe_strerror(-sg_fd));
return SG_LIB_FILE_ERROR;
}
- if (do_ext_time) {
- res = do_modes_0a(sg_fd, rsp_buff, 32, 1, 0, verbose);
+ if (opts.do_extdur) {
+ res = do_modes_0a(sg_fd, rsp_buff, 32, 1, 0, opts.do_verbose);
if (0 == res) {
/* Assume mode sense(10) response without block descriptors */
num = (rsp_buff[0] << 8) + rsp_buff[1] - 6;
@@ -433,8 +674,13 @@ int main(int argc, char * argv[])
int secs;
secs = (rsp_buff[18] << 8) + rsp_buff[19];
+#ifdef SG3_UTILS_MINGW
+ printf("Expected extended self-test duration=%d seconds "
+ "(%g minutes)\n", secs, secs / 60.0);
+#else
printf("Expected extended self-test duration=%d seconds "
"(%.2f minutes)\n", secs, secs / 60.0);
+#endif
} else
printf("Extended self-test duration not available\n");
} else {
@@ -442,16 +688,16 @@ int main(int argc, char * argv[])
printf("Extended self-test duration (mode page 0xa) failed\n");
goto err_out9;
}
- } else if (do_list) {
+ } else if (opts.do_list) {
memset(rsp_buff, 0, sizeof(rsp_buff));
res = do_senddiag(sg_fd, 0, 1 /* pf */, 0, 0, 0, rsp_buff, 4, 1,
- verbose);
+ opts.do_verbose);
if (0 == res) {
if (0 == sg_ll_receive_diag(sg_fd, 0, 0, rsp_buff,
- rsp_buff_size, 1, verbose)) {
+ rsp_buff_size, 1, opts.do_verbose)) {
printf("Supported diagnostic pages response:\n");
rsp_len = (rsp_buff[2] << 8) + rsp_buff[3] + 4;
- if (do_hex)
+ if (opts.do_hex)
dStrHex((const char *)rsp_buff, rsp_len, 1);
else {
for (k = 0; k < (rsp_len - 4); ++k) {
@@ -470,21 +716,22 @@ int main(int argc, char * argv[])
ret = res;
goto err_out;
}
- } else if (do_raw) {
- res = do_senddiag(sg_fd, 0, do_pf, 0, 0, 0, read_in, read_in_len, 1,
- verbose);
+ } else if (opts.do_raw) {
+ res = do_senddiag(sg_fd, 0, opts.do_pf, 0, 0, 0, read_in,
+ read_in_len, 1, opts.do_verbose);
if (res) {
ret = res;
goto err_out;
}
} else {
- res = do_senddiag(sg_fd, self_test_code, do_pf, do_def_test,
- do_doff, do_uoff, NULL, 0, 1, verbose);
+ res = do_senddiag(sg_fd, opts.do_selftest, opts.do_pf,
+ opts.do_deftest, opts.do_doff, opts.do_uoff, NULL,
+ 0, 1, opts.do_verbose);
if (0 == res) {
- if ((5 == self_test_code) || (6 == self_test_code))
- printf("Foreground self test returned GOOD status\n");
- else if (do_def_test && (! do_doff) && (! do_uoff))
- printf("Default self test returned GOOD status\n");
+ if ((5 == opts.do_selftest) || (6 == opts.do_selftest))
+ printf("Foreground self-test returned GOOD status\n");
+ else if (opts.do_deftest && (! opts.do_doff) && (! opts.do_uoff))
+ printf("Default self-test returned GOOD status\n");
} else {
ret = res;
goto err_out;
@@ -506,7 +753,7 @@ err_out:
else
fprintf(stderr, "SEND DIAGNOSTIC command, failed\n");
err_out9:
- if (verbose < 2)
+ if (opts.do_verbose < 2)
fprintf(stderr, " try again with '-vv' for more information\n");
res = sg_cmds_close_device(sg_fd);
if ((res < 0) && (0 == ret))