1 /*
2 * Copyright (c) 2004-2022 Douglas Gilbert.
3 * All rights reserved.
4 * Use of this source code is governed by a BSD-style
5 * license that can be found in the BSD_LICENSE file.
6 *
7 * SPDX-License-Identifier: BSD-2-Clause
8 */
9
10 #include <unistd.h>
11 #include <fcntl.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <stdarg.h>
15 #include <stdbool.h>
16 #include <string.h>
17 #include <getopt.h>
18
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22 #include "sg_lib.h"
23 #include "sg_cmds_basic.h"
24 #include "sg_pr2serr.h"
25
26 /* A utility program originally written for the Linux OS SCSI subsystem.
27 *
28 * This program issues the SCSI PREVENT ALLOW MEDIUM REMOVAL command to the
29 * given SCSI device.
30 */
31
32 static const char * version_str = "1.13 20220826";
33
34 #define ME "sg_prevent: "
35
36
37 static struct option long_options[] = {
38 {"allow", no_argument, 0, 'a'},
39 {"help", no_argument, 0, 'h'},
40 {"prevent", required_argument, 0, 'p'},
41 {"verbose", no_argument, 0, 'v'},
42 {"version", no_argument, 0, 'V'},
43 {0, 0, 0, 0},
44 };
45
46
47 static void
usage()48 usage()
49 {
50 pr2serr("Usage: "
51 "sg_prevent [--allow] [--help] [--prevent=PC] [--verbose] "
52 "[--version]\n"
53 " DEVICE\n"
54 " where:\n"
55 " --allow|-a allow media removal\n"
56 " --help|-h print usage message then exit\n"
57 " --prevent=PC|-p PC prevent code value (def: 1 -> "
58 "prevent)\n"
59 " 0 -> allow, 1 -> prevent\n"
60 " 2 -> persistent allow, 3 -> "
61 "persistent prevent\n"
62 " --verbose|-v increase verbosity\n"
63 " --version|-V print version string and exit\n\n"
64 "Performs a SCSI PREVENT ALLOW MEDIUM REMOVAL command\n");
65
66 }
67
68 int
main(int argc,char * argv[])69 main(int argc, char * argv[])
70 {
71 bool allow = false;
72 bool verbose_given = false;
73 bool version_given = false;
74 int sg_fd, res, c;
75 int prevent = -1;
76 int verbose = 0;
77 const char * device_name = NULL;
78 int ret = 0;
79
80 while (1) {
81 int option_index = 0;
82
83 c = getopt_long(argc, argv, "ahp:vV", long_options,
84 &option_index);
85 if (c == -1)
86 break;
87
88 switch (c) {
89 case 'a':
90 allow = true;
91 break;
92 case 'h':
93 case '?':
94 usage();
95 return 0;
96 case 'p':
97 prevent = sg_get_num(optarg);
98 if ((prevent < 0) || (prevent > 3)) {
99 pr2serr("bad argument to '--prevent'\n");
100 return SG_LIB_SYNTAX_ERROR;
101 }
102 break;
103 case 'v':
104 verbose_given = true;
105 ++verbose;
106 break;
107 case 'V':
108 version_given = true;
109 break;
110 default:
111 pr2serr("unrecognised option code 0x%x ??\n", c);
112 usage();
113 return SG_LIB_SYNTAX_ERROR;
114 }
115 }
116 if (optind < argc) {
117 if (NULL == device_name) {
118 device_name = argv[optind];
119 ++optind;
120 }
121 if (optind < argc) {
122 for (; optind < argc; ++optind)
123 pr2serr("Unexpected extra argument: %s\n", argv[optind]);
124 usage();
125 return SG_LIB_SYNTAX_ERROR;
126 }
127 }
128 #ifdef DEBUG
129 pr2serr("In DEBUG mode, ");
130 if (verbose_given && version_given) {
131 pr2serr("but override: '-vV' given, zero verbose and continue\n");
132 verbose_given = false;
133 version_given = false;
134 verbose = 0;
135 } else if (! verbose_given) {
136 pr2serr("set '-vv'\n");
137 verbose = 2;
138 } else
139 pr2serr("keep verbose=%d\n", verbose);
140 #else
141 if (verbose_given && version_given)
142 pr2serr("Not in DEBUG mode, so '-vV' has no special action\n");
143 #endif
144 if (version_given) {
145 pr2serr(ME "version: %s\n", version_str);
146 return 0;
147 }
148
149 if (NULL == device_name) {
150 pr2serr("missing device name!\n");
151 usage();
152 return SG_LIB_SYNTAX_ERROR;
153 }
154 if (allow && (prevent >= 0)) {
155 pr2serr("can't give both '--allow' and '--prevent='\n");
156 usage();
157 return SG_LIB_CONTRADICT;
158 }
159 if (allow)
160 prevent = 0;
161 else if (prevent < 0)
162 prevent = 1; /* default is to prevent, as utility name suggests */
163
164 sg_fd = sg_cmds_open_device(device_name, false /* rw */, verbose);
165 if (sg_fd < 0) {
166 if (verbose)
167 pr2serr(ME "open error: %s: %s\n", device_name,
168 safe_strerror(-sg_fd));
169 ret = sg_convert_errno(-sg_fd);
170 goto fini;
171 }
172 res = sg_ll_prevent_allow(sg_fd, prevent, true, verbose);
173 ret = res;
174 if (res) {
175 char b[80];
176
177 sg_get_category_sense_str(res, sizeof(b), b, verbose);
178 pr2serr("Prevent allow medium removal: %s\n", b);
179 }
180 res = sg_cmds_close_device(sg_fd);
181 if (res < 0) {
182 pr2serr("close error: %s\n", safe_strerror(-res));
183 if (0 == ret)
184 ret = sg_convert_errno(-res);
185 }
186 fini:
187 if (0 == verbose) {
188 if (! sg_if_can2stderr("sg_prevent failed: ", ret))
189 pr2serr("Some error occurred, try again with '-v' "
190 "or '-vv' for more information\n");
191 }
192 return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
193 }
194