]> git.ipfire.org Git - thirdparty/util-linux.git/blob - misc-utils/uuidparse.c
textual: harmonize the messages for invalid count and timeout values
[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 #include <uuid.h>
49
50 #include "c.h"
51 #include "cctype.h"
52 #include "closestream.h"
53 #include "nls.h"
54 #include "optutils.h"
55 #include "strutils.h"
56 #include "timeutils.h"
57 #include "xalloc.h"
58
59 /* column IDs */
60 enum {
61 COL_UUID = 0,
62 COL_VARIANT,
63 COL_TYPE,
64 COL_TIME
65 };
66
67 /* column names */
68 struct colinfo {
69 const char *name; /* header */
70 double whint; /* width hint (N < 1 is in percent of termwidth) */
71 int flags; /* SCOLS_FL_* */
72 const char *help;
73 };
74
75 /* columns descriptions */
76 static const struct colinfo infos[] = {
77 [COL_UUID] = {"UUID", UUID_STR_LEN, 0, N_("unique identifier")},
78 [COL_VARIANT] = {"VARIANT", 9, 0, N_("variant name")},
79 [COL_TYPE] = {"TYPE", 10, 0, N_("type name")},
80 [COL_TIME] = {"TIME", 31, 0, N_("timestamp")}
81 };
82
83 static int columns[ARRAY_SIZE(infos) * 2];
84 static size_t ncolumns;
85
86 struct control {
87 bool json,
88 no_headings,
89 raw;
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 fputsln(_(" -J, --json use JSON output format"), stdout);
101 fputsln(_(" -n, --noheadings don't print headings"), stdout);
102 fputsln(_(" -o, --output <list> COLUMNS to display (see below)"), stdout);
103 fputsln(_(" -r, --raw use the raw output format"), stdout);
104 fprintf(stdout, 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 fprintf(stdout, 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 (!c_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 if (variant != UUID_VARIANT_DCE)
195 break;
196 switch (type) {
197 case UUID_TYPE_DCE_NIL:
198 if (uuid_is_null(buf))
199 str = xstrdup(_("nil"));
200 else
201 str = xstrdup(_("unknown"));
202 break;
203 case UUID_TYPE_DCE_TIME:
204 str = xstrdup(_("time-based"));
205 break;
206 case UUID_TYPE_DCE_TIME_V6:
207 str = xstrdup(_("time-v6"));
208 break;
209 case UUID_TYPE_DCE_TIME_V7:
210 str = xstrdup(_("time-v7"));
211 break;
212 case UUID_TYPE_DCE_SECURITY:
213 str = xstrdup("DCE");
214 break;
215 case UUID_TYPE_DCE_MD5:
216 str = xstrdup(_("name-based"));
217 break;
218 case UUID_TYPE_DCE_RANDOM:
219 str = xstrdup(_("random"));
220 break;
221 case UUID_TYPE_DCE_SHA1:
222 str = xstrdup(_("sha1-based"));
223 break;
224 case UUID_TYPE_DCE_VENDOR:
225 str = xstrdup(_("vendor"));
226 break;
227 default:
228 str = xstrdup(_("unknown"));
229 }
230 break;
231 case COL_TIME:
232 if (invalid) {
233 str = xstrdup(_("invalid"));
234 break;
235 }
236 if (variant != UUID_VARIANT_DCE)
237 break;
238 if (type == UUID_TYPE_DCE_TIME ||
239 type == UUID_TYPE_DCE_TIME_V6 ||
240 type == UUID_TYPE_DCE_TIME_V7) {
241 struct timeval tv;
242 char date_buf[ISO_BUFSIZ];
243
244 uuid_time(buf, &tv);
245 strtimeval_iso(&tv, ISO_TIMESTAMP_COMMA,
246 date_buf, sizeof(date_buf));
247 str = xstrdup(date_buf);
248 }
249 break;
250 default:
251 abort();
252 }
253 if (str && scols_line_refer_data(ln, i, str))
254 errx(EXIT_FAILURE, _("failed to add output data"));
255 }
256 }
257
258 static void print_output(struct control const *const ctrl, int argc,
259 char **argv)
260 {
261 struct libscols_table *tb;
262 size_t i;
263
264 scols_init_debug(0);
265 tb = scols_new_table();
266 if (!tb)
267 err(EXIT_FAILURE, _("failed to allocate output table"));
268
269 if (ctrl->json) {
270 scols_table_enable_json(tb, 1);
271 scols_table_set_name(tb, "uuids");
272 }
273 scols_table_enable_noheadings(tb, ctrl->no_headings);
274 scols_table_enable_raw(tb, ctrl->raw);
275
276 for (i = 0; i < ncolumns; i++) {
277 const struct colinfo *col = get_column_info(i);
278
279 if (!scols_table_new_column(tb, col->name, col->whint,
280 col->flags))
281 err(EXIT_FAILURE,
282 _("failed to initialize output column"));
283 }
284
285 for (i = 0; i < (size_t) argc; i++)
286 fill_table_row(tb, argv[i]);
287
288 if (i == 0) {
289 char uuid[UUID_STR_LEN];
290
291 while (scanf(" %36[^ \t\n]%*c", uuid) && !feof(stdin))
292 fill_table_row(tb, uuid);
293 }
294 scols_print_table(tb);
295 scols_unref_table(tb);
296 }
297
298 int main(int argc, char **argv)
299 {
300 struct control ctrl = { 0 };
301 char *outarg = NULL;
302 int c;
303
304 static const struct option longopts[] = {
305 {"json", no_argument, NULL, 'J'},
306 {"noheadings", no_argument, NULL, 'n'},
307 {"output", required_argument, NULL, 'o'},
308 {"raw", no_argument, NULL, 'r'},
309 {"version", no_argument, NULL, 'V'},
310 {"help", no_argument, NULL, 'h'},
311 {NULL, 0, NULL, 0}
312 };
313 static const ul_excl_t excl[] = {
314 {'J', 'r'},
315 {0}
316 };
317 int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
318
319 setlocale(LC_ALL, "");
320 bindtextdomain(PACKAGE, LOCALEDIR);
321 textdomain(PACKAGE);
322 close_stdout_atexit();
323
324 while ((c = getopt_long(argc, argv, "Jno:rVh", longopts, NULL)) != -1) {
325 err_exclusive_options(c, longopts, excl, excl_st);
326 switch (c) {
327 case 'J':
328 ctrl.json = 1;
329 break;
330 case 'n':
331 ctrl.no_headings = 1;
332 break;
333 case 'o':
334 outarg = optarg;
335 break;
336 case 'r':
337 ctrl.raw = 1;
338 break;
339
340 case 'V':
341 print_version(EXIT_SUCCESS);
342 case 'h':
343 usage();
344 default:
345 errtryhelp(EXIT_FAILURE);
346 }
347 }
348 argc -= optind;
349 argv += optind;
350
351 columns[ncolumns++] = COL_UUID;
352 columns[ncolumns++] = COL_VARIANT;
353 columns[ncolumns++] = COL_TYPE;
354 columns[ncolumns++] = COL_TIME;
355
356 if (outarg
357 && string_add_to_idarray(outarg, columns, ARRAY_SIZE(columns),
358 &ncolumns, column_name_to_id) < 0)
359 return EXIT_FAILURE;
360
361 print_output(&ctrl, argc, argv);
362
363 return EXIT_SUCCESS;
364 }