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