chiark / gitweb /
bootctl: rename status output header
[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("Identification:\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         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                 if (info->loader_options_added)
184                         printf("      Options: %s\n", info->loader_options_added);
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
196 static 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
267 int main(int argc, char *argv[]) {
268         int r, retval = EXIT_FAILURE;
269
270         log_parse_environment();
271         log_open();
272
273         r = parse_argv(argc, argv);
274         if (r < 0)
275                 goto finish;
276         else if (r == 0) {
277                 retval = EXIT_SUCCESS;
278                 goto finish;
279         }
280
281         r = bootctl_main(argc, argv);
282         retval = r < 0 ? EXIT_FAILURE : r;
283 finish:
284         return retval;
285 }