smartctl.cpp 10.2 KB
Newer Older
ballen4705's avatar
ballen4705 committed
1
2
3
/*
 * smartctl.c
 *
4
5
 * Home page of code is: http://smartmontools.sourceforge.net
 *
ballen4705's avatar
ballen4705 committed
6
 * Copyright (C) 2002 Bruce Allen <smartmontools-support@lists.sourceforge.net>
ballen4705's avatar
ballen4705 committed
7
8
9
10
11
12
13
14
15
16
 * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * You should have received a copy of the GNU General Public License
 * (for example COPYING); if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
ballen4705's avatar
ballen4705 committed
17
18
19
20
21
22
 *
 * This code was originally developed as a Senior Thesis by Michael Cornwell
 * at the Concurrent Systems Laboratory (now part of the Storage Systems
 * Research Center), Jack Baskin School of Engineering, University of
 * California, Santa Cruz. http://ssrc.soe.ucsc.edu/
 *
ballen4705's avatar
ballen4705 committed
23
24
25
26
27
28
29
30
31
32
 */


#include <stdio.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/hdreg.h>
#include <sys/fcntl.h>
#include <sys/types.h>
#include <string.h>
33
#include <stdarg.h>
ballen4705's avatar
ballen4705 committed
34
35
36
37
38
#include "smartctl.h"
#include "atacmds.h"
#include "ataprint.h"
#include "scsicmds.h"
#include "scsiprint.h"
39
#include "extern.h"
ballen4705's avatar
ballen4705 committed
40

41
extern const char *CVSid1, *CVSid2, *CVSid3, *CVSid4; 
ballen4705's avatar
ballen4705 committed
42
const char* CVSid5="$Id: smartctl.cpp,v 1.24 2002/10/30 06:02:40 ballen4705 Exp $"
43
CVSID1 CVSID2 CVSID3 CVSID4 CVSID5 CVSID6;
ballen4705's avatar
ballen4705 committed
44

45
46
47
// This is a block containing all the "control variables".  We declare
// this globally in this file, and externally in other files.
atamainctrl *con=NULL;
ballen4705's avatar
ballen4705 committed
48

49
void printslogan(){
50
  pout("smartctl version %d.%d-%d Copyright (C) 2002 Bruce Allen\n",
ballen4705's avatar
ballen4705 committed
51
      (int)RELEASE_MAJOR, (int)RELEASE_MINOR, (int)SMARTMONTOOLS_VERSION);
ballen4705's avatar
ballen4705 committed
52
  pout("Home page is %s\n\n",PROJECTHOME);
53
54
55
56
57
  return;
}


void printcopy(){
58
  char out[CVSMAXLEN];
59
60
61
62
63
  pout("smartctl comes with ABSOLUTELY NO WARRANTY. This\n");
  pout("is free software, and you are welcome to redistribute it\n");
  pout("under the terms of the GNU General Public License Version 2.\n");
  pout("See http://www.gnu.org for further details.\n\n");
  pout("CVS version IDs of files used to build this code are:\n");
64
65
66
67
  printone(out,CVSid1);
  pout("%s",out);
  printone(out,CVSid2);
  pout("%s",out);
68
69
  printone(out,CVSid3);
  pout("%s",out);
70
71
72
73
  printone(out,CVSid4);
  pout("%s",out);
  printone(out,CVSid5);
  pout("%s",out);
74
75
76
77
  return;
}

/*  void prints help information for command syntax */
ballen4705's avatar
ballen4705 committed
78
void Usage ( void){
ballen4705's avatar
ballen4705 committed
79
80
  printf("Usage: smartctl -[options] [device]\n");
  printf("\nRead Only Options:\n");
81
82
83
84
85
86
87
88
89
90
  printf("  %c  Show version, copyright and license info\n", PRINTCOPYLEFT);
  printf("  %c  Show all SMART Information              (ATA/SCSI)\n",SMARTVERBOSEALL);
  printf("  %c  Show SMART Drive Info                   (ATA/SCSI)\n",DRIVEINFO);
  printf("  %c  Show SMART Status                       (ATA/SCSI)\n",CHECKSMART);
  printf("  %c  Show SMART General Attributes           (ATA Only)\n",    GENERALSMARTVALUES);
  printf("  %c  Show SMART Vendor Attributes            (ATA Only)\n",    SMARTVENDORATTRIB);
  printf("  %c  Show SMART Drive Error Log              (ATA Only\n",     SMARTERRORLOG);
  printf("  %c  Show SMART Drive Self Test Log          (ATA Only)\n",    SMARTSELFTESTLOG);
  printf("  %c  Quiet: only show SMART drive errors     (ATA Only)\n",    QUIETMODE);
  printf("  %c  Very Quiet: no display, use exit status (ATA Only)\n",    VERYQUIETMODE);
ballen4705's avatar
ballen4705 committed
91
  printf("\nVendor-specific Display Options:\n");
92
  printf("  %c  Raw Attribute 009 is minutes            (ATA Only)\n",    SMART009MINUTES);
ballen4705's avatar
ballen4705 committed
93
  printf("\nEnable/Disable Options:\n");
94
95
96
97
98
99
  printf("  %c  Enable  SMART data collection           (ATA/SCSI)\n",SMARTENABLE);
  printf("  %c  Disable SMART data collection           (ATA/SCSI)\n",SMARTDISABLE);
  printf("  %c  Enable  SMART Automatic Offline Test    (ATA Only)\n",    SMARTAUTOOFFLINEENABLE);
  printf("  %c  Disable SMART Automatic Offline Test    (ATA Only)\n",    SMARTAUTOOFFLINEDISABLE);
  printf("  %c  Enable  SMART Attribute Autosave        (ATA Only)\n",    SMARTAUTOSAVEENABLE);
  printf("  %c  Disable SMART Attribute Autosave        (ATA Only)\n",    SMARTAUTOSAVEDISABLE);
ballen4705's avatar
ballen4705 committed
100
  printf("\nTest Options (no more than one):\n");
101
102
103
104
105
106
  printf("  %c  Execute Off-line data collection        (ATA/SCSI)\n",    SMARTEXEOFFIMMEDIATE);
  printf("  %c  Execute Short Self Test                 (ATA/SCSI)\n",    SMARTSHORTSELFTEST );
  printf("  %c  Execute Short Self Test (Captive Mode)  (ATA/SCSI)\n",    SMARTSHORTCAPSELFTEST );
  printf("  %c  Execute Extended Self Test              (ATA/SCSI)\n",    SMARTEXTENDSELFTEST );
  printf("  %c  Execute Extended Self Test (Captive)    (ATA/SCSI)\n",    SMARTEXTENDCAPSELFTEST );
  printf("  %c  Execute Self Test Abort                 (ATA/SCSI)\n",    SMARTSELFTESTABORT );
ballen4705's avatar
ballen4705 committed
107
  printf("\nExamples:\n");
108
109
110
111
  printf("  smartctl -etf /dev/hda  (Enables SMART on first disk)\n");
  printf("  smartctl -a   /dev/hda  (Prints all SMART information)\n");
  printf("  smartctl -X   /dev/hda  (Executes extended disk self-test)\n");
  printf("  smartctl -qvL /dev/hda  (Prints Self-Test & Attribute errors.)\n");
ballen4705's avatar
ballen4705 committed
112
113
}

114
115
116
117
118
119
const char opts[] = { 
  DRIVEINFO, CHECKSMART, SMARTVERBOSEALL, SMARTVENDORATTRIB,
  GENERALSMARTVALUES, SMARTERRORLOG, SMARTSELFTESTLOG, SMARTDISABLE,
  SMARTENABLE, SMARTAUTOOFFLINEENABLE, SMARTAUTOOFFLINEDISABLE,
  SMARTEXEOFFIMMEDIATE, SMARTSHORTSELFTEST, SMARTEXTENDSELFTEST, 
  SMARTSHORTCAPSELFTEST, SMARTEXTENDCAPSELFTEST, SMARTSELFTESTABORT,
120
  SMARTAUTOSAVEENABLE,SMARTAUTOSAVEDISABLE,PRINTCOPYLEFT,SMART009MINUTES,QUIETMODE,VERYQUIETMODE,'h','?','\0'
121
};
ballen4705's avatar
ballen4705 committed
122

123
124
unsigned char printcopyleft=0;

125
/*      Takes command options and sets features to be run */	
ballen4705's avatar
ballen4705 committed
126
void ParseOpts (int argc, char** argv){
127
128
129
  int optchar;
  extern char *optarg;
  extern int optopt, optind, opterr;
ballen4705's avatar
ballen4705 committed
130
  
131
132
  memset(con,0,sizeof(*con));
  con->testcase=-1;
133
  opterr=optopt=0;
134
  while (-1 != (optchar = getopt(argc, argv, opts))) {
ballen4705's avatar
ballen4705 committed
135
    switch (optchar){
136
    case QUIETMODE:
137
      con->quietmode=TRUE;
138
139
      break;
    case VERYQUIETMODE:
140
      con->veryquietmode=TRUE;
141
      break;
142
    case SMART009MINUTES:
143
      con->smart009minutes=TRUE;
144
      break;
ballen4705's avatar
ballen4705 committed
145
146
147
148
    case PRINTCOPYLEFT :
      printcopyleft=TRUE;
      break;
    case DRIVEINFO :
149
      con->driveinfo  = TRUE;
ballen4705's avatar
ballen4705 committed
150
151
      break;		
    case CHECKSMART :
152
      con->checksmart = TRUE;		
ballen4705's avatar
ballen4705 committed
153
154
      break;
    case SMARTVERBOSEALL :
155
156
157
158
159
160
      con->driveinfo = TRUE;
      con->checksmart = TRUE;
      con->generalsmartvalues = TRUE;
      con->smartvendorattrib = TRUE;
      con->smarterrorlog = TRUE;
      con->smartselftestlog = TRUE;
ballen4705's avatar
ballen4705 committed
161
162
      break;
    case SMARTVENDORATTRIB :
163
      con->smartvendorattrib = TRUE;
ballen4705's avatar
ballen4705 committed
164
165
      break;
    case GENERALSMARTVALUES :
166
      con->generalsmartvalues = TRUE;
ballen4705's avatar
ballen4705 committed
167
168
      break;
    case SMARTERRORLOG :
169
      con->smarterrorlog = TRUE;
ballen4705's avatar
ballen4705 committed
170
171
      break;
    case SMARTSELFTESTLOG :
172
      con->smartselftestlog = TRUE;
ballen4705's avatar
ballen4705 committed
173
174
      break;
    case SMARTDISABLE :
175
      con->smartdisable = TRUE;
ballen4705's avatar
ballen4705 committed
176
177
      break;
    case SMARTENABLE :
178
      con->smartenable   = TRUE;
ballen4705's avatar
ballen4705 committed
179
180
      break;
    case SMARTAUTOSAVEENABLE:
181
      con->smartautosaveenable = TRUE;
ballen4705's avatar
ballen4705 committed
182
183
      break;
    case SMARTAUTOSAVEDISABLE:
184
      con->smartautosavedisable = TRUE;
ballen4705's avatar
ballen4705 committed
185
186
      break;
    case SMARTAUTOOFFLINEENABLE: 
187
      con->smartautoofflineenable = TRUE;
ballen4705's avatar
ballen4705 committed
188
189
      break;
    case SMARTAUTOOFFLINEDISABLE:
190
      con->smartautoofflinedisable = TRUE;
ballen4705's avatar
ballen4705 committed
191
192
      break;
    case SMARTEXEOFFIMMEDIATE:
193
194
      con->smartexeoffimmediate = TRUE;
      con->testcase=OFFLINE_FULL_SCAN;
ballen4705's avatar
ballen4705 committed
195
196
      break;
    case SMARTSHORTSELFTEST :
197
198
      con->smartshortselftest = TRUE;
      con->testcase=SHORT_SELF_TEST;
ballen4705's avatar
ballen4705 committed
199
200
      break;
    case SMARTEXTENDSELFTEST :
201
202
      con->smartextendselftest = TRUE;
      con->testcase=EXTEND_SELF_TEST;
ballen4705's avatar
ballen4705 committed
203
204
      break;
    case SMARTSHORTCAPSELFTEST:
205
206
      con->smartshortcapselftest = TRUE;
      con->testcase=SHORT_CAPTIVE_SELF_TEST;
ballen4705's avatar
ballen4705 committed
207
208
      break;
    case SMARTEXTENDCAPSELFTEST:
209
210
      con->smartextendcapselftest = TRUE;
      con->testcase=EXTEND_CAPTIVE_SELF_TEST;
ballen4705's avatar
ballen4705 committed
211
212
      break;
    case SMARTSELFTESTABORT:
213
214
      con->smartselftestabort = TRUE;
      con->testcase=ABORT_SELF_TEST;
ballen4705's avatar
ballen4705 committed
215
      break;
216
217
    case 'h':
    case '?':
ballen4705's avatar
ballen4705 committed
218
    default:
219
      con->veryquietmode=FALSE;
220
      printslogan();
221
      if (optopt){
ballen4705's avatar
ballen4705 committed
222
	pout("=======> UNRECOGNIZED OPTION: %c <=======\n\n",(int)optopt);
223
224
225
	Usage();
	exit(FAILCMD);
      }
ballen4705's avatar
ballen4705 committed
226
      Usage();
227
      exit(0);	
ballen4705's avatar
ballen4705 committed
228
229
    }
  }
230
  // Do this here, so results are independent of argument order	
231
232
  if (con->quietmode)
    con->veryquietmode=TRUE;
233
  
234
  // error message if user has asked for more than one test
235
236
237
  if (1<(con->smartexeoffimmediate+con->smartshortselftest+con->smartextendselftest+
	 con->smartshortcapselftest+con->smartextendcapselftest+con->smartselftestabort)){
    con->veryquietmode=FALSE;
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
    printslogan();
    Usage();
    printf ("\nERROR: smartctl can only run a single test (or abort) at a time.\n\n");
    exit(FAILCMD);
  }

  // From here on, normal operations...
  printslogan();
  
  // Print Copyright/License info if needed
  if (printcopyleft){
    printcopy();
    if (argc==2)
      exit(0);
  }   
ballen4705's avatar
ballen4705 committed
253
254
255
}


ballen4705's avatar
ballen4705 committed
256
257
258
259
260
261
262
263
// Printing function (controlled by global con->veryquietmode) 

// [From GLIBC Manual: Since the prototype doesn't specify types for
// optional arguments, in a call to a variadic function the default
// argument promotions are performed on the optional argument
// values. This means the objects of type char or short int (whether
// signed or not) are promoted to either int or unsigned int, as
// appropriate.]
264
265
266
267
268
void pout(char *fmt, ...){
  va_list ap;

  // initialize variable argument list 
  va_start(ap,fmt);
269
  if (con->veryquietmode){
270
271
272
273
274
275
276
277
278
279
280
281
    va_end(ap);
    return;
  }

  // print out
  vprintf(fmt,ap);
  va_end(ap);
  return;
}


/* Main Program */
ballen4705's avatar
ballen4705 committed
282
int main (int argc, char **argv){
283
  int fd,retval=0;
ballen4705's avatar
ballen4705 committed
284
  char *device;
285
286
287
288
289
  atamainctrl control;

  // define control block for external functions
  con=&control;

ballen4705's avatar
ballen4705 committed
290
  // Part input arguments
291
  ParseOpts(argc,argv);
292
    
ballen4705's avatar
ballen4705 committed
293
  // Further argument checking
294
  if (argc != 3){
ballen4705's avatar
ballen4705 committed
295
    Usage();
296
    return FAILCMD;
ballen4705's avatar
ballen4705 committed
297
  }
298
  
299
  // open device - read-only mode is enough to issue needed commands
300
  fd = open(device=argv[2], O_RDONLY);
ballen4705's avatar
ballen4705 committed
301
  
302
303
  if (fd<0) {
    perror("Smartctl device open failed");
304
    return FAILDEV;
ballen4705's avatar
ballen4705 committed
305
306
  }
  
307
  if (device[5] == 'h')
308
    retval=ataPrintMain(fd);
ballen4705's avatar
ballen4705 committed
309
310
  else if (device[5] == 's')
    scsiPrintMain (fd);
311
  else {
ballen4705's avatar
ballen4705 committed
312
    Usage();
313
314
315
316
    return FAILCMD;
  }

  return retval;
ballen4705's avatar
ballen4705 committed
317
}