summaryrefslogtreecommitdiffstats
path: root/misc-utils/uuidparse.c
diff options
context:
space:
mode:
Diffstat (limited to 'misc-utils/uuidparse.c')
-rw-r--r--misc-utils/uuidparse.c354
1 files changed, 354 insertions, 0 deletions
diff --git a/misc-utils/uuidparse.c b/misc-utils/uuidparse.c
new file mode 100644
index 000000000..0938b8559
--- /dev/null
+++ b/misc-utils/uuidparse.c
@@ -0,0 +1,354 @@
+/*
+ * 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 "c.h"
+#include "closestream.h"
+#include "nls.h"
+#include "optutils.h"
+#include "strutils.h"
+#include "timeutils.h"
+#include "uuid.h"
+#include "xalloc.h"
+
+#define UUID_STR_LEN 37
+
+/* 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);
+ fputs(_(" -J, --json use JSON output format\n"), stdout);
+ fputs(_(" -n, --noheadings don't print headings\n"), stdout);
+ fputs(_(" -o, --output <list> define which output columns to use\n"), stdout);
+ fputs(_(" -r, --raw use the raw output format\n"), stdout);
+
+ fputs(USAGE_SEPARATOR, stdout);
+ fputs(USAGE_HELP, stdout);
+ fputs(USAGE_VERSION, stdout);
+
+ fputs(USAGE_COLUMNS, stdout);
+ for (i = 0; i < ARRAY_SIZE(infos); i++)
+ fprintf(stdout, " %8s %s\n", infos[i].name, _(infos[i].help));
+
+ fprintf(stdout, 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:
+ str = xstrdup(_("nil"));
+ 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_8601_BUFSIZ + 4];
+
+ uuid_time(buf, &tv);
+ strtimeval_iso(&tv,
+ ISO_8601_DATE |
+ ISO_8601_TIME |
+ ISO_8601_COMMAUSEC |
+ ISO_8601_TIMEZONE |
+ ISO_8601_SPACE,
+ 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"));
+
+ scols_table_enable_json(tb, ctrl->json);
+ 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(" %" stringify_value(UUID_STR_LEN)
+ "[^ \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'},
+ };
+ 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;
+}