]> git.ozlabs.org Git - petitboot/blobdiff - discover/device-handler.c
discover/device-handler: Make boot_status() public
[petitboot] / discover / device-handler.c
index 9de2a1901ea16b41f1f78513bec59cfbfc302f87..1c69de02e7f85a8f9dfe5166af9d4bb2cbaab95a 100644 (file)
@@ -396,7 +396,7 @@ void device_handler_remove(struct device_handler *handler,
        talloc_free(device);
 }
 
-static void boot_status(void *arg, struct boot_status *status)
+void device_handler_boot_status(void *arg, struct boot_status *status)
 {
        struct device_handler *handler = arg;
 
@@ -445,8 +445,11 @@ static int default_timeout(void *arg)
 
        pb_log("Timeout expired, booting default option %s\n", opt->option->id);
 
+       platform_pre_boot();
+
        handler->pending_boot = boot(handler, handler->default_boot_option,
-                       NULL, handler->dry_run, boot_status, handler);
+                       NULL, handler->dry_run, device_handler_boot_status,
+                       handler);
        handler->pending_boot_is_default = true;
        return 0;
 }
@@ -871,7 +874,7 @@ int device_handler_discover(struct device_handler *handler,
        status->message = talloc_asprintf(status, _("Processing %s device %s"),
                                device_type_display_name(dev->device->type),
                                dev->device->id);
-       boot_status(handler, status);
+       device_handler_boot_status(handler, status);
 
        process_boot_option_queue(handler);
 
@@ -899,7 +902,7 @@ out:
         */
        status->message = talloc_asprintf(status,_("Processing %s complete"),
                                dev->device->id);
-       boot_status(handler, status);
+       device_handler_boot_status(handler, status);
 
        talloc_free(status);
        talloc_free(ctx);
@@ -922,7 +925,7 @@ int device_handler_dhcp(struct device_handler *handler,
         */
        status->message = talloc_asprintf(status, _("Processing dhcp event on %s"),
                                dev->device->id);
-       boot_status(handler, status);
+       device_handler_boot_status(handler, status);
 
        /* create our context */
        ctx = device_handler_discover_context_create(handler, dev);
@@ -938,7 +941,7 @@ int device_handler_dhcp(struct device_handler *handler,
         */
        status->message = talloc_asprintf(status,_("Processing %s complete"),
                                dev->device->id);
-       boot_status(handler, status);
+       device_handler_boot_status(handler, status);
 
        talloc_free(status);
        talloc_free(ctx);
@@ -956,7 +959,7 @@ int device_handler_conf(struct device_handler *handler,
        status = talloc_zero(handler, struct boot_status);
        status->type = BOOT_STATUS_INFO;
        status->message = talloc_asprintf(status, _("Processing user config"));
-       boot_status(handler, status);
+       device_handler_boot_status(handler, status);
 
        /* create our context */
        ctx = device_handler_discover_context_create(handler, dev);
@@ -968,7 +971,7 @@ int device_handler_conf(struct device_handler *handler,
 
        status->message = talloc_asprintf(status,
                                _("Processing user config complete"));
-       boot_status(handler, status);
+       device_handler_boot_status(handler, status);
 
        talloc_free(status);
        talloc_free(ctx);
@@ -1007,7 +1010,7 @@ void device_handler_boot(struct device_handler *handler,
        platform_pre_boot();
 
        handler->pending_boot = boot(handler, opt, cmd, handler->dry_run,
-                       boot_status, handler);
+                       device_handler_boot_status, handler);
        handler->pending_boot_is_default = false;
 }
 
@@ -1175,13 +1178,17 @@ void device_handler_process_url(struct device_handler *handler,
        }
 
        pb_url = pb_url_parse(event, event->params->value);
-       if (!pb_url || !pb_url->host) {
+       if (!pb_url || (pb_url->scheme != pb_url_file && !pb_url->host)) {
                status->message = talloc_asprintf(handler,
                                        _("Invalid config URL!"));
                goto msg;
        }
 
-       event->device = device_from_addr(event, pb_url);
+       if (pb_url->scheme == pb_url_file)
+               event->device = talloc_asprintf(event, "local");
+       else
+               event->device = device_from_addr(event, pb_url);
+
        if (!event->device) {
                status->message = talloc_asprintf(status,
                                        _("Unable to route to host %s"),
@@ -1190,6 +1197,8 @@ void device_handler_process_url(struct device_handler *handler,
        }
 
        dev = discover_device_create(handler, event->device);
+       if (pb_url->scheme == pb_url_file)
+               dev->device->type = DEVICE_TYPE_ANY;
        ctx = device_handler_discover_context_create(handler, dev);
        ctx->event = event;
 
@@ -1203,7 +1212,7 @@ void device_handler_process_url(struct device_handler *handler,
        status->message = talloc_asprintf(status, _("Config file %s parsed"),
                                        pb_url->file);
 msg:
-       boot_status(handler, status);
+       device_handler_boot_status(handler, status);
        talloc_free(status);
 }
 
@@ -1258,30 +1267,6 @@ static void device_handler_reinit_sources(struct device_handler *handler)
                        handler->dry_run);
 }
 
-static const char *fs_parameters(struct discover_device *dev,
-                                unsigned int rw_flags)
-{
-       const char *fstype = discover_device_get_param(dev, "ID_FS_TYPE");
-
-       /* XFS journals are not cross-endian compatible; don't try recovery
-        * even if we have a snapshot */
-       if (!strncmp(fstype, "xfs", strlen("xfs")))
-               return "norecovery";
-
-       /* If we have a snapshot available allow touching the filesystem */
-       if (dev->ramdisk)
-               return "";
-
-       if ((rw_flags | MS_RDONLY) != MS_RDONLY)
-               return "";
-
-       /* Avoid writes due to journal replay if we don't have a snapshot */
-       if (!strncmp(fstype, "ext4", strlen("ext4")))
-               return "norecovery";
-
-       return "";
-}
-
 static inline const char *get_device_path(struct discover_device *dev)
 {
        return dev->ramdisk ? dev->ramdisk->snapshot : dev->device_path;
@@ -1368,6 +1353,52 @@ static bool check_existing_mount(struct discover_device *dev)
        return mnt != NULL;
 }
 
+/*
+ * Attempt to mount a filesystem safely, while handling certain filesytem-
+ * specific options
+ */
+static int try_mount(const char *device_path, const char *mount_path,
+                            const char *fstype, unsigned long flags,
+                            bool have_snapshot)
+{
+       const char *fs, *safe_opts;
+       int rc;
+
+       /* Mount ext3 as ext4 instead so 'norecovery' can be used */
+       if (strncmp(fstype, "ext3", strlen("ext3")) == 0) {
+               pb_debug("Mounting ext3 filesystem as ext4\n");
+               fs = "ext4";
+       } else
+               fs = fstype;
+
+       if (strncmp(fs, "xfs", strlen("xfs")) == 0 ||
+           strncmp(fs, "ext4", strlen("ext4")) == 0)
+               safe_opts = "norecovery";
+       else
+               safe_opts = NULL;
+
+       errno = 0;
+       /* If no snapshot is available don't attempt recovery */
+       if (!have_snapshot)
+               return mount(device_path, mount_path, fs, flags, safe_opts);
+
+       rc = mount(device_path, mount_path, fs, flags, NULL);
+
+       if (!rc)
+               return rc;
+
+       /* Mounting failed; some filesystems will fail to mount if a recovery
+        * journal exists (eg. cross-endian XFS), so try again with norecovery
+        * where that option is available.
+        * If mounting read-write just return the error as norecovery is not a
+        * valid option */
+       if ((flags & MS_RDONLY) != MS_RDONLY || !safe_opts)
+               return rc;
+
+       errno = 0;
+       return mount(device_path, mount_path, fs, flags, safe_opts);
+}
+
 static int mount_device(struct discover_device *dev)
 {
        const char *fstype, *device_path;
@@ -1386,13 +1417,6 @@ static int mount_device(struct discover_device *dev)
        if (!fstype)
                return 0;
 
-       /* ext3 treats the norecovery option as an error, so mount the device
-        * as an ext4 filesystem instead */
-       if (!strncmp(fstype, "ext3", strlen("ext3"))) {
-               pb_debug("Mounting ext3 filesystem as ext4\n");
-               fstype = talloc_asprintf(dev, "ext4");
-       }
-
        dev->mount_path = join_paths(dev, mount_base(),
                                        dev->device_path);
 
@@ -1405,10 +1429,9 @@ static int mount_device(struct discover_device *dev)
        device_path = get_device_path(dev);
 
        pb_log("mounting device %s read-only\n", dev->device_path);
-       errno = 0;
-       rc = mount(device_path, dev->mount_path, fstype,
-                       MS_RDONLY | MS_SILENT,
-                       fs_parameters(dev, MS_RDONLY));
+       rc = try_mount(device_path, dev->mount_path, fstype,
+                      MS_RDONLY | MS_SILENT, dev->ramdisk);
+
        if (!rc) {
                dev->mounted = true;
                dev->mounted_rw = false;
@@ -1488,9 +1511,8 @@ int device_request_write(struct discover_device *dev, bool *release)
                return -1;
        }
 
-       rc = mount(device_path, dev->mount_path, fstype,
-                       MS_SILENT,
-                       fs_parameters(dev, MS_REMOUNT));
+       rc = try_mount(device_path, dev->mount_path, fstype,
+                      MS_SILENT, dev->ramdisk);
        if (rc)
                goto mount_ro;
 
@@ -1501,9 +1523,9 @@ int device_request_write(struct discover_device *dev, bool *release)
 mount_ro:
        pb_log("Unable to remount device %s read-write: %s\n",
               device_path, strerror(errno));
-       if (mount(device_path, dev->mount_path, fstype,
-                       MS_RDONLY | MS_SILENT,
-                       fs_parameters(dev, MS_RDONLY)))
+       rc = try_mount(device_path, dev->mount_path, fstype,
+                      MS_RDONLY | MS_SILENT, dev->ramdisk);
+       if (rc)
                pb_log("Unable to recover mount for %s: %s\n",
                       device_path, strerror(errno));
        return -1;
@@ -1534,9 +1556,8 @@ void device_release_write(struct discover_device *dev, bool release)
                device_path = get_device_path(dev);
        }
 
-       if (mount(device_path, dev->mount_path, fstype,
-                       MS_RDONLY | MS_SILENT,
-                       fs_parameters(dev, MS_RDONLY)))
+       if (try_mount(device_path, dev->mount_path, fstype,
+                      MS_RDONLY | MS_SILENT, dev->ramdisk))
                pb_log("Failed to remount %s read-only: %s\n",
                       device_path, strerror(errno));
        else