Exemple #1
0
/**
 * virProcessAbort:
 * @pid: child process to kill
 *
 * Abort a child process if PID is positive and that child is still
 * running, without issuing any errors or affecting errno.  Designed
 * for error paths where some but not all paths to the cleanup code
 * might have started the child process.  If @pid is 0 or negative,
 * this does nothing.
 */
void
virProcessAbort(pid_t pid)
{
    int saved_errno;
    int ret;
    int status;
    char *tmp = NULL;

    if (pid <= 0)
        return;

    /* See if intermediate process has exited; if not, try a nice
     * SIGTERM followed by a more severe SIGKILL.
     */
    saved_errno = errno;
    VIR_DEBUG("aborting child process %d", pid);
    while ((ret = waitpid(pid, &status, WNOHANG)) == -1 &&
           errno == EINTR);
    if (ret == pid) {
        tmp = virProcessTranslateStatus(status);
        VIR_DEBUG("process has ended: %s", tmp);
        goto cleanup;
    } else if (ret == 0) {
        VIR_DEBUG("trying SIGTERM to child process %d", pid);
        kill(pid, SIGTERM);
        usleep(10 * 1000);
        while ((ret = waitpid(pid, &status, WNOHANG)) == -1 &&
               errno == EINTR);
        if (ret == pid) {
            tmp = virProcessTranslateStatus(status);
            VIR_DEBUG("process has ended: %s", tmp);
            goto cleanup;
        } else if (ret == 0) {
            VIR_DEBUG("trying SIGKILL to child process %d", pid);
            kill(pid, SIGKILL);
            while ((ret = waitpid(pid, &status, 0)) == -1 &&
                   errno == EINTR);
            if (ret == pid) {
                tmp = virProcessTranslateStatus(status);
                VIR_DEBUG("process has ended: %s", tmp);
                goto cleanup;
            }
        }
    }
    VIR_DEBUG("failed to reap child %lld, abandoning it", (long long) pid);

 cleanup:
    VIR_FREE(tmp);
    errno = saved_errno;
}
Exemple #2
0
static int
virFDStreamCloseCommand(struct virFDStreamData *fdst, bool streamAbort)
{
    char buf[1024];
    ssize_t len;
    int status;
    int ret = -1;

    if (!fdst->cmd)
        return 0;

    if ((len = saferead(fdst->errfd, buf, sizeof(buf)-1)) < 0)
        buf[0] = '\0';
    else
        buf[len] = '\0';

    virCommandRawStatus(fdst->cmd);
    if (virCommandWait(fdst->cmd, &status) < 0)
        goto cleanup;

    if (status != 0) {
        if (buf[0] != '\0') {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s", buf);
        } else if (WIFSIGNALED(status) && WTERMSIG(status) == SIGPIPE) {
            if (streamAbort) {
                /* Explicit abort request means the caller doesn't care
                   if there's data left over, so skip the error */
                goto out;
            }

            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("I/O helper exited "
                             "before all data was processed"));
        } else {
            char *str = virProcessTranslateStatus(status);
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("I/O helper exited with %s"),
                           NULLSTR(str));
            VIR_FREE(str);
        }
        goto cleanup;
    }

 out:
    ret = 0;
 cleanup:
    virCommandFree(fdst->cmd);
    fdst->cmd = NULL;
    return ret;
}
Exemple #3
0
/**
 * virProcessWait:
 * @pid: child to wait on
 * @exitstatus: optional status collection
 * @raw: whether to pass non-normal status back to caller
 *
 * Wait for a child process to complete.  If @pid is -1, do nothing, but
 * return -1 (useful for error cleanup, and assumes an earlier message was
 * already issued).  All other pids issue an error message on failure.
 *
 * If @exitstatus is NULL, then the child must exit normally with status 0.
 * Otherwise, if @raw is false, the child must exit normally, and
 * @exitstatus will contain the final exit status (no need for the caller
 * to use WEXITSTATUS()).  If @raw is true, then the result of waitpid() is
 * returned in @exitstatus, and the caller must use WIFEXITED() and friends
 * to decipher the child's status.
 *
 * Returns 0 on a successful wait.  Returns -1 on any error waiting for
 * completion, or if the command completed with a status that cannot be
 * reflected via the choice of @exitstatus and @raw.
 */
int
virProcessWait(pid_t pid, int *exitstatus, bool raw)
{
    int ret;
    int status;

    if (pid <= 0) {
        if (pid != -1)
            virReportSystemError(EINVAL, _("unable to wait for process %lld"),
                                 (long long) pid);
        return -1;
    }

    /* Wait for intermediate process to exit */
    while ((ret = waitpid(pid, &status, 0)) == -1 &&
           errno == EINTR);

    if (ret == -1) {
        virReportSystemError(errno, _("unable to wait for process %lld"),
                             (long long) pid);
        return -1;
    }

    if (exitstatus == NULL) {
        if (status != 0)
            goto error;
    } else if (raw) {
        *exitstatus = status;
    } else if (WIFEXITED(status)) {
        *exitstatus = WEXITSTATUS(status);
    } else {
        goto error;
    }

    return 0;

 error:
    {
        char *st = virProcessTranslateStatus(status);
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Child process (%lld) unexpected %s"),
                       (long long) pid, NULLSTR(st));
        VIR_FREE(st);
    }
    return -1;
}