]>
Commit | Line | Data |
---|---|---|
51410fc6 KZ |
1 | /* |
2 | * blkid.c - User command-line interface for libblkid | |
3 | * | |
4 | * Copyright (C) 2001 Andreas Dilger | |
5 | * | |
6 | * %Begin-Header% | |
7 | * This file may be redistributed under the terms of the | |
8 | * GNU Lesser General Public License. | |
9 | * %End-Header% | |
10 | */ | |
11 | ||
12 | #include <stdio.h> | |
13 | #include <stdlib.h> | |
14 | #include <unistd.h> | |
15 | #include <string.h> | |
5b6215b5 KZ |
16 | #include <sys/types.h> |
17 | #include <sys/stat.h> | |
18 | #include <fcntl.h> | |
4fc5d65b | 19 | #include <errno.h> |
51410fc6 KZ |
20 | #ifdef HAVE_GETOPT_H |
21 | #include <getopt.h> | |
22 | #else | |
23 | extern int getopt(int argc, char * const argv[], const char *optstring); | |
24 | extern char *optarg; | |
25 | extern int optind; | |
26 | #endif | |
27 | ||
ab978962 KZ |
28 | #define OUTPUT_VALUE_ONLY (1 << 1) |
29 | #define OUTPUT_DEVICE_ONLY (1 << 2) | |
24d741d8 KZ |
30 | #define OUTPUT_PRETTY_LIST (1 << 3) /* deprecated */ |
31 | #define OUTPUT_UDEV_LIST (1 << 4) /* deprecated */ | |
ab978962 | 32 | #define OUTPUT_EXPORT_LIST (1 << 5) |
51410fc6 | 33 | |
ab978962 KZ |
34 | #define LOWPROBE_TOPOLOGY (1 << 1) |
35 | #define LOWPROBE_SUPERBLOCKS (1 << 2) | |
09792910 | 36 | |
1578ddd6 PU |
37 | #define BLKID_EXIT_NOTFOUND 2 /* token or device not found */ |
38 | #define BLKID_EXIT_OTHER 4 /* bad usage or other error */ | |
39 | #define BLKID_EXIT_AMBIVAL 8 /* ambivalent low-level probing detected */ | |
40 | ||
51410fc6 KZ |
41 | #include <blkid.h> |
42 | ||
2d71a929 | 43 | #include "ismounted.h" |
3c2662d5 | 44 | |
1578ddd6 | 45 | #define STRTOXX_EXIT_CODE BLKID_EXIT_OTHER /* strtoxx_or_err() */ |
8abcf290 | 46 | #include "strutils.h" |
c05a80ca | 47 | #include "closestream.h" |
597cfec5 | 48 | #include "ttyutils.h" |
2d71a929 | 49 | |
51410fc6 KZ |
50 | const char *progname = "blkid"; |
51 | ||
36a74e1b KZ |
52 | int raw_chars; |
53 | ||
51410fc6 KZ |
54 | static void print_version(FILE *out) |
55 | { | |
a0487b1c | 56 | fprintf(out, "%s from %s (libblkid %s, %s)\n", |
33b0be6d | 57 | progname, PACKAGE_STRING, LIBBLKID_VERSION, LIBBLKID_DATE); |
51410fc6 KZ |
58 | } |
59 | ||
60 | static void usage(int error) | |
61 | { | |
62 | FILE *out = error ? stderr : stdout; | |
63 | ||
64 | print_version(out); | |
65 | fprintf(out, | |
5b6215b5 | 66 | "Usage:\n" |
bf0128d6 KZ |
67 | " %1$s -L <label> | -U <uuid>\n\n" |
68 | " %1$s [-c <file>] [-ghlLv] [-o <format>] [-s <tag>] \n" | |
077b15dc | 69 | " [-t <token>] [<dev> ...]\n\n" |
bf0128d6 KZ |
70 | " %1$s -p [-s <tag>] [-O <offset>] [-S <size>] \n" |
71 | " [-o <format>] <dev> ...\n\n" | |
2327e2d6 | 72 | " %1$s -i [-s <tag>] [-o <format>] <dev> ...\n\n" |
5b6215b5 | 73 | "Options:\n" |
b82590ad KZ |
74 | " -c <file> read from <file> instead of reading from the default\n" |
75 | " cache file (-c /dev/null means no cache)\n" | |
bf0128d6 KZ |
76 | " -d don't encode non-printing characters\n" |
77 | " -h print this usage message and exit\n" | |
78 | " -g garbage collect the blkid cache\n" | |
79 | " -o <format> output format; can be one of:\n" | |
24d741d8 | 80 | " value, device, export or full; (default: full)\n" |
bf0128d6 KZ |
81 | " -k list all known filesystems/RAIDs and exit\n" |
82 | " -s <tag> show specified tag(s) (default show all tags)\n" | |
83 | " -t <token> find device with a specific token (NAME=value pair)\n" | |
84 | " -l look up only first device with token specified by -t\n" | |
85 | " -L <label> convert LABEL to device name\n" | |
86 | " -U <uuid> convert UUID to device name\n" | |
87 | " -v print version and exit\n" | |
bf0128d6 | 88 | " <dev> specify device(s) to probe (default: all devices)\n\n" |
02a8a21a | 89 | "Low-level probing options:\n" |
bf0128d6 KZ |
90 | " -p low-level superblocks probing (bypass cache)\n" |
91 | " -i gather information about I/O limits\n" | |
92 | " -S <size> overwrite device size\n" | |
93 | " -O <offset> probe at the given offset\n" | |
94 | " -u <list> filter by \"usage\" (e.g. -u filesystem,raid)\n" | |
95 | " -n <list> filter by filesystem type (e.g. -n vfat,ext3)\n" | |
2327e2d6 | 96 | "\n", progname); |
5b6215b5 | 97 | |
51410fc6 KZ |
98 | exit(error); |
99 | } | |
100 | ||
101 | /* | |
102 | * This function does "safe" printing. It will convert non-printable | |
103 | * ASCII characters using '^' and M- notation. | |
104 | */ | |
105 | static void safe_print(const char *cp, int len) | |
106 | { | |
107 | unsigned char ch; | |
108 | ||
109 | if (len < 0) | |
110 | len = strlen(cp); | |
111 | ||
112 | while (len--) { | |
113 | ch = *cp++; | |
36a74e1b | 114 | if (!raw_chars) { |
305a6122 | 115 | if (ch >= 128) { |
36a74e1b KZ |
116 | fputs("M-", stdout); |
117 | ch -= 128; | |
118 | } | |
119 | if ((ch < 32) || (ch == 0x7f)) { | |
120 | fputc('^', stdout); | |
121 | ch ^= 0x40; /* ^@, ^A, ^B; ^? for DEL */ | |
122 | } | |
51410fc6 KZ |
123 | } |
124 | fputc(ch, stdout); | |
125 | } | |
126 | } | |
127 | ||
51410fc6 KZ |
128 | static int pretty_print_word(const char *str, int max_len, |
129 | int left_len, int overflow_nl) | |
130 | { | |
131 | int len = strlen(str) + left_len; | |
132 | int ret = 0; | |
133 | ||
134 | fputs(str, stdout); | |
135 | if (overflow_nl && len > max_len) { | |
136 | fputc('\n', stdout); | |
137 | len = 0; | |
138 | } else if (len > max_len) | |
139 | ret = len - max_len; | |
140 | do | |
141 | fputc(' ', stdout); | |
142 | while (len++ < max_len); | |
143 | return ret; | |
144 | } | |
145 | ||
146 | static void pretty_print_line(const char *device, const char *fs_type, | |
147 | const char *label, const char *mtpt, | |
148 | const char *uuid) | |
149 | { | |
150 | static int device_len = 10, fs_type_len = 7; | |
151 | static int label_len = 8, mtpt_len = 14; | |
152 | static int term_width = -1; | |
153 | int len, w; | |
154 | ||
7e9a9af1 | 155 | if (term_width < 0) { |
51410fc6 | 156 | term_width = get_terminal_width(); |
7e9a9af1 KZ |
157 | if (term_width <= 0) |
158 | term_width = 80; | |
159 | } | |
51410fc6 KZ |
160 | if (term_width > 80) { |
161 | term_width -= 80; | |
162 | w = term_width / 10; | |
163 | if (w > 8) | |
164 | w = 8; | |
165 | term_width -= 2*w; | |
166 | label_len += w; | |
167 | fs_type_len += w; | |
168 | w = term_width/2; | |
169 | device_len += w; | |
170 | mtpt_len +=w; | |
171 | } | |
172 | ||
173 | len = pretty_print_word(device, device_len, 0, 1); | |
174 | len = pretty_print_word(fs_type, fs_type_len, len, 0); | |
175 | len = pretty_print_word(label, label_len, len, 0); | |
fec1339f KZ |
176 | pretty_print_word(mtpt, mtpt_len, len, 0); |
177 | ||
51410fc6 KZ |
178 | fputs(uuid, stdout); |
179 | fputc('\n', stdout); | |
180 | } | |
181 | ||
182 | static void pretty_print_dev(blkid_dev dev) | |
183 | { | |
51410fc6 KZ |
184 | blkid_tag_iterate iter; |
185 | const char *type, *value, *devname; | |
186 | const char *uuid = "", *fs_type = "", *label = ""; | |
51410fc6 KZ |
187 | int len, mount_flags; |
188 | char mtpt[80]; | |
2d71a929 | 189 | int retval; |
51410fc6 KZ |
190 | |
191 | if (dev == NULL) { | |
192 | pretty_print_line("device", "fs_type", "label", | |
193 | "mount point", "UUID"); | |
194 | for (len=get_terminal_width()-1; len > 0; len--) | |
195 | fputc('-', stdout); | |
196 | fputc('\n', stdout); | |
197 | return; | |
198 | } | |
199 | ||
200 | devname = blkid_dev_devname(dev); | |
201 | if (access(devname, F_OK)) | |
202 | return; | |
203 | ||
204 | /* Get the uuid, label, type */ | |
205 | iter = blkid_tag_iterate_begin(dev); | |
206 | while (blkid_tag_next(iter, &type, &value) == 0) { | |
207 | if (!strcmp(type, "UUID")) | |
208 | uuid = value; | |
209 | if (!strcmp(type, "TYPE")) | |
210 | fs_type = value; | |
211 | if (!strcmp(type, "LABEL")) | |
212 | label = value; | |
213 | } | |
214 | blkid_tag_iterate_end(iter); | |
215 | ||
216 | /* Get the mount point */ | |
217 | mtpt[0] = 0; | |
2d71a929 | 218 | retval = check_mount_point(devname, &mount_flags, mtpt, sizeof(mtpt)); |
51410fc6 | 219 | if (retval == 0) { |
2d71a929 | 220 | if (mount_flags & MF_MOUNTED) { |
51410fc6 KZ |
221 | if (!mtpt[0]) |
222 | strcpy(mtpt, "(mounted, mtpt unknown)"); | |
2d71a929 | 223 | } else if (mount_flags & MF_BUSY) |
51410fc6 KZ |
224 | strcpy(mtpt, "(in use)"); |
225 | else | |
226 | strcpy(mtpt, "(not mounted)"); | |
227 | } | |
228 | ||
229 | pretty_print_line(devname, fs_type, label, mtpt, uuid); | |
51410fc6 KZ |
230 | } |
231 | ||
525f3c28 | 232 | static void print_udev_format(const char *name, const char *value) |
b516dbe0 KZ |
233 | { |
234 | char enc[265], safe[256]; | |
09792910 | 235 | size_t namelen = strlen(name); |
b516dbe0 KZ |
236 | |
237 | *safe = *enc = '\0'; | |
238 | ||
d46c8ab3 | 239 | if (!strcmp(name, "TYPE") || !strcmp(name, "VERSION")) { |
b516dbe0 | 240 | blkid_encode_string(value, enc, sizeof(enc)); |
d46c8ab3 | 241 | printf("ID_FS_%s=%s\n", name, enc); |
b516dbe0 | 242 | |
d46c8ab3 | 243 | } else if (!strcmp(name, "UUID") || |
b516dbe0 KZ |
244 | !strcmp(name, "LABEL") || |
245 | !strcmp(name, "UUID_SUB")) { | |
246 | ||
247 | blkid_safe_string(value, safe, sizeof(safe)); | |
d46c8ab3 | 248 | printf("ID_FS_%s=%s\n", name, safe); |
b516dbe0 | 249 | |
d46c8ab3 | 250 | blkid_encode_string(value, enc, sizeof(enc)); |
b516dbe0 | 251 | printf("ID_FS_%s_ENC=%s\n", name, enc); |
e3d8933a | 252 | |
4f74ffdb | 253 | } else if (!strcmp(name, "PTTYPE")) { |
e3d8933a KZ |
254 | printf("ID_PART_TABLE_TYPE=%s\n", value); |
255 | ||
dcc58f62 KZ |
256 | } else if (!strcmp(name, "PART_ENTRY_NAME") || |
257 | !strcmp(name, "PART_ENTRY_TYPE")) { | |
4f74ffdb | 258 | |
4f74ffdb | 259 | blkid_encode_string(value, enc, sizeof(enc)); |
0159857e | 260 | printf("ID_%s=%s\n", name, enc); |
4f74ffdb KZ |
261 | |
262 | } else if (!strncmp(name, "PART_ENTRY_", 11)) | |
263 | printf("ID_%s=%s\n", name, value); | |
e3d8933a | 264 | |
09792910 KZ |
265 | else if (namelen >= 15 && ( |
266 | !strcmp(name + (namelen - 12), "_SECTOR_SIZE") || | |
267 | !strcmp(name + (namelen - 8), "_IO_SIZE") || | |
268 | !strcmp(name, "ALIGNMENT_OFFSET"))) | |
269 | printf("ID_IOLIMIT_%s=%s\n", name, value); | |
d46c8ab3 KZ |
270 | else |
271 | printf("ID_FS_%s=%s\n", name, value); | |
b516dbe0 KZ |
272 | } |
273 | ||
7711e215 KZ |
274 | static int has_item(char *ary[], const char *item) |
275 | { | |
276 | char **p; | |
277 | ||
278 | for (p = ary; *p != NULL; p++) | |
279 | if (!strcmp(item, *p)) | |
280 | return 1; | |
281 | return 0; | |
282 | } | |
283 | ||
cf778d68 | 284 | static void print_value(int output, int num, const char *devname, |
5b6215b5 KZ |
285 | const char *value, const char *name, size_t valsz) |
286 | { | |
287 | if (output & OUTPUT_VALUE_ONLY) { | |
288 | fputs(value, stdout); | |
289 | fputc('\n', stdout); | |
290 | ||
b516dbe0 | 291 | } else if (output & OUTPUT_UDEV_LIST) { |
525f3c28 | 292 | print_udev_format(name, value); |
5b6215b5 | 293 | |
ab978962 | 294 | } else if (output & OUTPUT_EXPORT_LIST) { |
dab33573 KZ |
295 | if (num == 1 && devname) |
296 | printf("DEVNAME=%s\n", devname); | |
ab978962 KZ |
297 | fputs(name, stdout); |
298 | fputs("=", stdout); | |
299 | safe_print(value, valsz); | |
300 | fputs("\n", stdout); | |
301 | ||
5b6215b5 | 302 | } else { |
cf778d68 KZ |
303 | if (num == 1 && devname) |
304 | printf("%s: ", devname); | |
5b6215b5 KZ |
305 | fputs(name, stdout); |
306 | fputs("=\"", stdout); | |
307 | safe_print(value, valsz); | |
308 | fputs("\" ", stdout); | |
309 | } | |
310 | } | |
311 | ||
7711e215 | 312 | static void print_tags(blkid_dev dev, char *show[], int output) |
51410fc6 KZ |
313 | { |
314 | blkid_tag_iterate iter; | |
cf778d68 | 315 | const char *type, *value, *devname; |
7711e215 | 316 | int num = 1; |
ab978962 | 317 | static int first = 1; |
51410fc6 KZ |
318 | |
319 | if (!dev) | |
320 | return; | |
321 | ||
322 | if (output & OUTPUT_PRETTY_LIST) { | |
323 | pretty_print_dev(dev); | |
324 | return; | |
325 | } | |
326 | ||
cf778d68 KZ |
327 | devname = blkid_dev_devname(dev); |
328 | ||
51410fc6 | 329 | if (output & OUTPUT_DEVICE_ONLY) { |
cf778d68 | 330 | printf("%s\n", devname); |
51410fc6 KZ |
331 | return; |
332 | } | |
333 | ||
334 | iter = blkid_tag_iterate_begin(dev); | |
335 | while (blkid_tag_next(iter, &type, &value) == 0) { | |
7711e215 KZ |
336 | if (show[0] && !has_item(show, type)) |
337 | continue; | |
ab978962 KZ |
338 | |
339 | if (num == 1 && !first && | |
340 | (output & (OUTPUT_UDEV_LIST | OUTPUT_EXPORT_LIST))) | |
341 | /* add extra line between output from more devices */ | |
342 | fputc('\n', stdout); | |
343 | ||
cf778d68 | 344 | print_value(output, num++, devname, value, type, strlen(value)); |
51410fc6 KZ |
345 | } |
346 | blkid_tag_iterate_end(iter); | |
347 | ||
ab978962 KZ |
348 | if (num > 1) { |
349 | if (!(output & (OUTPUT_VALUE_ONLY | OUTPUT_UDEV_LIST | | |
350 | OUTPUT_EXPORT_LIST))) | |
351 | printf("\n"); | |
352 | first = 0; | |
353 | } | |
51410fc6 KZ |
354 | } |
355 | ||
c54670d5 KZ |
356 | |
357 | static int append_str(char **res, size_t *sz, const char *a, const char *b) | |
358 | { | |
359 | char *str = *res; | |
360 | size_t asz = a ? strlen(a) : 0; | |
361 | size_t bsz = b ? strlen(b) : 0; | |
362 | size_t len = *sz + asz + bsz; | |
363 | ||
364 | if (!len) | |
365 | return -1; | |
366 | ||
367 | str = realloc(str, len + 1); | |
37beb702 | 368 | if (!str) |
c54670d5 | 369 | return -1; |
37beb702 | 370 | |
c54670d5 KZ |
371 | *res = str; |
372 | str += *sz; | |
373 | ||
374 | if (a) { | |
375 | memcpy(str, a, asz); | |
376 | str += asz; | |
377 | } | |
378 | if (b) { | |
379 | memcpy(str, b, bsz); | |
380 | str += bsz; | |
381 | } | |
382 | *str = '\0'; | |
383 | *sz = len; | |
384 | return 0; | |
385 | } | |
386 | ||
387 | /* | |
388 | * Compose and print ID_FS_AMBIVALENT for udev | |
389 | */ | |
390 | static int print_udev_ambivalent(blkid_probe pr) | |
391 | { | |
392 | char *val = NULL; | |
393 | size_t valsz = 0; | |
394 | int count = 0, rc = -1; | |
395 | ||
396 | while (!blkid_do_probe(pr)) { | |
397 | const char *usage = NULL, *type = NULL, *version = NULL; | |
398 | char enc[256]; | |
399 | ||
400 | blkid_probe_lookup_value(pr, "USAGE", &usage, NULL); | |
401 | blkid_probe_lookup_value(pr, "TYPE", &type, NULL); | |
402 | blkid_probe_lookup_value(pr, "VERSION", &version, NULL); | |
403 | ||
404 | if (!usage || !type) | |
405 | continue; | |
406 | ||
407 | blkid_encode_string(usage, enc, sizeof(enc)); | |
408 | if (append_str(&val, &valsz, enc, ":")) | |
409 | goto done; | |
410 | ||
411 | blkid_encode_string(type, enc, sizeof(enc)); | |
412 | if (append_str(&val, &valsz, enc, version ? ":" : " ")) | |
413 | goto done; | |
414 | ||
415 | if (version) { | |
416 | blkid_encode_string(version, enc, sizeof(enc)); | |
417 | if (append_str(&val, &valsz, enc, " ")) | |
418 | goto done; | |
419 | } | |
420 | count++; | |
421 | } | |
422 | ||
423 | if (count > 1) { | |
424 | *(val + valsz - 1) = '\0'; /* rem tailing whitespace */ | |
425 | printf("ID_FS_AMBIVALEN=%s\n", val); | |
426 | rc = 0; | |
427 | } | |
428 | done: | |
429 | free(val); | |
430 | return rc; | |
431 | } | |
432 | ||
09792910 | 433 | static int lowprobe_superblocks(blkid_probe pr) |
5b6215b5 | 434 | { |
e3d8933a | 435 | struct stat st; |
d75bcac4 | 436 | int rc, fd = blkid_probe_get_fd(pr); |
e3d8933a | 437 | |
d75bcac4 | 438 | if (fd < 0 || fstat(fd, &st)) |
09792910 | 439 | return -1; |
e3d8933a KZ |
440 | |
441 | blkid_probe_enable_partitions(pr, 1); | |
4f74ffdb | 442 | |
6a2f2f58 KZ |
443 | if (!S_ISCHR(st.st_mode) && blkid_probe_get_size(pr) <= 1024 * 1440 && |
444 | blkid_probe_is_wholedisk(pr)) { | |
e3d8933a | 445 | /* |
cba1f975 KZ |
446 | * check if the small disk is partitioned, if yes then |
447 | * don't probe for filesystems. | |
e3d8933a | 448 | */ |
cba1f975 | 449 | blkid_probe_enable_superblocks(pr, 0); |
e3d8933a | 450 | |
cba1f975 | 451 | rc = blkid_do_fullprobe(pr); |
e3d8933a | 452 | if (rc < 0) |
09792910 | 453 | return rc; /* -1 = error, 1 = nothing, 0 = succes */ |
cba1f975 KZ |
454 | |
455 | if (blkid_probe_lookup_value(pr, "PTTYPE", NULL, NULL) == 0) | |
09792910 | 456 | return 0; /* partition table detected */ |
e3d8933a | 457 | } |
5b6215b5 | 458 | |
6a2f2f58 | 459 | blkid_probe_set_partitions_flags(pr, BLKID_PARTS_ENTRY_DETAILS); |
cba1f975 KZ |
460 | blkid_probe_enable_superblocks(pr, 1); |
461 | ||
09792910 KZ |
462 | return blkid_do_safeprobe(pr); |
463 | } | |
464 | ||
465 | static int lowprobe_topology(blkid_probe pr) | |
466 | { | |
467 | /* enable topology probing only */ | |
468 | blkid_probe_enable_topology(pr, 1); | |
469 | ||
470 | blkid_probe_enable_superblocks(pr, 0); | |
471 | blkid_probe_enable_partitions(pr, 0); | |
472 | ||
473 | return blkid_do_fullprobe(pr); | |
474 | } | |
475 | ||
476 | static int lowprobe_device(blkid_probe pr, const char *devname, | |
477 | int chain, char *show[], int output, | |
478 | blkid_loff_t offset, blkid_loff_t size) | |
479 | { | |
480 | const char *data; | |
481 | const char *name; | |
482 | int nvals = 0, n, num = 1; | |
483 | size_t len; | |
484 | int fd; | |
485 | int rc = 0; | |
486 | static int first = 1; | |
487 | ||
488 | fd = open(devname, O_RDONLY); | |
489 | if (fd < 0) { | |
960cf573 | 490 | fprintf(stderr, "error: %s: %m\n", devname); |
1578ddd6 | 491 | return BLKID_EXIT_NOTFOUND; |
09792910 KZ |
492 | } |
493 | if (blkid_probe_set_device(pr, fd, offset, size)) | |
494 | goto done; | |
495 | ||
496 | if (chain & LOWPROBE_TOPOLOGY) | |
497 | rc = lowprobe_topology(pr); | |
498 | if (rc >= 0 && (chain & LOWPROBE_SUPERBLOCKS)) | |
499 | rc = lowprobe_superblocks(pr); | |
cba1f975 KZ |
500 | if (rc < 0) |
501 | goto done; | |
09792910 | 502 | |
dbcafb87 KZ |
503 | if (!rc) |
504 | nvals = blkid_probe_numof_values(pr); | |
5b6215b5 | 505 | |
53a4d69d | 506 | if (nvals && |
4b5f7895 | 507 | !(chain & LOWPROBE_TOPOLOGY) && |
53a4d69d KZ |
508 | !(output & OUTPUT_UDEV_LIST) && |
509 | !blkid_probe_has_value(pr, "TYPE") && | |
510 | !blkid_probe_has_value(pr, "PTTYPE")) | |
511 | /* | |
512 | * Ignore probing result if there is not any filesystem or | |
513 | * partition table on the device and udev output is not | |
514 | * requested. | |
515 | * | |
516 | * The udev db stores information about partitions, so | |
517 | * PART_ENTRY_* values are alway important. | |
518 | */ | |
519 | nvals = 0; | |
520 | ||
ab978962 | 521 | if (nvals && !first && output & (OUTPUT_UDEV_LIST | OUTPUT_EXPORT_LIST)) |
9eb44c28 KZ |
522 | /* add extra line between output from devices */ |
523 | fputc('\n', stdout); | |
524 | ||
dbcafb87 | 525 | if (nvals && (output & OUTPUT_DEVICE_ONLY)) { |
e88517b1 KZ |
526 | printf("%s\n", devname); |
527 | goto done; | |
528 | } | |
529 | ||
5b6215b5 KZ |
530 | for (n = 0; n < nvals; n++) { |
531 | if (blkid_probe_get_value(pr, n, &name, &data, &len)) | |
532 | continue; | |
7711e215 KZ |
533 | if (show[0] && !has_item(show, name)) |
534 | continue; | |
5b6215b5 | 535 | len = strnlen((char *) data, len); |
7711e215 | 536 | print_value(output, num++, devname, (char *) data, name, len); |
5b6215b5 KZ |
537 | } |
538 | ||
9eb44c28 KZ |
539 | if (first) |
540 | first = 0; | |
ab978962 KZ |
541 | if (nvals >= 1 && !(output & (OUTPUT_VALUE_ONLY | |
542 | OUTPUT_UDEV_LIST | OUTPUT_EXPORT_LIST))) | |
cf778d68 | 543 | printf("\n"); |
e88517b1 | 544 | done: |
c54670d5 KZ |
545 | if (rc == -2) { |
546 | if (output & OUTPUT_UDEV_LIST) | |
547 | print_udev_ambivalent(pr); | |
548 | else | |
549 | fprintf(stderr, | |
550 | "%s: ambivalent result (probably more " | |
551 | "filesystems on the device, use wipefs(8) " | |
552 | "to see more details)\n", | |
a2f01a1c | 553 | devname); |
c54670d5 | 554 | } |
5b6215b5 | 555 | close(fd); |
68c88d94 KZ |
556 | |
557 | if (rc == -2) | |
1578ddd6 | 558 | return BLKID_EXIT_AMBIVAL; /* ambivalent probing result */ |
68c88d94 | 559 | if (!nvals) |
1578ddd6 | 560 | return BLKID_EXIT_NOTFOUND; /* nothing detected */ |
68c88d94 | 561 | |
455fe9a0 | 562 | return 0; /* success */ |
5b6215b5 KZ |
563 | } |
564 | ||
0bdd2f97 KZ |
565 | /* converts comma separated list to BLKID_USAGE_* mask */ |
566 | static int list_to_usage(const char *list, int *flag) | |
567 | { | |
568 | int mask = 0; | |
962496d4 | 569 | const char *word = NULL, *p = list; |
0bdd2f97 KZ |
570 | |
571 | if (p && strncmp(p, "no", 2) == 0) { | |
572 | *flag = BLKID_FLTR_NOTIN; | |
573 | p += 2; | |
574 | } | |
962496d4 KZ |
575 | if (!p || !*p) |
576 | goto err; | |
962496d4 KZ |
577 | while(p) { |
578 | word = p; | |
962496d4 KZ |
579 | p = strchr(p, ','); |
580 | if (p) | |
581 | p++; | |
962496d4 KZ |
582 | if (!strncmp(word, "filesystem", 10)) |
583 | mask |= BLKID_USAGE_FILESYSTEM; | |
584 | else if (!strncmp(word, "raid", 4)) | |
585 | mask |= BLKID_USAGE_RAID; | |
586 | else if (!strncmp(word, "crypto", 6)) | |
587 | mask |= BLKID_USAGE_CRYPTO; | |
588 | else if (!strncmp(word, "other", 5)) | |
589 | mask |= BLKID_USAGE_OTHER; | |
590 | else | |
591 | goto err; | |
0bdd2f97 KZ |
592 | } |
593 | return mask; | |
962496d4 KZ |
594 | err: |
595 | *flag = 0; | |
596 | fprintf(stderr, "unknown kerword in -u <list> argument: '%s'\n", | |
597 | word ? word : list); | |
1578ddd6 | 598 | exit(BLKID_EXIT_OTHER); |
0bdd2f97 KZ |
599 | } |
600 | ||
4f946f53 KZ |
601 | /* converts comma separated list to types[] */ |
602 | static char **list_to_types(const char *list, int *flag) | |
603 | { | |
604 | int i; | |
605 | const char *p = list; | |
bc867ea3 | 606 | char **res = NULL; |
4f946f53 KZ |
607 | |
608 | if (p && strncmp(p, "no", 2) == 0) { | |
609 | *flag = BLKID_FLTR_NOTIN; | |
610 | p += 2; | |
611 | } | |
612 | if (!p || !*p) { | |
613 | fprintf(stderr, "error: -u <list> argument is empty\n"); | |
614 | goto err; | |
615 | } | |
616 | for (i = 1; p && (p = strchr(p, ',')); i++, p++); | |
617 | ||
618 | res = calloc(i + 1, sizeof(char *)); | |
619 | if (!res) | |
620 | goto err_mem; | |
621 | p = *flag & BLKID_FLTR_NOTIN ? list + 2 : list; | |
622 | i = 0; | |
623 | ||
624 | while(p) { | |
625 | const char *word = p; | |
626 | p = strchr(p, ','); | |
627 | res[i] = p ? strndup(word, p - word) : strdup(word); | |
628 | if (!res[i++]) | |
629 | goto err_mem; | |
630 | if (p) | |
631 | p++; | |
632 | } | |
633 | res[i] = NULL; | |
634 | return res; | |
635 | err_mem: | |
636 | fprintf(stderr, "out of memory\n"); | |
637 | err: | |
638 | *flag = 0; | |
639 | free(res); | |
1578ddd6 | 640 | exit(BLKID_EXIT_OTHER); |
4f946f53 KZ |
641 | } |
642 | ||
643 | static void free_types_list(char *list[]) | |
644 | { | |
645 | char **n; | |
646 | ||
647 | if (!list) | |
648 | return; | |
649 | for (n = list; *n; n++) | |
650 | free(*n); | |
651 | free(list); | |
652 | } | |
653 | ||
51410fc6 KZ |
654 | int main(int argc, char **argv) |
655 | { | |
656 | blkid_cache cache = NULL; | |
ea51c09c | 657 | char **devices = NULL; |
51410fc6 KZ |
658 | char *show[128] = { NULL, }; |
659 | char *search_type = NULL, *search_value = NULL; | |
660 | char *read = NULL; | |
0bdd2f97 | 661 | int fltr_usage = 0; |
4f946f53 | 662 | char **fltr_type = NULL; |
0bdd2f97 | 663 | int fltr_flag = BLKID_FLTR_ONLYIN; |
51410fc6 KZ |
664 | unsigned int numdev = 0, numtag = 0; |
665 | int version = 0; | |
1578ddd6 | 666 | int err = BLKID_EXIT_OTHER; |
51410fc6 KZ |
667 | unsigned int i; |
668 | int output_format = 0; | |
4786921c | 669 | int lookup = 0, gc = 0, lowprobe = 0, eval = 0; |
51410fc6 | 670 | int c; |
8ab912cf | 671 | uintmax_t offset = 0, size = 0; |
51410fc6 | 672 | |
7711e215 | 673 | show[0] = NULL; |
c05a80ca | 674 | atexit(close_stdout); |
7711e215 | 675 | |
70db6c7e | 676 | while ((c = getopt (argc, argv, "c:df:ghilL:n:ko:O:ps:S:t:u:U:w:v")) != EOF) |
51410fc6 KZ |
677 | switch (c) { |
678 | case 'c': | |
679 | if (optarg && !*optarg) | |
680 | read = NULL; | |
681 | else | |
682 | read = optarg; | |
51410fc6 | 683 | break; |
36a74e1b KZ |
684 | case 'd': |
685 | raw_chars = 1; | |
686 | break; | |
4786921c | 687 | case 'L': |
688 | eval++; | |
689 | search_value = strdup(optarg); | |
690 | search_type = strdup("LABEL"); | |
691 | break; | |
4f946f53 KZ |
692 | case 'n': |
693 | if (fltr_usage) { | |
694 | fprintf(stderr, "error: -u and -n options are mutually exclusive\n"); | |
1578ddd6 | 695 | exit(BLKID_EXIT_OTHER); |
4f946f53 KZ |
696 | } |
697 | fltr_type = list_to_types(optarg, &fltr_flag); | |
698 | break; | |
0bdd2f97 | 699 | case 'u': |
4f946f53 KZ |
700 | if (fltr_type) { |
701 | fprintf(stderr, "error: -u and -n options are mutually exclusive\n"); | |
1578ddd6 | 702 | exit(BLKID_EXIT_OTHER); |
4f946f53 | 703 | } |
0bdd2f97 KZ |
704 | fltr_usage = list_to_usage(optarg, &fltr_flag); |
705 | break; | |
4786921c | 706 | case 'U': |
707 | eval++; | |
708 | search_value = strdup(optarg); | |
709 | search_type = strdup("UUID"); | |
710 | break; | |
09792910 KZ |
711 | case 'i': |
712 | lowprobe |= LOWPROBE_TOPOLOGY; | |
713 | break; | |
51410fc6 KZ |
714 | case 'l': |
715 | lookup++; | |
716 | break; | |
51410fc6 KZ |
717 | case 'g': |
718 | gc = 1; | |
719 | break; | |
70db6c7e KZ |
720 | case 'k': |
721 | { | |
722 | size_t idx = 0; | |
723 | const char *name = NULL; | |
724 | ||
725 | while (blkid_superblocks_get_name(idx++, &name, NULL) == 0) | |
726 | printf("%s\n", name); | |
a922091d | 727 | exit(EXIT_SUCCESS); |
70db6c7e | 728 | } |
51410fc6 KZ |
729 | case 'o': |
730 | if (!strcmp(optarg, "value")) | |
731 | output_format = OUTPUT_VALUE_ONLY; | |
732 | else if (!strcmp(optarg, "device")) | |
733 | output_format = OUTPUT_DEVICE_ONLY; | |
734 | else if (!strcmp(optarg, "list")) | |
24d741d8 | 735 | output_format = OUTPUT_PRETTY_LIST; /* deprecated */ |
b516dbe0 KZ |
736 | else if (!strcmp(optarg, "udev")) |
737 | output_format = OUTPUT_UDEV_LIST; | |
ab978962 KZ |
738 | else if (!strcmp(optarg, "export")) |
739 | output_format = OUTPUT_EXPORT_LIST; | |
51410fc6 KZ |
740 | else if (!strcmp(optarg, "full")) |
741 | output_format = 0; | |
742 | else { | |
743 | fprintf(stderr, "Invalid output format %s. " | |
744 | "Choose from value,\n\t" | |
e88517b1 | 745 | "device, list, udev or full\n", optarg); |
1578ddd6 | 746 | exit(BLKID_EXIT_OTHER); |
51410fc6 KZ |
747 | } |
748 | break; | |
5b6215b5 | 749 | case 'O': |
db41a429 | 750 | offset = strtosize_or_err(optarg, "invalid offset argument"); |
5b6215b5 KZ |
751 | break; |
752 | case 'p': | |
09792910 | 753 | lowprobe |= LOWPROBE_SUPERBLOCKS; |
5b6215b5 | 754 | break; |
51410fc6 | 755 | case 's': |
7711e215 | 756 | if (numtag + 1 >= sizeof(show) / sizeof(*show)) { |
51410fc6 KZ |
757 | fprintf(stderr, "Too many tags specified\n"); |
758 | usage(err); | |
759 | } | |
760 | show[numtag++] = optarg; | |
7711e215 | 761 | show[numtag] = NULL; |
51410fc6 | 762 | break; |
5b6215b5 | 763 | case 'S': |
db41a429 | 764 | size = strtosize_or_err(optarg, "invalid size argument"); |
5b6215b5 | 765 | break; |
51410fc6 KZ |
766 | case 't': |
767 | if (search_type) { | |
768 | fprintf(stderr, "Can only search for " | |
769 | "one NAME=value pair\n"); | |
770 | usage(err); | |
771 | } | |
772 | if (blkid_parse_tag_string(optarg, | |
773 | &search_type, | |
774 | &search_value)) { | |
775 | fprintf(stderr, "-t needs NAME=value pair\n"); | |
776 | usage(err); | |
777 | } | |
778 | break; | |
779 | case 'v': | |
780 | version = 1; | |
781 | break; | |
782 | case 'w': | |
077b15dc | 783 | /* ignore - backward compatibility */ |
51410fc6 KZ |
784 | break; |
785 | case 'h': | |
786 | err = 0; | |
7113ddec | 787 | /* fallthrough */ |
51410fc6 KZ |
788 | default: |
789 | usage(err); | |
790 | } | |
791 | ||
ea51c09c ES |
792 | |
793 | /* The rest of the args are device names */ | |
794 | if (optind < argc) { | |
795 | devices = calloc(argc - optind, sizeof(char *)); | |
796 | if (!devices) { | |
797 | fprintf(stderr, "Failed to allocate device name array\n"); | |
798 | goto exit; | |
799 | } | |
ea51c09c | 800 | |
54a00b5c KZ |
801 | while (optind < argc) |
802 | devices[numdev++] = argv[optind++]; | |
803 | } | |
51410fc6 KZ |
804 | |
805 | if (version) { | |
806 | print_version(stdout); | |
807 | goto exit; | |
808 | } | |
809 | ||
4786921c | 810 | /* convert LABEL/UUID lookup to evaluate request */ |
811 | if (lookup && output_format == OUTPUT_DEVICE_ONLY && search_type && | |
812 | (!strcmp(search_type, "LABEL") || !strcmp(search_type, "UUID"))) { | |
813 | eval++; | |
814 | lookup = 0; | |
815 | } | |
816 | ||
817 | if (!lowprobe && !eval && blkid_get_cache(&cache, read) < 0) | |
51410fc6 KZ |
818 | goto exit; |
819 | ||
51410fc6 KZ |
820 | if (gc) { |
821 | blkid_gc_cache(cache); | |
324759d6 | 822 | err = 0; |
51410fc6 KZ |
823 | goto exit; |
824 | } | |
1578ddd6 | 825 | err = BLKID_EXIT_NOTFOUND; |
324759d6 | 826 | |
ab978962 | 827 | if (eval == 0 && (output_format & OUTPUT_PRETTY_LIST)) { |
2d71a929 KZ |
828 | if (lowprobe) { |
829 | fprintf(stderr, "The low-level probing mode does not " | |
830 | "support 'list' output format\n"); | |
1578ddd6 | 831 | exit(BLKID_EXIT_OTHER); |
2d71a929 | 832 | } |
51410fc6 | 833 | pretty_print_dev(NULL); |
2d71a929 | 834 | } |
51410fc6 | 835 | |
5b6215b5 | 836 | if (lowprobe) { |
4786921c | 837 | /* |
838 | * Low-level API | |
839 | */ | |
5b6215b5 KZ |
840 | blkid_probe pr; |
841 | ||
842 | if (!numdev) { | |
2d71a929 KZ |
843 | fprintf(stderr, "The low-level probing mode " |
844 | "requires a device\n"); | |
1578ddd6 | 845 | exit(BLKID_EXIT_OTHER); |
5b6215b5 | 846 | } |
ab978962 KZ |
847 | |
848 | /* automatically enable 'export' format for I/O Limits */ | |
849 | if (!output_format && (lowprobe & LOWPROBE_TOPOLOGY)) | |
850 | output_format = OUTPUT_EXPORT_LIST; | |
851 | ||
5b6215b5 KZ |
852 | pr = blkid_new_probe(); |
853 | if (!pr) | |
854 | goto exit; | |
1b780848 | 855 | |
09792910 KZ |
856 | if (lowprobe & LOWPROBE_SUPERBLOCKS) { |
857 | blkid_probe_set_superblocks_flags(pr, | |
1b780848 KZ |
858 | BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID | |
859 | BLKID_SUBLKS_TYPE | BLKID_SUBLKS_SECTYPE | | |
860 | BLKID_SUBLKS_USAGE | BLKID_SUBLKS_VERSION); | |
861 | ||
09792910 KZ |
862 | if (fltr_usage && blkid_probe_filter_superblocks_usage( |
863 | pr, fltr_flag, fltr_usage)) | |
864 | goto exit; | |
865 | ||
866 | else if (fltr_type && blkid_probe_filter_superblocks_type( | |
867 | pr, fltr_flag, fltr_type)) | |
868 | goto exit; | |
869 | } | |
5b6215b5 KZ |
870 | |
871 | for (i = 0; i < numdev; i++) | |
09792910 | 872 | err = lowprobe_device(pr, devices[i], lowprobe, show, |
8ab912cf KZ |
873 | output_format, |
874 | (blkid_loff_t) offset, | |
875 | (blkid_loff_t) size); | |
5b6215b5 | 876 | blkid_free_probe(pr); |
4786921c | 877 | } else if (eval) { |
878 | /* | |
879 | * Evaluate API | |
880 | */ | |
cee95a95 | 881 | char *res = blkid_evaluate_tag(search_type, search_value, NULL); |
324759d6 SJR |
882 | if (res) { |
883 | err = 0; | |
4786921c | 884 | printf("%s\n", res); |
324759d6 | 885 | } |
5b6215b5 | 886 | } else if (lookup) { |
4786921c | 887 | /* |
888 | * Classic (cache based) API | |
889 | */ | |
51410fc6 KZ |
890 | blkid_dev dev; |
891 | ||
892 | if (!search_type) { | |
893 | fprintf(stderr, "The lookup option requires a " | |
894 | "search type specified using -t\n"); | |
1578ddd6 | 895 | exit(BLKID_EXIT_OTHER); |
51410fc6 KZ |
896 | } |
897 | /* Load any additional devices not in the cache */ | |
898 | for (i = 0; i < numdev; i++) | |
899 | blkid_get_dev(cache, devices[i], BLKID_DEV_NORMAL); | |
900 | ||
901 | if ((dev = blkid_find_dev_with_tag(cache, search_type, | |
902 | search_value))) { | |
7711e215 | 903 | print_tags(dev, show, output_format); |
51410fc6 KZ |
904 | err = 0; |
905 | } | |
906 | /* If we didn't specify a single device, show all available devices */ | |
907 | } else if (!numdev) { | |
908 | blkid_dev_iterate iter; | |
909 | blkid_dev dev; | |
910 | ||
911 | blkid_probe_all(cache); | |
912 | ||
913 | iter = blkid_dev_iterate_begin(cache); | |
914 | blkid_dev_set_search(iter, search_type, search_value); | |
915 | while (blkid_dev_next(iter, &dev) == 0) { | |
916 | dev = blkid_verify(cache, dev); | |
917 | if (!dev) | |
918 | continue; | |
7711e215 | 919 | print_tags(dev, show, output_format); |
51410fc6 KZ |
920 | err = 0; |
921 | } | |
922 | blkid_dev_iterate_end(iter); | |
923 | /* Add all specified devices to cache (optionally display tags) */ | |
924 | } else for (i = 0; i < numdev; i++) { | |
925 | blkid_dev dev = blkid_get_dev(cache, devices[i], | |
926 | BLKID_DEV_NORMAL); | |
927 | ||
928 | if (dev) { | |
929 | if (search_type && | |
930 | !blkid_dev_has_tag(dev, search_type, | |
931 | search_value)) | |
932 | continue; | |
7711e215 | 933 | print_tags(dev, show, output_format); |
51410fc6 KZ |
934 | err = 0; |
935 | } | |
936 | } | |
937 | ||
938 | exit: | |
4786921c | 939 | free(search_type); |
940 | free(search_value); | |
4f946f53 | 941 | free_types_list(fltr_type); |
4786921c | 942 | if (!lowprobe && !eval) |
5b6215b5 | 943 | blkid_put_cache(cache); |
ea51c09c | 944 | free(devices); |
51410fc6 KZ |
945 | return err; |
946 | } |