parser/yaboot: Fix check for image presence
[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         /* all other processing requires an image */
179         if (!opt) {
180                 pb_log("%s: unknown name: %s\n", __func__, name);
181                 return;
182         }
183
184         /* initrd */
185
186         if (streq(name, "initrd")) {
187                 opt->initrd = create_yaboot_devpath_resource(opt, conf,
188                                 value, &state->desc_image);
189
190                 return;
191         }
192
193         /* label */
194
195         if (streq(name, "label")) {
196                 opt->option->id = talloc_asprintf(opt->option, "%s#%s",
197                         conf->dc->device->device->id, value);
198                 opt->option->name = talloc_strdup(opt->option, value);
199                 return;
200         }
201
202         /* args */
203
204         if (streq(name, "append")) {
205                 opt->option->boot_args = talloc_asprintf_append(
206                         opt->option->boot_args, "%s ", value);
207                 return;
208         }
209
210         if (streq(name, "initrd-size")) {
211                 opt->option->boot_args = talloc_asprintf_append(
212                         opt->option->boot_args, "ramdisk_size=%s ", value);
213                 return;
214         }
215
216         if (streq(name, "literal")) {
217                 if (*opt->option->boot_args) {
218                         pb_log("%s: literal over writes '%s'\n", __func__,
219                                 opt->option->boot_args);
220                         talloc_free(opt->option->boot_args);
221                 }
222                 talloc_asprintf(opt->option, "%s ", value);
223                 return;
224         }
225
226         if (streq(name, "ramdisk")) {
227                 opt->option->boot_args = talloc_asprintf_append(
228                         opt->option->boot_args, "ramdisk=%s ", value);
229                 return;
230         }
231
232         if (streq(name, "read-only")) {
233                 opt->option->boot_args = talloc_asprintf_append(
234                         opt->option->boot_args, "ro ");
235                 return;
236         }
237
238         if (streq(name, "read-write")) {
239                 opt->option->boot_args = talloc_asprintf_append(
240                         opt->option->boot_args, "rw ");
241                 return;
242         }
243
244         if (streq(name, "root")) {
245                 opt->option->boot_args = talloc_asprintf_append(
246                         opt->option->boot_args, "root=%s ", value);
247                 return;
248         }
249
250         pb_log("%s: unknown name: %s\n", __func__, name);
251 }
252
253 static struct conf_global_option yaboot_global_options[] = {
254         { .name = "boot" },
255         { .name = "initrd" },
256         { .name = "partition" },
257         { .name = "video" },
258         { .name = NULL },
259 };
260
261 static const char *const yaboot_conf_files[] = {
262         "/yaboot.conf",
263         "/yaboot.cnf",
264         "/etc/yaboot.conf",
265         "/etc/yaboot.cnf",
266         "/suseboot/yaboot.cnf",
267         "/YABOOT.CONF",
268         "/YABOOT.CNF",
269         "/ETC/YABOOT.CONF",
270         "/ETC/YABOOT.CNF",
271         "/SUSEBOOT/YABOOT.CNF",
272         NULL
273 };
274
275 static const char *yaboot_known_names[] = {
276         "append",
277         "image",
278         "image[64bit]", /* SUSE extension */
279         "image[32bit]", /* SUSE extension */
280         "initrd",
281         "initrd-size",
282         "label",
283         "literal",
284         "ramdisk",
285         "read-only",
286         "read-write",
287         "root",
288         NULL
289 };
290
291 static int yaboot_parse(struct discover_context *dc, char *buf, int len)
292 {
293         struct conf_context *conf;
294         struct yaboot_state *state;
295
296         conf = talloc_zero(dc, struct conf_context);
297
298         if (!conf)
299                 return 0;
300
301         conf->dc = dc;
302         conf->global_options = yaboot_global_options,
303         conf_init_global_options(conf);
304         conf->get_pair = conf_get_pair_equal;
305         conf->process_pair = yaboot_process_pair;
306         conf->finish = yaboot_finish;
307         conf->parser_info = state = talloc_zero(conf, struct yaboot_state);
308
309         state->known_names = yaboot_known_names;
310
311         state->opt = NULL;
312
313         conf_parse_buf(conf, buf, len);
314
315         talloc_free(conf);
316         return 1;
317 }
318
319 static struct parser yaboot_parser = {
320         .name                   = "yaboot",
321         .method                 = CONF_METHOD_LOCAL_FILE,
322         .parse                  = yaboot_parse,
323         .filenames              = yaboot_conf_files,
324         .resolve_resource       = resolve_devpath_resource,
325 };
326
327 register_parser(yaboot_parser);