]>
Commit | Line | Data |
---|---|---|
832b75ed | 1 | /* |
4d59bff9 | 2 | * smartctl.cpp |
832b75ed GG |
3 | * |
4 | * Home page of code is: http://smartmontools.sourceforge.net | |
5 | * | |
f4ebf3d1 GI |
6 | * Copyright (C) 2002-10 Bruce Allen <smartmontools-support@lists.sourceforge.net> |
7 | * Copyright (C) 2008-10 Christian Franke <smartmontools-support@lists.sourceforge.net> | |
832b75ed GG |
8 | * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org> |
9 | * | |
10 | * This program is free software; you can redistribute it and/or modify | |
11 | * it under the terms of the GNU General Public License as published by | |
12 | * the Free Software Foundation; either version 2, or (at your option) | |
13 | * any later version. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License | |
16 | * (for example COPYING); if not, write to the Free | |
17 | * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
18 | * | |
19 | * This code was originally developed as a Senior Thesis by Michael Cornwell | |
20 | * at the Concurrent Systems Laboratory (now part of the Storage Systems | |
21 | * Research Center), Jack Baskin School of Engineering, University of | |
22 | * California, Santa Cruz. http://ssrc.soe.ucsc.edu/ | |
23 | * | |
24 | */ | |
25 | ||
26 | #include <errno.h> | |
27 | #include <stdio.h> | |
28 | #include <sys/types.h> | |
29 | #include <string.h> | |
30 | #include <stdarg.h> | |
2127e193 GI |
31 | #include <stdexcept> |
32 | #include <getopt.h> | |
832b75ed GG |
33 | |
34 | #include "config.h" | |
2127e193 GI |
35 | |
36 | #ifdef HAVE_UNISTD_H | |
832b75ed GG |
37 | #include <unistd.h> |
38 | #endif | |
39 | ||
2127e193 GI |
40 | #if defined(__FreeBSD__) |
41 | #include <sys/param.h> | |
a37e7145 GG |
42 | #endif |
43 | ||
2127e193 GI |
44 | #if defined(__QNXNTO__) |
45 | #include <new> // TODO: Why is this include necessary on QNX ? | |
46 | #endif | |
a37e7145 | 47 | |
832b75ed GG |
48 | #include "int64.h" |
49 | #include "atacmds.h" | |
2127e193 | 50 | #include "dev_interface.h" |
832b75ed GG |
51 | #include "ataprint.h" |
52 | #include "extern.h" | |
53 | #include "knowndrives.h" | |
54 | #include "scsicmds.h" | |
55 | #include "scsiprint.h" | |
56 | #include "smartctl.h" | |
57 | #include "utility.h" | |
58 | ||
7f0798ef | 59 | const char * smartctl_cpp_cvsid = "$Id: smartctl.cpp 3065 2010-02-10 22:16:50Z chrfranke $" |
2127e193 | 60 | CONFIG_H_CVSID EXTERN_H_CVSID SMARTCTL_H_CVSID; |
832b75ed GG |
61 | |
62 | // This is a block containing all the "control variables". We declare | |
63 | // this globally in this file, and externally in other files. | |
64 | smartmonctrl *con=NULL; | |
65 | ||
2127e193 GI |
66 | static void printslogan() |
67 | { | |
68 | pout("%s\n", format_version_info("smartctl").c_str()); | |
832b75ed GG |
69 | } |
70 | ||
71 | void UsageSummary(){ | |
72 | pout("\nUse smartctl -h to get a usage summary\n\n"); | |
73 | return; | |
74 | } | |
75 | ||
54965743 | 76 | static std::string getvalidarglist(char opt); |
2127e193 | 77 | |
832b75ed GG |
78 | /* void prints help information for command syntax */ |
79 | void Usage (void){ | |
80 | printf("Usage: smartctl [options] device\n\n"); | |
832b75ed | 81 | printf( |
2127e193 | 82 | "============================================ SHOW INFORMATION OPTIONS =====\n\n" |
832b75ed GG |
83 | " -h, --help, --usage\n" |
84 | " Display this help and exit\n\n" | |
85 | " -V, --version, --copyright, --license\n" | |
86 | " Print license, copyright, and version information and exit\n\n" | |
87 | " -i, --info \n" | |
88 | " Show identity information for device\n\n" | |
89 | " -a, --all \n" | |
90 | " Show all SMART information for device\n\n" | |
2127e193 GI |
91 | " -x, --xall\n" |
92 | " Show all information for device\n\n" | |
832b75ed | 93 | ); |
832b75ed | 94 | printf( |
2127e193 | 95 | "================================== SMARTCTL RUN-TIME BEHAVIOR OPTIONS =====\n\n" |
832b75ed | 96 | " -q TYPE, --quietmode=TYPE (ATA)\n" |
a37e7145 | 97 | " Set smartctl quiet mode to one of: errorsonly, silent, noserial\n\n" |
832b75ed | 98 | " -d TYPE, --device=TYPE\n" |
2127e193 | 99 | " Specify device type to one of: %s\n\n" |
832b75ed GG |
100 | " -T TYPE, --tolerance=TYPE (ATA)\n" |
101 | " Tolerance: normal, conservative, permissive, verypermissive\n\n" | |
102 | " -b TYPE, --badsum=TYPE (ATA)\n" | |
103 | " Set action on bad checksum to one of: warn, exit, ignore\n\n" | |
104 | " -r TYPE, --report=TYPE\n" | |
105 | " Report transactions (see man page)\n\n" | |
4d59bff9 | 106 | " -n MODE, --nocheck=MODE (ATA)\n" |
2127e193 | 107 | " No check if: never, sleep, standby, idle (see man page)\n\n", |
54965743 | 108 | getvalidarglist('d').c_str()); // TODO: Use this function also for other options ? |
832b75ed | 109 | printf( |
2127e193 | 110 | "============================== DEVICE FEATURE ENABLE/DISABLE COMMANDS =====\n\n" |
832b75ed GG |
111 | " -s VALUE, --smart=VALUE\n" |
112 | " Enable/disable SMART on device (on/off)\n\n" | |
113 | " -o VALUE, --offlineauto=VALUE (ATA)\n" | |
114 | " Enable/disable automatic offline testing on device (on/off)\n\n" | |
115 | " -S VALUE, --saveauto=VALUE (ATA)\n" | |
116 | " Enable/disable Attribute autosave on device (on/off)\n\n" | |
117 | ); | |
832b75ed | 118 | printf( |
2127e193 | 119 | "======================================= READ AND DISPLAY DATA OPTIONS =====\n\n" |
832b75ed GG |
120 | " -H, --health\n" |
121 | " Show device SMART health status\n\n" | |
122 | " -c, --capabilities (ATA)\n" | |
123 | " Show device SMART capabilities\n\n" | |
124 | " -A, --attributes \n" | |
125 | " Show device SMART vendor-specific Attributes and values\n\n" | |
126 | " -l TYPE, --log=TYPE\n" | |
2127e193 GI |
127 | " Show device log. TYPE: error, selftest, selective, directory[,g|s],\n" |
128 | " background, sasphy[,reset], sataphy[,reset],\n" | |
7f0798ef | 129 | " scttemp[sts,hist], scterc[,N,M],\n" |
2127e193 GI |
130 | " gplog,N[,RANGE], smartlog,N[,RANGE],\n" |
131 | " xerror[,N][,error], xselftest[,N][,selftest]\n\n" | |
832b75ed GG |
132 | " -v N,OPTION , --vendorattribute=N,OPTION (ATA)\n" |
133 | " Set display OPTION for vendor Attribute N (see man page)\n\n" | |
134 | " -F TYPE, --firmwarebug=TYPE (ATA)\n" | |
a37e7145 GG |
135 | " Use firmware bug workaround: none, samsung, samsung2,\n" |
136 | " samsung3, swapid\n\n" | |
832b75ed GG |
137 | " -P TYPE, --presets=TYPE (ATA)\n" |
138 | " Drive-specific presets: use, ignore, show, showall\n\n" | |
2127e193 GI |
139 | " -B [+]FILE, --drivedb=[+]FILE (ATA)\n" |
140 | " Read and replace [add] drive database from FILE\n" | |
141 | #ifdef SMARTMONTOOLS_DRIVEDBDIR | |
142 | " [default is "SMARTMONTOOLS_DRIVEDBDIR"/drivedb.h]\n" | |
832b75ed | 143 | #endif |
2127e193 GI |
144 | "\n" |
145 | ); | |
832b75ed | 146 | printf( |
2127e193 | 147 | "============================================ DEVICE SELF-TEST OPTIONS =====\n\n" |
832b75ed | 148 | " -t TEST, --test=TEST\n" |
a37e7145 GG |
149 | " Run test. TEST: offline short long conveyance select,M-N\n" |
150 | " pending,N afterselect,[on|off] scttempint,N[,p]\n\n" | |
832b75ed GG |
151 | " -C, --captive\n" |
152 | " Do test in captive mode (along with -t)\n\n" | |
153 | " -X, --abort\n" | |
154 | " Abort any non-captive test on device\n\n" | |
155 | ); | |
54965743 GI |
156 | std::string examples = smi()->get_app_examples("smartctl"); |
157 | if (!examples.empty()) | |
158 | printf("%s\n", examples.c_str()); | |
832b75ed GG |
159 | } |
160 | ||
54965743 GI |
161 | /* Returns a string containing a formatted list of the valid arguments |
162 | to the option opt or empty on failure. Note 'v' case different */ | |
163 | static std::string getvalidarglist(char opt) | |
2127e193 | 164 | { |
832b75ed GG |
165 | switch (opt) { |
166 | case 'q': | |
a37e7145 | 167 | return "errorsonly, silent, noserial"; |
832b75ed | 168 | case 'd': |
54965743 | 169 | return smi()->get_valid_dev_types_str() + ", test"; |
832b75ed GG |
170 | case 'T': |
171 | return "normal, conservative, permissive, verypermissive"; | |
172 | case 'b': | |
173 | return "warn, exit, ignore"; | |
174 | case 'r': | |
175 | return "ioctl[,N], ataioctl[,N], scsiioctl[,N]"; | |
176 | case 's': | |
177 | case 'o': | |
178 | case 'S': | |
179 | return "on, off"; | |
180 | case 'l': | |
7f0798ef | 181 | return "error, selftest, selective, directory[,g|s], background, scttemp[sts|hist], scterc[,N,M], " |
2127e193 GI |
182 | "sasphy[,reset], sataphy[,reset], gplog,N[,RANGE], smartlog,N[,RANGE], " |
183 | "xerror[,N][,error], xselftest[,N][,selftest]"; | |
832b75ed GG |
184 | case 'P': |
185 | return "use, ignore, show, showall"; | |
186 | case 't': | |
a37e7145 | 187 | return "offline, short, long, conveyance, select,M-N, pending,N, afterselect,[on|off], scttempint,N[,p]"; |
832b75ed | 188 | case 'F': |
a37e7145 | 189 | return "none, samsung, samsung2, samsung3, swapid"; |
4d59bff9 GG |
190 | case 'n': |
191 | return "never, sleep, standby, idle"; | |
832b75ed GG |
192 | case 'v': |
193 | default: | |
54965743 | 194 | return ""; |
832b75ed GG |
195 | } |
196 | } | |
197 | ||
198 | /* Prints the message "=======> VALID ARGUMENTS ARE: <LIST> \n", where | |
199 | <LIST> is the list of valid arguments for option opt. */ | |
200 | void printvalidarglistmessage(char opt) { | |
832b75ed GG |
201 | |
202 | if (opt=='v'){ | |
2127e193 GI |
203 | pout("=======> VALID ARGUMENTS ARE:\n\thelp\n%s\n<=======\n", |
204 | create_vendor_attribute_arg_list().c_str()); | |
832b75ed GG |
205 | } |
206 | else { | |
207 | // getvalidarglist() might produce a multiline or single line string. We | |
208 | // need to figure out which to get the formatting right. | |
54965743 GI |
209 | std::string s = getvalidarglist(opt); |
210 | char separator = strchr(s.c_str(), '\n') ? '\n' : ' '; | |
211 | pout("=======> VALID ARGUMENTS ARE:%c%s%c<=======\n", separator, s.c_str(), separator); | |
832b75ed GG |
212 | } |
213 | ||
214 | return; | |
215 | } | |
216 | ||
2127e193 GI |
217 | // Checksum error mode |
218 | enum checksum_err_mode_t { | |
219 | CHECKSUM_ERR_WARN, CHECKSUM_ERR_EXIT, CHECKSUM_ERR_IGNORE | |
220 | }; | |
221 | ||
222 | static checksum_err_mode_t checksum_err_mode = CHECKSUM_ERR_WARN; | |
223 | ||
832b75ed | 224 | /* Takes command options and sets features to be run */ |
2127e193 GI |
225 | const char * parse_options(int argc, char** argv, |
226 | ata_print_options & ataopts, | |
227 | scsi_print_options & scsiopts) | |
228 | { | |
832b75ed | 229 | // Please update getvalidarglist() if you edit shortopts |
2127e193 | 230 | const char *shortopts = "h?Vq:d:T:b:r:s:o:S:HcAl:iaxv:P:t:CXF:n:B:"; |
832b75ed GG |
231 | // Please update getvalidarglist() if you edit longopts |
232 | struct option longopts[] = { | |
233 | { "help", no_argument, 0, 'h' }, | |
234 | { "usage", no_argument, 0, 'h' }, | |
235 | { "version", no_argument, 0, 'V' }, | |
236 | { "copyright", no_argument, 0, 'V' }, | |
237 | { "license", no_argument, 0, 'V' }, | |
238 | { "quietmode", required_argument, 0, 'q' }, | |
239 | { "device", required_argument, 0, 'd' }, | |
240 | { "tolerance", required_argument, 0, 'T' }, | |
241 | { "badsum", required_argument, 0, 'b' }, | |
242 | { "report", required_argument, 0, 'r' }, | |
243 | { "smart", required_argument, 0, 's' }, | |
244 | { "offlineauto", required_argument, 0, 'o' }, | |
245 | { "saveauto", required_argument, 0, 'S' }, | |
246 | { "health", no_argument, 0, 'H' }, | |
247 | { "capabilities", no_argument, 0, 'c' }, | |
248 | { "attributes", no_argument, 0, 'A' }, | |
249 | { "log", required_argument, 0, 'l' }, | |
250 | { "info", no_argument, 0, 'i' }, | |
251 | { "all", no_argument, 0, 'a' }, | |
2127e193 | 252 | { "xall", no_argument, 0, 'x' }, |
832b75ed GG |
253 | { "vendorattribute", required_argument, 0, 'v' }, |
254 | { "presets", required_argument, 0, 'P' }, | |
255 | { "test", required_argument, 0, 't' }, | |
256 | { "captive", no_argument, 0, 'C' }, | |
257 | { "abort", no_argument, 0, 'X' }, | |
258 | { "firmwarebug", required_argument, 0, 'F' }, | |
4d59bff9 | 259 | { "nocheck", required_argument, 0, 'n' }, |
2127e193 | 260 | { "drivedb", required_argument, 0, 'B' }, |
832b75ed GG |
261 | { 0, 0, 0, 0 } |
262 | }; | |
2127e193 GI |
263 | |
264 | char extraerror[256]; | |
832b75ed GG |
265 | memset(extraerror, 0, sizeof(extraerror)); |
266 | memset(con,0,sizeof(*con)); | |
832b75ed | 267 | opterr=optopt=0; |
2127e193 GI |
268 | |
269 | const char * type = 0; // set to -d optarg | |
270 | bool no_defaultdb = false; // set true on '-B FILE' | |
271 | bool badarg = false, captive = false; | |
272 | int testcnt = 0; // number of self-tests requested | |
273 | ||
274 | int optchar; | |
275 | char *arg; | |
276 | ||
832b75ed GG |
277 | // This miserable construction is needed to get emacs to do proper indenting. Sorry! |
278 | while (-1 != (optchar = | |
832b75ed | 279 | getopt_long(argc, argv, shortopts, longopts, NULL) |
832b75ed GG |
280 | )){ |
281 | switch (optchar){ | |
282 | case 'V': | |
2127e193 GI |
283 | con->dont_print = false; |
284 | pout("%s", format_version_info("smartctl", true /*full*/).c_str()); | |
285 | EXIT(0); | |
832b75ed GG |
286 | break; |
287 | case 'q': | |
288 | if (!strcmp(optarg,"errorsonly")) { | |
2127e193 GI |
289 | con->printing_switchable = true; |
290 | con->dont_print = false; | |
832b75ed | 291 | } else if (!strcmp(optarg,"silent")) { |
2127e193 GI |
292 | con->printing_switchable = false; |
293 | con->dont_print = true; | |
a37e7145 | 294 | } else if (!strcmp(optarg,"noserial")) { |
2127e193 | 295 | con->dont_print_serial = true; |
832b75ed | 296 | } else { |
2127e193 | 297 | badarg = true; |
832b75ed GG |
298 | } |
299 | break; | |
300 | case 'd': | |
2127e193 | 301 | type = optarg; |
832b75ed GG |
302 | break; |
303 | case 'T': | |
304 | if (!strcmp(optarg,"normal")) { | |
2127e193 | 305 | con->conservative = false; |
832b75ed GG |
306 | con->permissive = 0; |
307 | } else if (!strcmp(optarg,"conservative")) { | |
2127e193 | 308 | con->conservative = true; |
832b75ed GG |
309 | } else if (!strcmp(optarg,"permissive")) { |
310 | if (con->permissive<0xff) | |
311 | con->permissive++; | |
312 | } else if (!strcmp(optarg,"verypermissive")) { | |
2127e193 | 313 | con->permissive = 0xff; |
832b75ed | 314 | } else { |
2127e193 | 315 | badarg = true; |
832b75ed GG |
316 | } |
317 | break; | |
318 | case 'b': | |
319 | if (!strcmp(optarg,"warn")) { | |
2127e193 | 320 | checksum_err_mode = CHECKSUM_ERR_WARN; |
832b75ed | 321 | } else if (!strcmp(optarg,"exit")) { |
2127e193 | 322 | checksum_err_mode = CHECKSUM_ERR_EXIT; |
832b75ed | 323 | } else if (!strcmp(optarg,"ignore")) { |
2127e193 | 324 | checksum_err_mode = CHECKSUM_ERR_IGNORE; |
832b75ed | 325 | } else { |
2127e193 | 326 | badarg = true; |
832b75ed GG |
327 | } |
328 | break; | |
329 | case 'r': | |
330 | { | |
331 | int i; | |
332 | char *s; | |
333 | ||
334 | // split_report_arg() may modify its first argument string, so use a | |
335 | // copy of optarg in case we want optarg for an error message. | |
336 | if (!(s = strdup(optarg))) { | |
2127e193 | 337 | throw std::bad_alloc(); |
832b75ed GG |
338 | } |
339 | if (split_report_arg(s, &i)) { | |
2127e193 | 340 | badarg = true; |
832b75ed GG |
341 | } else if (!strcmp(s,"ioctl")) { |
342 | con->reportataioctl = con->reportscsiioctl = i; | |
343 | } else if (!strcmp(s,"ataioctl")) { | |
344 | con->reportataioctl = i; | |
345 | } else if (!strcmp(s,"scsiioctl")) { | |
346 | con->reportscsiioctl = i; | |
347 | } else { | |
2127e193 | 348 | badarg = true; |
832b75ed GG |
349 | } |
350 | free(s); | |
351 | } | |
352 | break; | |
353 | case 's': | |
354 | if (!strcmp(optarg,"on")) { | |
2127e193 GI |
355 | ataopts.smart_enable = scsiopts.smart_enable = true; |
356 | ataopts.smart_disable = scsiopts.smart_disable = false; | |
832b75ed | 357 | } else if (!strcmp(optarg,"off")) { |
2127e193 GI |
358 | ataopts.smart_disable = scsiopts.smart_disable = true; |
359 | ataopts.smart_enable = scsiopts.smart_enable = false; | |
832b75ed | 360 | } else { |
2127e193 | 361 | badarg = true; |
832b75ed GG |
362 | } |
363 | break; | |
364 | case 'o': | |
365 | if (!strcmp(optarg,"on")) { | |
2127e193 GI |
366 | ataopts.smart_auto_offl_enable = true; |
367 | ataopts.smart_auto_offl_disable = false; | |
832b75ed | 368 | } else if (!strcmp(optarg,"off")) { |
2127e193 GI |
369 | ataopts.smart_auto_offl_disable = true; |
370 | ataopts.smart_auto_offl_enable = false; | |
832b75ed | 371 | } else { |
2127e193 | 372 | badarg = true; |
832b75ed GG |
373 | } |
374 | break; | |
375 | case 'S': | |
376 | if (!strcmp(optarg,"on")) { | |
2127e193 GI |
377 | ataopts.smart_auto_save_enable = scsiopts.smart_auto_save_enable = true; |
378 | ataopts.smart_auto_save_disable = scsiopts.smart_auto_save_disable = false; | |
832b75ed | 379 | } else if (!strcmp(optarg,"off")) { |
2127e193 GI |
380 | ataopts.smart_auto_save_disable = scsiopts.smart_auto_save_disable = true; |
381 | ataopts.smart_auto_save_enable = scsiopts.smart_auto_save_enable = false; | |
832b75ed | 382 | } else { |
2127e193 | 383 | badarg = true; |
832b75ed GG |
384 | } |
385 | break; | |
386 | case 'H': | |
2127e193 | 387 | ataopts.smart_check_status = scsiopts.smart_check_status = true; |
832b75ed GG |
388 | break; |
389 | case 'F': | |
390 | if (!strcmp(optarg,"none")) { | |
2127e193 | 391 | ataopts.fix_firmwarebug = FIX_NONE; |
832b75ed | 392 | } else if (!strcmp(optarg,"samsung")) { |
2127e193 | 393 | ataopts.fix_firmwarebug = FIX_SAMSUNG; |
832b75ed | 394 | } else if (!strcmp(optarg,"samsung2")) { |
2127e193 | 395 | ataopts.fix_firmwarebug = FIX_SAMSUNG2; |
a37e7145 | 396 | } else if (!strcmp(optarg,"samsung3")) { |
2127e193 | 397 | ataopts.fix_firmwarebug = FIX_SAMSUNG3; |
a37e7145 | 398 | } else if (!strcmp(optarg,"swapid")) { |
2127e193 | 399 | ataopts.fix_swapped_id = true; |
832b75ed | 400 | } else { |
2127e193 | 401 | badarg = true; |
832b75ed GG |
402 | } |
403 | break; | |
404 | case 'c': | |
2127e193 | 405 | ataopts.smart_general_values = true; |
832b75ed GG |
406 | break; |
407 | case 'A': | |
2127e193 | 408 | ataopts.smart_vendor_attrib = scsiopts.smart_vendor_attrib = true; |
832b75ed GG |
409 | break; |
410 | case 'l': | |
411 | if (!strcmp(optarg,"error")) { | |
2127e193 | 412 | ataopts.smart_error_log = scsiopts.smart_error_log = true; |
832b75ed | 413 | } else if (!strcmp(optarg,"selftest")) { |
2127e193 | 414 | ataopts.smart_selftest_log = scsiopts.smart_selftest_log = true; |
832b75ed | 415 | } else if (!strcmp(optarg, "selective")) { |
2127e193 | 416 | ataopts.smart_selective_selftest_log = true; |
832b75ed | 417 | } else if (!strcmp(optarg,"directory")) { |
2127e193 GI |
418 | ataopts.smart_logdir = ataopts.gp_logdir = true; // SMART+GPL |
419 | } else if (!strcmp(optarg,"directory,s")) { | |
420 | ataopts.smart_logdir = true; // SMART | |
421 | } else if (!strcmp(optarg,"directory,g")) { | |
422 | ataopts.gp_logdir = true; // GPL | |
423 | } else if (!strcmp(optarg,"sasphy")) { | |
424 | scsiopts.sasphy = true; | |
425 | } else if (!strcmp(optarg,"sasphy,reset")) { | |
426 | scsiopts.sasphy = scsiopts.sasphy_reset = true; | |
427 | } else if (!strcmp(optarg,"sataphy")) { | |
428 | ataopts.sataphy = true; | |
429 | } else if (!strcmp(optarg,"sataphy,reset")) { | |
430 | ataopts.sataphy = ataopts.sataphy_reset = true; | |
4d59bff9 | 431 | } else if (!strcmp(optarg,"background")) { |
2127e193 | 432 | scsiopts.smart_background_log = true; |
7f0798ef GI |
433 | } else if (!strcmp(optarg,"scterc")) { |
434 | ataopts.sct_erc_get = true; | |
a37e7145 | 435 | } else if (!strcmp(optarg,"scttemp")) { |
2127e193 | 436 | ataopts.sct_temp_sts = ataopts.sct_temp_hist = true; |
a37e7145 | 437 | } else if (!strcmp(optarg,"scttempsts")) { |
2127e193 | 438 | ataopts.sct_temp_sts = true; |
a37e7145 | 439 | } else if (!strcmp(optarg,"scttemphist")) { |
2127e193 GI |
440 | ataopts.sct_temp_hist = true; |
441 | ||
442 | } else if (!strncmp(optarg, "xerror", sizeof("xerror")-1)) { | |
443 | int n1 = -1, n2 = -1, len = strlen(optarg); | |
444 | unsigned val = 8; | |
445 | sscanf(optarg, "xerror%n,error%n", &n1, &n2); | |
446 | if (!(n1 == len || n2 == len)) { | |
447 | n1 = n2 = -1; | |
448 | sscanf(optarg, "xerror,%u%n,error%n", &val, &n1, &n2); | |
449 | } | |
450 | if ((n1 == len || n2 == len) && val > 0) { | |
451 | ataopts.smart_ext_error_log = val; | |
452 | ataopts.retry_error_log = (n2 == len); | |
453 | } | |
454 | else | |
455 | badarg = true; | |
456 | ||
457 | } else if (!strncmp(optarg, "xselftest", sizeof("xselftest")-1)) { | |
458 | int n1 = -1, n2 = -1, len = strlen(optarg); | |
459 | unsigned val = 25; | |
460 | sscanf(optarg, "xselftest%n,selftest%n", &n1, &n2); | |
461 | if (!(n1 == len || n2 == len)) { | |
462 | n1 = n2 = -1; | |
463 | sscanf(optarg, "xselftest,%u%n,selftest%n", &val, &n1, &n2); | |
464 | } | |
465 | if ((n1 == len || n2 == len) && val > 0) { | |
466 | ataopts.smart_ext_selftest_log = val; | |
467 | ataopts.retry_selftest_log = (n2 == len); | |
468 | } | |
469 | else | |
470 | badarg = true; | |
471 | ||
7f0798ef GI |
472 | } else if (!strncmp(optarg, "scterc,", sizeof("scterc,")-1)) { |
473 | unsigned rt = ~0, wt = ~0; int n = -1; | |
474 | sscanf(optarg,"scterc,%u,%u%n", &rt, &wt, &n); | |
475 | if (n == (int)strlen(optarg) && rt <= 999 && wt <= 999) { | |
476 | ataopts.sct_erc_set = true; | |
477 | ataopts.sct_erc_readtime = rt; | |
478 | ataopts.sct_erc_writetime = wt; | |
479 | } | |
480 | else { | |
481 | sprintf(extraerror, "Option -l scterc,[READTIME,WRITETIME] syntax error\n"); | |
482 | badarg = true; | |
483 | } | |
2127e193 GI |
484 | } else if ( !strncmp(optarg, "gplog," , sizeof("gplog," )-1) |
485 | || !strncmp(optarg, "smartlog,", sizeof("smartlog,")-1)) { | |
486 | unsigned logaddr = ~0U; unsigned page = 0, nsectors = 1; char sign = 0; | |
487 | int n1 = -1, n2 = -1, n3 = -1, len = strlen(optarg); | |
488 | sscanf(optarg, "%*[a-z],0x%x%n,%u%n%c%u%n", | |
489 | &logaddr, &n1, &page, &n2, &sign, &nsectors, &n3); | |
490 | if (len > n2 && n3 == -1 && !strcmp(optarg+n2, "-max")) { | |
491 | nsectors = ~0U; sign = '+'; n3 = len; | |
492 | } | |
493 | bool gpl = (optarg[0] == 'g'); | |
494 | const char * erropt = (gpl ? "gplog" : "smartlog"); | |
495 | if (!( n1 == len || n2 == len | |
496 | || (n3 == len && (sign == '+' || sign == '-')))) { | |
497 | sprintf(extraerror, "Option -l %s,ADDR[,FIRST[-LAST|+SIZE]] syntax error\n", erropt); | |
498 | badarg = true; | |
499 | } | |
500 | else if (!( logaddr <= 0xff && page <= (gpl ? 0xffffU : 0x00ffU) | |
501 | && 0 < nsectors | |
502 | && (nsectors <= (gpl ? 0xffffU : 0xffU) || nsectors == ~0U) | |
503 | && (sign != '-' || page <= nsectors) )) { | |
504 | sprintf(extraerror, "Option -l %s,ADDR[,FIRST[-LAST|+SIZE]] parameter out of range\n", erropt); | |
505 | badarg = true; | |
506 | } | |
507 | else { | |
508 | ata_log_request req; | |
509 | req.gpl = gpl; req.logaddr = logaddr; req.page = page; | |
510 | req.nsectors = (sign == '-' ? nsectors-page+1 : nsectors); | |
511 | ataopts.log_requests.push_back(req); | |
512 | } | |
832b75ed | 513 | } else { |
2127e193 | 514 | badarg = true; |
832b75ed GG |
515 | } |
516 | break; | |
517 | case 'i': | |
2127e193 GI |
518 | ataopts.drive_info = scsiopts.drive_info = true; |
519 | break; | |
832b75ed | 520 | case 'a': |
2127e193 GI |
521 | ataopts.drive_info = scsiopts.drive_info = true; |
522 | ataopts.smart_check_status = scsiopts.smart_check_status = true; | |
523 | ataopts.smart_general_values = true; | |
524 | ataopts.smart_vendor_attrib = scsiopts.smart_vendor_attrib = true; | |
525 | ataopts.smart_error_log = scsiopts.smart_error_log = true; | |
526 | ataopts.smart_selftest_log = scsiopts.smart_selftest_log = true; | |
527 | ataopts.smart_selective_selftest_log = true; | |
528 | /* scsiopts.smart_background_log = true; */ | |
529 | break; | |
530 | case 'x': | |
531 | ataopts.drive_info = scsiopts.drive_info = true; | |
532 | ataopts.smart_check_status = scsiopts.smart_check_status = true; | |
533 | ataopts.smart_general_values = true; | |
534 | ataopts.smart_vendor_attrib = scsiopts.smart_vendor_attrib = true; | |
535 | ataopts.smart_ext_error_log = 8; | |
536 | ataopts.retry_error_log = true; | |
537 | ataopts.smart_ext_selftest_log = 25; | |
538 | ataopts.retry_selftest_log = true; | |
539 | scsiopts.smart_error_log = scsiopts.smart_selftest_log = true; | |
540 | ataopts.smart_selective_selftest_log = true; | |
541 | ataopts.smart_logdir = ataopts.gp_logdir = true; | |
542 | ataopts.sct_temp_sts = ataopts.sct_temp_hist = true; | |
7f0798ef | 543 | ataopts.sct_erc_get = true; |
2127e193 GI |
544 | ataopts.sataphy = true; |
545 | scsiopts.smart_background_log = true; | |
546 | scsiopts.sasphy = true; | |
832b75ed GG |
547 | break; |
548 | case 'v': | |
549 | // parse vendor-specific definitions of attributes | |
550 | if (!strcmp(optarg,"help")) { | |
2127e193 | 551 | con->dont_print = false; |
832b75ed | 552 | printslogan(); |
2127e193 GI |
553 | pout("The valid arguments to -v are:\n\thelp\n%s\n", |
554 | create_vendor_attribute_arg_list().c_str()); | |
832b75ed GG |
555 | EXIT(0); |
556 | } | |
bed94269 | 557 | if (!parse_attribute_def(optarg, ataopts.attribute_defs, PRIOR_USER)) |
2127e193 | 558 | badarg = true; |
832b75ed GG |
559 | break; |
560 | case 'P': | |
561 | if (!strcmp(optarg, "use")) { | |
2127e193 | 562 | ataopts.ignore_presets = false; |
832b75ed | 563 | } else if (!strcmp(optarg, "ignore")) { |
2127e193 | 564 | ataopts.ignore_presets = true; |
832b75ed | 565 | } else if (!strcmp(optarg, "show")) { |
2127e193 | 566 | ataopts.show_presets = true; |
832b75ed | 567 | } else if (!strcmp(optarg, "showall")) { |
2127e193 GI |
568 | if (!no_defaultdb && !read_default_drive_databases()) |
569 | EXIT(FAILCMD); | |
832b75ed GG |
570 | if (optind < argc) { // -P showall MODEL [FIRMWARE] |
571 | int cnt = showmatchingpresets(argv[optind], (optind+1<argc ? argv[optind+1] : NULL)); | |
572 | EXIT(cnt); // report #matches | |
573 | } | |
574 | if (showallpresets()) | |
575 | EXIT(FAILCMD); // report regexp syntax error | |
576 | EXIT(0); | |
577 | } else { | |
2127e193 | 578 | badarg = true; |
832b75ed GG |
579 | } |
580 | break; | |
581 | case 't': | |
582 | if (!strcmp(optarg,"offline")) { | |
2127e193 GI |
583 | testcnt++; |
584 | ataopts.smart_selftest_type = OFFLINE_FULL_SCAN; | |
585 | scsiopts.smart_default_selftest = true; | |
832b75ed | 586 | } else if (!strcmp(optarg,"short")) { |
2127e193 GI |
587 | testcnt++; |
588 | ataopts.smart_selftest_type = SHORT_SELF_TEST; | |
589 | scsiopts.smart_short_selftest = true; | |
832b75ed | 590 | } else if (!strcmp(optarg,"long")) { |
2127e193 GI |
591 | testcnt++; |
592 | ataopts.smart_selftest_type = EXTEND_SELF_TEST; | |
593 | scsiopts.smart_extend_selftest = true; | |
832b75ed | 594 | } else if (!strcmp(optarg,"conveyance")) { |
2127e193 GI |
595 | testcnt++; |
596 | ataopts.smart_selftest_type = CONVEYANCE_SELF_TEST; | |
832b75ed | 597 | } else if (!strcmp(optarg,"afterselect,on")) { |
2127e193 GI |
598 | // scan remainder of disk after doing selected segment |
599 | ataopts.smart_selective_args.scan_after_select = 2; | |
832b75ed | 600 | } else if (!strcmp(optarg,"afterselect,off")) { |
2127e193 GI |
601 | // don't scan remainder of disk after doing selected segments |
602 | ataopts.smart_selective_args.scan_after_select = 1; | |
832b75ed GG |
603 | } else if (!strncmp(optarg,"pending,",strlen("pending,"))) { |
604 | // parse number of minutes that test should be pending | |
605 | int i; | |
606 | char *tailptr=NULL; | |
607 | errno=0; | |
608 | i=(int)strtol(optarg+strlen("pending,"), &tailptr, 10); | |
609 | if (errno || *tailptr != '\0') { | |
610 | sprintf(extraerror, "Option -t pending,N requires N to be a non-negative integer\n"); | |
2127e193 | 611 | badarg = true; |
832b75ed GG |
612 | } else if (i<0 || i>65535) { |
613 | sprintf(extraerror, "Option -t pending,N (N=%d) must have 0 <= N <= 65535\n", i); | |
2127e193 | 614 | badarg = true; |
832b75ed | 615 | } else { |
2127e193 | 616 | ataopts.smart_selective_args.pending_time = i+1; |
832b75ed GG |
617 | } |
618 | } else if (!strncmp(optarg,"select",strlen("select"))) { | |
2127e193 | 619 | testcnt++; |
a37e7145 GG |
620 | // parse range of LBAs to test |
621 | uint64_t start, stop; int mode; | |
622 | if (split_selective_arg(optarg, &start, &stop, &mode)) { | |
832b75ed | 623 | sprintf(extraerror, "Option -t select,M-N must have non-negative integer M and N\n"); |
2127e193 | 624 | badarg = true; |
832b75ed | 625 | } else { |
2127e193 | 626 | if (ataopts.smart_selective_args.num_spans >= 5 || start > stop) { |
832b75ed GG |
627 | if (start > stop) { |
628 | sprintf(extraerror, "ERROR: Start LBA (%"PRIu64") > ending LBA (%"PRId64") in argument \"%s\"\n", | |
629 | start, stop, optarg); | |
630 | } else { | |
631 | sprintf(extraerror,"ERROR: No more than five selective self-test spans may be" | |
632 | " defined\n"); | |
633 | } | |
2127e193 | 634 | badarg = true; |
832b75ed | 635 | } |
2127e193 GI |
636 | ataopts.smart_selective_args.span[ataopts.smart_selective_args.num_spans].start = start; |
637 | ataopts.smart_selective_args.span[ataopts.smart_selective_args.num_spans].end = stop; | |
638 | ataopts.smart_selective_args.span[ataopts.smart_selective_args.num_spans].mode = mode; | |
639 | ataopts.smart_selective_args.num_spans++; | |
640 | ataopts.smart_selftest_type = SELECTIVE_SELF_TEST; | |
832b75ed | 641 | } |
a37e7145 GG |
642 | } else if (!strncmp(optarg, "scttempint,", sizeof("scstempint,")-1)) { |
643 | unsigned interval = 0; int n1 = -1, n2 = -1, len = strlen(optarg); | |
644 | if (!( sscanf(optarg,"scttempint,%u%n,p%n", &interval, &n1, &n2) == 1 | |
645 | && 0 < interval && interval <= 0xffff && (n1 == len || n2 == len))) { | |
646 | strcpy(extraerror, "Option -t scttempint,N[,p] must have positive integer N\n"); | |
2127e193 | 647 | badarg = true; |
a37e7145 | 648 | } |
2127e193 GI |
649 | ataopts.sct_temp_int = interval; |
650 | ataopts.sct_temp_int_pers = (n2 == len); | |
832b75ed | 651 | } else { |
2127e193 | 652 | badarg = true; |
832b75ed GG |
653 | } |
654 | break; | |
655 | case 'C': | |
2127e193 | 656 | captive = true; |
832b75ed GG |
657 | break; |
658 | case 'X': | |
2127e193 GI |
659 | testcnt++; |
660 | scsiopts.smart_selftest_abort = true; | |
661 | ataopts.smart_selftest_type = ABORT_SELF_TEST; | |
832b75ed | 662 | break; |
4d59bff9 GG |
663 | case 'n': |
664 | // skip disk check if in low-power mode | |
665 | if (!strcmp(optarg, "never")) | |
2127e193 | 666 | ataopts.powermode = 1; // do not skip, but print mode |
4d59bff9 | 667 | else if (!strcmp(optarg, "sleep")) |
2127e193 | 668 | ataopts.powermode = 2; |
4d59bff9 | 669 | else if (!strcmp(optarg, "standby")) |
2127e193 | 670 | ataopts.powermode = 3; |
4d59bff9 | 671 | else if (!strcmp(optarg, "idle")) |
2127e193 | 672 | ataopts.powermode = 4; |
4d59bff9 | 673 | else |
2127e193 GI |
674 | badarg = true; |
675 | break; | |
676 | case 'B': | |
677 | { | |
678 | const char * path = optarg; | |
679 | if (*path == '+' && path[1]) | |
680 | path++; | |
681 | else | |
682 | no_defaultdb = true; | |
683 | if (!read_drive_database(path)) | |
684 | EXIT(FAILCMD); | |
685 | } | |
4d59bff9 | 686 | break; |
832b75ed | 687 | case 'h': |
2127e193 | 688 | con->dont_print = false; |
832b75ed GG |
689 | printslogan(); |
690 | Usage(); | |
691 | EXIT(0); | |
692 | break; | |
693 | case '?': | |
694 | default: | |
2127e193 | 695 | con->dont_print = false; |
832b75ed | 696 | printslogan(); |
832b75ed GG |
697 | // Point arg to the argument in which this option was found. |
698 | arg = argv[optind-1]; | |
699 | // Check whether the option is a long option that doesn't map to -h. | |
700 | if (arg[1] == '-' && optchar != 'h') { | |
701 | // Iff optopt holds a valid option then argument must be missing. | |
702 | if (optopt && (strchr(shortopts, optopt) != NULL)) { | |
703 | pout("=======> ARGUMENT REQUIRED FOR OPTION: %s\n", arg+2); | |
704 | printvalidarglistmessage(optopt); | |
705 | } else | |
706 | pout("=======> UNRECOGNIZED OPTION: %s\n",arg+2); | |
707 | if (extraerror[0]) | |
708 | pout("=======> %s", extraerror); | |
709 | UsageSummary(); | |
710 | EXIT(FAILCMD); | |
711 | } | |
832b75ed GG |
712 | if (optopt) { |
713 | // Iff optopt holds a valid option then argument must be | |
714 | // missing. Note (BA) this logic seems to fail using Solaris | |
715 | // getopt! | |
716 | if (strchr(shortopts, optopt) != NULL) { | |
717 | pout("=======> ARGUMENT REQUIRED FOR OPTION: %c\n", optopt); | |
718 | printvalidarglistmessage(optopt); | |
719 | } else | |
720 | pout("=======> UNRECOGNIZED OPTION: %c\n",optopt); | |
721 | if (extraerror[0]) | |
722 | pout("=======> %s", extraerror); | |
723 | UsageSummary(); | |
724 | EXIT(FAILCMD); | |
725 | } | |
726 | Usage(); | |
727 | EXIT(0); | |
728 | } // closes switch statement to process command-line options | |
729 | ||
730 | // Check to see if option had an unrecognized or incorrect argument. | |
731 | if (badarg) { | |
732 | printslogan(); | |
733 | // It would be nice to print the actual option name given by the user | |
734 | // here, but we just print the short form. Please fix this if you know | |
735 | // a clean way to do it. | |
736 | pout("=======> INVALID ARGUMENT TO -%c: %s\n", optchar, optarg); | |
737 | printvalidarglistmessage(optchar); | |
738 | if (extraerror[0]) | |
739 | pout("=======> %s", extraerror); | |
740 | UsageSummary(); | |
741 | EXIT(FAILCMD); | |
742 | } | |
743 | } | |
744 | // At this point we have processed all command-line options. If the | |
745 | // print output is switchable, then start with the print output | |
746 | // turned off | |
747 | if (con->printing_switchable) | |
f4ebf3d1 | 748 | con->dont_print = true; |
832b75ed GG |
749 | |
750 | // error message if user has asked for more than one test | |
2127e193 GI |
751 | if (testcnt > 1) { |
752 | con->dont_print = false; | |
832b75ed GG |
753 | printslogan(); |
754 | pout("\nERROR: smartctl can only run a single test type (or abort) at a time.\n"); | |
755 | UsageSummary(); | |
756 | EXIT(FAILCMD); | |
757 | } | |
758 | ||
759 | // error message if user has set selective self-test options without | |
760 | // asking for a selective self-test | |
2127e193 GI |
761 | if ( (ataopts.smart_selective_args.pending_time || ataopts.smart_selective_args.scan_after_select) |
762 | && !ataopts.smart_selective_args.num_spans) { | |
763 | con->dont_print = false; | |
832b75ed | 764 | printslogan(); |
2127e193 | 765 | if (ataopts.smart_selective_args.pending_time) |
832b75ed GG |
766 | pout("\nERROR: smartctl -t pending,N must be used with -t select,N-M.\n"); |
767 | else | |
768 | pout("\nERROR: smartctl -t afterselect,(on|off) must be used with -t select,N-M.\n"); | |
769 | UsageSummary(); | |
770 | EXIT(FAILCMD); | |
771 | } | |
772 | ||
773 | // If captive option was used, change test type if appropriate. | |
2127e193 GI |
774 | if (captive) |
775 | switch (ataopts.smart_selftest_type) { | |
776 | case SHORT_SELF_TEST: | |
777 | ataopts.smart_selftest_type = SHORT_CAPTIVE_SELF_TEST; | |
778 | scsiopts.smart_short_selftest = false; | |
779 | scsiopts.smart_short_cap_selftest = true; | |
780 | break; | |
781 | case EXTEND_SELF_TEST: | |
782 | ataopts.smart_selftest_type = EXTEND_CAPTIVE_SELF_TEST; | |
783 | scsiopts.smart_extend_selftest = false; | |
784 | scsiopts.smart_extend_cap_selftest = true; | |
785 | break; | |
786 | case CONVEYANCE_SELF_TEST: | |
787 | ataopts.smart_selftest_type = CONVEYANCE_CAPTIVE_SELF_TEST; | |
788 | break; | |
789 | case SELECTIVE_SELF_TEST: | |
790 | ataopts.smart_selftest_type = SELECTIVE_CAPTIVE_SELF_TEST; | |
791 | break; | |
792 | } | |
793 | ||
832b75ed GG |
794 | // From here on, normal operations... |
795 | printslogan(); | |
796 | ||
797 | // Warn if the user has provided no device name | |
798 | if (argc-optind<1){ | |
799 | pout("ERROR: smartctl requires a device name as the final command-line argument.\n\n"); | |
800 | UsageSummary(); | |
801 | EXIT(FAILCMD); | |
802 | } | |
803 | ||
804 | // Warn if the user has provided more than one device name | |
805 | if (argc-optind>1){ | |
806 | int i; | |
807 | pout("ERROR: smartctl takes ONE device name as the final command-line argument.\n"); | |
808 | pout("You have provided %d device names:\n",argc-optind); | |
809 | for (i=0; i<argc-optind; i++) | |
810 | pout("%s\n",argv[optind+i]); | |
811 | UsageSummary(); | |
812 | EXIT(FAILCMD); | |
2127e193 GI |
813 | } |
814 | ||
815 | // Read or init drive database | |
816 | if (!no_defaultdb && !read_default_drive_databases()) | |
817 | EXIT(FAILCMD); | |
818 | ||
819 | return type; | |
832b75ed GG |
820 | } |
821 | ||
822 | // Printing function (controlled by global con->dont_print) | |
823 | // [From GLIBC Manual: Since the prototype doesn't specify types for | |
824 | // optional arguments, in a call to a variadic function the default | |
825 | // argument promotions are performed on the optional argument | |
826 | // values. This means the objects of type char or short int (whether | |
827 | // signed or not) are promoted to either int or unsigned int, as | |
828 | // appropriate.] | |
4d59bff9 | 829 | void pout(const char *fmt, ...){ |
832b75ed GG |
830 | va_list ap; |
831 | ||
832 | // initialize variable argument list | |
833 | va_start(ap,fmt); | |
834 | if (con->dont_print){ | |
835 | va_end(ap); | |
836 | return; | |
837 | } | |
838 | ||
839 | // print out | |
840 | vprintf(fmt,ap); | |
841 | va_end(ap); | |
842 | fflush(stdout); | |
843 | return; | |
844 | } | |
845 | ||
4d59bff9 | 846 | // This function is used by utility.cpp to report LOG_CRIT errors. |
832b75ed | 847 | // The smartctl version prints to stdout instead of syslog(). |
4d59bff9 | 848 | void PrintOut(int priority, const char *fmt, ...) { |
832b75ed GG |
849 | va_list ap; |
850 | ||
851 | // avoid warning message about unused variable from gcc -W: just | |
852 | // change value of local copy. | |
853 | priority=0; | |
854 | ||
855 | va_start(ap,fmt); | |
856 | vprintf(fmt,ap); | |
857 | va_end(ap); | |
858 | return; | |
859 | } | |
860 | ||
2127e193 GI |
861 | // Used to warn users about invalid checksums. Called from atacmds.cpp. |
862 | // Action to be taken may be altered by the user. | |
863 | void checksumwarning(const char * string) | |
864 | { | |
865 | // user has asked us to ignore checksum errors | |
866 | if (checksum_err_mode == CHECKSUM_ERR_IGNORE) | |
867 | return; | |
832b75ed | 868 | |
2127e193 | 869 | pout("Warning! %s error: invalid SMART checksum.\n", string); |
832b75ed | 870 | |
2127e193 GI |
871 | // user has asked us to fail on checksum errors |
872 | if (checksum_err_mode == CHECKSUM_ERR_EXIT) | |
873 | EXIT(FAILSMART); | |
874 | } | |
832b75ed | 875 | |
2127e193 GI |
876 | // Return info string about device protocol |
877 | static const char * get_protocol_info(const smart_device * dev) | |
878 | { | |
879 | switch ((int)dev->is_ata() | ((int)dev->is_scsi() << 1)) { | |
880 | case 0x1: return "ATA"; | |
881 | case 0x2: return "SCSI"; | |
882 | case 0x3: return "ATA+SCSI"; | |
883 | default: return "Unknown"; | |
884 | } | |
885 | } | |
832b75ed | 886 | |
2127e193 GI |
887 | // Main program without exception handling |
888 | int main_worker(int argc, char **argv) | |
889 | { | |
890 | // Initialize interface | |
891 | smart_interface::init(); | |
892 | if (!smi()) | |
893 | return 1; | |
894 | ||
bed94269 GI |
895 | // define control block for external functions |
896 | smartmonctrl control; | |
897 | con=&control; | |
2127e193 | 898 | |
bed94269 GI |
899 | // Parse input arguments |
900 | ata_print_options ataopts; | |
901 | scsi_print_options scsiopts; | |
902 | const char * type = parse_options(argc, argv, ataopts, scsiopts); | |
832b75ed | 903 | |
bed94269 GI |
904 | // '-d test' -> Report result of autodetection |
905 | bool print_type_only = (type && !strcmp(type, "test")); | |
906 | if (print_type_only) | |
907 | type = 0; | |
908 | ||
909 | const char * name = argv[argc-1]; | |
910 | ||
911 | smart_device_auto_ptr dev; | |
912 | if (!strcmp(name,"-")) { | |
913 | // Parse "smartctl -r ataioctl,2 ..." output from stdin | |
914 | if (type || print_type_only) { | |
915 | pout("Smartctl: -d option is not allowed in conjunction with device name \"-\".\n"); | |
a37e7145 GG |
916 | UsageSummary(); |
917 | return FAILCMD; | |
918 | } | |
bed94269 GI |
919 | dev = get_parsed_ata_device(smi(), name); |
920 | } | |
921 | else | |
922 | // get device of appropriate type | |
923 | dev = smi()->get_smart_device(name, type); | |
924 | ||
925 | if (!dev) { | |
926 | pout("%s: %s\n", name, smi()->get_errmsg()); | |
927 | if (type) | |
928 | printvalidarglistmessage('d'); | |
929 | else | |
930 | pout("Smartctl: please specify device type with the -d option.\n"); | |
931 | UsageSummary(); | |
932 | return FAILCMD; | |
933 | } | |
a37e7145 | 934 | |
bed94269 GI |
935 | if (print_type_only) |
936 | // Report result of first autodetection | |
937 | pout("%s: Device of type '%s' [%s] detected\n", | |
938 | dev->get_info_name(), dev->get_dev_type(), get_protocol_info(dev.get())); | |
2127e193 | 939 | |
bed94269 GI |
940 | // Open device |
941 | { | |
942 | // Save old info | |
943 | smart_device::device_info oldinfo = dev->get_info(); | |
2127e193 | 944 | |
bed94269 GI |
945 | // Open with autodetect support, may return 'better' device |
946 | dev.replace( dev->autodetect_open() ); | |
2127e193 | 947 | |
bed94269 GI |
948 | // Report if type has changed |
949 | if ((type || print_type_only) && oldinfo.dev_type != dev->get_dev_type()) | |
950 | pout("%s: Device open changed type from '%s' to '%s'\n", | |
951 | dev->get_info_name(), oldinfo.dev_type.c_str(), dev->get_dev_type()); | |
2127e193 | 952 | } |
bed94269 GI |
953 | if (!dev->is_open()) { |
954 | pout("Smartctl open device: %s failed: %s\n", dev->get_info_name(), dev->get_errmsg()); | |
955 | return FAILDEV; | |
832b75ed | 956 | } |
bed94269 GI |
957 | |
958 | // now call appropriate ATA or SCSI routine | |
959 | int retval = 0; | |
960 | if (print_type_only) | |
961 | pout("%s: Device of type '%s' [%s] opened\n", | |
962 | dev->get_info_name(), dev->get_dev_type(), get_protocol_info(dev.get())); | |
963 | else if (dev->is_ata()) | |
964 | retval = ataPrintMain(dev->to_ata(), ataopts); | |
965 | else if (dev->is_scsi()) | |
966 | retval = scsiPrintMain(dev->to_scsi(), scsiopts); | |
967 | else | |
968 | // we should never fall into this branch! | |
969 | pout("%s: Neither ATA nor SCSI device\n", dev->get_info_name()); | |
970 | ||
971 | dev->close(); | |
2127e193 GI |
972 | return retval; |
973 | } | |
832b75ed | 974 | |
2127e193 GI |
975 | |
976 | // Main program | |
977 | int main(int argc, char **argv) | |
978 | { | |
979 | int status; | |
980 | try { | |
981 | // Do the real work ... | |
982 | status = main_worker(argc, argv); | |
832b75ed | 983 | } |
2127e193 GI |
984 | catch (int ex) { |
985 | // EXIT(status) arrives here | |
986 | status = ex; | |
832b75ed | 987 | } |
2127e193 GI |
988 | catch (const std::bad_alloc & /*ex*/) { |
989 | // Memory allocation failed (also thrown by std::operator new) | |
bed94269 | 990 | printf("Smartctl: Out of memory\n"); |
2127e193 | 991 | status = FAILCMD; |
832b75ed | 992 | } |
2127e193 GI |
993 | catch (const std::exception & ex) { |
994 | // Other fatal errors | |
bed94269 | 995 | printf("Smartctl: Exception: %s\n", ex.what()); |
2127e193 | 996 | status = FAILCMD; |
832b75ed | 997 | } |
2127e193 | 998 | return status; |
832b75ed | 999 | } |
2127e193 | 1000 |