Commit 7c6ef2a2 by Serge Hallyn Committed by Daniel Lezcano

add lxc.devttydir config variable

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: 's avatarSerge Hallyn <serge@hallyn.com> Signed-off-by: 's avatarDaniel Lezcano <dlezcano@fr.ibm.com>
parent 5d325fcf
...@@ -512,10 +512,10 @@ static int setup_utsname(struct utsname *utsname) ...@@ -512,10 +512,10 @@ static int setup_utsname(struct utsname *utsname)
} }
static int setup_tty(const struct lxc_rootfs *rootfs, 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]; char path[MAXPATHLEN], lxcpath[MAXPATHLEN];
int i; int i, ret;
if (!rootfs->path) if (!rootfs->path)
return 0; return 0;
...@@ -524,17 +524,50 @@ static int setup_tty(const struct lxc_rootfs *rootfs, ...@@ -524,17 +524,50 @@ static int setup_tty(const struct lxc_rootfs *rootfs,
struct lxc_pty_info *pty_info = &tty_info->pty_info[i]; 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); 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 if (mount(pty_info->name, lxcpath, "none", MS_BIND, 0)) {
* to check the file is present or not because it fails WARN("failed to mount '%s'->'%s'",
* with EACCES errno and I don't know why :( */ pty_info->name, path);
continue;
}
if (mount(pty_info->name, path, "none", MS_BIND, 0)) { snprintf(lxcpath, sizeof(lxcpath), "%s/tty%d", ttydir, i+1);
WARN("failed to mount '%s'->'%s'", ret = symlink(lxcpath, path);
pty_info->name, path); if (ret) {
continue; 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) ...@@ -812,17 +845,18 @@ static int setup_personality(int persona)
return 0; 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) const struct lxc_console *console)
{ {
char path[MAXPATHLEN]; char path[MAXPATHLEN];
struct stat s; struct stat s;
int ret;
/* We don't have a rootfs, /dev/console will be shared */ ret = snprintf(path, sizeof(path), "%s/dev/console", rootfs->mount);
if (!rootfs->path) if (ret >= sizeof(path)) {
return 0; ERROR("console path too long\n");
return -1;
snprintf(path, sizeof(path), "%s/dev/console", rootfs->mount); }
if (access(path, F_OK)) { if (access(path, F_OK)) {
WARN("rootfs specified but no console found at '%s'", path); WARN("rootfs specified but no console found at '%s'", path);
...@@ -851,10 +885,85 @@ static int setup_console(const struct lxc_rootfs *rootfs, ...@@ -851,10 +885,85 @@ static int setup_console(const struct lxc_rootfs *rootfs,
} }
INFO("console has been setup"); 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; 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) static int setup_cgroup(const char *name, struct lxc_list *cgroups)
{ {
struct lxc_list *iterator; struct lxc_list *iterator;
...@@ -1908,12 +2017,12 @@ int lxc_setup(const char *name, struct lxc_conf *lxc_conf) ...@@ -1908,12 +2017,12 @@ int lxc_setup(const char *name, struct lxc_conf *lxc_conf)
return -1; 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); ERROR("failed to setup the console for '%s'", name);
return -1; 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); ERROR("failed to setup the ttys for '%s'", name);
return -1; return -1;
} }
......
...@@ -197,6 +197,7 @@ struct lxc_rootfs { ...@@ -197,6 +197,7 @@ struct lxc_rootfs {
* @caps : list of the capabilities * @caps : list of the capabilities
* @tty_info : tty data * @tty_info : tty data
* @console : console data * @console : console data
* @ttydir : directory (under /dev) in which to create console and ttys
*/ */
struct lxc_conf { struct lxc_conf {
char *fstab; char *fstab;
...@@ -213,6 +214,7 @@ struct lxc_conf { ...@@ -213,6 +214,7 @@ struct lxc_conf {
struct lxc_tty_info tty_info; struct lxc_tty_info tty_info;
struct lxc_console console; struct lxc_console console;
struct lxc_rootfs rootfs; struct lxc_rootfs rootfs;
char *ttydir;
}; };
/* /*
......
...@@ -48,6 +48,7 @@ lxc_log_define(lxc_confile, lxc); ...@@ -48,6 +48,7 @@ lxc_log_define(lxc_confile, lxc);
static int config_personality(const char *, char *, struct lxc_conf *); static int config_personality(const char *, char *, struct lxc_conf *);
static int config_pts(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_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_cgroup(const char *, char *, struct lxc_conf *);
static int config_mount(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 *); static int config_rootfs(const char *, char *, struct lxc_conf *);
...@@ -83,6 +84,7 @@ static struct config config[] = { ...@@ -83,6 +84,7 @@ static struct config config[] = {
{ "lxc.arch", config_personality }, { "lxc.arch", config_personality },
{ "lxc.pts", config_pts }, { "lxc.pts", config_pts },
{ "lxc.tty", config_tty }, { "lxc.tty", config_tty },
{ "lxc.devttydir", config_ttydir },
{ "lxc.cgroup", config_cgroup }, { "lxc.cgroup", config_cgroup },
{ "lxc.mount", config_mount }, { "lxc.mount", config_mount },
{ "lxc.rootfs.mount", config_rootfs_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) ...@@ -613,6 +615,24 @@ static int config_tty(const char *key, char *value, struct lxc_conf *lxc_conf)
return 0; 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) static int config_cgroup(const char *key, char *value, struct lxc_conf *lxc_conf)
{ {
char *token = "lxc.cgroup."; char *token = "lxc.cgroup.";
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment