summaryrefslogtreecommitdiffstats
path: root/misc-utils/uuidparse.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--misc-utils/uuidparse.c349
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;
+}