2017-06-18 12:16:35 -05:00
|
|
|
/*
|
|
|
|
* 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>
|
2017-09-15 06:30:45 -05:00
|
|
|
#include <uuid.h>
|
2017-06-18 12:16:35 -05:00
|
|
|
|
|
|
|
#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);
|
2017-06-29 05:40:22 -05:00
|
|
|
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"));
|
2017-06-29 08:52:16 -05:00
|
|
|
printf(USAGE_HELP_OPTIONS(24));
|
2017-06-18 12:16:35 -05:00
|
|
|
|
|
|
|
fputs(USAGE_COLUMNS, stdout);
|
|
|
|
for (i = 0; i < ARRAY_SIZE(infos); i++)
|
|
|
|
fprintf(stdout, " %8s %s\n", infos[i].name, _(infos[i].help));
|
|
|
|
|
2017-06-29 08:52:16 -05:00
|
|
|
printf(USAGE_MAN_TAIL("uuidparse(1)"));
|
2017-06-18 12:16:35 -05:00
|
|
|
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;
|
2019-02-09 03:34:52 -06:00
|
|
|
int variant = -1, type = -1;
|
2017-06-18 12:16:35 -05:00
|
|
|
|
|
|
|
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:
|
2017-07-29 16:14:34 -05:00
|
|
|
if (strspn(uuid, "0-") == 36)
|
|
|
|
str = xstrdup(_("nil"));
|
|
|
|
else
|
|
|
|
str = xstrdup(_("unknown"));
|
2017-06-18 12:16:35 -05:00
|
|
|
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;
|
2017-10-14 19:37:11 -05:00
|
|
|
char date_buf[ISO_BUFSIZ];
|
2017-06-18 12:16:35 -05:00
|
|
|
|
|
|
|
uuid_time(buf, &tv);
|
2017-10-14 19:37:11 -05:00
|
|
|
strtimeval_iso(&tv, ISO_TIMESTAMP_COMMA,
|
|
|
|
date_buf, sizeof(date_buf));
|
2017-06-18 12:16:35 -05:00
|
|
|
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"));
|
|
|
|
|
2017-06-29 04:07:54 -05:00
|
|
|
if (ctrl->json) {
|
|
|
|
scols_table_enable_json(tb, 1);
|
|
|
|
scols_table_set_name(tb, "uuids");
|
|
|
|
}
|
2017-06-18 12:16:35 -05:00
|
|
|
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];
|
|
|
|
|
2017-09-15 06:30:45 -05:00
|
|
|
while (scanf(" %36[^ \t\n]%*c", uuid) && !feof(stdin))
|
2017-06-18 12:16:35 -05:00
|
|
|
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'},
|
2017-06-26 11:20:06 -05:00
|
|
|
{NULL, 0, NULL, 0}
|
2017-06-18 12:16:35 -05:00
|
|
|
};
|
|
|
|
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;
|
|
|
|
}
|