aboutsummaryrefslogtreecommitdiff
path: root/sg_start.c
diff options
context:
space:
mode:
Diffstat (limited to 'sg_start.c')
-rw-r--r--sg_start.c642
1 files changed, 437 insertions, 205 deletions
diff --git a/sg_start.c b/sg_start.c
index 1c617515..4e08880d 100644
--- a/sg_start.c
+++ b/sg_start.c
@@ -3,46 +3,117 @@
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
+#include <getopt.h>
#include "sg_lib.h"
#include "sg_cmds_basic.h"
/*
- * Copyright (C) 1999-2006 D. Gilbert
+ * Copyright (C) 1999-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)
* any later version.
- Since this code has been used in the past to form the backbone of
- some Linux apps based on the "sg" device driver, it has been
- strengthened.
-
Start/Stop parameter by Kurt Garloff <garloff at suse dot de>, 6/2000
Sync cache parameter by Kurt Garloff <garloff at suse dot de>, 1/2001
Guard block device answering sg's ioctls.
<dgilbert at interlog dot com> 12/2002
Convert to SG_IO ioctl so can use sg or block devices in 2.6.* 3/2003
+
+ This utility was written for the Linux 2.4 kernel series. It should
+ now build for the Linux 2.6 kernel series and various other Operating
+ Systems.
*/
-static char * version_str = "0.51 20061016";
+static char * version_str = "0.55 20070128";
+
+static struct option long_options[] = {
+ {"eject", 0, 0, 'e'},
+ {"fl", 1, 0, 'f'},
+ {"help", 0, 0, 'h'},
+ {"immed", 0, 0, 'i'},
+ {"load", 0, 0, 'l'},
+ {"loej", 0, 0, 'L'},
+ {"new", 0, 0, 'N'},
+ {"old", 0, 0, 'O'},
+ {"pc", 1, 0, 'p'},
+ {"start", 0, 0, 's'},
+ {"stop", 0, 0, 'S'},
+ {"verbose", 0, 0, 'v'},
+ {"version", 0, 0, 'V'},
+ {0, 0, 0, 0},
+};
+struct opts_t {
+ int do_eject;
+ int do_fl;
+ int do_help;
+ int do_immed;
+ int do_load;
+ int do_loej;
+ int do_pc;
+ int do_start;
+ int do_stop;
+ int do_verbose;
+ int do_version;
+ const char * device_name;
+ int opt_new;
+};
+
+void usage()
+{
+ fprintf(stderr, "Usage: sg_start [--eject] [--fl=FL] [--help] "
+ "[--immed] [--load] [--loej]\n"
+ " [--pc=PC] [--start] [--stop] "
+ "[--verbose] [--version]\n"
+ " DEVICE\n"
+ " where:\n"
+ " --eject|-e stop unit then eject the medium\n"
+ " --fl=FL|-f FL format layer number (mmc5)\n"
+ " --help|-h print usage message then exit\n"
+ " --immed|-i device should return control after "
+ "receiving cdb,\n"
+ " default action is to wait until action "
+ "is complete\n"
+ " --load|-l load medium then start the unit\n"
+ " --loej|-L load or eject, corresponds to LOEJ bit "
+ "in cdb;\n"
+ " load when START bit also set, else "
+ "eject\n"
+ " --pc=PC|-p PC power conditions: 0 (default) -> no "
+ "power condition,\n"
+ " 1 -> active, 2 -> idle, 3 -> standby, "
+ "5 -> sleep (MMC)\n"
+ " --start|-s start unit, corresponds to START bit "
+ "in cdb,\n"
+ " default (START=1) if no other options "
+ "given\n"
+ " --stop|-S stop unit (e.g. spin down disk)\n"
+ " --verbose|-v increase verbosity\n"
+ " --version|-V print version string then exit\n\n"
+ " Example: 'sg_start --stop /dev/sdb' stops unit\n"
+ " 'sg_start --eject /dev/scd0' stops unit and "
+ "ejects medium\n\n"
+ "Performs a SCSI START STOP UNIT command\n"
+ );
+}
-void usage ()
+void usage_old()
{
- fprintf(stderr, "Usage: sg_start [0] [1] [--eject] [--fl=<n>] "
+ fprintf(stderr, "Usage: sg_start [0] [1] [--eject] [--fl=FL] "
"[-i] [--imm=0|1]\n"
- " [--load] [--loej] [--pc=<n>] [--start] "
+ " [--load] [--loej] [--pc=PC] [--start] "
"[--stop] [-v] [-V]\n"
- "< device>\n"
+ " DEVICE\n"
" where:\n"
" 0 stop unit (e.g. spin down a disk or a "
"cd/dvd)\n"
" 1 start unit (e.g. spin up a disk or a "
"cd/dvd)\n"
" --eject stop then eject the medium\n"
- " --fl=<n> format layer number (mmc5)\n"
+ " --fl=FL format layer number (mmc5)\n"
" -i return immediately (same as '--imm=1')\n"
" --imm=0|1 0->await completion(def), 1->return "
"immediately\n"
@@ -50,7 +121,7 @@ void usage ()
" --loej load the medium if '-start' option is "
"also given\n"
" or stop unit and eject\n"
- " --pc=<n> power conditions (in hex, default 0 -> no "
+ " --pc=PC power conditions (in hex, default 0 -> no "
"power condition)\n"
" 1 -> active, 2 -> idle, 3 -> standby, "
"5 -> sleep (MMC)\n"
@@ -62,212 +133,373 @@ void usage ()
" Example: 'sg_start --stop /dev/sdb' stops unit\n"
" 'sg_start --eject /dev/scd0' stops unit and "
"ejects medium\n\n"
- "Performs a START STOP UNIT SCSI command\n"
+ "Performs a SCSI START STOP UNIT command\n"
);
- exit (1);
}
-int main(int argc, char * argv[])
+static int process_cl_new(struct opts_t * optsp, int argc, char * argv[])
{
- int startstop = -1;
- const char * file_name = 0;
- const char * cp;
- int k, fd, num, res, plen, jmp_out;
- unsigned int u;
- int ambigu = 0;
- int immed = 0;
- int loej = 0;
- int fl_num = -1;
- int power_conds = 0;
- int verbose = 0;
- int ret = 0;
-
- 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 'i':
- if ('\0' == *(cp + 1))
- immed = 1;
- 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;
- case '-':
- ++cp;
- --plen;
- jmp_out = 1;
- break;
- default:
- jmp_out = 1;
- break;
- }
- if (jmp_out)
- break;
- }
- if (plen <= 0)
- continue;
+ int c, n, err;
- if (0 == strncmp(cp, "eject", 5)) {
- loej = 1;
- if (startstop == 1)
- ambigu = 1;
- else
- startstop = 0;
- } else if (0 == strncmp("fl=", cp, 3)) {
- num = sscanf(cp + 3, "%x", &u);
- if (1 != num) {
- fprintf(stderr, "Bad value after "
- "'fl=' option\n");
- usage();
- return SG_LIB_SYNTAX_ERROR;
- }
- fl_num = u;
- } else if (0 == strncmp("imm=", cp, 4)) {
- num = sscanf(cp + 4, "%x", &u);
- if ((1 != num) || (u > 1)) {
- fprintf(stderr, "Bad value after "
- "'imm=' option\n");
- usage();
- return SG_LIB_SYNTAX_ERROR;
- }
- immed = u;
- } else if (0 == strncmp(cp, "load", 4)) {
- loej = 1;
- if (startstop == 0)
- ambigu = 1;
- else
- startstop = 1;
- } else if (0 == strncmp(cp, "loej", 4))
- loej = 1;
- else if (0 == strncmp("pc=", cp, 3)) {
- num = sscanf(cp + 3, "%x", &u);
- if ((1 != num) || (u > 15)) {
- fprintf(stderr, "Bad value after "
- "after 'pc=' option\n");
- usage();
- return SG_LIB_SYNTAX_ERROR;
- }
- power_conds = u;
- } else if (0 == strncmp(cp, "start", 5)) {
- if (startstop == 0)
- ambigu = 1;
- else
- startstop = 1;
- } else if (0 == strncmp(cp, "stop", 4)) {
- if (startstop == 1)
- ambigu = 1;
- else
- startstop = 0;
- } else if (jmp_out) {
- fprintf(stderr, "Unrecognized option: %s\n",
- cp);
- usage();
- return SG_LIB_SYNTAX_ERROR;
- }
- } else if (0 == strcmp("0", cp)) {
- if (startstop >= 0)
- ambigu = 1;
- else
- startstop = 0;
- } else if (0 == strcmp("1", cp)) {
- if (startstop >= 0)
- ambigu = 1;
- else
- startstop = 1;
- } 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 (ambigu) {
- fprintf(stderr, "please, only one of 0, 1, --eject, "
- "--load, --start or --stop\n");
- usage();
- return SG_LIB_SYNTAX_ERROR;
- }
- }
-
- if (0 == file_name) {
- fprintf(stderr, "No <scsi_device> argument given\n");
+ while (1) {
+ int option_index = 0;
+
+ c = getopt_long(argc, argv, "ef:hilLNOp:sSvV", long_options,
+ &option_index);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'e':
+ ++optsp->do_eject;
+ ++optsp->do_loej;
+ break;
+ case 'f':
+ n = sg_get_num(optarg);
+ if ((n < 0) || (n > 3)) {
+ fprintf(stderr, "bad argument to '--fl='\n");
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ ++optsp->do_loej;
+ ++optsp->do_start;
+ optsp->do_fl = n;
+ break;
+ case 'h':
+ case '?':
+ ++optsp->do_help;
+ break;
+ case 'i':
+ ++optsp->do_immed;
+ break;
+ case 'l':
+ ++optsp->do_load;
+ ++optsp->do_loej;
+ break;
+ case 'L':
+ ++optsp->do_loej;
+ break;
+ case 'N':
+ break; /* ignore */
+ case 'O':
+ optsp->opt_new = 0;
+ return 0;
+ case 'p':
+ n = sg_get_num(optarg);
+ if ((n < 0) || (n > 15)) {
+ fprintf(stderr, "bad argument to '--pc='\n");
usage();
return SG_LIB_SYNTAX_ERROR;
+ }
+ optsp->do_pc = n;
+ break;
+ case 's':
+ ++optsp->do_start;
+ break;
+ case 'S':
+ ++optsp->do_stop;
+ 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;
}
+ }
+ err = 0;
+ for (; optind < argc; ++optind) {
+ if (1 == strlen(argv[optind])) {
+ if (0 == strcmp("0", argv[optind])) {
+ ++optsp->do_stop;
+ continue;
+ } else if (0 == strcmp("1", argv[optind])) {
+ ++optsp->do_start;
+ continue;
+ }
+ }
+ if (NULL == optsp->device_name)
+ optsp->device_name = argv[optind];
+ else {
+ fprintf(stderr, "Unexpected extra argument: %s\n", argv[optind]);
+ ++err;
+ }
+ }
+ if (err) {
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ } else
+ return 0;
+}
- if (fl_num >= 0) {
- if (startstop == 0) {
- fprintf(stderr, "Giving '--fl=<n>' and '--stop' (or "
- "'--eject') is invalid\n");
- usage();
- return SG_LIB_SYNTAX_ERROR;
+static int process_cl_old(struct opts_t * optsp, int argc, char * argv[])
+{
+ int k, jmp_out, plen, num;
+ int ambigu = 0;
+ int startstop = -1;
+ 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 'i':
+ if ('\0' == *(cp + 1))
+ optsp->do_immed = 1;
+ else
+ jmp_out = 1;
+ break;
+ case 'v':
+ ++optsp->do_verbose;
+ break;
+ case 'V':
+ ++optsp->do_version;
+ break;
+ case 'h':
+ case '?':
+ ++optsp->do_help;
+ break;
+ case 'N':
+ optsp->opt_new = 1;
+ return 0;
+ case 'O':
+ break;
+ case '-':
+ ++cp;
+ --plen;
+ jmp_out = 1;
+ break;
+ default:
+ jmp_out = 1;
+ break;
+ }
+ if (jmp_out)
+ break;
+ }
+ if (plen <= 0)
+ continue;
+
+ if (0 == strncmp(cp, "eject", 5)) {
+ optsp->do_loej = 1;
+ if (startstop == 1)
+ ambigu = 1;
+ else
+ startstop = 0;
+ } else if (0 == strncmp("fl=", cp, 3)) {
+ num = sscanf(cp + 3, "%x", &u);
+ if (1 != num) {
+ fprintf(stderr, "Bad value after 'fl=' option\n");
+ usage_old();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ startstop = 1;
+ optsp->do_loej = 1;
+ optsp->do_fl = u;
+ } else if (0 == strncmp("imm=", cp, 4)) {
+ num = sscanf(cp + 4, "%x", &u);
+ if ((1 != num) || (u > 1)) {
+ fprintf(stderr, "Bad value after 'imm=' option\n");
+ usage_old();
+ return SG_LIB_SYNTAX_ERROR;
}
- if (power_conds > 0) {
- fprintf(stderr, "Giving '--fl=<n>' and '--pc=<n>' "
- "when <n> is non-zero is invalid\n");
- usage();
- return SG_LIB_SYNTAX_ERROR;
+ optsp->do_immed = u;
+ } else if (0 == strncmp(cp, "load", 4)) {
+ optsp->do_loej = 1;
+ if (startstop == 0)
+ ambigu = 1;
+ else
+ startstop = 1;
+ } else if (0 == strncmp(cp, "loej", 4))
+ optsp->do_loej = 1;
+ else if (0 == strncmp("pc=", cp, 3)) {
+ num = sscanf(cp + 3, "%x", &u);
+ if ((1 != num) || (u > 15)) {
+ fprintf(stderr, "Bad value after after 'pc=' option\n");
+ usage_old();
+ return SG_LIB_SYNTAX_ERROR;
}
- } else {
- if ((startstop == -1) && loej)
- startstop = 0;
- if ((startstop == -1) && (0 == power_conds))
- startstop = 1;
+ optsp->do_pc = u;
+ } else if (0 == strncmp(cp, "start", 5)) {
+ if (startstop == 0)
+ ambigu = 1;
+ else
+ startstop = 1;
+ } else if (0 == strncmp(cp, "stop", 4)) {
+ if (startstop == 1)
+ ambigu = 1;
+ else
+ startstop = 0;
+ } else if (0 == strncmp(cp, "old", 3))
+ ;
+ else if (jmp_out) {
+ fprintf(stderr, "Unrecognized option: %s\n", cp);
+ usage_old();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ } else if (0 == strcmp("0", cp)) {
+ if (1 == startstop)
+ ambigu = 1;
+ else
+ startstop = 0;
+ } else if (0 == strcmp("1", cp)) {
+ if (0 == startstop)
+ ambigu = 1;
+ else
+ startstop = 1;
+ } 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;
}
-
- fd = sg_cmds_open_device(file_name, 0 /* rw */, verbose);
- if (fd < 0) {
- fprintf(stderr, "Error trying to open %s: %s\n",
- file_name, safe_strerror(-fd));
- return SG_LIB_FILE_ERROR;
+ if (ambigu) {
+ fprintf(stderr, "please, only one of 0, 1, --eject, "
+ "--load, --start or --stop\n");
+ usage_old();
+ return SG_LIB_SYNTAX_ERROR;
+ } else if (0 == startstop)
+ ++optsp->do_stop;
+ else if (1 == startstop)
+ ++optsp->do_start;
+ }
+ 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;
+}
+
+
+int main(int argc, char * argv[])
+{
+ int fd, res;
+ int ret = 0;
+ struct opts_t opts;
+
+ memset(&opts, 0, sizeof(opts));
+ opts.do_fl = -1; /* only when >= 0 set FL bit */
+ 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 (opts.do_start && opts.do_stop) {
+ fprintf(stderr, "Ambiguous to give both '--start' and '--stop'\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ if (opts.do_load && opts.do_eject) {
+ fprintf(stderr, "Ambiguous to give both '--load' and '--eject'\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ if (opts.do_load)
+ opts.do_start = 1;
+ else if ((opts.do_eject) || (opts.do_stop))
+ opts.do_start = 0;
+ else if (opts.opt_new && opts.do_loej && (0 == opts.do_start))
+ opts.do_start = 1; /* --loej alone in new interface is load */
+ else if ((0 == opts.do_loej) && (-1 == opts.do_fl) && (0 == opts.do_pc))
+ opts.do_start = 1;
+ /* default action is to start when no other active options */
+
+ if (0 == 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_fl >= 0) {
+ if (opts.do_start == 0) {
+ fprintf(stderr, "Giving '--fl=FL' with '--stop' (or "
+ "'--eject') is invalid\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ if (opts.do_pc > 0) {
+ fprintf(stderr, "Giving '--fl=FL' with '--pc=PC' "
+ "when PC is non-zero is invalid\n");
+ return SG_LIB_SYNTAX_ERROR;
}
+ }
+
+ fd = sg_cmds_open_device(opts.device_name, 0 /* rw */, opts.do_verbose);
+ if (fd < 0) {
+ fprintf(stderr, "Error trying to open %s: %s\n",
+ opts.device_name, safe_strerror(-fd));
+ return SG_LIB_FILE_ERROR;
+ }
- res = 0;
- if (fl_num >= 0)
- res = sg_ll_start_stop_unit(fd, immed, fl_num, power_conds,
- 1 /* fl */, 1 /* loej */,
- 1 /*start */, 1 /* noisy */,
- verbose);
- else if (power_conds > 0)
- res = sg_ll_start_stop_unit(fd, immed, 0, power_conds, 0, 0,
- 0, 1, verbose);
- else if (startstop != -1)
- res = sg_ll_start_stop_unit(fd, immed, 0, 0, 0, loej,
- startstop, 1, verbose);
- ret = res;
- if (res) {
- if (verbose < 2) {
- if (SG_LIB_CAT_INVALID_OP == res)
- fprintf(stderr, "command not supported\n");
- 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_ILLEGAL_REQ == res)
- fprintf(stderr, "invalid field in cdb\n");
- }
- fprintf(stderr, "START STOP UNIT command failed\n");
+ res = 0;
+ if (opts.do_fl >= 0)
+ res = sg_ll_start_stop_unit(fd, opts.do_immed, opts.do_fl, 0 /* pc */,
+ 1 /* fl */, 1 /* loej */,
+ 1 /*start */, 1 /* noisy */,
+ opts.do_verbose);
+ else if (opts.do_pc > 0)
+ res = sg_ll_start_stop_unit(fd, opts.do_immed, 0, opts.do_pc, 0, 0,
+ 0, 1, opts.do_verbose);
+ else
+ res = sg_ll_start_stop_unit(fd, opts.do_immed, 0, 0, 0, opts.do_loej,
+ opts.do_start, 1, opts.do_verbose);
+ ret = res;
+ if (res) {
+ if (opts.do_verbose < 2) {
+ if (SG_LIB_CAT_INVALID_OP == res)
+ fprintf(stderr, "command not supported\n");
+ 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_ILLEGAL_REQ == res)
+ fprintf(stderr, "invalid field in cdb\n");
}
- res = sg_cmds_close_device(fd);
- if ((res < 0) && (0 == ret))
- return SG_LIB_FILE_ERROR;
- return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
+ fprintf(stderr, "START STOP UNIT command failed\n");
+ }
+ res = sg_cmds_close_device(fd);
+ if ((res < 0) && (0 == ret))
+ return SG_LIB_FILE_ERROR;
+ return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
}