Fix parsing for OpenSUSE
[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 "pb-protocol/pb-protocol.h"
10 #include "parser-conf.h"
11 #include "parser-utils.h"
12 #include "paths.h"
13
14 struct yaboot_state {
15         struct boot_option *opt;
16         const 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
26         if (!state->desc_image) {
27                 pb_log("%s: %s: no image found\n", __func__,
28                         conf->dc->device->id);
29                 return;
30         }
31
32         assert(state->opt);
33         assert(state->opt->name);
34         assert(state->opt->boot_args);
35
36         state->opt->description = talloc_asprintf(state->opt, "%s %s %s",
37                 state->desc_image,
38                 (state->desc_initrd ? state->desc_initrd : ""),
39                 state->opt->boot_args);
40
41         talloc_free(state->desc_initrd);
42         state->desc_initrd = NULL;
43
44         conf_strip_str(state->opt->boot_args);
45         conf_strip_str(state->opt->description);
46
47         /* opt is persistent, so must be associated with device */
48
49         device_add_boot_option(conf->dc->device, state->opt);
50         state->opt = talloc_zero(conf->dc->device, struct boot_option);
51         state->opt->boot_args = talloc_strdup(state->opt, "");
52 }
53
54 static void yaboot_process_pair(struct conf_context *conf, const char *name,
55                 char *value)
56 {
57         struct yaboot_state *state = conf->parser_info;
58         struct fixed_pair {
59                 const char *image;
60                 const char *initrd;
61         };
62         static const struct fixed_pair suse_fp32 = {
63                 .image = "/suseboot/vmlinux32",
64                 .initrd = "/suseboot/initrd32",
65         };
66         static const struct fixed_pair suse_fp64 = {
67                 .image = "/suseboot/vmlinux64",
68                 .initrd = "/suseboot/initrd64",
69         };
70         const struct fixed_pair *suse_fp;
71
72         /* fixup for bare values */
73
74         if (!name)
75                 name = value;
76
77         if (!state->globals_done && conf_set_global_option(conf, name, value))
78                 return;
79
80         if (!conf_param_in_list(state->known_names, name))
81                 return;
82
83         state->globals_done = 1;
84
85         /* image */
86
87         if (streq(name, "image")) {
88
89                 /* First finish any previous image. */
90
91                 if (state->opt->boot_image_file)
92                         yaboot_finish(conf);
93
94                 /* Then start the new image. */
95
96                 state->opt->boot_image_file = resolve_path(state->opt, value,
97                         conf->dc->device_path);
98                 state->desc_image = talloc_strdup(state->opt, value);
99
100                 return;
101         }
102
103         /* Special processing for SUSE install CD. */
104
105         if (streq(name, "image[32bit]"))
106                 suse_fp = &suse_fp32;
107         else if (streq(name, "image[64bit]"))
108                 suse_fp = &suse_fp64;
109         else
110                 suse_fp = NULL;
111
112         if (suse_fp) {
113                 /* First finish any previous image. */
114
115                 if (state->opt->boot_image_file)
116                         yaboot_finish(conf);
117
118                 /* Then start the new image. */
119
120                 if (*value == '/') {
121                         state->opt->boot_image_file = resolve_path(state->opt,
122                                 value, conf->dc->device_path);
123                         state->desc_image = talloc_strdup(state->opt, value);
124                 } else {
125                         state->opt->boot_image_file = resolve_path(state->opt,
126                                 suse_fp->image, conf->dc->device_path);
127                         state->desc_image = talloc_strdup(state->opt,
128                                 suse_fp->image);
129
130                         state->opt->initrd_file = resolve_path(state->opt,
131                                 suse_fp->initrd, conf->dc->device_path);
132                         state->desc_initrd = talloc_asprintf(state, "initrd=%s",
133                                 suse_fp->initrd);
134                 }
135
136                 return;
137         }
138
139         if (!state->opt->boot_image_file) {
140                 pb_log("%s: unknown name: %s\n", __func__, name);
141                 return;
142         }
143
144         /* initrd */
145
146         if (streq(name, "initrd")) {
147                 state->opt->initrd_file = resolve_path(state->opt,
148                         value, conf->dc->device_path);
149                 state->desc_initrd = talloc_asprintf(state, "initrd=%s",
150                         value);
151                 return;
152         }
153
154         /* label */
155
156         if (streq(name, "label")) {
157                 state->opt->id = talloc_asprintf(state->opt, "%s#%s",
158                         conf->dc->device->id, value);
159                 state->opt->name = talloc_strdup(state->opt, value);
160                 return;
161         }
162
163         /* args */
164
165         if (streq(name, "append")) {
166                 state->opt->boot_args = talloc_asprintf_append(
167                         state->opt->boot_args, "%s ", value);
168                 return;
169         }
170
171         if (streq(name, "initrd-size")) {
172                 state->opt->boot_args = talloc_asprintf_append(
173                         state->opt->boot_args, "ramdisk_size=%s ", value);
174                 return;
175         }
176
177         if (streq(name, "literal")) {
178                 if (*state->opt->boot_args) {
179                         pb_log("%s: literal over writes '%s'\n", __func__,
180                                 state->opt->boot_args);
181                         talloc_free(state->opt->boot_args);
182                 }
183                 talloc_asprintf(state->opt, "%s ", value);
184                 return;
185         }
186
187         if (streq(name, "ramdisk")) {
188                 state->opt->boot_args = talloc_asprintf_append(
189                         state->opt->boot_args, "ramdisk=%s ", value);
190                 return;
191         }
192
193         if (streq(name, "read-only")) {
194                 state->opt->boot_args = talloc_asprintf_append(
195                         state->opt->boot_args, "ro ");
196                 return;
197         }
198
199         if (streq(name, "read-write")) {
200                 state->opt->boot_args = talloc_asprintf_append(
201                         state->opt->boot_args, "rw ");
202                 return;
203         }
204
205         if (streq(name, "root")) {
206                 state->opt->boot_args = talloc_asprintf_append(
207                         state->opt->boot_args, "root=%s ", value);
208                 return;
209         }
210
211         pb_log("%s: unknown name: %s\n", __func__, name);
212 }
213
214 static struct conf_global_option yaboot_global_options[] = {
215         { .name = "boot" },
216         { .name = "initrd" },
217         { .name = "partition" },
218         { .name = "video" },
219         { .name = NULL },
220 };
221
222 static const char *const yaboot_conf_files[] = {
223         "/yaboot.conf",
224         "/yaboot.cnf",
225         "/etc/yaboot.conf",
226         "/etc/yaboot.cnf",
227         "/suseboot/yaboot.cnf",
228         "/YABOOT.CONF",
229         "/YABOOT.CNF",
230         "/ETC/YABOOT.CONF",
231         "/ETC/YABOOT.CNF",
232         "/SUSEBOOT/YABOOT.CNF",
233         NULL
234 };
235
236 static const char *yaboot_known_names[] = {
237         "append",
238         "image",
239         "image[64bit]", /* SUSE extension */
240         "image[32bit]", /* SUSE extension */
241         "initrd",
242         "initrd-size",
243         "label",
244         "literal",
245         "ramdisk",
246         "read-only",
247         "read-write",
248         "root",
249         NULL
250 };
251
252 static int yaboot_parse(struct discover_context *dc)
253 {
254         struct conf_context *conf;
255         struct yaboot_state *state;
256         int rc;
257
258         conf = talloc_zero(dc, struct conf_context);
259
260         if (!conf)
261                 return -1;
262
263         conf->dc = dc;
264         conf->global_options = yaboot_global_options,
265         conf_init_global_options(conf);
266         conf->conf_files = yaboot_conf_files,
267         conf->process_pair = yaboot_process_pair;
268         conf->finish = yaboot_finish;
269         conf->parser_info = state = talloc_zero(conf, struct yaboot_state);
270
271         state->known_names = yaboot_known_names;
272
273         /* opt is persistent, so must be associated with device */
274
275         state->opt = talloc_zero(conf->dc->device, struct boot_option);
276         state->opt->boot_args = talloc_strdup(state->opt, "");
277
278         rc = conf_parse(conf);
279
280         talloc_free(conf);
281         return rc;
282 }
283
284 define_parser(yaboot, 99, yaboot_parse);