ui/ncurses: Allow booting custom boot options
[petitboot] / ui / common / discover-client.c
index c0cfea0fe19a8ddae06d5b0546a2f6f504d6c369..fea8c573c7d18516657dca663c94525164a1ccda 100644 (file)
@@ -1,4 +1,5 @@
 
 
+#include <assert.h>
 #include <errno.h>
 #include <unistd.h>
 #include <stdlib.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);
 }
 
        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++;
 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->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)
 }
 
 static void device_remove(struct discover_client *client, const char *id)
@@ -77,10 +110,29 @@ static void device_remove(struct discover_client *client, const char *id)
        talloc_free(device);
 }
 
        talloc_free(device);
 }
 
+static void update_status(struct discover_client *client,
+               struct boot_status *status)
+{
+       if (client->ops.update_status)
+               client->ops.update_status(status, client->ops.cb_arg);
+       talloc_free(status);
+}
+
+static void update_sysinfo(struct discover_client *client,
+               struct system_info *sysinfo)
+{
+       if (client->ops.update_sysinfo)
+               client->ops.update_sysinfo(sysinfo, client->ops.cb_arg);
+       talloc_free(sysinfo);
+}
+
 static int discover_client_process(void *arg)
 {
        struct discover_client *client = arg;
        struct pb_protocol_message *message;
 static int discover_client_process(void *arg)
 {
        struct discover_client *client = arg;
        struct pb_protocol_message *message;
+       struct system_info *sysinfo;
+       struct boot_status *status;
+       struct boot_option *opt;
        struct device *dev;
        char *dev_id;
        int rc;
        struct device *dev;
        char *dev_id;
        int rc;
@@ -91,8 +143,9 @@ static int discover_client_process(void *arg)
                return -1;
 
        switch (message->action) {
                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) {
 
                rc = pb_protocol_deserialise_device(dev, message);
                if (rc) {
@@ -102,7 +155,18 @@ static int discover_client_process(void *arg)
 
                device_add(client, dev);
                break;
 
                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__);
                dev_id = pb_protocol_deserialise_string(client, message);
                if (!dev_id) {
                        pb_log("%s: no device id?\n", __func__);
@@ -110,6 +174,26 @@ static int discover_client_process(void *arg)
                }
                device_remove(client, dev_id);
                break;
                }
                device_remove(client, dev_id);
                break;
+       case PB_PROTOCOL_ACTION_STATUS:
+               status = talloc_zero(client, struct boot_status);
+
+               rc = pb_protocol_deserialise_boot_status(status, message);
+               if (rc) {
+                       pb_log("%s: invalid status message?\n", __func__);
+                       return 0;
+               }
+               update_status(client, status);
+               break;
+       case PB_PROTOCOL_ACTION_SYSTEM_INFO:
+               sysinfo = talloc_zero(client, struct system_info);
+
+               rc = pb_protocol_deserialise_system_info(sysinfo, message);
+               if (rc) {
+                       pb_log("%s: invalid sysinfo message?\n", __func__);
+                       return 0;
+               }
+               update_sysinfo(client, sysinfo);
+               break;
        default:
                pb_log("%s: unknown action %d\n", __func__, message->action);
        }
        default:
                pb_log("%s: unknown action %d\n", __func__, message->action);
        }
@@ -150,8 +234,8 @@ struct discover_client* discover_client_init(struct waitset *waitset,
                goto out_err;
        }
 
                goto out_err;
        }
 
-       waiter_register(waitset, client->fd, WAIT_IN, discover_client_process,
-                       client);
+       waiter_register_io(waitset, client->fd, WAIT_IN,
+                       discover_client_process, client);
 
        return client;
 
 
        return client;
 
@@ -180,10 +264,10 @@ static void create_boot_command(struct boot_command *command,
                const struct boot_option *boot_option,
                const struct pb_boot_data *data)
 {
                const struct boot_option *boot_option,
                const struct pb_boot_data *data)
 {
-
-       command->option_id = boot_option->id;
+       command->option_id = boot_option ? boot_option->id : NULL;
        command->boot_image_file = data->image;
        command->initrd_file = data->initrd;
        command->boot_image_file = data->image;
        command->initrd_file = data->initrd;
+       command->dtb_file = data->dtb;
        command->boot_args = data->args;
 }
 
        command->boot_args = data->args;
 }
 
@@ -213,3 +297,16 @@ int discover_client_boot(struct discover_client *client,
 
        return rc;
 }
 
        return rc;
 }
+
+int discover_client_cancel_default(struct discover_client *client)
+{
+       struct pb_protocol_message *message;
+
+       message = pb_protocol_create_message(client,
+                       PB_PROTOCOL_ACTION_CANCEL_DEFAULT, 0);
+
+       if (!message)
+               return -1;
+
+       return pb_protocol_write_message(client->fd, message);
+}