]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
add lxc.devttydir config variable
authorSerge Hallyn <serge@hallyn.com>
Thu, 16 Feb 2012 19:59:10 +0000 (13:59 -0600)
committerDaniel Lezcano <daniel.lezcano@free.fr>
Sun, 26 Feb 2012 09:44:41 +0000 (10:44 +0100)
If set, then the console and ttys will be bind-mounted not over /dev/console,
but /dev/<ttydir>/console and then symlinked from there to /dev/console.

Signed-off-by: Serge Hallyn <serge@hallyn.com>
Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com>
src/lxc/conf.c
src/lxc/conf.h
src/lxc/confile.c

index 0c2ceef65abfec41ff540889774316654cfcdcad..e8088bb0973b2acfb3b83ed1dc43ad041a312226 100644 (file)
@@ -512,10 +512,10 @@ static int setup_utsname(struct utsname *utsname)
 }
 
 static int setup_tty(const struct lxc_rootfs *rootfs,
-                    const struct lxc_tty_info *tty_info)
+                    const struct lxc_tty_info *tty_info, char *ttydir)
 {
-       char path[MAXPATHLEN];
-       int i;
+       char path[MAXPATHLEN], lxcpath[MAXPATHLEN];
+       int i, ret;
 
        if (!rootfs->path)
                return 0;
@@ -524,17 +524,50 @@ static int setup_tty(const struct lxc_rootfs *rootfs,
 
                struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
 
-               snprintf(path, sizeof(path), "%s/dev/tty%d",
+               ret = snprintf(path, sizeof(path), "%s/dev/tty%d",
                         rootfs->mount, i + 1);
+               if (ret >= sizeof(path)) {
+                       ERROR("pathname too long for ttys");
+                       return -1;
+               }
+               if (ttydir) {
+                       /* create dev/lxc/tty%d" */
+                       snprintf(lxcpath, sizeof(lxcpath), "%s/dev/%s/tty%d",
+                                rootfs->mount, ttydir, i + 1);
+                       if (ret >= sizeof(lxcpath)) {
+                               ERROR("pathname too long for ttys");
+                               return -1;
+                       }
+                       ret = creat(lxcpath, 0660);
+                       if (ret==-1 && errno != EEXIST) {
+                               SYSERROR("error creating %s\n", lxcpath);
+                               return -1;
+                       }
+                       close(ret);
+                       ret = unlink(path);
+                       if (ret && errno != ENOENT) {
+                               SYSERROR("error unlinking %s\n", path);
+                               return -1;
+                       }
 
-               /* At this point I can not use the "access" function
-                * to check the file is present or not because it fails
-                * with EACCES errno and I don't know why :( */
+                       if (mount(pty_info->name, lxcpath, "none", MS_BIND, 0)) {
+                               WARN("failed to mount '%s'->'%s'",
+                                    pty_info->name, path);
+                               continue;
+                       }
 
-               if (mount(pty_info->name, path, "none", MS_BIND, 0)) {
-                       WARN("failed to mount '%s'->'%s'",
-                            pty_info->name, path);
-                       continue;
+                       snprintf(lxcpath, sizeof(lxcpath), "%s/tty%d", ttydir, i+1);
+                       ret = symlink(lxcpath, path);
+                       if (ret) {
+                               SYSERROR("failed to create symlink for tty %d\n", i+1);
+                               return -1;
+                       }
+               } else {
+                       if (mount(pty_info->name, path, "none", MS_BIND, 0)) {
+                               WARN("failed to mount '%s'->'%s'",
+                                               pty_info->name, path);
+                               continue;
+                       }
                }
        }
 
@@ -812,17 +845,18 @@ static int setup_personality(int persona)
        return 0;
 }
 
-static int setup_console(const struct lxc_rootfs *rootfs,
+static int setup_dev_console(const struct lxc_rootfs *rootfs,
                         const struct lxc_console *console)
 {
        char path[MAXPATHLEN];
        struct stat s;
+       int ret;
 
-       /* We don't have a rootfs, /dev/console will be shared */
-       if (!rootfs->path)
-               return 0;
-
-       snprintf(path, sizeof(path), "%s/dev/console", rootfs->mount);
+       ret = snprintf(path, sizeof(path), "%s/dev/console", rootfs->mount);
+       if (ret >= sizeof(path)) {
+               ERROR("console path too long\n");
+               return -1;
+       }
 
        if (access(path, F_OK)) {
                WARN("rootfs specified but no console found at '%s'", path);
@@ -851,10 +885,85 @@ static int setup_console(const struct lxc_rootfs *rootfs,
        }
 
        INFO("console has been setup");
+       return 0;
+}
+
+static int setup_ttydir_console(const struct lxc_rootfs *rootfs,
+                        const struct lxc_console *console,
+                        char *ttydir)
+{
+       char path[MAXPATHLEN], lxcpath[MAXPATHLEN];
+       int ret;
+
+       /* create rootfs/dev/<ttydir> directory */
+       ret = snprintf(path, sizeof(path), "%s/dev/%s", rootfs->mount,
+                      ttydir);
+       if (ret >= sizeof(path))
+               return -1;
+       ret = mkdir(path, 0755);
+       if (ret && errno != EEXIST) {
+               SYSERROR("failed with errno %d to create %s\n", errno, path);
+               return -1;
+       }
+       INFO("created %s\n", path);
+
+       ret = snprintf(lxcpath, sizeof(lxcpath), "%s/dev/%s/console",
+                      rootfs->mount, ttydir);
+       if (ret >= sizeof(lxcpath)) {
+               ERROR("console path too long\n");
+               return -1;
+       }
+
+       snprintf(path, sizeof(path), "%s/dev/console", rootfs->mount);
+       ret = unlink(path);
+       if (ret && errno != ENOENT) {
+               SYSERROR("error unlinking %s\n", path);
+               return -1;
+       }
+
+       ret = creat(lxcpath, 0660);
+       if (ret==-1 && errno != EEXIST) {
+               SYSERROR("error %d creating %s\n", errno, lxcpath);
+               return -1;
+       }
+       close(ret);
+
+       if (console->peer == -1) {
+               INFO("no console output required");
+               return 0;
+       }
+
+       if (mount(console->name, lxcpath, "none", MS_BIND, 0)) {
+               ERROR("failed to mount '%s' on '%s'", console->name, lxcpath);
+               return -1;
+       }
+
+       /* create symlink from rootfs/dev/console to 'lxc/console' */
+       snprintf(lxcpath, sizeof(lxcpath), "%s/console", ttydir);
+       ret = symlink(lxcpath, path);
+       if (ret) {
+               SYSERROR("failed to create symlink for console");
+               return -1;
+       }
+
+       INFO("console has been setup on %s", lxcpath);
 
        return 0;
 }
 
+static int setup_console(const struct lxc_rootfs *rootfs,
+                        const struct lxc_console *console,
+                        char *ttydir)
+{
+       /* We don't have a rootfs, /dev/console will be shared */
+       if (!rootfs->path)
+               return 0;
+       if (!ttydir)
+               return setup_dev_console(rootfs, console);
+
+       return setup_ttydir_console(rootfs, console, ttydir);
+}
+
 static int setup_cgroup(const char *name, struct lxc_list *cgroups)
 {
        struct lxc_list *iterator;
@@ -1908,12 +2017,12 @@ int lxc_setup(const char *name, struct lxc_conf *lxc_conf)
                return -1;
        }
 
-       if (setup_console(&lxc_conf->rootfs, &lxc_conf->console)) {
+       if (setup_console(&lxc_conf->rootfs, &lxc_conf->console, lxc_conf->ttydir)) {
                ERROR("failed to setup the console for '%s'", name);
                return -1;
        }
 
-       if (setup_tty(&lxc_conf->rootfs, &lxc_conf->tty_info)) {
+       if (setup_tty(&lxc_conf->rootfs, &lxc_conf->tty_info, lxc_conf->ttydir)) {
                ERROR("failed to setup the ttys for '%s'", name);
                return -1;
        }
index eff1828f896f7f517e578180efc6c8abbac614c2..24e7c43dcb907552ef7054c85cdcc00f71c20c79 100644 (file)
@@ -197,6 +197,7 @@ struct lxc_rootfs {
  * @caps       : list of the capabilities
  * @tty_info   : tty data
  * @console    : console data
+ * @ttydir     : directory (under /dev) in which to create console and ttys
  */
 struct lxc_conf {
        char *fstab;
@@ -213,6 +214,7 @@ struct lxc_conf {
        struct lxc_tty_info tty_info;
        struct lxc_console console;
        struct lxc_rootfs rootfs;
+       char *ttydir;
 };
 
 /*
index 1adce918b34d5fbae518dc2f6f6d9e8580e1d654..b305aef1c905188688c50709586e384632739d0b 100644 (file)
@@ -48,6 +48,7 @@ lxc_log_define(lxc_confile, lxc);
 static int config_personality(const char *, char *, struct lxc_conf *);
 static int config_pts(const char *, char *, struct lxc_conf *);
 static int config_tty(const char *, char *, struct lxc_conf *);
+static int config_ttydir(const char *, char *, struct lxc_conf *);
 static int config_cgroup(const char *, char *, struct lxc_conf *);
 static int config_mount(const char *, char *, struct lxc_conf *);
 static int config_rootfs(const char *, char *, struct lxc_conf *);
@@ -83,6 +84,7 @@ static struct config config[] = {
        { "lxc.arch",                 config_personality          },
        { "lxc.pts",                  config_pts                  },
        { "lxc.tty",                  config_tty                  },
+       { "lxc.devttydir",            config_ttydir               },
        { "lxc.cgroup",               config_cgroup               },
        { "lxc.mount",                config_mount                },
        { "lxc.rootfs.mount",         config_rootfs_mount         },
@@ -613,6 +615,24 @@ static int config_tty(const char *key, char *value, struct lxc_conf *lxc_conf)
        return 0;
 }
 
+static int config_ttydir(const char *key, char *value,
+                         struct lxc_conf *lxc_conf)
+{
+       char *path;
+
+       if (!value || strlen(value) == 0)
+               return 0;
+       path = strdup(value);
+       if (!path) {
+               SYSERROR("failed to strdup '%s': %m", value);
+               return -1;
+       }
+
+       lxc_conf->ttydir = path;
+
+       return 0;
+}
+
 static int config_cgroup(const char *key, char *value, struct lxc_conf *lxc_conf)
 {
        char *token = "lxc.cgroup.";