From 0ad5daa6572ad340244998f8f2243905d8f3974f Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Thu, 5 Apr 2007 10:31:32 +1000 Subject: [PATCH 1/1] Add kboot.conf parser Signed-off-by: Jeremy Kerr --- Makefile | 2 +- devices/kboot-parser.c | 233 +++++++++++++++++++++++++++++++++++++++++ devices/udev-helper.c | 4 +- 3 files changed, 237 insertions(+), 2 deletions(-) create mode 100644 devices/kboot-parser.c diff --git a/Makefile b/Makefile index e192b20..870fb14 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ TWIN_LDFLAGS?=$(shell pkg-config --libs libtwin) LDFLAGS = CFLAGS = -O0 -ggdb -Wall '-DPREFIX="$(PREFIX)"' -PARSERS = native yaboot +PARSERS = native yaboot kboot ARTWORK = background.jpg cdrom.png hdd.png usbpen.png cursor all: petitboot udev-helper diff --git a/devices/kboot-parser.c b/devices/kboot-parser.c new file mode 100644 index 0000000..27f3025 --- /dev/null +++ b/devices/kboot-parser.c @@ -0,0 +1,233 @@ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "udev-helper.h" +#include "params.h" + +#define buf_size 1024 + +static const char *mountpoint; + +static int param_is_ignored(const char *param) +{ + static const char *ignored_options[] = + { "message", "timeout", "default", NULL }; + const char **str; + + for (str = ignored_options; *str; str++) + if (streq(*str, param)) + return 1; + return 0; +} + +/** + * Splits a name=value pair, with value terminated by @term (or nul). if there + * is no '=', then only the value is populated, and *name is set to NULL. The + * string is modified in place. + * + * Returns the next byte to process, or null if we've hit the end of the + * string. + * + * */ +static char *get_param_pair(char *str, char **name_out, char **value_out, + char terminator) +{ + char *sep, *tmp, *name, *value; + + /* terminate the value */ + tmp = strchr(str, terminator); + if (tmp) + *tmp = 0; + else + tmp = NULL; + + sep = strchr(str, '='); + if (!sep) { + *name_out = NULL; + *value_out = str; + return tmp ? tmp + 1 : NULL; + } + + /* terminate the name */ + *sep = 0; + + /* remove leading spaces */ + for (name = str; isspace(*name); name++); + for (value = sep + 1; isspace(*value); value++); + + /* .. and trailing ones.. */ + for (sep--; isspace(*sep); sep--) + *sep = 0; + for (sep = value + strlen(value) - 1; isspace(*sep); sep--) + *sep = 0; + + *name_out = name; + *value_out = value; + + return tmp ? tmp + 1 : NULL; +} + +static int parse_option(struct boot_option *opt, char *config) +{ + char *pos, *name, *value, *root, *initrd, *cmdline, *tmp; + + root = initrd = cmdline = NULL; + + /* remove quotes around the value */ + while (*config == '"' || *config == '\'') + config++; + + pos = config + strlen(config) - 1; + while (*pos == '"' || *pos == '\'') + *(pos--) = 0; + + if (!strlen(pos)) + return 0; + + pos = strchr(config, ' '); + + /* if there's no space, it's only a kernel image with no params */ + if (!pos) { + opt->boot_image_file = join_paths(mountpoint, config); + opt->description = strdup(config); + return 1; + } + + *pos = 0; + opt->boot_image_file = join_paths(mountpoint, config); + + cmdline = malloc(buf_size); + + for (pos++; pos;) { + pos = get_param_pair(pos, &name, &value, ' '); + + if (!name) { + strcat(cmdline, " "); + strcat(cmdline, value); + + } else if (streq(name, "initrd")) { + initrd = value; + + } else if (streq(name, "root")) { + root = value; + + } else { + *(value - 1) = '='; + strcat(cmdline, name); + } + } + + if (initrd) { + asprintf(&tmp, "initrd=%s %s", initrd, cmdline); + free(cmdline); + cmdline = tmp; + + opt->initrd_file = join_paths(mountpoint, initrd); + } + + if (root) { + asprintf(&tmp, "root=%s %s", root, cmdline); + free(cmdline); + cmdline = tmp; + + } else if (!initrd) { + /* if there's an initrd but no root, fake up /dev/ram0 */ + asprintf(&tmp, "root=/dev/ram0 %s", cmdline); + free(cmdline); + cmdline = tmp; + } + + printf("kboot cmdline: %s", cmdline); + opt->boot_args = cmdline; + + asprintf(&opt->description, "%s %s", opt->boot_image_file, cmdline); + + return 1; +} + +static void parse_buf(struct device *dev, char *buf) +{ + char *pos, *name, *value; + int sent_device = 0; + + for (pos = buf; pos;) { + struct boot_option opt; + + pos = get_param_pair(pos, &name, &value, '\n'); + + printf("kboot param: '%s' = '%s'\n", name, value); + + if (name == NULL || param_is_ignored(name)) + continue; + + memset(&opt, 0, sizeof(opt)); + opt.name = strdup(name); + + if (parse_option(&opt, value)) + if (!sent_device++) + add_device(dev); + add_boot_option(&opt); + + free(opt.name); + } +} + +static int parse(const char *devicepath, const char *_mountpoint) +{ + char *filepath, *buf; + int fd, len, rc = 0; + struct stat stat; + struct device *dev; + + mountpoint = _mountpoint; + + filepath = join_paths(mountpoint, "/etc/kboot.conf"); + + fd = open(filepath, O_RDONLY); + if (fd < 0) + goto out_free_path; + + if (fstat(fd, &stat)) + goto out_close; + + buf = malloc(stat.st_size + 1); + if (!buf) + goto out_close;; + + len = read(fd, buf, stat.st_size); + if (len < 0) + goto out_free_buf; + buf[len] = 0; + + dev = malloc(sizeof(*dev)); + memset(dev, 0, sizeof(*dev)); + dev->id = strdup(devicepath); + dev->icon_file = strdup(generic_icon_file(guess_device_type())); + + parse_buf(dev, buf); + + rc = 1; + +out_free_buf: + free(buf); +out_close: + close(fd); +out_free_path: + free(filepath); + return rc; +} + +struct parser kboot_parser = { + .name = "kboot.conf parser", + .priority = 98, + .parse = parse +}; diff --git a/devices/udev-helper.c b/devices/udev-helper.c index da12129..1db8a26 100644 --- a/devices/udev-helper.c +++ b/devices/udev-helper.c @@ -26,6 +26,7 @@ extern struct parser native_parser; extern struct parser yaboot_parser; +extern struct parser kboot_parser; static FILE *logf; static int sock; @@ -33,6 +34,7 @@ static int sock; static struct parser *parsers[] = { &native_parser, &yaboot_parser, + &kboot_parser, NULL }; @@ -48,7 +50,7 @@ static void iterate_parsers(const char *devpath, const char *mountpoint) log("\ttrying parser '%s'\n", parsers[i]->name); /* just use a dummy device path for now */ if (parsers[i]->parse(devpath, mountpoint)) - return; + /*return*/; } log("\tno boot_options found\n"); } -- 2.39.2