]> git.proxmox.com Git - systemd.git/blame - src/boot/bootctl.c
Imported Upstream version 214
[systemd.git] / src / boot / bootctl.c
CommitLineData
663996b3
MS
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
35static int help(void) {
60f067b4 36
663996b3 37 printf("%s [OPTIONS...] COMMAND ...\n\n"
60f067b4 38 "Query or change firmware and boot manager settings.\n\n"
663996b3
MS
39 " -h --help Show this help\n"
40 " --version Show package version\n"
41 "Commands:\n"
42 " status Show current boot settings\n",
43 program_invocation_short_name);
44
45 return 0;
46}
47
48static int parse_argv(int argc, char *argv[]) {
49 enum {
50 ARG_VERSION = 0x100,
51 };
52
53 static const struct option options[] = {
54 { "help", no_argument, NULL, 'h' },
55 { "version", no_argument, NULL, ARG_VERSION },
60f067b4 56 {}
663996b3
MS
57 };
58
59 int c;
60
61 assert(argc >= 0);
62 assert(argv);
60f067b4
JS
63
64 while ((c = getopt_long(argc, argv, "+h", options, NULL)) >= 0) {
663996b3
MS
65
66 switch (c) {
67
68 case 'h':
60f067b4 69 return help();
663996b3
MS
70
71 case ARG_VERSION:
72 puts(PACKAGE_STRING);
73 puts(SYSTEMD_FEATURES);
74 return 0;
75
76 case '?':
77 return -EINVAL;
78
79 default:
60f067b4 80 assert_not_reached("Unhandled option");
663996b3
MS
81 }
82 }
83
84 return 1;
85}
86
87static 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;
108err:
109 free(in);
110 return err;
111}
112
113static 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
123static 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
135static 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
199static 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
270int 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;
286finish:
287 return retval;
288}