X-Git-Url: https://git.ozlabs.org/?p=petitboot;a=blobdiff_plain;f=discover%2Fyaboot-parser.c;h=1000505b9681df66da2bfff4e17709d503c0175e;hp=27b4b782306594c05cbaec0fd3b01bc826a409de;hb=49ebdeb3ffc0224f3f4bbf1f00beaa5007d38fd5;hpb=32e6a41f33e5576716b351bd473a27939fe94fa1 diff --git a/discover/yaboot-parser.c b/discover/yaboot-parser.c index 27b4b78..1000505 100644 --- a/discover/yaboot-parser.c +++ b/discover/yaboot-parser.c @@ -1,235 +1,321 @@ +#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) -{ - 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; -} -static int check_and_add_device(struct device *dev) -{ - if (!dev->icon_file) - dev->icon_file = strdup(generic_icon_file(guess_device_type())); +#include "log/log.h" +#include "talloc/talloc.h" +#include "pb-protocol/pb-protocol.h" +#include "parser-conf.h" +#include "parser-utils.h" +#include "paths.h" - return !add_device(dev); -} +struct yaboot_state { + struct boot_option *opt; + const char *desc_image; + char *desc_initrd; + int globals_done; + const char *const *known_names; +}; -void process_image(char *label) +static void yaboot_finish(struct conf_context *conf) { - struct boot_option opt; - char *cfgopt; + struct yaboot_state *state = conf->parser_info; - memset(&opt, 0, sizeof(opt)); + if (!state->desc_image) { + pb_log("%s: %s: no image found\n", __func__, + conf->dc->device->id); + return; + } - 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"); + assert(state->opt); + assert(state->opt->name); + assert(state->opt->boot_args); - cfgopt = cfg_get_strg(label, "initrd"); - if (cfgopt) - opt.initrd_file = resolve_path(cfgopt, devpath); + state->opt->description = talloc_asprintf(state->opt, "%s %s %s", + state->desc_image, + (state->desc_initrd ? state->desc_initrd : ""), + state->opt->boot_args); - opt.boot_args = make_params(label, NULL); + talloc_free(state->desc_initrd); + state->desc_initrd = NULL; - add_boot_option(&opt); + conf_strip_str(state->opt->boot_args); + conf_strip_str(state->opt->description); - if (opt.initrd_file) - free(opt.initrd_file); + /* opt is persistent, so must be associated with device */ + + device_add_boot_option(conf->dc->device, state->opt); + state->opt = talloc_zero(conf->dc->device, struct boot_option); + state->opt->boot_args = talloc_strdup(state->opt, ""); } -static int yaboot_parse(const char *device) +static void yaboot_process_pair(struct conf_context *conf, const char *name, + char *value) { - 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; + struct yaboot_state *state = conf->parser_info; + 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; + + /* fixup for bare values */ + + if (!name) + name = value; + + if (!state->globals_done && conf_set_global_option(conf, name, value)) + return; + + if (!conf_param_in_list(state->known_names, name)) + return; + + state->globals_done = 1; + + /* image */ + + if (streq(name, "image")) { + const char *g_boot = conf_get_global_option(conf, "boot"); + const char *g_part = conf_get_global_option(conf, "partition"); + + /* First finish any previous image. */ + + if (state->opt->boot_image_file) + yaboot_finish(conf); + + /* Then start the new image. */ + + if (g_boot && g_part) { + char* dev = talloc_asprintf(NULL, "%s%s", g_boot, + g_part); + + state->opt->boot_image_file = resolve_path(state->opt, + value, dev); + state->desc_image = talloc_asprintf(state->opt, + "%s%s", dev, value); + talloc_free(dev); + } else if (g_boot) { + state->opt->boot_image_file = resolve_path(state->opt, + value, g_boot); + state->desc_image = talloc_asprintf(state->opt, + "%s%s", g_boot, value); + } else { + state->opt->boot_image_file = resolve_path(state->opt, + value, conf->dc->device_path); + state->desc_image = talloc_strdup(state->opt, value); + } + + return; + } + + /* 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 (state->opt->boot_image_file) + yaboot_finish(conf); + + /* Then start the new image. */ + + if (*value == '/') { + state->opt->boot_image_file = resolve_path(state->opt, + value, conf->dc->device_path); + state->desc_image = talloc_strdup(state->opt, value); + } else { + state->opt->boot_image_file = resolve_path(state->opt, + suse_fp->image, conf->dc->device_path); + state->desc_image = talloc_strdup(state->opt, + suse_fp->image); + + state->opt->initrd_file = resolve_path(state->opt, + suse_fp->initrd, conf->dc->device_path); + state->desc_initrd = talloc_asprintf(state, "initrd=%s", + suse_fp->initrd); + } + + return; } - if (fstat(fd, &st)) { - close(fd); - return 0; + if (!state->opt->boot_image_file) { + pb_log("%s: unknown name: %s\n", __func__, name); + return; } - conf_file = malloc(st.st_size+1); - if (!conf_file) { - close(fd); - return 0; + /* initrd */ + + if (streq(name, "initrd")) { + const char *g_boot = conf_get_global_option(conf, "boot"); + const char *g_part = conf_get_global_option(conf, "partition"); + + if (g_boot && g_part) { + char* dev = talloc_asprintf(NULL, "%s%s", g_boot, + g_part); + + state->opt->initrd_file = resolve_path(state->opt, + value, dev); + state->desc_initrd = talloc_asprintf(state, + "initrd=%s%s", dev, value); + talloc_free(dev); + } else if (g_boot) { + state->opt->initrd_file = resolve_path(state->opt, + value, g_boot); + state->desc_initrd = talloc_asprintf(state, + "initrd=%s%s", g_boot, value); + } else { + state->opt->initrd_file = resolve_path(state->opt, + value, conf->dc->device_path); + state->desc_initrd = talloc_asprintf(state, "initrd=%s", + value); + } + return; } - - conf_len = read(fd, conf_file, st.st_size); - if (conf_len < 0) { - close(fd); - return 0; + + /* label */ + + if (streq(name, "label")) { + state->opt->id = talloc_asprintf(state->opt, "%s#%s", + conf->dc->device->id, value); + state->opt->name = talloc_strdup(state->opt, value); + 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; + /* args */ + + if (streq(name, "append")) { + state->opt->boot_args = talloc_asprintf_append( + state->opt->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")) { + state->opt->boot_args = talloc_asprintf_append( + state->opt->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 (*state->opt->boot_args) { + pb_log("%s: literal over writes '%s'\n", __func__, + state->opt->boot_args); + talloc_free(state->opt->boot_args); } + talloc_asprintf(state->opt, "%s ", value); + return; } - defimage = cfg_get_default(); - if (!defimage) - return 0; - defimage = cfg_get_strg(defimage, "image"); + if (streq(name, "ramdisk")) { + state->opt->boot_args = talloc_asprintf_append( + state->opt->boot_args, "ramdisk=%s ", value); + return; + } + + if (streq(name, "read-only")) { + state->opt->boot_args = talloc_asprintf_append( + state->opt->boot_args, "ro "); + return; + } - label = cfg_next_image(NULL); - if (!label || !check_and_add_device(dev)) - return 0; + if (streq(name, "read-write")) { + state->opt->boot_args = talloc_asprintf_append( + state->opt->boot_args, "rw "); + return; + } - do { - process_image(label); - } while ((label = cfg_next_image(label))); + if (streq(name, "root")) { + state->opt->boot_args = talloc_asprintf_append( + state->opt->boot_args, "root=%s ", value); + return; + } - return 1; + pb_log("%s: unknown name: %s\n", __func__, name); } -struct parser yaboot_parser = { - .name = "yaboot.conf parser", - .priority = 99, - .parse = yaboot_parse +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 +}; + +static int yaboot_parse(struct discover_context *dc) +{ + struct conf_context *conf; + struct yaboot_state *state; + int rc; + + conf = talloc_zero(dc, struct conf_context); + + if (!conf) + return -1; + + conf->dc = dc; + conf->global_options = yaboot_global_options, + conf_init_global_options(conf); + conf->conf_files = yaboot_conf_files, + 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 = talloc_zero(conf->dc->device, struct boot_option); + state->opt->boot_args = talloc_strdup(state->opt, ""); + + rc = conf_parse(conf); + + talloc_free(conf); + return rc; +} + +define_parser(yaboot, 99, yaboot_parse);