]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
Support block device for the rootfs
authordlezcano <dlezcano>
Mon, 16 Feb 2009 10:21:41 +0000 (10:21 +0000)
committerdlezcano <dlezcano>
Mon, 16 Feb 2009 10:21:41 +0000 (10:21 +0000)
From: Daniel Lezcano <dlezcano@fr.ibm.com>

Allow to specify a block device as the rootfs. The creation of the
container will try with brute force to determine the file system type.

Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com>
src/lxc/lxc_conf.c

index 872d05f14adabe2b4921f98b9b1d0f57e806ef04..83cce59736a0e0f08ed7e45872b03ec7f3c29b0f 100644 (file)
@@ -126,15 +126,42 @@ static int file_for_each_line(const char *file, file_cb callback,
                return -1;
        }
        
-       while (fgets(buffer, len, f))
-               if (callback(buffer, data))
+       while (fgets(buffer, len, f)) {
+               err = callback(buffer, data);
+               if (err)
                        goto out;
-       err = 0;
+       }
 out:
        fclose(f);
        return err;
 }
 
+static int char_left_gc(char *buffer, size_t len)
+{
+       int i;
+       for (i = 0; i < len; i++) {
+               if (buffer[i] == ' ' ||
+                   buffer[i] == '\t')
+                       continue;
+               return i;
+       }
+       return 0;
+}
+
+static int char_right_gc(char *buffer, size_t len)
+{
+       int i;
+       for (i = len - 1; i >= 0; i--) {
+               if (buffer[i] == ' '  ||
+                   buffer[i] == '\t' ||
+                   buffer[i] == '\n' ||
+                   buffer[i] == '\0')
+                       continue;
+               return i + 1;
+       }
+       return 0;
+}
+
 static int write_info(const char *path, const char *file, const char *info)
 {
        int fd, err = -1;
@@ -450,13 +477,134 @@ static int configure_tty(const char *name, int tty)
        return ret;
 }
 
+static int configure_find_fstype_cb(void* buffer, void *data)
+{
+       struct cbarg {
+               const char *rootfs;
+               const char *testdir;
+               char *fstype;
+               int mntopt;
+       } *cbarg = data;
+
+       char *fstype;
+
+       /* we don't try 'nodev' entries */
+       if (strstr(buffer, "nodev"))
+               return 0;
+
+       fstype = buffer;
+       fstype += char_left_gc(fstype, strlen(fstype));
+       fstype[char_right_gc(fstype, strlen(fstype))] = '\0';
+
+       if (mount(cbarg->rootfs, cbarg->testdir, fstype, cbarg->mntopt, NULL))
+               return 0;
+
+       /* found ! */
+       umount(cbarg->testdir);
+       strcpy(cbarg->fstype, fstype);
+
+       return 1;
+}
+
+/* find the filesystem type with brute force */
+static int configure_find_fstype(const char *rootfs, char *fstype, int mntopt)
+{
+       int i, found;
+       char buffer[MAXPATHLEN];
+
+       struct cbarg {
+               const char *rootfs;
+               const char *testdir;
+               char *fstype;
+               int mntopt;
+       } cbarg = {
+               .rootfs = rootfs,
+               .fstype = fstype,
+               .mntopt = mntopt,
+       };
+
+       /* first we check with /etc/filesystems, in case the modules
+        * are auto-loaded and fall back to the supported kernel fs
+        */
+       char *fsfile[] = {
+               "/etc/filesystems",
+               "/proc/filesystems",
+       };
+
+       cbarg.testdir = tempnam("/tmp", "lxc-");
+       if (!cbarg.testdir) {
+               lxc_log_syserror("failed to build a temp name");
+               return -1;
+       }
+
+       if (mkdir(cbarg.testdir, 0755)) {
+               lxc_log_syserror("failed to create temporary directory");
+               return -1;
+       }
+
+       for (i = 0; i < sizeof(fsfile)/sizeof(fsfile[0]); i++) {
+
+               found = file_for_each_line(fsfile[i],
+                                          configure_find_fstype_cb,
+                                          buffer, sizeof(buffer), &cbarg);
+
+               if (found < 0) {
+                       lxc_log_syserror("failed to read '%s'", fsfile[i]);
+                       goto out;
+               }
+
+               if (found)
+                       break;
+       }
+
+       if (!found) {
+               lxc_log_error("failed to determine fs type for '%s'", rootfs);
+               goto out;
+       }
+
+out:
+       rmdir(cbarg.testdir);
+       return found - 1;
+}
+
+static int configure_rootfs_dir_cb(const char *rootfs, const char *absrootfs,
+                                  FILE *f)
+{
+       return fprintf(f, "%s %s none bind 0 0\n", absrootfs, rootfs);
+}
+
+static int configure_rootfs_blk_cb(const char *rootfs, const char *absrootfs,
+                                  FILE *f)
+{
+       char fstype[MAXPATHLEN];
+
+       if (configure_find_fstype(absrootfs, fstype, 0)) {
+               lxc_log_error("failed to configure mount for block device '%s'",
+                             absrootfs);
+               return -1;
+       }
+
+       return fprintf(f, "%s %s %s defaults 0 0\n", absrootfs, rootfs, fstype);
+}
+
 static int configure_rootfs(const char *name, const char *rootfs)
 {
        char path[MAXPATHLEN];
        char absrootfs[MAXPATHLEN];
        char fstab[MAXPATHLEN];
+       struct stat s;
        FILE *f;
-       int ret;
+       int i, ret;
+
+       typedef int (*rootfs_cb)(const char *, const char *, FILE *);
+
+       struct rootfs_type {
+               int type;
+               rootfs_cb cb;
+       } rtfs_type[] = {
+               { __S_IFDIR, configure_rootfs_dir_cb },
+               { __S_IFBLK, configure_rootfs_blk_cb },
+       };
 
        if (!realpath(rootfs, absrootfs)) {
                lxc_log_syserror("failed to get real path for '%s'", rootfs);
@@ -465,36 +613,50 @@ static int configure_rootfs(const char *name, const char *rootfs)
 
        snprintf(path, MAXPATHLEN, LXCPATH "/%s/rootfs", name);
 
+       if (mkdir(path, 0755)) {
+               lxc_log_syserror("failed to create the '%s' directory", path);
+               return -1;
+       }
+
        if (access(absrootfs, F_OK)) {
                lxc_log_syserror("'%s' is not accessible", absrootfs);
                return -1;
        }
 
-       if (mkdir(path, 0755)) {
-               lxc_log_syserror("failed to create the '%s' directory", path);
+       if (stat(absrootfs, &s)) {
+               lxc_log_syserror("failed to stat '%s'", absrootfs);
                return -1;
        }
 
-       snprintf(fstab, MAXPATHLEN, LXCPATH "/%s/fstab", name);
+       for (i = 0; i < sizeof(rtfs_type)/sizeof(rtfs_type[0]); i++) {
 
-       f = fopen(fstab, "a+");
-       if (!f) {
-               lxc_log_syserror("failed to open fstab file");
-               return -1;
-       }
+               if (!__S_ISTYPE(s.st_mode, rtfs_type[i].type))
+                       continue;
 
-       ret = fprintf(f, "%s %s none bind 0 0\n", absrootfs, path);
+               snprintf(fstab, MAXPATHLEN, LXCPATH "/%s/fstab", name);
 
-       fclose(f);
+               f = fopen(fstab, "a+");
+               if (!f) {
+                       lxc_log_syserror("failed to open fstab file");
+                       return -1;
+               }
 
-       if (ret < 0) {
-               lxc_log_syserror("failed to add rootfs mount in fstab");
-               return -1;
-       }
+               ret = rtfs_type[i].cb(path, absrootfs, f);
+
+               fclose(f);
+
+               if (ret < 0) {
+                       lxc_log_error("failed to add rootfs mount in fstab");
+                       return -1;
+               }
 
-       snprintf(path, MAXPATHLEN, LXCPATH "/%s/rootfs/rootfs", name);
+               snprintf(path, MAXPATHLEN, LXCPATH "/%s/rootfs/rootfs", name);
 
-       return symlink(absrootfs, path);
+               return symlink(absrootfs, path);
+       }
+
+       lxc_log_error("unsupported rootfs type for '%s'", absrootfs);
+       return -1;
 }
 
 static int configure_pts(const char *name, int pts)