diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index 89ce7f54a4..c4e7832525 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -41,6 +41,8 @@ #include #include #include +#include +#include #if HAVE_CAPNG # include @@ -780,6 +782,50 @@ static int lxcSetPersonality(virDomainDefPtr def) # define MS_SLAVE (1<<19) #endif +/* Create a private tty using the private devpts at PTMX, returning + * the master in *TTYMASTER and the name of the slave, _from the + * perspective of the guest after remounting file systems_, in + * *TTYNAME. Heavily borrowed from glibc, but doesn't require that + * devpts == "/dev/pts" */ +static int +lxcCreateTty(char *ptmx, int *ttymaster, char **ttyName) +{ + int ret = -1; + int ptyno; + int unlock = 0; + + if ((*ttymaster = open(ptmx, O_RDWR|O_NOCTTY|O_NONBLOCK)) < 0) + goto cleanup; + + if (ioctl(*ttymaster, TIOCSPTLCK, &unlock) < 0) + goto cleanup; + + if (ioctl(*ttymaster, TIOCGPTN, &ptyno) < 0) + goto cleanup; + + /* If mount() succeeded at honoring newinstance, then the kernel + * was new enough to also honor the mode=0620,gid=5 options, which + * guarantee that the new pty already has correct permissions; so + * while glibc has to fstat(), fchmod(), and fchown() for older + * kernels, we can skip those steps. ptyno shouldn't currently be + * anything other than 0, but let's play it safe. */ + if (virAsprintf(ttyName, "/dev/pts/%d", ptyno) < 0) { + virReportOOMError(); + errno = ENOMEM; + goto cleanup; + } + + ret = 0; + +cleanup: + if (ret != 0) { + VIR_FORCE_CLOSE(*ttymaster); + VIR_FREE(*ttyName); + } + + return ret; +} + static int lxcControllerRun(virDomainDefPtr def, unsigned int nveths, @@ -877,6 +923,8 @@ lxcControllerRun(virDomainDefPtr def, goto cleanup; } + /* XXX should we support gid=X for X!=5 for distros which use + * a different gid for tty? */ VIR_DEBUG("Mounting 'devpts' on %s", devpts); if (mount("devpts", devpts, "devpts", 0, "newinstance,ptmxmode=0666,mode=0620,gid=5") < 0) { @@ -894,10 +942,7 @@ lxcControllerRun(virDomainDefPtr def, if (devptmx) { VIR_DEBUG("Opening tty on private %s", devptmx); - if (virFileOpenTtyAt(devptmx, - &containerPty, - &containerPtyPath, - 0) < 0) { + if (lxcCreateTty(devptmx, &containerPty, &containerPtyPath) < 0) { virReportSystemError(errno, "%s", _("Failed to allocate tty")); goto cleanup; diff --git a/src/util/util.c b/src/util/util.c index dac616bdb9..01146f5a02 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -1103,22 +1103,17 @@ virFileBuildPath(const char *dir, const char *name, const char *ext) int virFileOpenTty(int *ttymaster, char **ttyName, int rawmode) -{ - return virFileOpenTtyAt("/dev/ptmx", - ttymaster, - ttyName, - rawmode); -} - -#ifdef __linux__ -int virFileOpenTtyAt(const char *ptmx, - int *ttymaster, - char **ttyName, - int rawmode) { int rc = -1; - if ((*ttymaster = open(ptmx, O_RDWR|O_NOCTTY|O_NONBLOCK)) < 0) +#ifdef WIN32 + /* mingw completely lacks pseudo-terminals, and the gnulib + * replacements are not (yet) license compatible. */ + errno = ENOSYS; + +#else /* !WIN32 */ + + if ((*ttymaster = posix_openpt(O_RDWR|O_NOCTTY|O_NONBLOCK)) < 0) goto cleanup; if (unlockpt(*ttymaster) < 0) @@ -1156,19 +1151,9 @@ cleanup: if (rc != 0) VIR_FORCE_CLOSE(*ttymaster); +#endif /* !WIN32 */ return rc; - } -#else -int virFileOpenTtyAt(const char *ptmx ATTRIBUTE_UNUSED, - int *ttymaster ATTRIBUTE_UNUSED, - char **ttyName ATTRIBUTE_UNUSED, - int rawmode ATTRIBUTE_UNUSED) -{ - return -1; -} -#endif - /* * Creates an absolute path for a potentially relative path.