summaryrefslogtreecommitdiffstats
path: root/devices
diff options
context:
space:
mode:
authorJeremy Kerr <jk@ozlabs.org>2007-04-05 10:31:32 +1000
committerJeremy Kerr <jk@ozlabs.org>2007-04-05 10:31:32 +1000
commit0ad5daa6572ad340244998f8f2243905d8f3974f (patch)
tree203f279e32258618dcaff2d82e6e560be1a88d31 /devices
parentf6de8493cf6645f8da027671f935cf22f8008a1b (diff)
downloadtalos-petitboot-0ad5daa6572ad340244998f8f2243905d8f3974f.tar.gz
talos-petitboot-0ad5daa6572ad340244998f8f2243905d8f3974f.zip
Add kboot.conf parser
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
Diffstat (limited to 'devices')
-rw-r--r--devices/kboot-parser.c233
-rw-r--r--devices/udev-helper.c4
2 files changed, 236 insertions, 1 deletions
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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#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");
}
OpenPOWER on IntegriCloud