]> git.ozlabs.org Git - petitboot/blobdiff - discover/kboot-parser.c
discover: Use device_handler_status_dev_* for device-specific status
[petitboot] / discover / kboot-parser.c
index f227ee35f910e604c6c4623ff9166d3d64a01f63..f7f75e07ceae60212f3ccef5cea34d7ed3ef93aa 100644 (file)
-#define _GNU_SOURCE
+#if defined(HAVE_CONFIG_H)
+#include "config.h"
+#endif
 
+#include <assert.h>
 #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 <talloc/talloc.h>
-
-#include "log.h"
-#include "pb-protocol/pb-protocol.h"
-#include "paths.h"
-#include "params.h"
+#include "log/log.h"
+#include "talloc/talloc.h"
+#include "types/types.h"
+#include "parser-conf.h"
 #include "parser-utils.h"
-#include "device-handler.h"
-
-#define buf_size 1024
-
-struct kboot_context {
-       struct discover_context *discover;
-
-       char *buf;
+#include "resource.h"
 
-       struct global_option {
-               char *name;
-               char *value;
-       } *global_options;
-       int n_global_options;
-};
-
-static int param_is_ignored(const char *param)
+static void kboot_process_pair(struct conf_context *conf, const char *name,
+               char *value)
 {
-       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 struct global_option global_options[] = {
-       { .name = "root" },
-       { .name = "initrd" },
-       { .name = "video" },
-       { .name = NULL }
-};
-
-/*
- * Check if an option (name=value) is a global option. If so, store it in
- * the global options table, and return 1. Otherwise, return 0.
- */
-static int check_for_global_option(struct kboot_context *ctx,
-               const char *name, const char *value)
-{
-       int i;
-
-       for (i = 0; i < ctx->n_global_options; i++) {
-               if (!strcmp(name, ctx->global_options[i].name)) {
-                       global_options[i].value = strdup(value);
-                       break;
-               }
-       }
-       return 0;
-}
+       const char *const *ignored_names = conf->parser_info;
+       struct discover_boot_option *d_opt;
+       struct boot_option *opt;
+       char *pos;
+       char *args;
+       const char *initrd;
+       const char *root;
+       const char *dtb;
 
-static char *get_global_option(struct kboot_context *ctx, const char *name)
-{
-       int i;
+       /* ignore bare values */
 
-       for (i = 0; global_options[i].name ;i++)
-               if (!strcmp(name, global_options[i].name))
-                       return global_options[i].value;
+       if (!name)
+               return;
 
-       return NULL;
-}
+       if (conf_param_in_list(ignored_names, name))
+               return;
 
-static int parse_option(struct kboot_context *kboot_ctx, char *opt_name,
-               char *config)
-{
-       char *pos, *name, *value, *root, *initrd, *cmdline, *tmp;
-       struct boot_option *opt;
+       if (conf_set_global_option(conf, name, value))
+               return;
 
-       root = initrd = cmdline = NULL;
+       /* opt must be associated with dc */
 
-       /* remove quotes around the value */
-       while (*config == '"' || *config == '\'')
-               config++;
+       d_opt = talloc_zero(conf->dc, struct discover_boot_option);
+       d_opt->device = conf->dc->device;
+       opt = talloc_zero(d_opt, struct boot_option);
 
-       pos = config + strlen(config) - 1;
-       while (*pos == '"' || *pos == '\'')
-               *(pos--) = 0;
+       if (!opt)
+               return;
 
-       if (!strlen(pos))
-               return 0;
+       opt->id = talloc_asprintf(opt, "%s#%s", conf->dc->device->device->id,
+                       name);
+       opt->name = talloc_strdup(opt, name);
+       d_opt->option = opt;
 
-       pos = strchr(config, ' ');
+       args = talloc_strdup(opt, "");
+       initrd = conf_get_global_option(conf, "initrd");
+       root = conf_get_global_option(conf, "root");
+       dtb = conf_get_global_option(conf, "dtb");
 
-       opt = talloc_zero(kboot_ctx, struct boot_option);
-       opt->id = talloc_asprintf(opt, "%s#%s",
-                       kboot_ctx->discover->device->id, opt_name);
-       opt->name = talloc_strdup(opt, opt_name);
+       pos = strchr(value, ' ');
 
        /* if there's no space, it's only a kernel image with no params */
-       if (!pos) {
-               opt->boot_image_file = resolve_path(opt, config,
-                               kboot_ctx->discover->device_path);
-               opt->description = talloc_strdup(opt, config);
-               goto out_add;
-       }
 
+       if (!pos)
+               goto out_add;
        *pos = 0;
-       opt->boot_image_file = resolve_path(opt, config,
-                       kboot_ctx->discover->device_path);
-
-       cmdline = talloc_array(opt, char, buf_size);
-       *cmdline = 0;
 
        for (pos++; pos;) {
-               pos = get_param_pair(pos, &name, &value, ' ');
-
-               if (!name) {
-                       strcat(cmdline, " ");
-                       strcat(cmdline, value);
-
-               } else if (streq(name, "initrd")) {
-                       initrd = value;
+               char *cl_name, *cl_value;
 
-               } else if (streq(name, "root")) {
-                       root = value;
+               pos = conf_get_pair_equal(conf, pos, &cl_name, &cl_value, ' ');
 
-               } else {
-                       strcat(cmdline, " ");
-                       *(value - 1) = '=';
-                       strcat(cmdline, name);
+               if (!cl_name) {
+                       args = talloc_asprintf_append(args, "%s ", cl_value);
+                       continue;
                }
-       }
 
-       if (!root)
-               root = get_global_option(kboot_ctx, "root");
-       if (!initrd)
-               initrd = get_global_option(kboot_ctx, "initrd");
+               if (streq(cl_name, "initrd")) {
+                       initrd = cl_value;
+                       continue;
+               }
 
-       if (initrd) {
-               tmp = talloc_asprintf(opt, "initrd=%s %s", initrd, cmdline);
-               talloc_free(cmdline);
-               cmdline = tmp;
+               if (streq(cl_name, "root")) {
+                       root = cl_value;
+                       continue;
+               }
 
-               opt->initrd_file = resolve_path(opt, initrd,
-                               kboot_ctx->discover->device_path);
-       }
+               if (streq(cl_name, "dtb")) {
+                       dtb = cl_value;
+                       continue;
+               }
 
-       if (root) {
-               tmp = talloc_asprintf(opt, "root=%s %s", root, cmdline);
-               talloc_free(cmdline);
-               cmdline = tmp;
-
-       } else if (initrd) {
-               /* if there's an initrd but no root, fake up /dev/ram0 */
-               tmp = talloc_asprintf(opt, "root=/dev/ram0 %s", cmdline);
-               talloc_free(cmdline);
-               cmdline = tmp;
+               args = talloc_asprintf_append(args, "%s=%s ", cl_name,
+                       cl_value);
        }
 
-       opt->boot_args = cmdline;
-
-       opt->description = talloc_asprintf(opt, "%s %s",
-                       config, opt->boot_args);
-
 out_add:
-       device_add_boot_option(kboot_ctx->discover->device, opt);
-       return 1;
-}
+       d_opt->boot_image = create_devpath_resource(d_opt,
+                               conf->dc->device, value);
 
-static void parse_buf(struct kboot_context *kboot_ctx)
-{
-       char *pos, *name, *value;
+       char* args_sigfile_default = talloc_asprintf(d_opt,
+               "%s.cmdline.sig", value);
+       d_opt->args_sig_file = create_devpath_resource(d_opt,
+                               conf->dc->device, args_sigfile_default);
+       talloc_free(args_sigfile_default);
 
-       for (pos = kboot_ctx->buf; pos;) {
-               pos = get_param_pair(pos, &name, &value, '\n');
+       if (root) {
+               opt->boot_args = talloc_asprintf(opt, "root=%s %s", root, args);
+               talloc_free(args);
+       } else
+               opt->boot_args = args;
 
-               if (name == NULL || param_is_ignored(name))
-                       continue;
+       opt->description = talloc_asprintf(opt, "%s %s", value,
+                       opt->boot_args);
 
-               if (*name == '#')
-                       continue;
-
-               if (check_for_global_option(kboot_ctx, name, value))
-                       continue;
+       if (initrd) {
+               d_opt->initrd = create_devpath_resource(d_opt,
+                               conf->dc->device, initrd);
+               opt->description = talloc_asprintf_append(opt->description,
+                               " initrd=%s", initrd);
+       }
 
-               parse_option(kboot_ctx, name, value);
+       if (dtb) {
+               d_opt->dtb = create_devpath_resource(d_opt,
+                               conf->dc->device, dtb);
+               opt->description = talloc_asprintf_append(opt->description,
+                               " dtb=%s", dtb);
        }
-}
 
+       conf_strip_str(opt->boot_args);
+       conf_strip_str(opt->description);
 
-static int parse(struct discover_context *ctx)
-{
-       struct kboot_context *kboot_ctx;
-       char *filepath;
-       int fd, len, rc;
-       struct stat stat;
+       discover_context_add_boot_option(conf->dc, d_opt);
+}
 
-       rc = 0;
-       fd = -1;
+static struct conf_global_option kboot_global_options[] = {
+       { .name = "dtb" },
+       { .name = "initrd" },
+       { .name = "root" },
+       { .name = "video" },
+       { .name = NULL }
+};
 
-       kboot_ctx = talloc_zero(ctx, struct kboot_context);
-       kboot_ctx->discover = ctx;
+static const char *const kboot_conf_files[] = {
+       "/kboot.conf",
+       "/kboot.cnf",
+       "/etc/kboot.conf",
+       "/etc/kboot.cnf",
+       "/KBOOT.CONF",
+       "/KBOOT.CNF",
+       "/ETC/KBOOT.CONF",
+       "/ETC/KBOOT.CNF",
+       NULL
+};
 
-       filepath = resolve_path(kboot_ctx, "/etc/kboot.conf", ctx->device_path);
+static const char *const kboot_ignored_names[] = {
+       "default",
+       "delay",
+       "message",
+       "timeout",
+       NULL
+};
 
-       fd = open(filepath, O_RDONLY);
-       if (fd < 0)
-               goto out;
+static int kboot_parse(struct discover_context *dc)
+{
+       struct conf_context *conf;
+       const char * const *filename;
+       char *buf;
+       int len, rc;
 
-       if (fstat(fd, &stat))
-               goto out;
+       /* Support block device boot only at present */
+       if (dc->event)
+               return -1;
 
-       kboot_ctx->buf = talloc_array(kboot_ctx, char, stat.st_size + 1);
+       conf = talloc_zero(dc, struct conf_context);
 
-       len = read(fd, kboot_ctx->buf, stat.st_size);
-       if (len < 0)
-               goto out;
-       kboot_ctx->buf[len] = 0;
+       if (!conf)
+               return -1;
 
-       if (!ctx->device->icon_file)
-               ctx->device->icon_file = talloc_strdup(ctx,
-                               generic_icon_file(guess_device_type(ctx)));
+       conf->dc = dc;
+       conf->global_options = kboot_global_options,
+       conf_init_global_options(conf);
+       conf->get_pair = conf_get_pair_equal;
+       conf->process_pair = kboot_process_pair;
+       conf->parser_info = (void *)kboot_ignored_names;
 
-       parse_buf(kboot_ctx);
+       for (filename = kboot_conf_files; *filename; filename++) {
+               rc = parser_request_file(dc, dc->device, *filename, &buf, &len);
+               if (rc)
+                       continue;
 
-       rc = 1;
+               conf_parse_buf(conf, buf, len);
+               talloc_free(buf);
+       }
 
-out:
-       if (fd >= 0)
-               close(fd);
-       talloc_free(kboot_ctx);
-       return rc;
+       talloc_free(conf);
+       return 0;
 }
 
-struct parser kboot_parser = {
-       .name     = "kboot.conf parser",
-       .priority = 98,
-       .parse    = parse
+static struct parser kboot_parser = {
+       .name                   = "kboot",
+       .parse                  = kboot_parse,
+       .resolve_resource       = resolve_devpath_resource,
 };
+
+register_parser(kboot_parser);