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