Hook up parsers to device discovery
authorJeremy Kerr <jk@ozlabs.org>
Fri, 2 Jan 2009 07:34:18 +0000 (16:34 +0900)
committerJeremy Kerr <jk@ozlabs.org>
Fri, 2 Jan 2009 07:34:18 +0000 (16:34 +0900)
Iterate the parsers from the device handler on an add event.

Initial change to just the kboot parser.

Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
discover/device-handler.c
discover/device-handler.h
discover/discover-server.c
discover/discover-server.h
discover/kboot-parser.c
discover/parser-utils.c [new file with mode: 0644]
discover/parser-utils.h [new file with mode: 0644]
discover/parser.c
discover/parser.h
rules.mk

index 1f8938f295b322e68b2df19fb7eeadd8146b1ca1..593b8e0a961e8f0c3463a46702988442eca06135 100644 (file)
@@ -11,6 +11,8 @@
 #include <pb-protocol/pb-protocol.h>
 
 #include "device-handler.h"
+#include "discover-server.h"
+#include "parser.h"
 #include "udev.h"
 #include "log.h"
 #include "paths.h"
@@ -28,18 +30,6 @@ struct device_handler {
        struct list contexts;
 };
 
-struct discover_context {
-       char *id;
-       char *device_path;
-       char *mount_path;
-       struct udev_event *event;
-       struct device *device;
-       char **links;
-       int n_links;
-
-       struct list_item list;
-};
-
 struct mount_map {
        char *device_path;
        char *mount_point;
@@ -335,9 +325,18 @@ static int handle_add_event(struct device_handler *handler,
        }
 
        list_add(&handler->contexts, &ctx->list);
-
        talloc_set_destructor(ctx, destroy_context);
 
+       /* set up the top-level device */
+       ctx->device = talloc_zero(ctx, struct device);
+       ctx->device->id = talloc_strdup(ctx->device, ctx->id);
+       list_init(&ctx->device->boot_options);
+
+       /* run the parsers */
+       iterate_parsers(ctx);
+
+       discover_server_notify_add(handler->server, ctx->device);
+
        return 0;
 }
 
@@ -350,6 +349,8 @@ static int handle_remove_event(struct device_handler *handler,
        if (!ctx)
                return 0;
 
+       discover_server_notify_remove(handler->server, ctx->device);
+
        talloc_free(ctx);
 
        return 0;
@@ -381,6 +382,7 @@ struct device_handler *device_handler_init(struct discover_server *server)
        handler = talloc(NULL, struct device_handler);
        handler->devices = NULL;
        handler->n_devices = 0;
+       handler->server = server;
 
        list_init(&handler->contexts);
 
index ddcb20103e43eb457946b70d1a65066e6fd6d36e..cd28420a4056ae2a5318715514fb7e65b21b6bb7 100644 (file)
@@ -1,11 +1,25 @@
 #ifndef _DEVICE_HANDLER_H
 #define _DEVICE_HANDLER_H
 
+#include <list/list.h>
+
 struct device_handler;
 struct discover_server;
 struct udev_event;
 struct device;
 
+struct discover_context {
+       char *id;
+       char *device_path;
+       char *mount_path;
+       struct udev_event *event;
+       struct device *device;
+       char **links;
+       int n_links;
+
+       struct list_item list;
+};
+
 struct device_handler *device_handler_init(struct discover_server *server);
 
 void device_handler_destroy(struct device_handler *devices);
index 225f58c4b41aa5ec8f9b7dbbda7e9d69accf55fb..8ec1949121fd76f89819fc635c7b530f4ecd03c1 100644 (file)
@@ -154,6 +154,26 @@ static int discover_server_process(void *arg)
        return 0;
 }
 
+void discover_server_notify_add(struct discover_server *server,
+               struct device *device)
+{
+       struct client *client;
+
+       list_for_each_entry(&server->clients, client, list)
+               write_add_message(server, client, device);
+
+}
+
+void discover_server_notify_remove(struct discover_server *server,
+               struct device *device)
+{
+       struct client *client;
+
+       list_for_each_entry(&server->clients, client, list)
+               write_remove_message(server, client, device->id);
+
+}
+
 void discover_server_set_device_source(struct discover_server *server,
                struct device_handler *handler)
 {
index e5d7881905ffbcf9cd805242355ed67e9a697021..7c8993815ffdb11ca1b1e35d7573f4c251905413 100644 (file)
@@ -3,6 +3,7 @@
 
 struct discover_server;
 struct device_handler;
+struct device;
 
 struct discover_server *discover_server_init(void);
 
@@ -11,4 +12,8 @@ void discover_server_destroy(struct discover_server *server);
 void discover_server_set_device_source(struct discover_server *server,
                struct device_handler *handler);
 
+void discover_server_notify_add(struct discover_server *server,
+               struct device *device);
+void discover_server_notify_remove(struct discover_server *server,
+               struct device *device);
 #endif /* _DISCOVER_SERVER_H */
index df2e7620e13ad8ea40a735aaa04da60881f43de1..f227ee35f910e604c6c4623ff9166d3d64a01f63 100644 (file)
 #include <sys/types.h>
 #include <sys/stat.h>
 
-#include "parser.h"
+#include <talloc/talloc.h>
+
+#include "log.h"
+#include "pb-protocol/pb-protocol.h"
+#include "paths.h"
 #include "params.h"
+#include "parser-utils.h"
+#include "device-handler.h"
 
 #define buf_size 1024
 
-static const char *devpath;
+struct kboot_context {
+       struct discover_context *discover;
+
+       char *buf;
+
+       struct global_option {
+               char *name;
+               char *value;
+       } *global_options;
+       int n_global_options;
+};
 
 static int param_is_ignored(const char *param)
 {
@@ -76,12 +92,6 @@ static char *get_param_pair(char *str, char **name_out, char **value_out,
        return tmp ? tmp + 1 : NULL;
 }
 
-struct global_option {
-       char *name;
-       char *value;
-};
-
-
 static struct global_option global_options[] = {
        { .name = "root" },
        { .name = "initrd" },
@@ -93,20 +103,21 @@ static struct global_option global_options[] = {
  * 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(const char *name, const char *value)
+static int check_for_global_option(struct kboot_context *ctx,
+               const char *name, const char *value)
 {
        int i;
 
-       for (i = 0; global_options[i].name ;i++) {
-               if (!strcmp(name, global_options[i].name)) {
+       for (i = 0; i < ctx->n_global_options; i++) {
+               if (!strcmp(name, ctx->global_options[i].name)) {
                        global_options[i].value = strdup(value);
-                       return 1;
+                       break;
                }
        }
        return 0;
 }
 
-static char *get_global_option(const char *name)
+static char *get_global_option(struct kboot_context *ctx, const char *name)
 {
        int i;
 
@@ -117,9 +128,11 @@ static char *get_global_option(const char *name)
        return NULL;
 }
 
-static int parse_option(struct boot_option *opt, char *config)
+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;
 
        root = initrd = cmdline = NULL;
 
@@ -136,17 +149,24 @@ static int parse_option(struct boot_option *opt, char *config)
 
        pos = strchr(config, ' ');
 
+       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);
+
        /* if there's no space, it's only a kernel image with no params */
        if (!pos) {
-               opt->boot_image_file = resolve_path(config, devpath);
-               opt->description = strdup(config);
-               return 1;
+               opt->boot_image_file = resolve_path(opt, config,
+                               kboot_ctx->discover->device_path);
+               opt->description = talloc_strdup(opt, config);
+               goto out_add;
        }
 
        *pos = 0;
-       opt->boot_image_file = resolve_path(config, devpath);
+       opt->boot_image_file = resolve_path(opt, config,
+                       kboot_ctx->discover->device_path);
 
-       cmdline = malloc(buf_size);
+       cmdline = talloc_array(opt, char, buf_size);
        *cmdline = 0;
 
        for (pos++; pos;) {
@@ -170,119 +190,108 @@ static int parse_option(struct boot_option *opt, char *config)
        }
 
        if (!root)
-               root = get_global_option("root");
+               root = get_global_option(kboot_ctx, "root");
        if (!initrd)
-               initrd = get_global_option("initrd");
+               initrd = get_global_option(kboot_ctx, "initrd");
 
        if (initrd) {
-               asprintf(&tmp, "initrd=%s %s", initrd, cmdline);
-               free(cmdline);
+               tmp = talloc_asprintf(opt, "initrd=%s %s", initrd, cmdline);
+               talloc_free(cmdline);
                cmdline = tmp;
 
-               opt->initrd_file = resolve_path(initrd, devpath);
+               opt->initrd_file = resolve_path(opt, initrd,
+                               kboot_ctx->discover->device_path);
        }
 
        if (root) {
-               asprintf(&tmp, "root=%s %s", root, cmdline);
-               free(cmdline);
+               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 */
-               asprintf(&tmp, "root=/dev/ram0 %s", cmdline);
-               free(cmdline);
+               tmp = talloc_asprintf(opt, "root=/dev/ram0 %s", cmdline);
+               talloc_free(cmdline);
                cmdline = tmp;
        }
 
-       pb_log("kboot cmdline: %s\n", cmdline);
        opt->boot_args = cmdline;
 
-       asprintf(&opt->description, "%s %s",
+       opt->description = talloc_asprintf(opt, "%s %s",
                        config, opt->boot_args);
 
+out_add:
+       device_add_boot_option(kboot_ctx->discover->device, opt);
        return 1;
 }
 
-static void parse_buf(struct device *dev, char *buf)
+static void parse_buf(struct kboot_context *kboot_ctx)
 {
        char *pos, *name, *value;
-       int sent_device = 0;
-
-       for (pos = buf; pos;) {
-               struct boot_option opt;
 
+       for (pos = kboot_ctx->buf; pos;) {
                pos = get_param_pair(pos, &name, &value, '\n');
 
-               pb_log("kboot param: '%s' = '%s'\n", name, value);
-
                if (name == NULL || param_is_ignored(name))
                        continue;
 
                if (*name == '#')
                        continue;
 
-               if (check_for_global_option(name, value))
+               if (check_for_global_option(kboot_ctx, name, value))
                        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);
+               parse_option(kboot_ctx, name, value);
        }
 }
 
-static int parse(const char *device)
+
+static int parse(struct discover_context *ctx)
 {
-       char *filepath, *buf;
-       int fd, len, rc = 0;
+       struct kboot_context *kboot_ctx;
+       char *filepath;
+       int fd, len, rc;
        struct stat stat;
-       struct device *dev;
 
-       devpath = device;
+       rc = 0;
+       fd = -1;
+
+       kboot_ctx = talloc_zero(ctx, struct kboot_context);
+       kboot_ctx->discover = ctx;
 
-       filepath = resolve_path("/etc/kboot.conf", devpath);
+       filepath = resolve_path(kboot_ctx, "/etc/kboot.conf", ctx->device_path);
 
        fd = open(filepath, O_RDONLY);
        if (fd < 0)
-               goto out_free_path;
+               goto out;
 
        if (fstat(fd, &stat))
-               goto out_close;
+               goto out;
 
-       buf = malloc(stat.st_size + 1);
-       if (!buf)
-               goto out_close;;
+       kboot_ctx->buf = talloc_array(kboot_ctx, char, stat.st_size + 1);
 
-       len = read(fd, buf, stat.st_size);
+       len = read(fd, kboot_ctx->buf, stat.st_size);
        if (len < 0)
-               goto out_free_buf;
-       buf[len] = 0;
+               goto out;
+       kboot_ctx->buf[len] = 0;
 
-       dev = malloc(sizeof(*dev));
-       memset(dev, 0, sizeof(*dev));
-       dev->id = strdup(device);
-       dev->icon_file = strdup(generic_icon_file(guess_device_type()));
+       if (!ctx->device->icon_file)
+               ctx->device->icon_file = talloc_strdup(ctx,
+                               generic_icon_file(guess_device_type(ctx)));
 
-       parse_buf(dev, buf);
+       parse_buf(kboot_ctx);
 
        rc = 1;
 
-out_free_buf:
-       free(buf);
-out_close:
-       close(fd);
-out_free_path:
-       free(filepath);
+out:
+       if (fd >= 0)
+               close(fd);
+       talloc_free(kboot_ctx);
        return rc;
 }
 
 struct parser kboot_parser = {
-       .name = "kboot.conf parser",
+       .name     = "kboot.conf parser",
        .priority = 98,
        .parse    = parse
 };
diff --git a/discover/parser-utils.c b/discover/parser-utils.c
new file mode 100644 (file)
index 0000000..4982112
--- /dev/null
@@ -0,0 +1,53 @@
+
+#include <string.h>
+
+#include <talloc/talloc.h>
+
+#include "pb-protocol/pb-protocol.h"
+#include "udev.h"
+#include "device-handler.h"
+#include "parser-utils.h"
+
+void device_add_boot_option(struct device *device,
+               struct boot_option *boot_option)
+{
+       list_add(&device->boot_options, &boot_option->list);
+       talloc_steal(device, boot_option);
+}
+
+const char *generic_icon_file(enum generic_icon_type type)
+{
+       switch (type) {
+       case ICON_TYPE_DISK:
+               return artwork_pathname("hdd.png");
+       case ICON_TYPE_USB:
+               return artwork_pathname("usbpen.png");
+       case ICON_TYPE_OPTICAL:
+               return artwork_pathname("cdrom.png");
+       case ICON_TYPE_NETWORK:
+       case ICON_TYPE_UNKNOWN:
+               break;
+       }
+       return artwork_pathname("hdd.png");
+}
+
+enum generic_icon_type guess_device_type(struct discover_context *ctx)
+{
+       struct udev_event *event;
+       const char *type, *bus;
+
+       event = ctx->event;
+
+       type = udev_event_param(event, "ID_TYPE");
+       bus = udev_event_param(event, "ID_BUS");
+
+       if (type && streq(type, "cd"))
+               return ICON_TYPE_OPTICAL;
+       if (!bus)
+               return ICON_TYPE_UNKNOWN;
+       if (streq(bus, "usb"))
+               return ICON_TYPE_USB;
+       if (streq(bus, "ata") || streq(bus, "scsi"))
+               return ICON_TYPE_DISK;
+       return ICON_TYPE_UNKNOWN;
+}
diff --git a/discover/parser-utils.h b/discover/parser-utils.h
new file mode 100644 (file)
index 0000000..e82e3f9
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef PARSER_UTILS_H
+#define PARSER_UTILS_H
+
+#include "parser.h"
+
+#define streq(a,b) (!strcasecmp((a),(b)))
+
+#define artwork_pathname(file) (PKG_SHARE_DIR "/artwork/" file)
+
+void device_add_boot_option(struct device *device,
+               struct boot_option *boot_option);
+
+const char *generic_icon_file(enum generic_icon_type type);
+
+enum generic_icon_type guess_device_type(struct discover_context *ctx);
+
+#endif /* PARSER_UTILS_H */
index 5e50dcbdafc292f8c05a29f986f1d5510259938b..5b1a7abdab600656bc803721bef66f07bdcc9b88 100644 (file)
@@ -1,85 +1,30 @@
 
-#include <petitboot-paths.h>
 #include <stdlib.h>
-#include <string.h>
 
-#include "parser.h"
+#include "pb-protocol/pb-protocol.h"
 
-extern struct parser native_parser;
-extern struct parser yaboot_parser;
+#include "device-handler.h"
+#include "log.h"
+#include "parser.h"
 extern struct parser kboot_parser;
 
 /* array of parsers, ordered by priority */
 static struct parser *parsers[] = {
-       &native_parser,
-       &yaboot_parser,
        &kboot_parser,
        NULL
 };
 
-void iterate_parsers(const char *devpath, const char *mountpoint)
+void iterate_parsers(struct discover_context *ctx)
 {
        int i;
 
-       pb_log("trying parsers for %s\n", devpath);
+       pb_log("trying parsers for %s\n", ctx->device_path);
 
        for (i = 0; parsers[i]; i++) {
                pb_log("\ttrying parser '%s'\n", parsers[i]->name);
                /* just use a dummy device path for now */
-               if (parsers[i]->parse(devpath))
+               if (parsers[i]->parse(ctx))
                        return;
        }
        pb_log("\tno boot_options found\n");
 }
-
-/* convenience functions for parsers */
-void free_device(struct device *dev)
-{
-       if (!dev)
-               return;
-       if (dev->id)
-               free(dev->id);
-       if (dev->name)
-               free(dev->name);
-       if (dev->description)
-               free(dev->description);
-       if (dev->icon_file)
-               free(dev->icon_file);
-       free(dev);
-}
-
-void free_boot_option(struct boot_option *opt)
-{
-       if (!opt)
-               return;
-       if (opt->name)
-               free(opt->name);
-       if (opt->description)
-               free(opt->description);
-       if (opt->icon_file)
-               free(opt->icon_file);
-       if (opt->boot_image_file)
-               free(opt->boot_image_file);
-       if (opt->initrd_file)
-               free(opt->initrd_file);
-       if (opt->boot_args)
-               free(opt->boot_args);
-       free(opt);
-}
-
-const char *generic_icon_file(enum generic_icon_type type)
-{
-       switch (type) {
-       case ICON_TYPE_DISK:
-               return artwork_pathname("hdd.png");
-       case ICON_TYPE_USB:
-               return artwork_pathname("usbpen.png");
-       case ICON_TYPE_OPTICAL:
-               return artwork_pathname("cdrom.png");
-       case ICON_TYPE_NETWORK:
-       case ICON_TYPE_UNKNOWN:
-               break;
-       }
-       return artwork_pathname("hdd.png");
-}
-
index 9c6fb352e84337b14ce647e538e7f23bb07bd6f2..bf9a4d02b4e5f55a96f9e604f49cb653bcad40c5 100644 (file)
@@ -1,14 +1,12 @@
+#ifndef _PARSER_H
+#define _PARSER_H
 
-#ifndef _PARSERS_H
-#define _PARSERS_H
-
-#include <stdarg.h>
-#include "message.h"
+struct discover_context;
 
 struct parser {
        char *name;
        int priority;
-       int (*parse)(const char *device);
+       int (*parse)(struct discover_context *ctx);
        struct parser *next;
 };
 
@@ -22,25 +20,6 @@ enum generic_icon_type {
 
 #define streq(a,b) (!strcasecmp((a),(b)))
 
-/* general functions provided by parsers.c */
-void iterate_parsers(const char *devpath, const char *mountpoint);
-
-void free_device(struct device *dev);
-void free_boot_option(struct boot_option *opt);
-
-const char *generic_icon_file(enum generic_icon_type type);
-
-/* functions provided by udev-helper or the test wrapper */
-void pb_log(const char *fmt, ...);
-
-int mount_device(const char *dev_path);
-
-char *resolve_path(const char *path, const char *current_dev);
-const char *mountpoint_for_device(const char *dev_path);
-
-enum generic_icon_type guess_device_type(void);
-
-int add_device(const struct device *dev);
-int add_boot_option(const struct boot_option *opt);
+void iterate_parsers(struct discover_context *ctx);
 
-#endif /* _PARSERS_H */
+#endif /* _PARSER_H */
index 3a343c14e96d2e64736541455de125f61cc9b898..708c5a2f9f6702e6f230dcf337143e47fa1de6fb 100644 (file)
--- a/rules.mk
+++ b/rules.mk
@@ -9,13 +9,16 @@ DEFS += '-DPREFIX="$(prefix)"' '-DPKG_SHARE_DIR="$(pkgdatadir)"' \
 
 #uis = ui/twin/pb-twin
 uis = ui/test/pb-test
-parsers = native yaboot kboot
+#parsers = native yaboot kboot
+parsers = kboot
 artwork = background.jpg cdrom.png hdd.png usbpen.png tux.png cursor.gz
 
 
 talloc_objs = lib/talloc/talloc.o
 list_objs = lib/list/list.o
 server_objs = lib/pb-protocol/pb-protocol.o
+parser_objs = discover/parser.o discover/parser-utils.o \
+             $(foreach p, $(parsers), discover/$(p)-parser.o)
 
 parser_test_objs = parser-test.o $(parser_objs)
 
@@ -45,7 +48,7 @@ ui/test/pb-test: $(pb_test_objs)
 pb_discover_objs = discover/pb-discover.o discover/udev.o discover/log.o \
                   discover/waiter.o discover/discover-server.o \
                   discover/device-handler.o discover/paths.o \
-                  $(talloc_objs) $(server_objs) $(list_objs)
+                  $(talloc_objs) $(server_objs) $(parser_objs) $(list_objs)
 
 discover/pb-discover: $(pb_discover_objs)
        $(LINK.o) -o $@ $^