]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/boot/bootctl.c
d25ddef6e5ac7c61d99217b79ad8922060d5cf0c
[thirdparty/systemd.git] / src / boot / bootctl.c
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
35 static int help(void) {
36 printf("%s [OPTIONS...] COMMAND ...\n\n"
37 "Query or change firmware and boot manager settings.\n\n"
38 " -h --help Show this help\n"
39 " --version Show package version\n"
40 "Commands:\n"
41 " status Show current boot settings\n",
42 program_invocation_short_name);
43
44 return 0;
45 }
46
47 static int parse_argv(int argc, char *argv[]) {
48 enum {
49 ARG_VERSION = 0x100,
50 };
51
52 static const struct option options[] = {
53 { "help", no_argument, NULL, 'h' },
54 { "version", no_argument, NULL, ARG_VERSION },
55 { NULL, 0, NULL, 0 }
56 };
57
58 int c;
59
60 assert(argc >= 0);
61 assert(argv);
62 while ((c = getopt_long(argc, argv, "+hH:P", options, NULL)) >= 0) {
63
64 switch (c) {
65
66 case 'h':
67 help();
68 return 0;
69
70 case ARG_VERSION:
71 puts(PACKAGE_STRING);
72 puts(SYSTEMD_FEATURES);
73 return 0;
74
75 case '?':
76 return -EINVAL;
77
78 default:
79 log_error("Unknown option code %c", c);
80 return -EINVAL;
81 }
82 }
83
84 return 1;
85 }
86
87 static int boot_info_new(struct boot_info **info) {
88 struct boot_info *in;
89 int err;
90
91 in = new0(struct boot_info, 1);
92 if (!in)
93 return -ENOMEM;
94
95 err = sd_id128_get_machine(&in->machine_id);
96 if (err < 0)
97 goto err;
98
99 err = sd_id128_get_boot(&in->boot_id);
100 if (err < 0)
101 goto err;
102
103 in->fw_entry_active = -1;
104 in->loader_entry_active = -1;
105
106 *info = in;
107 return 0;
108 err:
109 free(in);
110 return err;
111 }
112
113 static void boot_info_entries_free(struct boot_info_entry *entries, size_t n) {
114 size_t i;
115
116 for (i = 0; i < n; i++) {
117 free(entries[i].title);
118 free(entries[i].path);
119 }
120 free(entries);
121 }
122
123 static void boot_info_free(struct boot_info *info) {
124 free(info->fw_type);
125 free(info->fw_info);
126 boot_info_entries_free(info->fw_entries, info->fw_entries_count);
127 free(info->fw_entries_order);
128 free(info->loader);
129 free(info->loader_image_path);
130 free(info->loader_options_added);
131 boot_info_entries_free(info->loader_entries, info->loader_entries_count);
132 free(info);
133 }
134
135 static int show_status(char **args, unsigned n) {
136 char buf[64];
137 struct boot_info *info;
138 int err;
139
140 err = boot_info_new(&info);
141 if (err < 0)
142 return -ENOMEM;
143
144 err = boot_info_query(info);
145
146 printf("System:\n");
147 printf(" Machine ID: %s\n", sd_id128_to_string(info->machine_id, buf));
148 printf(" Boot ID: %s\n", sd_id128_to_string(info->boot_id, buf));
149 if (info->fw_type)
150 printf(" Firmware: %s (%s)\n", info->fw_type, strna(info->fw_info));
151 if (info->fw_secure_boot >= 0)
152 printf(" Secure Boot: %s\n", info->fw_secure_boot ? "enabled" : "disabled");
153 if (info->fw_secure_boot_setup_mode >= 0)
154 printf(" Setup Mode: %s\n", info->fw_secure_boot_setup_mode ? "setup" : "user");
155 printf("\n");
156
157 if (info->fw_entry_active >= 0) {
158 printf("Selected Firmware Entry:\n");
159 printf(" Title: %s\n", strna(info->fw_entries[info->fw_entry_active].title));
160 if (!sd_id128_equal(info->fw_entries[info->fw_entry_active].part_uuid, SD_ID128_NULL))
161 printf(" Partition: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
162 SD_ID128_FORMAT_VAL(info->fw_entries[info->fw_entry_active].part_uuid));
163 else
164 printf(" Partition: n/a\n");
165 if (info->fw_entries[info->fw_entry_active].path)
166 printf(" File: %s%s\n", draw_special_char(DRAW_TREE_RIGHT), info->fw_entries[info->fw_entry_active].path);
167 }
168 printf("\n");
169
170 if (info->loader) {
171 printf("Boot Loader:\n");
172 printf(" Product: %s\n", info->loader);
173 if (!sd_id128_equal(info->loader_part_uuid, SD_ID128_NULL))
174 printf(" Partition: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
175 SD_ID128_FORMAT_VAL(info->loader_part_uuid));
176 else
177 printf(" Partition: n/a\n");
178 printf(" File: %s%s\n", draw_special_char(DRAW_TREE_RIGHT), strna(info->loader_image_path));
179 printf("\n");
180
181 if (info->loader_entry_active >= 0) {
182 printf("Selected Boot Loader Entry:\n");
183 printf(" Title: %s\n", strna(info->loader_entries[info->loader_entry_active].title));
184 printf(" File: %s\n", info->loader_entries[info->loader_entry_active].path);
185 if (info->loader_options_added)
186 printf(" Options: %s\n", info->loader_options_added);
187 }
188 } else
189 printf("No suitable data is provided by the boot manager. See:\n"
190 " http://www.freedesktop.org/wiki/Software/systemd/BootLoaderInterface\n"
191 " http://www.freedesktop.org/wiki/Specifications/BootLoaderSpec\n"
192 "for details.\n");
193 printf("\n");
194
195 boot_info_free(info);
196 return err;
197 }
198
199 static int bootctl_main(int argc, char *argv[]) {
200 static const struct {
201 const char* verb;
202 const enum {
203 MORE,
204 LESS,
205 EQUAL
206 } argc_cmp;
207 const int argc;
208 int (* const dispatch)(char **args, unsigned n);
209 } verbs[] = {
210 { "status", LESS, 1, show_status },
211 };
212
213 int left;
214 unsigned i;
215
216 assert(argc >= 0);
217 assert(argv);
218
219 left = argc - optind;
220
221 if (left <= 0)
222 /* Special rule: no arguments means "status" */
223 i = 0;
224 else {
225 if (streq(argv[optind], "help")) {
226 help();
227 return 0;
228 }
229
230 for (i = 0; i < ELEMENTSOF(verbs); i++)
231 if (streq(argv[optind], verbs[i].verb))
232 break;
233
234 if (i >= ELEMENTSOF(verbs)) {
235 log_error("Unknown operation %s", argv[optind]);
236 return -EINVAL;
237 }
238 }
239
240 switch (verbs[i].argc_cmp) {
241
242 case EQUAL:
243 if (left != verbs[i].argc) {
244 log_error("Invalid number of arguments.");
245 return -EINVAL;
246 }
247 break;
248
249 case MORE:
250 if (left < verbs[i].argc) {
251 log_error("Too few arguments.");
252 return -EINVAL;
253 }
254 break;
255
256 case LESS:
257 if (left > verbs[i].argc) {
258 log_error("Too many arguments.");
259 return -EINVAL;
260 }
261 break;
262
263 default:
264 assert_not_reached("Unknown comparison operator.");
265 }
266
267 return verbs[i].dispatch(argv + optind, left);
268 }
269
270 int main(int argc, char *argv[]) {
271 int r, retval = EXIT_FAILURE;
272
273 log_parse_environment();
274 log_open();
275
276 r = parse_argv(argc, argv);
277 if (r < 0)
278 goto finish;
279 else if (r == 0) {
280 retval = EXIT_SUCCESS;
281 goto finish;
282 }
283
284 r = bootctl_main(argc, argv);
285 retval = r < 0 ? EXIT_FAILURE : r;
286 finish:
287 return retval;
288 }