]>
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, | |
61 | raw_chars:1; | |
62 | }; | |
36a74e1b | 63 | |
51410fc6 KZ |
64 | static void print_version(FILE *out) |
65 | { | |
f5a2b07e | 66 | fprintf(out, _("%s from %s (libblkid %s, %s)\n"), |
217615e8 BS |
67 | program_invocation_short_name, PACKAGE_STRING, |
68 | LIBBLKID_VERSION, LIBBLKID_DATE); | |
51410fc6 KZ |
69 | } |
70 | ||
71 | static void usage(int error) | |
72 | { | |
73 | FILE *out = error ? stderr : stdout; | |
74 | ||
f5a2b07e | 75 | fputs(USAGE_HEADER, out); |
15a74f75 SK |
76 | fprintf(out, _( " %s --label <label> | --uuid <uuid>\n\n"), program_invocation_short_name); |
77 | fprintf(out, _( " %s [--cache-file <file>] [-ghlLv] [--output <format>] [--match-tag <tag>] \n" | |
78 | " [--match-token <token>] [<dev> ...]\n\n"), program_invocation_short_name); | |
79 | fprintf(out, _( " %s -p [--match-tag <tag>] [--offset <offset>] [--size <size>] \n" | |
80 | " [--output <format>] <dev> ...\n\n"), program_invocation_short_name); | |
81 | fprintf(out, _( " %s -i [--match-tag <tag>] [--output <format>] <dev> ...\n"), program_invocation_short_name); | |
f5a2b07e | 82 | fputs(USAGE_OPTIONS, out); |
15a74f75 SK |
83 | fputs(_( " -c, --cache-file <file> read from <file> instead of reading from the default\n" |
84 | " cache file (-c /dev/null means no cache)\n"), out); | |
85 | fputs(_( " -d, --no-encoding don't encode non-printing characters\n"), out); | |
86 | fputs(_( " -g, --garbage-collect garbage collect the blkid cache\n"), out); | |
87 | fputs(_( " -o, --output <format> output format; can be one of:\n" | |
88 | " value, device, export or full; (default: full)\n"), out); | |
89 | fputs(_( " -k, --list-filesystems list all known filesystems/RAIDs and exit\n"), out); | |
90 | fputs(_( " -s, --match-tag <tag> show specified tag(s) (default show all tags)\n"), out); | |
91 | fputs(_( " -t, --match-token <token> find device with a specific token (NAME=value pair)\n"), out); | |
92 | fputs(_( " -l, --list-one look up only first device with token specified by -t\n"), out); | |
93 | fputs(_( " -L, --label <label> convert LABEL to device name\n"), out); | |
94 | fputs(_( " -U, --uuid <uuid> convert UUID to device name\n"), out); | |
95 | fputs(_( " <dev> specify device(s) to probe (default: all devices)\n"), out); | |
f5a2b07e SK |
96 | fputs( "\n", out); |
97 | fputs(_( "Low-level probing options:\n"), out); | |
15a74f75 SK |
98 | fputs(_( " -p, --probe low-level superblocks probing (bypass cache)\n"), out); |
99 | fputs(_( " -i, --info gather information about I/O limits\n"), out); | |
100 | fputs(_( " -S, --size <size> overwrite device size\n"), out); | |
101 | fputs(_( " -O, --offset <offset> probe at the given offset\n"), out); | |
102 | fputs(_( " -u, --usages <list> filter by \"usage\" (e.g. -u filesystem,raid)\n"), out); | |
103 | fputs(_( " -n, --match-types <list> filter by filesystem type (e.g. -n vfat,ext3)\n"), out); | |
104 | ||
105 | fputs(USAGE_SEPARATOR, out); | |
106 | fputs(USAGE_HELP, out); | |
107 | fputs(USAGE_VERSION, out); | |
f5a2b07e | 108 | fprintf(out, USAGE_MAN_TAIL("blkid(8)")); |
51410fc6 KZ |
109 | exit(error); |
110 | } | |
111 | ||
112 | /* | |
113 | * This function does "safe" printing. It will convert non-printable | |
114 | * ASCII characters using '^' and M- notation. | |
1c9885cd KZ |
115 | * |
116 | * If 'esc' is defined then escape all chars from esc by \. | |
51410fc6 | 117 | */ |
59b94cc0 SK |
118 | static void safe_print(const struct blkid_control *ctl, const char *cp, int len, |
119 | const char *esc) | |
51410fc6 KZ |
120 | { |
121 | unsigned char ch; | |
122 | ||
123 | if (len < 0) | |
124 | len = strlen(cp); | |
125 | ||
126 | while (len--) { | |
127 | ch = *cp++; | |
59b94cc0 | 128 | if (!ctl->raw_chars) { |
305a6122 | 129 | if (ch >= 128) { |
36a74e1b KZ |
130 | fputs("M-", stdout); |
131 | ch -= 128; | |
132 | } | |
133 | if ((ch < 32) || (ch == 0x7f)) { | |
134 | fputc('^', stdout); | |
135 | ch ^= 0x40; /* ^@, ^A, ^B; ^? for DEL */ | |
1c9885cd KZ |
136 | |
137 | } else if (esc && strchr(esc, ch)) | |
138 | fputc('\\', stdout); | |
51410fc6 KZ |
139 | } |
140 | fputc(ch, stdout); | |
141 | } | |
142 | } | |
143 | ||
51410fc6 KZ |
144 | static int pretty_print_word(const char *str, int max_len, |
145 | int left_len, int overflow_nl) | |
146 | { | |
147 | int len = strlen(str) + left_len; | |
148 | int ret = 0; | |
149 | ||
150 | fputs(str, stdout); | |
151 | if (overflow_nl && len > max_len) { | |
152 | fputc('\n', stdout); | |
153 | len = 0; | |
154 | } else if (len > max_len) | |
155 | ret = len - max_len; | |
126d8cf3 | 156 | do { |
51410fc6 | 157 | fputc(' ', stdout); |
126d8cf3 | 158 | } while (len++ < max_len); |
51410fc6 KZ |
159 | return ret; |
160 | } | |
161 | ||
162 | static void pretty_print_line(const char *device, const char *fs_type, | |
163 | const char *label, const char *mtpt, | |
164 | const char *uuid) | |
165 | { | |
166 | static int device_len = 10, fs_type_len = 7; | |
167 | static int label_len = 8, mtpt_len = 14; | |
168 | static int term_width = -1; | |
169 | int len, w; | |
170 | ||
7e9a9af1 | 171 | if (term_width < 0) { |
43b4f7ea | 172 | term_width = get_terminal_width(80); |
7e9a9af1 | 173 | } |
51410fc6 KZ |
174 | if (term_width > 80) { |
175 | term_width -= 80; | |
176 | w = term_width / 10; | |
177 | if (w > 8) | |
178 | w = 8; | |
179 | term_width -= 2*w; | |
180 | label_len += w; | |
181 | fs_type_len += w; | |
182 | w = term_width/2; | |
183 | device_len += w; | |
184 | mtpt_len +=w; | |
185 | } | |
186 | ||
187 | len = pretty_print_word(device, device_len, 0, 1); | |
188 | len = pretty_print_word(fs_type, fs_type_len, len, 0); | |
189 | len = pretty_print_word(label, label_len, len, 0); | |
fec1339f KZ |
190 | pretty_print_word(mtpt, mtpt_len, len, 0); |
191 | ||
51410fc6 KZ |
192 | fputs(uuid, stdout); |
193 | fputc('\n', stdout); | |
194 | } | |
195 | ||
196 | static void pretty_print_dev(blkid_dev dev) | |
197 | { | |
51410fc6 KZ |
198 | blkid_tag_iterate iter; |
199 | const char *type, *value, *devname; | |
200 | const char *uuid = "", *fs_type = "", *label = ""; | |
51410fc6 KZ |
201 | int len, mount_flags; |
202 | char mtpt[80]; | |
2d71a929 | 203 | int retval; |
51410fc6 KZ |
204 | |
205 | if (dev == NULL) { | |
206 | pretty_print_line("device", "fs_type", "label", | |
207 | "mount point", "UUID"); | |
43b4f7ea | 208 | for (len=get_terminal_width(0)-1; len > 0; len--) |
51410fc6 KZ |
209 | fputc('-', stdout); |
210 | fputc('\n', stdout); | |
211 | return; | |
212 | } | |
213 | ||
214 | devname = blkid_dev_devname(dev); | |
215 | if (access(devname, F_OK)) | |
216 | return; | |
217 | ||
218 | /* Get the uuid, label, type */ | |
219 | iter = blkid_tag_iterate_begin(dev); | |
220 | while (blkid_tag_next(iter, &type, &value) == 0) { | |
221 | if (!strcmp(type, "UUID")) | |
222 | uuid = value; | |
223 | if (!strcmp(type, "TYPE")) | |
224 | fs_type = value; | |
225 | if (!strcmp(type, "LABEL")) | |
226 | label = value; | |
227 | } | |
228 | blkid_tag_iterate_end(iter); | |
229 | ||
230 | /* Get the mount point */ | |
231 | mtpt[0] = 0; | |
2d71a929 | 232 | retval = check_mount_point(devname, &mount_flags, mtpt, sizeof(mtpt)); |
51410fc6 | 233 | if (retval == 0) { |
2d71a929 | 234 | if (mount_flags & MF_MOUNTED) { |
51410fc6 | 235 | if (!mtpt[0]) |
f5a2b07e | 236 | strcpy(mtpt, _("(mounted, mtpt unknown)")); |
2d71a929 | 237 | } else if (mount_flags & MF_BUSY) |
f5a2b07e | 238 | strcpy(mtpt, _("(in use)")); |
51410fc6 | 239 | else |
f5a2b07e | 240 | strcpy(mtpt, _("(not mounted)")); |
51410fc6 KZ |
241 | } |
242 | ||
243 | pretty_print_line(devname, fs_type, label, mtpt, uuid); | |
51410fc6 KZ |
244 | } |
245 | ||
525f3c28 | 246 | static void print_udev_format(const char *name, const char *value) |
b516dbe0 KZ |
247 | { |
248 | char enc[265], safe[256]; | |
09792910 | 249 | size_t namelen = strlen(name); |
b516dbe0 KZ |
250 | |
251 | *safe = *enc = '\0'; | |
252 | ||
d46c8ab3 | 253 | if (!strcmp(name, "TYPE") || !strcmp(name, "VERSION")) { |
b516dbe0 | 254 | blkid_encode_string(value, enc, sizeof(enc)); |
d46c8ab3 | 255 | printf("ID_FS_%s=%s\n", name, enc); |
b516dbe0 | 256 | |
d46c8ab3 | 257 | } else if (!strcmp(name, "UUID") || |
b516dbe0 KZ |
258 | !strcmp(name, "LABEL") || |
259 | !strcmp(name, "UUID_SUB")) { | |
260 | ||
261 | blkid_safe_string(value, safe, sizeof(safe)); | |
d46c8ab3 | 262 | printf("ID_FS_%s=%s\n", name, safe); |
b516dbe0 | 263 | |
d46c8ab3 | 264 | blkid_encode_string(value, enc, sizeof(enc)); |
b516dbe0 | 265 | printf("ID_FS_%s_ENC=%s\n", name, enc); |
e3d8933a | 266 | |
834eca4e KZ |
267 | } else if (!strcmp(name, "PTUUID")) { |
268 | printf("ID_PART_TABLE_UUID=%s\n", value); | |
269 | ||
4f74ffdb | 270 | } else if (!strcmp(name, "PTTYPE")) { |
e3d8933a KZ |
271 | printf("ID_PART_TABLE_TYPE=%s\n", value); |
272 | ||
dcc58f62 KZ |
273 | } else if (!strcmp(name, "PART_ENTRY_NAME") || |
274 | !strcmp(name, "PART_ENTRY_TYPE")) { | |
4f74ffdb | 275 | |
4f74ffdb | 276 | blkid_encode_string(value, enc, sizeof(enc)); |
0159857e | 277 | printf("ID_%s=%s\n", name, enc); |
4f74ffdb KZ |
278 | |
279 | } else if (!strncmp(name, "PART_ENTRY_", 11)) | |
280 | printf("ID_%s=%s\n", name, value); | |
e3d8933a | 281 | |
09792910 KZ |
282 | else if (namelen >= 15 && ( |
283 | !strcmp(name + (namelen - 12), "_SECTOR_SIZE") || | |
284 | !strcmp(name + (namelen - 8), "_IO_SIZE") || | |
285 | !strcmp(name, "ALIGNMENT_OFFSET"))) | |
286 | printf("ID_IOLIMIT_%s=%s\n", name, value); | |
d46c8ab3 KZ |
287 | else |
288 | printf("ID_FS_%s=%s\n", name, value); | |
b516dbe0 KZ |
289 | } |
290 | ||
071147ab | 291 | static int has_item(const struct blkid_control *ctl, const char *item) |
7711e215 | 292 | { |
071147ab | 293 | char * const *p; |
7711e215 | 294 | |
071147ab | 295 | for (p = ctl->show; *p != NULL; p++) |
7711e215 KZ |
296 | if (!strcmp(item, *p)) |
297 | return 1; | |
298 | return 0; | |
299 | } | |
300 | ||
59b94cc0 SK |
301 | static void print_value(const struct blkid_control *ctl, int num, |
302 | const char *devname, const char *value, | |
303 | const char *name, size_t valsz) | |
5b6215b5 | 304 | { |
59b94cc0 | 305 | if (ctl->output & OUTPUT_VALUE_ONLY) { |
5b6215b5 KZ |
306 | fputs(value, stdout); |
307 | fputc('\n', stdout); | |
308 | ||
59b94cc0 | 309 | } else if (ctl->output & OUTPUT_UDEV_LIST) { |
525f3c28 | 310 | print_udev_format(name, value); |
5b6215b5 | 311 | |
59b94cc0 | 312 | } else if (ctl->output & OUTPUT_EXPORT_LIST) { |
dab33573 KZ |
313 | if (num == 1 && devname) |
314 | printf("DEVNAME=%s\n", devname); | |
ab978962 KZ |
315 | fputs(name, stdout); |
316 | fputs("=", stdout); | |
59b94cc0 | 317 | safe_print(ctl, value, valsz, " \\\"'$`<>"); |
ab978962 KZ |
318 | fputs("\n", stdout); |
319 | ||
5b6215b5 | 320 | } else { |
cf778d68 | 321 | if (num == 1 && devname) |
16714abe KZ |
322 | printf("%s:", devname); |
323 | fputs(" ", stdout); | |
5b6215b5 KZ |
324 | fputs(name, stdout); |
325 | fputs("=\"", stdout); | |
59b94cc0 | 326 | safe_print(ctl, value, valsz, "\"\\"); |
16714abe | 327 | fputs("\"", stdout); |
5b6215b5 KZ |
328 | } |
329 | } | |
330 | ||
59b94cc0 | 331 | static void print_tags(const struct blkid_control *ctl, blkid_dev dev) |
51410fc6 KZ |
332 | { |
333 | blkid_tag_iterate iter; | |
cf778d68 | 334 | const char *type, *value, *devname; |
7711e215 | 335 | int num = 1; |
ab978962 | 336 | static int first = 1; |
51410fc6 KZ |
337 | |
338 | if (!dev) | |
339 | return; | |
340 | ||
59b94cc0 | 341 | if (ctl->output & OUTPUT_PRETTY_LIST) { |
51410fc6 KZ |
342 | pretty_print_dev(dev); |
343 | return; | |
344 | } | |
345 | ||
cf778d68 KZ |
346 | devname = blkid_dev_devname(dev); |
347 | ||
59b94cc0 | 348 | if (ctl->output & OUTPUT_DEVICE_ONLY) { |
cf778d68 | 349 | printf("%s\n", devname); |
51410fc6 KZ |
350 | return; |
351 | } | |
352 | ||
353 | iter = blkid_tag_iterate_begin(dev); | |
354 | while (blkid_tag_next(iter, &type, &value) == 0) { | |
071147ab | 355 | if (ctl->show[0] && !has_item(ctl, type)) |
7711e215 | 356 | continue; |
ab978962 KZ |
357 | |
358 | if (num == 1 && !first && | |
59b94cc0 | 359 | (ctl->output & (OUTPUT_UDEV_LIST | OUTPUT_EXPORT_LIST))) |
ab978962 KZ |
360 | /* add extra line between output from more devices */ |
361 | fputc('\n', stdout); | |
362 | ||
59b94cc0 | 363 | print_value(ctl, num++, devname, value, type, strlen(value)); |
51410fc6 KZ |
364 | } |
365 | blkid_tag_iterate_end(iter); | |
366 | ||
ab978962 | 367 | if (num > 1) { |
59b94cc0 | 368 | if (!(ctl->output & (OUTPUT_VALUE_ONLY | OUTPUT_UDEV_LIST | |
ab978962 KZ |
369 | OUTPUT_EXPORT_LIST))) |
370 | printf("\n"); | |
371 | first = 0; | |
372 | } | |
51410fc6 KZ |
373 | } |
374 | ||
c54670d5 KZ |
375 | |
376 | static int append_str(char **res, size_t *sz, const char *a, const char *b) | |
377 | { | |
293eef71 | 378 | char *str = *res; |
c54670d5 KZ |
379 | size_t asz = a ? strlen(a) : 0; |
380 | size_t bsz = b ? strlen(b) : 0; | |
381 | size_t len = *sz + asz + bsz; | |
382 | ||
383 | if (!len) | |
384 | return -1; | |
385 | ||
293eef71 | 386 | *res = str = xrealloc(str, len + 1); |
c54670d5 KZ |
387 | str += *sz; |
388 | ||
389 | if (a) { | |
390 | memcpy(str, a, asz); | |
391 | str += asz; | |
392 | } | |
393 | if (b) { | |
394 | memcpy(str, b, bsz); | |
395 | str += bsz; | |
396 | } | |
397 | *str = '\0'; | |
398 | *sz = len; | |
399 | return 0; | |
400 | } | |
401 | ||
402 | /* | |
403 | * Compose and print ID_FS_AMBIVALENT for udev | |
404 | */ | |
405 | static int print_udev_ambivalent(blkid_probe pr) | |
406 | { | |
407 | char *val = NULL; | |
408 | size_t valsz = 0; | |
409 | int count = 0, rc = -1; | |
410 | ||
411 | while (!blkid_do_probe(pr)) { | |
f5ee44b1 | 412 | const char *usage_txt = NULL, *type = NULL, *version = NULL; |
c54670d5 KZ |
413 | char enc[256]; |
414 | ||
f5ee44b1 | 415 | blkid_probe_lookup_value(pr, "USAGE", &usage_txt, NULL); |
c54670d5 KZ |
416 | blkid_probe_lookup_value(pr, "TYPE", &type, NULL); |
417 | blkid_probe_lookup_value(pr, "VERSION", &version, NULL); | |
418 | ||
f5ee44b1 | 419 | if (!usage_txt || !type) |
c54670d5 KZ |
420 | continue; |
421 | ||
f5ee44b1 | 422 | blkid_encode_string(usage_txt, enc, sizeof(enc)); |
c54670d5 KZ |
423 | if (append_str(&val, &valsz, enc, ":")) |
424 | goto done; | |
425 | ||
426 | blkid_encode_string(type, enc, sizeof(enc)); | |
427 | if (append_str(&val, &valsz, enc, version ? ":" : " ")) | |
428 | goto done; | |
429 | ||
430 | if (version) { | |
431 | blkid_encode_string(version, enc, sizeof(enc)); | |
432 | if (append_str(&val, &valsz, enc, " ")) | |
433 | goto done; | |
434 | } | |
435 | count++; | |
436 | } | |
437 | ||
438 | if (count > 1) { | |
439 | *(val + valsz - 1) = '\0'; /* rem tailing whitespace */ | |
08af448f | 440 | printf("ID_FS_AMBIVALENT=%s\n", val); |
c54670d5 KZ |
441 | rc = 0; |
442 | } | |
443 | done: | |
444 | free(val); | |
445 | return rc; | |
446 | } | |
447 | ||
09792910 | 448 | static int lowprobe_superblocks(blkid_probe pr) |
5b6215b5 | 449 | { |
e3d8933a | 450 | struct stat st; |
d75bcac4 | 451 | int rc, fd = blkid_probe_get_fd(pr); |
e3d8933a | 452 | |
d75bcac4 | 453 | if (fd < 0 || fstat(fd, &st)) |
09792910 | 454 | return -1; |
e3d8933a KZ |
455 | |
456 | blkid_probe_enable_partitions(pr, 1); | |
4f74ffdb | 457 | |
6a2f2f58 KZ |
458 | if (!S_ISCHR(st.st_mode) && blkid_probe_get_size(pr) <= 1024 * 1440 && |
459 | blkid_probe_is_wholedisk(pr)) { | |
e3d8933a | 460 | /* |
cba1f975 KZ |
461 | * check if the small disk is partitioned, if yes then |
462 | * don't probe for filesystems. | |
e3d8933a | 463 | */ |
cba1f975 | 464 | blkid_probe_enable_superblocks(pr, 0); |
e3d8933a | 465 | |
cba1f975 | 466 | rc = blkid_do_fullprobe(pr); |
e3d8933a | 467 | if (rc < 0) |
9e930041 | 468 | return rc; /* -1 = error, 1 = nothing, 0 = success */ |
cba1f975 KZ |
469 | |
470 | if (blkid_probe_lookup_value(pr, "PTTYPE", NULL, NULL) == 0) | |
09792910 | 471 | return 0; /* partition table detected */ |
e3d8933a | 472 | } |
5b6215b5 | 473 | |
6a2f2f58 | 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) |
09792910 | 513 | rc = lowprobe_superblocks(pr); |
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; |
5b6215b5 | 534 | len = strnlen((char *) data, len); |
59b94cc0 | 535 | print_value(ctl, num++, devname, (char *) 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' }, | |
665 | { "garbage-collect", no_argument, NULL, 'g' }, | |
666 | { "output", required_argument, NULL, 'o' }, | |
667 | { "list-filesystems", no_argument, NULL, 'k' }, | |
668 | { "match-tag", required_argument, NULL, 's' }, | |
669 | { "match-token", required_argument, NULL, 't' }, | |
670 | { "list-one", no_argument, NULL, 'l' }, | |
671 | { "label", required_argument, NULL, 'L' }, | |
672 | { "uuid", required_argument, NULL, 'U' }, | |
673 | { "probe", no_argument, NULL, 'p' }, | |
674 | { "info", no_argument, NULL, 'i' }, | |
675 | { "size", required_argument, NULL, 'S' }, | |
676 | { "offset", required_argument, NULL, 'O' }, | |
677 | { "usages", required_argument, NULL, 'u' }, | |
678 | { "match-types", required_argument, NULL, 'n' }, | |
679 | { "version", no_argument, NULL, 'V' }, | |
680 | { "help", no_argument, NULL, 'h' }, | |
681 | { NULL, 0, NULL, 0 } | |
682 | }; | |
683 | ||
a7349ee3 | 684 | static const ul_excl_t excl[] = { /* rows and cols in ASCII order */ |
a8e458b9 KZ |
685 | { 'n','u' }, |
686 | { 0 } | |
72b99fc5 | 687 | }; |
a8e458b9 | 688 | int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT; |
72b99fc5 | 689 | |
f5a2b07e SK |
690 | setlocale(LC_ALL, ""); |
691 | bindtextdomain(PACKAGE, LOCALEDIR); | |
692 | textdomain(PACKAGE); | |
c05a80ca | 693 | atexit(close_stdout); |
7711e215 | 694 | |
9c8b9fba RM |
695 | strutils_set_exitcode(BLKID_EXIT_OTHER); |
696 | ||
15a74f75 SK |
697 | while ((c = getopt_long (argc, argv, |
698 | "c:dghilL:n:ko:O:ps:S:t:u:U:w:Vv", longopts, NULL)) != -1) { | |
a8e458b9 KZ |
699 | |
700 | err_exclusive_options(c, NULL, excl, excl_st); | |
701 | ||
51410fc6 KZ |
702 | switch (c) { |
703 | case 'c': | |
59b94cc0 | 704 | read = optarg; |
51410fc6 | 705 | break; |
36a74e1b | 706 | case 'd': |
59b94cc0 | 707 | ctl.raw_chars = 1; |
36a74e1b | 708 | break; |
4786921c | 709 | case 'L': |
59b94cc0 | 710 | ctl.eval = 1; |
fe20e5d1 SK |
711 | search_value = xstrdup(optarg); |
712 | search_type = xstrdup("LABEL"); | |
4786921c | 713 | break; |
4f946f53 | 714 | case 'n': |
4f946f53 KZ |
715 | fltr_type = list_to_types(optarg, &fltr_flag); |
716 | break; | |
0bdd2f97 KZ |
717 | case 'u': |
718 | fltr_usage = list_to_usage(optarg, &fltr_flag); | |
719 | break; | |
4786921c | 720 | case 'U': |
59b94cc0 | 721 | ctl.eval = 1; |
fe20e5d1 SK |
722 | search_value = xstrdup(optarg); |
723 | search_type = xstrdup("UUID"); | |
4786921c | 724 | break; |
09792910 | 725 | case 'i': |
59b94cc0 | 726 | ctl.lowprobe_topology = 1; |
09792910 | 727 | break; |
51410fc6 | 728 | case 'l': |
59b94cc0 | 729 | ctl.lookup = 1; |
51410fc6 | 730 | break; |
51410fc6 | 731 | case 'g': |
59b94cc0 | 732 | ctl.gc = 1; |
51410fc6 | 733 | break; |
70db6c7e KZ |
734 | case 'k': |
735 | { | |
736 | size_t idx = 0; | |
737 | const char *name = NULL; | |
738 | ||
739 | while (blkid_superblocks_get_name(idx++, &name, NULL) == 0) | |
740 | printf("%s\n", name); | |
a922091d | 741 | exit(EXIT_SUCCESS); |
70db6c7e | 742 | } |
51410fc6 KZ |
743 | case 'o': |
744 | if (!strcmp(optarg, "value")) | |
59b94cc0 | 745 | ctl.output = OUTPUT_VALUE_ONLY; |
51410fc6 | 746 | else if (!strcmp(optarg, "device")) |
59b94cc0 | 747 | ctl.output = OUTPUT_DEVICE_ONLY; |
51410fc6 | 748 | else if (!strcmp(optarg, "list")) |
59b94cc0 | 749 | ctl.output = OUTPUT_PRETTY_LIST; /* deprecated */ |
b516dbe0 | 750 | else if (!strcmp(optarg, "udev")) |
59b94cc0 | 751 | ctl.output = OUTPUT_UDEV_LIST; |
ab978962 | 752 | else if (!strcmp(optarg, "export")) |
59b94cc0 | 753 | ctl.output = OUTPUT_EXPORT_LIST; |
51410fc6 | 754 | else if (!strcmp(optarg, "full")) |
59b94cc0 | 755 | ctl.output = 0; |
f5a2b07e SK |
756 | else |
757 | errx(BLKID_EXIT_OTHER, _("unsupported output format %s"), optarg); | |
51410fc6 | 758 | break; |
5b6215b5 | 759 | case 'O': |
59b94cc0 | 760 | ctl.offset = strtosize_or_err(optarg, _("invalid offset argument")); |
5b6215b5 KZ |
761 | break; |
762 | case 'p': | |
59b94cc0 | 763 | ctl.lowprobe_superblocks = 1; |
5b6215b5 | 764 | break; |
51410fc6 | 765 | case 's': |
59b94cc0 | 766 | if (numtag + 1 >= sizeof(ctl.show) / sizeof(*ctl.show)) { |
f5a2b07e | 767 | warnx(_("Too many tags specified")); |
3b7693ca | 768 | errtryhelp(err); |
51410fc6 | 769 | } |
59b94cc0 | 770 | ctl.show[numtag++] = optarg; |
51410fc6 | 771 | break; |
5b6215b5 | 772 | case 'S': |
59b94cc0 | 773 | ctl.size = strtosize_or_err(optarg, _("invalid size argument")); |
5b6215b5 | 774 | break; |
51410fc6 KZ |
775 | case 't': |
776 | if (search_type) { | |
f5a2b07e SK |
777 | warnx(_("Can only search for " |
778 | "one NAME=value pair")); | |
3b7693ca | 779 | errtryhelp(err); |
51410fc6 KZ |
780 | } |
781 | if (blkid_parse_tag_string(optarg, | |
782 | &search_type, | |
783 | &search_value)) { | |
f5a2b07e | 784 | warnx(_("-t needs NAME=value pair")); |
3b7693ca | 785 | errtryhelp(err); |
51410fc6 KZ |
786 | } |
787 | break; | |
a9b2c52f | 788 | case 'V': |
51410fc6 | 789 | case 'v': |
93bdbe19 | 790 | print_version(stdout); |
dc46610b | 791 | err = 0; |
93bdbe19 | 792 | goto exit; |
51410fc6 | 793 | case 'w': |
077b15dc | 794 | /* ignore - backward compatibility */ |
51410fc6 KZ |
795 | break; |
796 | case 'h': | |
677ec86c KZ |
797 | usage(0); |
798 | break; | |
51410fc6 | 799 | default: |
3b7693ca | 800 | errtryhelp(EXIT_FAILURE); |
51410fc6 | 801 | } |
a8e458b9 | 802 | } |
51410fc6 | 803 | |
59b94cc0 SK |
804 | if (ctl.lowprobe_topology || ctl.lowprobe_superblocks) |
805 | ctl.lowprobe = 1; | |
ea51c09c ES |
806 | |
807 | /* The rest of the args are device names */ | |
808 | if (optind < argc) { | |
5d00280c | 809 | devices = xcalloc(argc - optind, sizeof(char *)); |
54a00b5c KZ |
810 | while (optind < argc) |
811 | devices[numdev++] = argv[optind++]; | |
812 | } | |
51410fc6 | 813 | |
4786921c | 814 | /* convert LABEL/UUID lookup to evaluate request */ |
59b94cc0 | 815 | if (ctl.lookup && ctl.output == OUTPUT_DEVICE_ONLY && search_type && |
4786921c | 816 | (!strcmp(search_type, "LABEL") || !strcmp(search_type, "UUID"))) { |
59b94cc0 SK |
817 | ctl.eval = 1; |
818 | ctl.lookup = 0; | |
4786921c | 819 | } |
820 | ||
59b94cc0 | 821 | if (!ctl.lowprobe && !ctl.eval && blkid_get_cache(&cache, read) < 0) |
51410fc6 KZ |
822 | goto exit; |
823 | ||
59b94cc0 | 824 | if (ctl.gc) { |
51410fc6 | 825 | blkid_gc_cache(cache); |
324759d6 | 826 | err = 0; |
51410fc6 KZ |
827 | goto exit; |
828 | } | |
1578ddd6 | 829 | err = BLKID_EXIT_NOTFOUND; |
324759d6 | 830 | |
59b94cc0 SK |
831 | if (ctl.eval == 0 && (ctl.output & OUTPUT_PRETTY_LIST)) { |
832 | if (ctl.lowprobe) | |
f5a2b07e SK |
833 | errx(BLKID_EXIT_OTHER, |
834 | _("The low-level probing mode does not " | |
835 | "support 'list' output format")); | |
51410fc6 | 836 | pretty_print_dev(NULL); |
2d71a929 | 837 | } |
51410fc6 | 838 | |
59b94cc0 | 839 | if (ctl.lowprobe) { |
4786921c | 840 | /* |
841 | * Low-level API | |
842 | */ | |
5b6215b5 KZ |
843 | blkid_probe pr; |
844 | ||
f5a2b07e SK |
845 | if (!numdev) |
846 | errx(BLKID_EXIT_OTHER, | |
847 | _("The low-level probing mode " | |
848 | "requires a device")); | |
ab978962 KZ |
849 | |
850 | /* automatically enable 'export' format for I/O Limits */ | |
59b94cc0 SK |
851 | if (!ctl.output && ctl.lowprobe_topology) |
852 | ctl.output = OUTPUT_EXPORT_LIST; | |
ab978962 | 853 | |
5b6215b5 KZ |
854 | pr = blkid_new_probe(); |
855 | if (!pr) | |
856 | goto exit; | |
1b780848 | 857 | |
59b94cc0 | 858 | if (ctl.lowprobe_superblocks) { |
09792910 | 859 | blkid_probe_set_superblocks_flags(pr, |
1b780848 KZ |
860 | BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID | |
861 | BLKID_SUBLKS_TYPE | BLKID_SUBLKS_SECTYPE | | |
862 | BLKID_SUBLKS_USAGE | BLKID_SUBLKS_VERSION); | |
863 | ||
59b94cc0 SK |
864 | |
865 | if (fltr_usage && | |
866 | blkid_probe_filter_superblocks_usage(pr, fltr_flag, fltr_usage)) | |
09792910 KZ |
867 | goto exit; |
868 | ||
59b94cc0 SK |
869 | else if (fltr_type && |
870 | blkid_probe_filter_superblocks_type(pr, fltr_flag, fltr_type)) | |
09792910 KZ |
871 | goto exit; |
872 | } | |
5b6215b5 | 873 | |
078ad9bf | 874 | for (i = 0; i < numdev; i++) { |
59b94cc0 | 875 | err = lowprobe_device(pr, devices[i], &ctl); |
078ad9bf PU |
876 | if (err) |
877 | break; | |
878 | } | |
5b6215b5 | 879 | blkid_free_probe(pr); |
59b94cc0 | 880 | } else if (ctl.eval) { |
4786921c | 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 | } |
59b94cc0 | 889 | } else if (ctl.lookup) { |
4786921c | 890 | /* |
891 | * Classic (cache based) API | |
892 | */ | |
51410fc6 KZ |
893 | blkid_dev dev; |
894 | ||
f5a2b07e SK |
895 | if (!search_type) |
896 | errx(BLKID_EXIT_OTHER, | |
897 | _("The lookup option requires a " | |
898 | "search type specified using -t")); | |
51410fc6 KZ |
899 | /* Load any additional devices not in the cache */ |
900 | for (i = 0; i < numdev; i++) | |
901 | blkid_get_dev(cache, devices[i], BLKID_DEV_NORMAL); | |
902 | ||
903 | if ((dev = blkid_find_dev_with_tag(cache, search_type, | |
904 | search_value))) { | |
59b94cc0 | 905 | print_tags(&ctl, dev); |
51410fc6 KZ |
906 | err = 0; |
907 | } | |
908 | /* If we didn't specify a single device, show all available devices */ | |
909 | } else if (!numdev) { | |
910 | blkid_dev_iterate iter; | |
911 | blkid_dev dev; | |
912 | ||
913 | blkid_probe_all(cache); | |
914 | ||
915 | iter = blkid_dev_iterate_begin(cache); | |
916 | blkid_dev_set_search(iter, search_type, search_value); | |
917 | while (blkid_dev_next(iter, &dev) == 0) { | |
918 | dev = blkid_verify(cache, dev); | |
919 | if (!dev) | |
920 | continue; | |
59b94cc0 | 921 | print_tags(&ctl, dev); |
51410fc6 KZ |
922 | err = 0; |
923 | } | |
924 | blkid_dev_iterate_end(iter); | |
925 | /* Add all specified devices to cache (optionally display tags) */ | |
926 | } else for (i = 0; i < numdev; i++) { | |
927 | blkid_dev dev = blkid_get_dev(cache, devices[i], | |
928 | BLKID_DEV_NORMAL); | |
929 | ||
930 | if (dev) { | |
931 | if (search_type && | |
932 | !blkid_dev_has_tag(dev, search_type, | |
933 | search_value)) | |
934 | continue; | |
59b94cc0 | 935 | print_tags(&ctl, dev); |
51410fc6 KZ |
936 | err = 0; |
937 | } | |
938 | } | |
939 | ||
940 | exit: | |
4786921c | 941 | free(search_type); |
942 | free(search_value); | |
4f946f53 | 943 | free_types_list(fltr_type); |
59b94cc0 | 944 | if (!ctl.lowprobe && !ctl.eval) |
5b6215b5 | 945 | blkid_put_cache(cache); |
ea51c09c | 946 | free(devices); |
51410fc6 KZ |
947 | return err; |
948 | } |