]>
Commit | Line | Data |
---|---|---|
83893f26 SK |
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> | |
ae1c9d60 | 48 | #include <uuid.h> |
83893f26 SK |
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" | |
83893f26 SK |
56 | #include "xalloc.h" |
57 | ||
83893f26 SK |
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); | |
4c2af168 KZ |
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")); | |
f45f3ec3 | 104 | printf(USAGE_HELP_OPTIONS(24)); |
83893f26 SK |
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 | ||
f45f3ec3 | 110 | printf(USAGE_MAN_TAIL("uuidparse(1)")); |
83893f26 SK |
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, type; | |
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 0: | |
8cfbd350 SK |
196 | if (strspn(uuid, "0-") == 36) |
197 | str = xstrdup(_("nil")); | |
198 | else | |
199 | str = xstrdup(_("unknown")); | |
83893f26 SK |
200 | break; |
201 | case 1: | |
202 | str = xstrdup(_("time-based")); | |
203 | break; | |
204 | case 2: | |
205 | str = xstrdup("DCE"); | |
206 | break; | |
207 | case 3: | |
208 | str = xstrdup(_("name-based")); | |
209 | break; | |
210 | case 4: | |
211 | str = xstrdup(_("random")); | |
212 | break; | |
213 | case 5: | |
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 == 1) { | |
226 | struct timeval tv; | |
4111bb3a | 227 | char date_buf[ISO_BUFSIZ]; |
83893f26 SK |
228 | |
229 | uuid_time(buf, &tv); | |
4111bb3a WP |
230 | strtimeval_iso(&tv, ISO_TIMESTAMP_COMMA, |
231 | date_buf, sizeof(date_buf)); | |
83893f26 SK |
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 | ||
e8fd8c6b KZ |
254 | if (ctrl->json) { |
255 | scols_table_enable_json(tb, 1); | |
256 | scols_table_set_name(tb, "uuids"); | |
257 | } | |
83893f26 SK |
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 | ||
ae1c9d60 | 276 | while (scanf(" %36[^ \t\n]%*c", uuid) && !feof(stdin)) |
83893f26 SK |
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'}, | |
f2bd6881 | 296 | {NULL, 0, NULL, 0} |
83893f26 SK |
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 | atexit(close_stdout); | |
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 | case 'V': | |
325 | printf(UTIL_LINUX_VERSION); | |
326 | return 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 | } |