11 #include <sys/types.h>
14 #include <talloc/talloc.h>
17 #include "pb-protocol/pb-protocol.h"
20 #include "parser-utils.h"
21 #include "device-handler.h"
25 struct kboot_context {
26 struct discover_context *discover;
30 struct global_option {
37 static int param_is_ignored(const char *param)
39 static const char *ignored_options[] =
40 { "message", "timeout", "default", NULL };
43 for (str = ignored_options; *str; str++)
44 if (streq(*str, param))
50 * Splits a name=value pair, with value terminated by @term (or nul). if there
51 * is no '=', then only the value is populated, and *name is set to NULL. The
52 * string is modified in place.
54 * Returns the next byte to process, or null if we've hit the end of the
58 static char *get_param_pair(char *str, char **name_out, char **value_out,
61 char *sep, *tmp, *name, *value;
63 /* terminate the value */
64 tmp = strchr(str, terminator);
70 sep = strchr(str, '=');
74 return tmp ? tmp + 1 : NULL;
77 /* terminate the name */
80 /* remove leading spaces */
81 for (name = str; isspace(*name); name++);
82 for (value = sep + 1; isspace(*value); value++);
84 /* .. and trailing ones.. */
85 for (sep--; isspace(*sep); sep--)
87 for (sep = value + strlen(value) - 1; isspace(*sep); sep--)
93 return tmp ? tmp + 1 : NULL;
96 static struct global_option global_options[] = {
104 * Check if an option (name=value) is a global option. If so, store it in
105 * the global options table, and return 1. Otherwise, return 0.
107 static int check_for_global_option(struct kboot_context *ctx,
108 const char *name, const char *value)
112 for (i = 0; i < ctx->n_global_options; i++) {
113 if (!strcmp(name, ctx->global_options[i].name)) {
114 global_options[i].value = strdup(value);
121 static char *get_global_option(
122 struct kboot_context *ctx __attribute__((unused)),
127 for (i = 0; global_options[i].name ;i++)
128 if (!strcmp(name, global_options[i].name))
129 return global_options[i].value;
134 static int parse_option(struct kboot_context *kboot_ctx, char *opt_name,
137 char *pos, *name, *value, *root, *initrd, *cmdline, *tmp;
138 struct boot_option *opt;
140 root = initrd = cmdline = NULL;
142 /* remove quotes around the value */
143 while (*config == '"' || *config == '\'')
146 pos = config + strlen(config) - 1;
147 while (*pos == '"' || *pos == '\'')
153 pos = strchr(config, ' ');
155 opt = talloc_zero(kboot_ctx, struct boot_option);
156 opt->id = talloc_asprintf(opt, "%s#%s",
157 kboot_ctx->discover->device->id, opt_name);
158 opt->name = talloc_strdup(opt, opt_name);
160 /* if there's no space, it's only a kernel image with no params */
162 opt->boot_image_file = resolve_path(opt, config,
163 kboot_ctx->discover->device_path);
164 opt->description = talloc_strdup(opt, config);
169 opt->boot_image_file = resolve_path(opt, config,
170 kboot_ctx->discover->device_path);
172 cmdline = talloc_array(opt, char, buf_size);
176 pos = get_param_pair(pos, &name, &value, ' ');
179 strcat(cmdline, " ");
180 strcat(cmdline, value);
182 } else if (streq(name, "initrd")) {
185 } else if (streq(name, "root")) {
189 strcat(cmdline, " ");
191 strcat(cmdline, name);
196 root = get_global_option(kboot_ctx, "root");
198 initrd = get_global_option(kboot_ctx, "initrd");
201 tmp = talloc_asprintf(opt, "initrd=%s %s", initrd, cmdline);
202 talloc_free(cmdline);
205 opt->initrd_file = resolve_path(opt, initrd,
206 kboot_ctx->discover->device_path);
210 tmp = talloc_asprintf(opt, "root=%s %s", root, cmdline);
211 talloc_free(cmdline);
215 /* if there's an initrd but no root, fake up /dev/ram0 */
216 tmp = talloc_asprintf(opt, "root=/dev/ram0 %s", cmdline);
217 talloc_free(cmdline);
221 opt->boot_args = cmdline;
223 opt->description = talloc_asprintf(opt, "%s %s",
224 config, opt->boot_args);
227 device_add_boot_option(kboot_ctx->discover->device, opt);
231 static void parse_buf(struct kboot_context *kboot_ctx)
233 char *pos, *name, *value;
235 for (pos = kboot_ctx->buf; pos;) {
236 pos = get_param_pair(pos, &name, &value, '\n');
238 if (name == NULL || param_is_ignored(name))
244 if (check_for_global_option(kboot_ctx, name, value))
247 parse_option(kboot_ctx, name, value);
252 static int kboot_parse(struct discover_context *ctx)
254 static const char *const conf_names[] = {
258 struct kboot_context *kboot_ctx;
266 kboot_ctx = talloc_zero(ctx, struct kboot_context);
267 kboot_ctx->discover = ctx;
269 for (i = 0, len = 0; i < sizeof(conf_names) / sizeof(conf_names[0]);
271 char *filepath = resolve_path(kboot_ctx, conf_names[i],
274 pb_log("%s: try: %s\n", __func__, filepath);
276 fd = open(filepath, O_RDONLY);
278 pb_log("%s: open failed: %s : %s\n", __func__, filepath,
282 if (fstat(fd, &stat)) {
283 pb_log("%s: fstat failed: %s : %s\n", __func__,
284 filepath, strerror(errno));
288 kboot_ctx->buf = talloc_array(kboot_ctx, char,
291 len = read(fd, kboot_ctx->buf, stat.st_size);
293 pb_log("%s: read failed: %s : %s\n", __func__, filepath,
297 kboot_ctx->buf[len] = 0;
303 if (!ctx->device->icon_file)
304 ctx->device->icon_file = talloc_strdup(ctx,
305 generic_icon_file(guess_device_type(ctx)));
307 parse_buf(kboot_ctx);
312 pb_log("%s: %s\n", __func__, (rc ? "ok" : "failed"));
316 talloc_free(kboot_ctx);
320 define_parser(kboot, 98, kboot_parse);