/** * 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; }
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; }
/** * 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; }