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