discover: Remove {U,}MOUNT_BIN defines
[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                 const char *g_boot = conf_get_global_option(conf, "boot");
89                 const char *g_part = conf_get_global_option(conf, "partition");
90
91                 /* First finish any previous image. */
92
93                 if (state->opt->boot_image_file)
94                         yaboot_finish(conf);
95
96                 /* Then start the new image. */
97
98                 if (g_boot && g_part) {
99                         char* dev = talloc_asprintf(NULL, "%s%s", g_boot,
100                                 g_part);
101
102                         state->opt->boot_image_file = resolve_path(state->opt,
103                                 value, dev);
104                         state->desc_image = talloc_asprintf(state->opt,
105                                 "%s%s", dev, value);
106                         talloc_free(dev);
107                 } else if (g_boot) {
108                         state->opt->boot_image_file = resolve_path(state->opt,
109                                 value, g_boot);
110                         state->desc_image = talloc_asprintf(state->opt,
111                                 "%s%s", g_boot, value);
112                 } else {
113                         state->opt->boot_image_file = resolve_path(state->opt,
114                                 value, conf->dc->device_path);
115                         state->desc_image = talloc_strdup(state->opt, value);
116                 }
117
118                 return;
119         }
120
121         /* Special processing for SUSE install CD. */
122
123         if (streq(name, "image[32bit]"))
124                 suse_fp = &suse_fp32;
125         else if (streq(name, "image[64bit]"))
126                 suse_fp = &suse_fp64;
127         else
128                 suse_fp = NULL;
129
130         if (suse_fp) {
131                 /* First finish any previous image. */
132
133                 if (state->opt->boot_image_file)
134                         yaboot_finish(conf);
135
136                 /* Then start the new image. */
137
138                 if (*value == '/') {
139                         state->opt->boot_image_file = resolve_path(state->opt,
140                                 value, conf->dc->device_path);
141                         state->desc_image = talloc_strdup(state->opt, value);
142                 } else {
143                         state->opt->boot_image_file = resolve_path(state->opt,
144                                 suse_fp->image, conf->dc->device_path);
145                         state->desc_image = talloc_strdup(state->opt,
146                                 suse_fp->image);
147
148                         state->opt->initrd_file = resolve_path(state->opt,
149                                 suse_fp->initrd, conf->dc->device_path);
150                         state->desc_initrd = talloc_asprintf(state, "initrd=%s",
151                                 suse_fp->initrd);
152                 }
153
154                 return;
155         }
156
157         if (!state->opt->boot_image_file) {
158                 pb_log("%s: unknown name: %s\n", __func__, name);
159                 return;
160         }
161
162         /* initrd */
163
164         if (streq(name, "initrd")) {
165                 const char *g_boot = conf_get_global_option(conf, "boot");
166                 const char *g_part = conf_get_global_option(conf, "partition");
167
168                 if (g_boot && g_part) {
169                         char* dev = talloc_asprintf(NULL, "%s%s", g_boot,
170                                 g_part);
171
172                         state->opt->initrd_file = resolve_path(state->opt,
173                                 value, dev);
174                         state->desc_initrd = talloc_asprintf(state,
175                                 "initrd=%s%s", dev, value);
176                         talloc_free(dev);
177                 } else if (g_boot) {
178                         state->opt->initrd_file = resolve_path(state->opt,
179                                 value, g_boot);
180                         state->desc_initrd = talloc_asprintf(state,
181                                 "initrd=%s%s", g_boot, value);
182                 } else {
183                         state->opt->initrd_file = resolve_path(state->opt,
184                                 value, conf->dc->device_path);
185                         state->desc_initrd = talloc_asprintf(state, "initrd=%s",
186                                 value);
187                 }
188                 return;
189         }
190
191         /* label */
192
193         if (streq(name, "label")) {
194                 state->opt->id = talloc_asprintf(state->opt, "%s#%s",
195                         conf->dc->device->id, value);
196                 state->opt->name = talloc_strdup(state->opt, value);
197                 return;
198         }
199
200         /* args */
201
202         if (streq(name, "append")) {
203                 state->opt->boot_args = talloc_asprintf_append(
204                         state->opt->boot_args, "%s ", value);
205                 return;
206         }
207
208         if (streq(name, "initrd-size")) {
209                 state->opt->boot_args = talloc_asprintf_append(
210                         state->opt->boot_args, "ramdisk_size=%s ", value);
211                 return;
212         }
213
214         if (streq(name, "literal")) {
215                 if (*state->opt->boot_args) {
216                         pb_log("%s: literal over writes '%s'\n", __func__,
217                                 state->opt->boot_args);
218                         talloc_free(state->opt->boot_args);
219                 }
220                 talloc_asprintf(state->opt, "%s ", value);
221                 return;
222         }
223
224         if (streq(name, "ramdisk")) {
225                 state->opt->boot_args = talloc_asprintf_append(
226                         state->opt->boot_args, "ramdisk=%s ", value);
227                 return;
228         }
229
230         if (streq(name, "read-only")) {
231                 state->opt->boot_args = talloc_asprintf_append(
232                         state->opt->boot_args, "ro ");
233                 return;
234         }
235
236         if (streq(name, "read-write")) {
237                 state->opt->boot_args = talloc_asprintf_append(
238                         state->opt->boot_args, "rw ");
239                 return;
240         }
241
242         if (streq(name, "root")) {
243                 state->opt->boot_args = talloc_asprintf_append(
244                         state->opt->boot_args, "root=%s ", value);
245                 return;
246         }
247
248         pb_log("%s: unknown name: %s\n", __func__, name);
249 }
250
251 static struct conf_global_option yaboot_global_options[] = {
252         { .name = "boot" },
253         { .name = "initrd" },
254         { .name = "partition" },
255         { .name = "video" },
256         { .name = NULL },
257 };
258
259 static const char *const yaboot_conf_files[] = {
260         "/yaboot.conf",
261         "/yaboot.cnf",
262         "/etc/yaboot.conf",
263         "/etc/yaboot.cnf",
264         "/suseboot/yaboot.cnf",
265         "/YABOOT.CONF",
266         "/YABOOT.CNF",
267         "/ETC/YABOOT.CONF",
268         "/ETC/YABOOT.CNF",
269         "/SUSEBOOT/YABOOT.CNF",
270         NULL
271 };
272
273 static const char *yaboot_known_names[] = {
274         "append",
275         "image",
276         "image[64bit]", /* SUSE extension */
277         "image[32bit]", /* SUSE extension */
278         "initrd",
279         "initrd-size",
280         "label",
281         "literal",
282         "ramdisk",
283         "read-only",
284         "read-write",
285         "root",
286         NULL
287 };
288
289 static int yaboot_parse(struct discover_context *dc)
290 {
291         struct conf_context *conf;
292         struct yaboot_state *state;
293         int rc;
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->conf_files = yaboot_conf_files,
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         /* opt is persistent, so must be associated with device */
312
313         state->opt = talloc_zero(conf->dc->device, struct boot_option);
314         state->opt->boot_args = talloc_strdup(state->opt, "");
315
316         rc = conf_parse(conf);
317
318         talloc_free(conf);
319         return rc;
320 }
321
322 define_parser(yaboot, yaboot_parse);