1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include <getopt.h>
4 #include <stdio.h>
5 
6 #include "alloc-util.h"
7 #include "gpt.h"
8 #include "id128-print.h"
9 #include "main-func.h"
10 #include "pretty-print.h"
11 #include "strv.h"
12 #include "format-table.h"
13 #include "terminal-util.h"
14 #include "util.h"
15 #include "verbs.h"
16 
17 static Id128PrettyPrintMode arg_mode = ID128_PRINT_ID128;
18 static sd_id128_t arg_app = {};
19 
verb_new(int argc,char ** argv,void * userdata)20 static int verb_new(int argc, char **argv, void *userdata) {
21         return id128_print_new(arg_mode);
22 }
23 
verb_machine_id(int argc,char ** argv,void * userdata)24 static int verb_machine_id(int argc, char **argv, void *userdata) {
25         sd_id128_t id;
26         int r;
27 
28         if (sd_id128_is_null(arg_app))
29                 r = sd_id128_get_machine(&id);
30         else
31                 r = sd_id128_get_machine_app_specific(arg_app, &id);
32         if (r < 0)
33                 return log_error_errno(r, "Failed to get %smachine-ID: %m",
34                                        sd_id128_is_null(arg_app) ? "" : "app-specific ");
35 
36         return id128_pretty_print(id, arg_mode);
37 }
38 
verb_boot_id(int argc,char ** argv,void * userdata)39 static int verb_boot_id(int argc, char **argv, void *userdata) {
40         sd_id128_t id;
41         int r;
42 
43         if (sd_id128_is_null(arg_app))
44                 r = sd_id128_get_boot(&id);
45         else
46                 r = sd_id128_get_boot_app_specific(arg_app, &id);
47         if (r < 0)
48                 return log_error_errno(r, "Failed to get %sboot-ID: %m",
49                                        sd_id128_is_null(arg_app) ? "" : "app-specific ");
50 
51         return id128_pretty_print(id, arg_mode);
52 }
53 
verb_invocation_id(int argc,char ** argv,void * userdata)54 static int verb_invocation_id(int argc, char **argv, void *userdata) {
55         sd_id128_t id;
56         int r;
57 
58         if (!sd_id128_is_null(arg_app))
59                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
60                                        "Verb \"invocation-id\" cannot be combined with --app-specific=.");
61 
62         r = sd_id128_get_invocation(&id);
63         if (r < 0)
64                 return log_error_errno(r, "Failed to get invocation-ID: %m");
65 
66         return id128_pretty_print(id, arg_mode);
67 }
68 
show_one(Table ** table,const char * name,sd_id128_t uuid,bool first)69 static int show_one(Table **table, const char *name, sd_id128_t uuid, bool first) {
70         int r;
71 
72         if (arg_mode == ID128_PRINT_PRETTY) {
73                 _cleanup_free_ char *id = NULL;
74 
75                 id = strreplace(name, "-", "_");
76                 if (!id)
77                         return log_oom();
78 
79                 ascii_strupper(id);
80 
81                 r = id128_pretty_print_sample(id, uuid);
82                 if (r < 0)
83                         return r;
84                 if (!first)
85                         puts("");
86                 return 0;
87 
88         } else {
89                 if (!*table) {
90                         *table = table_new("name", "id");
91                         if (!*table)
92                                 return log_oom();
93                         table_set_width(*table, 0);
94                 }
95 
96                 return table_add_many(*table,
97                                       TABLE_STRING, name,
98                                       arg_mode == ID128_PRINT_ID128 ? TABLE_ID128 : TABLE_UUID,
99                                       uuid);
100         }
101 }
102 
verb_show(int argc,char ** argv,void * userdata)103 static int verb_show(int argc, char **argv, void *userdata) {
104         _cleanup_(table_unrefp) Table *table = NULL;
105         int r;
106 
107         argv = strv_skip(argv, 1);
108         if (strv_isempty(argv))
109                 for (const GptPartitionType *e = gpt_partition_type_table; e->name; e++) {
110                         r = show_one(&table, e->name, e->uuid, e == gpt_partition_type_table);
111                         if (r < 0)
112                                 return r;
113                 }
114         else
115                 STRV_FOREACH(p, argv) {
116                         sd_id128_t uuid;
117                         bool have_uuid;
118                         const char *id;
119 
120                         /* Check if the argument is an actual UUID first */
121                         have_uuid = sd_id128_from_string(*p, &uuid) >= 0;
122 
123                         if (have_uuid)
124                                 id = gpt_partition_type_uuid_to_string(uuid) ?: "XYZ";
125                         else {
126                                 r = gpt_partition_type_uuid_from_string(*p, &uuid);
127                                 if (r < 0)
128                                         return log_error_errno(r, "Unknown identifier \"%s\".", *p);
129 
130                                 id = *p;
131                         }
132 
133                         r = show_one(&table, id, uuid, p == argv);
134                         if (r < 0)
135                                 return r;
136                 }
137 
138         if (table) {
139                 r = table_print(table, NULL);
140                 if (r < 0)
141                         return table_log_print_error(r);
142         }
143 
144         return 0;
145 }
146 
help(void)147 static int help(void) {
148         _cleanup_free_ char *link = NULL;
149         int r;
150 
151         r = terminal_urlify_man("systemd-id128", "1", &link);
152         if (r < 0)
153                 return log_oom();
154 
155         printf("%s [OPTIONS...] COMMAND\n\n"
156                "%sGenerate and print 128bit identifiers.%s\n"
157                "\nCommands:\n"
158                "  new                     Generate a new ID\n"
159                "  machine-id              Print the ID of current machine\n"
160                "  boot-id                 Print the ID of current boot\n"
161                "  invocation-id           Print the ID of current invocation\n"
162                "  show [NAME]             Print one or more well-known GPT partition type IDs\n"
163                "  help                    Show this help\n"
164                "\nOptions:\n"
165                "  -h --help               Show this help\n"
166                "  -p --pretty             Generate samples of program code\n"
167                "  -a --app-specific=ID    Generate app-specific IDs\n"
168                "  -u --uuid               Output in UUID format\n"
169                "\nSee the %s for details.\n",
170                program_invocation_short_name,
171                ansi_highlight(),
172                ansi_normal(),
173                link);
174 
175         return 0;
176 }
177 
verb_help(int argc,char ** argv,void * userdata)178 static int verb_help(int argc, char **argv, void *userdata) {
179         return help();
180 }
181 
parse_argv(int argc,char * argv[])182 static int parse_argv(int argc, char *argv[]) {
183         enum {
184                 ARG_VERSION = 0x100,
185         };
186 
187         static const struct option options[] = {
188                 { "help",         no_argument,       NULL, 'h'              },
189                 { "version",      no_argument,       NULL, ARG_VERSION      },
190                 { "pretty",       no_argument,       NULL, 'p'              },
191                 { "app-specific", required_argument, NULL, 'a'              },
192                 { "uuid",         no_argument,       NULL, 'u'              },
193                 {},
194         };
195 
196         int c, r;
197 
198         assert(argc >= 0);
199         assert(argv);
200 
201         while ((c = getopt_long(argc, argv, "hpa:u", options, NULL)) >= 0)
202                 switch (c) {
203 
204                 case 'h':
205                         return help();
206 
207                 case ARG_VERSION:
208                         return version();
209 
210                 case 'p':
211                         arg_mode = ID128_PRINT_PRETTY;
212                         break;
213 
214                 case 'a':
215                         r = sd_id128_from_string(optarg, &arg_app);
216                         if (r < 0)
217                                 return log_error_errno(r, "Failed to parse \"%s\" as application-ID: %m", optarg);
218                         break;
219 
220                 case 'u':
221                         arg_mode = ID128_PRINT_UUID;
222                         break;
223 
224                 case '?':
225                         return -EINVAL;
226 
227                 default:
228                         assert_not_reached();
229                 }
230 
231         return 1;
232 }
233 
id128_main(int argc,char * argv[])234 static int id128_main(int argc, char *argv[]) {
235         static const Verb verbs[] = {
236                 { "new",            VERB_ANY, 1,        0,  verb_new           },
237                 { "machine-id",     VERB_ANY, 1,        0,  verb_machine_id    },
238                 { "boot-id",        VERB_ANY, 1,        0,  verb_boot_id       },
239                 { "invocation-id",  VERB_ANY, 1,        0,  verb_invocation_id },
240                 { "show",           VERB_ANY, VERB_ANY, 0,  verb_show          },
241                 { "help",           VERB_ANY, VERB_ANY, 0,  verb_help          },
242                 {}
243         };
244 
245         return dispatch_verb(argc, argv, verbs, NULL);
246 }
247 
run(int argc,char * argv[])248 static int run(int argc, char *argv[]) {
249         int r;
250 
251         log_setup();
252 
253         r = parse_argv(argc, argv);
254         if (r <= 0)
255                 return r;
256 
257         return id128_main(argc, argv);
258 }
259 
260 DEFINE_MAIN_FUNCTION(run);
261