X-Git-Url: http://git.ozlabs.org/?p=petitboot;a=blobdiff_plain;f=discover%2Fyaboot-parser.c;h=22792d4a63b4007bcfc46c400ab88cf8b2adbbc4;hp=27b4b782306594c05cbaec0fd3b01bc826a409de;hb=503d1454f222e2b0c6f8dd433a9e91870a17f460;hpb=32e6a41f33e5576716b351bd473a27939fe94fa1 diff --git a/discover/yaboot-parser.c b/discover/yaboot-parser.c index 27b4b78..22792d4 100644 --- a/discover/yaboot-parser.c +++ b/discover/yaboot-parser.c @@ -1,235 +1,395 @@ +#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; +#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 { + int globals_done; + const char *const *known_names; + + /* current option data */ + struct discover_boot_option *opt; + const char *device; + const char *partition; + const char *boot_image; + const char *initrd; + const char *initrd_size; + const char *literal; + const char *ramdisk; + const char *root; + bool read_only; + bool read_write; +}; -char * -make_params(char *label, char *params) +static struct discover_boot_option *state_start_new_option( + struct conf_context *conf, + struct yaboot_state *state) { - 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; + state->opt = discover_boot_option_create(conf->dc, conf->dc->device); + state->opt->option->boot_args = talloc_strdup(state->opt->option, ""); + + /* old allocated values will get freed with the state */ + state->device = conf_get_global_option(conf, "device"); + state->partition = conf_get_global_option(conf, "partition"); + state->initrd_size = conf_get_global_option(conf, "initrd_size"); + state->literal = conf_get_global_option(conf, "literal"); + state->ramdisk = conf_get_global_option(conf, "ramdisk"); + state->root = conf_get_global_option(conf, "root"); + + return state->opt; } -static int check_and_add_device(struct device *dev) +static struct resource *create_yaboot_devpath_resource( + struct yaboot_state *state, + struct conf_context *conf, + const char *path) { - if (!dev->icon_file) - dev->icon_file = strdup(generic_icon_file(guess_device_type())); + struct discover_boot_option *opt = state->opt; + const char *dev, *part, *devpos; + struct resource *res; + char *devpath, *devstr; + + dev = state->device; + part = state->partition; + + if (!dev) + dev = conf_get_global_option(conf, "device"); + if (!part) + part = conf_get_global_option(conf, "partition"); + + if (strchr(path, ':')) { + devpath = talloc_strdup(conf, path); + + } else if (dev && part) { + devpos = &dev[strlen(dev) - 1]; + if (isdigit(*devpos)) { + while (isdigit(*devpos)) + devpos--; + + devstr = talloc_strndup(conf, dev, devpos - dev + 1); + devpath = talloc_asprintf(conf, "%s%s:%s", devstr, + part, path); + talloc_free(devstr); + } else { + devpath = talloc_asprintf(conf, + "%s%s:%s", dev, part, path); + } + } else if (dev) { + devpath = talloc_asprintf(conf, "%s:%s", dev, path); + } else { + devpath = talloc_strdup(conf, path); + } - return !add_device(dev); + res = create_devpath_resource(opt, conf->dc->device, devpath); + + talloc_free(devpath); + + return res; } -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; + const char *default_label; + struct boot_option *opt; + + assert(state->opt); + + opt = state->opt->option; + assert(opt); + assert(opt->name); + assert(opt->boot_args); + + /* populate the boot option from state data */ + state->opt->boot_image = create_yaboot_devpath_resource(state, + conf, state->boot_image); + if (state->initrd) { + state->opt->initrd = create_yaboot_devpath_resource(state, + conf, state->initrd); + } + + if (state->initrd_size) { + opt->boot_args = talloc_asprintf(opt, "ramdisk_size=%s %s", + state->initrd_size, opt->boot_args); + } + + if (state->ramdisk) { + opt->boot_args = talloc_asprintf(opt, "ramdisk=%s %s", + state->initrd_size, opt->boot_args); + } + + if (state->root) { + opt->boot_args = talloc_asprintf(opt, "root=%s %s", + state->root, opt->boot_args); + } - memset(&opt, 0, sizeof(opt)); + if (state->read_only && state->read_write) { + pb_log("boot option %s specified both 'ro' and 'rw', " + "using 'rw'\n", opt->name); + state->read_only = false; + } - 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 (state->read_only || state->read_write) { + opt->boot_args = talloc_asprintf(opt, "%s %s", + state->read_only ? "ro" : "rw", + opt->boot_args); + } - cfgopt = cfg_get_strg(label, "initrd"); - if (cfgopt) - opt.initrd_file = resolve_path(cfgopt, devpath); + if (state->literal) { + opt->boot_args = talloc_strdup(opt, state->literal); + } - opt.boot_args = make_params(label, NULL); + opt->description = talloc_asprintf(opt, "%s %s %s", + state->boot_image, + (state->initrd ? state->initrd : ""), + opt->boot_args ? opt->boot_args : ""); - add_boot_option(&opt); + conf_strip_str(opt->boot_args); + conf_strip_str(opt->description); - if (opt.initrd_file) - free(opt.initrd_file); + default_label = conf_get_global_option(conf, "default"); + if (default_label && + !strcasecmp(state->opt->option->name, default_label)) + state->opt->option->is_default = true; + + discover_context_add_boot_option(conf->dc, 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; - } - - if (fstat(fd, &st)) { - close(fd); - return 0; + 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; + + /* 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")) { + + /* First finish any previous image. */ + if (opt) + yaboot_finish(conf); + + /* Then start the new image. */ + opt = state_start_new_option(conf, state); + + state->boot_image = talloc_strdup(state, value); + + return; } - conf_file = malloc(st.st_size+1); - if (!conf_file) { - 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) + yaboot_finish(conf); + + /* Then start the new image. */ + opt = state_start_new_option(conf, state); + + if (*value == '/') { + state->boot_image = talloc_strdup(state, value); + } else { + state->boot_image = talloc_strdup(state, + suse_fp->image); + state->initrd = talloc_strdup(state, suse_fp->initrd); + } + + return; } - - conf_len = read(fd, conf_file, st.st_size); - if (conf_len < 0) { - close(fd); - return 0; + + /* all other processing requires an image */ + if (!opt) { + pb_log("%s: unknown name: %s\n", __func__, name); + 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; + /* initrd */ + if (streq(name, "initrd")) { + state->initrd = talloc_strdup(state, value); + return; } - free(filepath); + /* 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; + } - 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; + /* args */ + if (streq(name, "device")) { + printf("option device : %s", value); + state->device = talloc_strdup(state, 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; + if (streq(name, "parititon")) { + state->partition = talloc_strdup(state, value); + return; + } - new_dev = malloc(strlen(devpath) + strlen(tmpstr) + 1); - if (!new_dev) - return 0; + if (streq(name, "append")) { + opt->option->boot_args = talloc_asprintf_append( + opt->option->boot_args, "%s ", value); + return; + } - strcpy(new_dev, devpath); + if (streq(name, "initrd-size")) { + state->initrd_size = talloc_strdup(state, value); + return; + } - /* Strip digits (partition number) from string */ - endp = new_dev + strlen(devpath) - 1; - while (isdigit(*endp)) - *(endp--) = 0; + if (streq(name, "literal")) { + state->literal = talloc_strdup(state, value); + return; + } - /* and add our own... */ - sprintf(endp + 1, "%d", partnr); + if (streq(name, "ramdisk")) { + state->ramdisk = talloc_strdup(state, value); + return; + } - tmp = devpath; - devpath = parse_device_path(new_dev, devpath); - free(tmp); - free(new_dev); - } + if (streq(name, "read-only")) { + state->read_only = true; + return; } - defimage = cfg_get_default(); - if (!defimage) - return 0; - defimage = cfg_get_strg(defimage, "image"); + if (streq(name, "read-write")) { + state->read_write = true; + return; + } + + if (streq(name, "root")) { + state->root = talloc_strdup(state, value); + return; + } - label = cfg_next_image(NULL); - if (!label || !check_and_add_device(dev)) + pb_log("%s: unknown name: %s\n", __func__, name); +} + +static struct conf_global_option yaboot_global_options[] = { + { .name = "root" }, + { .name = "device" }, + { .name = "partition" }, + { .name = "initrd" }, + { .name = "initrd_size" }, + { .name = "video" }, + { .name = "literal" }, + { .name = "ramdisk" }, + { .name = "default" }, + { .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", + "device", + "partition", + NULL +}; + +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; + state->opt = NULL; + + 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);