beef up skdump to be able to load/save blobs
[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_BAD,
39         MODE_TEMPERATURE,
40         MODE_SAVE
41 };
42
43 int mode = MODE_DUMP;
44
45 enum {
46         ARG_SAVE = 256,
47         ARG_LOAD
48 };
49
50 int main(int argc, char *argv[]) {
51         int ret;
52         const char *device = NULL, *argv0, *p, *file = NULL;
53         SkDisk *d;
54         int q = 1;
55         SkBool from_blob = FALSE;
56
57         static const struct option long_options[] = {
58                 {"overall",     no_argument, &mode, MODE_OVERALL},
59                 {"power-on",    no_argument, &mode, MODE_POWER_ON},
60                 {"bad",         no_argument, &mode, MODE_BAD},
61                 {"temperature", no_argument, &mode, MODE_TEMPERATURE},
62                 {"save",        optional_argument, NULL, ARG_SAVE},
63                 {"load",        optional_argument, NULL, ARG_LOAD},
64                 {"help",        no_argument, NULL, 'h' },
65                 {0, 0, 0, 0}
66         };
67
68         argv0 = argv[0];
69         if ((p = strrchr(argv0, '/')))
70                 argv0 = p+1;
71
72         for (;;) {
73                 int opt;
74
75                 if ((opt = getopt_long(argc, argv, "h", long_options, NULL)) < 0)
76                         break;
77
78                 switch (opt) {
79                         case 0:
80                                 break;
81
82                         case 'h':
83                                 fprintf(stderr,
84                                         "Usage: %s [PARAMETERS] DEVICE\n"
85                                         "Reads ATA SMART data from a device and parses it.\n"
86                                         "\n"
87                                         "\t--overall        \tShow overall status\n"
88                                         "\t--power-on       \tPrint power on time in ms\n"
89                                         "\t--bad            \tPrint bad sector count\n"
90                                         "\t--temperature    \tPrint drive temperature in mKelvin\n"
91                                         "\t--save[=FILENAME]\tSave raw data to file/STDOUT\n"
92                                         "\t--load           \tRead data from a file/STDIN instead of device\n"
93                                         "\t-h | --help      \tShow this help\n", argv0);
94
95                                 return 0;
96
97                         case ARG_SAVE:
98                                 file = optarg;
99                                 mode = MODE_SAVE;
100                                 break;
101
102                         case ARG_LOAD:
103                                 device = optarg ? optarg : "-";
104                                 from_blob = TRUE;
105                                 break;
106
107                         case '?':
108                                 return 1;
109
110                         default:
111                                 fprintf(stderr, "Invalid arguments.\n");
112                                 return 1;
113                 }
114         }
115
116         if (!device) {
117                 if (optind != argc-1) {
118                         fprintf(stderr, "No or more than one device specified.\n");
119                         return 1;
120                 }
121
122                 device = argv[optind];
123         } else {
124                 if (optind != argc) {
125                         fprintf(stderr, "Too many arguments.\n");
126                         return 1;
127                 }
128         }
129
130         if (from_blob) {
131                 uint8_t blob[4096];
132                 size_t size;
133                 FILE *f = stdin;
134
135                 if ((ret = sk_disk_open(NULL, &d)) < 0) {
136                         fprintf(stderr, "Failed to open disk: %s\n", strerror(errno));
137                         return 1;
138                 }
139
140                 if (strcmp(device, "-")) {
141                         if (!(f = fopen(device, "r"))) {
142                                 fprintf(stderr, "Failed to open file: %s\n", strerror(errno));
143                                 goto finish;
144                         }
145                 }
146
147                 size = fread(blob, 1, sizeof(blob), f);
148
149                 if (f != stdin)
150                         fclose(f);
151
152                 if (size >= sizeof(blob)) {
153                         fprintf(stderr, "File too large for buffer.\n");
154                         goto finish;
155                 }
156
157                 if ((ret = sk_disk_set_blob(d, blob, size)) < 0) {
158                         fprintf(stderr, "Failed to set blob: %s\n", strerror(errno));
159                         goto finish;
160                 }
161
162         } else {
163                 if ((ret = sk_disk_open(device, &d)) < 0) {
164                         fprintf(stderr, "Failed to open disk %s: %s\n", device, strerror(errno));
165                         return 1;
166                 }
167         }
168
169         switch (mode) {
170                 case MODE_DUMP:
171                         if ((ret = sk_disk_dump(d)) < 0) {
172                                 fprintf(stderr, "Failed to dump disk data: %s\n", strerror(errno));
173                                 goto finish;
174                         }
175
176                         break;
177
178                 case MODE_OVERALL: {
179                         SkSmartOverall overall;
180
181                         if ((ret = sk_disk_smart_read_data(d)) < 0) {
182                                 fprintf(stderr, "Failed to read SMART data: %s\n", strerror(errno));
183                                 goto finish;
184                         }
185
186                         if ((ret = sk_disk_smart_get_overall(d, &overall)) < 0) {
187                                 fprintf(stderr, "Failed to get overall status: %s\n", strerror(errno));
188                                 goto finish;
189                         }
190
191                         printf("%s\n", sk_smart_overall_to_string(overall));
192                         q = overall == SK_SMART_OVERALL_GOOD ? 0 : 1;
193                         goto finish;
194                 }
195
196                 case MODE_POWER_ON: {
197                         uint64_t ms;
198
199                         if ((ret = sk_disk_smart_read_data(d)) < 0) {
200                                 fprintf(stderr, "Failed to read SMART data: %s\n", strerror(errno));
201                                 goto finish;
202                         }
203
204                         if ((ret = sk_disk_smart_get_power_on(d, &ms)) < 0) {
205                                 fprintf(stderr, "Failed to get power on time: %s\n", strerror(errno));
206                                 goto finish;
207                         }
208
209                         printf("%llu\n", (unsigned long long) ms);
210                         break;
211                 }
212
213
214                 case MODE_BAD: {
215                         uint64_t bad;
216
217                         if ((ret = sk_disk_smart_read_data(d)) < 0) {
218                                 fprintf(stderr, "Failed to read SMART data: %s\n", strerror(errno));
219                                 goto finish;
220                         }
221
222                         if ((ret = sk_disk_smart_get_bad(d, &bad)) < 0) {
223                                 fprintf(stderr, "Failed to get bad sectors: %s\n", strerror(errno));
224                                 goto finish;
225                         }
226
227                         printf("%llu\n", (unsigned long long) bad);
228                         q = !!bad;
229                         goto finish;
230                 }
231
232                 case MODE_TEMPERATURE: {
233                         uint64_t mkelvin;
234
235                         if ((ret = sk_disk_smart_read_data(d)) < 0) {
236                                 fprintf(stderr, "Failed to read SMART data: %s\n", strerror(errno));
237                                 goto finish;
238                         }
239
240                         if ((ret = sk_disk_smart_get_temperature(d, &mkelvin)) < 0) {
241                                 fprintf(stderr, "Failed to get temperature: %s\n", strerror(errno));
242                                 goto finish;
243                         }
244
245                         printf("%llu\n", (unsigned long long) mkelvin);
246                         break;
247                 }
248
249                 case MODE_SAVE: {
250                         const void *blob;
251                         size_t size;
252                         FILE *f = stdout;
253                         size_t n;
254
255                         if ((ret = sk_disk_smart_read_data(d)) < 0) {
256                                 fprintf(stderr, "Failed to read SMART data: %s\n", strerror(errno));
257                                 goto finish;
258                         }
259
260                         if ((ret = sk_disk_get_blob(d, &blob, &size)) < 0) {
261                                 fprintf(stderr, "Failed to get blob: %s\n", strerror(errno));
262                                 goto finish;
263                         }
264
265                         if (file && strcmp(file, "-")) {
266                                 if (!(f = fopen(file, "w"))) {
267                                         fprintf(stderr, "Failed to open '%s': %s\n", file, strerror(errno));
268                                         goto finish;
269                                 }
270                         }
271
272                         n = fwrite(blob, 1, size, f);
273
274                         if (f != stdout)
275                                 fclose(f);
276
277                         if (n != size) {
278                                 fprintf(stderr, "Failed to write to disk: %s\n", strerror(errno));
279                                 goto finish;
280                         }
281
282                         break;
283                 }
284
285         }
286
287
288         q = 0;
289
290 finish:
291
292         if (d)
293                 sk_disk_free(d);
294
295         return q;
296 }