discover: Change parsers to explicitly request configuration files
authorNeelesh Gupta <neelegup@linux.vnet.ibm.com>
Mon, 28 Oct 2013 07:15:21 +0000 (12:45 +0530)
committerJeremy Kerr <jk@ozlabs.org>
Wed, 6 Nov 2013 08:34:26 +0000 (16:34 +0800)
Add a new function parser_request_url() to read the data from
configuration files present remotely. We deprecate
iterate_parser_files() and download_config() functions along with the
'filenames' and 'method' members of the 'parser' structure so that
individual parsers would now require to request the configuration files
data from the parser code and doesn't necessarily export the list of
configuration files.

Add the support to handle incoming DHCP event, done by passing all the
relevant environment variables of the udhcpc to the discover code.
Also, update the pxe parser code to populate the list of configuration
file names as per PXELINUX convention of fallback names using mac and ip
addresses of the booting machine.

Signed-off-by: Neelesh Gupta <neelegup@linux.vnet.ibm.com>
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
15 files changed:
discover/device-handler.c
discover/device-handler.h
discover/event.c
discover/event.h
discover/grub2/grub2.c
discover/kboot-parser.c
discover/parser.c
discover/parser.h
discover/pxe-parser.c
discover/udev.c
discover/user-event.c
discover/user-event.h
discover/yaboot-parser.c
test/parser/handler.c
utils/pb-udhcpc

index a497147918d43232498d23eeb833b4101d1ec6c0..cfd0c7bf8b5effede8b706493301c44d7ffc5503 100644 (file)
@@ -589,7 +589,7 @@ void device_handler_add_device(struct device_handler *handler,
  * array, but has only just been initialised by the hotplug source.
  */
 int device_handler_discover(struct device_handler *handler,
-               struct discover_device *dev, enum conf_method method)
+               struct discover_device *dev)
 {
        struct discover_context *ctx;
        int rc;
@@ -604,7 +604,7 @@ int device_handler_discover(struct device_handler *handler,
                goto out;
 
        /* run the parsers. This will populate the ctx's boot_option list. */
-       iterate_parsers(ctx, method);
+       iterate_parsers(ctx);
 
        /* add discovered stuff to the handler */
        device_handler_discover_context_commit(handler, ctx);
@@ -615,18 +615,17 @@ out:
        return 0;
 }
 
-/* incoming conf event */
-int device_handler_conf(struct device_handler *handler,
-               struct discover_device *dev, struct pb_url *url,
-               enum conf_method method)
+/* Incoming dhcp event */
+int device_handler_dhcp(struct device_handler *handler,
+               struct discover_device *dev, struct event *event)
 {
        struct discover_context *ctx;
 
        /* create our context */
        ctx = device_handler_discover_context_create(handler, dev);
-       ctx->conf_url = url;
+       ctx->event = event;
 
-       iterate_parsers(ctx, method);
+       iterate_parsers(ctx);
 
        device_handler_discover_context_commit(handler, ctx);
 
@@ -635,6 +634,25 @@ int device_handler_conf(struct device_handler *handler,
        return 0;
 }
 
+/* incoming conf event */
+int device_handler_conf(struct device_handler *handler,
+               struct discover_device *dev, struct pb_url *url)
+{
+        struct discover_context *ctx;
+
+        /* create our context */
+        ctx = device_handler_discover_context_create(handler, dev);
+        ctx->conf_url = url;
+
+        iterate_parsers(ctx);
+
+        device_handler_discover_context_commit(handler, ctx);
+
+        talloc_free(ctx);
+
+        return 0;
+}
+
 static struct discover_boot_option *find_boot_option_by_id(
                struct device_handler *handler, const char *id)
 {
index 6b36e075000ecd2bcad00e9edf912463e9221010..56d585a8ba117f4e474c4ba1e134dab6c176ef45 100644 (file)
@@ -14,16 +14,6 @@ struct event;
 struct device;
 struct waitset;
 
-enum conf_method {
-       CONF_METHOD_LOCAL_FILE, /* discover by looking at local files on this
-                                  block device */
-
-       CONF_METHOD_DHCP,       /* configuration from a DHCP response */
-
-       CONF_METHOD_UNKNOWN = -1,
-};
-
-
 struct discover_device {
        struct device           *device;
 
@@ -64,7 +54,6 @@ struct discover_context {
        struct discover_device  *device;
        struct list             boot_options;
        struct pb_url           *conf_url;
-       enum conf_method        method;
        void                    *test_data;
 };
 
@@ -82,10 +71,11 @@ struct discover_device *discover_device_create(struct device_handler *handler,
 void device_handler_add_device(struct device_handler *handler,
                struct discover_device *device);
 int device_handler_discover(struct device_handler *handler,
-               struct discover_device *dev, enum conf_method method);
+               struct discover_device *dev);
+int device_handler_dhcp(struct device_handler *handler,
+               struct discover_device *dev, struct event *event);
 int device_handler_conf(struct device_handler *handler,
-               struct discover_device *dev, struct pb_url *url,
-               enum conf_method method);
+               struct discover_device *dev, struct pb_url *url);
 void device_handler_remove(struct device_handler *handler,
                struct discover_device *device);
 
index 0ccd3910e18396e989fe58ce8e8e423be6716373..d4bb2c5dbcaeb9de78ee5caf50b0bc61bd80a0e1 100644 (file)
@@ -50,6 +50,8 @@ static int event_parse_ad_header(char *buf, int len, enum event_action *action,
                *action = EVENT_ACTION_REMOVE;
        else if (streq(buf, "conf"))
                *action = EVENT_ACTION_CONF;
+       else if (streq(buf, "dhcp"))
+               *action = EVENT_ACTION_DHCP;
        else {
                pb_log("%s: unknown action: %s\n", __func__, buf);
                return -1;
index adba336067ad3bf0b97361ed3a68259d992a909e..98ece11c73a8bd3bcda0362b8789d30baa3cb452 100644 (file)
@@ -11,6 +11,7 @@ enum event_action {
        EVENT_ACTION_ADD = 20,
        EVENT_ACTION_REMOVE,
        EVENT_ACTION_CONF,
+       EVENT_ACTION_DHCP,
        EVENT_ACTION_MAX,
 };
 
index 22d42dfc432a093d776a03b4109847413a66077b..9a4612714312c419fcf1efc1cc0eeb7776f78632 100644 (file)
@@ -86,24 +86,36 @@ bool resolve_grub2_resource(struct device_handler *handler,
        return true;
 }
 
-static int grub2_parse(struct discover_context *dc, char *buf, int len)
-{
+static int grub2_parse(struct discover_context *dc)
+       {
+       const char * const *filename;
        struct grub2_parser *parser;
+       int len, rc;
+       char *buf;
+
+       /* Support block device boot only at present */
+       if (dc->event)
+               return -1;
 
        parser = grub2_parser_create(dc);
 
-       grub2_parser_parse(parser, buf, len);
+       for (filename = grub2_conf_files; *filename; filename++) {
+               rc = parser_request_file(dc, dc->device, *filename, &buf, &len);
+               if (rc)
+                       continue;
+
+               grub2_parser_parse(parser, buf, len);
+               talloc_free(buf);
+       }
 
        talloc_free(parser);
 
-       return 1;
+       return 0;
 }
 
 static struct parser grub2_parser = {
        .name                   = "grub2",
-       .method                 = CONF_METHOD_LOCAL_FILE,
        .parse                  = grub2_parse,
-       .filenames              = grub2_conf_files,
        .resolve_resource       = resolve_grub2_resource,
 };
 
index 9d0322de39280e0f66a28ad9f783c419afbc12ae..8572674b982a94f1b49395cb3d504cf67f3f3879 100644 (file)
@@ -151,33 +151,45 @@ static const char *const kboot_ignored_names[] = {
        NULL
 };
 
-static int kboot_parse(struct discover_context *dc, char *buf, int len)
+static int kboot_parse(struct discover_context *dc)
 {
        struct conf_context *conf;
+       const char * const *filename;
+       char *buf;
+       int len, rc;
+
+       /* Support block device boot only at present */
+       if (dc->event)
+               return -1;
 
        conf = talloc_zero(dc, struct conf_context);
 
        if (!conf)
-               return 0;
+               return -1;
 
        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,
+       conf->parser_info = (void *)kboot_ignored_names;
+
+       for (filename = kboot_conf_files; *filename; filename++) {
+               rc = parser_request_file(dc, dc->device, *filename, &buf, &len);
+               if (rc)
+                       continue;
 
-       conf_parse_buf(conf, buf, len);
+               conf_parse_buf(conf, buf, len);
+               talloc_free(buf);
+       }
 
        talloc_free(conf);
-       return 1;
+       return 0;
 }
 
 static struct parser kboot_parser = {
        .name                   = "kboot",
-       .method                 = CONF_METHOD_LOCAL_FILE,
        .parse                  = kboot_parse,
-       .filenames              = kboot_conf_files,
        .resolve_resource       = resolve_devpath_resource,
 };
 
index 7b701181811d4f358b777b2ea2ea8394c431f95b..21b48debcb31d52e4f788040c1ce391e4ded7fc6 100644 (file)
@@ -78,97 +78,44 @@ int parser_replace_file(struct discover_context *ctx,
        return rc;
 }
 
-static int download_config(struct discover_context *ctx, char **buf, int *len)
+int parser_request_url(struct discover_context *ctx, struct pb_url *url,
+               char **buf, int *len)
 {
        struct load_url_result *result;
        int rc;
 
-       result = load_url(ctx, ctx->conf_url);
+       result = load_url(ctx, url);
        if (!result)
-               return -1;
+               goto out;
 
        rc = read_file(ctx, result->local, buf, len);
-       if (rc)
+       if (rc) {
+               pb_log("Read failed for the parser %s on file %s\n",
+                               ctx->parser->name, result->local);
                goto out_clean;
+       }
 
        return 0;
 
 out_clean:
        if (result->cleanup_local)
                unlink(result->local);
+out:
        return -1;
 }
 
-static void iterate_parser_files(struct discover_context *ctx,
-               const struct parser *parser)
-{
-       const char * const *filename;
-       const char *path;
-
-       if (!parser->filenames)
-               return;
-
-       for (filename = parser->filenames; *filename; filename++) {
-               int rc, len;
-               char *buf;
-
-               path = local_path(ctx, ctx->device, *filename);
-               if (!path)
-                       continue;
-
-               rc = read_file(ctx, path, &buf, &len);
-               if (!rc) {
-                       pb_log("Running parser %s on file %s\n",
-                                       parser->name, *filename);
-                       parser->parse(ctx, buf, len);
-                       talloc_free(buf);
-               }
-       }
-}
-
-void iterate_parsers(struct discover_context *ctx, enum conf_method method)
+void iterate_parsers(struct discover_context *ctx)
 {
        struct p_item* i;
-       int rc, len;
-       char *buf;
 
        pb_log("trying parsers for %s\n", ctx->device->device->id);
 
-       switch (method) {
-       case CONF_METHOD_LOCAL_FILE:
-               list_for_each_entry(&parsers, i, list) {
-                       if (i->parser->method != CONF_METHOD_LOCAL_FILE)
-                               continue;
-
-                       pb_debug("\ttrying parser '%s'\n", i->parser->name);
-                       ctx->parser = i->parser;
-                       iterate_parser_files(ctx, ctx->parser);
-               }
-               ctx->parser = NULL;
-               break;
-
-       case CONF_METHOD_DHCP:
-               rc = download_config(ctx, &buf, &len);
-               if (rc) {
-                       pb_log("\tdownload failed, aborting\n");
-                       return;
-               }
-
-               list_for_each_entry(&parsers, i, list) {
-                       if (i->parser->method != method)
-                               continue;
-
-                       pb_debug("\ttrying parser '%s'\n", i->parser->name);
-                       ctx->parser = i->parser;
-                       i->parser->parse(ctx, buf, len);
-               }
-
-               break;
-
-       case CONF_METHOD_UNKNOWN:
-               break;
-
+       list_for_each_entry(&parsers, i, list) {
+               pb_debug("\ttrying parser '%s'\n", i->parser->name);
+               ctx->parser = i->parser;
+               i->parser->parse(ctx);
        }
+       ctx->parser = NULL;
 }
 
 static void *parsers_ctx;
index 2aaa07744d62281334df79fdaa3411321a4cc5d5..970d72c05b6814f33c80ff674eef68e378c67c9f 100644 (file)
@@ -27,10 +27,7 @@ struct resource;
  */
 struct parser {
        char                    *name;
-       enum conf_method        method;
-       const char * const      *filenames;
-       int                     (*parse)(struct discover_context *ctx,
-                                               char *buf, int len);
+       int                     (*parse)(struct discover_context *ctx);
        bool                    (*resolve_resource)(
                                                struct device_handler *handler,
                                                struct resource *res);
@@ -48,7 +45,7 @@ enum generic_icon_type {
 
 void parser_init(void);
 
-void iterate_parsers(struct discover_context *ctx, enum conf_method method);
+void iterate_parsers(struct discover_context *ctx);
 int parse_user_event(struct discover_context *ctx, struct event *event);
 
 /* File IO functions for parsers; these should be the only interface that
@@ -63,5 +60,7 @@ int parser_request_file(struct discover_context *ctx,
 int parser_replace_file(struct discover_context *ctx,
                struct discover_device *dev, const char *filename,
                char *buf, int len);
+int parser_request_url(struct discover_context *ctx, struct pb_url *url,
+               char **buf, int *len);
 
 #endif /* _PARSER_H */
index 368d5c7a9e2ba81e56179241218dc525ec50a4e8..bc07a13c54b1ff8eb9884fe30de5977b1d04e881 100644 (file)
@@ -9,6 +9,8 @@
 #include "parser-conf.h"
 #include "parser-utils.h"
 #include "resource.h"
+#include "paths.h"
+#include "user-event.h"
 
 struct pxe_parser_info {
        struct discover_boot_option *opt;
@@ -91,15 +93,23 @@ static void pxe_process_pair(struct conf_context *ctx,
 
 }
 
-static int pxe_parse(struct discover_context *dc, char *buf, int len)
+static int pxe_parse(struct discover_context *dc)
 {
        struct pxe_parser_info *parser_info;
+       char **pxe_conf_files, **filename;
+       struct pb_url *conf_url, *url;
        struct conf_context *conf;
+       int len, rc;
+       char *buf;
+
+       /* Expects dhcp event parameters to support network boot */
+       if (!dc->event)
+               return -1;
 
        conf = talloc_zero(dc, struct conf_context);
 
        if (!conf)
-               return 0;
+               goto out;
 
        conf->dc = dc;
        conf->get_pair = conf_get_pair_space;
@@ -109,16 +119,60 @@ static int pxe_parse(struct discover_context *dc, char *buf, int len)
        parser_info = talloc_zero(conf, struct pxe_parser_info);
        conf->parser_info = parser_info;
 
+       conf_url = user_event_parse_conf_url(dc, dc->event);
+       if (!conf_url)
+               goto out_conf;
+
+       if (dc->conf_url) {
+               rc = parser_request_url(dc, dc->conf_url, &buf, &len);
+               if (rc)
+                       goto out_conf;
+       } else {
+               pxe_conf_files = user_event_parse_conf_filenames(dc, dc->event);
+               if (!pxe_conf_files)
+                       goto out_conf;
+
+               for (filename = pxe_conf_files; *filename; filename++) {
+                       url = pb_url_join(dc, conf_url, *filename);
+                       if (!url)
+                               goto out_pxe_conf;
+
+                       rc = parser_request_url(dc, url, &buf, &len);
+                       if (!rc) /* found one, just break */
+                               break;
+
+                       talloc_free(url);
+               }
+
+               /* No configuration file found on the boot server */
+               if (rc)
+                       goto out_pxe_conf;
+
+               dc->conf_url = url;
+
+               talloc_free(conf_url);
+               talloc_free(pxe_conf_files);
+       }
+
+       /* Call the config file parser with the data read from the file */
        conf_parse_buf(conf, buf, len);
 
+       talloc_free(buf);
+       talloc_free(conf);
+
+       return 0;
+
+out_pxe_conf:
+       talloc_free(pxe_conf_files);
+out_conf:
        talloc_free(conf);
-       return 1;
+out:
+       return -1;
 }
 
 static struct parser pxe_parser = {
        .name                   = "pxe",
        .parse                  = pxe_parse,
-       .method                 = CONF_METHOD_DHCP,
 };
 
 register_parser(pxe_parser);
index 0c656f35f3d707189ad6200c75426d8cb0c94f6b..48ab745b4f371ac410048dc3ab7b93f9dc3ff4fb 100644 (file)
@@ -116,7 +116,7 @@ static int udev_handle_dev_add(struct pb_udev *udev, struct udev_device *dev)
 
        udev_setup_device_params(dev, ddev);
 
-       device_handler_discover(udev->handler, ddev, CONF_METHOD_LOCAL_FILE);
+       device_handler_discover(udev->handler, ddev);
 
        return 0;
 }
index 4b56de48177c0561f6f78b223e52599c7879cb5f..61008c1a1cc484dd38c5d6dcd78795a2aa77e4ea 100644 (file)
@@ -40,6 +40,9 @@
 #include "user-event.h"
 
 
+#define MAC_ADDR_SIZE  6
+#define IP_ADDR_SIZE   4
+
 struct user_event {
        struct device_handler *handler;
        int socket;
@@ -52,8 +55,8 @@ static const char *event_action_name(enum event_action action)
                return "add";
        case EVENT_ACTION_REMOVE:
                return "remove";
-       case EVENT_ACTION_CONF:
-               return "conf";
+       case EVENT_ACTION_DHCP:
+               return "dhcp";
        default:
                break;
        }
@@ -73,27 +76,30 @@ static void user_event_print_event(struct event __attribute__((unused)) *event)
                        event->params[i].name, event->params[i].value);
 }
 
-static enum conf_method parse_conf_method(const char *str)
-{
-
-       if (!strcasecmp(str, "dhcp")) {
-               return CONF_METHOD_DHCP;
-       }
-       return CONF_METHOD_UNKNOWN;
-}
-
 static struct resource *user_event_resource(struct discover_boot_option *opt,
-               struct event *event, const char *param_name)
+               struct event *event)
 {
+       const char *siaddr, *boot_file;
        struct resource *res;
        struct pb_url *url;
-       const char *val;
+       char *url_str;
 
-       val = event_get_param(event, param_name);
-       if (!val)
+       siaddr = event_get_param(event, "siaddr");
+       if (!siaddr) {
+               pb_log("%s: next server option not found\n", __func__);
+               return NULL;
+       }
+
+       boot_file = event_get_param(event, "boot_file");
+       if (!boot_file) {
+               pb_log("%s: boot_file not found\n", __func__);
                return NULL;
+       }
+
+       url_str = talloc_asprintf(opt, "%s%s/%s", "tftp://", siaddr, boot_file);
+       url = pb_url_parse(opt, url_str);
+       talloc_free(url_str);
 
-       url = pb_url_parse(opt, val);
        if (!url)
                return NULL;
 
@@ -109,41 +115,55 @@ static struct resource *user_event_resource(struct discover_boot_option *opt,
 static int parse_user_event(struct discover_context *ctx, struct event *event)
 {
        struct discover_boot_option *d_opt;
+       char *server_ip, *root_dir, *p;
        struct boot_option *opt;
        struct device *dev;
-       const char *p;
+       const char *val;
 
        dev = ctx->device->device;
 
        d_opt = discover_boot_option_create(ctx, ctx->device);
-       opt = d_opt->option;
-
        if (!d_opt)
                goto fail;
 
-       p = event_get_param(event, "name");
+       opt = d_opt->option;
+
+       val = event_get_param(event, "name");
 
-       if (!p) {
+       if (!val) {
                pb_log("%s: no name found\n", __func__);
-               goto fail;
+               goto fail_opt;
        }
 
-       opt->id = talloc_asprintf(opt, "%s#%s", dev->id, p);
-       opt->name = talloc_strdup(opt, p);
+       opt->id = talloc_asprintf(opt, "%s#%s", dev->id, val);
+       opt->name = talloc_strdup(opt, val);
 
-       d_opt->boot_image = user_event_resource(d_opt, event, "image");
+       d_opt->boot_image = user_event_resource(d_opt, event);
        if (!d_opt->boot_image) {
                pb_log("%s: no boot image found for %s!\n", __func__,
                                opt->name);
-               goto fail;
+               goto fail_opt;
        }
 
-       d_opt->initrd = user_event_resource(d_opt, event, "initrd");
-
-       p = event_get_param(event, "args");
-
-       if (p)
-               opt->boot_args = talloc_strdup(opt, p);
+       val = event_get_param(event, "rootpath");
+       if (val) {
+               server_ip = talloc_strdup(opt, val);
+               p = strchr(server_ip, ':');
+               if (p) {
+                       root_dir = talloc_strdup(opt, p + 1);
+                       *p = '\0';
+                       opt->boot_args = talloc_asprintf(opt, "%s%s:%s",
+                                       "root=/dev/nfs ip=any nfsroot=",
+                                       server_ip, root_dir);
+
+                       talloc_free(root_dir);
+               } else {
+                       opt->boot_args = talloc_asprintf(opt, "%s",
+                                       "root=/dev/nfs ip=any nfsroot=");
+               }
+
+               talloc_free(server_ip);
+       }
 
        opt->description = talloc_asprintf(opt, "%s %s", opt->boot_image_file,
                opt->boot_args ? : "");
@@ -155,16 +175,189 @@ static int parse_user_event(struct discover_context *ctx, struct event *event)
 
        return 0;
 
-fail:
+fail_opt:
        talloc_free(d_opt);
+fail:
        return -1;
 }
 
+static const char *parse_host_addr(struct event *event)
+{
+       const char *val;
+
+       val = event_get_param(event, "tftp");
+       if (val)
+               return val;
+
+       val = event_get_param(event, "siaddr");
+       if (val)
+               return val;
+
+       val = event_get_param(event, "serverid");
+       if (val)
+               return val;
+
+       return NULL;
+}
+
+static char *parse_mac_addr(struct discover_context *ctx, const char *mac)
+{
+       unsigned int mac_addr_arr[MAC_ADDR_SIZE];
+       char *mac_addr;
+
+       sscanf(mac, "%X:%X:%X:%X:%X:%X", mac_addr_arr, mac_addr_arr + 1,
+                       mac_addr_arr + 2, mac_addr_arr + 3, mac_addr_arr + 4,
+                       mac_addr_arr + 5);
+
+       mac_addr = talloc_asprintf(ctx, "01-%02X-%02X-%02X-%02X-%02X-%02X",
+                       mac_addr_arr[0], mac_addr_arr[1], mac_addr_arr[2],
+                       mac_addr_arr[3], mac_addr_arr[4], mac_addr_arr[5]);
+
+       return mac_addr;
+}
+
+static char *parse_ip_addr(struct discover_context *ctx, const char *ip)
+{
+       unsigned int ip_addr_arr[IP_ADDR_SIZE];
+       char *ip_hex;
+
+       sscanf(ip, "%u.%u.%u.%u", ip_addr_arr, ip_addr_arr + 1,
+                       ip_addr_arr + 2, ip_addr_arr + 3);
+
+       ip_hex = talloc_asprintf(ctx, "%02X%02X%02X%02X", ip_addr_arr[0],
+                       ip_addr_arr[1], ip_addr_arr[2], ip_addr_arr[3]);
+
+       return ip_hex;
+}
+
+struct pb_url *user_event_parse_conf_url(struct discover_context *ctx,
+               struct event *event)
+{
+       const char *conffile, *host, *bootfile;
+       char *p, *basedir, *url_str;
+       struct pb_url *url;
+
+       conffile = event_get_param(event, "conffile");
+       if (conffile) {
+               if (is_url(conffile)) {
+                       url = pb_url_parse(ctx, conffile);
+               } else {
+                       host = parse_host_addr(event);
+                       if (!host) {
+                               pb_log("%s: host address not found\n",
+                                               __func__);
+                               return NULL;
+                       }
+
+                       url_str = talloc_asprintf(ctx, "%s%s/%s", "tftp://",
+                                       host, conffile);
+                       url = pb_url_parse(ctx, url_str);
+
+                       talloc_free(url_str);
+               }
+
+               ctx->conf_url = url;
+       } else {
+               host = parse_host_addr(event);
+               if (!host) {
+                       pb_log("%s: host address not found\n", __func__);
+                       return NULL;
+               }
+
+               bootfile = event_get_param(event, "bootfile");
+               if (!bootfile) {
+                       pb_log("%s: bootfile param not found\n", __func__);
+                       return NULL;
+               }
+
+               basedir = talloc_strdup(ctx, bootfile);
+               p = strchr(basedir, '/');
+               if (p)
+                       *p = '\0';
+
+               if (!strcmp(basedir,"") || !strcmp(basedir, "."))
+                       url_str = talloc_asprintf(ctx, "%s%s/", "tftp://",host);
+               else
+                       url_str = talloc_asprintf(ctx, "%s%s/%s/", "tftp://",host,
+                                       basedir);
+
+               url = pb_url_parse(ctx, url_str);
+
+               talloc_free(url_str);
+               talloc_free(basedir);
+       }
+
+       return url;
+}
+
+char **user_event_parse_conf_filenames(
+               struct discover_context *ctx, struct event *event)
+{
+       char *mac_addr, *ip_hex;
+       const char *mac, *ip;
+       char **filenames;
+       int index, len;
+
+       mac = event_get_param(event, "mac");
+       if (mac)
+               mac_addr = parse_mac_addr(ctx, mac);
+       else
+               mac_addr = NULL;
+
+       ip = event_get_param(event, "ip");
+       if (ip) {
+               ip_hex = parse_ip_addr(ctx, ip);
+               len = strlen(ip_hex);
+       } else {
+               ip_hex = NULL;
+               len = 0;
+       }
+
+       if (!mac_addr && !ip_hex) {
+               pb_log("%s: neither mac nor ip parameter found\n", __func__);
+               return NULL;
+       }
+
+       /* Filenames as fallback IP's + mac + default */
+       filenames = talloc_array(ctx, char *, len + 3);
+
+       index = 0;
+       if (mac_addr)
+               filenames[index++] = talloc_strdup(filenames, mac_addr);
+
+       while (len) {
+               filenames[index++] = talloc_strdup(filenames, ip_hex);
+               ip_hex[--len] = '\0';
+       }
+
+       filenames[index++] = talloc_strdup(filenames, "default");
+       filenames[index++] = NULL;
+
+       if (mac_addr)
+               talloc_free(mac_addr);
+
+       if (ip_hex)
+               talloc_free(ip_hex);
+
+       return filenames;
+}
+
+static int user_event_dhcp(struct user_event *uev, struct event *event)
+{
+       struct device_handler *handler = uev->handler;
+       struct discover_device *dev;
+
+       dev = discover_device_create(handler, event->device);
+
+       device_handler_dhcp(handler, dev, event);
+
+       return 0;
+}
+
 static int user_event_conf(struct user_event *uev, struct event *event)
 {
        struct device_handler *handler = uev->handler;
        struct discover_device *dev;
-       enum conf_method method;
        struct pb_url *url;
        const char *val;
 
@@ -176,17 +369,9 @@ static int user_event_conf(struct user_event *uev, struct event *event)
        if (!url)
                return 0;
 
-       val = event_get_param(event, "method");
-       if (!val)
-               return 0;
-
-       method = parse_conf_method(val);
-       if (method == CONF_METHOD_UNKNOWN)
-               return 0;
-
        dev = discover_device_create(handler, event->device);
 
-       device_handler_conf(handler, dev, url, method);
+       device_handler_conf(handler, dev, url);
 
        return 0;
 }
@@ -249,6 +434,9 @@ static void user_event_handle_message(struct user_event *uev, char *buf,
        case EVENT_ACTION_CONF:
                result = user_event_conf(uev, event);
                break;
+       case EVENT_ACTION_DHCP:
+               result = user_event_dhcp(uev, event);
+               break;
        default:
                break;
        }
index 488f04af089050c8a49ab1499228152e8f0a17d6..976c25761c810fc63aeaadc6ca7979889330cb59 100644 (file)
 struct user_event;
 struct waitset;
 
+struct pb_url *user_event_parse_conf_url(struct discover_context *ctx,
+               struct event *event);
+char **user_event_parse_conf_filenames(
+               struct discover_context *ctx, struct event *event);
 struct user_event *user_event_init(struct waitset *waitset,
                struct device_handler *handler);
 void user_event_destroy(struct user_event *uev);
index 22792d4a63b4007bcfc46c400ab88cf8b2adbbc4..e52187fff6b61203325e13019fa472ca95c9ad0f 100644 (file)
@@ -356,15 +356,22 @@ static const char *yaboot_known_names[] = {
        NULL
 };
 
-static int yaboot_parse(struct discover_context *dc, char *buf, int len)
+static int yaboot_parse(struct discover_context *dc)
 {
-       struct conf_context *conf;
+       const char * const *filename;
        struct yaboot_state *state;
+       struct conf_context *conf;
+       int len, rc;
+       char *buf;
+
+       /* Support block device boot only at present */
+       if (dc->event)
+               return -1;
 
        conf = talloc_zero(dc, struct conf_context);
 
        if (!conf)
-               return 0;
+               return -1;
 
        conf->dc = dc;
        conf->global_options = yaboot_global_options,
@@ -378,17 +385,22 @@ static int yaboot_parse(struct discover_context *dc, char *buf, int len)
 
        state->opt = NULL;
 
-       conf_parse_buf(conf, buf, len);
+       for (filename = yaboot_conf_files; *filename; filename++) {
+               rc = parser_request_file(dc, dc->device, *filename, &buf, &len);
+               if (rc)
+                       continue;
+
+               conf_parse_buf(conf, buf, len);
+               talloc_free(buf);
+       }
 
        talloc_free(conf);
-       return 1;
+       return 0;
 }
 
 static struct parser yaboot_parser = {
        .name                   = "yaboot",
-       .method                 = CONF_METHOD_LOCAL_FILE,
        .parse                  = yaboot_parse,
-       .filenames              = yaboot_conf_files,
        .resolve_resource       = resolve_devpath_resource,
 };
 
index 64978da92f745988fdfc871718981105d51b9e5a..d9057eb56c60fd5bff19e937e80a4bf43abd0ab6 100644 (file)
@@ -40,10 +40,9 @@ void parser_init(void)
 {
 }
 
-void iterate_parsers(struct discover_context *ctx, enum conf_method method)
+void iterate_parsers(struct discover_context *ctx)
 {
        (void)ctx;
-       (void)method;
        assert(false);
 }
 
index dd291b9a0fa61441f072b2b75251abdf160056b5..3494985d3fc33dfcb6ed0b74b9b5d74368ba10b4 100644 (file)
@@ -9,97 +9,44 @@
 PBOOT_USER_EVENT_SOCKET="/tmp/petitboot.ev"
 log="/var/log/petitboot/pb-udhcpc.log"
 
-resolve_url() {
-       file="$1"
-
-       # URL? use as-is.
-       tmp=${file%://*}
-       if [ "$tmp" != "$file" ]
-       then
-               echo "$file"
-               return
-       fi
-
-       # Otherwise, TFTP using an appropriate host. Start with the
-       # DHCP 'tftp' option:
-       host=${tftp}
-
-       # next, try the DHCP next-server-address
-       [ -z "$host" ] && host=${siaddr}
-
-       # finally, use the DHCP server we got this lease from:
-       [ -z "$host" ] && host=${serverid}
-
-       echo "tftp://$host/$file"
-}
-
-do_pxe() {
-       basedir=$1
-
-       params="conf@${interface} method=dhcp"
+pb_add () {
+       # Looks like udhcpc will give us different names, depending if the
+       # parameter was in the header, or specified by options
+       [ -z "$bootfile" ] && bootfile=${boot_file}
 
-       # first, try by MAC
-       mac=$(tr ':' '-' < /sys/class/$interface/address)
-       pb-event $params url=$basedir/01-$mac
+       mac=$(< /sys/class/net/$interface/address)
+       paramstr=''
 
-       # try decreasing fragments of IP lease
-       ip_hex=$(printf '%02X%02X%02X%02X' $(echo $ip | tr '.' ' '))
-       for i in $(seq 8 -1 1)
+       # Collect relevant DHCP response parameters into $paramstr
+       for name in conffile bootfile mac ip siaddr serverid tftp
        do
-               frag=${ip_hex:0:$i}
-               pb-event $params url=$basedir/$frag
-       done
+               value=$(eval "echo \${$name}")
+               [ -n "$value" ] || continue;
 
-       # last, use default
-       pb-event $params url=$basedir/default
-}
+               paramstr="$paramstr $name=$value"
+       done
 
-pb_add () {
+       pb-event dhcp@{interface} $paramstr
 
-       # Look for an explicit config file location in the DHCP config-file
-       # parameter
+       # Check if an explicit config file present
        if [ -n "${conffile}" ]
        then
-               url=$(resolve_url ${conffile})
-               pb-event conf@${interface} url=$url method=dhcp
-               return
-       fi
-
-       # Otherwise, we'll need the boot-file parameter. Looks like udhcpc
-       # will give us different names, depending if the parameter was in
-       # the header, or specified by options
-       [ -z "$bootfile" ] && bootfile=${boot_file}
-
-       if [ -z "$bootfile" ]
-       then
-               return
+               return;
        fi
 
-       # PXE behaviour is to download the config file based on a file
-       # structure relative to the pxelinux binary
-       file=${bootfile}
-       [ -z "$file" ] && file=${boot_file}
-       if [ -n "$file" ]
-       then
-               basedir=${file%%/*}
-               do_pxe $basedir
-       fi
+        # Finally, add an option for the boot_file parameter
+       paramstr='name=netboot'
 
-       # Finally, add an option for the boot_file parameter
-       k_server_ip=${rootpath%%:*}
-       k_root_dir=${rootpath#*:}
+       # Collect relevant parameters to add an option to the boot_file parameter
+       for name in rootpath siaddr boot_file
+        do
+                value=$(eval "echo \${$name}")
+                [ -n "$value" ] || continue;
 
-       args=
-       if [ -n "$rootpath" ]
-       then
-               [ ${k_server_ip} != ${rootpath} ] || k_server_ip=${serverid}
-               args="root=/dev/nfs ip=any nfsroot=${k_server_ip}:${k_root_dir}"
-       fi
+                paramstr="$paramstr $name=$value"
+        done
 
-       pb-event add@${interface} \
-               name=netboot \
-               image=tftp://${siaddr}/${boot_file} \
-               args="$args"
+       pb-event add@{interface} $paramstr
 }
 
 pb_remove () {