glibc's grantpt and ptsname cannot be used on a fd for a pty not in /dev/pts. The lxc controller tries to do just that. So if you try to start a container on a system where /dev/pts/0 is not available, it will fail. You can make this happen by opening a terminal on /dev/pts/0, and doing 'sleep 2h & disown; exit'. To fix this, I call the virFileOpenTtyAt() from a forked task in a new mount ns, and first mount the container's /dev/pts onto /dev/pts. (Then the opened fd must be passed back to the lxc driver). Another solution would be to just do it all by hand without grantpt and ptsname. Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/libvirt/+bug/863629 Signed-off-by: Serge Hallyn <serge.hallyn@xxxxxxxxxxxxx> --- src/lxc/lxc_controller.c | 117 ++++++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 112 insertions(+), 5 deletions(-) diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index 51488e7..1a56e0c 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -780,6 +780,113 @@ static int lxcSetPersonality(virDomainDefPtr def) # define MS_SLAVE (1<<19) #endif +static int send_pty(int sock, int *pty) +{ + struct iovec vector; + struct msghdr msg; + struct cmsghdr * cmsg; + int ret; + + vector.iov_base = "PTY"; + vector.iov_len = 3; + + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &vector; + msg.msg_iovlen = 1; + + cmsg = alloca(sizeof(struct cmsghdr) + sizeof(*pty)); + cmsg->cmsg_len = sizeof(struct cmsghdr) + sizeof(*pty); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + + memcpy(CMSG_DATA(cmsg), pty, sizeof(*pty)); + + msg.msg_control = cmsg; + msg.msg_controllen = cmsg->cmsg_len; + + ret = sendmsg(sock, &msg, 0); + if (ret < 0) + return -1; + return 0; +} + +static int recv_pty(int sock, int *pty, char **path, char *devpts) +{ + char buf[50]; + struct iovec vector; + struct msghdr msg; + struct cmsghdr * cmsg; + int ret; + + vector.iov_base = buf; + vector.iov_len = 50; + + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &vector; + msg.msg_iovlen = 1; + + cmsg = alloca(sizeof(struct cmsghdr) + sizeof(*pty)); + cmsg->cmsg_len = sizeof(struct cmsghdr) + sizeof(*pty); + msg.msg_control = cmsg; + msg.msg_controllen = cmsg->cmsg_len; + + ret = recvmsg(sock, &msg, 0); + if (ret < 0) + return ret; + + memcpy(pty, CMSG_DATA(cmsg), sizeof(*pty)); + + if (VIR_ALLOC_N(*path, PATH_MAX) < 0) { + virReportSystemError(errno, "%s", + _("Failed to allocate space for ptyname")); + return -ENOMEM; + } + //snprintf(*path, PATH_MAX, "%s/0", devpts); + snprintf(*path, PATH_MAX, "/dev/pts/0"); + return 0; +} + +static int private_open_tty_at(char *devpts, char *devptmx, + int *containerPty, + char **containerPtyPath, int rawmode) +{ + int pid; + int ret; + int status; + int s[2]; + + ret = socketpair(PF_UNIX, SOCK_DGRAM, 0, s); + if (ret < 0) + return ret; + + pid = fork(); + if (pid < 0) + exit(pid); + if (pid == 0) { + close(s[1]); + ret = unshare(CLONE_NEWNS); + if (ret < 0) + exit(ret); + ret = mount(devpts, "/dev/pts", "none", MS_BIND, NULL); + if (ret < 0) + exit(ret); + ret = virFileOpenTtyAt(devptmx, containerPty, containerPtyPath, rawmode); + if (ret < 0) + exit(ret); + send_pty(s[0], containerPty); + exit(ret); + } + close(s[0]); + ret = recv_pty(s[1], containerPty, containerPtyPath, devpts); + close(s[1]); + if (ret) + return ret; + waitpid(pid, &status, 0); + return WEXITSTATUS(status); +} + static int lxcControllerRun(virDomainDefPtr def, unsigned int nveths, @@ -894,12 +1001,12 @@ lxcControllerRun(virDomainDefPtr def, if (devptmx) { VIR_DEBUG("Opening tty on private %s", devptmx); - if (virFileOpenTtyAt(devptmx, - &containerPty, - &containerPtyPath, - 0) < 0) { + if (private_open_tty_at(devpts, devptmx, + &containerPty, + &containerPtyPath, + 0) < 0) { virReportSystemError(errno, "%s", - _("Failed to allocate tty")); + _("Failed to allocate tty")); goto cleanup; } } else { -- 1.7.5.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list