]> git.ipfire.org Git - thirdparty/util-linux.git/blob - misc-utils/uuidparse.c
Merge branch 'master' of https://github.com/RAOF/util-linux
[thirdparty/util-linux.git] / 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
49 #include "c.h"
50 #include "closestream.h"
51 #include "nls.h"
52 #include "optutils.h"
53 #include "strutils.h"
54 #include "timeutils.h"
55 #include "uuid.h"
56 #include "xalloc.h"
57
58 #define UUID_STR_LEN 37
59
60 /* column IDs */
61 enum {
62 COL_UUID = 0,
63 COL_VARIANT,
64 COL_TYPE,
65 COL_TIME
66 };
67
68 /* column names */
69 struct colinfo {
70 const char *name; /* header */
71 double whint; /* width hint (N < 1 is in percent of termwidth) */
72 int flags; /* SCOLS_FL_* */
73 const char *help;
74 };
75
76 /* columns descriptions */
77 static const struct colinfo infos[] = {
78 [COL_UUID] = {"UUID", UUID_STR_LEN, 0, N_("unique identifier")},
79 [COL_VARIANT] = {"VARIANT", 9, 0, N_("variant name")},
80 [COL_TYPE] = {"TYPE", 10, 0, N_("type name")},
81 [COL_TIME] = {"TIME", 31, 0, N_("timestamp")}
82 };
83
84 static int columns[ARRAY_SIZE(infos) * 2];
85 static size_t ncolumns;
86
87 struct control {
88 unsigned int
89 json:1,
90 no_headings:1,
91 raw:1;
92 };
93
94 static void __attribute__((__noreturn__)) usage(void)
95 {
96 size_t i;
97
98 fputs(USAGE_HEADER, stdout);
99 fprintf(stdout, _(" %s [options] <uuid ...>\n"), program_invocation_short_name);
100
101 fputs(USAGE_OPTIONS, stdout);
102 puts(_(" -J, --json use JSON output format"));
103 puts(_(" -n, --noheadings don't print headings"));
104 puts(_(" -o, --output <list> COLUMNS to display (see below)"));
105 puts(_(" -r, --raw use the raw output format"));
106 printf(USAGE_HELP_OPTIONS(24));
107
108 fputs(USAGE_COLUMNS, stdout);
109 for (i = 0; i < ARRAY_SIZE(infos); i++)
110 fprintf(stdout, " %8s %s\n", infos[i].name, _(infos[i].help));
111
112 printf(USAGE_MAN_TAIL("uuidparse(1)"));
113 exit(EXIT_SUCCESS);
114 }
115
116 static int column_name_to_id(const char *name, size_t namesz)
117 {
118 size_t i;
119
120 assert(name);
121
122 for (i = 0; i < ARRAY_SIZE(infos); i++) {
123 const char *cn = infos[i].name;
124 if (!strncasecmp(name, cn, namesz) && !*(cn + namesz))
125 return i;
126 }
127 warnx(_("unknown column: %s"), name);
128 return -1;
129 }
130
131 static int get_column_id(size_t num)
132 {
133 assert(num < ncolumns);
134 assert(columns[num] < (int)ARRAY_SIZE(infos));
135 return columns[num];
136 }
137
138 static const struct colinfo *get_column_info(int num)
139 {
140 return &infos[get_column_id(num)];
141 }
142
143 static void fill_table_row(struct libscols_table *tb, char const *const uuid)
144 {
145 static struct libscols_line *ln;
146 size_t i;
147 uuid_t buf;
148 int invalid = 0;
149 int variant, type;
150
151 assert(tb);
152 assert(uuid);
153
154 ln = scols_table_new_line(tb, NULL);
155 if (!ln)
156 errx(EXIT_FAILURE, _("failed to allocate output line"));
157
158 if (uuid_parse(uuid, buf))
159 invalid = 1;
160 else {
161 variant = uuid_variant(buf);
162 type = uuid_type(buf);
163 }
164
165 for (i = 0; i < ncolumns; i++) {
166 char *str = NULL;
167
168 switch (get_column_id(i)) {
169 case COL_UUID:
170 str = xstrdup(uuid);
171 break;
172 case COL_VARIANT:
173 if (invalid) {
174 str = xstrdup(_("invalid"));
175 break;
176 }
177 switch (variant) {
178 case UUID_VARIANT_NCS:
179 str = xstrdup("NCS");
180 break;
181 case UUID_VARIANT_DCE:
182 str = xstrdup("DCE");
183 break;
184 case UUID_VARIANT_MICROSOFT:
185 str = xstrdup("Microsoft");
186 break;
187 default:
188 str = xstrdup(_("other"));
189 }
190 break;
191 case COL_TYPE:
192 if (invalid) {
193 str = xstrdup(_("invalid"));
194 break;
195 }
196 switch (type) {
197 case 0:
198 if (strspn(uuid, "0-") == 36)
199 str = xstrdup(_("nil"));
200 else
201 str = xstrdup(_("unknown"));
202 break;
203 case 1:
204 str = xstrdup(_("time-based"));
205 break;
206 case 2:
207 str = xstrdup("DCE");
208 break;
209 case 3:
210 str = xstrdup(_("name-based"));
211 break;
212 case 4:
213 str = xstrdup(_("random"));
214 break;
215 case 5:
216 str = xstrdup(_("sha1-based"));
217 break;
218 default:
219 str = xstrdup(_("unknown"));
220 }
221 break;
222 case COL_TIME:
223 if (invalid) {
224 str = xstrdup(_("invalid"));
225 break;
226 }
227 if (variant == UUID_VARIANT_DCE && type == 1) {
228 struct timeval tv;
229 char date_buf[ISO_8601_BUFSIZ + 4];
230
231 uuid_time(buf, &tv);
232 strtimeval_iso(&tv,
233 ISO_8601_DATE |
234 ISO_8601_TIME |
235 ISO_8601_COMMAUSEC |
236 ISO_8601_TIMEZONE |
237 ISO_8601_SPACE,
238 date_buf,
239 sizeof(date_buf));
240 str = xstrdup(date_buf);
241 }
242 break;
243 default:
244 abort();
245 }
246 if (str && scols_line_refer_data(ln, i, str))
247 errx(EXIT_FAILURE, _("failed to add output data"));
248 }
249 }
250
251 static void print_output(struct control const *const ctrl, int argc,
252 char **argv)
253 {
254 struct libscols_table *tb;
255 size_t i;
256
257 scols_init_debug(0);
258 tb = scols_new_table();
259 if (!tb)
260 err(EXIT_FAILURE, _("failed to allocate output table"));
261
262 if (ctrl->json) {
263 scols_table_enable_json(tb, 1);
264 scols_table_set_name(tb, "uuids");
265 }
266 scols_table_enable_noheadings(tb, ctrl->no_headings);
267 scols_table_enable_raw(tb, ctrl->raw);
268
269 for (i = 0; i < ncolumns; i++) {
270 const struct colinfo *col = get_column_info(i);
271
272 if (!scols_table_new_column(tb, col->name, col->whint,
273 col->flags))
274 err(EXIT_FAILURE,
275 _("failed to initialize output column"));
276 }
277
278 for (i = 0; i < (size_t) argc; i++)
279 fill_table_row(tb, argv[i]);
280
281 if (i == 0) {
282 char uuid[UUID_STR_LEN];
283
284 while (scanf(" %" stringify_value(UUID_STR_LEN)
285 "[^ \t\n]%*c", uuid) && !feof(stdin))
286 fill_table_row(tb, uuid);
287 }
288 scols_print_table(tb);
289 scols_unref_table(tb);
290 }
291
292 int main(int argc, char **argv)
293 {
294 struct control ctrl = { 0 };
295 char *outarg = NULL;
296 int c;
297
298 static const struct option longopts[] = {
299 {"json", no_argument, NULL, 'J'},
300 {"noheadings", no_argument, NULL, 'n'},
301 {"output", required_argument, NULL, 'o'},
302 {"raw", no_argument, NULL, 'r'},
303 {"version", no_argument, NULL, 'V'},
304 {"help", no_argument, NULL, 'h'},
305 {NULL, 0, NULL, 0}
306 };
307 static const ul_excl_t excl[] = {
308 {'J', 'r'},
309 {0}
310 };
311 int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
312
313 setlocale(LC_ALL, "");
314 bindtextdomain(PACKAGE, LOCALEDIR);
315 textdomain(PACKAGE);
316 atexit(close_stdout);
317
318 while ((c = getopt_long(argc, argv, "Jno:rVh", longopts, NULL)) != -1) {
319 err_exclusive_options(c, longopts, excl, excl_st);
320 switch (c) {
321 case 'J':
322 ctrl.json = 1;
323 break;
324 case 'n':
325 ctrl.no_headings = 1;
326 break;
327 case 'o':
328 outarg = optarg;
329 break;
330 case 'r':
331 ctrl.raw = 1;
332 break;
333 case 'V':
334 printf(UTIL_LINUX_VERSION);
335 return EXIT_SUCCESS;
336 case 'h':
337 usage();
338 default:
339 errtryhelp(EXIT_FAILURE);
340 }
341 }
342 argc -= optind;
343 argv += optind;
344
345 columns[ncolumns++] = COL_UUID;
346 columns[ncolumns++] = COL_VARIANT;
347 columns[ncolumns++] = COL_TYPE;
348 columns[ncolumns++] = COL_TIME;
349
350 if (outarg
351 && string_add_to_idarray(outarg, columns, ARRAY_SIZE(columns),
352 &ncolumns, column_name_to_id) < 0)
353 return EXIT_FAILURE;
354
355 print_output(&ctrl, argc, argv);
356
357 return EXIT_SUCCESS;
358 }