mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-08-26 18:41:17 +00:00
Use a private /dev/pts instance in containers if kernel is new enough
This commit is contained in:
parent
9c19a898f9
commit
220bcb0535
17
ChangeLog
17
ChangeLog
@ -1,3 +1,20 @@
|
|||||||
|
Wed Apr 22 15:27:03 BST 2009 Daniel P. Berrange <berrange@redhat.com>
|
||||||
|
|
||||||
|
Use private /dev/pts instance for containers (needs 'newinstance'
|
||||||
|
mount flag for devpts since 2.6.29 kernels), fallback to shared
|
||||||
|
instance if not supported
|
||||||
|
* src/domain_conf.h, src/domain_conf.c: Add a convenient
|
||||||
|
routine virDomainGetRootFilesystem()
|
||||||
|
* src/libvirt_private.sym: export virDomainGetRootFilesystem
|
||||||
|
to drivers
|
||||||
|
* src/util.c, src/util.h: Add virFileOpenTtyAt() to allow
|
||||||
|
alternate path to /dev/ptmx to be given
|
||||||
|
* src/lxc_controller.c: Attempt to setup a private /dev/pts
|
||||||
|
instance for the container's stdio I/O
|
||||||
|
* src/lxc_container.h, src/lxc_container.c: Pull in the
|
||||||
|
private /dev/pts instance setup by controller, and create
|
||||||
|
a symlink for /dev/ptmx.
|
||||||
|
|
||||||
Tue Apr 21 20:14:03 BST 2009 Daniel P. Berrange <berrange@redhat.com>
|
Tue Apr 21 20:14:03 BST 2009 Daniel P. Berrange <berrange@redhat.com>
|
||||||
|
|
||||||
* src/qemu_driver.c: Remove pidfile when domain shuts down and
|
* src/qemu_driver.c: Remove pidfile when domain shuts down and
|
||||||
|
@ -3066,7 +3066,8 @@ static int
|
|||||||
virDomainChrDefFormat(virConnectPtr conn,
|
virDomainChrDefFormat(virConnectPtr conn,
|
||||||
virBufferPtr buf,
|
virBufferPtr buf,
|
||||||
virDomainChrDefPtr def,
|
virDomainChrDefPtr def,
|
||||||
const char *name)
|
const char *name,
|
||||||
|
int flags)
|
||||||
{
|
{
|
||||||
const char *type = virDomainChrTypeToString(def->type);
|
const char *type = virDomainChrTypeToString(def->type);
|
||||||
|
|
||||||
@ -3081,6 +3082,7 @@ virDomainChrDefFormat(virConnectPtr conn,
|
|||||||
name, type);
|
name, type);
|
||||||
if (STREQ(name, "console") &&
|
if (STREQ(name, "console") &&
|
||||||
def->type == VIR_DOMAIN_CHR_TYPE_PTY &&
|
def->type == VIR_DOMAIN_CHR_TYPE_PTY &&
|
||||||
|
!(flags & VIR_DOMAIN_XML_INACTIVE) &&
|
||||||
def->data.file.path) {
|
def->data.file.path) {
|
||||||
virBufferEscapeString(buf, " tty='%s'>\n",
|
virBufferEscapeString(buf, " tty='%s'>\n",
|
||||||
def->data.file.path);
|
def->data.file.path);
|
||||||
@ -3100,7 +3102,7 @@ virDomainChrDefFormat(virConnectPtr conn,
|
|||||||
case VIR_DOMAIN_CHR_TYPE_FILE:
|
case VIR_DOMAIN_CHR_TYPE_FILE:
|
||||||
case VIR_DOMAIN_CHR_TYPE_PIPE:
|
case VIR_DOMAIN_CHR_TYPE_PIPE:
|
||||||
if (def->type != VIR_DOMAIN_CHR_TYPE_PTY ||
|
if (def->type != VIR_DOMAIN_CHR_TYPE_PTY ||
|
||||||
def->data.file.path) {
|
(def->data.file.path && !(flags & VIR_DOMAIN_XML_INACTIVE))) {
|
||||||
virBufferEscapeString(buf, " <source path='%s'/>\n",
|
virBufferEscapeString(buf, " <source path='%s'/>\n",
|
||||||
def->data.file.path);
|
def->data.file.path);
|
||||||
}
|
}
|
||||||
@ -3481,21 +3483,21 @@ char *virDomainDefFormat(virConnectPtr conn,
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
for (n = 0 ; n < def->nserials ; n++)
|
for (n = 0 ; n < def->nserials ; n++)
|
||||||
if (virDomainChrDefFormat(conn, &buf, def->serials[n], "serial") < 0)
|
if (virDomainChrDefFormat(conn, &buf, def->serials[n], "serial", flags) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
for (n = 0 ; n < def->nparallels ; n++)
|
for (n = 0 ; n < def->nparallels ; n++)
|
||||||
if (virDomainChrDefFormat(conn, &buf, def->parallels[n], "parallel") < 0)
|
if (virDomainChrDefFormat(conn, &buf, def->parallels[n], "parallel", flags) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
/* If there's a PV console that's preferred.. */
|
/* If there's a PV console that's preferred.. */
|
||||||
if (def->console) {
|
if (def->console) {
|
||||||
if (virDomainChrDefFormat(conn, &buf, def->console, "console") < 0)
|
if (virDomainChrDefFormat(conn, &buf, def->console, "console", flags) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
} else if (def->nserials != 0) {
|
} else if (def->nserials != 0) {
|
||||||
/* ..else for legacy compat duplicate the first serial device as a
|
/* ..else for legacy compat duplicate the first serial device as a
|
||||||
* console */
|
* console */
|
||||||
if (virDomainChrDefFormat(conn, &buf, def->serials[0], "console") < 0)
|
if (virDomainChrDefFormat(conn, &buf, def->serials[0], "console", flags) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3856,6 +3858,21 @@ const char *virDomainDefDefaultEmulator(virConnectPtr conn,
|
|||||||
return emulator;
|
return emulator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virDomainFSDefPtr virDomainGetRootFilesystem(virDomainDefPtr def)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0 ; i < def->nfss ; i++) {
|
||||||
|
if (def->fss[i]->type != VIR_DOMAIN_FS_TYPE_MOUNT)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (STREQ(def->fss[i]->dst, "/"))
|
||||||
|
return def->fss[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void virDomainObjLock(virDomainObjPtr obj)
|
void virDomainObjLock(virDomainObjPtr obj)
|
||||||
{
|
{
|
||||||
|
@ -636,6 +636,8 @@ const char *virDomainDefDefaultEmulator(virConnectPtr conn,
|
|||||||
virDomainDefPtr def,
|
virDomainDefPtr def,
|
||||||
virCapsPtr caps);
|
virCapsPtr caps);
|
||||||
|
|
||||||
|
virDomainFSDefPtr virDomainGetRootFilesystem(virDomainDefPtr def);
|
||||||
|
|
||||||
void virDomainObjLock(virDomainObjPtr obj);
|
void virDomainObjLock(virDomainObjPtr obj);
|
||||||
void virDomainObjUnlock(virDomainObjPtr obj);
|
void virDomainObjUnlock(virDomainObjPtr obj);
|
||||||
|
|
||||||
|
@ -79,6 +79,7 @@ virDomainDiskQSort;
|
|||||||
virDomainFindByID;
|
virDomainFindByID;
|
||||||
virDomainFindByName;
|
virDomainFindByName;
|
||||||
virDomainFindByUUID;
|
virDomainFindByUUID;
|
||||||
|
virDomainGetRootFilesystem;
|
||||||
virDomainGraphicsTypeFromString;
|
virDomainGraphicsTypeFromString;
|
||||||
virDomainGraphicsDefFree;
|
virDomainGraphicsDefFree;
|
||||||
virDomainInputDefFree;
|
virDomainInputDefFree;
|
||||||
|
@ -308,7 +308,7 @@ static int lxcContainerPivotRoot(virDomainFSDefPtr root)
|
|||||||
|
|
||||||
/* Create a tmpfs root since old and new roots must be
|
/* Create a tmpfs root since old and new roots must be
|
||||||
* on separate filesystems */
|
* on separate filesystems */
|
||||||
if (mount("", oldroot, "tmpfs", 0, NULL) < 0) {
|
if (mount("tmprootfs", oldroot, "tmpfs", 0, NULL) < 0) {
|
||||||
virReportSystemError(NULL, errno,
|
virReportSystemError(NULL, errno,
|
||||||
_("failed to mount empty tmpfs at %s"),
|
_("failed to mount empty tmpfs at %s"),
|
||||||
oldroot);
|
oldroot);
|
||||||
@ -338,15 +338,9 @@ static int lxcContainerPivotRoot(virDomainFSDefPtr root)
|
|||||||
|
|
||||||
/* Now we chroot into the tmpfs, then pivot into the
|
/* Now we chroot into the tmpfs, then pivot into the
|
||||||
* root->src bind-mounted onto '/new' */
|
* root->src bind-mounted onto '/new' */
|
||||||
if (chroot(oldroot) < 0) {
|
if (chdir(newroot) < 0) {
|
||||||
virReportSystemError(NULL, errno, "%s",
|
virReportSystemError(NULL, errno,
|
||||||
_("failed to chroot into tmpfs"));
|
_("failed to chroot into %s"), newroot);
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (chdir("/new") < 0) {
|
|
||||||
virReportSystemError(NULL, errno, "%s",
|
|
||||||
_("failed to chdir into /new on tmpfs"));
|
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -362,12 +356,6 @@ static int lxcContainerPivotRoot(virDomainFSDefPtr root)
|
|||||||
if (chdir("/") < 0)
|
if (chdir("/") < 0)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
if (umount2(".oldroot", MNT_DETACH) < 0) {
|
|
||||||
virReportSystemError(NULL, errno, "%s",
|
|
||||||
_("failed to lazily unmount old root"));
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
@ -377,10 +365,64 @@ err:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int lxcContainerMountBasicFS(virDomainFSDefPtr root)
|
||||||
|
{
|
||||||
|
const struct {
|
||||||
|
const char *src;
|
||||||
|
const char *dst;
|
||||||
|
const char *type;
|
||||||
|
} mnts[] = {
|
||||||
|
{ "/dev", "/dev", "tmpfs" },
|
||||||
|
{ "/proc", "/proc", "proc" },
|
||||||
|
{ "/sys", "/sys", "sysfs" },
|
||||||
|
#if WITH_SELINUX
|
||||||
|
{ "none", "/selinux", "selinuxfs" },
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
int i, rc;
|
||||||
|
char *devpts;
|
||||||
|
|
||||||
|
if (virAsprintf(&devpts, "/.oldroot%s/dev/pts", root->src) < 0) {
|
||||||
|
virReportOOMError(NULL);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0 ; i < ARRAY_CARDINALITY(mnts) ; i++) {
|
||||||
|
if (virFileMakePath(mnts[i].dst) < 0) {
|
||||||
|
virReportSystemError(NULL, errno,
|
||||||
|
_("failed to mkdir %s"),
|
||||||
|
mnts[i].src);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (mount(mnts[i].src, mnts[i].dst, mnts[i].type, 0, NULL) < 0) {
|
||||||
|
virReportSystemError(NULL, errno,
|
||||||
|
_("failed to mount %s on %s"),
|
||||||
|
mnts[i].type, mnts[i].type);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((rc = virFileMakePath("/dev/pts") < 0)) {
|
||||||
|
virReportSystemError(NULL, rc, "%s",
|
||||||
|
_("cannot create /dev/pts"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
VIR_DEBUG("Trying to move %s to %s", devpts, "/dev/pts");
|
||||||
|
if ((rc = mount(devpts, "/dev/pts", NULL, MS_MOVE, NULL)) < 0) {
|
||||||
|
virReportSystemError(NULL, errno, "%s",
|
||||||
|
_("failed to mount /dev/pts in container"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
VIR_FREE(devpts);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int lxcContainerPopulateDevices(void)
|
static int lxcContainerPopulateDevices(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int rc;
|
|
||||||
const struct {
|
const struct {
|
||||||
int maj;
|
int maj;
|
||||||
int min;
|
int min;
|
||||||
@ -395,33 +437,6 @@ static int lxcContainerPopulateDevices(void)
|
|||||||
{ LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_URANDOM, 0666, "/dev/urandom" },
|
{ LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_URANDOM, 0666, "/dev/urandom" },
|
||||||
};
|
};
|
||||||
|
|
||||||
if ((rc = virFileMakePath("/dev")) < 0) {
|
|
||||||
virReportSystemError(NULL, rc, "%s",
|
|
||||||
_("cannot create /dev/"));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (mount("none", "/dev", "tmpfs", 0, NULL) < 0) {
|
|
||||||
virReportSystemError(NULL, errno, "%s",
|
|
||||||
_("failed to mount /dev tmpfs"));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
/* Move old devpts into container, since we have to
|
|
||||||
connect to the master ptmx which was opened in
|
|
||||||
the parent.
|
|
||||||
XXX This sucks, we need to figure out how to get our
|
|
||||||
own private devpts for isolation
|
|
||||||
*/
|
|
||||||
if ((rc = virFileMakePath("/dev/pts") < 0)) {
|
|
||||||
virReportSystemError(NULL, rc, "%s",
|
|
||||||
_("cannot create /dev/pts"));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (mount("devpts", "/dev/pts", "devpts", 0, NULL) < 0) {
|
|
||||||
virReportSystemError(NULL, errno, "%s",
|
|
||||||
_("failed to mount /dev/pts in container"));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Populate /dev/ with a few important bits */
|
/* Populate /dev/ with a few important bits */
|
||||||
for (i = 0 ; i < ARRAY_CARDINALITY(devs) ; i++) {
|
for (i = 0 ; i < ARRAY_CARDINALITY(devs) ; i++) {
|
||||||
dev_t dev = makedev(devs[i].maj, devs[i].min);
|
dev_t dev = makedev(devs[i].maj, devs[i].min);
|
||||||
@ -434,6 +449,23 @@ static int lxcContainerPopulateDevices(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (access("/dev/pts/ptmx", W_OK) == 0) {
|
||||||
|
if (symlink("/dev/pts/ptmx", "/dev/ptmx") < 0) {
|
||||||
|
virReportSystemError(NULL, errno, "%s",
|
||||||
|
_("failed to create symlink /dev/ptmx to /dev/pts/ptmx"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dev_t dev = makedev(LXC_DEV_MAJ_TTY, LXC_DEV_MIN_PTMX);
|
||||||
|
if (mknod("/dev/ptmx", 0, dev) < 0 ||
|
||||||
|
chmod("/dev/ptmx", 0666)) {
|
||||||
|
virReportSystemError(NULL, errno, "%s",
|
||||||
|
_("failed to make device /dev/ptmx"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -493,6 +525,7 @@ static int lxcContainerUnmountOldFS(void)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
while (getmntent_r(procmnt, &mntent, mntbuf, sizeof(mntbuf)) != NULL) {
|
while (getmntent_r(procmnt, &mntent, mntbuf, sizeof(mntbuf)) != NULL) {
|
||||||
|
VIR_DEBUG("Got %s", mntent.mnt_dir);
|
||||||
if (!STRPREFIX(mntent.mnt_dir, "/.oldroot"))
|
if (!STRPREFIX(mntent.mnt_dir, "/.oldroot"))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -513,6 +546,7 @@ static int lxcContainerUnmountOldFS(void)
|
|||||||
lxcContainerChildMountSort);
|
lxcContainerChildMountSort);
|
||||||
|
|
||||||
for (i = 0 ; i < nmounts ; i++) {
|
for (i = 0 ; i < nmounts ; i++) {
|
||||||
|
VIR_DEBUG("Umount %s", mounts[i]);
|
||||||
if (umount(mounts[i]) < 0) {
|
if (umount(mounts[i]) < 0) {
|
||||||
virReportSystemError(NULL, errno,
|
virReportSystemError(NULL, errno,
|
||||||
_("failed to unmount '%s'"),
|
_("failed to unmount '%s'"),
|
||||||
@ -534,22 +568,23 @@ static int lxcContainerUnmountOldFS(void)
|
|||||||
static int lxcContainerSetupPivotRoot(virDomainDefPtr vmDef,
|
static int lxcContainerSetupPivotRoot(virDomainDefPtr vmDef,
|
||||||
virDomainFSDefPtr root)
|
virDomainFSDefPtr root)
|
||||||
{
|
{
|
||||||
|
/* Gives us a private root, leaving all parent OS mounts on /.oldroot */
|
||||||
if (lxcContainerPivotRoot(root) < 0)
|
if (lxcContainerPivotRoot(root) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (virFileMakePath("/proc") < 0 ||
|
/* Mounts the core /proc, /sys, /dev, /dev/pts filesystems */
|
||||||
mount("none", "/proc", "proc", 0, NULL) < 0) {
|
if (lxcContainerMountBasicFS(root) < 0)
|
||||||
virReportSystemError(NULL, errno, "%s",
|
|
||||||
_("failed to mount /proc"));
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
|
|
||||||
|
/* Populates device nodes in /dev/ */
|
||||||
if (lxcContainerPopulateDevices() < 0)
|
if (lxcContainerPopulateDevices() < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
/* Sets up any non-root mounts from guest config */
|
||||||
if (lxcContainerMountNewFS(vmDef) < 0)
|
if (lxcContainerMountNewFS(vmDef) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
/* Gets rid of all remaining mounts from host OS, including /.oldroot itself */
|
||||||
if (lxcContainerUnmountOldFS() < 0)
|
if (lxcContainerUnmountOldFS() < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@ -595,18 +630,9 @@ static int lxcContainerSetupExtraMounts(virDomainDefPtr vmDef)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lxcContainerSetupMounts(virDomainDefPtr vmDef)
|
static int lxcContainerSetupMounts(virDomainDefPtr vmDef,
|
||||||
|
virDomainFSDefPtr root)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
virDomainFSDefPtr root = NULL;
|
|
||||||
|
|
||||||
for (i = 0 ; i < vmDef->nfss ; i++) {
|
|
||||||
if (vmDef->fss[i]->type != VIR_DOMAIN_FS_TYPE_MOUNT)
|
|
||||||
continue;
|
|
||||||
if (STREQ(vmDef->fss[i]->dst, "/"))
|
|
||||||
root = vmDef->fss[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (root)
|
if (root)
|
||||||
return lxcContainerSetupPivotRoot(vmDef, root);
|
return lxcContainerSetupPivotRoot(vmDef, root);
|
||||||
else
|
else
|
||||||
@ -630,6 +656,8 @@ static int lxcContainerChild( void *data )
|
|||||||
lxc_child_argv_t *argv = data;
|
lxc_child_argv_t *argv = data;
|
||||||
virDomainDefPtr vmDef = argv->config;
|
virDomainDefPtr vmDef = argv->config;
|
||||||
int ttyfd;
|
int ttyfd;
|
||||||
|
char *ttyPath;
|
||||||
|
virDomainFSDefPtr root;
|
||||||
|
|
||||||
if (NULL == vmDef) {
|
if (NULL == vmDef) {
|
||||||
lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
||||||
@ -637,16 +665,28 @@ static int lxcContainerChild( void *data )
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lxcContainerSetupMounts(vmDef) < 0)
|
root = virDomainGetRootFilesystem(vmDef);
|
||||||
return -1;
|
|
||||||
|
|
||||||
ttyfd = open(argv->ttyPath, O_RDWR|O_NOCTTY);
|
if (root) {
|
||||||
|
if (virAsprintf(&ttyPath, "%s%s", root->src, argv->ttyPath) < 0) {
|
||||||
|
virReportOOMError(NULL);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!(ttyPath = strdup(argv->ttyPath))) {
|
||||||
|
virReportOOMError(NULL);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ttyfd = open(ttyPath, O_RDWR|O_NOCTTY);
|
||||||
if (ttyfd < 0) {
|
if (ttyfd < 0) {
|
||||||
virReportSystemError(NULL, errno,
|
virReportSystemError(NULL, errno,
|
||||||
_("failed to open %s"),
|
_("failed to open tty %s"),
|
||||||
argv->ttyPath);
|
ttyPath);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
VIR_FREE(ttyPath);
|
||||||
|
|
||||||
if (lxcContainerSetStdio(argv->monitor, ttyfd) < 0) {
|
if (lxcContainerSetStdio(argv->monitor, ttyfd) < 0) {
|
||||||
close(ttyfd);
|
close(ttyfd);
|
||||||
@ -654,6 +694,9 @@ static int lxcContainerChild( void *data )
|
|||||||
}
|
}
|
||||||
close(ttyfd);
|
close(ttyfd);
|
||||||
|
|
||||||
|
if (lxcContainerSetupMounts(vmDef, root) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
/* Wait for interface devices to show up */
|
/* Wait for interface devices to show up */
|
||||||
if (lxcContainerWaitForContinue(argv->monitor) < 0)
|
if (lxcContainerWaitForContinue(argv->monitor) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -40,6 +40,7 @@ enum {
|
|||||||
|
|
||||||
#define LXC_DEV_MAJ_TTY 5
|
#define LXC_DEV_MAJ_TTY 5
|
||||||
#define LXC_DEV_MIN_CONSOLE 1
|
#define LXC_DEV_MIN_CONSOLE 1
|
||||||
|
#define LXC_DEV_MIN_PTMX 2
|
||||||
|
|
||||||
#define LXC_DEV_MAJ_PTY 136
|
#define LXC_DEV_MAJ_PTY 136
|
||||||
|
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
#include <sys/mount.h>
|
||||||
|
|
||||||
#include "virterror_internal.h"
|
#include "virterror_internal.h"
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
@ -426,6 +427,13 @@ static int lxcControllerCleanupInterfaces(unsigned int nveths,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef MS_REC
|
||||||
|
#define MS_REC 16384
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MS_SLAVE
|
||||||
|
#define MS_SLAVE (1<<19)
|
||||||
|
#endif
|
||||||
|
|
||||||
static int
|
static int
|
||||||
lxcControllerRun(virDomainDefPtr def,
|
lxcControllerRun(virDomainDefPtr def,
|
||||||
@ -440,6 +448,9 @@ lxcControllerRun(virDomainDefPtr def,
|
|||||||
int containerPty;
|
int containerPty;
|
||||||
char *containerPtyPath;
|
char *containerPtyPath;
|
||||||
pid_t container = -1;
|
pid_t container = -1;
|
||||||
|
virDomainFSDefPtr root;
|
||||||
|
char *devpts = NULL;
|
||||||
|
char *devptmx = NULL;
|
||||||
|
|
||||||
if (socketpair(PF_UNIX, SOCK_STREAM, 0, control) < 0) {
|
if (socketpair(PF_UNIX, SOCK_STREAM, 0, control) < 0) {
|
||||||
virReportSystemError(NULL, errno, "%s",
|
virReportSystemError(NULL, errno, "%s",
|
||||||
@ -447,14 +458,91 @@ lxcControllerRun(virDomainDefPtr def,
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (virFileOpenTty(&containerPty,
|
root = virDomainGetRootFilesystem(def);
|
||||||
&containerPtyPath,
|
|
||||||
0) < 0) {
|
/*
|
||||||
virReportSystemError(NULL, errno, "%s",
|
* If doing a chroot style setup, we need to prepare
|
||||||
_("failed to allocate tty"));
|
* a private /dev/pts for the child now, which they
|
||||||
goto cleanup;
|
* will later move into position.
|
||||||
|
*
|
||||||
|
* This is complex because 'virsh console' needs to
|
||||||
|
* use /dev/pts from the host OS, and the guest OS
|
||||||
|
* needs to use /dev/pts from the guest.
|
||||||
|
*
|
||||||
|
* This means that we (libvirt_lxc) need to see and
|
||||||
|
* use both /dev/pts instances. We're running in the
|
||||||
|
* host OS context though and don't want to expose
|
||||||
|
* the guest OS /dev/pts there.
|
||||||
|
*
|
||||||
|
* Thus we call unshare(CLONE_NS) so that we can see
|
||||||
|
* the guest's new /dev/pts, without it becoming
|
||||||
|
* visible to the host OS. We also put the root FS
|
||||||
|
* into slave mode, just in case it was currently
|
||||||
|
* marked as shared
|
||||||
|
*/
|
||||||
|
if (root) {
|
||||||
|
VIR_DEBUG0("Setting up private /dev/pts");
|
||||||
|
if (unshare(CLONE_NEWNS) < 0) {
|
||||||
|
virReportSystemError(NULL, errno, "%s",
|
||||||
|
_("cannot unshare mount namespace"));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mount("", "/", NULL, MS_SLAVE|MS_REC, NULL) < 0) {
|
||||||
|
virReportSystemError(NULL, errno, "%s",
|
||||||
|
_("failed to switch root mount into slave mode"));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (virAsprintf(&devpts, "%s/dev/pts", root->src) < 0 ||
|
||||||
|
virAsprintf(&devptmx, "%s/dev/pts/ptmx", root->src) < 0) {
|
||||||
|
virReportOOMError(NULL);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (virFileMakePath(devpts) < 0) {
|
||||||
|
virReportSystemError(NULL, errno,
|
||||||
|
_("failed to make path %s"),
|
||||||
|
devpts);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
VIR_DEBUG("Mouting 'devpts' on %s", devpts);
|
||||||
|
if (mount("devpts", devpts, "devpts", 0, "newinstance,ptmxmode=0666") < 0) {
|
||||||
|
virReportSystemError(NULL, errno,
|
||||||
|
_("failed to mount devpts on %s"),
|
||||||
|
devpts);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (access(devptmx, R_OK) < 0) {
|
||||||
|
VIR_WARN0("kernel does not support private devpts, using shared devpts");
|
||||||
|
VIR_FREE(devptmx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (devptmx) {
|
||||||
|
VIR_DEBUG("Opening tty on private %s", devptmx);
|
||||||
|
if (virFileOpenTtyAt(devptmx,
|
||||||
|
&containerPty,
|
||||||
|
&containerPtyPath,
|
||||||
|
0) < 0) {
|
||||||
|
virReportSystemError(NULL, errno, "%s",
|
||||||
|
_("failed to allocate tty"));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
VIR_DEBUG0("Opening tty on shared /dev/ptmx");
|
||||||
|
if (virFileOpenTty(&containerPty,
|
||||||
|
&containerPtyPath,
|
||||||
|
0) < 0) {
|
||||||
|
virReportSystemError(NULL, errno, "%s",
|
||||||
|
_("failed to allocate tty"));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (lxcSetContainerResources(def) < 0)
|
if (lxcSetContainerResources(def) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
@ -476,6 +564,8 @@ lxcControllerRun(virDomainDefPtr def,
|
|||||||
rc = lxcControllerMain(monitor, client, appPty, containerPty);
|
rc = lxcControllerMain(monitor, client, appPty, containerPty);
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
|
VIR_FREE(devptmx);
|
||||||
|
VIR_FREE(devpts);
|
||||||
if (control[0] != -1)
|
if (control[0] != -1)
|
||||||
close(control[0]);
|
close(control[0]);
|
||||||
if (control[1] != -1)
|
if (control[1] != -1)
|
||||||
|
22
src/util.c
22
src/util.c
@ -1050,14 +1050,25 @@ int virFileBuildPath(const char *dir,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef __linux__
|
|
||||||
int virFileOpenTty(int *ttymaster,
|
int virFileOpenTty(int *ttymaster,
|
||||||
char **ttyName,
|
char **ttyName,
|
||||||
int rawmode)
|
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;
|
int rc = -1;
|
||||||
|
|
||||||
if ((*ttymaster = posix_openpt(O_RDWR|O_NOCTTY|O_NONBLOCK)) < 0)
|
if ((*ttymaster = open(ptmx, O_RDWR|O_NOCTTY|O_NONBLOCK)) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
if (unlockpt(*ttymaster) < 0)
|
if (unlockpt(*ttymaster) < 0)
|
||||||
@ -1100,9 +1111,10 @@ cleanup:
|
|||||||
|
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
int virFileOpenTty(int *ttymaster ATTRIBUTE_UNUSED,
|
int virFileOpenTtyAt(const char *ptmx ATTRIBUTE_UNUSED,
|
||||||
char **ttyName ATTRIBUTE_UNUSED,
|
int *ttymaster ATTRIBUTE_UNUSED,
|
||||||
int rawmode ATTRIBUTE_UNUSED)
|
char **ttyName ATTRIBUTE_UNUSED,
|
||||||
|
int rawmode ATTRIBUTE_UNUSED)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -103,6 +103,10 @@ int virFileBuildPath(const char *dir,
|
|||||||
int virFileOpenTty(int *ttymaster,
|
int virFileOpenTty(int *ttymaster,
|
||||||
char **ttyName,
|
char **ttyName,
|
||||||
int rawmode);
|
int rawmode);
|
||||||
|
int virFileOpenTtyAt(const char *ptmx,
|
||||||
|
int *ttymaster,
|
||||||
|
char **ttyName,
|
||||||
|
int rawmode);
|
||||||
|
|
||||||
char* virFilePid(const char *dir,
|
char* virFilePid(const char *dir,
|
||||||
const char *name);
|
const char *name);
|
||||||
|
Loading…
Reference in New Issue
Block a user