(root)/
util-linux-2.39/
misc-utils/
uuidparse.c
       1  /*
       2   * uuidparse.c --- Interpret uuid encoded information.  This program
       3   *	violates the UUID abstraction barrier by reaching into the
       4   *	guts of a UUID.
       5   *
       6   * Based on libuuid/src/uuid_time.c
       7   * Copyright (C) 1998, 1999 Theodore Ts'o.
       8   *
       9   * All alterations (C) 2017 Sami Kerola
      10   * The 3-Clause BSD License
      11   *
      12   * Redistribution and use in source and binary forms, with or without
      13   * modification, are permitted provided that the following conditions
      14   * are met:
      15   * 1. Redistributions of source code must retain the above copyright
      16   *    notice, and the entire permission notice in its entirety,
      17   *    including the disclaimer of warranties.
      18   * 2. Redistributions in binary form must reproduce the above copyright
      19   *    notice, this list of conditions and the following disclaimer in the
      20   *    documentation and/or other materials provided with the distribution.
      21   * 3. The name of the author may not be used to endorse or promote
      22   *    products derived from this software without specific prior
      23   *    written permission.
      24   *
      25   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
      26   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      27   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
      28   * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
      29   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      30   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
      31   * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
      32   * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
      33   * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      34   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
      35   * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
      36   * DAMAGE.
      37   */
      38  
      39  #include <assert.h>
      40  #include <getopt.h>
      41  #include <libsmartcols.h>
      42  #include <stdint.h>
      43  #include <stdio.h>
      44  #include <stdlib.h>
      45  #include <string.h>
      46  #include <time.h>
      47  #include <unistd.h>
      48  #include <uuid.h>
      49  
      50  #include "c.h"
      51  #include "closestream.h"
      52  #include "nls.h"
      53  #include "optutils.h"
      54  #include "strutils.h"
      55  #include "timeutils.h"
      56  #include "xalloc.h"
      57  
      58  /* column IDs */
      59  enum {
      60  	COL_UUID = 0,
      61  	COL_VARIANT,
      62  	COL_TYPE,
      63  	COL_TIME
      64  };
      65  
      66  /* column names */
      67  struct colinfo {
      68  	const char *name;	/* header */
      69  	double whint;		/* width hint (N < 1 is in percent of termwidth) */
      70  	int flags;		/* SCOLS_FL_* */
      71  	const char *help;
      72  };
      73  
      74  /* columns descriptions */
      75  static const struct colinfo infos[] = {
      76  	[COL_UUID]    = {"UUID",    UUID_STR_LEN, 0, N_("unique identifier")},
      77  	[COL_VARIANT] = {"VARIANT", 9,  0, N_("variant name")},
      78  	[COL_TYPE]    = {"TYPE",    10, 0, N_("type name")},
      79  	[COL_TIME]    = {"TIME",    31, 0, N_("timestamp")}
      80  };
      81  
      82  static int columns[ARRAY_SIZE(infos) * 2];
      83  static size_t ncolumns;
      84  
      85  struct control {
      86  	unsigned int
      87  		json:1,
      88  		no_headings:1,
      89  		raw:1;
      90  };
      91  
      92  static void __attribute__((__noreturn__)) usage(void)
      93  {
      94  	size_t i;
      95  
      96  	fputs(USAGE_HEADER, stdout);
      97  	fprintf(stdout, _(" %s [options] <uuid ...>\n"), program_invocation_short_name);
      98  
      99  	fputs(USAGE_OPTIONS, stdout);
     100  	puts(_(" -J, --json             use JSON output format"));
     101  	puts(_(" -n, --noheadings       don't print headings"));
     102  	puts(_(" -o, --output <list>    COLUMNS to display (see below)"));
     103  	puts(_(" -r, --raw              use the raw output format"));
     104  	printf(USAGE_HELP_OPTIONS(24));
     105  
     106  	fputs(USAGE_COLUMNS, stdout);
     107  	for (i = 0; i < ARRAY_SIZE(infos); i++)
     108  		fprintf(stdout, " %8s  %s\n", infos[i].name, _(infos[i].help));
     109  
     110  	printf(USAGE_MAN_TAIL("uuidparse(1)"));
     111  	exit(EXIT_SUCCESS);
     112  }
     113  
     114  static int column_name_to_id(const char *name, size_t namesz)
     115  {
     116  	size_t i;
     117  
     118  	assert(name);
     119  
     120  	for (i = 0; i < ARRAY_SIZE(infos); i++) {
     121  		const char *cn = infos[i].name;
     122  		if (!strncasecmp(name, cn, namesz) && !*(cn + namesz))
     123  			return i;
     124  	}
     125  	warnx(_("unknown column: %s"), name);
     126  	return -1;
     127  }
     128  
     129  static int get_column_id(size_t num)
     130  {
     131  	assert(num < ncolumns);
     132  	assert(columns[num] < (int)ARRAY_SIZE(infos));
     133  	return columns[num];
     134  }
     135  
     136  static const struct colinfo *get_column_info(int num)
     137  {
     138  	return &infos[get_column_id(num)];
     139  }
     140  
     141  static void fill_table_row(struct libscols_table *tb, char const *const uuid)
     142  {
     143  	static struct libscols_line *ln;
     144  	size_t i;
     145  	uuid_t buf;
     146  	int invalid = 0;
     147  	int variant = -1, type = -1;
     148  
     149  	assert(tb);
     150  	assert(uuid);
     151  
     152  	ln = scols_table_new_line(tb, NULL);
     153  	if (!ln)
     154  		errx(EXIT_FAILURE, _("failed to allocate output line"));
     155  
     156  	if (uuid_parse(uuid, buf))
     157  		invalid = 1;
     158  	else {
     159  		variant = uuid_variant(buf);
     160  		type = uuid_type(buf);
     161  	}
     162  
     163  	for (i = 0; i < ncolumns; i++) {
     164  		char *str = NULL;
     165  
     166  		switch (get_column_id(i)) {
     167  		case COL_UUID:
     168  			str = xstrdup(uuid);
     169  			break;
     170  		case COL_VARIANT:
     171  			if (invalid) {
     172  				str = xstrdup(_("invalid"));
     173  				break;
     174  			}
     175  			switch (variant) {
     176  			case UUID_VARIANT_NCS:
     177  				str = xstrdup("NCS");
     178  				break;
     179  			case UUID_VARIANT_DCE:
     180  				str = xstrdup("DCE");
     181  				break;
     182  			case UUID_VARIANT_MICROSOFT:
     183  				str = xstrdup("Microsoft");
     184  				break;
     185  			default:
     186  				str = xstrdup(_("other"));
     187  			}
     188  			break;
     189  		case COL_TYPE:
     190  			if (invalid) {
     191  				str = xstrdup(_("invalid"));
     192  				break;
     193  			}
     194  			switch (type) {
     195  			case UUID_TYPE_DCE_NIL:
     196  				if (uuid_is_null(buf))
     197  					str = xstrdup(_("nil"));
     198  				else
     199  					str = xstrdup(_("unknown"));
     200  				break;
     201  			case UUID_TYPE_DCE_TIME:
     202  				str = xstrdup(_("time-based"));
     203  				break;
     204  			case UUID_TYPE_DCE_SECURITY:
     205  				str = xstrdup("DCE");
     206  				break;
     207  			case UUID_TYPE_DCE_MD5:
     208  				str = xstrdup(_("name-based"));
     209  				break;
     210  			case UUID_TYPE_DCE_RANDOM:
     211  				str = xstrdup(_("random"));
     212  				break;
     213  			case UUID_TYPE_DCE_SHA1:
     214  				str = xstrdup(_("sha1-based"));
     215  				break;
     216  			default:
     217  				str = xstrdup(_("unknown"));
     218  			}
     219  			break;
     220  		case COL_TIME:
     221  			if (invalid) {
     222  				str = xstrdup(_("invalid"));
     223  				break;
     224  			}
     225  			if (variant == UUID_VARIANT_DCE && type == UUID_TYPE_DCE_TIME) {
     226  				struct timeval tv;
     227  				char date_buf[ISO_BUFSIZ];
     228  
     229  				uuid_time(buf, &tv);
     230  				strtimeval_iso(&tv, ISO_TIMESTAMP_COMMA,
     231  					       date_buf, sizeof(date_buf));
     232  				str = xstrdup(date_buf);
     233  			}
     234  			break;
     235  		default:
     236  			abort();
     237  		}
     238  		if (str && scols_line_refer_data(ln, i, str))
     239  			errx(EXIT_FAILURE, _("failed to add output data"));
     240  	}
     241  }
     242  
     243  static void print_output(struct control const *const ctrl, int argc,
     244  			 char **argv)
     245  {
     246  	struct libscols_table *tb;
     247  	size_t i;
     248  
     249  	scols_init_debug(0);
     250  	tb = scols_new_table();
     251  	if (!tb)
     252  		err(EXIT_FAILURE, _("failed to allocate output table"));
     253  
     254  	if (ctrl->json) {
     255  		scols_table_enable_json(tb, 1);
     256  		scols_table_set_name(tb, "uuids");
     257  	}
     258  	scols_table_enable_noheadings(tb, ctrl->no_headings);
     259  	scols_table_enable_raw(tb, ctrl->raw);
     260  
     261  	for (i = 0; i < ncolumns; i++) {
     262  		const struct colinfo *col = get_column_info(i);
     263  
     264  		if (!scols_table_new_column(tb, col->name, col->whint,
     265  					    col->flags))
     266  			err(EXIT_FAILURE,
     267  			    _("failed to initialize output column"));
     268  	}
     269  
     270  	for (i = 0; i < (size_t) argc; i++)
     271  		fill_table_row(tb, argv[i]);
     272  
     273  	if (i == 0) {
     274  		char uuid[UUID_STR_LEN];
     275  
     276  		while (scanf(" %36[^ \t\n]%*c", uuid) && !feof(stdin))
     277  			fill_table_row(tb, uuid);
     278  	}
     279  	scols_print_table(tb);
     280  	scols_unref_table(tb);
     281  }
     282  
     283  int main(int argc, char **argv)
     284  {
     285  	struct control ctrl = { 0 };
     286  	char *outarg = NULL;
     287  	int c;
     288  
     289  	static const struct option longopts[] = {
     290  		{"json",       no_argument,       NULL, 'J'},
     291  		{"noheadings", no_argument,       NULL, 'n'},
     292  		{"output",     required_argument, NULL, 'o'},
     293  		{"raw",        no_argument,       NULL, 'r'},
     294  		{"version",    no_argument,       NULL, 'V'},
     295  		{"help",       no_argument,       NULL, 'h'},
     296  		{NULL, 0, NULL, 0}
     297  	};
     298  	static const ul_excl_t excl[] = {
     299  		{'J', 'r'},
     300  		{0}
     301  	};
     302  	int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
     303  
     304  	setlocale(LC_ALL, "");
     305  	bindtextdomain(PACKAGE, LOCALEDIR);
     306  	textdomain(PACKAGE);
     307  	close_stdout_atexit();
     308  
     309  	while ((c = getopt_long(argc, argv, "Jno:rVh", longopts, NULL)) != -1) {
     310  		err_exclusive_options(c, longopts, excl, excl_st);
     311  		switch (c) {
     312  		case 'J':
     313  			ctrl.json = 1;
     314  			break;
     315  		case 'n':
     316  			ctrl.no_headings = 1;
     317  			break;
     318  		case 'o':
     319  			outarg = optarg;
     320  			break;
     321  		case 'r':
     322  			ctrl.raw = 1;
     323  			break;
     324  
     325  		case 'V':
     326  			print_version(EXIT_SUCCESS);
     327  		case 'h':
     328  			usage();
     329  		default:
     330  			errtryhelp(EXIT_FAILURE);
     331  		}
     332  	}
     333  	argc -= optind;
     334  	argv += optind;
     335  
     336  	columns[ncolumns++] = COL_UUID;
     337  	columns[ncolumns++] = COL_VARIANT;
     338  	columns[ncolumns++] = COL_TYPE;
     339  	columns[ncolumns++] = COL_TIME;
     340  
     341  	if (outarg
     342  	    && string_add_to_idarray(outarg, columns, ARRAY_SIZE(columns),
     343  				     &ncolumns, column_name_to_id) < 0)
     344  		return EXIT_FAILURE;
     345  
     346  	print_output(&ctrl, argc, argv);
     347  
     348  	return EXIT_SUCCESS;
     349  }