Ejemplo n.º 1
0
static int virLXCControllerConsoleSetNonblocking(virLXCControllerConsolePtr console)
{
    if (virSetBlocking(console->hostFd, false) < 0 ||
            virSetBlocking(console->contFd, false) < 0) {
        virReportSystemError(errno, "%s",
                             _("Unable to set console file descriptor non-blocking"));
        return -1;
    }

    return 0;
}
Ejemplo n.º 2
0
int virSetNonBlock(int fd) {
    return virSetBlocking(fd, false);
}
Ejemplo n.º 3
0
static int
lxcControllerRun(virDomainDefPtr def,
                 unsigned int nveths,
                 char **veths,
                 int monitor,
                 int client,
                 int *ttyFDs,
                 size_t nttyFDs,
                 int handshakefd)
{
    int rc = -1;
    int control[2] = { -1, -1};
    int containerhandshake[2] = { -1, -1 };
    int *containerTtyFDs = NULL;
    char **containerTtyPaths = NULL;
    pid_t container = -1;
    virDomainFSDefPtr root;
    char *devpts = NULL;
    char *devptmx = NULL;
    size_t nloopDevs = 0;
    int *loopDevs = NULL;
    size_t i;

    if (VIR_ALLOC_N(containerTtyFDs, nttyFDs) < 0) {
        virReportOOMError();
        goto cleanup;
    }
    if (VIR_ALLOC_N(containerTtyPaths, nttyFDs) < 0) {
        virReportOOMError();
        goto cleanup;
    }

    if (socketpair(PF_UNIX, SOCK_STREAM, 0, control) < 0) {
        virReportSystemError(errno, "%s",
                             _("sockpair failed"));
        goto cleanup;
    }

    if (socketpair(PF_UNIX, SOCK_STREAM, 0, containerhandshake) < 0) {
        virReportSystemError(errno, "%s",
                             _("socketpair failed"));
        goto cleanup;
    }

    if (lxcSetupLoopDevices(def, &nloopDevs, &loopDevs) < 0)
        goto cleanup;

    root = virDomainGetRootFilesystem(def);

    if (lxcSetContainerResources(def) < 0)
        goto cleanup;

    /*
     * If doing a chroot style setup, we need to prepare
     * a private /dev/pts for the child now, which they
     * 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_DEBUG("Setting up private /dev/pts");

        if (!virFileExists(root->src)) {
            virReportSystemError(errno,
                                 _("root source %s does not exist"),
                                 root->src);
            goto cleanup;
        }

        if (unshare(CLONE_NEWNS) < 0) {
            virReportSystemError(errno, "%s",
                                 _("Cannot unshare mount namespace"));
            goto cleanup;
        }

        if (mount("", "/", NULL, MS_SLAVE|MS_REC, NULL) < 0) {
            virReportSystemError(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();
            goto cleanup;
        }

        if (virFileMakePath(devpts) < 0) {
            virReportSystemError(errno,
                                 _("Failed to make path %s"),
                                 devpts);
            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) {
            virReportSystemError(errno,
                                 _("Failed to mount devpts on %s"),
                                 devpts);
            goto cleanup;
        }

        if (access(devptmx, R_OK) < 0) {
            VIR_WARN("Kernel does not support private devpts, using shared devpts");
            VIR_FREE(devptmx);
        }
    } else {
        if (nttyFDs != -1) {
            lxcError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                     _("Expected exactly one TTY fd"));
            goto cleanup;
        }
    }

    for (i = 0 ; i < nttyFDs ; i++) {
        if (devptmx) {
            VIR_DEBUG("Opening tty on private %s", devptmx);
            if (lxcCreateTty(devptmx,
                             &containerTtyFDs[i],
                             &containerTtyPaths[i]) < 0) {
                virReportSystemError(errno, "%s",
                                     _("Failed to allocate tty"));
                goto cleanup;
            }
        } else {
            VIR_DEBUG("Opening tty on shared /dev/ptmx");
            if (virFileOpenTty(&containerTtyFDs[i],
                               &containerTtyPaths[i],
                               0) < 0) {
                virReportSystemError(errno, "%s",
                                     _("Failed to allocate tty"));
                goto cleanup;
            }
        }
    }

    if (lxcSetPersonality(def) < 0)
        goto cleanup;

    if ((container = lxcContainerStart(def,
                                       nveths,
                                       veths,
                                       control[1],
                                       containerhandshake[1],
                                       containerTtyPaths,
                                       nttyFDs)) < 0)
        goto cleanup;
    VIR_FORCE_CLOSE(control[1]);
    VIR_FORCE_CLOSE(containerhandshake[1]);

    if (lxcControllerMoveInterfaces(nveths, veths, container) < 0)
        goto cleanup;

    if (lxcContainerSendContinue(control[0]) < 0) {
        virReportSystemError(errno, "%s",
                             _("Unable to send container continue message"));
        goto cleanup;
    }

    if (lxcContainerWaitForContinue(containerhandshake[0]) < 0) {
        virReportSystemError(errno, "%s",
                             _("error receiving signal from container"));
        goto cleanup;
    }

    /* Now the container is fully setup... */

    /* ...we can close the loop devices... */

    for (i = 0 ; i < nloopDevs ; i++)
        VIR_FORCE_CLOSE(loopDevs[i]);

    /* ...and reduce our privileges */
    if (lxcControllerClearCapabilities() < 0)
        goto cleanup;

    if (lxcContainerSendContinue(handshakefd) < 0) {
        virReportSystemError(errno, "%s",
                             _("error sending continue signal to parent"));
        goto cleanup;
    }
    VIR_FORCE_CLOSE(handshakefd);

    if (virSetBlocking(monitor, false) < 0 ||
        virSetBlocking(client, false) < 0) {
        virReportSystemError(errno, "%s",
                             _("Unable to set file descriptor non blocking"));
        goto cleanup;
    }
    for (i = 0 ; i < nttyFDs ; i++) {
        if (virSetBlocking(ttyFDs[i], false) < 0 ||
            virSetBlocking(containerTtyFDs[i], false) < 0) {
            virReportSystemError(errno, "%s",
                                 _("Unable to set file descriptor non blocking"));
            goto cleanup;
        }
    }

    rc = lxcControllerMain(monitor, client, ttyFDs, containerTtyFDs, nttyFDs, container);
    monitor = client = -1;

cleanup:
    VIR_FREE(devptmx);
    VIR_FREE(devpts);
    VIR_FORCE_CLOSE(control[0]);
    VIR_FORCE_CLOSE(control[1]);
    VIR_FORCE_CLOSE(handshakefd);
    VIR_FORCE_CLOSE(containerhandshake[0]);
    VIR_FORCE_CLOSE(containerhandshake[1]);

    for (i = 0 ; i < nttyFDs ; i++)
        VIR_FREE(containerTtyPaths[i]);
    VIR_FREE(containerTtyPaths);
    for (i = 0 ; i < nttyFDs ; i++)
        VIR_FORCE_CLOSE(containerTtyFDs[i]);
    VIR_FREE(containerTtyFDs);

    for (i = 0 ; i < nloopDevs ; i++)
        VIR_FORCE_CLOSE(loopDevs[i]);
    VIR_FREE(loopDevs);

    virPidAbort(container);

    return rc;
}