diff options
Diffstat (limited to 'misc-utils/uuidparse.c')
-rw-r--r-- | misc-utils/uuidparse.c | 349 |
1 files changed, 349 insertions, 0 deletions
diff --git a/misc-utils/uuidparse.c b/misc-utils/uuidparse.c new file mode 100644 index 0000000..2dc6dfb --- /dev/null +++ b/misc-utils/uuidparse.c @@ -0,0 +1,349 @@ +/* + * 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 = -1, type = -1; + + 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 UUID_TYPE_DCE_NIL: + if (uuid_is_null(buf)) + str = xstrdup(_("nil")); + else + str = xstrdup(_("unknown")); + break; + case UUID_TYPE_DCE_TIME: + str = xstrdup(_("time-based")); + break; + case UUID_TYPE_DCE_SECURITY: + str = xstrdup("DCE"); + break; + case UUID_TYPE_DCE_MD5: + str = xstrdup(_("name-based")); + break; + case UUID_TYPE_DCE_RANDOM: + str = xstrdup(_("random")); + break; + case UUID_TYPE_DCE_SHA1: + 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 == UUID_TYPE_DCE_TIME) { + 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); + close_stdout_atexit(); + + 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': + print_version(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; +} |