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>
This commit is contained in:
Sami Kerola 2017-06-18 17:16:35 +00:00 committed by Karel Zak
parent c3a4cfc579
commit 83893f2678
8 changed files with 534 additions and 0 deletions

1
.gitignore vendored
View File

@ -165,6 +165,7 @@ ylwrap
/utmpdump
/uuidd
/uuidgen
/uuidparse
/vipw
/wall
/wdctl

View File

@ -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])

View File

@ -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

69
misc-utils/uuidparse.1 Normal file
View File

@ -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 .

354
misc-utils/uuidparse.c Normal file
View File

@ -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;
}

View File

@ -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"}

View File

@ -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

63
tests/ts/uuid/uuidparse Executable file
View File

@ -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