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