X-Git-Url: http://git.ozlabs.org/?p=petitboot;a=blobdiff_plain;f=discover%2Fyaboot-parser.c;h=65252029952acfad51a4416567ed4698db621cc5;hp=27b4b782306594c05cbaec0fd3b01bc826a409de;hb=c7c1f9f2270a753f8515d523f6b55b6d077ae6c3;hpb=32e6a41f33e5576716b351bd473a27939fe94fa1 diff --git a/discover/yaboot-parser.c b/discover/yaboot-parser.c index 27b4b78..6525202 100644 --- a/discover/yaboot-parser.c +++ b/discover/yaboot-parser.c @@ -1,235 +1,324 @@ +#define _GNU_SOURCE -#include "parser.h" -#include "params.h" -#include "paths.h" -#include "yaboot-cfg.h" - +#include #include -#include #include -#include -#include -#include -#include -#include -#include - -static struct device *dev; -static char *devpath; -static char *defimage; - -char * -make_params(char *label, char *params) + +#include "log/log.h" +#include "talloc/talloc.h" +#include "types/types.h" +#include "parser-conf.h" +#include "parser-utils.h" +#include "resource.h" + +struct yaboot_state { + struct discover_boot_option *opt; + char *desc_image; + char *desc_initrd; + int globals_done; + const char *const *known_names; +}; + +static void yaboot_finish(struct conf_context *conf) { - char *p, *q; - static char buffer[2048]; - - q = buffer; - *q = 0; - - p = cfg_get_strg(label, "literal"); - if (p) { - strcpy(q, p); - q = strchr(q, 0); - if (params) { - if (*p) - *q++ = ' '; - strcpy(q, params); - } - return buffer; - } - - p = cfg_get_strg(label, "root"); - if (p) { - strcpy (q, "root="); - strcpy (q + 5, p); - q = strchr (q, 0); - *q++ = ' '; - } - if (cfg_get_flag(label, "read-only")) { - strcpy (q, "ro "); - q += 3; - } - if (cfg_get_flag(label, "read-write")) { - strcpy (q, "rw "); - q += 3; - } - p = cfg_get_strg(label, "ramdisk"); - if (p) { - strcpy (q, "ramdisk="); - strcpy (q + 8, p); - q = strchr (q, 0); - *q++ = ' '; - } - p = cfg_get_strg(label, "initrd-size"); - if (p) { - strcpy (q, "ramdisk_size="); - strcpy (q + 13, p); - q = strchr (q, 0); - *q++ = ' '; - } - if (cfg_get_flag(label, "novideo")) { - strcpy (q, "video=ofonly"); - q = strchr (q, 0); - *q++ = ' '; - } - p = cfg_get_strg (label, "append"); - if (p) { - strcpy (q, p); - q = strchr (q, 0); - *q++ = ' '; - } - *q = 0; - if (params) - strcpy(q, params); - - return buffer; + struct yaboot_state *state = conf->parser_info; + struct device *dev = conf->dc->device->device; + struct boot_option *opt; + + if (!state->desc_image) { + pb_log("%s: %s: no image found\n", __func__, dev->id); + return; + } + + assert(state->opt); + + opt = state->opt->option; + assert(opt); + assert(opt->name); + assert(opt->boot_args); + + opt->description = talloc_asprintf(opt, "%s %s %s", + state->desc_image, + (state->desc_initrd ? state->desc_initrd : ""), + opt->boot_args); + + talloc_free(state->desc_initrd); + state->desc_initrd = NULL; + + conf_strip_str(opt->boot_args); + conf_strip_str(opt->description); + + /* opt is persistent, so must be associated with device */ + + discover_context_add_boot_option(conf->dc, state->opt); + + state->opt = discover_boot_option_create(conf->dc, conf->dc->device); + state->opt->option->boot_args = talloc_strdup(state->opt->option, ""); } -static int check_and_add_device(struct device *dev) +static struct resource *create_yaboot_devpath_resource( + struct conf_context *conf, + const char *path, char **desc_str) { - if (!dev->icon_file) - dev->icon_file = strdup(generic_icon_file(guess_device_type())); + const char *g_boot = conf_get_global_option(conf, "boot"); + const char *g_part = conf_get_global_option(conf, "partition"); + struct resource *res; + char *devpath; + + if (g_boot && g_part) { + devpath = talloc_asprintf(conf, + "%s%s:%s", g_boot, g_part, path); + } else if (g_boot) { + devpath = talloc_asprintf(conf, "%s:%s", g_boot, path); + } else { + devpath = talloc_strdup(conf, path); + } + + res = create_devpath_resource(conf->dc, conf->dc->device, devpath); - return !add_device(dev); + if (desc_str) + *desc_str = devpath; + else + talloc_free(devpath); + + return res; } -void process_image(char *label) + +static void yaboot_process_pair(struct conf_context *conf, const char *name, + char *value) { - struct boot_option opt; - char *cfgopt; + struct yaboot_state *state = conf->parser_info; + struct discover_boot_option *opt = state->opt; + struct fixed_pair { + const char *image; + const char *initrd; + }; + static const struct fixed_pair suse_fp32 = { + .image = "/suseboot/vmlinux32", + .initrd = "/suseboot/initrd32", + }; + static const struct fixed_pair suse_fp64 = { + .image = "/suseboot/vmlinux64", + .initrd = "/suseboot/initrd64", + }; + const struct fixed_pair *suse_fp; - memset(&opt, 0, sizeof(opt)); + /* fixup for bare values */ - opt.name = label; - cfgopt = cfg_get_strg(label, "image"); - opt.boot_image_file = resolve_path(cfgopt, devpath); - if (cfgopt == defimage) - pb_log("This one is default. What do we do about it?\n"); + if (!name) + name = value; - cfgopt = cfg_get_strg(label, "initrd"); - if (cfgopt) - opt.initrd_file = resolve_path(cfgopt, devpath); + if (!state->globals_done && conf_set_global_option(conf, name, value)) + return; - opt.boot_args = make_params(label, NULL); + if (!conf_param_in_list(state->known_names, name)) + return; - add_boot_option(&opt); + state->globals_done = 1; - if (opt.initrd_file) - free(opt.initrd_file); -} + /* image */ -static int yaboot_parse(const char *device) -{ - char *filepath; - char *conf_file; - char *tmpstr; - ssize_t conf_len; - int fd; - struct stat st; - char *label; - - devpath = strdup(device); - - filepath = resolve_path("/etc/yaboot.conf", devpath); - - fd = open(filepath, O_RDONLY); - if (fd < 0) { - free(filepath); - filepath = resolve_path("/yaboot.conf", devpath); - fd = open(filepath, O_RDONLY); - - if (fd < 0) - return 0; + if (streq(name, "image")) { + + /* First finish any previous image. */ + if (opt->boot_image) + yaboot_finish(conf); + + /* Then start the new image. */ + opt->boot_image = create_yaboot_devpath_resource(conf, + value, &state->desc_image); + + return; } - if (fstat(fd, &st)) { - close(fd); - return 0; + /* Special processing for SUSE install CD. */ + + if (streq(name, "image[32bit]")) + suse_fp = &suse_fp32; + else if (streq(name, "image[64bit]")) + suse_fp = &suse_fp64; + else + suse_fp = NULL; + + if (suse_fp) { + /* First finish any previous image. */ + + if (opt->boot_image) + yaboot_finish(conf); + + /* Then start the new image. */ + + if (*value == '/') { + opt->boot_image = create_yaboot_devpath_resource( + conf, value, &state->desc_image); + } else { + char *tmp; + + opt->boot_image = create_yaboot_devpath_resource( + conf, suse_fp->image, + &state->desc_image); + + opt->initrd = create_yaboot_devpath_resource( + conf, suse_fp->initrd, &tmp); + + state->desc_initrd = talloc_asprintf(opt, + "initrd=%s", tmp); + talloc_free(tmp); + } + + return; } - conf_file = malloc(st.st_size+1); - if (!conf_file) { - close(fd); - return 0; + if (!opt->boot_image) { + pb_log("%s: unknown name: %s\n", __func__, name); + return; } - - conf_len = read(fd, conf_file, st.st_size); - if (conf_len < 0) { - close(fd); - return 0; + + /* initrd */ + + if (streq(name, "initrd")) { + opt->initrd = create_yaboot_devpath_resource(conf, + value, &state->desc_image); + + return; } - conf_file[conf_len] = 0; - close(fd); - - if (cfg_parse(filepath, conf_file, conf_len)) { - pb_log("Error parsing yaboot.conf\n"); - return 0; + /* label */ + + if (streq(name, "label")) { + opt->option->id = talloc_asprintf(opt->option, "%s#%s", + conf->dc->device->device->id, value); + opt->option->name = talloc_strdup(opt->option, value); + return; + } + + /* args */ + + if (streq(name, "append")) { + opt->option->boot_args = talloc_asprintf_append( + opt->option->boot_args, "%s ", value); + return; } - free(filepath); - - dev = malloc(sizeof(*dev)); - memset(dev, 0, sizeof(*dev)); - dev->id = strdup(devpath); - if (cfg_get_strg(0, "init-message")) { - char *newline; - dev->description = strdup(cfg_get_strg(0, "init-message")); - newline = strchr(dev->description, '\n'); - if (newline) - *newline = 0; + if (streq(name, "initrd-size")) { + opt->option->boot_args = talloc_asprintf_append( + opt->option->boot_args, "ramdisk_size=%s ", value); + return; } - dev->icon_file = strdup(generic_icon_file(guess_device_type())); - - /* If we have a 'partiton=' directive, update the default devpath - * to use that instead of the current device */ - tmpstr = cfg_get_strg(0, "partition"); - if (tmpstr) { - char *endp; - int partnr = strtol(tmpstr, &endp, 10); - if (endp != tmpstr && !*endp) { - char *new_dev, *tmp; - - new_dev = malloc(strlen(devpath) + strlen(tmpstr) + 1); - if (!new_dev) - return 0; - - strcpy(new_dev, devpath); - - /* Strip digits (partition number) from string */ - endp = new_dev + strlen(devpath) - 1; - while (isdigit(*endp)) - *(endp--) = 0; - - /* and add our own... */ - sprintf(endp + 1, "%d", partnr); - - tmp = devpath; - devpath = parse_device_path(new_dev, devpath); - free(tmp); - free(new_dev); + + if (streq(name, "literal")) { + if (*opt->option->boot_args) { + pb_log("%s: literal over writes '%s'\n", __func__, + opt->option->boot_args); + talloc_free(opt->option->boot_args); } + talloc_asprintf(opt->option, "%s ", value); + return; } - defimage = cfg_get_default(); - if (!defimage) - return 0; - defimage = cfg_get_strg(defimage, "image"); + if (streq(name, "ramdisk")) { + opt->option->boot_args = talloc_asprintf_append( + opt->option->boot_args, "ramdisk=%s ", value); + return; + } + + if (streq(name, "read-only")) { + opt->option->boot_args = talloc_asprintf_append( + opt->option->boot_args, "ro "); + return; + } + + if (streq(name, "read-write")) { + opt->option->boot_args = talloc_asprintf_append( + opt->option->boot_args, "rw "); + return; + } + + if (streq(name, "root")) { + opt->option->boot_args = talloc_asprintf_append( + opt->option->boot_args, "root=%s ", value); + return; + } + + pb_log("%s: unknown name: %s\n", __func__, name); +} + +static struct conf_global_option yaboot_global_options[] = { + { .name = "boot" }, + { .name = "initrd" }, + { .name = "partition" }, + { .name = "video" }, + { .name = NULL }, +}; + +static const char *const yaboot_conf_files[] = { + "/yaboot.conf", + "/yaboot.cnf", + "/etc/yaboot.conf", + "/etc/yaboot.cnf", + "/suseboot/yaboot.cnf", + "/YABOOT.CONF", + "/YABOOT.CNF", + "/ETC/YABOOT.CONF", + "/ETC/YABOOT.CNF", + "/SUSEBOOT/YABOOT.CNF", + NULL +}; + +static const char *yaboot_known_names[] = { + "append", + "image", + "image[64bit]", /* SUSE extension */ + "image[32bit]", /* SUSE extension */ + "initrd", + "initrd-size", + "label", + "literal", + "ramdisk", + "read-only", + "read-write", + "root", + NULL +}; - label = cfg_next_image(NULL); - if (!label || !check_and_add_device(dev)) +static int yaboot_parse(struct discover_context *dc, char *buf, int len) +{ + struct conf_context *conf; + struct yaboot_state *state; + + conf = talloc_zero(dc, struct conf_context); + + if (!conf) return 0; - do { - process_image(label); - } while ((label = cfg_next_image(label))); + conf->dc = dc; + conf->global_options = yaboot_global_options, + conf_init_global_options(conf); + conf->get_pair = conf_get_pair_equal; + conf->process_pair = yaboot_process_pair; + conf->finish = yaboot_finish; + conf->parser_info = state = talloc_zero(conf, struct yaboot_state); + + state->known_names = yaboot_known_names; + /* opt is persistent, so must be associated with device */ + + state->opt = discover_boot_option_create(conf->dc, conf->dc->device); + state->opt->option->boot_args = talloc_strdup(state->opt->option, ""); + + conf_parse_buf(conf, buf, len); + + talloc_free(conf); return 1; } -struct parser yaboot_parser = { - .name = "yaboot.conf parser", - .priority = 99, - .parse = yaboot_parse +static struct parser yaboot_parser = { + .name = "yaboot", + .method = CONF_METHOD_LOCAL_FILE, + .parse = yaboot_parse, + .filenames = yaboot_conf_files, + .resolve_resource = resolve_devpath_resource, }; + +register_parser(yaboot_parser);