#include "network.h"
#include "error.h"
+#include "af_unix.h"
#include "parse.h"
#include "utils.h"
#include "conf.h"
static int setup_tty(struct lxc_conf *conf)
{
- const struct lxc_rootfs *rootfs = &conf->rootfs;
const struct lxc_tty_info *tty_info = &conf->tty_info;
char *ttydir = conf->ttydir;
char path[MAXPATHLEN], lxcpath[MAXPATHLEN];
int i, ret;
- if (!rootfs->path)
+ if (!conf->rootfs.path)
return 0;
for (i = 0; i < tty_info->nbtty; i++) {
struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
- ret = snprintf(path, sizeof(path), "%s/dev/tty%d",
- rootfs->mount, i + 1);
+ ret = snprintf(path, sizeof(path), "/dev/tty%d", i + 1);
if (ret >= sizeof(path)) {
ERROR("pathname too long for ttys");
return -1;
}
if (ttydir) {
/* create dev/lxc/tty%d" */
- ret = snprintf(lxcpath, sizeof(lxcpath), "%s/dev/%s/tty%d",
- rootfs->mount, ttydir, i + 1);
+ ret = snprintf(lxcpath, sizeof(lxcpath), "/dev/%s/tty%d", ttydir, i + 1);
if (ret >= sizeof(lxcpath)) {
ERROR("pathname too long for ttys");
return -1;
SYSERROR("failed to create symlink for tty %d", i+1);
return -1;
}
- /* Now save the relative path in @path for append_ptyname */
- sprintf(path, "%s/tty%d", ttydir, i + 1);
} else {
/* If we populated /dev, then we need to create /dev/ttyN */
if (access(path, F_OK)) {
}
}
if (mount(pty_info->name, path, "none", MS_BIND, 0)) {
- WARN("failed to mount '%s'->'%s'",
- pty_info->name, path);
+ SYSERROR("failed to mount '%s'->'%s'", pty_info->name, path);
continue;
}
- /* Now save the relative path in @path for append_ptyname */
- sprintf(path, "tty%d", i + 1);
}
- if (!append_ptyname(&conf->pty_names, path)) {
+ if (!append_ptyname(&conf->pty_names, pty_info->name)) {
ERROR("Error setting up container_ttys string");
return -1;
}
int ttys_shift_ids(struct lxc_conf *c)
{
- int i;
-
if (lxc_list_empty(&c->id_map))
return 0;
- for (i = 0; i < c->tty_info.nbtty; i++) {
- struct lxc_pty_info *pty_info = &c->tty_info.pty_info[i];
-
- if (chown_mapped_root(pty_info->name, c) < 0) {
- ERROR("Failed to chown %s", pty_info->name);
- return -1;
- }
- }
-
if (strcmp(c->console.name, "") !=0 && chown_mapped_root(c->console.name, c) < 0) {
ERROR("Failed to chown %s", c->console.name);
return -1;
return true;
}
+static int send_fd(int sock, int fd)
+{
+ int ret = lxc_abstract_unix_send_fd(sock, fd, NULL, 0);
+
+
+ if (ret < 0) {
+ SYSERROR("Error sending tty fd to parent");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int send_ttys_to_parent(struct lxc_handler *handler)
+{
+ struct lxc_conf *conf = handler->conf;
+ const struct lxc_tty_info *tty_info = &conf->tty_info;
+ int i;
+ int sock = handler->ttysock[0];
+
+ for (i = 0; i < tty_info->nbtty; i++) {
+ struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
+ if (send_fd(sock, pty_info->slave) < 0)
+ goto bad;
+ close(pty_info->slave);
+ pty_info->slave = -1;
+ if (send_fd(sock, pty_info->master) < 0)
+ goto bad;
+ close(pty_info->master);
+ pty_info->master = -1;
+ }
+
+ close(handler->ttysock[0]);
+ close(handler->ttysock[1]);
+
+ return 0;
+
+bad:
+ ERROR("Error writing tty fd to parent");
+ return -1;
+}
+
int lxc_setup(struct lxc_handler *handler)
{
const char *name = handler->name;
ERROR("failed to setup kmsg for '%s'", name);
}
- if (!lxc_conf->is_execute && setup_tty(lxc_conf)) {
- ERROR("failed to setup the ttys for '%s'", name);
- return -1;
- }
-
- if (lxc_conf->pty_names && setenv("container_ttys", lxc_conf->pty_names, 1))
- SYSERROR("failed to set environment variable for container ptys");
-
if (!lxc_conf->is_execute && setup_dev_symlinks(&lxc_conf->rootfs)) {
ERROR("failed to setup /dev symlinks for '%s'", name);
return -1;
return -1;
}
+ if (lxc_create_tty(name, lxc_conf)) {
+ ERROR("failed to create the ttys");
+ return -1;
+ }
+
+ if (send_ttys_to_parent(handler) < 0) {
+ ERROR("failure sending console info to parent");
+ return -1;
+ }
+
+
+ if (!lxc_conf->is_execute && setup_tty(lxc_conf)) {
+ ERROR("failed to setup the ttys for '%s'", name);
+ return -1;
+ }
+
+ if (lxc_conf->pty_names && setenv("container_ttys", lxc_conf->pty_names, 1))
+ SYSERROR("failed to set environment variable for container ptys");
+
+
if (setup_personality(lxc_conf->personality)) {
ERROR("failed to setup personality");
return -1;
memset(handler, 0, sizeof(*handler));
+ handler->ttysock[0] = handler->ttysock[1] = -1;
handler->conf = conf;
handler->lxcpath = lxcpath;
handler->pinfd = -1;
goto out_aborting;
}
- if (lxc_create_tty(name, conf)) {
- ERROR("failed to create the ttys");
- goto out_aborting;
- }
-
/* the signal fd has to be created before forking otherwise
* if the child process exits before we setup the signal fd,
* the event will be lost and the command will be stuck */
close(handler->conf->maincmd_fd);
handler->conf->maincmd_fd = -1;
free(handler->name);
+ if (handler->ttysock[0] != -1) {
+ close(handler->ttysock[0]);
+ close(handler->ttysock[1]);
+ }
cgroup_destroy(handler);
free(handler);
}
return 0;
}
+static int recv_fd(int sock, int *fd)
+{
+ if (lxc_abstract_unix_recv_fd(sock, fd, NULL, 0) < 0) {
+ SYSERROR("Error receiving tty fd from child");
+ return -1;
+ }
+ if (*fd == -1)
+ return -1;
+ return 0;
+}
+
+static int recv_ttys_from_child(struct lxc_handler *handler)
+{
+ struct lxc_conf *conf = handler->conf;
+ int i, sock = handler->ttysock[1];
+ struct lxc_tty_info *tty_info = &conf->tty_info;
+
+ if (!conf->tty)
+ return 0;
+
+ tty_info->pty_info = malloc(sizeof(*tty_info->pty_info)*conf->tty);
+ if (!tty_info->pty_info) {
+ SYSERROR("failed to allocate pty_info");
+ return -1;
+ }
+
+ for (i = 0; i < conf->tty; i++) {
+ struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
+ pty_info->busy = 0;
+ if (recv_fd(sock, &pty_info->slave) < 0 ||
+ recv_fd(sock, &pty_info->master) < 0) {
+ ERROR("Error receiving tty info from child");
+ return -1;
+ }
+ }
+ tty_info->nbtty = conf->tty;
+
+ return 0;
+}
+
static int lxc_spawn(struct lxc_handler *handler)
{
int failed_before_rename = 0;
handler->clone_flags |= CLONE_NEWUSER;
}
+ if (socketpair(AF_UNIX, SOCK_DGRAM, 0, handler->ttysock) < 0) {
+ lxc_sync_fini(handler);
+ return -1;
+ }
+
if (handler->conf->inherit_ns_fd[LXC_NS_NET] == -1) {
if (!lxc_requests_empty_network(handler))
handler->clone_flags |= CLONE_NEWNET;
cgroup_disconnect();
cgroups_connected = false;
+ /* read tty fds allocated by child */
+ if (recv_ttys_from_child(handler) < 0) {
+ ERROR("failed to receive tty info from child");
+ goto out_delete_net;
+ }
+
/* Tell the child to complete its initialization and wait for
* it to exec or return an error. (the child will never
* return LXC_SYNC_POST_CGROUP+1. It will either close the