]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/boot/bootctl.c
Unify parse_argv style
[thirdparty/systemd.git] / src / boot / bootctl.c
CommitLineData
7b4d7cc0
KS
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2013 Kay Sievers
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <stdlib.h>
23#include <stdbool.h>
24#include <unistd.h>
25#include <getopt.h>
26#include <locale.h>
27#include <string.h>
28#include <sys/timex.h>
29
30#include "boot.h"
31#include "build.h"
32#include "util.h"
33#include "utf8.h"
34
601185b4 35static void help(void) {
7b4d7cc0 36 printf("%s [OPTIONS...] COMMAND ...\n\n"
82de16f9 37 "Query or change firmware and boot manager settings.\n\n"
7b4d7cc0
KS
38 " -h --help Show this help\n"
39 " --version Show package version\n"
40 "Commands:\n"
601185b4
ZJS
41 " status Show current boot settings\n"
42 , program_invocation_short_name);
7b4d7cc0
KS
43}
44
45static int parse_argv(int argc, char *argv[]) {
46 enum {
47 ARG_VERSION = 0x100,
48 };
49
50 static const struct option options[] = {
601185b4
ZJS
51 { "help", no_argument, NULL, 'h' },
52 { "version", no_argument, NULL, ARG_VERSION },
eb9da376 53 {}
7b4d7cc0
KS
54 };
55
56 int c;
57
58 assert(argc >= 0);
59 assert(argv);
eb9da376 60
601185b4 61 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
7b4d7cc0
KS
62
63 switch (c) {
64
65 case 'h':
601185b4
ZJS
66 help();
67 return 0;
7b4d7cc0
KS
68
69 case ARG_VERSION:
70 puts(PACKAGE_STRING);
71 puts(SYSTEMD_FEATURES);
72 return 0;
73
74 case '?':
75 return -EINVAL;
76
77 default:
eb9da376 78 assert_not_reached("Unhandled option");
7b4d7cc0 79 }
7b4d7cc0
KS
80
81 return 1;
82}
83
84static int boot_info_new(struct boot_info **info) {
85 struct boot_info *in;
86 int err;
87
88 in = new0(struct boot_info, 1);
89 if (!in)
90 return -ENOMEM;
91
92 err = sd_id128_get_machine(&in->machine_id);
93 if (err < 0)
94 goto err;
95
96 err = sd_id128_get_boot(&in->boot_id);
97 if (err < 0)
98 goto err;
99
100 in->fw_entry_active = -1;
101 in->loader_entry_active = -1;
102
103 *info = in;
104 return 0;
105err:
106 free(in);
107 return err;
108}
109
110static void boot_info_entries_free(struct boot_info_entry *entries, size_t n) {
111 size_t i;
112
113 for (i = 0; i < n; i++) {
114 free(entries[i].title);
115 free(entries[i].path);
116 }
117 free(entries);
118}
119
120static void boot_info_free(struct boot_info *info) {
121 free(info->fw_type);
122 free(info->fw_info);
123 boot_info_entries_free(info->fw_entries, info->fw_entries_count);
124 free(info->fw_entries_order);
125 free(info->loader);
126 free(info->loader_image_path);
127 free(info->loader_options_added);
128 boot_info_entries_free(info->loader_entries, info->loader_entries_count);
129 free(info);
130}
131
132static int show_status(char **args, unsigned n) {
133 char buf[64];
134 struct boot_info *info;
135 int err;
136
137 err = boot_info_new(&info);
138 if (err < 0)
139 return -ENOMEM;
140
141 err = boot_info_query(info);
142
33696ef4 143 printf("System:\n");
3483fab9 144 printf(" Machine ID: %s\n", sd_id128_to_string(info->machine_id, buf));
bc6f2e7c 145 printf(" Boot ID: %s\n", sd_id128_to_string(info->boot_id, buf));
7b4d7cc0 146 if (info->fw_type)
33696ef4 147 printf(" Firmware: %s (%s)\n", info->fw_type, strna(info->fw_info));
bc6f2e7c
KS
148 if (info->fw_secure_boot >= 0)
149 printf(" Secure Boot: %s\n", info->fw_secure_boot ? "enabled" : "disabled");
150 if (info->fw_secure_boot_setup_mode >= 0)
0876dc1c 151 printf(" Setup Mode: %s\n", info->fw_secure_boot_setup_mode ? "setup" : "user");
33696ef4 152 printf("\n");
7b4d7cc0
KS
153
154 if (info->fw_entry_active >= 0) {
33696ef4 155 printf("Selected Firmware Entry:\n");
bc6f2e7c 156 printf(" Title: %s\n", strna(info->fw_entries[info->fw_entry_active].title));
7b4d7cc0 157 if (!sd_id128_equal(info->fw_entries[info->fw_entry_active].part_uuid, SD_ID128_NULL))
0014c522 158 printf(" Partition: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
abb381b3 159 SD_ID128_FORMAT_VAL(info->fw_entries[info->fw_entry_active].part_uuid));
33696ef4 160 else
0014c522 161 printf(" Partition: n/a\n");
33696ef4
KS
162 if (info->fw_entries[info->fw_entry_active].path)
163 printf(" File: %s%s\n", draw_special_char(DRAW_TREE_RIGHT), info->fw_entries[info->fw_entry_active].path);
7b4d7cc0 164 }
bc6f2e7c 165 printf("\n");
7b4d7cc0
KS
166
167 if (info->loader) {
33696ef4
KS
168 printf("Boot Loader:\n");
169 printf(" Product: %s\n", info->loader);
7b4d7cc0 170 if (!sd_id128_equal(info->loader_part_uuid, SD_ID128_NULL))
0014c522 171 printf(" Partition: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
abb381b3 172 SD_ID128_FORMAT_VAL(info->loader_part_uuid));
33696ef4 173 else
0014c522 174 printf(" Partition: n/a\n");
33696ef4
KS
175 printf(" File: %s%s\n", draw_special_char(DRAW_TREE_RIGHT), strna(info->loader_image_path));
176 printf("\n");
7b4d7cc0
KS
177
178 if (info->loader_entry_active >= 0) {
33696ef4 179 printf("Selected Boot Loader Entry:\n");
bc6f2e7c 180 printf(" Title: %s\n", strna(info->loader_entries[info->loader_entry_active].title));
33696ef4
KS
181 printf(" File: %s\n", info->loader_entries[info->loader_entry_active].path);
182 if (info->loader_options_added)
183 printf(" Options: %s\n", info->loader_options_added);
7b4d7cc0 184 }
7b4d7cc0
KS
185 } else
186 printf("No suitable data is provided by the boot manager. See:\n"
187 " http://www.freedesktop.org/wiki/Software/systemd/BootLoaderInterface\n"
188 " http://www.freedesktop.org/wiki/Specifications/BootLoaderSpec\n"
189 "for details.\n");
190 printf("\n");
191
192 boot_info_free(info);
193 return err;
194}
195
196static int bootctl_main(int argc, char *argv[]) {
197 static const struct {
198 const char* verb;
199 const enum {
200 MORE,
201 LESS,
202 EQUAL
203 } argc_cmp;
204 const int argc;
205 int (* const dispatch)(char **args, unsigned n);
206 } verbs[] = {
207 { "status", LESS, 1, show_status },
208 };
209
210 int left;
211 unsigned i;
212
213 assert(argc >= 0);
214 assert(argv);
215
216 left = argc - optind;
217
218 if (left <= 0)
219 /* Special rule: no arguments means "status" */
220 i = 0;
221 else {
222 if (streq(argv[optind], "help")) {
223 help();
224 return 0;
225 }
226
227 for (i = 0; i < ELEMENTSOF(verbs); i++)
228 if (streq(argv[optind], verbs[i].verb))
229 break;
230
231 if (i >= ELEMENTSOF(verbs)) {
232 log_error("Unknown operation %s", argv[optind]);
233 return -EINVAL;
234 }
235 }
236
237 switch (verbs[i].argc_cmp) {
238
239 case EQUAL:
240 if (left != verbs[i].argc) {
241 log_error("Invalid number of arguments.");
242 return -EINVAL;
243 }
244 break;
245
246 case MORE:
247 if (left < verbs[i].argc) {
248 log_error("Too few arguments.");
249 return -EINVAL;
250 }
251 break;
252
253 case LESS:
254 if (left > verbs[i].argc) {
255 log_error("Too many arguments.");
256 return -EINVAL;
257 }
258 break;
259
260 default:
261 assert_not_reached("Unknown comparison operator.");
262 }
263
264 return verbs[i].dispatch(argv + optind, left);
265}
266
267int main(int argc, char *argv[]) {
601185b4 268 int r;
7b4d7cc0
KS
269
270 log_parse_environment();
271 log_open();
272
273 r = parse_argv(argc, argv);
601185b4 274 if (r <= 0)
7b4d7cc0 275 goto finish;
7b4d7cc0
KS
276
277 r = bootctl_main(argc, argv);
601185b4
ZJS
278
279 finish:
280 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
7b4d7cc0 281}