Handle duplicated Total LBAs Written
[platform/upstream/libatasmart.git] / skdump.c
1 /*-*- Mode: C; c-basic-offset: 8 -*-*/
2
3 /***
4     This file is part of libatasmart.
5
6     Copyright 2008 Lennart Poettering
7
8     libatasmart is free software; you can redistribute it and/or modify
9     it under the terms of the GNU Lesser General Public License as
10     published by the Free Software Foundation, either version 2.1 of the
11     License, or (at your option) any later version.
12
13     libatasmart is distributed in the hope that it will be useful, but
14     WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16     Lesser General Public License for more details.
17
18     You should have received a copy of the GNU Lesser General Public
19     License along with libatasmart. If not, If not, see
20     <http://www.gnu.org/licenses/>.
21 ***/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <stdio.h>
28 #include <string.h>
29 #include <errno.h>
30 #include <getopt.h>
31
32 #include "atasmart.h"
33
34 enum {
35         MODE_DUMP = 10,
36         MODE_OVERALL,
37         MODE_POWER_ON,
38         MODE_POWER_CYCLE,
39         MODE_BAD,
40         MODE_TEMPERATURE,
41         MODE_STATUS,
42         MODE_CAN_SMART,
43         MODE_SAVE
44 };
45
46 int mode = MODE_DUMP;
47
48 enum {
49         ARG_SAVE = 256,
50         ARG_LOAD
51 };
52
53 int main(int argc, char *argv[]) {
54         int ret;
55         const char *device = NULL, *argv0, *p, *file = NULL;
56         SkDisk *d;
57         int q = 1;
58         SkBool from_blob = FALSE;
59
60         static const struct option long_options[] = {
61                 {"overall",     no_argument, &mode, MODE_OVERALL},
62                 {"power-on",    no_argument, &mode, MODE_POWER_ON},
63                 {"power-cycle", no_argument, &mode, MODE_POWER_CYCLE},
64                 {"bad",         no_argument, &mode, MODE_BAD},
65                 {"temperature", no_argument, &mode, MODE_TEMPERATURE},
66                 {"can-smart",   no_argument, &mode, MODE_CAN_SMART},
67                 {"status",      no_argument, &mode, MODE_STATUS},
68                 {"save",        optional_argument, NULL, ARG_SAVE},
69                 {"load",        optional_argument, NULL, ARG_LOAD},
70                 {"help",        no_argument, NULL, 'h' },
71                 {0, 0, 0, 0}
72         };
73
74         argv0 = argv[0];
75         if ((p = strrchr(argv0, '/')))
76                 argv0 = p+1;
77
78         for (;;) {
79                 int opt;
80
81                 if ((opt = getopt_long(argc, argv, "h", long_options, NULL)) < 0)
82                         break;
83
84                 switch (opt) {
85                         case 0:
86                                 break;
87
88                         case 'h':
89                                 fprintf(stderr,
90                                         "Usage: %s [PARAMETERS] DEVICE\n"
91                                         "Reads ATA SMART data from a device and parses it.\n"
92                                         "\n"
93                                         "\t--overall        \tShow overall status\n"
94                                         "\t--status         \tShow SMART status\n"
95                                         "\t--can-smart      \tShow whether SMART is supported\n"
96                                         "\t--power-on       \tPrint power on time in ms\n"
97                                         "\t--power-cycle    \tPrint number of power cycles\n"
98                                         "\t--bad            \tPrint bad sector count\n"
99                                         "\t--temperature    \tPrint drive temperature in mKelvin\n"
100                                         "\t--save[=FILENAME]\tSave raw data to file/STDOUT\n"
101                                         "\t--load[=FILENAME]\tRead data from a file/STDIN instead of device\n"
102                                         "\t-h | --help      \tShow this help\n", argv0);
103
104                                 return 0;
105
106                         case ARG_SAVE:
107                                 file = optarg;
108                                 mode = MODE_SAVE;
109                                 break;
110
111                         case ARG_LOAD:
112                                 device = optarg ? optarg : "-";
113                                 from_blob = TRUE;
114                                 break;
115
116                         case '?':
117                                 return 1;
118
119                         default:
120                                 fprintf(stderr, "Invalid arguments.\n");
121                                 return 1;
122                 }
123         }
124
125         if (!device) {
126                 if (optind != argc-1) {
127                         fprintf(stderr, "No or more than one device specified.\n");
128                         return 1;
129                 }
130
131                 device = argv[optind];
132         } else {
133                 if (optind != argc) {
134                         fprintf(stderr, "Too many arguments.\n");
135                         return 1;
136                 }
137         }
138
139         if (from_blob) {
140                 uint8_t blob[4096];
141                 size_t size;
142                 FILE *f = stdin;
143
144                 if ((ret = sk_disk_open(NULL, &d)) < 0) {
145                         fprintf(stderr, "Failed to open disk: %s\n", strerror(errno));
146                         return 1;
147                 }
148
149                 if (strcmp(device, "-")) {
150                         if (!(f = fopen(device, "r"))) {
151                                 fprintf(stderr, "Failed to open file: %s\n", strerror(errno));
152                                 goto finish;
153                         }
154                 }
155
156                 size = fread(blob, 1, sizeof(blob), f);
157
158                 if (f != stdin)
159                         fclose(f);
160
161                 if (size >= sizeof(blob)) {
162                         fprintf(stderr, "File too large for buffer.\n");
163                         goto finish;
164                 }
165
166                 if ((ret = sk_disk_set_blob(d, blob, size)) < 0) {
167                         fprintf(stderr, "Failed to set blob: %s\n", strerror(errno));
168                         goto finish;
169                 }
170
171         } else {
172                 if ((ret = sk_disk_open(device, &d)) < 0) {
173                         fprintf(stderr, "Failed to open disk %s: %s\n", device, strerror(errno));
174                         return 1;
175                 }
176         }
177
178         switch (mode) {
179                 case MODE_DUMP:
180                         if ((ret = sk_disk_dump(d)) < 0) {
181                                 fprintf(stderr, "Failed to dump disk data: %s\n", strerror(errno));
182                                 goto finish;
183                         }
184
185                         break;
186
187                 case MODE_CAN_SMART: {
188                         SkBool available;
189
190                         if ((ret = sk_disk_smart_is_available(d, &available)) < 0) {
191                                 fprintf(stderr, "Failed to query whether SMART is available: %s\n", strerror(errno));
192                                 goto finish;
193                         }
194
195                         printf("%s\n", available ? "YES" : "NO");
196                         q = available ? 0 : 1;
197                         break;
198                 }
199
200                 case MODE_OVERALL: {
201                         SkSmartOverall overall;
202
203                         if ((ret = sk_disk_smart_read_data(d)) < 0) {
204                                 fprintf(stderr, "Failed to read SMART data: %s\n", strerror(errno));
205                                 goto finish;
206                         }
207
208                         if ((ret = sk_disk_smart_get_overall(d, &overall)) < 0) {
209                                 fprintf(stderr, "Failed to get overall status: %s\n", strerror(errno));
210                                 goto finish;
211                         }
212
213                         printf("%s\n", sk_smart_overall_to_string(overall));
214                         q = overall == SK_SMART_OVERALL_GOOD ? 0 : 1;
215                         goto finish;
216                 }
217
218                 case MODE_STATUS: {
219                         SkBool good;
220
221                         if ((ret = sk_disk_smart_status(d, &good)) < 0) {
222                                 fprintf(stderr, "Failed to get SMART status: %s\n", strerror(errno));
223                                 goto finish;
224                         }
225
226                         printf("%s\n", good ? "GOOD" : "BAD");
227                         q = good ? 0 : 1;
228                         goto finish;
229                 }
230
231                 case MODE_POWER_ON: {
232                         uint64_t ms;
233
234                         if ((ret = sk_disk_smart_read_data(d)) < 0) {
235                                 fprintf(stderr, "Failed to read SMART data: %s\n", strerror(errno));
236                                 goto finish;
237                         }
238
239                         if ((ret = sk_disk_smart_get_power_on(d, &ms)) < 0) {
240                                 fprintf(stderr, "Failed to get power on time: %s\n", strerror(errno));
241                                 goto finish;
242                         }
243
244                         printf("%llu\n", (unsigned long long) ms);
245                         break;
246                 }
247
248                 case MODE_POWER_CYCLE: {
249                         uint64_t count;
250
251                         if ((ret = sk_disk_smart_read_data(d)) < 0) {
252                                 fprintf(stderr, "Failed to read SMART data: %s\n", strerror(errno));
253                                 goto finish;
254                         }
255
256                         if ((ret = sk_disk_smart_get_power_cycle(d, &count)) < 0) {
257                                 fprintf(stderr, "Failed to get power cycles: %s\n", strerror(errno));
258                                 goto finish;
259                         }
260
261                         printf("%llu\n", (unsigned long long) count);
262                         break;
263                 }
264
265                 case MODE_BAD: {
266                         uint64_t bad;
267
268                         if ((ret = sk_disk_smart_read_data(d)) < 0) {
269                                 fprintf(stderr, "Failed to read SMART data: %s\n", strerror(errno));
270                                 goto finish;
271                         }
272
273                         if ((ret = sk_disk_smart_get_bad(d, &bad)) < 0) {
274                                 fprintf(stderr, "Failed to get bad sectors: %s\n", strerror(errno));
275                                 goto finish;
276                         }
277
278                         printf("%llu\n", (unsigned long long) bad);
279                         q = !!bad;
280                         goto finish;
281                 }
282
283                 case MODE_TEMPERATURE: {
284                         uint64_t mkelvin;
285
286                         if ((ret = sk_disk_smart_read_data(d)) < 0) {
287                                 fprintf(stderr, "Failed to read SMART data: %s\n", strerror(errno));
288                                 goto finish;
289                         }
290
291                         if ((ret = sk_disk_smart_get_temperature(d, &mkelvin)) < 0) {
292                                 fprintf(stderr, "Failed to get temperature: %s\n", strerror(errno));
293                                 goto finish;
294                         }
295
296                         printf("%llu\n", (unsigned long long) mkelvin);
297                         break;
298                 }
299
300                 case MODE_SAVE: {
301                         const void *blob;
302                         size_t size;
303                         FILE *f = stdout;
304                         size_t n;
305
306                         if ((ret = sk_disk_smart_read_data(d)) < 0) {
307                                 fprintf(stderr, "Failed to read SMART data: %s\n", strerror(errno));
308                                 goto finish;
309                         }
310
311                         if ((ret = sk_disk_get_blob(d, &blob, &size)) < 0) {
312                                 fprintf(stderr, "Failed to get blob: %s\n", strerror(errno));
313                                 goto finish;
314                         }
315
316                         if (file && strcmp(file, "-")) {
317                                 if (!(f = fopen(file, "w"))) {
318                                         fprintf(stderr, "Failed to open '%s': %s\n", file, strerror(errno));
319                                         goto finish;
320                                 }
321                         }
322
323                         n = fwrite(blob, 1, size, f);
324
325                         if (f != stdout)
326                                 fclose(f);
327
328                         if (n != size) {
329                                 fprintf(stderr, "Failed to write to disk: %s\n", strerror(errno));
330                                 goto finish;
331                         }
332
333                         break;
334                 }
335
336         }
337
338
339         q = 0;
340
341 finish:
342
343         if (d)
344                 sk_disk_free(d);
345
346         return q;
347 }