summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSami Kerola2017-06-18 19:16:35 +0200
committerKarel Zak2017-06-26 14:46:35 +0200
commit83893f26789d4ffe11146a7c0ee9d34a92a0aaf7 (patch)
tree230e18f58443edabcd9314cc0ec990c514b5b86a
parentmisc: consolidate usage() "Available columns" (diff)
downloadkernel-qcow2-util-linux-83893f26789d4ffe11146a7c0ee9d34a92a0aaf7.tar.gz
kernel-qcow2-util-linux-83893f26789d4ffe11146a7c0ee9d34a92a0aaf7.tar.xz
kernel-qcow2-util-linux-83893f26789d4ffe11146a7c0ee9d34a92a0aaf7.zip
uuidparse: add new command
This command will analyze and print information about UUID's. The command is based on libuuid/src/uuid_time.c but modified to use libsmartcol. [kzak@redhat.com: - minor coding style changes] Reference: http://marc.info/?l=util-linux-ng&m=149735980715600&w=2 Signed-off-by: Sami Kerola <kerolasa@iki.fi> Signed-off-by: Karel Zak <kzak@redhat.com>
-rw-r--r--.gitignore1
-rw-r--r--configure.ac5
-rw-r--r--misc-utils/Makemodule.am8
-rw-r--r--misc-utils/uuidparse.169
-rw-r--r--misc-utils/uuidparse.c354
-rw-r--r--tests/commands.sh1
-rw-r--r--tests/expected/uuid/uuidparse33
-rwxr-xr-xtests/ts/uuid/uuidparse63
8 files changed, 534 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index 38afedbab..7a6c4afc2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -165,6 +165,7 @@ ylwrap
/utmpdump
/uuidd
/uuidgen
+/uuidparse
/vipw
/wall
/wdctl
diff --git a/configure.ac b/configure.ac
index 53d25b8ab..34980ab40 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1146,6 +1146,11 @@ UL_BUILD_INIT([uuidgen], [check])
UL_REQUIRES_BUILD([uuidgen], [libuuid])
AM_CONDITIONAL([BUILD_UUIDGEN], [test "x$build_uuidgen" = xyes])
+UL_BUILD_INIT([uuidparse], [check])
+UL_REQUIRES_BUILD([uuidparse], [libuuid])
+UL_REQUIRES_BUILD([uuidparse], [libsmartcols])
+AM_CONDITIONAL([BUILD_UUIDPARSE], [test "x$build_uuidparse" = xyes])
+
UL_BUILD_INIT([blkid], [check])
UL_REQUIRES_BUILD([blkid], [libblkid])
AM_CONDITIONAL([BUILD_BLKID], [test "x$build_blkid" = xyes])
diff --git a/misc-utils/Makemodule.am b/misc-utils/Makemodule.am
index f28261c8b..87ea9ff2a 100644
--- a/misc-utils/Makemodule.am
+++ b/misc-utils/Makemodule.am
@@ -88,6 +88,14 @@ uuidgen_LDADD = $(LDADD) libuuid.la
uuidgen_CFLAGS = $(AM_CFLAGS) -I$(ul_libuuid_incdir)
endif
+if BUILD_UUIDPARSE
+usrbin_exec_PROGRAMS += uuidparse
+dist_man_MANS += misc-utils/uuidparse.1
+uuidparse_SOURCES = misc-utils/uuidparse.c
+uuidparse_LDADD = $(LDADD) libcommon.la libuuid.la libsmartcols.la
+uuidparse_CFLAGS = $(AM_CFLAGS) -I$(ul_libuuid_incdir) -I$(ul_libsmartcols_incdir)
+endif
+
if BUILD_UUIDD
usrsbin_exec_PROGRAMS += uuidd
dist_man_MANS += misc-utils/uuidd.8
diff --git a/misc-utils/uuidparse.1 b/misc-utils/uuidparse.1
new file mode 100644
index 000000000..9afa6b071
--- /dev/null
+++ b/misc-utils/uuidparse.1
@@ -0,0 +1,69 @@
+.\" Copyright (c) 2017 Sami Kerola
+.\" The 3-Clause BSD License
+.TH UUIDPARSE "1" "2017-06-18" "util-linux" "User Commands"
+.SH NAME
+uuidparse \- an utility to parse unique identifiers
+.SH SYNOPSIS
+.B uuidparse
+[options]
+.I uuid
+.SH DESCRIPTION
+This command will parse unique identifier inputs from either command line
+arguments or standard input. The inputs are white-space separated.
+.SH OUTPUT
+.SS Variants
+.TS
+tab(:);
+left l l.
+NCS:Network Computing System identifier. These were the original UUIDs.
+DCE:The Open Software Foundation's (OSF) Distributed Computing Environment UUIDs.
+Microsoft:Microsoft Windows platform globally unique identifier (GUID).
+other:Unknown variant. Usually invalid input data.
+.TE
+.SS Types
+.TS
+tab(:);
+left l l.
+nil:Special type for zero in type file.
+time-based:The DCE time based.
+DCE:The DCE time and MAC Address.
+name-based:RFC 4122 md5sum hash.
+random:RFC 4122 random.
+sha1-based:RFC 4122 sha-1 hash.
+unknown:Unknown type. Usually invalid input data.
+.TE
+.SH OPTIONS
+.TP
+\fB\-J\fR, \fB\-\-json\fR
+Use JSON output format.
+.TP
+\fB\-n\fR, \fB\-\-noheadings\fR
+Do not print a header line.
+.TP
+\fB\-o\fR, \fB\-\-output\fR
+Specify which output columns to print. Use \-\-help to get a list of all
+supported columns.
+.TP
+\fB\-r\fR, \fB\-\-raw\fR
+Use the raw output format.
+.TP
+\fB\-V\fR, \fB\-\-version\fR
+Display version information and exit.
+.TP
+\fB\-h\fR, \fB\-\-help\fR
+Display help text and exit.
+.SH AUTHORS
+.MT kerolasa@iki.fi
+Sami Kerola
+.ME
+.SH "SEE ALSO"
+.BR uuidgen (1),
+.BR libuuid (3),
+.UR https://\:tools.ietf.org\:/html\:/rfc4122
+RFC 4122
+.UE
+.SH AVAILABILITY
+The example command is part of the util-linux package and is available from
+.UR https://\:www.kernel.org\:/pub\:/linux\:/utils\:/util-linux/
+Linux Kernel Archive
+.UE .
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;
+}
diff --git a/tests/commands.sh b/tests/commands.sh
index f655a6829..2d9e3b8ea 100644
--- a/tests/commands.sh
+++ b/tests/commands.sh
@@ -93,6 +93,7 @@ TS_CMD_UMOUNT=${TS_CMD_UMOUNT:-"$top_builddir/umount"}
TS_CMD_UTMPDUMP=${TS_CMD_UTMPDUMP-"$top_builddir/utmpdump"}
TS_CMD_UUIDD=${TS_CMD_UUIDD-"$top_builddir/uuidd"}
TS_CMD_UUIDGEN=${TS_CMD_UUIDGEN-"$top_builddir/uuidgen"}
+TS_CMD_UUIDPARSE=${TS_CMD_UUIDPARSE-"$top_builddir/uuidparse"}
TS_CMD_WHEREIS=${TS_CMD_WHEREIS-"$top_builddir/whereis"}
TS_CMD_WIPEFS=${TS_CMD_WIPEFS-"$top_builddir/wipefs"}
TS_CMD_CHRT=${TS_CMD_CHRT-"$top_builddir/chrt"}
diff --git a/tests/expected/uuid/uuidparse b/tests/expected/uuid/uuidparse
new file mode 100644
index 000000000..cda67e4a3
--- /dev/null
+++ b/tests/expected/uuid/uuidparse
@@ -0,0 +1,33 @@
+UUID VARIANT TYPE TIME
+00000000-0000-0000-0000-000000000000 NCS nil
+00000000-0000-1000-0000-000000000000 NCS time-based
+00000000-0000-2000-0000-000000000000 NCS DCE
+00000000-0000-3000-0000-000000000000 NCS name-based
+00000000-0000-4000-0000-000000000000 NCS random
+00000000-0000-5000-0000-000000000000 NCS sha1-based
+00000000-0000-6000-0000-000000000000 NCS unknown
+00000000-0000-0000-8000-000000000000 DCE nil
+00000000-0000-1000-8000-000000000000 DCE time-based 60038-03-11 05:36:10,955161+0000
+00000000-0000-2000-8000-000000000000 DCE DCE
+00000000-0000-3000-8000-000000000000 DCE name-based
+00000000-0000-4000-8000-000000000000 DCE random
+00000000-0000-5000-8000-000000000000 DCE sha1-based
+00000000-0000-6000-8000-000000000000 DCE unknown
+00000000-0000-0000-d000-000000000000 Microsoft nil
+00000000-0000-1000-d000-000000000000 Microsoft time-based
+00000000-0000-2000-d000-000000000000 Microsoft DCE
+00000000-0000-3000-d000-000000000000 Microsoft name-based
+00000000-0000-4000-d000-000000000000 Microsoft random
+00000000-0000-5000-d000-000000000000 Microsoft sha1-based
+00000000-0000-6000-d000-000000000000 Microsoft unknown
+00000000-0000-0000-f000-000000000000 other nil
+00000000-0000-1000-f000-000000000000 other time-based
+00000000-0000-2000-f000-000000000000 other DCE
+00000000-0000-3000-f000-000000000000 other name-based
+00000000-0000-4000-f000-000000000000 other random
+00000000-0000-5000-f000-000000000000 other sha1-based
+00000000-0000-6000-f000-000000000000 other unknown
+9b274c46-544a-11e7-a972-00037f500001 DCE time-based 2017-06-18 17:21:46,544647+0000
+ffffffff-ffff-1fff-8fff-ffffffffffff DCE time-based 5236-03-31 21:21:00,684697+0000
+invalid-input invalid invalid invalid
+return value: 0
diff --git a/tests/ts/uuid/uuidparse b/tests/ts/uuid/uuidparse
new file mode 100755
index 000000000..229994f6f
--- /dev/null
+++ b/tests/ts/uuid/uuidparse
@@ -0,0 +1,63 @@
+#!/bin/bash
+
+# This file is part of util-linux.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+TS_TOPDIR="${0%/*}/../.."
+TS_DESC="uuidparse"
+export TZ=GMT
+
+. $TS_TOPDIR/functions.sh
+ts_init "$*"
+
+ts_check_test_command "$TS_CMD_UUIDPARSE"
+
+echo '00000000-0000-0000-0000-000000000000
+
+00000000-0000-1000-0000-000000000000
+00000000-0000-2000-0000-000000000000
+00000000-0000-3000-0000-000000000000
+00000000-0000-4000-0000-000000000000
+00000000-0000-5000-0000-000000000000
+00000000-0000-6000-0000-000000000000
+
+00000000-0000-0000-8000-000000000000
+00000000-0000-1000-8000-000000000000
+00000000-0000-2000-8000-000000000000
+00000000-0000-3000-8000-000000000000
+00000000-0000-4000-8000-000000000000
+00000000-0000-5000-8000-000000000000
+00000000-0000-6000-8000-000000000000
+
+00000000-0000-0000-d000-000000000000
+00000000-0000-1000-d000-000000000000
+00000000-0000-2000-d000-000000000000
+00000000-0000-3000-d000-000000000000
+00000000-0000-4000-d000-000000000000
+00000000-0000-5000-d000-000000000000
+00000000-0000-6000-d000-000000000000
+
+00000000-0000-0000-f000-000000000000
+00000000-0000-1000-f000-000000000000
+00000000-0000-2000-f000-000000000000
+00000000-0000-3000-f000-000000000000
+00000000-0000-4000-f000-000000000000
+00000000-0000-5000-f000-000000000000
+00000000-0000-6000-f000-000000000000
+
+9b274c46-544a-11e7-a972-00037f500001
+ffffffff-ffff-1fff-8fff-ffffffffffff
+
+invalid-input' | $TS_CMD_UUIDPARSE 1>$TS_OUTPUT 2>&1
+echo "return value: $?" >> $TS_OUTPUT
+
+ts_finalize