diff options
Diffstat (limited to 'misc-utils/blkid.c')
-rw-r--r-- | misc-utils/blkid.c | 963 |
1 files changed, 963 insertions, 0 deletions
diff --git a/misc-utils/blkid.c b/misc-utils/blkid.c new file mode 100644 index 0000000..dba3bb7 --- /dev/null +++ b/misc-utils/blkid.c @@ -0,0 +1,963 @@ +/* + * blkid.c - User command-line interface for libblkid + * + * Copyright (C) 2001 Andreas Dilger + * + * %Begin-Header% + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * %End-Header% + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> +#include <getopt.h> + +#define OUTPUT_FULL (1 << 0) +#define OUTPUT_VALUE_ONLY (1 << 1) +#define OUTPUT_DEVICE_ONLY (1 << 2) +#define OUTPUT_PRETTY_LIST (1 << 3) /* deprecated */ +#define OUTPUT_UDEV_LIST (1 << 4) /* deprecated */ +#define OUTPUT_EXPORT_LIST (1 << 5) + +#define BLKID_EXIT_NOTFOUND 2 /* token or device not found */ +#define BLKID_EXIT_OTHER 4 /* bad usage or other error */ +#define BLKID_EXIT_AMBIVAL 8 /* ambivalent low-level probing detected */ + +#include <blkid.h> + +#include "ismounted.h" + +#include "strutils.h" +#define OPTUTILS_EXIT_CODE BLKID_EXIT_OTHER /* exclusive_option() */ +#include "optutils.h" +#define CLOSE_EXIT_CODE BLKID_EXIT_OTHER /* close_stdout() */ +#include "closestream.h" + +#include "nls.h" +#include "ttyutils.h" + +#define XALLOC_EXIT_CODE BLKID_EXIT_OTHER /* x.*alloc(), xstrndup() */ +#include "xalloc.h" + +struct blkid_control { + int output; + uintmax_t offset; + uintmax_t size; + char *show[128]; + unsigned int + eval:1, + gc:1, + lookup:1, + lowprobe:1, + lowprobe_superblocks:1, + lowprobe_topology:1, + no_part_details:1, + raw_chars:1; +}; + +static void __attribute__((__noreturn__)) usage(void) +{ + FILE *out = stdout; + + fputs(USAGE_HEADER, out); + fprintf(out, _( " %s --label <label> | --uuid <uuid>\n\n"), program_invocation_short_name); + fprintf(out, _( " %s [--cache-file <file>] [-ghlLv] [--output <format>] [--match-tag <tag>] \n" + " [--match-token <token>] [<dev> ...]\n\n"), program_invocation_short_name); + fprintf(out, _( " %s -p [--match-tag <tag>] [--offset <offset>] [--size <size>] \n" + " [--output <format>] <dev> ...\n\n"), program_invocation_short_name); + fprintf(out, _( " %s -i [--match-tag <tag>] [--output <format>] <dev> ...\n"), program_invocation_short_name); + fputs(USAGE_OPTIONS, out); + fputs(_( " -c, --cache-file <file> read from <file> instead of reading from the default\n" + " cache file (-c /dev/null means no cache)\n"), out); + fputs(_( " -d, --no-encoding don't encode non-printing characters\n"), out); + fputs(_( " -g, --garbage-collect garbage collect the blkid cache\n"), out); + fputs(_( " -o, --output <format> output format; can be one of:\n" + " value, device, export or full; (default: full)\n"), out); + fputs(_( " -k, --list-filesystems list all known filesystems/RAIDs and exit\n"), out); + fputs(_( " -s, --match-tag <tag> show specified tag(s) (default show all tags)\n"), out); + fputs(_( " -t, --match-token <token> find device with a specific token (NAME=value pair)\n"), out); + fputs(_( " -l, --list-one look up only first device with token specified by -t\n"), out); + fputs(_( " -L, --label <label> convert LABEL to device name\n"), out); + fputs(_( " -U, --uuid <uuid> convert UUID to device name\n"), out); + fputs( "\n", out); + fputs(_( "Low-level probing options:\n"), out); + fputs(_( " -p, --probe low-level superblocks probing (bypass cache)\n"), out); + fputs(_( " -i, --info gather information about I/O limits\n"), out); + fputs(_( " -S, --size <size> overwrite device size\n"), out); + fputs(_( " -O, --offset <offset> probe at the given offset\n"), out); + fputs(_( " -u, --usages <list> filter by \"usage\" (e.g. -u filesystem,raid)\n"), out); + fputs(_( " -n, --match-types <list> filter by filesystem type (e.g. -n vfat,ext3)\n"), out); + fputs(_( " -D, --no-part-details don't print info from partition table\n"), out); + + fputs(USAGE_SEPARATOR, out); + printf(USAGE_HELP_OPTIONS(28)); + + fputs(USAGE_ARGUMENTS, out); + printf(USAGE_ARG_SIZE(_("<size> and <offset>"))); + fputs(USAGE_ARG_SEPARATOR, out); + fputs(_(" <dev> specify device(s) to probe (default: all devices)\n"), out); + + printf(USAGE_MAN_TAIL("blkid(8)")); + exit(EXIT_SUCCESS); +} + +/* + * This function does "safe" printing. It will convert non-printable + * ASCII characters using '^' and M- notation. + * + * If 'esc' is defined then escape all chars from esc by \. + */ +static void safe_print(const struct blkid_control *ctl, const char *cp, int len, + const char *esc) +{ + unsigned char ch; + + if (len < 0) + len = strlen(cp); + + while (len--) { + ch = *cp++; + if (!ctl->raw_chars) { + if (ch >= 128) { + fputs("M-", stdout); + ch -= 128; + } + if ((ch < 32) || (ch == 0x7f)) { + fputc('^', stdout); + ch ^= 0x40; /* ^@, ^A, ^B; ^? for DEL */ + + } else if (esc && strchr(esc, ch)) + fputc('\\', stdout); + } + fputc(ch, stdout); + } +} + +static int pretty_print_word(const char *str, int max_len, + int left_len, int overflow_nl) +{ + int len = strlen(str) + left_len; + int ret = 0; + + fputs(str, stdout); + if (overflow_nl && len > max_len) { + fputc('\n', stdout); + len = 0; + } else if (len > max_len) + ret = len - max_len; + do { + fputc(' ', stdout); + } while (len++ < max_len); + return ret; +} + +static void pretty_print_line(const char *device, const char *fs_type, + const char *label, const char *mtpt, + const char *uuid) +{ + static int device_len = 10, fs_type_len = 7; + static int label_len = 8, mtpt_len = 14; + static int term_width = -1; + int len, w; + + if (term_width < 0) { + term_width = get_terminal_width(80); + } + if (term_width > 80) { + term_width -= 80; + w = term_width / 10; + if (w > 8) + w = 8; + term_width -= 2*w; + label_len += w; + fs_type_len += w; + w = term_width/2; + device_len += w; + mtpt_len +=w; + } + + len = pretty_print_word(device, device_len, 0, 1); + len = pretty_print_word(fs_type, fs_type_len, len, 0); + len = pretty_print_word(label, label_len, len, 0); + pretty_print_word(mtpt, mtpt_len, len, 0); + + fputs(uuid, stdout); + fputc('\n', stdout); +} + +static void pretty_print_dev(blkid_dev dev) +{ + blkid_tag_iterate iter; + const char *type, *value, *devname; + const char *uuid = "", *fs_type = "", *label = ""; + int len, mount_flags; + char mtpt[80]; + int retval; + + if (dev == NULL) { + pretty_print_line("device", "fs_type", "label", + "mount point", "UUID"); + for (len=get_terminal_width(0)-1; len > 0; len--) + fputc('-', stdout); + fputc('\n', stdout); + return; + } + + devname = blkid_dev_devname(dev); + if (access(devname, F_OK)) + return; + + /* Get the uuid, label, type */ + iter = blkid_tag_iterate_begin(dev); + while (blkid_tag_next(iter, &type, &value) == 0) { + if (!strcmp(type, "UUID")) + uuid = value; + if (!strcmp(type, "TYPE")) + fs_type = value; + if (!strcmp(type, "LABEL")) + label = value; + } + blkid_tag_iterate_end(iter); + + /* Get the mount point */ + mtpt[0] = 0; + retval = check_mount_point(devname, &mount_flags, mtpt, sizeof(mtpt)); + if (retval == 0) { + const char *msg = NULL; + + if (mount_flags & MF_MOUNTED) { + if (!mtpt[0]) + msg = _("(mounted, mtpt unknown)"); + } else if (mount_flags & MF_BUSY) + msg = _("(in use)"); + else + msg = _("(not mounted)"); + + if (msg) + xstrncpy(mtpt, msg, sizeof(mtpt)); + } + + pretty_print_line(devname, fs_type, label, mtpt, uuid); +} + +static void print_udev_format(const char *name, const char *value) +{ + char enc[265], safe[256]; + size_t namelen = strlen(name); + + *safe = *enc = '\0'; + + if (!strcmp(name, "TYPE") || !strcmp(name, "VERSION")) { + blkid_encode_string(value, enc, sizeof(enc)); + printf("ID_FS_%s=%s\n", name, enc); + + } else if (!strcmp(name, "UUID") || + !strncmp(name, "LABEL", 5) || + !strcmp(name, "UUID_SUB")) { + + blkid_safe_string(value, safe, sizeof(safe)); + printf("ID_FS_%s=%s\n", name, safe); + + blkid_encode_string(value, enc, sizeof(enc)); + printf("ID_FS_%s_ENC=%s\n", name, enc); + + } else if (!strcmp(name, "PTUUID")) { + printf("ID_PART_TABLE_UUID=%s\n", value); + + } else if (!strcmp(name, "PTTYPE")) { + printf("ID_PART_TABLE_TYPE=%s\n", value); + + } else if (!strcmp(name, "PART_ENTRY_NAME") || + !strcmp(name, "PART_ENTRY_TYPE")) { + + blkid_encode_string(value, enc, sizeof(enc)); + printf("ID_%s=%s\n", name, enc); + + } else if (!strncmp(name, "PART_ENTRY_", 11)) + printf("ID_%s=%s\n", name, value); + + else if (namelen >= 15 && ( + !strcmp(name + (namelen - 12), "_SECTOR_SIZE") || + !strcmp(name + (namelen - 8), "_IO_SIZE") || + !strcmp(name, "ALIGNMENT_OFFSET"))) + printf("ID_IOLIMIT_%s=%s\n", name, value); + else + printf("ID_FS_%s=%s\n", name, value); +} + +static int has_item(const struct blkid_control *ctl, const char *item) +{ + char * const *p; + + for (p = ctl->show; *p != NULL; p++) + if (!strcmp(item, *p)) + return 1; + return 0; +} + +static void print_value(const struct blkid_control *ctl, int num, + const char *devname, const char *value, + const char *name, size_t valsz) +{ + if (ctl->output & OUTPUT_VALUE_ONLY) { + fputs(value, stdout); + fputc('\n', stdout); + + } else if (ctl->output & OUTPUT_UDEV_LIST) { + print_udev_format(name, value); + + } else if (ctl->output & OUTPUT_EXPORT_LIST) { + if (num == 1 && devname) + printf("DEVNAME=%s\n", devname); + fputs(name, stdout); + fputs("=", stdout); + safe_print(ctl, value, valsz, " \\\"'$`<>"); + fputs("\n", stdout); + + } else { + if (num == 1 && devname) + printf("%s:", devname); + fputs(" ", stdout); + fputs(name, stdout); + fputs("=\"", stdout); + safe_print(ctl, value, valsz, "\"\\"); + fputs("\"", stdout); + } +} + +static void print_tags(const struct blkid_control *ctl, blkid_dev dev) +{ + blkid_tag_iterate iter; + const char *type, *value, *devname; + int num = 1; + static int first = 1; + + if (!dev) + return; + + if (ctl->output & OUTPUT_PRETTY_LIST) { + pretty_print_dev(dev); + return; + } + + devname = blkid_dev_devname(dev); + + if (ctl->output & OUTPUT_DEVICE_ONLY) { + printf("%s\n", devname); + return; + } + + iter = blkid_tag_iterate_begin(dev); + while (blkid_tag_next(iter, &type, &value) == 0) { + if (ctl->show[0] && !has_item(ctl, type)) + continue; + + if (num == 1 && !first && + (ctl->output & (OUTPUT_UDEV_LIST | OUTPUT_EXPORT_LIST))) + /* add extra line between output from more devices */ + fputc('\n', stdout); + + print_value(ctl, num++, devname, value, type, strlen(value)); + } + blkid_tag_iterate_end(iter); + + if (num > 1) { + if (!(ctl->output & (OUTPUT_VALUE_ONLY | OUTPUT_UDEV_LIST | + OUTPUT_EXPORT_LIST))) + printf("\n"); + first = 0; + } +} + + +static int append_str(char **res, size_t *sz, const char *a, const char *b) +{ + char *str = *res; + size_t asz = a ? strlen(a) : 0; + size_t bsz = b ? strlen(b) : 0; + size_t len = *sz + asz + bsz; + + if (!len) + return -1; + + *res = str = xrealloc(str, len + 1); + str += *sz; + + if (a) { + memcpy(str, a, asz); + str += asz; + } + if (b) { + memcpy(str, b, bsz); + str += bsz; + } + *str = '\0'; + *sz = len; + return 0; +} + +/* + * Compose and print ID_FS_AMBIVALENT for udev + */ +static int print_udev_ambivalent(blkid_probe pr) +{ + char *val = NULL; + size_t valsz = 0; + int count = 0, rc = -1; + + while (!blkid_do_probe(pr)) { + const char *usage_txt = NULL, *type = NULL, *version = NULL; + char enc[256]; + + blkid_probe_lookup_value(pr, "USAGE", &usage_txt, NULL); + blkid_probe_lookup_value(pr, "TYPE", &type, NULL); + blkid_probe_lookup_value(pr, "VERSION", &version, NULL); + + if (!usage_txt || !type) + continue; + + blkid_encode_string(usage_txt, enc, sizeof(enc)); + if (append_str(&val, &valsz, enc, ":")) + goto done; + + blkid_encode_string(type, enc, sizeof(enc)); + if (append_str(&val, &valsz, enc, version ? ":" : " ")) + goto done; + + if (version) { + blkid_encode_string(version, enc, sizeof(enc)); + if (append_str(&val, &valsz, enc, " ")) + goto done; + } + count++; + } + + if (count > 1) { + *(val + valsz - 1) = '\0'; /* rem tailing whitespace */ + printf("ID_FS_AMBIVALENT=%s\n", val); + rc = 0; + } +done: + free(val); + return rc; +} + +static int lowprobe_superblocks(blkid_probe pr, struct blkid_control *ctl) +{ + struct stat st; + int rc, fd = blkid_probe_get_fd(pr); + + if (fd < 0 || fstat(fd, &st)) + return -1; + + blkid_probe_enable_partitions(pr, 1); + + if (!S_ISCHR(st.st_mode) && blkid_probe_get_size(pr) <= 1024 * 1440 && + blkid_probe_is_wholedisk(pr)) { + /* + * check if the small disk is partitioned, if yes then + * don't probe for filesystems. + */ + blkid_probe_enable_superblocks(pr, 0); + + rc = blkid_do_fullprobe(pr); + if (rc < 0) + return rc; /* -1 = error, 1 = nothing, 0 = success */ + + if (blkid_probe_lookup_value(pr, "PTTYPE", NULL, NULL) == 0) + return 0; /* partition table detected */ + } + + if (!ctl->no_part_details) + blkid_probe_set_partitions_flags(pr, BLKID_PARTS_ENTRY_DETAILS); + blkid_probe_enable_superblocks(pr, 1); + + return blkid_do_safeprobe(pr); +} + +static int lowprobe_topology(blkid_probe pr) +{ + /* enable topology probing only */ + blkid_probe_enable_topology(pr, 1); + + blkid_probe_enable_superblocks(pr, 0); + blkid_probe_enable_partitions(pr, 0); + + return blkid_do_fullprobe(pr); +} + +static int lowprobe_device(blkid_probe pr, const char *devname, + struct blkid_control *ctl) +{ + const char *data; + const char *name; + int nvals = 0, n, num = 1; + size_t len; + int fd; + int rc = 0; + static int first = 1; + + fd = open(devname, O_RDONLY|O_CLOEXEC|O_NONBLOCK); + if (fd < 0) { + warn(_("error: %s"), devname); + return BLKID_EXIT_NOTFOUND; + } + errno = 0; + if (blkid_probe_set_device(pr, fd, ctl->offset, ctl->size)) { + if (errno) + warn(_("error: %s"), devname); + goto done; + } + + if (ctl->lowprobe_topology) + rc = lowprobe_topology(pr); + if (rc >= 0 && ctl->lowprobe_superblocks) + rc = lowprobe_superblocks(pr, ctl); + if (rc < 0) + goto done; + + if (!rc) + nvals = blkid_probe_numof_values(pr); + + if (nvals && !first && ctl->output & (OUTPUT_UDEV_LIST | OUTPUT_EXPORT_LIST)) + /* add extra line between output from devices */ + fputc('\n', stdout); + + if (nvals && (ctl->output & OUTPUT_DEVICE_ONLY)) { + printf("%s\n", devname); + goto done; + } + + for (n = 0; n < nvals; n++) { + if (blkid_probe_get_value(pr, n, &name, &data, &len)) + continue; + if (ctl->show[0] && !has_item(ctl, name)) + continue; + len = strnlen(data, len); + print_value(ctl, num++, devname, data, name, len); + } + + if (first) + first = 0; + + if (nvals >= 1 && !(ctl->output & (OUTPUT_VALUE_ONLY | + OUTPUT_UDEV_LIST | OUTPUT_EXPORT_LIST))) + printf("\n"); +done: + if (rc == -2) { + if (ctl->output & OUTPUT_UDEV_LIST) + print_udev_ambivalent(pr); + else + warnx(_("%s: ambivalent result (probably more " + "filesystems on the device, use wipefs(8) " + "to see more details)"), + devname); + } + close(fd); + + if (rc == -2) + return BLKID_EXIT_AMBIVAL; /* ambivalent probing result */ + if (!nvals) + return BLKID_EXIT_NOTFOUND; /* nothing detected */ + + return 0; /* success */ +} + +/* converts comma separated list to BLKID_USAGE_* mask */ +static int list_to_usage(const char *list, int *flag) +{ + int mask = 0; + const char *word = NULL, *p = list; + + if (p && strncmp(p, "no", 2) == 0) { + *flag = BLKID_FLTR_NOTIN; + p += 2; + } + if (!p || !*p) + goto err; + while(p) { + word = p; + p = strchr(p, ','); + if (p) + p++; + if (!strncmp(word, "filesystem", 10)) + mask |= BLKID_USAGE_FILESYSTEM; + else if (!strncmp(word, "raid", 4)) + mask |= BLKID_USAGE_RAID; + else if (!strncmp(word, "crypto", 6)) + mask |= BLKID_USAGE_CRYPTO; + else if (!strncmp(word, "other", 5)) + mask |= BLKID_USAGE_OTHER; + else + goto err; + } + return mask; +err: + *flag = 0; + warnx(_("unknown keyword in -u <list> argument: '%s'"), + word ? word : list); + exit(BLKID_EXIT_OTHER); +} + +/* converts comma separated list to types[] */ +static char **list_to_types(const char *list, int *flag) +{ + int i; + const char *p = list; + char **res = NULL; + + if (p && strncmp(p, "no", 2) == 0) { + *flag = BLKID_FLTR_NOTIN; + p += 2; + } + if (!p || !*p) { + warnx(_("error: -u <list> argument is empty")); + goto err; + } + for (i = 1; p && (p = strchr(p, ',')); i++, p++); + + res = xcalloc(i + 1, sizeof(char *)); + p = *flag & BLKID_FLTR_NOTIN ? list + 2 : list; + i = 0; + + while(p) { + const char *word = p; + p = strchr(p, ','); + res[i++] = p ? xstrndup(word, p - word) : xstrdup(word); + if (p) + p++; + } + res[i] = NULL; + return res; +err: + *flag = 0; + free(res); + exit(BLKID_EXIT_OTHER); +} + +static void free_types_list(char *list[]) +{ + char **n; + + if (!list) + return; + for (n = list; *n; n++) + free(*n); + free(list); +} + +int main(int argc, char **argv) +{ + struct blkid_control ctl = { .output = OUTPUT_FULL, 0 }; + blkid_cache cache = NULL; + char **devices = NULL; + char *search_type = NULL, *search_value = NULL; + char *read = NULL; + int fltr_usage = 0; + char **fltr_type = NULL; + int fltr_flag = BLKID_FLTR_ONLYIN; + unsigned int numdev = 0, numtag = 0; + int err = BLKID_EXIT_OTHER; + unsigned int i; + int c; + + static const struct option longopts[] = { + { "cache-file", required_argument, NULL, 'c' }, + { "no-encoding", no_argument, NULL, 'd' }, + { "no-part-details", no_argument, NULL, 'D' }, + { "garbage-collect", no_argument, NULL, 'g' }, + { "output", required_argument, NULL, 'o' }, + { "list-filesystems", no_argument, NULL, 'k' }, + { "match-tag", required_argument, NULL, 's' }, + { "match-token", required_argument, NULL, 't' }, + { "list-one", no_argument, NULL, 'l' }, + { "label", required_argument, NULL, 'L' }, + { "uuid", required_argument, NULL, 'U' }, + { "probe", no_argument, NULL, 'p' }, + { "info", no_argument, NULL, 'i' }, + { "size", required_argument, NULL, 'S' }, + { "offset", required_argument, NULL, 'O' }, + { "usages", required_argument, NULL, 'u' }, + { "match-types", required_argument, NULL, 'n' }, + { "version", no_argument, NULL, 'V' }, + { "help", no_argument, NULL, 'h' }, + { NULL, 0, NULL, 0 } + }; + + static const ul_excl_t excl[] = { /* rows and cols in ASCII order */ + { 'n','u' }, + { 0 } + }; + int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT; + + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + close_stdout_atexit(); + + strutils_set_exitcode(BLKID_EXIT_OTHER); + + while ((c = getopt_long (argc, argv, + "c:DdghilL:n:ko:O:ps:S:t:u:U:w:Vv", longopts, NULL)) != -1) { + + err_exclusive_options(c, NULL, excl, excl_st); + + switch (c) { + case 'c': + read = optarg; + break; + case 'd': + ctl.raw_chars = 1; + break; + case 'D': + ctl.no_part_details = 1; + break; + case 'L': + ctl.eval = 1; + search_value = xstrdup(optarg); + search_type = xstrdup("LABEL"); + break; + case 'n': + fltr_type = list_to_types(optarg, &fltr_flag); + break; + case 'u': + fltr_usage = list_to_usage(optarg, &fltr_flag); + break; + case 'U': + ctl.eval = 1; + search_value = xstrdup(optarg); + search_type = xstrdup("UUID"); + break; + case 'i': + ctl.lowprobe_topology = 1; + break; + case 'l': + ctl.lookup = 1; + break; + case 'g': + ctl.gc = 1; + break; + case 'k': + { + size_t idx = 0; + const char *name = NULL; + + while (blkid_superblocks_get_name(idx++, &name, NULL) == 0) + printf("%s\n", name); + exit(EXIT_SUCCESS); + } + case 'o': + if (!strcmp(optarg, "value")) + ctl.output = OUTPUT_VALUE_ONLY; + else if (!strcmp(optarg, "device")) + ctl.output = OUTPUT_DEVICE_ONLY; + else if (!strcmp(optarg, "list")) + ctl.output = OUTPUT_PRETTY_LIST; /* deprecated */ + else if (!strcmp(optarg, "udev")) + ctl.output = OUTPUT_UDEV_LIST; + else if (!strcmp(optarg, "export")) + ctl.output = OUTPUT_EXPORT_LIST; + else if (!strcmp(optarg, "full")) + ctl.output = 0; + else + errx(BLKID_EXIT_OTHER, _("unsupported output format %s"), optarg); + break; + case 'O': + ctl.offset = strtosize_or_err(optarg, _("invalid offset argument")); + break; + case 'p': + ctl.lowprobe_superblocks = 1; + break; + case 's': + if (numtag + 1 >= sizeof(ctl.show) / sizeof(*ctl.show)) { + warnx(_("Too many tags specified")); + errtryhelp(err); + } + ctl.show[numtag++] = optarg; + break; + case 'S': + ctl.size = strtosize_or_err(optarg, _("invalid size argument")); + break; + case 't': + if (search_type) { + warnx(_("Can only search for " + "one NAME=value pair")); + errtryhelp(err); + } + if (blkid_parse_tag_string(optarg, + &search_type, + &search_value)) { + warnx(_("-t needs NAME=value pair")); + errtryhelp(err); + } + break; + case 'V': + case 'v': + fprintf(stdout, _("%s from %s (libblkid %s, %s)\n"), + program_invocation_short_name, PACKAGE_STRING, + LIBBLKID_VERSION, LIBBLKID_DATE); + err = 0; + goto exit; + case 'w': + /* ignore - backward compatibility */ + break; + case 'h': + usage(); + break; + default: + errtryhelp(EXIT_FAILURE); + } + } + + if (ctl.lowprobe_topology || ctl.lowprobe_superblocks) + ctl.lowprobe = 1; + + /* The rest of the args are device names */ + if (optind < argc) { + devices = xcalloc(argc - optind, sizeof(char *)); + while (optind < argc) + devices[numdev++] = argv[optind++]; + } + + /* convert LABEL/UUID lookup to evaluate request */ + if (ctl.lookup && ctl.output == OUTPUT_DEVICE_ONLY && search_type && + (!strcmp(search_type, "LABEL") || !strcmp(search_type, "UUID"))) { + ctl.eval = 1; + ctl.lookup = 0; + } + + if (!ctl.lowprobe && !ctl.eval && blkid_get_cache(&cache, read) < 0) + goto exit; + + if (ctl.gc) { + blkid_gc_cache(cache); + err = 0; + goto exit; + } + err = BLKID_EXIT_NOTFOUND; + + if (ctl.eval == 0 && (ctl.output & OUTPUT_PRETTY_LIST)) { + if (ctl.lowprobe) + errx(BLKID_EXIT_OTHER, + _("The low-level probing mode does not " + "support 'list' output format")); + pretty_print_dev(NULL); + } + + if (ctl.lowprobe) { + /* + * Low-level API + */ + blkid_probe pr; + + if (!numdev) + errx(BLKID_EXIT_OTHER, + _("The low-level probing mode " + "requires a device")); + + /* automatically enable 'export' format for I/O Limits */ + if (!ctl.output && ctl.lowprobe_topology) + ctl.output = OUTPUT_EXPORT_LIST; + + pr = blkid_new_probe(); + if (!pr) + goto exit; + + if (ctl.lowprobe_superblocks) { + blkid_probe_set_superblocks_flags(pr, + BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID | + BLKID_SUBLKS_TYPE | BLKID_SUBLKS_SECTYPE | + BLKID_SUBLKS_USAGE | BLKID_SUBLKS_VERSION); + + + if (fltr_usage && + blkid_probe_filter_superblocks_usage(pr, fltr_flag, fltr_usage)) + goto exit; + + else if (fltr_type && + blkid_probe_filter_superblocks_type(pr, fltr_flag, fltr_type)) + goto exit; + } + + for (i = 0; i < numdev; i++) { + err = lowprobe_device(pr, devices[i], &ctl); + if (err) + break; + } + blkid_free_probe(pr); + } else if (ctl.eval) { + /* + * Evaluate API + */ + char *res = blkid_evaluate_tag(search_type, search_value, NULL); + if (res) { + err = 0; + printf("%s\n", res); + } + } else if (ctl.lookup) { + /* + * Classic (cache based) API + */ + blkid_dev dev; + + if (!search_type) + errx(BLKID_EXIT_OTHER, + _("The lookup option requires a " + "search type specified using -t")); + /* Load any additional devices not in the cache */ + for (i = 0; i < numdev; i++) + blkid_get_dev(cache, devices[i], BLKID_DEV_NORMAL); + + if ((dev = blkid_find_dev_with_tag(cache, search_type, + search_value))) { + print_tags(&ctl, dev); + err = 0; + } + /* If we didn't specify a single device, show all available devices */ + } else if (!numdev) { + blkid_dev_iterate iter; + blkid_dev dev; + + blkid_probe_all(cache); + + iter = blkid_dev_iterate_begin(cache); + blkid_dev_set_search(iter, search_type, search_value); + while (blkid_dev_next(iter, &dev) == 0) { + dev = blkid_verify(cache, dev); + if (!dev) + continue; + print_tags(&ctl, dev); + err = 0; + } + blkid_dev_iterate_end(iter); + /* Add all specified devices to cache (optionally display tags) */ + } else for (i = 0; i < numdev; i++) { + blkid_dev dev = blkid_get_dev(cache, devices[i], + BLKID_DEV_NORMAL); + + if (dev) { + if (search_type && + !blkid_dev_has_tag(dev, search_type, + search_value)) + continue; + print_tags(&ctl, dev); + err = 0; + } + } + +exit: + free(search_type); + free(search_value); + free_types_list(fltr_type); + if (!ctl.lowprobe && !ctl.eval) + blkid_put_cache(cache); + free(devices); + return err; +} |