chiark / gitweb /
bootctl: print secure boot flags
[elogind.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 mananger settings.\n\n"
38                "  -h --help              Show this help\n"
39                "     --version           Show package version\n"
40                "Commands:\n"
41                "  status                 Show current time 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("Machine:\n");
147         printf("           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         printf("\n");
150
151         printf("Firmware:\n");
152         if (info->fw_type)
153                 printf("         Type: %s (%s)\n", info->fw_type, strna(info->fw_info));
154
155         if (info->fw_secure_boot >= 0)
156                 printf("  Secure Boot: %s\n", info->fw_secure_boot ? "enabled" : "disabled");
157         if (info->fw_secure_boot_setup_mode >= 0)
158                 printf("     Setup Mode: %s\n", info->fw_secure_boot_setup_mode ? "setup" : "user");
159
160         if (info->fw_entry_active >= 0) {
161                 printf("        Title: %s\n", strna(info->fw_entries[info->fw_entry_active].title));
162                 if (info->fw_entries[info->fw_entry_active].path)
163                         printf("       Binary: %s\n", info->fw_entries[info->fw_entry_active].path);
164                 if (!sd_id128_equal(info->fw_entries[info->fw_entry_active].part_uuid, SD_ID128_NULL))
165                         printf("    Partition: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
166                                SD_ID128_FORMAT_VAL(info->fw_entries[info->fw_entry_active].part_uuid));
167         }
168         printf("\n");
169
170         if (info->loader) {
171                 printf("Boot loader:\n");
172                 printf("         Type: %s\n", info->loader);
173                 printf("       Binary: %s\n", strna(info->loader_image_path));
174                 if (!sd_id128_equal(info->loader_part_uuid, SD_ID128_NULL))
175                         printf("    Partition: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
176                                SD_ID128_FORMAT_VAL(info->loader_part_uuid));
177
178                 if (info->loader_entry_active >= 0) {
179                         printf("        Title: %s\n", strna(info->loader_entries[info->loader_entry_active].title));
180                         printf("        Entry: %s\n", info->loader_entries[info->loader_entry_active].path);
181                 }
182
183                 printf("      Options: %s\n", strna(info->loader_options_added));
184         } else
185                 printf("No suitable data is provided by the boot manager. See:\n"
186                        "  http://www.freedesktop.org/wiki/Software/systemd/BootLoaderInterface\n"
187                        "  http://www.freedesktop.org/wiki/Specifications/BootLoaderSpec\n"
188                        "for details.\n");
189         printf("\n");
190
191         boot_info_free(info);
192         return err;
193 }
194
195 static int bootctl_main(int argc, char *argv[]) {
196         static const struct {
197                 const char* verb;
198                 const enum {
199                         MORE,
200                         LESS,
201                         EQUAL
202                 } argc_cmp;
203                 const int argc;
204                 int (* const dispatch)(char **args, unsigned n);
205         } verbs[] = {
206                 { "status",                LESS,   1, show_status      },
207         };
208
209         int left;
210         unsigned i;
211
212         assert(argc >= 0);
213         assert(argv);
214
215         left = argc - optind;
216
217         if (left <= 0)
218                 /* Special rule: no arguments means "status" */
219                 i = 0;
220         else {
221                 if (streq(argv[optind], "help")) {
222                         help();
223                         return 0;
224                 }
225
226                 for (i = 0; i < ELEMENTSOF(verbs); i++)
227                         if (streq(argv[optind], verbs[i].verb))
228                                 break;
229
230                 if (i >= ELEMENTSOF(verbs)) {
231                         log_error("Unknown operation %s", argv[optind]);
232                         return -EINVAL;
233                 }
234         }
235
236         switch (verbs[i].argc_cmp) {
237
238         case EQUAL:
239                 if (left != verbs[i].argc) {
240                         log_error("Invalid number of arguments.");
241                         return -EINVAL;
242                 }
243                 break;
244
245         case MORE:
246                 if (left < verbs[i].argc) {
247                         log_error("Too few arguments.");
248                         return -EINVAL;
249                 }
250                 break;
251
252         case LESS:
253                 if (left > verbs[i].argc) {
254                         log_error("Too many arguments.");
255                         return -EINVAL;
256                 }
257                 break;
258
259         default:
260                 assert_not_reached("Unknown comparison operator.");
261         }
262
263         return verbs[i].dispatch(argv + optind, left);
264 }
265
266 int main(int argc, char *argv[]) {
267         int r, retval = EXIT_FAILURE;
268
269         log_parse_environment();
270         log_open();
271
272         r = parse_argv(argc, argv);
273         if (r < 0)
274                 goto finish;
275         else if (r == 0) {
276                 retval = EXIT_SUCCESS;
277                 goto finish;
278         }
279
280         r = bootctl_main(argc, argv);
281         retval = r < 0 ? EXIT_FAILURE : r;
282 finish:
283         return retval;
284 }