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