| /* |
| * uuidparse.c --- Interpret uuid encoded information. This program |
| * violates the UUID abstraction barrier by reaching into the |
| * guts of a UUID. |
| * |
| * Based on libuuid/src/uuid_time.c |
| * Copyright (C) 1998, 1999 Theodore Ts'o. |
| * |
| * All alterations (C) 2017 Sami Kerola |
| * The 3-Clause BSD License |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, and the entire permission notice in its entirety, |
| * including the disclaimer of warranties. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * 3. The name of the author may not be used to endorse or promote |
| * products derived from this software without specific prior |
| * written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF |
| * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE |
| * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT |
| * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE |
| * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH |
| * DAMAGE. |
| */ |
| |
| #include <assert.h> |
| #include <getopt.h> |
| #include <libsmartcols.h> |
| #include <stdint.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <time.h> |
| #include <unistd.h> |
| #include <uuid.h> |
| |
| #include "c.h" |
| #include "closestream.h" |
| #include "nls.h" |
| #include "optutils.h" |
| #include "strutils.h" |
| #include "timeutils.h" |
| #include "xalloc.h" |
| |
| /* column IDs */ |
| enum { |
| COL_UUID = 0, |
| COL_VARIANT, |
| COL_TYPE, |
| COL_TIME |
| }; |
| |
| /* column names */ |
| struct colinfo { |
| const char *name; /* header */ |
| double whint; /* width hint (N < 1 is in percent of termwidth) */ |
| int flags; /* SCOLS_FL_* */ |
| const char *help; |
| }; |
| |
| /* columns descriptions */ |
| static const struct colinfo infos[] = { |
| [COL_UUID] = {"UUID", UUID_STR_LEN, 0, N_("unique identifier")}, |
| [COL_VARIANT] = {"VARIANT", 9, 0, N_("variant name")}, |
| [COL_TYPE] = {"TYPE", 10, 0, N_("type name")}, |
| [COL_TIME] = {"TIME", 31, 0, N_("timestamp")} |
| }; |
| |
| static int columns[ARRAY_SIZE(infos) * 2]; |
| static size_t ncolumns; |
| |
| struct control { |
| unsigned int |
| json:1, |
| no_headings:1, |
| raw:1; |
| }; |
| |
| static void __attribute__((__noreturn__)) usage(void) |
| { |
| size_t i; |
| |
| fputs(USAGE_HEADER, stdout); |
| fprintf(stdout, _(" %s [options] <uuid ...>\n"), program_invocation_short_name); |
| |
| fputs(USAGE_OPTIONS, stdout); |
| puts(_(" -J, --json use JSON output format")); |
| puts(_(" -n, --noheadings don't print headings")); |
| puts(_(" -o, --output <list> COLUMNS to display (see below)")); |
| puts(_(" -r, --raw use the raw output format")); |
| printf(USAGE_HELP_OPTIONS(24)); |
| |
| fputs(USAGE_COLUMNS, stdout); |
| for (i = 0; i < ARRAY_SIZE(infos); i++) |
| fprintf(stdout, " %8s %s\n", infos[i].name, _(infos[i].help)); |
| |
| printf(USAGE_MAN_TAIL("uuidparse(1)")); |
| exit(EXIT_SUCCESS); |
| } |
| |
| static int column_name_to_id(const char *name, size_t namesz) |
| { |
| size_t i; |
| |
| assert(name); |
| |
| for (i = 0; i < ARRAY_SIZE(infos); i++) { |
| const char *cn = infos[i].name; |
| if (!strncasecmp(name, cn, namesz) && !*(cn + namesz)) |
| return i; |
| } |
| warnx(_("unknown column: %s"), name); |
| return -1; |
| } |
| |
| static int get_column_id(size_t num) |
| { |
| assert(num < ncolumns); |
| assert(columns[num] < (int)ARRAY_SIZE(infos)); |
| return columns[num]; |
| } |
| |
| static const struct colinfo *get_column_info(int num) |
| { |
| return &infos[get_column_id(num)]; |
| } |
| |
| static void fill_table_row(struct libscols_table *tb, char const *const uuid) |
| { |
| static struct libscols_line *ln; |
| size_t i; |
| uuid_t buf; |
| int invalid = 0; |
| int variant, type; |
| |
| assert(tb); |
| assert(uuid); |
| |
| ln = scols_table_new_line(tb, NULL); |
| if (!ln) |
| errx(EXIT_FAILURE, _("failed to allocate output line")); |
| |
| if (uuid_parse(uuid, buf)) |
| invalid = 1; |
| else { |
| variant = uuid_variant(buf); |
| type = uuid_type(buf); |
| } |
| |
| for (i = 0; i < ncolumns; i++) { |
| char *str = NULL; |
| |
| switch (get_column_id(i)) { |
| case COL_UUID: |
| str = xstrdup(uuid); |
| break; |
| case COL_VARIANT: |
| if (invalid) { |
| str = xstrdup(_("invalid")); |
| break; |
| } |
| switch (variant) { |
| case UUID_VARIANT_NCS: |
| str = xstrdup("NCS"); |
| break; |
| case UUID_VARIANT_DCE: |
| str = xstrdup("DCE"); |
| break; |
| case UUID_VARIANT_MICROSOFT: |
| str = xstrdup("Microsoft"); |
| break; |
| default: |
| str = xstrdup(_("other")); |
| } |
| break; |
| case COL_TYPE: |
| if (invalid) { |
| str = xstrdup(_("invalid")); |
| break; |
| } |
| switch (type) { |
| case 0: |
| if (strspn(uuid, "0-") == 36) |
| str = xstrdup(_("nil")); |
| else |
| str = xstrdup(_("unknown")); |
| break; |
| case 1: |
| str = xstrdup(_("time-based")); |
| break; |
| case 2: |
| str = xstrdup("DCE"); |
| break; |
| case 3: |
| str = xstrdup(_("name-based")); |
| break; |
| case 4: |
| str = xstrdup(_("random")); |
| break; |
| case 5: |
| str = xstrdup(_("sha1-based")); |
| break; |
| default: |
| str = xstrdup(_("unknown")); |
| } |
| break; |
| case COL_TIME: |
| if (invalid) { |
| str = xstrdup(_("invalid")); |
| break; |
| } |
| if (variant == UUID_VARIANT_DCE && type == 1) { |
| struct timeval tv; |
| char date_buf[ISO_BUFSIZ]; |
| |
| uuid_time(buf, &tv); |
| strtimeval_iso(&tv, ISO_TIMESTAMP_COMMA, |
| date_buf, sizeof(date_buf)); |
| str = xstrdup(date_buf); |
| } |
| break; |
| default: |
| abort(); |
| } |
| if (str && scols_line_refer_data(ln, i, str)) |
| errx(EXIT_FAILURE, _("failed to add output data")); |
| } |
| } |
| |
| static void print_output(struct control const *const ctrl, int argc, |
| char **argv) |
| { |
| struct libscols_table *tb; |
| size_t i; |
| |
| scols_init_debug(0); |
| tb = scols_new_table(); |
| if (!tb) |
| err(EXIT_FAILURE, _("failed to allocate output table")); |
| |
| if (ctrl->json) { |
| scols_table_enable_json(tb, 1); |
| scols_table_set_name(tb, "uuids"); |
| } |
| scols_table_enable_noheadings(tb, ctrl->no_headings); |
| scols_table_enable_raw(tb, ctrl->raw); |
| |
| for (i = 0; i < ncolumns; i++) { |
| const struct colinfo *col = get_column_info(i); |
| |
| if (!scols_table_new_column(tb, col->name, col->whint, |
| col->flags)) |
| err(EXIT_FAILURE, |
| _("failed to initialize output column")); |
| } |
| |
| for (i = 0; i < (size_t) argc; i++) |
| fill_table_row(tb, argv[i]); |
| |
| if (i == 0) { |
| char uuid[UUID_STR_LEN]; |
| |
| while (scanf(" %36[^ \t\n]%*c", uuid) && !feof(stdin)) |
| fill_table_row(tb, uuid); |
| } |
| scols_print_table(tb); |
| scols_unref_table(tb); |
| } |
| |
| int main(int argc, char **argv) |
| { |
| struct control ctrl = { 0 }; |
| char *outarg = NULL; |
| int c; |
| |
| static const struct option longopts[] = { |
| {"json", no_argument, NULL, 'J'}, |
| {"noheadings", no_argument, NULL, 'n'}, |
| {"output", required_argument, NULL, 'o'}, |
| {"raw", no_argument, NULL, 'r'}, |
| {"version", no_argument, NULL, 'V'}, |
| {"help", no_argument, NULL, 'h'}, |
| {NULL, 0, NULL, 0} |
| }; |
| static const ul_excl_t excl[] = { |
| {'J', 'r'}, |
| {0} |
| }; |
| int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT; |
| |
| setlocale(LC_ALL, ""); |
| bindtextdomain(PACKAGE, LOCALEDIR); |
| textdomain(PACKAGE); |
| atexit(close_stdout); |
| |
| while ((c = getopt_long(argc, argv, "Jno:rVh", longopts, NULL)) != -1) { |
| err_exclusive_options(c, longopts, excl, excl_st); |
| switch (c) { |
| case 'J': |
| ctrl.json = 1; |
| break; |
| case 'n': |
| ctrl.no_headings = 1; |
| break; |
| case 'o': |
| outarg = optarg; |
| break; |
| case 'r': |
| ctrl.raw = 1; |
| break; |
| case 'V': |
| printf(UTIL_LINUX_VERSION); |
| return EXIT_SUCCESS; |
| case 'h': |
| usage(); |
| default: |
| errtryhelp(EXIT_FAILURE); |
| } |
| } |
| argc -= optind; |
| argv += optind; |
| |
| columns[ncolumns++] = COL_UUID; |
| columns[ncolumns++] = COL_VARIANT; |
| columns[ncolumns++] = COL_TYPE; |
| columns[ncolumns++] = COL_TIME; |
| |
| if (outarg |
| && string_add_to_idarray(outarg, columns, ARRAY_SIZE(columns), |
| &ncolumns, column_name_to_id) < 0) |
| return EXIT_FAILURE; |
| |
| print_output(&ctrl, argc, argv); |
| |
| return EXIT_SUCCESS; |
| } |