]> git.ozlabs.org Git - petitboot/blobdiff - discover/device-handler.c
Extend the "add url" function to allow file:// URLs
[petitboot] / discover / device-handler.c
index 77f9e3c59b9bb761d02a668f26ad130187f516d9..cc48747331dc6f3c6d161583499f5ca2d9ce5524 100644 (file)
@@ -445,6 +445,8 @@ 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);
        handler->pending_boot_is_default = true;
@@ -1099,10 +1101,12 @@ static char *device_from_addr(void *ctx, struct pb_url *url)
 
        rc = process_run_sync(p);
 
-       if (rc) {
+       if (rc || p->exit_status) {
                /* ip has complained for some reason; most likely
                 * there is no route to the host - bail out */
-               pb_debug("%s: No route to %s\n",__func__,url->host);
+               pb_debug("%s: `ip` returns non-zero exit status\n", __func__);
+               pb_debug("ip buf: %s\n", p->stdout_buf);
+               process_release(p);
                return NULL;
        }
 
@@ -1173,13 +1177,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"),
@@ -1188,6 +1196,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;
 
@@ -1256,30 +1266,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;
@@ -1366,6 +1352,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;
@@ -1384,13 +1416,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);
 
@@ -1403,10 +1428,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;
@@ -1486,9 +1510,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;
 
@@ -1499,9 +1522,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;
@@ -1532,9 +1555,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