]>
Commit | Line | Data |
---|---|---|
832b75ed | 1 | /* |
4d59bff9 | 2 | * smartctl.cpp |
832b75ed GG |
3 | * |
4 | * Home page of code is: http://smartmontools.sourceforge.net | |
5 | * | |
a37e7145 | 6 | * Copyright (C) 2002-7 Bruce Allen <smartmontools-support@lists.sourceforge.net> |
832b75ed GG |
7 | * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org> |
8 | * | |
9 | * This program is free software; you can redistribute it and/or modify | |
10 | * it under the terms of the GNU General Public License as published by | |
11 | * the Free Software Foundation; either version 2, or (at your option) | |
12 | * any later version. | |
13 | * | |
14 | * You should have received a copy of the GNU General Public License | |
15 | * (for example COPYING); if not, write to the Free | |
16 | * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
17 | * | |
18 | * This code was originally developed as a Senior Thesis by Michael Cornwell | |
19 | * at the Concurrent Systems Laboratory (now part of the Storage Systems | |
20 | * Research Center), Jack Baskin School of Engineering, University of | |
21 | * California, Santa Cruz. http://ssrc.soe.ucsc.edu/ | |
22 | * | |
23 | */ | |
24 | ||
25 | #include <errno.h> | |
26 | #include <stdio.h> | |
27 | #include <sys/types.h> | |
28 | #include <string.h> | |
29 | #include <stdarg.h> | |
30 | ||
31 | #include "config.h" | |
32 | #ifdef HAVE_GETOPT_LONG | |
33 | #include <getopt.h> | |
34 | #endif | |
35 | #if defined(__FreeBSD_version) && (__FreeBSD_version < 500000) | |
36 | #include <unistd.h> | |
37 | #endif | |
38 | ||
a37e7145 GG |
39 | #if defined(__QNXNTO__) |
40 | #include <unistd.h> | |
41 | #endif | |
42 | ||
43 | ||
832b75ed GG |
44 | #include "int64.h" |
45 | #include "atacmds.h" | |
46 | #include "ataprint.h" | |
47 | #include "extern.h" | |
48 | #include "knowndrives.h" | |
49 | #include "scsicmds.h" | |
50 | #include "scsiprint.h" | |
51 | #include "smartctl.h" | |
52 | #include "utility.h" | |
53 | ||
54 | #ifdef NEED_SOLARIS_ATA_CODE | |
55 | extern const char *os_solaris_ata_s_cvsid; | |
56 | #endif | |
57 | extern const char *atacmdnames_c_cvsid, *atacmds_c_cvsid, *ataprint_c_cvsid, *knowndrives_c_cvsid, *os_XXXX_c_cvsid, *scsicmds_c_cvsid, *scsiprint_c_cvsid, *utility_c_cvsid; | |
a37e7145 | 58 | const char* smartctl_c_cvsid="$Id: smartctl.cpp,v 1.168 2007/11/13 14:53:27 jhering Exp $" |
832b75ed GG |
59 | ATACMDS_H_CVSID ATAPRINT_H_CVSID CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID KNOWNDRIVES_H_CVSID SCSICMDS_H_CVSID SCSIPRINT_H_CVSID SMARTCTL_H_CVSID UTILITY_H_CVSID; |
60 | ||
61 | // This is a block containing all the "control variables". We declare | |
62 | // this globally in this file, and externally in other files. | |
63 | smartmonctrl *con=NULL; | |
64 | ||
65 | // to hold onto exit code for atexit routine | |
66 | extern int exitstatus; | |
67 | ||
68 | // Track memory use | |
69 | extern int64_t bytes; | |
70 | ||
71 | void printslogan(){ | |
72 | #ifdef HAVE_GET_OS_VERSION_STR | |
73 | const char * ver = get_os_version_str(); | |
74 | #else | |
75 | const char * ver = SMARTMONTOOLS_BUILD_HOST; | |
76 | #endif | |
a37e7145 | 77 | pout("smartctl version %s [%s] Copyright (C) 2002-7 Bruce Allen\n", PACKAGE_VERSION, ver); |
832b75ed GG |
78 | pout("Home page is " PACKAGE_HOMEPAGE "\n\n"); |
79 | return; | |
80 | } | |
81 | ||
82 | void PrintOneCVS(const char *a_cvs_id){ | |
83 | char out[CVSMAXLEN]; | |
84 | printone(out,a_cvs_id); | |
85 | pout("%s",out); | |
86 | return; | |
87 | } | |
88 | ||
89 | void printcopy(){ | |
a37e7145 | 90 | const char *configargs=strlen(SMARTMONTOOLS_CONFIGURE_ARGS)?SMARTMONTOOLS_CONFIGURE_ARGS:"[no arguments given]"; |
832b75ed GG |
91 | |
92 | pout("smartctl comes with ABSOLUTELY NO WARRANTY. This\n"); | |
93 | pout("is free software, and you are welcome to redistribute it\n"); | |
94 | pout("under the terms of the GNU General Public License Version 2.\n"); | |
95 | pout("See http://www.gnu.org for further details.\n\n"); | |
96 | pout("CVS version IDs of files used to build this code are:\n"); | |
97 | PrintOneCVS(atacmdnames_c_cvsid); | |
98 | PrintOneCVS(atacmds_c_cvsid); | |
99 | PrintOneCVS(ataprint_c_cvsid); | |
100 | PrintOneCVS(knowndrives_c_cvsid); | |
101 | PrintOneCVS(os_XXXX_c_cvsid); | |
102 | #ifdef NEED_SOLARIS_ATA_CODE | |
103 | PrintOneCVS(os_solaris_ata_s_cvsid); | |
104 | #endif | |
105 | PrintOneCVS(scsicmds_c_cvsid); | |
106 | PrintOneCVS(scsiprint_c_cvsid); | |
107 | PrintOneCVS(smartctl_c_cvsid); | |
108 | PrintOneCVS(utility_c_cvsid); | |
109 | pout("\nsmartmontools release " PACKAGE_VERSION " dated " SMARTMONTOOLS_RELEASE_DATE " at " SMARTMONTOOLS_RELEASE_TIME "\n"); | |
110 | pout("smartmontools build host: " SMARTMONTOOLS_BUILD_HOST "\n"); | |
111 | pout("smartmontools build configured: " SMARTMONTOOLS_CONFIGURE_DATE "\n"); | |
112 | pout("smartctl compile dated " __DATE__ " at "__TIME__ "\n"); | |
113 | pout("smartmontools configure arguments: %s\n", configargs); | |
114 | return; | |
115 | } | |
116 | ||
117 | void UsageSummary(){ | |
118 | pout("\nUse smartctl -h to get a usage summary\n\n"); | |
119 | return; | |
120 | } | |
121 | ||
122 | /* void prints help information for command syntax */ | |
123 | void Usage (void){ | |
124 | printf("Usage: smartctl [options] device\n\n"); | |
125 | printf("============================================ SHOW INFORMATION OPTIONS =====\n\n"); | |
126 | #ifdef HAVE_GETOPT_LONG | |
127 | printf( | |
128 | " -h, --help, --usage\n" | |
129 | " Display this help and exit\n\n" | |
130 | " -V, --version, --copyright, --license\n" | |
131 | " Print license, copyright, and version information and exit\n\n" | |
132 | " -i, --info \n" | |
133 | " Show identity information for device\n\n" | |
134 | " -a, --all \n" | |
135 | " Show all SMART information for device\n\n" | |
136 | ); | |
137 | #else | |
138 | printf( | |
139 | " -h Display this help and exit\n" | |
140 | " -V Print license, copyright, and version information\n" | |
141 | " -i Show identity information for device\n" | |
142 | " -a Show all SMART information for device\n\n" | |
143 | ); | |
144 | #endif | |
145 | printf("================================== SMARTCTL RUN-TIME BEHAVIOR OPTIONS =====\n\n"); | |
146 | #ifdef HAVE_GETOPT_LONG | |
147 | printf( | |
148 | " -q TYPE, --quietmode=TYPE (ATA)\n" | |
a37e7145 | 149 | " Set smartctl quiet mode to one of: errorsonly, silent, noserial\n\n" |
832b75ed | 150 | " -d TYPE, --device=TYPE\n" |
4d59bff9 | 151 | " Specify device type to one of: ata, scsi, marvell, sat, 3ware,N\n\n" |
832b75ed GG |
152 | " -T TYPE, --tolerance=TYPE (ATA)\n" |
153 | " Tolerance: normal, conservative, permissive, verypermissive\n\n" | |
154 | " -b TYPE, --badsum=TYPE (ATA)\n" | |
155 | " Set action on bad checksum to one of: warn, exit, ignore\n\n" | |
156 | " -r TYPE, --report=TYPE\n" | |
157 | " Report transactions (see man page)\n\n" | |
4d59bff9 GG |
158 | " -n MODE, --nocheck=MODE (ATA)\n" |
159 | " No check if: never, sleep, standby, idle (see man page)\n\n" | |
832b75ed GG |
160 | ); |
161 | #else | |
162 | printf( | |
a37e7145 GG |
163 | " -q TYPE Set smartctl quiet mode to one of: errorsonly, silent, (ATA)\n" |
164 | " noserial\n" | |
832b75ed | 165 | " -d TYPE Specify device type to one of: ata, scsi, 3ware,N\n" |
a37e7145 | 166 | " -T TYPE Tolerance: normal, conservative,permissive,verypermissive (ATA)\n" |
832b75ed | 167 | " -b TYPE Set action on bad checksum to one of: warn, exit, ignore (ATA)\n" |
4d59bff9 GG |
168 | " -r TYPE Report transactions (see man page)\n" |
169 | " -n MODE No check if: never, sleep, standby, idle (see man page) (ATA)\n\n" | |
832b75ed GG |
170 | ); |
171 | #endif | |
172 | printf("============================== DEVICE FEATURE ENABLE/DISABLE COMMANDS =====\n\n"); | |
173 | #ifdef HAVE_GETOPT_LONG | |
174 | printf( | |
175 | " -s VALUE, --smart=VALUE\n" | |
176 | " Enable/disable SMART on device (on/off)\n\n" | |
177 | " -o VALUE, --offlineauto=VALUE (ATA)\n" | |
178 | " Enable/disable automatic offline testing on device (on/off)\n\n" | |
179 | " -S VALUE, --saveauto=VALUE (ATA)\n" | |
180 | " Enable/disable Attribute autosave on device (on/off)\n\n" | |
181 | ); | |
182 | #else | |
183 | printf( | |
184 | " -s VALUE Enable/disable SMART on device (on/off)\n" | |
185 | " -o VALUE Enable/disable device automatic offline testing (on/off) (ATA)\n" | |
186 | " -S VALUE Enable/disable device Attribute autosave (on/off) (ATA)\n\n" | |
187 | ); | |
188 | #endif | |
189 | printf("======================================= READ AND DISPLAY DATA OPTIONS =====\n\n"); | |
190 | #ifdef HAVE_GETOPT_LONG | |
191 | printf( | |
192 | " -H, --health\n" | |
193 | " Show device SMART health status\n\n" | |
194 | " -c, --capabilities (ATA)\n" | |
195 | " Show device SMART capabilities\n\n" | |
196 | " -A, --attributes \n" | |
197 | " Show device SMART vendor-specific Attributes and values\n\n" | |
198 | " -l TYPE, --log=TYPE\n" | |
4d59bff9 | 199 | " Show device log. TYPE: error, selftest, selective, directory,\n" |
a37e7145 | 200 | " background, scttemp[sts,hist]\n\n" |
832b75ed GG |
201 | " -v N,OPTION , --vendorattribute=N,OPTION (ATA)\n" |
202 | " Set display OPTION for vendor Attribute N (see man page)\n\n" | |
203 | " -F TYPE, --firmwarebug=TYPE (ATA)\n" | |
a37e7145 GG |
204 | " Use firmware bug workaround: none, samsung, samsung2,\n" |
205 | " samsung3, swapid\n\n" | |
832b75ed GG |
206 | " -P TYPE, --presets=TYPE (ATA)\n" |
207 | " Drive-specific presets: use, ignore, show, showall\n\n" | |
208 | ); | |
209 | #else | |
210 | printf( | |
211 | " -H Show device SMART health status\n" | |
212 | " -c Show device SMART capabilities (ATA)\n" | |
213 | " -A Show device SMART vendor-specific Attributes and values (ATA)\n" | |
4d59bff9 | 214 | " -l TYPE Show device log. TYPE: error, selftest, selective, directory,\n" |
a37e7145 | 215 | " background, scttemp[sts,hist]\n" |
832b75ed | 216 | " -v N,OPT Set display OPTion for vendor Attribute N (see man page) (ATA)\n" |
a37e7145 GG |
217 | " -F TYPE Use firmware bug workaround: none, samsung, samsung2, (ATA)\n" |
218 | " samsung3, swapid\n" | |
832b75ed GG |
219 | " -P TYPE Drive-specific presets: use, ignore, show, showall (ATA)\n\n" |
220 | ); | |
221 | #endif | |
222 | printf("============================================ DEVICE SELF-TEST OPTIONS =====\n\n"); | |
223 | #ifdef HAVE_GETOPT_LONG | |
224 | printf( | |
225 | " -t TEST, --test=TEST\n" | |
a37e7145 GG |
226 | " Run test. TEST: offline short long conveyance select,M-N\n" |
227 | " pending,N afterselect,[on|off] scttempint,N[,p]\n\n" | |
832b75ed GG |
228 | " -C, --captive\n" |
229 | " Do test in captive mode (along with -t)\n\n" | |
230 | " -X, --abort\n" | |
231 | " Abort any non-captive test on device\n\n" | |
232 | ); | |
233 | #else | |
234 | printf( | |
a37e7145 GG |
235 | " -t TEST Run test. TEST: offline short long conveyance select,M-N\n" |
236 | " pending,N afterselect,[on|off] scttempint,N[,p]\n" | |
832b75ed GG |
237 | " -C Do test in captive mode (along with -t)\n" |
238 | " -X Abort any non-captive test\n\n" | |
239 | ); | |
240 | #endif | |
241 | print_smartctl_examples(); | |
242 | return; | |
243 | } | |
244 | ||
245 | /* Returns a pointer to a static string containing a formatted list of the valid | |
246 | arguments to the option opt or NULL on failure. Note 'v' case different */ | |
247 | const char *getvalidarglist(char opt) { | |
248 | switch (opt) { | |
249 | case 'q': | |
a37e7145 | 250 | return "errorsonly, silent, noserial"; |
832b75ed | 251 | case 'd': |
ba59cff1 | 252 | return "ata, scsi, marvell, sat, 3ware,N, hpt,L/M/N cciss,N"; |
832b75ed GG |
253 | case 'T': |
254 | return "normal, conservative, permissive, verypermissive"; | |
255 | case 'b': | |
256 | return "warn, exit, ignore"; | |
257 | case 'r': | |
258 | return "ioctl[,N], ataioctl[,N], scsiioctl[,N]"; | |
259 | case 's': | |
260 | case 'o': | |
261 | case 'S': | |
262 | return "on, off"; | |
263 | case 'l': | |
a37e7145 | 264 | return "error, selftest, selective, directory, background, scttemp[sts|hist]"; |
832b75ed GG |
265 | case 'P': |
266 | return "use, ignore, show, showall"; | |
267 | case 't': | |
a37e7145 | 268 | return "offline, short, long, conveyance, select,M-N, pending,N, afterselect,[on|off], scttempint,N[,p]"; |
832b75ed | 269 | case 'F': |
a37e7145 | 270 | return "none, samsung, samsung2, samsung3, swapid"; |
4d59bff9 GG |
271 | case 'n': |
272 | return "never, sleep, standby, idle"; | |
832b75ed GG |
273 | case 'v': |
274 | default: | |
275 | return NULL; | |
276 | } | |
277 | } | |
278 | ||
279 | /* Prints the message "=======> VALID ARGUMENTS ARE: <LIST> \n", where | |
280 | <LIST> is the list of valid arguments for option opt. */ | |
281 | void printvalidarglistmessage(char opt) { | |
282 | char *s; | |
283 | ||
284 | if (opt=='v') | |
285 | s=create_vendor_attribute_arg_list(); | |
286 | else | |
287 | s=(char *)getvalidarglist(opt); | |
288 | ||
289 | if (!s) { | |
290 | pout("Error whilst constructing argument list for option %c", opt); | |
291 | return; | |
292 | } | |
293 | ||
294 | if (opt=='v'){ | |
295 | pout("=======> VALID ARGUMENTS ARE:\n\thelp\n%s\n<=======\n", s); | |
296 | free(s); | |
297 | } | |
298 | else { | |
299 | // getvalidarglist() might produce a multiline or single line string. We | |
300 | // need to figure out which to get the formatting right. | |
301 | char separator = strchr(s, '\n') ? '\n' : ' '; | |
302 | pout("=======> VALID ARGUMENTS ARE:%c%s%c<=======\n", separator, (char *)s, separator); | |
303 | } | |
304 | ||
305 | return; | |
306 | } | |
307 | ||
308 | /* Takes command options and sets features to be run */ | |
309 | void ParseOpts (int argc, char** argv){ | |
310 | int optchar; | |
311 | int badarg; | |
312 | int captive; | |
313 | unsigned char *charp; | |
314 | extern char *optarg; | |
315 | extern int optopt, optind, opterr; | |
316 | char extraerror[256]; | |
317 | // Please update getvalidarglist() if you edit shortopts | |
4d59bff9 | 318 | const char *shortopts = "h?Vq:d:T:b:r:s:o:S:HcAl:iav:P:t:CXF:n:"; |
832b75ed GG |
319 | #ifdef HAVE_GETOPT_LONG |
320 | char *arg; | |
321 | // Please update getvalidarglist() if you edit longopts | |
322 | struct option longopts[] = { | |
323 | { "help", no_argument, 0, 'h' }, | |
324 | { "usage", no_argument, 0, 'h' }, | |
325 | { "version", no_argument, 0, 'V' }, | |
326 | { "copyright", no_argument, 0, 'V' }, | |
327 | { "license", no_argument, 0, 'V' }, | |
328 | { "quietmode", required_argument, 0, 'q' }, | |
329 | { "device", required_argument, 0, 'd' }, | |
330 | { "tolerance", required_argument, 0, 'T' }, | |
331 | { "badsum", required_argument, 0, 'b' }, | |
332 | { "report", required_argument, 0, 'r' }, | |
333 | { "smart", required_argument, 0, 's' }, | |
334 | { "offlineauto", required_argument, 0, 'o' }, | |
335 | { "saveauto", required_argument, 0, 'S' }, | |
336 | { "health", no_argument, 0, 'H' }, | |
337 | { "capabilities", no_argument, 0, 'c' }, | |
338 | { "attributes", no_argument, 0, 'A' }, | |
339 | { "log", required_argument, 0, 'l' }, | |
340 | { "info", no_argument, 0, 'i' }, | |
341 | { "all", no_argument, 0, 'a' }, | |
342 | { "vendorattribute", required_argument, 0, 'v' }, | |
343 | { "presets", required_argument, 0, 'P' }, | |
344 | { "test", required_argument, 0, 't' }, | |
345 | { "captive", no_argument, 0, 'C' }, | |
346 | { "abort", no_argument, 0, 'X' }, | |
347 | { "firmwarebug", required_argument, 0, 'F' }, | |
4d59bff9 | 348 | { "nocheck", required_argument, 0, 'n' }, |
832b75ed GG |
349 | { 0, 0, 0, 0 } |
350 | }; | |
351 | #endif | |
352 | ||
353 | memset(extraerror, 0, sizeof(extraerror)); | |
354 | memset(con,0,sizeof(*con)); | |
355 | con->testcase=-1; | |
356 | opterr=optopt=0; | |
357 | badarg = captive = FALSE; | |
358 | ||
359 | // This miserable construction is needed to get emacs to do proper indenting. Sorry! | |
360 | while (-1 != (optchar = | |
361 | #ifdef HAVE_GETOPT_LONG | |
362 | getopt_long(argc, argv, shortopts, longopts, NULL) | |
363 | #else | |
364 | getopt(argc, argv, shortopts) | |
365 | #endif | |
366 | )){ | |
367 | switch (optchar){ | |
368 | case 'V': | |
369 | con->dont_print=FALSE; | |
370 | printslogan(); | |
371 | printcopy(); | |
372 | exit(0); | |
373 | break; | |
374 | case 'q': | |
375 | if (!strcmp(optarg,"errorsonly")) { | |
376 | con->printing_switchable = TRUE; | |
377 | con->dont_print = FALSE; | |
378 | } else if (!strcmp(optarg,"silent")) { | |
379 | con->printing_switchable = FALSE; | |
380 | con->dont_print = TRUE; | |
a37e7145 GG |
381 | } else if (!strcmp(optarg,"noserial")) { |
382 | con->dont_print_serial = TRUE; | |
832b75ed GG |
383 | } else { |
384 | badarg = TRUE; | |
385 | } | |
386 | break; | |
387 | case 'd': | |
4d59bff9 | 388 | con->controller_explicit = 1; |
832b75ed | 389 | if (!strcmp(optarg,"ata")) { |
4d59bff9 | 390 | con->controller_type = CONTROLLER_ATA; |
832b75ed GG |
391 | con->controller_port = 0; |
392 | } else if (!strcmp(optarg,"scsi")) { | |
4d59bff9 | 393 | con->controller_type = CONTROLLER_SCSI; |
832b75ed GG |
394 | con->controller_port = 0; |
395 | } else if (!strcmp(optarg,"marvell")) { | |
4d59bff9 | 396 | con->controller_type = CONTROLLER_MARVELL_SATA; |
832b75ed | 397 | con->controller_port = 0; |
4d59bff9 GG |
398 | } else if (!strncmp(optarg, "sat", 3)) { |
399 | con->controller_type = CONTROLLER_SAT; | |
400 | con->controller_port = 0; | |
401 | con->satpassthrulen = 0; | |
402 | if (strlen(optarg) > 3) { | |
403 | int k; | |
404 | char * cp; | |
405 | ||
406 | cp = strchr(optarg, ','); | |
407 | if (cp && (1 == sscanf(cp + 1, "%d", &k)) && | |
408 | ((0 == k) || (12 == k) || (16 == k))) | |
409 | con->satpassthrulen = k; | |
410 | else { | |
411 | sprintf(extraerror, "Option '-d sat,<n>' requires <n> to be " | |
412 | "0, 12 or 16\n"); | |
413 | badarg = TRUE; | |
414 | } | |
415 | } | |
416 | } else if (!strncmp(optarg, "hpt", 3)){ | |
417 | unsigned char i, slash = 0; | |
418 | con->hpt_data[0] = 0; | |
419 | con->hpt_data[1] = 0; | |
420 | con->hpt_data[2] = 0; | |
421 | con->controller_type = CONTROLLER_HPT; | |
422 | for (i=4; i < strlen(optarg); i++) { | |
423 | if(optarg[i] == '/') { | |
424 | slash++; | |
425 | if(slash == 3) { | |
426 | sprintf(extraerror, "Option '-d hpt,L/M/N' supports 2-3 items\n"); | |
427 | badarg = TRUE; | |
428 | break; | |
429 | } | |
430 | } | |
431 | else if ((optarg[i])>='0' && (optarg[i])<='9') { | |
432 | if (con->hpt_data[slash]>1) { /* hpt_data[x] max 19 */ | |
433 | badarg = TRUE; | |
434 | break; | |
435 | } | |
436 | con->hpt_data[slash] = con->hpt_data[slash]*10 + optarg[i] - '0'; | |
437 | } | |
438 | else { | |
439 | badarg = TRUE; | |
440 | break; | |
441 | } | |
442 | } | |
443 | if (slash == 0) { | |
444 | sprintf(extraerror, "Option '-d hpt,L/M/N' requires 2-3 items\n"); | |
445 | badarg = TRUE; | |
446 | } else if (badarg != TRUE) { | |
447 | if (con->hpt_data[0]==0 || con->hpt_data[0]>8){ | |
448 | sprintf(extraerror, "Option '-d hpt,L/M/N' no/invalid controller id L supplied\n"); | |
449 | badarg = TRUE; | |
450 | } | |
451 | if (con->hpt_data[1]==0 || con->hpt_data[1]>8){ | |
452 | sprintf(extraerror, "Option '-d hpt,L/M/N' no/invalid channel number M supplied\n"); | |
453 | badarg = TRUE; | |
454 | } | |
455 | if (slash==2) { | |
456 | if ( con->hpt_data[2]==0 || con->hpt_data[2]>15) { | |
457 | sprintf(extraerror, "Option '-d hpt,L/M/N' no/invalid pmport number N supplied\n"); | |
458 | badarg = TRUE; | |
459 | } | |
460 | } else { | |
461 | con->hpt_data[2]=1; | |
462 | } | |
463 | } | |
832b75ed GG |
464 | } else { |
465 | // look for RAID-type device | |
466 | int i; | |
467 | char *s; | |
468 | ||
469 | // make a copy of the string to mess with | |
470 | if (!(s = strdup(optarg))) { | |
471 | con->dont_print = FALSE; | |
472 | pout("No memory for argument of -d. Exiting...\n"); | |
473 | exit(FAILCMD); | |
ba59cff1 GG |
474 | } else if (!strncmp(s,"3ware,",6)) { |
475 | if (split_report_arg2(s, &i)) { | |
476 | sprintf(extraerror, "Option -d 3ware,N requires N to be a non-negative integer\n"); | |
477 | badarg = TRUE; | |
a37e7145 GG |
478 | } else if (i<0 || i>31) { |
479 | sprintf(extraerror, "Option -d 3ware,N (N=%d) must have 0 <= N <= 31\n", i); | |
ba59cff1 GG |
480 | badarg = TRUE; |
481 | } else { | |
482 | // NOTE: controller_port == disk number + 1 | |
483 | con->controller_type = CONTROLLER_3WARE; | |
484 | con->controller_port = i+1; | |
485 | } | |
486 | free(s); | |
487 | } else if (!strncmp(s,"cciss,",6)) { | |
488 | if (split_report_arg2(s, &i)) { | |
489 | sprintf(extraerror, "Option -d cciss,N requires N to be a non-negative integer\n"); | |
490 | badarg = TRUE; | |
a37e7145 GG |
491 | } else if (i<0 || i>127) { |
492 | sprintf(extraerror, "Option -d cciss,N (N=%d) must have 0 <= N <= 127\n", i); | |
ba59cff1 GG |
493 | badarg = TRUE; |
494 | } else { | |
495 | // NOTE: controller_port == drive number | |
496 | con->controller_type = CONTROLLER_CCISS; | |
497 | con->controller_port = i+1; | |
498 | } | |
499 | free(s); | |
500 | } else | |
501 | badarg=TRUE; | |
502 | } | |
832b75ed GG |
503 | break; |
504 | case 'T': | |
505 | if (!strcmp(optarg,"normal")) { | |
506 | con->conservative = FALSE; | |
507 | con->permissive = 0; | |
508 | } else if (!strcmp(optarg,"conservative")) { | |
509 | con->conservative = TRUE; | |
510 | } else if (!strcmp(optarg,"permissive")) { | |
511 | if (con->permissive<0xff) | |
512 | con->permissive++; | |
513 | } else if (!strcmp(optarg,"verypermissive")) { | |
514 | con->permissive=0xff; | |
515 | } else { | |
516 | badarg = TRUE; | |
517 | } | |
518 | break; | |
519 | case 'b': | |
520 | if (!strcmp(optarg,"warn")) { | |
521 | con->checksumfail = FALSE; | |
522 | con->checksumignore = FALSE; | |
523 | } else if (!strcmp(optarg,"exit")) { | |
524 | con->checksumfail = TRUE; | |
525 | con->checksumignore = FALSE; | |
526 | } else if (!strcmp(optarg,"ignore")) { | |
527 | con->checksumignore = TRUE; | |
528 | con->checksumfail = FALSE; | |
529 | } else { | |
530 | badarg = TRUE; | |
531 | } | |
532 | break; | |
533 | case 'r': | |
534 | { | |
535 | int i; | |
536 | char *s; | |
537 | ||
538 | // split_report_arg() may modify its first argument string, so use a | |
539 | // copy of optarg in case we want optarg for an error message. | |
540 | if (!(s = strdup(optarg))) { | |
541 | con->dont_print = FALSE; | |
542 | pout("Can't allocate memory to copy argument to -r option" | |
543 | " - exiting\n"); | |
544 | EXIT(FAILCMD); | |
545 | } | |
546 | if (split_report_arg(s, &i)) { | |
547 | badarg = TRUE; | |
548 | } else if (!strcmp(s,"ioctl")) { | |
549 | con->reportataioctl = con->reportscsiioctl = i; | |
550 | } else if (!strcmp(s,"ataioctl")) { | |
551 | con->reportataioctl = i; | |
552 | } else if (!strcmp(s,"scsiioctl")) { | |
553 | con->reportscsiioctl = i; | |
554 | } else { | |
555 | badarg = TRUE; | |
556 | } | |
557 | free(s); | |
558 | } | |
559 | break; | |
560 | case 's': | |
561 | if (!strcmp(optarg,"on")) { | |
562 | con->smartenable = TRUE; | |
563 | con->smartdisable = FALSE; | |
564 | } else if (!strcmp(optarg,"off")) { | |
565 | con->smartdisable = TRUE; | |
566 | con->smartenable = FALSE; | |
567 | } else { | |
568 | badarg = TRUE; | |
569 | } | |
570 | break; | |
571 | case 'o': | |
572 | if (!strcmp(optarg,"on")) { | |
573 | con->smartautoofflineenable = TRUE; | |
574 | con->smartautoofflinedisable = FALSE; | |
575 | } else if (!strcmp(optarg,"off")) { | |
576 | con->smartautoofflinedisable = TRUE; | |
577 | con->smartautoofflineenable = FALSE; | |
578 | } else { | |
579 | badarg = TRUE; | |
580 | } | |
581 | break; | |
582 | case 'S': | |
583 | if (!strcmp(optarg,"on")) { | |
584 | con->smartautosaveenable = TRUE; | |
585 | con->smartautosavedisable = FALSE; | |
586 | } else if (!strcmp(optarg,"off")) { | |
587 | con->smartautosavedisable = TRUE; | |
588 | con->smartautosaveenable = FALSE; | |
589 | } else { | |
590 | badarg = TRUE; | |
591 | } | |
592 | break; | |
593 | case 'H': | |
594 | con->checksmart = TRUE; | |
595 | break; | |
596 | case 'F': | |
597 | if (!strcmp(optarg,"none")) { | |
598 | con->fixfirmwarebug = FIX_NONE; | |
599 | } else if (!strcmp(optarg,"samsung")) { | |
600 | con->fixfirmwarebug = FIX_SAMSUNG; | |
601 | } else if (!strcmp(optarg,"samsung2")) { | |
602 | con->fixfirmwarebug = FIX_SAMSUNG2; | |
a37e7145 GG |
603 | } else if (!strcmp(optarg,"samsung3")) { |
604 | con->fixfirmwarebug = FIX_SAMSUNG3; | |
605 | } else if (!strcmp(optarg,"swapid")) { | |
606 | con->fixswappedid = TRUE; | |
832b75ed GG |
607 | } else { |
608 | badarg = TRUE; | |
609 | } | |
610 | break; | |
611 | case 'c': | |
612 | con->generalsmartvalues = TRUE; | |
613 | break; | |
614 | case 'A': | |
615 | con->smartvendorattrib = TRUE; | |
616 | break; | |
617 | case 'l': | |
618 | if (!strcmp(optarg,"error")) { | |
619 | con->smarterrorlog = TRUE; | |
620 | } else if (!strcmp(optarg,"selftest")) { | |
621 | con->smartselftestlog = TRUE; | |
622 | } else if (!strcmp(optarg, "selective")) { | |
a37e7145 | 623 | con->selectivetestlog = TRUE; |
832b75ed GG |
624 | } else if (!strcmp(optarg,"directory")) { |
625 | con->smartlogdirectory = TRUE; | |
4d59bff9 GG |
626 | } else if (!strcmp(optarg,"background")) { |
627 | con->smartbackgroundlog = TRUE; | |
a37e7145 GG |
628 | } else if (!strcmp(optarg,"scttemp")) { |
629 | con->scttempsts = con->scttemphist = TRUE; | |
630 | } else if (!strcmp(optarg,"scttempsts")) { | |
631 | con->scttempsts = TRUE; | |
632 | } else if (!strcmp(optarg,"scttemphist")) { | |
633 | con->scttemphist = TRUE; | |
832b75ed GG |
634 | } else { |
635 | badarg = TRUE; | |
636 | } | |
637 | break; | |
638 | case 'i': | |
639 | con->driveinfo = TRUE; | |
640 | break; | |
641 | case 'a': | |
642 | con->driveinfo = TRUE; | |
643 | con->checksmart = TRUE; | |
644 | con->generalsmartvalues = TRUE; | |
645 | con->smartvendorattrib = TRUE; | |
646 | con->smarterrorlog = TRUE; | |
647 | con->smartselftestlog = TRUE; | |
648 | con->selectivetestlog = TRUE; | |
4d59bff9 | 649 | /* con->smartbackgroundlog = TRUE; */ |
832b75ed GG |
650 | break; |
651 | case 'v': | |
652 | // parse vendor-specific definitions of attributes | |
653 | if (!strcmp(optarg,"help")) { | |
654 | char *s; | |
655 | con->dont_print=FALSE; | |
656 | printslogan(); | |
657 | if (!(s = create_vendor_attribute_arg_list())) { | |
658 | pout("Insufficient memory to construct argument list\n"); | |
659 | EXIT(FAILCMD); | |
660 | } | |
661 | pout("The valid arguments to -v are:\n\thelp\n%s\n", s); | |
662 | free(s); | |
663 | EXIT(0); | |
664 | } | |
665 | charp=con->attributedefs; | |
666 | if (!charp){ | |
667 | pout("Fatal internal error in ParseOpts()\n"); | |
668 | EXIT(FAILCMD); | |
669 | } | |
670 | if (parse_attribute_def(optarg, &charp)) | |
671 | badarg = TRUE; | |
672 | break; | |
673 | case 'P': | |
674 | if (!strcmp(optarg, "use")) { | |
675 | con->ignorepresets = FALSE; | |
676 | } else if (!strcmp(optarg, "ignore")) { | |
677 | con->ignorepresets = TRUE; | |
678 | } else if (!strcmp(optarg, "show")) { | |
679 | con->showpresets = TRUE; | |
680 | } else if (!strcmp(optarg, "showall")) { | |
681 | if (optind < argc) { // -P showall MODEL [FIRMWARE] | |
682 | int cnt = showmatchingpresets(argv[optind], (optind+1<argc ? argv[optind+1] : NULL)); | |
683 | EXIT(cnt); // report #matches | |
684 | } | |
685 | if (showallpresets()) | |
686 | EXIT(FAILCMD); // report regexp syntax error | |
687 | EXIT(0); | |
688 | } else { | |
689 | badarg = TRUE; | |
690 | } | |
691 | break; | |
692 | case 't': | |
693 | if (!strcmp(optarg,"offline")) { | |
694 | con->smartexeoffimmediate = TRUE; | |
695 | con->testcase = OFFLINE_FULL_SCAN; | |
696 | } else if (!strcmp(optarg,"short")) { | |
697 | con->smartshortselftest = TRUE; | |
698 | con->testcase = SHORT_SELF_TEST; | |
699 | } else if (!strcmp(optarg,"long")) { | |
700 | con->smartextendselftest = TRUE; | |
701 | con->testcase = EXTEND_SELF_TEST; | |
702 | } else if (!strcmp(optarg,"conveyance")) { | |
703 | con->smartconveyanceselftest = TRUE; | |
704 | con->testcase = CONVEYANCE_SELF_TEST; | |
705 | } else if (!strcmp(optarg,"afterselect,on")) { | |
706 | // scan remainder of disk after doing selected segments | |
707 | con->scanafterselect=2; | |
708 | } else if (!strcmp(optarg,"afterselect,off")) { | |
709 | // don't scan remainder of disk after doing selected segments | |
710 | con->scanafterselect=1; | |
711 | } else if (!strncmp(optarg,"pending,",strlen("pending,"))) { | |
712 | // parse number of minutes that test should be pending | |
713 | int i; | |
714 | char *tailptr=NULL; | |
715 | errno=0; | |
716 | i=(int)strtol(optarg+strlen("pending,"), &tailptr, 10); | |
717 | if (errno || *tailptr != '\0') { | |
718 | sprintf(extraerror, "Option -t pending,N requires N to be a non-negative integer\n"); | |
719 | badarg = TRUE; | |
720 | } else if (i<0 || i>65535) { | |
721 | sprintf(extraerror, "Option -t pending,N (N=%d) must have 0 <= N <= 65535\n", i); | |
722 | badarg = TRUE; | |
723 | } else { | |
724 | con->pendingtime=i+1; | |
725 | } | |
726 | } else if (!strncmp(optarg,"select",strlen("select"))) { | |
a37e7145 GG |
727 | // parse range of LBAs to test |
728 | uint64_t start, stop; int mode; | |
729 | if (split_selective_arg(optarg, &start, &stop, &mode)) { | |
832b75ed GG |
730 | sprintf(extraerror, "Option -t select,M-N must have non-negative integer M and N\n"); |
731 | badarg = TRUE; | |
732 | } else { | |
733 | if (con->smartselectivenumspans >= 5 || start > stop) { | |
734 | if (start > stop) { | |
735 | sprintf(extraerror, "ERROR: Start LBA (%"PRIu64") > ending LBA (%"PRId64") in argument \"%s\"\n", | |
736 | start, stop, optarg); | |
737 | } else { | |
738 | sprintf(extraerror,"ERROR: No more than five selective self-test spans may be" | |
739 | " defined\n"); | |
740 | } | |
741 | badarg = TRUE; | |
742 | } | |
743 | con->smartselectivespan[con->smartselectivenumspans][0] = start; | |
744 | con->smartselectivespan[con->smartselectivenumspans][1] = stop; | |
a37e7145 | 745 | con->smartselectivemode[con->smartselectivenumspans] = mode; |
832b75ed GG |
746 | con->smartselectivenumspans++; |
747 | con->testcase = SELECTIVE_SELF_TEST; | |
748 | } | |
a37e7145 GG |
749 | } else if (!strncmp(optarg, "scttempint,", sizeof("scstempint,")-1)) { |
750 | unsigned interval = 0; int n1 = -1, n2 = -1, len = strlen(optarg); | |
751 | if (!( sscanf(optarg,"scttempint,%u%n,p%n", &interval, &n1, &n2) == 1 | |
752 | && 0 < interval && interval <= 0xffff && (n1 == len || n2 == len))) { | |
753 | strcpy(extraerror, "Option -t scttempint,N[,p] must have positive integer N\n"); | |
754 | badarg = TRUE; | |
755 | } | |
756 | con->scttempint = interval; | |
757 | con->scttempintp = (n2 == len); | |
832b75ed GG |
758 | } else { |
759 | badarg = TRUE; | |
760 | } | |
761 | break; | |
762 | case 'C': | |
763 | captive = TRUE; | |
764 | break; | |
765 | case 'X': | |
766 | con->smartselftestabort = TRUE; | |
767 | con->testcase = ABORT_SELF_TEST; | |
768 | break; | |
4d59bff9 GG |
769 | case 'n': |
770 | // skip disk check if in low-power mode | |
771 | if (!strcmp(optarg, "never")) | |
772 | con->powermode = 1; // do not skip, but print mode | |
773 | else if (!strcmp(optarg, "sleep")) | |
774 | con->powermode = 2; | |
775 | else if (!strcmp(optarg, "standby")) | |
776 | con->powermode = 3; | |
777 | else if (!strcmp(optarg, "idle")) | |
778 | con->powermode = 4; | |
779 | else | |
780 | badarg = TRUE; | |
781 | break; | |
832b75ed GG |
782 | case 'h': |
783 | con->dont_print=FALSE; | |
784 | printslogan(); | |
785 | Usage(); | |
786 | EXIT(0); | |
787 | break; | |
788 | case '?': | |
789 | default: | |
790 | con->dont_print=FALSE; | |
791 | printslogan(); | |
792 | #ifdef HAVE_GETOPT_LONG | |
793 | // Point arg to the argument in which this option was found. | |
794 | arg = argv[optind-1]; | |
795 | // Check whether the option is a long option that doesn't map to -h. | |
796 | if (arg[1] == '-' && optchar != 'h') { | |
797 | // Iff optopt holds a valid option then argument must be missing. | |
798 | if (optopt && (strchr(shortopts, optopt) != NULL)) { | |
799 | pout("=======> ARGUMENT REQUIRED FOR OPTION: %s\n", arg+2); | |
800 | printvalidarglistmessage(optopt); | |
801 | } else | |
802 | pout("=======> UNRECOGNIZED OPTION: %s\n",arg+2); | |
803 | if (extraerror[0]) | |
804 | pout("=======> %s", extraerror); | |
805 | UsageSummary(); | |
806 | EXIT(FAILCMD); | |
807 | } | |
808 | #endif | |
809 | if (optopt) { | |
810 | // Iff optopt holds a valid option then argument must be | |
811 | // missing. Note (BA) this logic seems to fail using Solaris | |
812 | // getopt! | |
813 | if (strchr(shortopts, optopt) != NULL) { | |
814 | pout("=======> ARGUMENT REQUIRED FOR OPTION: %c\n", optopt); | |
815 | printvalidarglistmessage(optopt); | |
816 | } else | |
817 | pout("=======> UNRECOGNIZED OPTION: %c\n",optopt); | |
818 | if (extraerror[0]) | |
819 | pout("=======> %s", extraerror); | |
820 | UsageSummary(); | |
821 | EXIT(FAILCMD); | |
822 | } | |
823 | Usage(); | |
824 | EXIT(0); | |
825 | } // closes switch statement to process command-line options | |
826 | ||
827 | // Check to see if option had an unrecognized or incorrect argument. | |
828 | if (badarg) { | |
829 | printslogan(); | |
830 | // It would be nice to print the actual option name given by the user | |
831 | // here, but we just print the short form. Please fix this if you know | |
832 | // a clean way to do it. | |
833 | pout("=======> INVALID ARGUMENT TO -%c: %s\n", optchar, optarg); | |
834 | printvalidarglistmessage(optchar); | |
835 | if (extraerror[0]) | |
836 | pout("=======> %s", extraerror); | |
837 | UsageSummary(); | |
838 | EXIT(FAILCMD); | |
839 | } | |
840 | } | |
841 | // At this point we have processed all command-line options. If the | |
842 | // print output is switchable, then start with the print output | |
843 | // turned off | |
844 | if (con->printing_switchable) | |
845 | con->dont_print=TRUE; | |
846 | ||
847 | // error message if user has asked for more than one test | |
848 | if (1<(con->smartexeoffimmediate+con->smartshortselftest+con->smartextendselftest+ | |
849 | con->smartshortcapselftest+con->smartextendcapselftest+con->smartselftestabort + (con->smartselectivenumspans>0?1:0))){ | |
850 | con->dont_print=FALSE; | |
851 | printslogan(); | |
852 | pout("\nERROR: smartctl can only run a single test type (or abort) at a time.\n"); | |
853 | UsageSummary(); | |
854 | EXIT(FAILCMD); | |
855 | } | |
856 | ||
857 | // error message if user has set selective self-test options without | |
858 | // asking for a selective self-test | |
859 | if ((con->pendingtime || con->scanafterselect) && !con->smartselectivenumspans){ | |
860 | con->dont_print=FALSE; | |
861 | printslogan(); | |
862 | if (con->pendingtime) | |
863 | pout("\nERROR: smartctl -t pending,N must be used with -t select,N-M.\n"); | |
864 | else | |
865 | pout("\nERROR: smartctl -t afterselect,(on|off) must be used with -t select,N-M.\n"); | |
866 | UsageSummary(); | |
867 | EXIT(FAILCMD); | |
868 | } | |
869 | ||
870 | // If captive option was used, change test type if appropriate. | |
871 | if (captive && con->smartshortselftest) { | |
872 | con->smartshortselftest = FALSE; | |
873 | con->smartshortcapselftest = TRUE; | |
874 | con->testcase = SHORT_CAPTIVE_SELF_TEST; | |
875 | } else if (captive && con->smartextendselftest) { | |
876 | con->smartextendselftest = FALSE; | |
877 | con->smartextendcapselftest = TRUE; | |
878 | con->testcase = EXTEND_CAPTIVE_SELF_TEST; | |
879 | } | |
880 | else if (captive && con->smartconveyanceselftest) { | |
881 | con->smartconveyanceselftest = FALSE; | |
882 | con->smartconveyancecapselftest = TRUE; | |
883 | con->testcase = CONVEYANCE_CAPTIVE_SELF_TEST; | |
884 | } | |
885 | else if (captive && con->smartselectiveselftest) { | |
886 | con->smartselectiveselftest = FALSE; | |
887 | con->smartselectivecapselftest = TRUE; | |
888 | con->testcase = SELECTIVE_CAPTIVE_SELF_TEST; | |
889 | } | |
890 | ||
891 | // From here on, normal operations... | |
892 | printslogan(); | |
893 | ||
894 | // Warn if the user has provided no device name | |
895 | if (argc-optind<1){ | |
896 | pout("ERROR: smartctl requires a device name as the final command-line argument.\n\n"); | |
897 | UsageSummary(); | |
898 | EXIT(FAILCMD); | |
899 | } | |
900 | ||
901 | // Warn if the user has provided more than one device name | |
902 | if (argc-optind>1){ | |
903 | int i; | |
904 | pout("ERROR: smartctl takes ONE device name as the final command-line argument.\n"); | |
905 | pout("You have provided %d device names:\n",argc-optind); | |
906 | for (i=0; i<argc-optind; i++) | |
907 | pout("%s\n",argv[optind+i]); | |
908 | UsageSummary(); | |
909 | EXIT(FAILCMD); | |
910 | } | |
911 | } | |
912 | ||
913 | // Printing function (controlled by global con->dont_print) | |
914 | // [From GLIBC Manual: Since the prototype doesn't specify types for | |
915 | // optional arguments, in a call to a variadic function the default | |
916 | // argument promotions are performed on the optional argument | |
917 | // values. This means the objects of type char or short int (whether | |
918 | // signed or not) are promoted to either int or unsigned int, as | |
919 | // appropriate.] | |
4d59bff9 | 920 | void pout(const char *fmt, ...){ |
832b75ed GG |
921 | va_list ap; |
922 | ||
923 | // initialize variable argument list | |
924 | va_start(ap,fmt); | |
925 | if (con->dont_print){ | |
926 | va_end(ap); | |
927 | return; | |
928 | } | |
929 | ||
930 | // print out | |
931 | vprintf(fmt,ap); | |
932 | va_end(ap); | |
933 | fflush(stdout); | |
934 | return; | |
935 | } | |
936 | ||
4d59bff9 | 937 | // This function is used by utility.cpp to report LOG_CRIT errors. |
832b75ed | 938 | // The smartctl version prints to stdout instead of syslog(). |
4d59bff9 | 939 | void PrintOut(int priority, const char *fmt, ...) { |
832b75ed GG |
940 | va_list ap; |
941 | ||
942 | // avoid warning message about unused variable from gcc -W: just | |
943 | // change value of local copy. | |
944 | priority=0; | |
945 | ||
946 | va_start(ap,fmt); | |
947 | vprintf(fmt,ap); | |
948 | va_end(ap); | |
949 | return; | |
950 | } | |
951 | ||
952 | ||
953 | /* Main Program */ | |
954 | int main (int argc, char **argv){ | |
955 | int fd,retval=0; | |
956 | char *device; | |
957 | smartmonctrl control; | |
958 | char *mode=NULL; | |
959 | ||
960 | // define control block for external functions | |
961 | con=&control; | |
962 | ||
963 | // Part input arguments | |
964 | ParseOpts(argc,argv); | |
965 | ||
966 | device = argv[argc-1]; | |
967 | ||
a37e7145 GG |
968 | // Device name "-": Parse "smartctl -r ataioctl,2 ..." output |
969 | if (!strcmp(device,"-")) { | |
970 | if (con->controller_type != CONTROLLER_UNKNOWN) { | |
971 | pout("Smartctl: -d option is not allowed in conjunction with device name \"-\".\n"); | |
972 | UsageSummary(); | |
973 | return FAILCMD; | |
974 | } | |
975 | con->controller_type = CONTROLLER_PARSEDEV; | |
976 | } | |
977 | ||
832b75ed GG |
978 | // If use has specified 3ware controller, determine which interface |
979 | if (con->controller_type == CONTROLLER_3WARE) { | |
980 | con->controller_type=guess_device_type(device); | |
981 | if (con->controller_type!=CONTROLLER_3WARE_9000_CHAR && con->controller_type!=CONTROLLER_3WARE_678K_CHAR) | |
982 | con->controller_type = CONTROLLER_3WARE_678K; | |
983 | } | |
984 | ||
985 | if (con->controller_type == CONTROLLER_UNKNOWN) | |
986 | con->controller_type=guess_device_type(device); | |
987 | ||
988 | if (con->controller_type == CONTROLLER_UNKNOWN) { | |
989 | pout("Smartctl: please specify device type with the -d option.\n"); | |
990 | UsageSummary(); | |
991 | return FAILCMD; | |
992 | } | |
993 | ||
994 | // set up mode for open() call. SCSI case is: | |
995 | switch (con->controller_type) { | |
996 | case CONTROLLER_SCSI: | |
4d59bff9 | 997 | case CONTROLLER_SAT: |
832b75ed GG |
998 | mode="SCSI"; |
999 | break; | |
1000 | case CONTROLLER_3WARE_9000_CHAR: | |
1001 | mode="ATA_3WARE_9000"; | |
1002 | break; | |
1003 | case CONTROLLER_3WARE_678K_CHAR: | |
1004 | mode="ATA_3WARE_678K"; | |
1005 | break; | |
ba59cff1 GG |
1006 | case CONTROLLER_CCISS: |
1007 | mode="CCISS"; | |
1008 | break; | |
832b75ed GG |
1009 | default: |
1010 | mode="ATA"; | |
1011 | break; | |
1012 | } | |
1013 | ||
1014 | // open device - SCSI devices are opened (O_RDWR | O_NONBLOCK) so the | |
1015 | // scsi generic device can be used (needs write permission for MODE | |
1016 | // SELECT command) plus O_NONBLOCK to stop open hanging if media not | |
1017 | // present (e.g. with st). Opening is retried O_RDONLY if read-only | |
1018 | // media prevents opening O_RDWR (it cannot happen for scsi generic | |
1019 | // devices, but it can for the others). | |
a37e7145 GG |
1020 | if (con->controller_type != CONTROLLER_PARSEDEV) |
1021 | fd = deviceopen(device, mode); | |
1022 | else | |
1023 | fd = parsedev_open(device); | |
832b75ed GG |
1024 | if (fd<0) { |
1025 | char errmsg[256]; | |
1026 | snprintf(errmsg,256,"Smartctl open device: %s failed",argv[argc-1]); | |
1027 | errmsg[255]='\0'; | |
1028 | syserror(errmsg); | |
1029 | return FAILDEV; | |
1030 | } | |
1031 | ||
1032 | // now call appropriate ATA or SCSI routine | |
1033 | switch (con->controller_type) { | |
1034 | case CONTROLLER_UNKNOWN: | |
1035 | // we should never fall into this branch! | |
1036 | pout("Smartctl: please specify device type with the -d option.\n"); | |
1037 | UsageSummary(); | |
1038 | retval = FAILCMD; | |
1039 | break; | |
1040 | case CONTROLLER_SCSI: | |
1041 | retval = scsiPrintMain(fd); | |
4d59bff9 GG |
1042 | if ((0 == retval) && (CONTROLLER_SAT == con->controller_type)) |
1043 | retval = ataPrintMain(fd); | |
832b75ed | 1044 | break; |
ba59cff1 GG |
1045 | case CONTROLLER_CCISS: |
1046 | // route the cciss command through scsiPrintMain. | |
1047 | // cciss pass-throughs will separeate from the SCSI data-path. | |
1048 | retval = scsiPrintMain(fd); | |
1049 | break; | |
832b75ed GG |
1050 | default: |
1051 | retval = ataPrintMain(fd); | |
1052 | break; | |
1053 | } | |
1054 | ||
a37e7145 GG |
1055 | if (con->controller_type != CONTROLLER_PARSEDEV) |
1056 | deviceclose(fd); | |
1057 | else | |
1058 | parsedev_close(fd); | |
1059 | ||
832b75ed GG |
1060 | return retval; |
1061 | } |