xref: /aosp_15_r20/external/sg3_utils/src/sg_start.c (revision 44704f698541f6367e81f991ef8bb54ccbf3fc18)
1*44704f69SBart Van Assche /*
2*44704f69SBart Van Assche  *  Copyright (C) 1999-2020 D. Gilbert
3*44704f69SBart Van Assche  *  This program is free software; you can redistribute it and/or modify
4*44704f69SBart Van Assche  *  it under the terms of the GNU General Public License as published by
5*44704f69SBart Van Assche  *  the Free Software Foundation; either version 2, or (at your option)
6*44704f69SBart Van Assche  *  any later version.
7*44704f69SBart Van Assche  *
8*44704f69SBart Van Assche  * SPDX-License-Identifier: GPL-2.0-or-later
9*44704f69SBart Van Assche 
10*44704f69SBart Van Assche     Start/Stop parameter by Kurt Garloff, 6/2000
11*44704f69SBart Van Assche     Sync cache parameter by Kurt Garloff, 1/2001
12*44704f69SBart Van Assche     Guard block device answering sg's ioctls.
13*44704f69SBart Van Assche                      <dgilbert at interlog dot com> 12/2002
14*44704f69SBart Van Assche     Convert to SG_IO ioctl so can use sg or block devices in 2.6.* 3/2003
15*44704f69SBart Van Assche 
16*44704f69SBart Van Assche     This utility was written for the Linux 2.4 kernel series. It now
17*44704f69SBart Van Assche     builds for the Linux 2.6 and 3 kernel series and various other
18*44704f69SBart Van Assche     Operating Systems.
19*44704f69SBart Van Assche 
20*44704f69SBart Van Assche */
21*44704f69SBart Van Assche 
22*44704f69SBart Van Assche #include <stdio.h>
23*44704f69SBart Van Assche #include <stdlib.h>
24*44704f69SBart Van Assche #include <stdarg.h>
25*44704f69SBart Van Assche #include <stdbool.h>
26*44704f69SBart Van Assche #include <unistd.h>
27*44704f69SBart Van Assche #include <string.h>
28*44704f69SBart Van Assche #include <fcntl.h>
29*44704f69SBart Van Assche #include <getopt.h>
30*44704f69SBart Van Assche 
31*44704f69SBart Van Assche #ifdef HAVE_CONFIG_H
32*44704f69SBart Van Assche #include "config.h"
33*44704f69SBart Van Assche #endif
34*44704f69SBart Van Assche #include "sg_lib.h"
35*44704f69SBart Van Assche #include "sg_cmds_basic.h"
36*44704f69SBart Van Assche #include "sg_pr2serr.h"
37*44704f69SBart Van Assche 
38*44704f69SBart Van Assche 
39*44704f69SBart Van Assche static const char * version_str = "0.67 20200930";  /* sbc3r14; mmc6r01a */
40*44704f69SBart Van Assche 
41*44704f69SBart Van Assche static struct option long_options[] = {
42*44704f69SBart Van Assche         {"eject", no_argument, 0, 'e'},
43*44704f69SBart Van Assche         {"fl", required_argument, 0, 'f'},
44*44704f69SBart Van Assche         {"help", no_argument, 0, 'h'},
45*44704f69SBart Van Assche         {"immed", no_argument, 0, 'i'},
46*44704f69SBart Van Assche         {"load", no_argument, 0, 'l'},
47*44704f69SBart Van Assche         {"loej", no_argument, 0, 'L'},
48*44704f69SBart Van Assche         {"mod", required_argument, 0, 'm'},
49*44704f69SBart Van Assche         {"noflush", no_argument, 0, 'n'},
50*44704f69SBart Van Assche         {"new", no_argument, 0, 'N'},
51*44704f69SBart Van Assche         {"old", no_argument, 0, 'O'},
52*44704f69SBart Van Assche         {"pc", required_argument, 0, 'p'},
53*44704f69SBart Van Assche         {"readonly", no_argument, 0, 'r'},
54*44704f69SBart Van Assche         {"start", no_argument, 0, 's'},
55*44704f69SBart Van Assche         {"stop", no_argument, 0, 'S'},
56*44704f69SBart Van Assche         {"verbose", no_argument, 0, 'v'},
57*44704f69SBart Van Assche         {"version", no_argument, 0, 'V'},
58*44704f69SBart Van Assche         {0, 0, 0, 0},
59*44704f69SBart Van Assche };
60*44704f69SBart Van Assche 
61*44704f69SBart Van Assche struct opts_t {
62*44704f69SBart Van Assche     bool do_eject;
63*44704f69SBart Van Assche     bool do_immed;
64*44704f69SBart Van Assche     bool do_load;
65*44704f69SBart Van Assche     bool do_loej;
66*44704f69SBart Van Assche     bool do_noflush;
67*44704f69SBart Van Assche     bool do_readonly;
68*44704f69SBart Van Assche     bool do_start;
69*44704f69SBart Van Assche     bool do_stop;
70*44704f69SBart Van Assche     bool opt_new;
71*44704f69SBart Van Assche     bool verbose_given;
72*44704f69SBart Van Assche     bool version_given;
73*44704f69SBart Van Assche     int do_fl;
74*44704f69SBart Van Assche     int do_help;
75*44704f69SBart Van Assche     int do_mod;
76*44704f69SBart Van Assche     int do_pc;
77*44704f69SBart Van Assche     int verbose;
78*44704f69SBart Van Assche     const char * device_name;
79*44704f69SBart Van Assche };
80*44704f69SBart Van Assche 
81*44704f69SBart Van Assche static void
usage()82*44704f69SBart Van Assche usage()
83*44704f69SBart Van Assche {
84*44704f69SBart Van Assche     pr2serr("Usage: sg_start [--eject] [--fl=FL] [--help] "
85*44704f69SBart Van Assche             "[--immed] [--load] [--loej]\n"
86*44704f69SBart Van Assche             "                [--mod=PC_MOD] [--noflush] [--pc=PC] "
87*44704f69SBart Van Assche             "[--readonly]\n"
88*44704f69SBart Van Assche             "                [--start] [--stop] [--verbose] "
89*44704f69SBart Van Assche             "[--version] DEVICE\n"
90*44704f69SBart Van Assche             "  where:\n"
91*44704f69SBart Van Assche             "    --eject|-e      stop unit then eject the medium\n"
92*44704f69SBart Van Assche             "    --fl=FL|-f FL    format layer number (mmc5)\n"
93*44704f69SBart Van Assche             "    --help|-h       print usage message then exit\n"
94*44704f69SBart Van Assche             "    --immed|-i      device should return control after "
95*44704f69SBart Van Assche             "receiving cdb,\n"
96*44704f69SBart Van Assche             "                    default action is to wait until action "
97*44704f69SBart Van Assche             "is complete\n"
98*44704f69SBart Van Assche             "    --load|-l       load medium then start the unit\n"
99*44704f69SBart Van Assche             "    --loej|-L       load or eject, corresponds to LOEJ bit "
100*44704f69SBart Van Assche             "in cdb;\n"
101*44704f69SBart Van Assche             "                    load when START bit also set, else "
102*44704f69SBart Van Assche             "eject\n"
103*44704f69SBart Van Assche             "    --mod=PC_MOD|-m PC_MOD    power condition modifier "
104*44704f69SBart Van Assche             "(def: 0) (sbc)\n"
105*44704f69SBart Van Assche             "    --noflush|-n    no flush prior to operation that limits "
106*44704f69SBart Van Assche             "access (sbc)\n"
107*44704f69SBart Van Assche             "    --pc=PC|-p PC    power condition: 0 (default) -> no "
108*44704f69SBart Van Assche             "power condition,\n"
109*44704f69SBart Van Assche             "                    1 -> active, 2 -> idle, 3 -> standby, "
110*44704f69SBart Van Assche             "5 -> sleep (mmc)\n"
111*44704f69SBart Van Assche             "    --readonly|-r    open DEVICE read-only (def: read-write)\n"
112*44704f69SBart Van Assche             "                     recommended if DEVICE is ATA disk\n"
113*44704f69SBart Van Assche             "    --start|-s      start unit, corresponds to START bit "
114*44704f69SBart Van Assche             "in cdb,\n"
115*44704f69SBart Van Assche             "                    default (START=1) if no other options "
116*44704f69SBart Van Assche             "given\n"
117*44704f69SBart Van Assche             "    --stop|-S       stop unit (e.g. spin down disk)\n"
118*44704f69SBart Van Assche             "    --verbose|-v    increase verbosity\n"
119*44704f69SBart Van Assche             "    --old|-O        use old interface (use as first option)\n"
120*44704f69SBart Van Assche             "    --version|-V    print version string then exit\n\n"
121*44704f69SBart Van Assche             "    Example: 'sg_start --stop /dev/sdb'    stops unit\n"
122*44704f69SBart Van Assche             "             'sg_start --eject /dev/scd0'  stops unit and "
123*44704f69SBart Van Assche             "ejects medium\n\n"
124*44704f69SBart Van Assche             "Performs a SCSI START STOP UNIT command\n"
125*44704f69SBart Van Assche             );
126*44704f69SBart Van Assche }
127*44704f69SBart Van Assche 
128*44704f69SBart Van Assche static void
usage_old()129*44704f69SBart Van Assche usage_old()
130*44704f69SBart Van Assche {
131*44704f69SBart Van Assche     pr2serr("Usage:  sg_start [0] [1] [--eject] [--fl=FL] "
132*44704f69SBart Van Assche             "[-i] [--imm=0|1]\n"
133*44704f69SBart Van Assche             "                 [--load] [--loej] [--mod=PC_MOD] "
134*44704f69SBart Van Assche             "[--noflush] [--pc=PC]\n"
135*44704f69SBart Van Assche             "                 [--readonly] [--start] [--stop] [-v] [-V]\n"
136*44704f69SBart Van Assche             "                 DEVICE\n"
137*44704f69SBart Van Assche             "  where:\n"
138*44704f69SBart Van Assche             "    0          stop unit (e.g. spin down a disk or a "
139*44704f69SBart Van Assche             "cd/dvd)\n"
140*44704f69SBart Van Assche             "    1          start unit (e.g. spin up a disk or a "
141*44704f69SBart Van Assche             "cd/dvd)\n"
142*44704f69SBart Van Assche             "    --eject    stop then eject the medium\n"
143*44704f69SBart Van Assche             "    --fl=FL    format layer number (mmc5)\n"
144*44704f69SBart Van Assche             "    -i         return immediately (same as '--imm=1')\n"
145*44704f69SBart Van Assche             "    --imm=0|1  0->await completion(def), 1->return "
146*44704f69SBart Van Assche             "immediately\n"
147*44704f69SBart Van Assche             "    --load     load then start the medium\n"
148*44704f69SBart Van Assche             "    --loej     load the medium if '-start' option is "
149*44704f69SBart Van Assche             "also given\n"
150*44704f69SBart Van Assche             "               or stop unit and eject\n"
151*44704f69SBart Van Assche             "    --mod=PC_MOD    power condition modifier "
152*44704f69SBart Van Assche             "(def: 0) (sbc)\n"
153*44704f69SBart Van Assche             "    --noflush    no flush prior to operation that limits "
154*44704f69SBart Van Assche             "access (sbc)\n"
155*44704f69SBart Van Assche             "    --pc=PC    power condition (in hex, default 0 -> no "
156*44704f69SBart Van Assche             "power condition)\n"
157*44704f69SBart Van Assche             "               1 -> active, 2 -> idle, 3 -> standby, "
158*44704f69SBart Van Assche             "5 -> sleep (mmc)\n"
159*44704f69SBart Van Assche             "    --readonly|-r    open DEVICE read-only (def: read-write)\n"
160*44704f69SBart Van Assche             "                     recommended if DEVICE is ATA disk\n"
161*44704f69SBart Van Assche             "    --start    start unit (same as '1'), default "
162*44704f69SBart Van Assche             "action\n"
163*44704f69SBart Van Assche             "    --stop     stop unit (same as '0')\n"
164*44704f69SBart Van Assche             "    -v         verbose (print out SCSI commands)\n"
165*44704f69SBart Van Assche             "    --new|-N   use new interface\n"
166*44704f69SBart Van Assche             "    -V         print version string then exit\n\n"
167*44704f69SBart Van Assche             "    Example: 'sg_start --stop /dev/sdb'    stops unit\n"
168*44704f69SBart Van Assche             "             'sg_start --eject /dev/scd0'  stops unit and "
169*44704f69SBart Van Assche             "ejects medium\n\n"
170*44704f69SBart Van Assche             "Performs a SCSI START STOP UNIT command\n"
171*44704f69SBart Van Assche             );
172*44704f69SBart Van Assche }
173*44704f69SBart Van Assche 
174*44704f69SBart Van Assche static int
new_parse_cmd_line(struct opts_t * op,int argc,char * argv[])175*44704f69SBart Van Assche new_parse_cmd_line(struct opts_t * op, int argc, char * argv[])
176*44704f69SBart Van Assche {
177*44704f69SBart Van Assche     int c, n, err;
178*44704f69SBart Van Assche 
179*44704f69SBart Van Assche     while (1) {
180*44704f69SBart Van Assche         int option_index = 0;
181*44704f69SBart Van Assche 
182*44704f69SBart Van Assche         c = getopt_long(argc, argv, "ef:hilLm:nNOp:rsSvV", long_options,
183*44704f69SBart Van Assche                         &option_index);
184*44704f69SBart Van Assche         if (c == -1)
185*44704f69SBart Van Assche             break;
186*44704f69SBart Van Assche 
187*44704f69SBart Van Assche         switch (c) {
188*44704f69SBart Van Assche         case 'e':
189*44704f69SBart Van Assche             op->do_eject = true;
190*44704f69SBart Van Assche             op->do_loej = true;
191*44704f69SBart Van Assche             break;
192*44704f69SBart Van Assche         case 'f':
193*44704f69SBart Van Assche             n = sg_get_num(optarg);
194*44704f69SBart Van Assche             if ((n < 0) || (n > 3)) {
195*44704f69SBart Van Assche                 pr2serr("bad argument to '--fl='\n");
196*44704f69SBart Van Assche                 usage();
197*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
198*44704f69SBart Van Assche             }
199*44704f69SBart Van Assche             op->do_loej = true;
200*44704f69SBart Van Assche             op->do_start = true;
201*44704f69SBart Van Assche             op->do_fl = n;
202*44704f69SBart Van Assche             break;
203*44704f69SBart Van Assche         case 'h':
204*44704f69SBart Van Assche         case '?':
205*44704f69SBart Van Assche             ++op->do_help;
206*44704f69SBart Van Assche             break;
207*44704f69SBart Van Assche         case 'i':
208*44704f69SBart Van Assche             op->do_immed = true;
209*44704f69SBart Van Assche             break;
210*44704f69SBart Van Assche         case 'l':
211*44704f69SBart Van Assche             op->do_load = true;
212*44704f69SBart Van Assche             op->do_loej = true;
213*44704f69SBart Van Assche             break;
214*44704f69SBart Van Assche         case 'L':
215*44704f69SBart Van Assche             op->do_loej = true;
216*44704f69SBart Van Assche             break;
217*44704f69SBart Van Assche         case 'm':
218*44704f69SBart Van Assche             n = sg_get_num(optarg);
219*44704f69SBart Van Assche             if ((n < 0) || (n > 15)) {
220*44704f69SBart Van Assche                 pr2serr("bad argument to '--mod='\n");
221*44704f69SBart Van Assche                 usage();
222*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
223*44704f69SBart Van Assche             }
224*44704f69SBart Van Assche             op->do_mod = n;
225*44704f69SBart Van Assche             break;
226*44704f69SBart Van Assche         case 'n':
227*44704f69SBart Van Assche             op->do_noflush = true;
228*44704f69SBart Van Assche             break;
229*44704f69SBart Van Assche         case 'N':
230*44704f69SBart Van Assche             break;      /* ignore */
231*44704f69SBart Van Assche         case 'O':
232*44704f69SBart Van Assche             op->opt_new = false;
233*44704f69SBart Van Assche             return 0;
234*44704f69SBart Van Assche         case 'p':
235*44704f69SBart Van Assche             n = sg_get_num(optarg);
236*44704f69SBart Van Assche             if ((n < 0) || (n > 15)) {
237*44704f69SBart Van Assche                 pr2serr("bad argument to '--pc='\n");
238*44704f69SBart Van Assche                 usage();
239*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
240*44704f69SBart Van Assche             }
241*44704f69SBart Van Assche             op->do_pc = n;
242*44704f69SBart Van Assche             break;
243*44704f69SBart Van Assche         case 'r':
244*44704f69SBart Van Assche             op->do_readonly = true;
245*44704f69SBart Van Assche             break;
246*44704f69SBart Van Assche         case 's':
247*44704f69SBart Van Assche             op->do_start = true;
248*44704f69SBart Van Assche             break;
249*44704f69SBart Van Assche         case 'S':
250*44704f69SBart Van Assche             op->do_stop = true;
251*44704f69SBart Van Assche             break;
252*44704f69SBart Van Assche         case 'v':
253*44704f69SBart Van Assche             op->verbose_given = true;
254*44704f69SBart Van Assche             ++op->verbose;
255*44704f69SBart Van Assche             break;
256*44704f69SBart Van Assche         case 'V':
257*44704f69SBart Van Assche             op->version_given = true;
258*44704f69SBart Van Assche             break;
259*44704f69SBart Van Assche         default:
260*44704f69SBart Van Assche             pr2serr("unrecognised option code %c [0x%x]\n", c, c);
261*44704f69SBart Van Assche             if (op->do_help)
262*44704f69SBart Van Assche                 break;
263*44704f69SBart Van Assche             usage();
264*44704f69SBart Van Assche             return SG_LIB_SYNTAX_ERROR;
265*44704f69SBart Van Assche         }
266*44704f69SBart Van Assche     }
267*44704f69SBart Van Assche     err = 0;
268*44704f69SBart Van Assche     for (; optind < argc; ++optind) {
269*44704f69SBart Van Assche         if (1 == strlen(argv[optind])) {
270*44704f69SBart Van Assche             if (0 == strcmp("0", argv[optind])) {
271*44704f69SBart Van Assche                 op->do_stop = true;
272*44704f69SBart Van Assche                 continue;
273*44704f69SBart Van Assche             } else if (0 == strcmp("1", argv[optind])) {
274*44704f69SBart Van Assche                 op->do_start = true;
275*44704f69SBart Van Assche                 continue;
276*44704f69SBart Van Assche             }
277*44704f69SBart Van Assche         }
278*44704f69SBart Van Assche         if (NULL == op->device_name)
279*44704f69SBart Van Assche             op->device_name = argv[optind];
280*44704f69SBart Van Assche         else {
281*44704f69SBart Van Assche             pr2serr("Unexpected extra argument: %s\n", argv[optind]);
282*44704f69SBart Van Assche             ++err;
283*44704f69SBart Van Assche         }
284*44704f69SBart Van Assche     }
285*44704f69SBart Van Assche     if (err) {
286*44704f69SBart Van Assche         usage();
287*44704f69SBart Van Assche         return SG_LIB_SYNTAX_ERROR;
288*44704f69SBart Van Assche     } else
289*44704f69SBart Van Assche         return 0;
290*44704f69SBart Van Assche }
291*44704f69SBart Van Assche 
292*44704f69SBart Van Assche static int
old_parse_cmd_line(struct opts_t * op,int argc,char * argv[])293*44704f69SBart Van Assche old_parse_cmd_line(struct opts_t * op, int argc, char * argv[])
294*44704f69SBart Van Assche {
295*44704f69SBart Van Assche     bool ambigu = false;
296*44704f69SBart Van Assche     bool jmp_out;
297*44704f69SBart Van Assche     bool startstop = false;
298*44704f69SBart Van Assche     bool startstop_set = false;
299*44704f69SBart Van Assche     int k, plen, num;
300*44704f69SBart Van Assche     unsigned int u;
301*44704f69SBart Van Assche     const char * cp;
302*44704f69SBart Van Assche 
303*44704f69SBart Van Assche     for (k = 1; k < argc; ++k) {
304*44704f69SBart Van Assche         cp = argv[k];
305*44704f69SBart Van Assche         plen = strlen(cp);
306*44704f69SBart Van Assche         if (plen <= 0)
307*44704f69SBart Van Assche             continue;
308*44704f69SBart Van Assche         if ('-' == *cp) {
309*44704f69SBart Van Assche             for (--plen, ++cp, jmp_out = false; plen > 0;
310*44704f69SBart Van Assche                  --plen, ++cp) {
311*44704f69SBart Van Assche                 switch (*cp) {
312*44704f69SBart Van Assche                 case 'i':
313*44704f69SBart Van Assche                     if ('\0' == *(cp + 1))
314*44704f69SBart Van Assche                         op->do_immed = true;
315*44704f69SBart Van Assche                     else
316*44704f69SBart Van Assche                         jmp_out = true;
317*44704f69SBart Van Assche                     break;
318*44704f69SBart Van Assche                 case 'r':
319*44704f69SBart Van Assche                     op->do_readonly = true;
320*44704f69SBart Van Assche                     break;
321*44704f69SBart Van Assche                 case 'v':
322*44704f69SBart Van Assche                     op->verbose_given = true;
323*44704f69SBart Van Assche                     ++op->verbose;
324*44704f69SBart Van Assche                     break;
325*44704f69SBart Van Assche                 case 'V':
326*44704f69SBart Van Assche                     op->version_given = true;
327*44704f69SBart Van Assche                     break;
328*44704f69SBart Van Assche                 case 'h':
329*44704f69SBart Van Assche                 case '?':
330*44704f69SBart Van Assche                     ++op->do_help;
331*44704f69SBart Van Assche                     break;
332*44704f69SBart Van Assche                 case 'N':
333*44704f69SBart Van Assche                     op->opt_new = true;
334*44704f69SBart Van Assche                     return 0;
335*44704f69SBart Van Assche                 case 'O':
336*44704f69SBart Van Assche                     break;
337*44704f69SBart Van Assche                 case '-':
338*44704f69SBart Van Assche                     ++cp;
339*44704f69SBart Van Assche                     --plen;
340*44704f69SBart Van Assche                     jmp_out = true;
341*44704f69SBart Van Assche                     break;
342*44704f69SBart Van Assche                 default:
343*44704f69SBart Van Assche                     jmp_out = true;
344*44704f69SBart Van Assche                     break;
345*44704f69SBart Van Assche                 }
346*44704f69SBart Van Assche                 if (jmp_out)
347*44704f69SBart Van Assche                     break;
348*44704f69SBart Van Assche             }
349*44704f69SBart Van Assche             if (plen <= 0)
350*44704f69SBart Van Assche                 continue;
351*44704f69SBart Van Assche 
352*44704f69SBart Van Assche             if (0 == strncmp(cp, "eject", 5)) {
353*44704f69SBart Van Assche                 op->do_loej = true;
354*44704f69SBart Van Assche                 if (startstop_set && startstop)
355*44704f69SBart Van Assche                     ambigu = true;
356*44704f69SBart Van Assche                 else {
357*44704f69SBart Van Assche                     startstop = false;
358*44704f69SBart Van Assche                     startstop_set = true;
359*44704f69SBart Van Assche                 }
360*44704f69SBart Van Assche             } else if (0 == strncmp("fl=", cp, 3)) {
361*44704f69SBart Van Assche                 num = sscanf(cp + 3, "%x", &u);
362*44704f69SBart Van Assche                 if (1 != num) {
363*44704f69SBart Van Assche                     pr2serr("Bad value after 'fl=' option\n");
364*44704f69SBart Van Assche                     usage_old();
365*44704f69SBart Van Assche                     return SG_LIB_SYNTAX_ERROR;
366*44704f69SBart Van Assche                 }
367*44704f69SBart Van Assche                 startstop = true;
368*44704f69SBart Van Assche                 startstop_set = true;
369*44704f69SBart Van Assche                 op->do_loej = true;
370*44704f69SBart Van Assche                 op->do_fl = u;
371*44704f69SBart Van Assche             } else if (0 == strncmp("imm=", cp, 4)) {
372*44704f69SBart Van Assche                 num = sscanf(cp + 4, "%x", &u);
373*44704f69SBart Van Assche                 if ((1 != num) || (u > 1)) {
374*44704f69SBart Van Assche                     pr2serr("Bad value after 'imm=' option\n");
375*44704f69SBart Van Assche                     usage_old();
376*44704f69SBart Van Assche                     return SG_LIB_SYNTAX_ERROR;
377*44704f69SBart Van Assche                 }
378*44704f69SBart Van Assche                 op->do_immed = !! u;
379*44704f69SBart Van Assche             } else if (0 == strncmp(cp, "load", 4)) {
380*44704f69SBart Van Assche                 op->do_loej = true;
381*44704f69SBart Van Assche                 if (startstop_set && (! startstop))
382*44704f69SBart Van Assche                     ambigu = true;
383*44704f69SBart Van Assche                 else {
384*44704f69SBart Van Assche                     startstop = true;
385*44704f69SBart Van Assche                     startstop_set = true;
386*44704f69SBart Van Assche                 }
387*44704f69SBart Van Assche             } else if (0 == strncmp(cp, "loej", 4))
388*44704f69SBart Van Assche                 op->do_loej = true;
389*44704f69SBart Van Assche             else if (0 == strncmp("pc=", cp, 3)) {
390*44704f69SBart Van Assche                 num = sscanf(cp + 3, "%x", &u);
391*44704f69SBart Van Assche                 if ((1 != num) || (u > 15)) {
392*44704f69SBart Van Assche                     pr2serr("Bad value after after 'pc=' option\n");
393*44704f69SBart Van Assche                     usage_old();
394*44704f69SBart Van Assche                     return SG_LIB_SYNTAX_ERROR;
395*44704f69SBart Van Assche                 }
396*44704f69SBart Van Assche                 op->do_pc = u;
397*44704f69SBart Van Assche             } else if (0 == strncmp("mod=", cp, 4)) {
398*44704f69SBart Van Assche                 num = sscanf(cp + 3, "%x", &u);
399*44704f69SBart Van Assche                 if (1 != num) {
400*44704f69SBart Van Assche                     pr2serr("Bad value after 'mod=' option\n");
401*44704f69SBart Van Assche                     usage_old();
402*44704f69SBart Van Assche                     return SG_LIB_SYNTAX_ERROR;
403*44704f69SBart Van Assche                 }
404*44704f69SBart Van Assche                 op->do_mod = u;
405*44704f69SBart Van Assche             } else if (0 == strncmp(cp, "noflush", 7)) {
406*44704f69SBart Van Assche                 op->do_noflush = true;
407*44704f69SBart Van Assche             } else if (0 == strncmp(cp, "start", 5)) {
408*44704f69SBart Van Assche                 if (startstop_set && (! startstop))
409*44704f69SBart Van Assche                     ambigu = true;
410*44704f69SBart Van Assche                 else {
411*44704f69SBart Van Assche                     startstop = true;
412*44704f69SBart Van Assche                     startstop_set = true;
413*44704f69SBart Van Assche                 }
414*44704f69SBart Van Assche             } else if (0 == strncmp(cp, "stop", 4)) {
415*44704f69SBart Van Assche                 if (startstop_set && startstop)
416*44704f69SBart Van Assche                     ambigu = true;
417*44704f69SBart Van Assche                 else {
418*44704f69SBart Van Assche                     startstop = false;
419*44704f69SBart Van Assche                     startstop_set = true;
420*44704f69SBart Van Assche                 }
421*44704f69SBart Van Assche             } else if (0 == strncmp(cp, "old", 3))
422*44704f69SBart Van Assche                 ;
423*44704f69SBart Van Assche             else if (jmp_out) {
424*44704f69SBart Van Assche                 pr2serr("Unrecognized option: %s\n", cp);
425*44704f69SBart Van Assche                 usage_old();
426*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
427*44704f69SBart Van Assche             }
428*44704f69SBart Van Assche         } else if (0 == strcmp("0", cp)) {
429*44704f69SBart Van Assche             if (startstop_set && startstop)
430*44704f69SBart Van Assche                 ambigu = true;
431*44704f69SBart Van Assche             else {
432*44704f69SBart Van Assche                 startstop = false;
433*44704f69SBart Van Assche                 startstop_set = true;
434*44704f69SBart Van Assche             }
435*44704f69SBart Van Assche         } else if (0 == strcmp("1", cp)) {
436*44704f69SBart Van Assche             if (startstop_set && (! startstop))
437*44704f69SBart Van Assche                 ambigu = true;
438*44704f69SBart Van Assche             else {
439*44704f69SBart Van Assche                 startstop = true;
440*44704f69SBart Van Assche                 startstop_set = true;
441*44704f69SBart Van Assche             }
442*44704f69SBart Van Assche         } else if (0 == op->device_name)
443*44704f69SBart Van Assche                 op->device_name = cp;
444*44704f69SBart Van Assche         else {
445*44704f69SBart Van Assche             pr2serr("too many arguments, got: %s, not "
446*44704f69SBart Van Assche                     "expecting: %s\n", op->device_name, cp);
447*44704f69SBart Van Assche             usage_old();
448*44704f69SBart Van Assche             return SG_LIB_SYNTAX_ERROR;
449*44704f69SBart Van Assche         }
450*44704f69SBart Van Assche         if (ambigu) {
451*44704f69SBart Van Assche             pr2serr("please, only one of 0, 1, --eject, "
452*44704f69SBart Van Assche                     "--load, --start or --stop\n");
453*44704f69SBart Van Assche             usage_old();
454*44704f69SBart Van Assche             return SG_LIB_CONTRADICT;
455*44704f69SBart Van Assche         } else if (startstop_set) {
456*44704f69SBart Van Assche             if (startstop)
457*44704f69SBart Van Assche                 op->do_start = true;
458*44704f69SBart Van Assche             else
459*44704f69SBart Van Assche                 op->do_stop = true;
460*44704f69SBart Van Assche         }
461*44704f69SBart Van Assche     }
462*44704f69SBart Van Assche     return 0;
463*44704f69SBart Van Assche }
464*44704f69SBart Van Assche 
465*44704f69SBart Van Assche static int
parse_cmd_line(struct opts_t * op,int argc,char * argv[])466*44704f69SBart Van Assche parse_cmd_line(struct opts_t * op, int argc, char * argv[])
467*44704f69SBart Van Assche {
468*44704f69SBart Van Assche     int res;
469*44704f69SBart Van Assche     char * cp;
470*44704f69SBart Van Assche 
471*44704f69SBart Van Assche     cp = getenv("SG3_UTILS_OLD_OPTS");
472*44704f69SBart Van Assche     if (cp) {
473*44704f69SBart Van Assche         op->opt_new = false;
474*44704f69SBart Van Assche         res = old_parse_cmd_line(op, argc, argv);
475*44704f69SBart Van Assche         if ((0 == res) && op->opt_new)
476*44704f69SBart Van Assche             res = new_parse_cmd_line(op, argc, argv);
477*44704f69SBart Van Assche     } else {
478*44704f69SBart Van Assche         op->opt_new = true;
479*44704f69SBart Van Assche         res = new_parse_cmd_line(op, argc, argv);
480*44704f69SBart Van Assche         if ((0 == res) && (! op->opt_new))
481*44704f69SBart Van Assche             res = old_parse_cmd_line(op, argc, argv);
482*44704f69SBart Van Assche     }
483*44704f69SBart Van Assche     return res;
484*44704f69SBart Van Assche }
485*44704f69SBart Van Assche 
486*44704f69SBart Van Assche 
487*44704f69SBart Van Assche int
main(int argc,char * argv[])488*44704f69SBart Van Assche main(int argc, char * argv[])
489*44704f69SBart Van Assche {
490*44704f69SBart Van Assche     int res;
491*44704f69SBart Van Assche     int sg_fd = -1;
492*44704f69SBart Van Assche     int ret = 0;
493*44704f69SBart Van Assche     struct opts_t opts;
494*44704f69SBart Van Assche     struct opts_t * op;
495*44704f69SBart Van Assche 
496*44704f69SBart Van Assche     op = &opts;
497*44704f69SBart Van Assche     memset(op, 0, sizeof(opts));
498*44704f69SBart Van Assche     op->do_fl = -1;    /* only when >= 0 set FL bit */
499*44704f69SBart Van Assche     res = parse_cmd_line(op, argc, argv);
500*44704f69SBart Van Assche     if (res)
501*44704f69SBart Van Assche         return res;
502*44704f69SBart Van Assche     if (op->do_help) {
503*44704f69SBart Van Assche         if (op->opt_new)
504*44704f69SBart Van Assche             usage();
505*44704f69SBart Van Assche         else
506*44704f69SBart Van Assche             usage_old();
507*44704f69SBart Van Assche         return 0;
508*44704f69SBart Van Assche     }
509*44704f69SBart Van Assche 
510*44704f69SBart Van Assche #ifdef DEBUG
511*44704f69SBart Van Assche     pr2serr("In DEBUG mode, ");
512*44704f69SBart Van Assche     if (op->verbose_given && op->version_given) {
513*44704f69SBart Van Assche         pr2serr("but override: '-vV' given, zero verbose and continue\n");
514*44704f69SBart Van Assche         op->verbose_given = false;
515*44704f69SBart Van Assche         op->version_given = false;
516*44704f69SBart Van Assche         op->verbose = 0;
517*44704f69SBart Van Assche     } else if (! op->verbose_given) {
518*44704f69SBart Van Assche         pr2serr("set '-vv'\n");
519*44704f69SBart Van Assche         op->verbose = 2;
520*44704f69SBart Van Assche     } else
521*44704f69SBart Van Assche         pr2serr("keep verbose=%d\n", op->verbose);
522*44704f69SBart Van Assche #else
523*44704f69SBart Van Assche     if (op->verbose_given && op->version_given)
524*44704f69SBart Van Assche         pr2serr("Not in DEBUG mode, so '-vV' has no special action\n");
525*44704f69SBart Van Assche #endif
526*44704f69SBart Van Assche     if (op->version_given) {
527*44704f69SBart Van Assche         pr2serr("Version string: %s\n", version_str);
528*44704f69SBart Van Assche         return 0;
529*44704f69SBart Van Assche     }
530*44704f69SBart Van Assche 
531*44704f69SBart Van Assche     if (op->do_start && op->do_stop) {
532*44704f69SBart Van Assche         pr2serr("Ambiguous to give both '--start' and '--stop'\n");
533*44704f69SBart Van Assche         return SG_LIB_CONTRADICT;
534*44704f69SBart Van Assche     }
535*44704f69SBart Van Assche     if (op->do_load && op->do_eject) {
536*44704f69SBart Van Assche         pr2serr("Ambiguous to give both '--load' and '--eject'\n");
537*44704f69SBart Van Assche         return SG_LIB_CONTRADICT;
538*44704f69SBart Van Assche     }
539*44704f69SBart Van Assche     if (op->do_load)
540*44704f69SBart Van Assche        op->do_start = true;
541*44704f69SBart Van Assche     else if ((op->do_eject) || op->do_stop)
542*44704f69SBart Van Assche        op->do_start = false;
543*44704f69SBart Van Assche     else if (op->opt_new && op->do_loej && (! op->do_start))
544*44704f69SBart Van Assche         op->do_start = true;      /* --loej alone in new interface is load */
545*44704f69SBart Van Assche     else if ((! op->do_loej) && (-1 == op->do_fl) && (0 == op->do_pc))
546*44704f69SBart Van Assche        op->do_start = true;
547*44704f69SBart Van Assche     /* default action is to start when no other active options */
548*44704f69SBart Van Assche 
549*44704f69SBart Van Assche     if (0 == op->device_name) {
550*44704f69SBart Van Assche         pr2serr("No DEVICE argument given\n");
551*44704f69SBart Van Assche         if (op->opt_new)
552*44704f69SBart Van Assche             usage();
553*44704f69SBart Van Assche         else
554*44704f69SBart Van Assche             usage_old();
555*44704f69SBart Van Assche         return SG_LIB_SYNTAX_ERROR;
556*44704f69SBart Van Assche     }
557*44704f69SBart Van Assche 
558*44704f69SBart Van Assche     if (op->do_fl >= 0) {
559*44704f69SBart Van Assche         if (! op->do_start) {
560*44704f69SBart Van Assche             pr2serr("Giving '--fl=FL' with '--stop' (or '--eject') is "
561*44704f69SBart Van Assche                     "invalid\n");
562*44704f69SBart Van Assche             return SG_LIB_CONTRADICT;
563*44704f69SBart Van Assche         }
564*44704f69SBart Van Assche         if (op->do_pc > 0) {
565*44704f69SBart Van Assche             pr2serr("Giving '--fl=FL' with '--pc=PC' when PC is non-zero "
566*44704f69SBart Van Assche                     "is invalid\n");
567*44704f69SBart Van Assche             return SG_LIB_CONTRADICT;
568*44704f69SBart Van Assche         }
569*44704f69SBart Van Assche     }
570*44704f69SBart Van Assche 
571*44704f69SBart Van Assche     sg_fd = sg_cmds_open_device(op->device_name, op->do_readonly,
572*44704f69SBart Van Assche                                 op->verbose);
573*44704f69SBart Van Assche     if (sg_fd < 0) {
574*44704f69SBart Van Assche         if (op->verbose)
575*44704f69SBart Van Assche             pr2serr("Error trying to open %s: %s\n", op->device_name,
576*44704f69SBart Van Assche                     safe_strerror(-sg_fd));
577*44704f69SBart Van Assche         ret = sg_convert_errno(-sg_fd);
578*44704f69SBart Van Assche         goto fini;
579*44704f69SBart Van Assche     }
580*44704f69SBart Van Assche 
581*44704f69SBart Van Assche     if (op->do_fl >= 0)
582*44704f69SBart Van Assche         res = sg_ll_start_stop_unit(sg_fd, op->do_immed, op->do_fl, 0 /* pc */,
583*44704f69SBart Van Assche                                     true /* fl */, true /* loej */,
584*44704f69SBart Van Assche                                     true /*start */, true /* noisy */,
585*44704f69SBart Van Assche                                     op->verbose);
586*44704f69SBart Van Assche     else if (op->do_pc > 0)
587*44704f69SBart Van Assche         res = sg_ll_start_stop_unit(sg_fd, op->do_immed, op->do_mod,
588*44704f69SBart Van Assche                                     op->do_pc, op->do_noflush, false, false,
589*44704f69SBart Van Assche                                     true, op->verbose);
590*44704f69SBart Van Assche     else
591*44704f69SBart Van Assche         res = sg_ll_start_stop_unit(sg_fd, op->do_immed, 0, false,
592*44704f69SBart Van Assche                                     op->do_noflush, op->do_loej,
593*44704f69SBart Van Assche                                     op->do_start, true, op->verbose);
594*44704f69SBart Van Assche     ret = res;
595*44704f69SBart Van Assche     if (res) {
596*44704f69SBart Van Assche         if (op->verbose < 2) {
597*44704f69SBart Van Assche             char b[80];
598*44704f69SBart Van Assche 
599*44704f69SBart Van Assche             sg_get_category_sense_str(res, sizeof(b), b, op->verbose);
600*44704f69SBart Van Assche             pr2serr("%s\n", b);
601*44704f69SBart Van Assche         }
602*44704f69SBart Van Assche         pr2serr("START STOP UNIT command failed\n");
603*44704f69SBart Van Assche     }
604*44704f69SBart Van Assche fini:
605*44704f69SBart Van Assche     if (sg_fd >= 0) {
606*44704f69SBart Van Assche         res = sg_cmds_close_device(sg_fd);
607*44704f69SBart Van Assche         if (res < 0) {
608*44704f69SBart Van Assche             if (0 == ret)
609*44704f69SBart Van Assche                 ret = sg_convert_errno(-res);
610*44704f69SBart Van Assche         }
611*44704f69SBart Van Assche     }
612*44704f69SBart Van Assche     if (0 == op->verbose) {
613*44704f69SBart Van Assche         if (! sg_if_can2stderr("sg_start failed: ", ret))
614*44704f69SBart Van Assche             pr2serr("Some error occurred, try again with '-v' "
615*44704f69SBart Van Assche                     "or '-vv' for more information\n");
616*44704f69SBart Van Assche     }
617*44704f69SBart Van Assche     return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
618*44704f69SBart Van Assche }
619