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