Resolve device paths in kernel and initrd locations.
authorJeremy Kerr <jk@ozlabs.org>
Wed, 27 Jun 2007 01:02:38 +0000 (11:02 +1000)
committerJeremy Kerr <jk@ozlabs.org>
Wed, 27 Jun 2007 01:02:38 +0000 (11:02 +1000)
Instead of mounting in random locations, create a fixed mapping between
device and mountpoint. This allows the parsers to refer to files
outside the current partition.

Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
devices/kboot-parser.c
devices/parser-test.c
devices/parser.c
devices/parser.h
devices/udev-helper.c
devices/yaboot-parser.c
petitboot-paths.h
utils/ps3-kboot-0.1-petitboot.patch

index d449ef673e4b5c8d4cc218e79d9dd619a1257373..b70d5fca82b1290efba3f44550dc95d0ace1c582 100644 (file)
@@ -138,13 +138,13 @@ static int parse_option(struct boot_option *opt, char *config)
 
        /* if there's no space, it's only a kernel image with no params */
        if (!pos) {
-               opt->boot_image_file = join_paths(mountpoint, config);
+               opt->boot_image_file = resolve_path(config, mountpoint);
                opt->description = strdup(config);
                return 1;
        }
 
        *pos = 0;
-       opt->boot_image_file = join_paths(mountpoint, config);
+       opt->boot_image_file = resolve_path(config, mountpoint);
 
        cmdline = malloc(buf_size);
        *cmdline = 0;
@@ -179,7 +179,7 @@ static int parse_option(struct boot_option *opt, char *config)
                free(cmdline);
                cmdline = tmp;
 
-               opt->initrd_file = join_paths(mountpoint, initrd);
+               opt->initrd_file = resolve_path(initrd, mountpoint);
        }
 
        if (root) {
@@ -197,7 +197,8 @@ static int parse_option(struct boot_option *opt, char *config)
        pb_log("kboot cmdline: %s\n", cmdline);
        opt->boot_args = cmdline;
 
-       asprintf(&opt->description, "%s %s", config, cmdline);
+       asprintf(&opt->description, "%s %s",
+                       config, opt->boot_args);
 
        return 1;
 }
index 4b134d0e5bd4eba470322a83eaa6c3f94c5a2b81..9622d4d31463e0268207483507f1b990fddaa42c 100644 (file)
@@ -1,8 +1,10 @@
+#define _GNU_SOURCE
 
 #include <stdlib.h>
 #include <stdio.h>
 #include <stdarg.h>
 #include <unistd.h>
+#include <string.h>
 
 #include "parser.h"
 
@@ -16,10 +18,10 @@ void pb_log(const char *fmt, ...)
 }
 
 
-int mount_device(const char *dev_path, char *mount_path)
+int mount_device(const char *dev_path)
 {
        pb_log("attempt to mount device (%s) not supported\n", dev_path);
-       return -1;
+       return 0;
 }
 
 int add_device(const struct device *dev)
@@ -48,16 +50,49 @@ enum generic_icon_type guess_device_type(void)
        return ICON_TYPE_UNKNOWN;
 }
 
+static char *mountpoint;
+
+const char *mountpoint_for_device(const char *dev_path)
+{
+       char *tmp, *dev;
+       dev = strrchr(dev_path, '/');
+       if (dev)
+               dev_path = dev + 1;
+       asprintf(&tmp, "%s/%s", mountpoint, dev_path);
+       return tmp;
+}
+
+char *resolve_path(const char *path, const char *default_mountpoint)
+{
+       char *sep, *ret;
+       const char *devpath;
+
+       sep = strchr(path, ':');
+       if (!sep) {
+               devpath = default_mountpoint;
+               asprintf(&ret, "%s/%s", devpath, path);
+       } else {
+               char *tmp = strndup(path, sep - path);
+               devpath = mountpoint_for_device(path);
+               asprintf(&ret, "%s/%s", devpath, sep + 1);
+               free(tmp);
+       }
+
+       return ret;
+}
+
 int main(int argc, char **argv)
 {
-       const char *dev = "/dev/null";
+       const char *dev = "sda1";
 
        if (argc != 2) {
                fprintf(stderr, "usage: %s <fake-mountpoint>\n", argv[0]);
                return EXIT_FAILURE;
        }
 
-       iterate_parsers(dev, argv[1]);
+       mountpoint = argv[1];
+
+       iterate_parsers(dev, mountpoint);
 
        return EXIT_SUCCESS;
 }
index d1cdb43b632cab6255c7bc4c70ab9fdc1952ae78..00f36598f0e25e4431feab15cf2cc67c3bd447ba 100644 (file)
@@ -21,12 +21,12 @@ void iterate_parsers(const char *devpath, const char *mountpoint)
 {
        int i;
 
-       pb_log("trying parsers for %s@%s\n", devpath, mountpoint);
+       pb_log("trying parsers for %s\n", devpath);
 
        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, mountpoint))
+               if (parsers[i]->parse(devpath, mountpoint_for_device(devpath)))
                        return;
        }
        pb_log("\tno boot_options found\n");
index 2034cf194ad0581bec38ab5248e6c3fa2d5e664b..840ca1b9d477ee56b50984af58ee5993ee71f0bb 100644 (file)
@@ -35,7 +35,10 @@ 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 *mount_path);
+int mount_device(const char *dev_path);
+
+char *resolve_path(const char *path, const char *default_mountpoint);
+const char *mountpoint_for_device(const char *dev_path);
 
 enum generic_icon_type guess_device_type(void);
 
index 4ec054b38411ad8e053a2f3171de89dc2e865e84..661fb08b4ef9c2021984109b78d2d3af68fe9943 100644 (file)
@@ -1,4 +1,6 @@
 
+#define _GNU_SOURCE
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
@@ -181,28 +183,92 @@ int connect_to_socket()
 #endif
 }
 
-int mount_device(const char *dev_path, char *mount_path)
+struct device_map {
+       char *dev, *mnt;
+};
+
+#define DEVICE_MAP_SIZE 32
+static struct device_map device_map[DEVICE_MAP_SIZE];
+
+const char *mountpoint_for_device(const char *dev_path)
 {
-       char *dir;
+       int i;
        const char *basename;
-       int pid, status, rc = -1;
 
-       basename = strrchr(dev_path, '/');
-       if (basename)
-               basename++;
-       else
+       /* shorten '/dev/foo' to 'foo' */
+       basename = strrchr(dev_path, '/');
+       if (basename)
+               basename++;
+       else
                basename = dev_path;
-       /* create a unique mountpoint */
-       dir = malloc(strlen(TMP_DIR) + 13 + strlen(basename));
-       sprintf(dir, "%s/mnt-%s-XXXXXX", TMP_DIR, basename);
-
-       if (!mkdtemp(dir)) {
-               pb_log("failed to create temporary directory in %s: %s",
-                               TMP_DIR, strerror(errno));
-               goto out;
+
+       /* check existing entries in the map */
+       for (i = 0; (i < DEVICE_MAP_SIZE) && device_map[i].dev; i++)
+               if (!strcmp(device_map[i].dev, basename))
+                       return device_map[i].mnt;
+
+       if (i == DEVICE_MAP_SIZE)
+               return NULL;
+
+       device_map[i].dev = strdup(dev_path);
+       asprintf(&device_map[i].mnt, "%s/%s", TMP_DIR, basename);
+       return device_map[i].mnt;
+}
+
+/**
+ * Resolve a path given in a config file, to a path in the local filesystem.
+ * Paths may be of the form:
+ *  device:path (eg /dev/sda:/boot/vmlinux)
+ *
+ * or just a path:
+ *  /boot/vmlinux
+ * - in this case, the default mountpoint is used.
+ *
+ * Returns a newly-allocated string containing a full path to the file in path
+ */
+char *resolve_path(const char *path, const char *default_mountpoint)
+{
+       char *ret;
+       const char *devpath, *sep;
+
+       sep = strchr(path, ':');
+       if (!sep) {
+               devpath = default_mountpoint;
+               asprintf(&ret, "%s/%s", devpath, path);
+       } else {
+               /* copy just the device name into tmp */
+               char *dev = strndup(path, sep - path);
+               devpath = mountpoint_for_device(dev);
+               asprintf(&ret, "%s/%s", devpath, sep + 1);
+               free(dev);
        }
 
+       return ret;
+}
+
+int mount_device(const char *dev_path)
+{
+       const char *dir;
+       int pid, status, rc = -1;
+       struct stat statbuf;
+
+       dir = mountpoint_for_device(dev_path);
+
+       if (stat(dir, &statbuf)) {
+               if (mkdir(dir, 0755)) {
+                       pb_log("couldn't create directory %s: %s\n",
+                                       dir, strerror(errno));
+                       goto out;
+               }
+       } else {
+               if (!S_ISDIR(statbuf.st_mode)) {
+                       pb_log("mountpoint %s exists, "
+                                       "but isn't a directory\n", dir);
+                       goto out;
+               }
+       }
+
+
        pid = fork();
        if (pid == -1) {
                pb_log("%s: fork failed: %s\n", __FUNCTION__, strerror(errno));
@@ -220,13 +286,10 @@ int mount_device(const char *dev_path, char *mount_path)
                goto out;
        }
 
-       if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
-               strcpy(mount_path, dir);
+       if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
                rc = 0;
-       }
 
 out:
-       free(dir);
        return rc;
 }
 
@@ -348,9 +411,9 @@ static int is_ignored_device(const char *devname)
 
 static int found_new_device(const char *dev_path)
 {
-       char mountpoint[PATH_MAX];
+       const char *mountpoint = mountpoint_for_device(dev_path);
 
-       if (mount_device(dev_path, mountpoint)) {
+       if (mount_device(dev_path)) {
                pb_log("failed to mount %s\n", dev_path);
                return EXIT_FAILURE;
        }
index 23249509cdd04b18329f36bf590fd0ff29fb02cf..fc55047809b09ad6e8b8fc8fc533406fca363498 100644 (file)
@@ -15,7 +15,6 @@
 
 static struct device *dev;
 static const char *mountpoint;
-static char partition_mntpoint[PATH_MAX];
 static char *defimage;
 
 char *
@@ -103,13 +102,13 @@ void process_image(char *label)
 
        opt.name = label;
        cfgopt = cfg_get_strg(label, "image");
-       opt.boot_image_file = join_paths(mountpoint, cfgopt);
+       opt.boot_image_file = resolve_path(cfgopt, mountpoint);
        if (cfgopt == defimage)
                pb_log("This one is default. What do we do about it?\n");
 
        cfgopt = cfg_get_strg(label, "initrd");
        if (cfgopt)
-               opt.initrd_file = join_paths(mountpoint, cfgopt);
+               opt.initrd_file = resolve_path(cfgopt, mountpoint);
 
        opt.boot_args = make_params(label, NULL);
 
@@ -182,8 +181,8 @@ static int yaboot_parse(const char *devicepath, const char *_mountpoint)
        }
        dev->icon_file = strdup(generic_icon_file(guess_device_type()));
 
-       /* Mount the 'partition' which is what all the image filenames
-          are relative to */
+       /* If we have a 'partiton=' directive, update the default mountpoint
+        * to use that instead of the current mountpoint */
        tmpstr = cfg_get_strg(0, "partition");
        if (tmpstr) {
                char *endp;
@@ -203,16 +202,9 @@ static int yaboot_parse(const char *devicepath, const char *_mountpoint)
                        /* and add our own... */
                        sprintf(endp+1, "%d", partnr);
 
-                       /* FIXME: udev may not have created the device node
-                          yet. And on removal, unmount_device() only unmounts
-                          it once, while in fact it may be mounted twice. */
-                       if (mount_device(new_dev, partition_mntpoint)) {
-                               pb_log("Error mounting image partition\n");
-                               return 0;
-                       }
-                       mountpoint = partition_mntpoint;
+                       mountpoint = mountpoint_for_device(new_dev);
                        dev->id = new_dev;
-               }                               
+               }
        }
 
        defimage = cfg_get_default();
index 114d0b22b2a37bf4f185538ea3d67c7fc54afb18..f8c59646e537362e1d5ebdc8b6bf47e6aeeed539 100644 (file)
@@ -10,7 +10,7 @@
 #endif
 
 #ifndef TMP_DIR
-#define TMP_DIR "/var/tmp"
+#define TMP_DIR "/var/tmp/mnt/"
 #endif
 
 #define PBOOT_DEVICE_SOCKET "/var/tmp/petitboot-dev"
index 651f5480ebd845d8b59f10ffab2b43e5e7494076..a33fa24697c40cd53129a2c64f460dd6602144f7 100644 (file)
@@ -50,7 +50,7 @@ More info at http://ozlabs.org/~jk/projects/petitboot/
 +      find root/ -name '*.a' -o -name '*.la' -exec rm {} \;
        mkdir -p root/etc root/tmp root/proc root/dev root/sys
        mkdir -p root/mnt/tmp root/mnt/root root/bin root/sbin
-+      mkdir -p root/var/tmp
++      mkdir -p root/var/tmp/mnt
 +      mkdir -p root/etc/udev/rules.d
        [ -e root/dev/console ] || mknod root/dev/console c 5 1
        [ -e root/dev/null ] || mknod root/dev/null c 1 3
@@ -283,7 +283,7 @@ diff -urN ps3-kboot.orig/ps3-kboot-0.1/scripts/petitboot-init ps3-kboot/ps3-kboo
 +      /sbin/petitboot -u
 +
 +      # clean up after petitboot
-+      for dir in /var/tmp/mnt-*;
++      for dir in /var/tmp/mnt/*;
 +      do
 +              umount "$dir"
 +              rmdir "$dir"