static int virFDStreamClose(virStreamPtr st) { struct virFDStreamData *fdst = st->privateData; int ret; VIR_DEBUG("st=%p", st); if (!fdst) return 0; virMutexLock(&fdst->lock); ret = VIR_CLOSE(fdst->fd); if (fdst->cmd) { char buf[1024]; ssize_t len; int status; if ((len = saferead(fdst->errfd, buf, sizeof(buf)-1)) < 0) buf[0] = '\0'; else buf[len] = '\0'; if (virCommandWait(fdst->cmd, &status) < 0) { ret = -1; } else if (status != 0) { if (buf[0] == '\0') { if (WIFEXITED(status)) { streamsReportError(VIR_ERR_INTERNAL_ERROR, _("I/O helper exited with status %d"), WEXITSTATUS(status)); } else { streamsReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("I/O helper exited abnormally")); } } else { streamsReportError(VIR_ERR_INTERNAL_ERROR, "%s", buf); } ret = -1; } virCommandFree(fdst->cmd); } st->privateData = NULL; virMutexUnlock(&fdst->lock); virMutexDestroy(&fdst->lock); VIR_FREE(fdst); return ret; }
static int openvzListDefinedDomains(virConnectPtr conn ATTRIBUTE_UNUSED, char **const names, int nnames) { int got = 0; int veid, outfd = -1, ret; int rc = -1; char vpsname[32]; char buf[32]; char *endptr; virCommandPtr cmd = virCommandNewArgList(VZLIST, "-ovpsid", "-H", "-S", NULL); /* the -S options lists only stopped domains */ virCommandSetOutputFD(cmd, &outfd); if (virCommandRunAsync(cmd, NULL) < 0) goto out; while (got < nnames) { ret = openvz_readline(outfd, buf, 32); if (!ret) break; if (virStrToLong_i(buf, &endptr, 10, &veid) < 0) { openvzError(VIR_ERR_INTERNAL_ERROR, _("Could not parse VPS ID %s"), buf); continue; } snprintf(vpsname, sizeof(vpsname), "%d", veid); if (!(names[got] = strdup(vpsname))) { virReportOOMError(); goto out; } got ++; } if (virCommandWait(cmd, NULL) < 0) goto out; if (VIR_CLOSE(outfd) < 0) { virReportSystemError(errno, "%s", _("failed to close file")); goto out; } rc = got; out: VIR_FORCE_CLOSE(outfd); virCommandFree(cmd); if (rc < 0) { for ( ; got >= 0 ; got--) VIR_FREE(names[got]); } return rc; }
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; }
static int openvzListDomains(virConnectPtr conn ATTRIBUTE_UNUSED, int *ids, int nids) { int got = 0; int veid; int outfd = -1; int rc = -1; int ret; char buf[32]; char *endptr; virCommandPtr cmd = virCommandNewArgList(VZLIST, "-ovpsid", "-H" , NULL); virCommandSetOutputFD(cmd, &outfd); if (virCommandRunAsync(cmd, NULL) < 0) goto cleanup; while (got < nids) { ret = openvz_readline(outfd, buf, 32); if (!ret) break; if (virStrToLong_i(buf, &endptr, 10, &veid) < 0) { openvzError(VIR_ERR_INTERNAL_ERROR, _("Could not parse VPS ID %s"), buf); continue; } ids[got] = veid; got ++; } if (virCommandWait(cmd, NULL) < 0) goto cleanup; if (VIR_CLOSE(outfd) < 0) { virReportSystemError(errno, "%s", _("failed to close file")); goto cleanup; } rc = got; cleanup: VIR_FORCE_CLOSE(outfd); virCommandFree(cmd); return rc; }
/** * qemuCreateInBridgePortWithHelper: * @cfg: the configuration object in which the helper name is looked up * @brname: the bridge name * @ifname: the returned interface name * @macaddr: the returned MAC address * @tapfd: file descriptor return value for the new tap device * @flags: OR of virNetDevTapCreateFlags: * VIR_NETDEV_TAP_CREATE_VNET_HDR * - Enable IFF_VNET_HDR on the tap device * * This function creates a new tap device on a bridge using an external * helper. The final name for the bridge will be stored in @ifname. * * Returns 0 in case of success or -1 on failure */ static int qemuCreateInBridgePortWithHelper(virQEMUDriverConfigPtr cfg, const char *brname, char **ifname, int *tapfd, unsigned int flags) { virCommandPtr cmd; char *errbuf = NULL, *cmdstr = NULL; int pair[2] = { -1, -1 }; if ((flags & ~VIR_NETDEV_TAP_CREATE_VNET_HDR) != VIR_NETDEV_TAP_CREATE_IFUP) return -1; if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) < 0) { virReportSystemError(errno, "%s", _("failed to create socket")); return -1; } if (!virFileIsExecutable(cfg->bridgeHelperName)) { virReportSystemError(errno, _("'%s' is not a suitable bridge helper"), cfg->bridgeHelperName); return -1; } cmd = virCommandNew(cfg->bridgeHelperName); if (flags & VIR_NETDEV_TAP_CREATE_VNET_HDR) virCommandAddArgFormat(cmd, "--use-vnet"); virCommandAddArgFormat(cmd, "--br=%s", brname); virCommandAddArgFormat(cmd, "--fd=%d", pair[1]); virCommandSetErrorBuffer(cmd, &errbuf); virCommandDoAsyncIO(cmd); virCommandPassFD(cmd, pair[1], VIR_COMMAND_PASS_FD_CLOSE_PARENT); virCommandClearCaps(cmd); #ifdef CAP_NET_ADMIN virCommandAllowCap(cmd, CAP_NET_ADMIN); #endif if (virCommandRunAsync(cmd, NULL) < 0) { *tapfd = -1; goto cleanup; } do { *tapfd = recvfd(pair[0], 0); } while (*tapfd < 0 && errno == EINTR); if (*tapfd < 0) { char ebuf[1024]; char *errstr = NULL; if (!(cmdstr = virCommandToString(cmd))) goto cleanup; virCommandAbort(cmd); if (errbuf && *errbuf && virAsprintf(&errstr, "\nstderr=%s", errbuf) < 0) goto cleanup; virReportError(VIR_ERR_INTERNAL_ERROR, _("%s: failed to communicate with bridge helper: %s%s"), cmdstr, virStrerror(errno, ebuf, sizeof(ebuf)), errstr ? errstr : ""); VIR_FREE(errstr); goto cleanup; } if (virNetDevTapGetName(*tapfd, ifname) < 0 || virCommandWait(cmd, NULL) < 0) { VIR_FORCE_CLOSE(*tapfd); *tapfd = -1; } cleanup: VIR_FREE(cmdstr); VIR_FREE(errbuf); virCommandFree(cmd); VIR_FORCE_CLOSE(pair[0]); return *tapfd < 0 ? -1 : 0; }
static int virFDStreamCloseInt(virStreamPtr st, bool streamAbort) { struct virFDStreamData *fdst; virStreamEventCallback cb; void *opaque; int ret; VIR_DEBUG("st=%p", st); if (!st || !(fdst = st->privateData) || fdst->abortCallbackDispatching) return 0; virMutexLock(&fdst->lock); /* aborting the stream, ensure the callback is called if it's * registered for stream error event */ if (streamAbort && fdst->cb && (fdst->events & (VIR_STREAM_EVENT_READABLE | VIR_STREAM_EVENT_WRITABLE))) { /* don't enter this function accidentally from the callback again */ if (fdst->abortCallbackCalled) { virMutexUnlock(&fdst->lock); return 0; } fdst->abortCallbackCalled = true; fdst->abortCallbackDispatching = true; /* cache the pointers */ cb = fdst->cb; opaque = fdst->opaque; virMutexUnlock(&fdst->lock); /* call failure callback, poll reports nothing on closed fd */ (cb)(st, VIR_STREAM_EVENT_ERROR, opaque); virMutexLock(&fdst->lock); fdst->abortCallbackDispatching = false; } /* mutex locked */ ret = VIR_CLOSE(fdst->fd); if (fdst->cmd) { char buf[1024]; ssize_t len; int status; 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) { ret = -1; } else if (status != 0) { if (buf[0] == '\0') { if (WIFEXITED(status)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("I/O helper exited with status %d"), WEXITSTATUS(status)); } else { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("I/O helper exited abnormally")); } } else { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", buf); } ret = -1; } virCommandFree(fdst->cmd); fdst->cmd = NULL; } if (VIR_CLOSE(fdst->errfd) < 0) VIR_DEBUG("ignoring failed close on fd %d", fdst->errfd); st->privateData = NULL; /* call the internal stream closing callback */ if (fdst->icbCb) { /* the mutex is not accessible anymore, as private data is null */ (fdst->icbCb)(st, fdst->icbOpaque); if (fdst->icbFreeOpaque) (fdst->icbFreeOpaque)(fdst->icbOpaque); } if (fdst->dispatching) { fdst->closed = true; virMutexUnlock(&fdst->lock); } else { virMutexUnlock(&fdst->lock); virMutexDestroy(&fdst->lock); VIR_FREE(fdst); } return ret; }
static int virStorageBackendIQNFound(const char *initiatoriqn, char **ifacename) { int ret = IQN_MISSING, fd = -1; char ebuf[64]; FILE *fp = NULL; char *line = NULL, *newline = NULL, *iqn = NULL, *token = NULL; virCommandPtr cmd = virCommandNewArgList(ISCSIADM, "--mode", "iface", NULL); if (VIR_ALLOC_N(line, LINE_SIZE) != 0) { ret = IQN_ERROR; virStorageReportError(VIR_ERR_INTERNAL_ERROR, _("Could not allocate memory for output of '%s'"), ISCSIADM); goto out; } memset(line, 0, LINE_SIZE); virCommandSetOutputFD(cmd, &fd); if (virCommandRunAsync(cmd, NULL) < 0) { ret = IQN_ERROR; goto out; } if ((fp = VIR_FDOPEN(fd, "r")) == NULL) { virStorageReportError(VIR_ERR_INTERNAL_ERROR, _("Failed to open stream for file descriptor " "when reading output from '%s': '%s'"), ISCSIADM, virStrerror(errno, ebuf, sizeof ebuf)); ret = IQN_ERROR; goto out; } while (fgets(line, LINE_SIZE, fp) != NULL) { newline = strrchr(line, '\n'); if (newline == NULL) { ret = IQN_ERROR; virStorageReportError(VIR_ERR_INTERNAL_ERROR, _("Unexpected line > %d characters " "when parsing output of '%s'"), LINE_SIZE, ISCSIADM); goto out; } *newline = '\0'; iqn = strrchr(line, ','); if (iqn == NULL) { continue; } iqn++; if (STREQ(iqn, initiatoriqn)) { token = strchr(line, ' '); if (!token) { ret = IQN_ERROR; virStorageReportError(VIR_ERR_INTERNAL_ERROR, _("Missing space when parsing output " "of '%s'"), ISCSIADM); goto out; } *ifacename = strndup(line, token - line); if (*ifacename == NULL) { ret = IQN_ERROR; virReportOOMError(); goto out; } VIR_DEBUG("Found interface '%s' with IQN '%s'", *ifacename, iqn); ret = IQN_FOUND; break; } } if (virCommandWait(cmd, NULL) < 0) ret = IQN_ERROR; out: if (ret == IQN_MISSING) { VIR_DEBUG("Could not find interface with IQN '%s'", iqn); } VIR_FREE(line); VIR_FORCE_FCLOSE(fp); VIR_FORCE_CLOSE(fd); virCommandFree(cmd); return ret; }
/* * Run the command and wait for completion. * Returns -1 on any error executing the * command. Returns 0 if the command executed, * with the exit status set */ int virCommandRun(virCommandPtr cmd, int *exitstatus) { int ret = 0; char *outbuf = NULL; char *errbuf = NULL; int infd[2] = { -1, -1 }; struct stat st; bool string_io; bool async_io = false; char *str; if (!cmd ||cmd->has_error == ENOMEM) { virReportOOMError(); return -1; } if (cmd->has_error) { virCommandError(VIR_ERR_INTERNAL_ERROR, "%s", _("invalid use of command API")); return -1; } /* Avoid deadlock, by requiring that any open fd not under our * control must be visiting a regular file, or that we are * daemonized and no string io is required. */ string_io = cmd->inbuf || cmd->outbuf || cmd->errbuf; if (cmd->infd != -1 && (fstat(cmd->infd, &st) < 0 || !S_ISREG(st.st_mode))) async_io = true; if (cmd->outfdptr && cmd->outfdptr != &cmd->outfd && (*cmd->outfdptr == -1 || fstat(*cmd->outfdptr, &st) < 0 || !S_ISREG(st.st_mode))) async_io = true; if (cmd->errfdptr && cmd->errfdptr != &cmd->errfd && (*cmd->errfdptr == -1 || fstat(*cmd->errfdptr, &st) < 0 || !S_ISREG(st.st_mode))) async_io = true; if (async_io) { if (!(cmd->flags & VIR_EXEC_DAEMON) || string_io) { virCommandError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot mix caller fds with blocking execution")); return -1; } } else { if ((cmd->flags & VIR_EXEC_DAEMON) && string_io) { virCommandError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot mix string I/O with daemon")); return -1; } } /* If we have an input buffer, we need * a pipe to feed the data to the child */ if (cmd->inbuf) { if (pipe(infd) < 0) { virReportSystemError(errno, "%s", _("unable to open pipe")); cmd->has_error = -1; return -1; } cmd->infd = infd[0]; cmd->inpipe = infd[1]; } /* If caller hasn't requested capture of stdout/err, then capture * it ourselves so we can log it. But the intermediate child for * a daemon has no expected output, and we don't want our * capturing pipes passed on to the daemon grandchild. */ if (!(cmd->flags & VIR_EXEC_DAEMON)) { if (!cmd->outfdptr) { cmd->outfdptr = &cmd->outfd; cmd->outbuf = &outbuf; string_io = true; } if (!cmd->errfdptr) { cmd->errfdptr = &cmd->errfd; cmd->errbuf = &errbuf; string_io = true; } } cmd->flags |= VIR_EXEC_RUN_SYNC; if (virCommandRunAsync(cmd, NULL) < 0) { if (cmd->inbuf) { int tmpfd = infd[0]; if (VIR_CLOSE(infd[0]) < 0) VIR_DEBUG("ignoring failed close on fd %d", tmpfd); tmpfd = infd[1]; if (VIR_CLOSE(infd[1]) < 0) VIR_DEBUG("ignoring failed close on fd %d", tmpfd); } cmd->has_error = -1; return -1; } if (string_io) ret = virCommandProcessIO(cmd); if (virCommandWait(cmd, exitstatus) < 0) ret = -1; str = (exitstatus ? virCommandTranslateStatus(*exitstatus) : (char *) "status 0"); VIR_DEBUG("Result %s, stdout: '%s' stderr: '%s'", NULLSTR(str), cmd->outbuf ? NULLSTR(*cmd->outbuf) : "(null)", cmd->errbuf ? NULLSTR(*cmd->errbuf) : "(null)"); if (exitstatus) VIR_FREE(str); /* Reset any capturing, in case caller runs * this identical command again */ if (cmd->inbuf) { int tmpfd = infd[0]; if (VIR_CLOSE(infd[0]) < 0) VIR_DEBUG("ignoring failed close on fd %d", tmpfd); tmpfd = infd[1]; if (VIR_CLOSE(infd[1]) < 0) VIR_DEBUG("ignoring failed close on fd %d", tmpfd); } if (cmd->outbuf == &outbuf) { int tmpfd = cmd->outfd; if (VIR_CLOSE(cmd->outfd) < 0) VIR_DEBUG("ignoring failed close on fd %d", tmpfd); cmd->outfdptr = NULL; cmd->outbuf = NULL; VIR_FREE(outbuf); } if (cmd->errbuf == &errbuf) { int tmpfd = cmd->errfd; if (VIR_CLOSE(cmd->errfd) < 0) VIR_DEBUG("ignoring failed close on fd %d", tmpfd); cmd->errfdptr = NULL; cmd->errbuf = NULL; VIR_FREE(errbuf); } return ret; }