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