protocol: Separate device add from boot-option add messages
authorJeremy Kerr <jk@ozlabs.org>
Mon, 11 Mar 2013 05:43:48 +0000 (13:43 +0800)
committerJeremy Kerr <jk@ozlabs.org>
Tue, 16 Apr 2013 03:41:46 +0000 (11:41 +0800)
We want to cater for situations where boot options may be discovered
some time after we get notificiation about devices. For instance,
discovering boot options from DHCP configuration parameters. In this
case, we'll need to notify UIs of boot options appear some time after
the device (and/or other boot options on the same device) has appeared.

This change adds a new protocol message type,
PB_PROTOCOL_ACTION_BOOT_OPTION_ADD. We also rename
PB_PROTOCOL_ACTION_ADD to make it clear that it is just for devices.

The discover server is updated to send boot option add events at device
discover time, but we are now able to decouple this later.

We also update the clients to handle the boot option add events
separately.

Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
12 files changed:
discover/device-handler.c
discover/discover-server.c
discover/discover-server.h
discover/event-parser.c
lib/pb-protocol/pb-protocol.c
lib/pb-protocol/pb-protocol.h
lib/types/types.h
ui/common/discover-client.c
ui/common/discover-client.h
ui/ncurses/nc-cui.c
ui/twin/pbt-client.c
ui/twin/pbt-menu.h

index 12bd5aed63a20ee56b45cd12e19f7d98a12c1901..ab27b51b2eaf764d98a37b7df3185dd49d46a20b 100644 (file)
@@ -275,6 +275,7 @@ static int handle_add_udev_event(struct device_handler *handler,
                struct event *event)
 {
        struct discover_context *ctx;
+       struct boot_option *opt;
        const char *devname;
        int rc;
 
@@ -311,7 +312,10 @@ static int handle_add_udev_event(struct device_handler *handler,
        /* add device to handler device array */
        device_handler_add(handler, ctx->device);
 
-       discover_server_notify_add(handler->server, ctx->device);
+       discover_server_notify_device_add(handler->server, ctx->device);
+
+       list_for_each_entry(&ctx->device->boot_options, opt, list)
+               discover_server_notify_boot_option_add(handler->server, opt);
 
        return 0;
 }
@@ -325,7 +329,7 @@ static int handle_remove_udev_event(struct device_handler *handler,
        if (!ctx)
                return 0;
 
-       discover_server_notify_remove(handler->server, ctx->device);
+       discover_server_notify_device_remove(handler->server, ctx->device);
 
        /* remove device from handler device array */
        device_handler_remove(handler, ctx->device);
@@ -338,6 +342,7 @@ static int handle_remove_udev_event(struct device_handler *handler,
 static int handle_add_user_event(struct device_handler *handler,
                struct event *event)
 {
+       struct boot_option *opt;
        struct device *device;
 
        assert(event->device);
@@ -352,7 +357,10 @@ static int handle_add_user_event(struct device_handler *handler,
 
        parse_user_event(device, event);
 
-       discover_server_notify_add(handler->server, device);
+       discover_server_notify_device_add(handler->server, device);
+
+       list_for_each_entry(&device->boot_options, opt, list)
+               discover_server_notify_boot_option_add(handler->server, opt);
 
        /* add device to handler device array */
        device_handler_add(handler, device);
@@ -372,7 +380,7 @@ static int handle_remove_user_event(struct device_handler *handler,
        if (!device)
                return 0;
 
-       discover_server_notify_remove(handler->server, device);
+       discover_server_notify_device_remove(handler->server, device);
 
        /* remove device from handler device array */
        device_handler_remove(handler, device);
index 9ec33826254f0515a79fc320aad89ca1def3f297..9f6e7daaa6793b40f8389ef69ee22edb35498d5d 100644 (file)
@@ -91,7 +91,7 @@ static int client_write_message(
        return rc;
 }
 
-static int write_add_message(struct discover_server *server,
+static int write_device_add_message(struct discover_server *server,
                struct client *client, const struct device *dev)
 {
        struct pb_protocol_message *message;
@@ -100,7 +100,7 @@ static int write_add_message(struct discover_server *server,
        len = pb_protocol_device_len(dev);
 
        message = pb_protocol_create_message(client,
-                       PB_PROTOCOL_ACTION_ADD, len);
+                       PB_PROTOCOL_ACTION_DEVICE_ADD, len);
        if (!message)
                return -1;
 
@@ -109,7 +109,25 @@ static int write_add_message(struct discover_server *server,
        return client_write_message(server, client, message);
 }
 
-static int write_remove_message(struct discover_server *server,
+static int write_boot_option_add_message(struct discover_server *server,
+               struct client *client, const struct boot_option *opt)
+{
+       struct pb_protocol_message *message;
+       int len;
+
+       len = pb_protocol_boot_option_len(opt);
+
+       message = pb_protocol_create_message(client,
+                       PB_PROTOCOL_ACTION_BOOT_OPTION_ADD, len);
+       if (!message)
+               return -1;
+
+       pb_protocol_serialise_boot_option(opt, message->payload, len);
+
+       return client_write_message(server, client, message);
+}
+
+static int write_device_remove_message(struct discover_server *server,
                struct client *client, char *dev_id)
 {
        struct pb_protocol_message *message;
@@ -118,7 +136,7 @@ static int write_remove_message(struct discover_server *server,
        len = strlen(dev_id) + sizeof(uint32_t);
 
        message = pb_protocol_create_message(client,
-                       PB_PROTOCOL_ACTION_REMOVE, len);
+                       PB_PROTOCOL_ACTION_DEVICE_REMOVE, len);
        if (!message)
                return -1;
 
@@ -183,9 +201,14 @@ static int discover_server_process_connection(void *arg)
        n_devices = device_handler_get_device_count(server->device_handler);
        for (i = 0; i < n_devices; i++) {
                const struct device *device;
+               struct boot_option *opt;
 
                device = device_handler_get_device(server->device_handler, i);
-               write_add_message(server, client, device);
+               write_device_add_message(server, client, device);
+
+               list_for_each_entry(&device->boot_options, opt, list)
+                       discover_server_notify_boot_option_add(server, opt);
+
        }
 
        waiter_register(server->waitset, client->fd, WAIT_IN,
@@ -194,23 +217,32 @@ static int discover_server_process_connection(void *arg)
        return 0;
 }
 
-void discover_server_notify_add(struct discover_server *server,
+void discover_server_notify_device_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);
+               write_device_add_message(server, client, device);
+
+}
 
+void discover_server_notify_boot_option_add(struct discover_server *server,
+               struct boot_option *boot_option)
+{
+       struct client *client;
+
+       list_for_each_entry(&server->clients, client, list)
+               write_boot_option_add_message(server, client, boot_option);
 }
 
-void discover_server_notify_remove(struct discover_server *server,
+void discover_server_notify_device_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);
+               write_device_remove_message(server, client, device->id);
 
 }
 
index 6650bba638095c9d91306eb3ef9d89520b03d1fe..e47cf5f67237125ef641b9ec4311261575edfdad 100644 (file)
@@ -5,6 +5,7 @@
 
 struct discover_server;
 struct device_handler;
+struct boot_option;
 struct device;
 
 struct discover_server *discover_server_init(struct waitset *waitset);
@@ -14,8 +15,10 @@ 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,
+void discover_server_notify_device_add(struct discover_server *server,
                struct device *device);
-void discover_server_notify_remove(struct discover_server *server,
+void discover_server_notify_boot_option_add(struct discover_server *server,
+               struct boot_option *option);
+void discover_server_notify_device_remove(struct discover_server *server,
                struct device *device);
 #endif /* _DISCOVER_SERVER_H */
index 0b96a09ba72365b774b406d94d30feb60f247530..1eec5c9cd410ca55f7a90a33f987e82a83a06c7d 100644 (file)
@@ -31,6 +31,7 @@ int parse_user_event(struct device *device, struct event *event)
        }
 
        opt->id = talloc_asprintf(opt, "%s#%s", device->id, p);
+       opt->device_id = talloc_strdup(opt, device->id);
        opt->name = talloc_strdup(opt, p);
 
        p = event_get_param(event, "image");
index c6d8f635ad6a495d5f9bd15b7c6b94e851d375b1..ded35eb5a1f5888b01374ac028fe9af2d68f2d0b 100644 (file)
@@ -161,26 +161,23 @@ static int optional_strlen(const char *str)
 
 int pb_protocol_device_len(const struct device *dev)
 {
-       struct boot_option *opt;
-       int len;
-
-       len =   4 + optional_strlen(dev->id) +
+       return  4 + optional_strlen(dev->id) +
                4 + optional_strlen(dev->name) +
                4 + optional_strlen(dev->description) +
-               4 + optional_strlen(dev->icon_file) +
-               4;
+               4 + optional_strlen(dev->icon_file);
+}
 
-       list_for_each_entry(&dev->boot_options, opt, list) {
-               len +=  4 + optional_strlen(opt->id) +
-                       4 + optional_strlen(opt->name) +
-                       4 + optional_strlen(opt->description) +
-                       4 + optional_strlen(opt->icon_file) +
-                       4 + optional_strlen(opt->boot_image_file) +
-                       4 + optional_strlen(opt->initrd_file) +
-                       4 + optional_strlen(opt->boot_args);
-       }
+int pb_protocol_boot_option_len(const struct boot_option *opt)
+{
 
-       return len;
+       return  4 + optional_strlen(opt->device_id) +
+               4 + optional_strlen(opt->id) +
+               4 + optional_strlen(opt->name) +
+               4 + optional_strlen(opt->description) +
+               4 + optional_strlen(opt->icon_file) +
+               4 + optional_strlen(opt->boot_image_file) +
+               4 + optional_strlen(opt->initrd_file) +
+               4 + optional_strlen(opt->boot_args);
 }
 
 int pb_protocol_boot_len(const struct boot_command *boot)
@@ -191,39 +188,35 @@ int pb_protocol_boot_len(const struct boot_command *boot)
                4 + optional_strlen(boot->boot_args);
 }
 
-int pb_protocol_serialise_device(const struct device *dev, char *buf, int buf_len)
+int pb_protocol_serialise_device(const struct device *dev,
+               char *buf, int buf_len)
 {
-       struct boot_option *opt;
-       uint32_t n;
-       char *pos;
-
-       pos = buf;
+       char *pos = buf;
 
-       /* construct payload into buffer */
        pos += pb_protocol_serialise_string(pos, dev->id);
        pos += pb_protocol_serialise_string(pos, dev->name);
        pos += pb_protocol_serialise_string(pos, dev->description);
        pos += pb_protocol_serialise_string(pos, dev->icon_file);
 
-       /* write option count */
-       n = 0;
+       assert(pos <= buf + buf_len);
+       (void)buf_len;
 
-       list_for_each_entry(&dev->boot_options, opt, list)
-               n++;
+       return 0;
+}
 
-       *(uint32_t *)pos = __cpu_to_be32(n);
-       pos += sizeof(uint32_t);
+int pb_protocol_serialise_boot_option(const struct boot_option *opt,
+               char *buf, int buf_len)
+{
+       char *pos = buf;
 
-       /* write each option */
-       list_for_each_entry(&dev->boot_options, opt, list) {
-               pos += pb_protocol_serialise_string(pos, opt->id);
-               pos += pb_protocol_serialise_string(pos, opt->name);
-               pos += pb_protocol_serialise_string(pos, opt->description);
-               pos += pb_protocol_serialise_string(pos, opt->icon_file);
-               pos += pb_protocol_serialise_string(pos, opt->boot_image_file);
-               pos += pb_protocol_serialise_string(pos, opt->initrd_file);
-               pos += pb_protocol_serialise_string(pos, opt->boot_args);
-       }
+       pos += pb_protocol_serialise_string(pos, opt->device_id);
+       pos += pb_protocol_serialise_string(pos, opt->id);
+       pos += pb_protocol_serialise_string(pos, opt->name);
+       pos += pb_protocol_serialise_string(pos, opt->description);
+       pos += pb_protocol_serialise_string(pos, opt->icon_file);
+       pos += pb_protocol_serialise_string(pos, opt->boot_image_file);
+       pos += pb_protocol_serialise_string(pos, opt->initrd_file);
+       pos += pb_protocol_serialise_string(pos, opt->boot_args);
 
        assert(pos <= buf + buf_len);
        (void)buf_len;
@@ -341,89 +334,95 @@ struct pb_protocol_message *pb_protocol_read_message(void *ctx, int fd)
 int pb_protocol_deserialise_device(struct device *dev,
                const struct pb_protocol_message *message)
 {
-       const char *pos;
-       int i, n_options;
        unsigned int len;
+       const char *pos;
+       int rc = -1;
 
        len = message->payload_len;
        pos = message->payload;
 
        if (read_string(dev, &pos, &len, &dev->id))
-               goto out_err;
+               goto out;
 
        if (read_string(dev, &pos, &len, &dev->name))
-               goto out_err;
+               goto out;
 
        if (read_string(dev, &pos, &len, &dev->description))
-               goto out_err;
+               goto out;
 
        if (read_string(dev, &pos, &len, &dev->icon_file))
-               goto out_err;
+               goto out;
 
-       n_options = __be32_to_cpu(*(uint32_t *)pos);
-       pos += sizeof(uint32_t);
+       rc = 0;
 
-       dev->n_options = n_options;
-
-       list_init(&dev->boot_options);
-
-       for (i = 0; i < n_options; i++) {
-               struct boot_option *opt;
-
-               opt = talloc(dev, struct boot_option);
-
-               if (read_string(opt, &pos, &len, &opt->id))
-                       goto out_err;
-               if (read_string(opt, &pos, &len, &opt->name))
-                       goto out_err;
-               if (read_string(opt, &pos, &len,
-                                       &opt->description))
-                       goto out_err;
-               if (read_string(opt, &pos, &len,
-                                       &opt->icon_file))
-                       goto out_err;
-               if (read_string(opt, &pos, &len,
-                                       &opt->boot_image_file))
-                       goto out_err;
-               if (read_string(opt, &pos, &len,
-                                       &opt->initrd_file))
-                       goto out_err;
-               if (read_string(opt, &pos, &len,
-                                       &opt->boot_args))
-                       goto out_err;
-
-               list_add(&dev->boot_options, &opt->list);
-       }
+out:
+       return rc;
+}
 
-       return 0;
+int pb_protocol_deserialise_boot_option(struct boot_option *opt,
+               const struct pb_protocol_message *message)
+{
+       unsigned int len;
+       const char *pos;
+       int rc = -1;
 
-out_err:
-       return -1;
+       len = message->payload_len;
+       pos = message->payload;
+
+       if (read_string(opt, &pos, &len, &opt->device_id))
+               goto out;
+
+       if (read_string(opt, &pos, &len, &opt->id))
+               goto out;
+
+       if (read_string(opt, &pos, &len, &opt->name))
+               goto out;
+
+       if (read_string(opt, &pos, &len, &opt->description))
+               goto out;
+
+       if (read_string(opt, &pos, &len, &opt->icon_file))
+               goto out;
+
+       if (read_string(opt, &pos, &len, &opt->boot_image_file))
+               goto out;
+
+       if (read_string(opt, &pos, &len, &opt->initrd_file))
+               goto out;
+
+       if (read_string(opt, &pos, &len, &opt->boot_args))
+               goto out;
+
+       rc = 0;
+
+out:
+       return rc;
 }
 
 int pb_protocol_deserialise_boot_command(struct boot_command *cmd,
                const struct pb_protocol_message *message)
 {
-       const char *pos;
        unsigned int len;
+       const char *pos;
+       int rc = -1;
 
        len = message->payload_len;
        pos = message->payload;
 
        if (read_string(cmd, &pos, &len, &cmd->option_id))
-               goto out_err;
+               goto out;
 
        if (read_string(cmd, &pos, &len, &cmd->boot_image_file))
-               goto out_err;
+               goto out;
 
        if (read_string(cmd, &pos, &len, &cmd->initrd_file))
-               goto out_err;
+               goto out;
 
        if (read_string(cmd, &pos, &len, &cmd->boot_args))
-               goto out_err;
+               goto out;
 
-       return 0;
+       rc = 0;
 
-out_err:
-       return -1;
+out:
+       return rc;
 }
index de2ae7c9e82f607893151e9d234fac36fc8a76af..35e96f0d1a7c510a25e44cdaf909fbe9858d6a93 100644 (file)
 #define PB_PROTOCOL_MAX_PAYLOAD_SIZE (64 * 1024)
 
 enum pb_protocol_action {
-       PB_PROTOCOL_ACTION_ADD          = 0x1,
-       PB_PROTOCOL_ACTION_REMOVE       = 0x2,
-       PB_PROTOCOL_ACTION_BOOT         = 0x3,
+       PB_PROTOCOL_ACTION_DEVICE_ADD           = 0x1,
+       PB_PROTOCOL_ACTION_BOOT_OPTION_ADD      = 0x2,
+       PB_PROTOCOL_ACTION_DEVICE_REMOVE        = 0x3,
+/*     PB_PROTOCOL_ACTION_BOOT_OPTION_REMOVE   = 0x4, */
+       PB_PROTOCOL_ACTION_BOOT                 = 0x5,
 };
 
 struct pb_protocol_message {
@@ -26,6 +28,7 @@ struct pb_protocol_message {
 void pb_protocol_dump_device(const struct device *dev, const char *text,
        FILE *stream);
 int pb_protocol_device_len(const struct device *dev);
+int pb_protocol_boot_option_len(const struct boot_option *opt);
 int pb_protocol_boot_len(const struct boot_command *boot);
 int pb_protocol_device_cmp(const struct device *a, const struct device *b);
 
@@ -36,7 +39,10 @@ int pb_protocol_serialise_string(char *pos, const char *str);
 char *pb_protocol_deserialise_string(void *ctx,
                const struct pb_protocol_message *message);
 
-int pb_protocol_serialise_device(const struct device *dev, char *buf, int buf_len);
+int pb_protocol_serialise_device(const struct device *dev,
+               char *buf, int buf_len);
+int pb_protocol_serialise_boot_option(const struct boot_option *opt,
+               char *buf, int buf_len);
 int pb_protocol_serialise_boot_command(const struct boot_command *boot,
                char *buf, int buf_len);
 
@@ -50,6 +56,9 @@ struct pb_protocol_message *pb_protocol_read_message(void *ctx, int fd);
 int pb_protocol_deserialise_device(struct device *dev,
                const struct pb_protocol_message *message);
 
+int pb_protocol_deserialise_boot_option(struct boot_option *opt,
+               const struct pb_protocol_message *message);
+
 int pb_protocol_deserialise_boot_command(struct boot_command *cmd,
                const struct pb_protocol_message *message);
 
index 1843557728814111383342402c64c98f46974514..fb53826902d7507e1f82d874c2fbc947167664d8 100644 (file)
@@ -16,6 +16,7 @@ struct device {
 };
 
 struct boot_option {
+       char            *device_id;
        char            *id;
        char            *name;
        char            *description;
index c0cfea0fe19a8ddae06d5b0546a2f6f504d6c369..42aa9de9a950a3877a7b3dad8c96b96d47305373 100644 (file)
@@ -1,4 +1,5 @@
 
+#include <assert.h>
 #include <errno.h>
 #include <unistd.h>
 #include <stdlib.h>
@@ -37,6 +38,20 @@ void discover_client_destroy(struct discover_client *client)
        talloc_free(client);
 }
 
+static struct device *find_device(struct discover_client *client,
+               const char *id)
+{
+       int i;
+
+       for (i = 0; i < client->n_devices; i++) {
+               struct device *dev = client->devices[i];
+               if (!strcmp(dev->id, id))
+                       return dev;
+       }
+
+       return NULL;
+}
+
 static void device_add(struct discover_client *client, struct device *device)
 {
        client->n_devices++;
@@ -46,7 +61,25 @@ static void device_add(struct discover_client *client, struct device *device)
        client->devices[client->n_devices - 1] = device;
        talloc_steal(client, device);
 
-       client->ops.device_add(device, client->ops.cb_arg);
+       if (client->ops.device_add)
+               client->ops.device_add(device, client->ops.cb_arg);
+}
+
+static void boot_option_add(struct discover_client *client,
+               struct boot_option *opt)
+{
+       struct device *dev;
+
+       dev = find_device(client, opt->device_id);
+
+       /* we require that devices are already present before any boot options
+        * are added */
+       assert(dev);
+
+       talloc_steal(dev, opt);
+
+       if (client->ops.boot_option_add)
+               client->ops.boot_option_add(dev, opt, client->ops.cb_arg);
 }
 
 static void device_remove(struct discover_client *client, const char *id)
@@ -81,6 +114,7 @@ static int discover_client_process(void *arg)
 {
        struct discover_client *client = arg;
        struct pb_protocol_message *message;
+       struct boot_option *opt;
        struct device *dev;
        char *dev_id;
        int rc;
@@ -91,8 +125,9 @@ static int discover_client_process(void *arg)
                return -1;
 
        switch (message->action) {
-       case PB_PROTOCOL_ACTION_ADD:
-               dev = talloc(client, struct device);
+       case PB_PROTOCOL_ACTION_DEVICE_ADD:
+               dev = talloc_zero(client, struct device);
+               list_init(&dev->boot_options);
 
                rc = pb_protocol_deserialise_device(dev, message);
                if (rc) {
@@ -102,7 +137,18 @@ static int discover_client_process(void *arg)
 
                device_add(client, dev);
                break;
-       case PB_PROTOCOL_ACTION_REMOVE:
+       case PB_PROTOCOL_ACTION_BOOT_OPTION_ADD:
+               opt = talloc_zero(client, struct boot_option);
+
+               rc = pb_protocol_deserialise_boot_option(opt, message);
+               if (rc) {
+                       pb_log("%s: no boot_option?\n", __func__);
+                       return 0;
+               }
+
+               boot_option_add(client, opt);
+               break;
+       case PB_PROTOCOL_ACTION_DEVICE_REMOVE:
                dev_id = pb_protocol_deserialise_string(client, message);
                if (!dev_id) {
                        pb_log("%s: no device id?\n", __func__);
index 6d5d1c483ac33b6c3bace0b3b457d4c6721cb6a6..5317b446f5407e50682b91a523d1889bfeaa4bc3 100644 (file)
@@ -21,6 +21,8 @@ struct pb_boot_data {
 
 struct discover_client_ops {
        int (*device_add)(struct device *device, void *arg);
+       int (*boot_option_add)(struct device *dev, struct boot_option *option,
+                       void *arg);
        void (*device_remove)(struct device *device, void *arg);
        void *cb_arg;
 };
index 2d4dea59a77d1ae872443e577480b143f780d6d8..c26819faeec7f988499934beb6f93902df3265f5 100644 (file)
@@ -142,7 +142,7 @@ static int cui_boot(struct pmenu_item *item)
 
        def_prog_mode();
 
-       result = discover_client_boot(cui->client, cod->dev, cod->opt, cod->bd);
+       result = discover_client_boot(cui->client, NULL, cod->opt, cod->bd);
 
        reset_prog_mode();
        redrawwin(cui->current->main_ncw);
@@ -354,16 +354,18 @@ void cui_on_open(struct pmenu *menu)
  * menu_items into the main menu.  Redraws the main menu if it is active.
  */
 
-static int cui_device_add(struct device *dev, void *arg)
+static int cui_boot_option_add(struct device *dev, struct boot_option *opt,
+               void *arg)
 {
        struct cui *cui = cui_from_arg(arg);
-       int result;
-       struct boot_option *opt;
-       unsigned int o_count; /* device opts */
+       struct cui_opt_data *cod;
        unsigned int insert_pt;
+       struct pmenu_item *i;
        ITEM *selected;
+       char *name;
+       int result;
 
-       pb_log("%s: %p %s\n", __func__, dev, dev->id);
+       pb_log("%s: %p %s\n", __func__, opt, opt->id);
 
        selected = current_item(cui->main->ncm);
 
@@ -377,57 +379,42 @@ static int cui_device_add(struct device *dev, void *arg)
        if (result)
                pb_log("%s: set_menu_items failed: %d\n", __func__, result);
 
-       o_count = 0;
-       list_for_each_entry(&dev->boot_options, opt, list)
-               o_count++;
-
        /* Insert new items at insert_pt. */
+       insert_pt = pmenu_grow(cui->main, 1);
 
-       insert_pt = pmenu_grow(cui->main, o_count);
-
-       list_for_each_entry(&dev->boot_options, opt, list) {
-               struct pmenu_item *i;
-               struct cui_opt_data *cod;
-               char *name;
-
-               /* Save the item in opt->ui_info for cui_device_remove() */
+       /* Save the item in opt->ui_info for cui_device_remove() */
 
-               opt->ui_info = i = pmenu_item_alloc(cui->main);
+       opt->ui_info = i = pmenu_item_alloc(cui->main);
 
-               i->on_edit = cui_boot_editor_run;
-               i->on_execute = cui_boot;
-               i->data = cod = talloc(i, struct cui_opt_data);
-
-               cod->dev = dev;
-               cod->opt = opt;
-               cod->opt_hash = pb_opt_hash(dev, opt);
-               cod->name = opt->name;
-               cod->bd = talloc(i, struct pb_boot_data);
-
-               cod->bd->image = talloc_strdup(cod->bd, opt->boot_image_file);
-               cod->bd->initrd = talloc_strdup(cod->bd, opt->initrd_file);
-               cod->bd->args = talloc_strdup(cod->bd, opt->boot_args);
-
-               name = cui_make_item_name(i, cod);
-               pmenu_item_setup(cui->main, i, insert_pt, name);
-
-               insert_pt++;
-
-               pb_log("%s: adding opt '%s'\n", __func__, cod->name);
-               pb_log("   image  '%s'\n", cod->bd->image);
-               pb_log("   initrd '%s'\n", cod->bd->initrd);
-               pb_log("   args   '%s'\n", cod->bd->args);
-
-               /* If this is the default_item select it and start timer. */
-
-               if (cod->opt_hash == cui->default_item) {
-                       selected = i->nci;
-                       ui_timer_kick(&cui->timer);
-               }
+       i->on_edit = cui_boot_editor_run;
+       i->on_execute = cui_boot;
+       i->data = cod = talloc(i, struct cui_opt_data);
+
+       cod->opt = opt;
+       cod->dev = dev;
+       cod->opt_hash = pb_opt_hash(dev, opt);
+       cod->name = opt->name;
+       cod->bd = talloc(i, struct pb_boot_data);
+
+       cod->bd->image = talloc_strdup(cod->bd, opt->boot_image_file);
+       cod->bd->initrd = talloc_strdup(cod->bd, opt->initrd_file);
+       cod->bd->args = talloc_strdup(cod->bd, opt->boot_args);
+
+       name = cui_make_item_name(i, cod);
+       pmenu_item_setup(cui->main, i, insert_pt, name);
+
+       pb_log("%s: adding opt '%s'\n", __func__, cod->name);
+       pb_log("   image  '%s'\n", cod->bd->image);
+       pb_log("   initrd '%s'\n", cod->bd->initrd);
+       pb_log("   args   '%s'\n", cod->bd->args);
+
+       /* If this is the default_item select it and start timer. */
+       if (cod->opt_hash == cui->default_item) {
+               selected = i->nci;
+               ui_timer_kick(&cui->timer);
        }
 
        /* Re-attach the items array. */
-
        result = set_menu_items(cui->main->ncm, cui->main->items);
 
        if (result)
@@ -506,7 +493,8 @@ static void cui_device_remove(struct device *dev, void *arg)
 }
 
 static struct discover_client_ops cui_client_ops = {
-       .device_add = cui_device_add,
+       .device_add = NULL,
+       .boot_option_add = cui_boot_option_add,
        .device_remove = cui_device_remove,
 };
 
index 875b40874fd845e2e43713e94bb7d9850e54f9ba..09d8e99c2518e5d138b3e3781b76ab7688d02afb 100644 (file)
@@ -63,7 +63,7 @@ static int pbt_client_boot(struct pbt_item *item)
                pbt_item_name(item));
 
        result = discover_client_boot(item->pbt_client->discover_client,
-                       opt_data->dev, opt_data->opt, opt_data->bd);
+                       NULL, opt_data->opt, opt_data->bd);
 
        if (result) {
                pb_log("%s: failed: %s\n", __func__, opt_data->bd->image);
@@ -83,101 +83,89 @@ static int pbt_client_on_edit(struct pbt_item *item)
 static int pbt_device_add(struct device *dev, struct pbt_client *client)
 {
        struct pbt_frame *const frame = &client->frame;
-       struct pbt_item *device_item;
-       struct boot_option *opt;
+       struct pbt_item *item;
        struct pbt_quad q;
        const char *icon_file;
-       struct pbt_item *selected_item = NULL;
 
        pb_log("%s: %p %s: n_options %d\n", __func__, dev, dev->id,
                dev->n_options);
 
        pb_protocol_dump_device(dev, "", pb_log_get_stream());
 
-       /* device_item */
-
        // FIXME: check for existing dev->id
 
        icon_file = dev->icon_file ? dev->icon_file : pbt_icon_chooser(dev->id);
 
-       device_item = pbt_item_create_reduced(frame->top_menu, dev->id,
+       item = pbt_item_create_reduced(frame->top_menu, dev->id,
                frame->top_menu->n_items, icon_file);
 
-       if (!device_item)
-               goto fail_device_item_create;
+       if (!item)
+               return -1;
 
-       device_item->pb_device = dev;
+       item->pb_device = dev;
+       dev->ui_info = item;
        frame->top_menu->n_items++;
 
        /* sub_menu */
-
        q.x = frame->top_menu->window->pixmap->width;
        q.y = 0;
        q.width = frame->top_menu->scr->tscreen->width - q.x;
        q.height = frame->top_menu->scr->tscreen->height;
 
-       device_item->sub_menu = pbt_menu_create(device_item, dev->id,
+       item->sub_menu = pbt_menu_create(item, dev->id,
                frame->top_menu->scr, frame->top_menu, &q,
                &frame->top_menu->layout);
-       if (!device_item->sub_menu)
-               goto fail_sub_menu_create;
+       if (!item->sub_menu)
+               return -1;
+
+       pbt_menu_show(frame->top_menu, 1);
 
-       list_for_each_entry(&dev->boot_options, opt, list) {
-               struct pbt_item *i;
-               struct pb_opt_data *opt_data;
+       return 0;
+}
+
+static int pbt_boot_option_add(struct device *dev, struct boot_option *opt,
+               struct pbt_client *client)
+{
+       struct pbt_item *opt_item, *device_item;
+       struct pb_opt_data *opt_data;
 
-               i = pbt_item_create(device_item->sub_menu,
+       device_item = dev->ui_info;
+
+       opt_item = pbt_item_create(device_item->sub_menu,
                        opt->id, device_item->sub_menu->n_items++,
                        opt->icon_file, opt->name, opt->description);
 
-               if (!i) {
-                       assert(0);
-                       break;
-               }
-
-               i->pb_opt = opt;
-               i->pbt_client = client;
-               i->on_execute = pbt_client_boot;
-               i->on_edit = pbt_client_on_edit;
-
-               i->data = opt_data = talloc(i, struct pb_opt_data);
-               opt_data->name = opt->name;
-               opt_data->bd = talloc(i, struct pb_boot_data);
-               opt_data->bd->image = talloc_strdup(opt_data->bd,
-                       opt->boot_image_file);
-               opt_data->bd->initrd = talloc_strdup(opt_data->bd,
-                       opt->initrd_file);
-               opt_data->bd->args = talloc_strdup(opt_data->bd,
-                       opt->boot_args);
-               opt_data->dev = dev;
-               opt_data->opt = opt;
-               opt_data->opt_hash = pb_opt_hash(dev, opt);
-
-               /* Select the first item as default. */
-
-               if (!selected_item)
-                       selected_item = i;
-
-               /* If this is the default_item select it and start timer. */
-
-               if (opt_data->opt_hash
-                       == device_item->sub_menu->default_item_hash) {
-                       selected_item = i;
-                       ui_timer_kick(&client->signal_data.timer);
-               }
+       opt_item->pb_opt = opt;
+       opt_item->pbt_client = client;
+       opt_item->on_execute = pbt_client_boot;
+       opt_item->on_edit = pbt_client_on_edit;
+
+       opt_item->data = opt_data = talloc(opt_item, struct pb_opt_data);
+       opt_data->name = opt->name;
+       opt_data->bd = talloc(opt_item, struct pb_boot_data);
+       opt_data->bd->image = talloc_strdup(opt_data->bd,
+               opt->boot_image_file);
+       opt_data->bd->initrd = talloc_strdup(opt_data->bd,
+               opt->initrd_file);
+       opt_data->bd->args = talloc_strdup(opt_data->bd,
+               opt->boot_args);
+       opt_data->opt = opt;
+       opt_data->opt_hash = pb_opt_hash(dev, opt);
+
+       /* If this is the default_item select it and start timer. */
+       if (opt_data->opt_hash == device_item->sub_menu->default_item_hash) {
+               device_item->selected_item = opt_item;
+               pbt_menu_set_selected(device_item->sub_menu, opt_item);
+               ui_timer_kick(&client->signal_data.timer);
        }
 
-       pbt_menu_set_selected(device_item->sub_menu, selected_item);
+       /* Select the first item as default. */
+       if (!device_item->selected_item)
+               pbt_menu_set_selected(device_item->sub_menu, opt_item);
 
-       pbt_menu_show(frame->top_menu, 1);
        twin_screen_update(client->frame.scr->tscreen);
 
        return 0;
-
-fail_sub_menu_create:
-fail_device_item_create:
-       assert(0);
-       return -1;
 }
 
 static void pbt_device_remove(struct device *dev, struct pbt_client *client)
@@ -248,6 +236,7 @@ static void pbt_device_remove(struct device *dev, struct pbt_client *client)
 
 static struct discover_client_ops pbt_client_ops = {
        .device_add = (void *)pbt_device_add,
+       .boot_option_add = (void *)pbt_boot_option_add,
        .device_remove = (void *)pbt_device_remove,
 };
 
index cb696eaa98b7bcce64dfef3b5a7c10d20afb5f19..698b64d2852a0558d9f312820beb625eb8fb00ac 100644 (file)
@@ -41,6 +41,7 @@ struct pbt_item
        twin_pixmap_t *pixmap_active;
 
        struct pbt_menu *sub_menu;
+       struct pbt_item *selected_item;
 
        int (*on_execute)(struct pbt_item *item);
        int (*on_edit)(struct pbt_item *item);