]> git.ozlabs.org Git - petitboot/blob - discover/yaboot-parser.c
discover/boot: Allow boot hooks to alter boot data
[petitboot] / discover / yaboot-parser.c
1 #define _GNU_SOURCE
2
3 #include <assert.h>
4 #include <stdlib.h>
5 #include <string.h>
6
7 #include "log/log.h"
8 #include "talloc/talloc.h"
9 #include "types/types.h"
10 #include "parser-conf.h"
11 #include "parser-utils.h"
12 #include "resource.h"
13
14 struct yaboot_state {
15         struct discover_boot_option *opt;
16         char *desc_image;
17         char *desc_initrd;
18         int globals_done;
19         const char *const *known_names;
20 };
21
22 static void yaboot_finish(struct conf_context *conf)
23 {
24         struct yaboot_state *state = conf->parser_info;
25         struct device *dev = conf->dc->device->device;
26         struct boot_option *opt;
27
28         if (!state->desc_image) {
29                 pb_log("%s: %s: no image found\n", __func__, dev->id);
30                 return;
31         }
32
33         assert(state->opt);
34
35         opt = state->opt->option;
36         assert(opt);
37         assert(opt->name);
38         assert(opt->boot_args);
39
40         opt->description = talloc_asprintf(opt, "%s %s %s",
41                 state->desc_image,
42                 (state->desc_initrd ? state->desc_initrd : ""),
43                 opt->boot_args);
44
45         talloc_free(state->desc_initrd);
46         state->desc_initrd = NULL;
47
48         conf_strip_str(opt->boot_args);
49         conf_strip_str(opt->description);
50
51         discover_context_add_boot_option(conf->dc, state->opt);
52 }
53
54 static struct resource *create_yaboot_devpath_resource(
55                 struct discover_boot_option *opt,
56                 struct conf_context *conf,
57                 const char *path, char **desc_str)
58 {
59         const char *g_boot = conf_get_global_option(conf, "boot");
60         const char *g_part = conf_get_global_option(conf, "partition");
61         struct resource *res;
62         char *devpath;
63
64         if (g_boot && g_part) {
65                 devpath = talloc_asprintf(conf,
66                                 "%s%s:%s", g_boot, g_part, path);
67         } else if (g_boot) {
68                 devpath = talloc_asprintf(conf, "%s:%s", g_boot, path);
69         } else {
70                 devpath = talloc_strdup(conf, path);
71         }
72
73         res = create_devpath_resource(opt, conf->dc->device, devpath);
74
75         if (desc_str)
76                 *desc_str = devpath;
77         else
78                 talloc_free(devpath);
79
80         return res;
81 }
82
83
84 static void yaboot_process_pair(struct conf_context *conf, const char *name,
85                 char *value)
86 {
87         struct yaboot_state *state = conf->parser_info;
88         struct discover_boot_option *opt = state->opt;
89         struct fixed_pair {
90                 const char *image;
91                 const char *initrd;
92         };
93         static const struct fixed_pair suse_fp32 = {
94                 .image = "/suseboot/vmlinux32",
95                 .initrd = "/suseboot/initrd32",
96         };
97         static const struct fixed_pair suse_fp64 = {
98                 .image = "/suseboot/vmlinux64",
99                 .initrd = "/suseboot/initrd64",
100         };
101         const struct fixed_pair *suse_fp;
102
103         /* fixup for bare values */
104
105         if (!name)
106                 name = value;
107
108         if (!state->globals_done && conf_set_global_option(conf, name, value))
109                 return;
110
111         if (!conf_param_in_list(state->known_names, name))
112                 return;
113
114         state->globals_done = 1;
115
116         /* image */
117
118         if (streq(name, "image")) {
119
120                 /* First finish any previous image. */
121                 if (opt)
122                         yaboot_finish(conf);
123
124                 opt = discover_boot_option_create(conf->dc, conf->dc->device);
125                 opt->option->boot_args = talloc_strdup(opt->option, "");
126
127                 /* Then start the new image. */
128                 opt->boot_image = create_yaboot_devpath_resource(opt,
129                                 conf, value, &state->desc_image);
130
131                 state->opt = opt;
132
133                 return;
134         }
135
136         /* Special processing for SUSE install CD. */
137
138         if (streq(name, "image[32bit]"))
139                 suse_fp = &suse_fp32;
140         else if (streq(name, "image[64bit]"))
141                 suse_fp = &suse_fp64;
142         else
143                 suse_fp = NULL;
144
145         if (suse_fp) {
146                 /* First finish any previous image. */
147                 if (opt)
148                         yaboot_finish(conf);
149
150                 /* Then start the new image. */
151
152                 opt = discover_boot_option_create(conf->dc, conf->dc->device);
153                 opt->option->boot_args = talloc_strdup(opt->option, "");
154
155                 state->opt = opt;
156
157                 if (*value == '/') {
158                         opt->boot_image = create_yaboot_devpath_resource(opt,
159                                         conf, value, &state->desc_image);
160                 } else {
161                         char *tmp;
162
163                         opt->boot_image = create_yaboot_devpath_resource(opt,
164                                         conf, suse_fp->image,
165                                         &state->desc_image);
166
167                         opt->initrd = create_yaboot_devpath_resource(opt,
168                                         conf, suse_fp->initrd, &tmp);
169
170                         state->desc_initrd = talloc_asprintf(opt,
171                                 "initrd=%s", tmp);
172                         talloc_free(tmp);
173                 }
174
175                 return;
176         }
177
178         if (!opt->boot_image) {
179                 pb_log("%s: unknown name: %s\n", __func__, name);
180                 return;
181         }
182
183         /* initrd */
184
185         if (streq(name, "initrd")) {
186                 opt->initrd = create_yaboot_devpath_resource(opt, conf,
187                                 value, &state->desc_image);
188
189                 return;
190         }
191
192         /* label */
193
194         if (streq(name, "label")) {
195                 opt->option->id = talloc_asprintf(opt->option, "%s#%s",
196                         conf->dc->device->device->id, value);
197                 opt->option->name = talloc_strdup(opt->option, value);
198                 return;
199         }
200
201         /* args */
202
203         if (streq(name, "append")) {
204                 opt->option->boot_args = talloc_asprintf_append(
205                         opt->option->boot_args, "%s ", value);
206                 return;
207         }
208
209         if (streq(name, "initrd-size")) {
210                 opt->option->boot_args = talloc_asprintf_append(
211                         opt->option->boot_args, "ramdisk_size=%s ", value);
212                 return;
213         }
214
215         if (streq(name, "literal")) {
216                 if (*opt->option->boot_args) {
217                         pb_log("%s: literal over writes '%s'\n", __func__,
218                                 opt->option->boot_args);
219                         talloc_free(opt->option->boot_args);
220                 }
221                 talloc_asprintf(opt->option, "%s ", value);
222                 return;
223         }
224
225         if (streq(name, "ramdisk")) {
226                 opt->option->boot_args = talloc_asprintf_append(
227                         opt->option->boot_args, "ramdisk=%s ", value);
228                 return;
229         }
230
231         if (streq(name, "read-only")) {
232                 opt->option->boot_args = talloc_asprintf_append(
233                         opt->option->boot_args, "ro ");
234                 return;
235         }
236
237         if (streq(name, "read-write")) {
238                 opt->option->boot_args = talloc_asprintf_append(
239                         opt->option->boot_args, "rw ");
240                 return;
241         }
242
243         if (streq(name, "root")) {
244                 opt->option->boot_args = talloc_asprintf_append(
245                         opt->option->boot_args, "root=%s ", value);
246                 return;
247         }
248
249         pb_log("%s: unknown name: %s\n", __func__, name);
250 }
251
252 static struct conf_global_option yaboot_global_options[] = {
253         { .name = "boot" },
254         { .name = "initrd" },
255         { .name = "partition" },
256         { .name = "video" },
257         { .name = NULL },
258 };
259
260 static const char *const yaboot_conf_files[] = {
261         "/yaboot.conf",
262         "/yaboot.cnf",
263         "/etc/yaboot.conf",
264         "/etc/yaboot.cnf",
265         "/suseboot/yaboot.cnf",
266         "/YABOOT.CONF",
267         "/YABOOT.CNF",
268         "/ETC/YABOOT.CONF",
269         "/ETC/YABOOT.CNF",
270         "/SUSEBOOT/YABOOT.CNF",
271         NULL
272 };
273
274 static const char *yaboot_known_names[] = {
275         "append",
276         "image",
277         "image[64bit]", /* SUSE extension */
278         "image[32bit]", /* SUSE extension */
279         "initrd",
280         "initrd-size",
281         "label",
282         "literal",
283         "ramdisk",
284         "read-only",
285         "read-write",
286         "root",
287         NULL
288 };
289
290 static int yaboot_parse(struct discover_context *dc, char *buf, int len)
291 {
292         struct conf_context *conf;
293         struct yaboot_state *state;
294
295         conf = talloc_zero(dc, struct conf_context);
296
297         if (!conf)
298                 return 0;
299
300         conf->dc = dc;
301         conf->global_options = yaboot_global_options,
302         conf_init_global_options(conf);
303         conf->get_pair = conf_get_pair_equal;
304         conf->process_pair = yaboot_process_pair;
305         conf->finish = yaboot_finish;
306         conf->parser_info = state = talloc_zero(conf, struct yaboot_state);
307
308         state->known_names = yaboot_known_names;
309
310         state->opt = NULL;
311
312         conf_parse_buf(conf, buf, len);
313
314         talloc_free(conf);
315         return 1;
316 }
317
318 static struct parser yaboot_parser = {
319         .name                   = "yaboot",
320         .method                 = CONF_METHOD_LOCAL_FILE,
321         .parse                  = yaboot_parse,
322         .filenames              = yaboot_conf_files,
323         .resolve_resource       = resolve_devpath_resource,
324 };
325
326 register_parser(yaboot_parser);