Exemple #1
0
/**
 * qemuAgentSend:
 * @mon: Monitor
 * @msg: Message
 * @seconds: number of seconds to wait for the result, it can be either
 *           -2, -1, 0 or positive.
 *
 * Send @msg to agent @mon. If @seconds is equal to
 * VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK(-2), this function will block forever
 * waiting for the result. The value of
 * VIR_DOMAIN_QEMU_AGENT_COMMAND_DEFAULT(-1) means use default timeout value
 * and VIR_DOMAIN_QEMU_AGENT_COMMAND_NOWAIT(0) makes this this function return
 * immediately without waiting. Any positive value means the number of seconds
 * to wait for the result.
 *
 * Returns: 0 on success,
 *          -2 on timeout,
 *          -1 otherwise
 */
static int qemuAgentSend(qemuAgentPtr mon,
                         qemuAgentMessagePtr msg,
                         int seconds)
{
    int ret = -1;
    unsigned long long then = 0;

    /* Check whether qemu quit unexpectedly */
    if (mon->lastError.code != VIR_ERR_OK) {
        VIR_DEBUG("Attempt to send command while error is set %s",
                  NULLSTR(mon->lastError.message));
        virSetError(&mon->lastError);
        return -1;
    }

    if (seconds > VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) {
        unsigned long long now;
        if (virTimeMillisNow(&now) < 0)
            return -1;
        if (seconds == VIR_DOMAIN_QEMU_AGENT_COMMAND_DEFAULT)
            seconds = QEMU_AGENT_WAIT_TIME;
        then = now + seconds * 1000ull;
    }

    mon->msg = msg;
    qemuAgentUpdateWatch(mon);

    while (!mon->msg->finished) {
        if ((then && virCondWaitUntil(&mon->notify, &mon->parent.lock, then) < 0) ||
            (!then && virCondWait(&mon->notify, &mon->parent.lock) < 0)) {
            if (errno == ETIMEDOUT) {
                virReportError(VIR_ERR_AGENT_UNRESPONSIVE, "%s",
                               _("Guest agent not available for now"));
                ret = -2;
            } else {
                virReportSystemError(errno, "%s",
                                     _("Unable to wait on agent monitor "
                                       "condition"));
            }
            goto cleanup;
        }
    }

    if (mon->lastError.code != VIR_ERR_OK) {
        VIR_DEBUG("Send command resulted in error %s",
                  NULLSTR(mon->lastError.message));
        virSetError(&mon->lastError);
        goto cleanup;
    }

    ret = 0;

 cleanup:
    mon->msg = NULL;
    qemuAgentUpdateWatch(mon);

    return ret;
}
/**
 * qemuAgentSend:
 * @mon: Monitor
 * @msg: Message
 * @timeout: use timeout?
 *
 * Send @msg to agent @mon.
 * Wait max QEMU_AGENT_WAIT_TIME for agent
 * to reply.
 *
 * Returns: 0 on success,
 *          -2 on timeout,
 *          -1 otherwise
 */
static int qemuAgentSend(qemuAgentPtr mon,
                         qemuAgentMessagePtr msg,
                         bool timeout)
{
    int ret = -1;
    unsigned long long now, then = 0;

    /* Check whether qemu quit unexpectedly */
    if (mon->lastError.code != VIR_ERR_OK) {
        VIR_DEBUG("Attempt to send command while error is set %s",
                  NULLSTR(mon->lastError.message));
        virSetError(&mon->lastError);
        return -1;
    }

    if (timeout) {
        if (virTimeMillisNow(&now) < 0)
            return -1;
        then = now + QEMU_AGENT_WAIT_TIME;
    }

    mon->msg = msg;
    qemuAgentUpdateWatch(mon);

    while (!mon->msg->finished) {
        if ((timeout && virCondWaitUntil(&mon->notify, &mon->lock, then) < 0) ||
            (!timeout && virCondWait(&mon->notify, &mon->lock) < 0)) {
            if (errno == ETIMEDOUT) {
                qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                _("Guest agent not available for now"));
                ret = -2;
            } else {
                qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                _("Unable to wait on monitor condition"));
            }
            goto cleanup;
        }
    }

    if (mon->lastError.code != VIR_ERR_OK) {
        VIR_DEBUG("Send command resulted in error %s",
                  NULLSTR(mon->lastError.message));
        virSetError(&mon->lastError);
        goto cleanup;
    }

    ret = 0;

cleanup:
    mon->msg = NULL;
    qemuAgentUpdateWatch(mon);

    return ret;
}
Exemple #3
0
/**
 * virErrorRestore:
 * @savederr: error object holding saved error
 *
 * Restores the error passed via @savederr and clears associated memory.
 */
void
virErrorRestore(virErrorPtr *savederr)
{
    int saved_errno = errno;

    if (!*savederr)
        return;

    virSetError(*savederr);
    virFreeError(*savederr);
    *savederr = NULL;
    errno = saved_errno;
}
Exemple #4
0
/**
 * qemuCgroupEmulatorAllNodesRestore:
 * @data: data structure created by qemuCgroupEmulatorAllNodesAllow
 *
 * Rolls back the setting done by qemuCgroupEmulatorAllNodesAllow and frees the
 * associated data.
 */
void
qemuCgroupEmulatorAllNodesRestore(qemuCgroupEmulatorAllNodesDataPtr data)
{
    virErrorPtr err;

    if (!data)
        return;

    err = virSaveLastError();
    virCgroupSetCpusetMems(data->emulatorCgroup, data->emulatorMemMask);
    virSetError(err);
    virFreeError(err);

    qemuCgroupEmulatorAllNodesDataFree(data);
}
Exemple #5
0
/*
 * vshAdmCatchDisconnect:
 *
 * We get here when the connection was closed. Unlike virsh, we do not save
 * the fact that the event was raised, sice there is virAdmConnectIsAlive to
 * check if the communication channel has not been closed by remote party.
 */
static void
vshAdmCatchDisconnect(virAdmConnectPtr conn ATTRIBUTE_UNUSED,
                      int reason,
                      void *opaque)
{
    vshControl *ctl = opaque;
    const char *str = "unknown reason";
    virErrorPtr error;
    char *uri = NULL;

    if (reason == VIR_CONNECT_CLOSE_REASON_CLIENT)
        return;

    error = virSaveLastError();
    uri = virAdmConnectGetURI(conn);

    switch ((virConnectCloseReason) reason) {
    case VIR_CONNECT_CLOSE_REASON_ERROR:
        str = N_("Disconnected from %s due to I/O error");
        break;
    case VIR_CONNECT_CLOSE_REASON_EOF:
        str = N_("Disconnected from %s due to end of file");
        break;
    case VIR_CONNECT_CLOSE_REASON_KEEPALIVE:
        str = N_("Disconnected from %s due to keepalive timeout");
        break;
        /* coverity[dead_error_condition] */
    case VIR_CONNECT_CLOSE_REASON_CLIENT:
    case VIR_CONNECT_CLOSE_REASON_LAST:
        break;
    }

    vshError(ctl, _(str), NULLSTR(uri));
    VIR_FREE(uri);

    if (error) {
        virSetError(error);
        virFreeError(error);
    }
}
Exemple #6
0
int
qemuSetupCgroupVcpuBW(virCgroupPtr cgroup,
                      unsigned long long period,
                      long long quota)
{
    unsigned long long old_period;

    if (period == 0 && quota == 0)
        return 0;

    if (period) {
        /* get old period, and we can rollback if set quota failed */
        if (virCgroupGetCpuCfsPeriod(cgroup, &old_period) < 0)
            return -1;

        if (virCgroupSetCpuCfsPeriod(cgroup, period) < 0)
            return -1;
    }

    if (quota &&
        virCgroupSetCpuCfsQuota(cgroup, quota) < 0)
        goto error;

    return 0;

 error:
    if (period) {
        virErrorPtr saved = virSaveLastError();
        ignore_value(virCgroupSetCpuCfsPeriod(cgroup, old_period));
        if (saved) {
            virSetError(saved);
            virFreeError(saved);
        }
    }

    return -1;
}
Exemple #7
0
int
libxlMakeNic(virDomainDefPtr def,
             virDomainNetDefPtr l_nic,
             libxl_device_nic *x_nic)
{
    bool ioemu_nic = STREQ(def->os.type, "hvm");
    virDomainNetType actual_type = virDomainNetGetActualType(l_nic);

    /* TODO: Where is mtu stored?
     *
     * x_nics[i].mtu = 1492;
     */

    if (l_nic->script && !(actual_type == VIR_DOMAIN_NET_TYPE_BRIDGE ||
                           actual_type == VIR_DOMAIN_NET_TYPE_ETHERNET)) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("specifying a script is only supported with "
                         "interface types bridge and ethernet"));
        return -1;
    }

    libxl_device_nic_init(x_nic);

    virMacAddrGetRaw(&l_nic->mac, x_nic->mac);

    if (ioemu_nic)
        x_nic->nictype = LIBXL_NIC_TYPE_VIF_IOEMU;
    else
        x_nic->nictype = LIBXL_NIC_TYPE_VIF;

    if (l_nic->model) {
        if (VIR_STRDUP(x_nic->model, l_nic->model) < 0)
            return -1;
        if (STREQ(l_nic->model, "netfront"))
            x_nic->nictype = LIBXL_NIC_TYPE_VIF;
    }

    if (VIR_STRDUP(x_nic->ifname, l_nic->ifname) < 0)
        return -1;

    switch (actual_type) {
        case VIR_DOMAIN_NET_TYPE_BRIDGE:
            if (VIR_STRDUP(x_nic->bridge,
                           virDomainNetGetActualBridgeName(l_nic)) < 0)
                return -1;
            /* fallthrough */
        case VIR_DOMAIN_NET_TYPE_ETHERNET:
            if (VIR_STRDUP(x_nic->script, l_nic->script) < 0)
                return -1;
            break;
        case VIR_DOMAIN_NET_TYPE_NETWORK:
        {
            bool fail = false;
            char *brname = NULL;
            virNetworkPtr network;
            virConnectPtr conn;
            virErrorPtr errobj;

            if (!(conn = virConnectOpen("xen:///system")))
                return -1;

            if (!(network =
                  virNetworkLookupByName(conn, l_nic->data.network.name))) {
                virObjectUnref(conn);
                return -1;
            }

            if ((brname = virNetworkGetBridgeName(network))) {
                if (VIR_STRDUP(x_nic->bridge, brname) < 0)
                    fail = true;
            } else {
                fail = true;
            }

            VIR_FREE(brname);

            /* Preserve any previous failure */
            errobj = virSaveLastError();
            virNetworkFree(network);
            virSetError(errobj);
            virFreeError(errobj);
            virObjectUnref(conn);
            if (fail)
                return -1;
            break;
        }
        case VIR_DOMAIN_NET_TYPE_USER:
        case VIR_DOMAIN_NET_TYPE_SERVER:
        case VIR_DOMAIN_NET_TYPE_CLIENT:
        case VIR_DOMAIN_NET_TYPE_MCAST:
        case VIR_DOMAIN_NET_TYPE_INTERNAL:
        case VIR_DOMAIN_NET_TYPE_DIRECT:
        case VIR_DOMAIN_NET_TYPE_HOSTDEV:
        case VIR_DOMAIN_NET_TYPE_LAST:
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                    _("unsupported interface type %s"),
                    virDomainNetTypeToString(l_nic->type));
            return -1;
    }

    return 0;
}
Exemple #8
0
/**
 * virLXCProcessSetupInterfaces:
 * @conn: pointer to connection
 * @def: pointer to virtual machine structure
 * @nveths: number of interfaces
 * @veths: interface names
 *
 * Sets up the container interfaces by creating the veth device pairs and
 * attaching the parent end to the appropriate bridge.  The container end
 * will moved into the container namespace later after clone has been called.
 *
 * Returns 0 on success or -1 in case of error
 */
static int virLXCProcessSetupInterfaces(virConnectPtr conn,
                                        virDomainDefPtr def,
                                        size_t *nveths,
                                        char ***veths)
{
    int ret = -1;
    size_t i;

    for (i = 0; i < def->nnets; i++) {
        char *veth = NULL;
        /* If appropriate, grab a physical device from the configured
         * network's pool of devices, or resolve bridge device name
         * to the one defined in the network definition.
         */
        if (networkAllocateActualDevice(def, def->nets[i]) < 0)
            goto cleanup;

        if (VIR_EXPAND_N(*veths, *nveths, 1) < 0)
            goto cleanup;

        switch (virDomainNetGetActualType(def->nets[i])) {
        case VIR_DOMAIN_NET_TYPE_NETWORK: {
            virNetworkPtr network;
            char *brname = NULL;
            bool fail = false;
            int active;
            virErrorPtr errobj;

            if (!(network = virNetworkLookupByName(conn,
                                                   def->nets[i]->data.network.name)))
                goto cleanup;

            active = virNetworkIsActive(network);
            if (active != 1) {
                fail = true;
                if (active == 0)
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Network '%s' is not active."),
                                   def->nets[i]->data.network.name);
            }

            if (!fail) {
                brname = virNetworkGetBridgeName(network);
                if (brname == NULL)
                    fail = true;
            }

            /* Make sure any above failure is preserved */
            errobj = virSaveLastError();
            virNetworkFree(network);
            virSetError(errobj);
            virFreeError(errobj);

            if (fail)
                goto cleanup;

            if (!(veth = virLXCProcessSetupInterfaceBridged(conn,
                                                            def,
                                                            def->nets[i],
                                                            brname))) {
                VIR_FREE(brname);
                goto cleanup;
            }
            VIR_FREE(brname);
            break;
        }
        case VIR_DOMAIN_NET_TYPE_BRIDGE: {
            const char *brname = virDomainNetGetActualBridgeName(def->nets[i]);
            if (!brname) {
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("No bridge name specified"));
                goto cleanup;
            }
            if (!(veth = virLXCProcessSetupInterfaceBridged(conn,
                                                            def,
                                                            def->nets[i],
                                                            brname)))
                goto cleanup;
        }   break;

        case VIR_DOMAIN_NET_TYPE_DIRECT:
            if (!(veth = virLXCProcessSetupInterfaceDirect(conn,
                                                           def,
                                                           def->nets[i])))
                goto cleanup;
            break;

        case VIR_DOMAIN_NET_TYPE_USER:
        case VIR_DOMAIN_NET_TYPE_ETHERNET:
        case VIR_DOMAIN_NET_TYPE_SERVER:
        case VIR_DOMAIN_NET_TYPE_CLIENT:
        case VIR_DOMAIN_NET_TYPE_MCAST:
        case VIR_DOMAIN_NET_TYPE_INTERNAL:
        case VIR_DOMAIN_NET_TYPE_LAST:
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unsupported network type %s"),
                           virDomainNetTypeToString(
                               virDomainNetGetActualType(def->nets[i])
                               ));
            goto cleanup;
        }

        (*veths)[(*nveths)-1] = veth;
    }

    ret = 0;

 cleanup:
    if (ret < 0) {
        for (i = 0; i < def->nnets; i++) {
            virDomainNetDefPtr iface = def->nets[i];
            virNetDevVPortProfilePtr vport = virDomainNetGetActualVirtPortProfile(iface);
            if (vport && vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH)
                ignore_value(virNetDevOpenvswitchRemovePort(
                                virDomainNetGetActualBridgeName(iface),
                                iface->ifname));
            networkReleaseActualDevice(def, iface);
        }
    }
    return ret;
}
Exemple #9
0
/**
 * virLXCProcessStart:
 * @conn: pointer to connection
 * @driver: pointer to driver structure
 * @vm: pointer to virtual machine structure
 * @autoDestroy: mark the domain for auto destruction
 * @reason: reason for switching vm to running state
 *
 * Starts a vm
 *
 * Returns 0 on success or -1 in case of error
 */
int virLXCProcessStart(virConnectPtr conn,
                       virLXCDriverPtr  driver,
                       virDomainObjPtr vm,
                       unsigned int nfiles, int *files,
                       bool autoDestroy,
                       virDomainRunningReason reason)
{
    int rc = -1, r;
    size_t nttyFDs = 0;
    int *ttyFDs = NULL;
    size_t i;
    char *logfile = NULL;
    int logfd = -1;
    size_t nveths = 0;
    char **veths = NULL;
    int handshakefds[2] = { -1, -1 };
    off_t pos = -1;
    char ebuf[1024];
    char *timestamp;
    virCommandPtr cmd = NULL;
    virLXCDomainObjPrivatePtr priv = vm->privateData;
    virCapsPtr caps = NULL;
    virErrorPtr err = NULL;
    virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
    virCgroupPtr selfcgroup;
    int status;

    if (virCgroupNewSelf(&selfcgroup) < 0)
        return -1;

    if (!virCgroupHasController(selfcgroup,
                                VIR_CGROUP_CONTROLLER_CPUACCT)) {
        virCgroupFree(&selfcgroup);
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Unable to find 'cpuacct' cgroups controller mount"));
        return -1;
    }
    if (!virCgroupHasController(selfcgroup,
                                VIR_CGROUP_CONTROLLER_DEVICES)) {
        virCgroupFree(&selfcgroup);
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Unable to find 'devices' cgroups controller mount"));
        return -1;
    }
    if (!virCgroupHasController(selfcgroup,
                                VIR_CGROUP_CONTROLLER_MEMORY)) {
        virCgroupFree(&selfcgroup);
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Unable to find 'memory' cgroups controller mount"));
        return -1;
    }
    virCgroupFree(&selfcgroup);

    if (virFileMakePath(cfg->logDir) < 0) {
        virReportSystemError(errno,
                             _("Cannot create log directory '%s'"),
                             cfg->logDir);
        return -1;
    }

    if (!vm->def->resource) {
        virDomainResourceDefPtr res;

        if (VIR_ALLOC(res) < 0)
            goto cleanup;

        if (VIR_STRDUP(res->partition, "/machine") < 0) {
            VIR_FREE(res);
            goto cleanup;
        }

        vm->def->resource = res;
    }

    if (virAsprintf(&logfile, "%s/%s.log",
                    cfg->logDir, vm->def->name) < 0)
        return -1;

    if (!(caps = virLXCDriverGetCapabilities(driver, false)))
        goto cleanup;

    /* Do this up front, so any part of the startup process can add
     * runtime state to vm->def that won't be persisted. This let's us
     * report implicit runtime defaults in the XML, like vnc listen/socket
     */
    VIR_DEBUG("Setting current domain def as transient");
    if (virDomainObjSetDefTransient(caps, driver->xmlopt, vm, true) < 0)
        goto cleanup;

    /* Run an early hook to set-up missing devices */
    if (virHookPresent(VIR_HOOK_DRIVER_LXC)) {
        char *xml = virDomainDefFormat(vm->def, 0);
        int hookret;

        hookret = virHookCall(VIR_HOOK_DRIVER_LXC, vm->def->name,
                              VIR_HOOK_LXC_OP_PREPARE, VIR_HOOK_SUBOP_BEGIN,
                              NULL, xml, NULL);
        VIR_FREE(xml);

        /*
         * If the script raised an error abort the launch
         */
        if (hookret < 0)
            goto cleanup;
    }

    if (virLXCProcessEnsureRootFS(vm) < 0)
        goto cleanup;

    /* Must be run before security labelling */
    VIR_DEBUG("Preparing host devices");
    if (virLXCPrepareHostDevices(driver, vm->def) < 0)
        goto cleanup;

    /* Here we open all the PTYs we need on the host OS side.
     * The LXC controller will open the guest OS side PTYs
     * and forward I/O between them.
     */
    nttyFDs = vm->def->nconsoles;
    if (VIR_ALLOC_N(ttyFDs, nttyFDs) < 0)
        goto cleanup;
    for (i = 0; i < vm->def->nconsoles; i++)
        ttyFDs[i] = -1;

    /* If you are using a SecurityDriver with dynamic labelling,
       then generate a security label for isolation */
    VIR_DEBUG("Generating domain security label (if required)");
    if (vm->def->nseclabels &&
        vm->def->seclabels[0]->type == VIR_DOMAIN_SECLABEL_DEFAULT)
        vm->def->seclabels[0]->type = VIR_DOMAIN_SECLABEL_NONE;

    if (virSecurityManagerGenLabel(driver->securityManager, vm->def) < 0) {
        virDomainAuditSecurityLabel(vm, false);
        goto cleanup;
    }
    virDomainAuditSecurityLabel(vm, true);

    VIR_DEBUG("Setting domain security labels");
    if (virSecurityManagerSetAllLabel(driver->securityManager,
                                      vm->def, NULL) < 0)
        goto cleanup;

    for (i = 0; i < vm->def->nconsoles; i++) {
        char *ttyPath;
        if (vm->def->consoles[i]->source.type != VIR_DOMAIN_CHR_TYPE_PTY) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("Only PTY console types are supported"));
            goto cleanup;
        }

        if (virFileOpenTty(&ttyFDs[i], &ttyPath, 1) < 0) {
            virReportSystemError(errno, "%s",
                                 _("Failed to allocate tty"));
            goto cleanup;
        }

        VIR_FREE(vm->def->consoles[i]->source.data.file.path);
        vm->def->consoles[i]->source.data.file.path = ttyPath;

        VIR_FREE(vm->def->consoles[i]->info.alias);
        if (virAsprintf(&vm->def->consoles[i]->info.alias, "console%zu", i) < 0)
            goto cleanup;
    }

    if (virLXCProcessSetupInterfaces(conn, vm->def, &nveths, &veths) < 0)
        goto cleanup;

    /* Save the configuration for the controller */
    if (virDomainSaveConfig(cfg->stateDir, vm->def) < 0)
        goto cleanup;

    if ((logfd = open(logfile, O_WRONLY | O_APPEND | O_CREAT,
             S_IRUSR|S_IWUSR)) < 0) {
        virReportSystemError(errno,
                             _("Failed to open '%s'"),
                             logfile);
        goto cleanup;
    }

    if (pipe(handshakefds) < 0) {
        virReportSystemError(errno, "%s",
                             _("Unable to create pipe"));
        goto cleanup;
    }

    if (!(cmd = virLXCProcessBuildControllerCmd(driver,
                                                vm,
                                                nveths, veths,
                                                ttyFDs, nttyFDs,
                                                files, nfiles,
                                                handshakefds[1])))
        goto cleanup;
    virCommandSetOutputFD(cmd, &logfd);
    virCommandSetErrorFD(cmd, &logfd);

    /* now that we know it is about to start call the hook if present */
    if (virHookPresent(VIR_HOOK_DRIVER_LXC)) {
        char *xml = virDomainDefFormat(vm->def, 0);
        int hookret;

        hookret = virHookCall(VIR_HOOK_DRIVER_LXC, vm->def->name,
                              VIR_HOOK_LXC_OP_START, VIR_HOOK_SUBOP_BEGIN,
                              NULL, xml, NULL);
        VIR_FREE(xml);

        /*
         * If the script raised an error abort the launch
         */
        if (hookret < 0)
            goto cleanup;
    }

    /* Log timestamp */
    if ((timestamp = virTimeStringNow()) == NULL)
        goto cleanup;
    if (safewrite(logfd, timestamp, strlen(timestamp)) < 0 ||
        safewrite(logfd, START_POSTFIX, strlen(START_POSTFIX)) < 0) {
        VIR_WARN("Unable to write timestamp to logfile: %s",
                 virStrerror(errno, ebuf, sizeof(ebuf)));
    }
    VIR_FREE(timestamp);

    /* Log generated command line */
    virCommandWriteArgLog(cmd, logfd);
    if ((pos = lseek(logfd, 0, SEEK_END)) < 0)
        VIR_WARN("Unable to seek to end of logfile: %s",
                 virStrerror(errno, ebuf, sizeof(ebuf)));

    virCommandRawStatus(cmd);
    if (virCommandRun(cmd, &status) < 0)
        goto cleanup;

    if (status != 0) {
        if (virLXCProcessReadLogOutput(vm, logfile, pos, ebuf,
                                       sizeof(ebuf)) <= 0) {
            if (WIFEXITED(status))
                snprintf(ebuf, sizeof(ebuf), _("unexpected exit status %d"),
                         WEXITSTATUS(status));
            else
                snprintf(ebuf, sizeof(ebuf), "%s", _("terminated abnormally"));
        }
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("guest failed to start: %s"), ebuf);
        goto cleanup;
    }


    if (VIR_CLOSE(handshakefds[1]) < 0) {
        virReportSystemError(errno, "%s", _("could not close handshake fd"));
        goto cleanup;
    }

    /* Connect to the controller as a client *first* because
     * this will block until the child has written their
     * pid file out to disk & created their cgroup */
    if (!(priv->monitor = virLXCProcessConnectMonitor(driver, vm))) {
        /* Intentionally overwrite the real monitor error message,
         * since a better one is almost always found in the logs
         */
        if (virLXCProcessReadLogOutput(vm, logfile, pos, ebuf, sizeof(ebuf)) > 0) {
            virResetLastError();
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("guest failed to start: %s"), ebuf);
        }
        goto cleanup;
    }

    /* And get its pid */
    if ((r = virPidFileRead(cfg->stateDir, vm->def->name, &vm->pid)) < 0) {
        if (virLXCProcessReadLogOutput(vm, logfile, pos, ebuf, sizeof(ebuf)) > 0)
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("guest failed to start: %s"), ebuf);
        else
            virReportSystemError(-r,
                                 _("Failed to read pid file %s/%s.pid"),
                                 cfg->stateDir, vm->def->name);
        goto cleanup;
    }

    if (virCgroupNewDetectMachine(vm->def->name, "lxc", vm->pid,
                                  vm->def->resource ?
                                  vm->def->resource->partition :
                                  NULL,
                                  -1, &priv->cgroup) < 0)
        goto error;

    if (!priv->cgroup) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No valid cgroup for machine %s"),
                       vm->def->name);
        goto error;
    }

    priv->stopReason = VIR_DOMAIN_EVENT_STOPPED_FAILED;
    priv->wantReboot = false;
    vm->def->id = vm->pid;
    virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, reason);
    priv->doneStopEvent = false;

    if (virAtomicIntInc(&driver->nactive) == 1 && driver->inhibitCallback)
        driver->inhibitCallback(true, driver->inhibitOpaque);

    if (lxcContainerWaitForContinue(handshakefds[0]) < 0) {
        char out[1024];

        if (!(virLXCProcessReadLogOutput(vm, logfile, pos, out, 1024) < 0)) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("guest failed to start: %s"), out);
        }

        goto error;
    }

    if (autoDestroy &&
        virCloseCallbacksSet(driver->closeCallbacks, vm,
                             conn, lxcProcessAutoDestroy) < 0)
        goto error;

    if (virDomainObjSetDefTransient(caps, driver->xmlopt,
                                    vm, false) < 0)
        goto error;

    /* Write domain status to disk.
     *
     * XXX: Earlier we wrote the plain "live" domain XML to this
     * location for the benefit of libvirt_lxc. We're now overwriting
     * it with the live status XML instead. This is a (currently
     * harmless) inconsistency we should fix one day */
    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
        goto error;

    /* finally we can call the 'started' hook script if any */
    if (virHookPresent(VIR_HOOK_DRIVER_LXC)) {
        char *xml = virDomainDefFormat(vm->def, 0);
        int hookret;

        hookret = virHookCall(VIR_HOOK_DRIVER_LXC, vm->def->name,
                              VIR_HOOK_LXC_OP_STARTED, VIR_HOOK_SUBOP_BEGIN,
                              NULL, xml, NULL);
        VIR_FREE(xml);

        /*
         * If the script raised an error abort the launch
         */
        if (hookret < 0)
            goto error;
    }

    rc = 0;

 cleanup:
    if (rc != 0 && !err)
        err = virSaveLastError();
    virCommandFree(cmd);
    if (VIR_CLOSE(logfd) < 0) {
        virReportSystemError(errno, "%s", _("could not close logfile"));
        rc = -1;
    }
    for (i = 0; i < nveths; i++) {
        if (rc != 0 && veths[i])
            ignore_value(virNetDevVethDelete(veths[i]));
        VIR_FREE(veths[i]);
    }
    if (rc != 0) {
        if (vm->newDef) {
            virDomainDefFree(vm->newDef);
            vm->newDef = NULL;
        }
        if (priv->monitor) {
            virObjectUnref(priv->monitor);
            priv->monitor = NULL;
        }
        virDomainConfVMNWFilterTeardown(vm);

        virSecurityManagerRestoreAllLabel(driver->securityManager,
                                          vm->def, false);
        virSecurityManagerReleaseLabel(driver->securityManager, vm->def);
        /* Clear out dynamically assigned labels */
        if (vm->def->nseclabels &&
            vm->def->seclabels[0]->type == VIR_DOMAIN_SECLABEL_DYNAMIC) {
            VIR_FREE(vm->def->seclabels[0]->model);
            VIR_FREE(vm->def->seclabels[0]->label);
            VIR_FREE(vm->def->seclabels[0]->imagelabel);
        }
    }
    for (i = 0; i < nttyFDs; i++)
        VIR_FORCE_CLOSE(ttyFDs[i]);
    VIR_FREE(ttyFDs);
    VIR_FORCE_CLOSE(handshakefds[0]);
    VIR_FORCE_CLOSE(handshakefds[1]);
    VIR_FREE(logfile);
    virObjectUnref(cfg);
    virObjectUnref(caps);

    if (err) {
        virSetError(err);
        virFreeError(err);
    }

    return rc;

 error:
    err = virSaveLastError();
    virLXCProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED);
    goto cleanup;
}
Exemple #10
0
int
virshRunConsole(vshControl *ctl,
                virDomainPtr dom,
                const char *dev_name,
                unsigned int flags)
{
    virConsolePtr con = NULL;
    virshControlPtr priv = ctl->privData;
    int ret = -1;

    struct sigaction old_sigquit;
    struct sigaction old_sigterm;
    struct sigaction old_sigint;
    struct sigaction old_sighup;
    struct sigaction old_sigpipe;
    struct sigaction sighandler = {.sa_handler = virConsoleHandleSignal,
                                   .sa_flags = SA_SIGINFO };

    sigemptyset(&sighandler.sa_mask);

    /* Put STDIN into raw mode so that stuff typed does not echo to the screen
     * (the TTY reads will result in it being echoed back already), and also
     * ensure Ctrl-C, etc is blocked, and misc other bits */
    if (vshTTYMakeRaw(ctl, true) < 0)
        goto resettty;

    if (!(con = virConsoleNew()))
        goto resettty;

    virObjectLock(con);

    /* Trap all common signals so that we can safely restore the original
     * terminal settings on STDIN before the process exits - people don't like
     * being left with a messed up terminal ! */
    sigaction(SIGQUIT, &sighandler, &old_sigquit);
    sigaction(SIGTERM, &sighandler, &old_sigterm);
    sigaction(SIGINT,  &sighandler, &old_sigint);
    sigaction(SIGHUP,  &sighandler, &old_sighup);
    sigaction(SIGPIPE, &sighandler, &old_sigpipe);

    con->escapeChar = virshGetEscapeChar(priv->escapeChar);
    con->st = virStreamNew(virDomainGetConnect(dom),
                           VIR_STREAM_NONBLOCK);
    if (!con->st)
        goto cleanup;

    if (virDomainOpenConsole(dom, dev_name, con->st, flags) < 0)
        goto cleanup;

    virObjectRef(con);
    if ((con->stdinWatch = virEventAddHandle(STDIN_FILENO,
                                             VIR_EVENT_HANDLE_READABLE,
                                             virConsoleEventOnStdin,
                                             con,
                                             virObjectFreeCallback)) < 0) {
        virObjectUnref(con);
        goto cleanup;
    }

    virObjectRef(con);
    if ((con->stdoutWatch = virEventAddHandle(STDOUT_FILENO,
                                              0,
                                              virConsoleEventOnStdout,
                                              con,
                                              virObjectFreeCallback)) < 0) {
        virObjectUnref(con);
        goto cleanup;
    }

    virObjectRef(con);
    if (virStreamEventAddCallback(con->st,
                                  VIR_STREAM_EVENT_READABLE,
                                  virConsoleEventOnStream,
                                  con,
                                  virObjectFreeCallback) < 0) {
        virObjectUnref(con);
        goto cleanup;
    }

    while (!con->quit) {
        if (virCondWait(&con->cond, &con->parent.lock) < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("unable to wait on console condition"));
            goto cleanup;
        }
    }

    if (con->error.code == VIR_ERR_OK)
        ret = 0;

 cleanup:
    virConsoleShutdown(con);

    if (ret < 0) {
        vshResetLibvirtError();
        virSetError(&con->error);
        vshSaveLibvirtHelperError();
    }

    virObjectUnlock(con);
    virObjectUnref(con);

    /* Restore original signal handlers */
    sigaction(SIGQUIT, &old_sigquit, NULL);
    sigaction(SIGTERM, &old_sigterm, NULL);
    sigaction(SIGINT,  &old_sigint,  NULL);
    sigaction(SIGHUP,  &old_sighup,  NULL);
    sigaction(SIGPIPE, &old_sigpipe, NULL);

 resettty:
    /* Put STDIN back into the (sane?) state we found
       it in before starting */
    vshTTYRestore(ctl);

    return ret;
}