static int virFDStreamUpdateCallback(virStreamPtr stream, int events) { struct virFDStreamData *fdst = stream->privateData; int ret = -1; if (!fdst) { streamsReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("stream is not open")); return -1; } virMutexLock(&fdst->lock); if (fdst->watch == 0) { streamsReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("stream does not have a callback registered")); goto cleanup; } virEventUpdateHandle(fdst->watch, events); ret = 0; cleanup: virMutexUnlock(&fdst->lock); return ret; }
static int virFDStreamRemoveCallback(virStreamPtr stream) { struct virFDStreamData *fdst = stream->privateData; int ret = -1; if (!fdst) { streamsReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("stream is not open")); return -1; } virMutexLock(&fdst->lock); if (fdst->watch == 0) { streamsReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("stream does not have a callback registered")); goto cleanup; } virEventRemoveHandle(fdst->watch); if (fdst->dispatching) fdst->cbRemoved = 1; else if (fdst->ff) (fdst->ff)(fdst->opaque); fdst->watch = 0; fdst->ff = NULL; fdst->cb = NULL; fdst->opaque = NULL; ret = 0; cleanup: virMutexUnlock(&fdst->lock); return ret; }
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 virFDStreamAddCallback(virStreamPtr st, int events, virStreamEventCallback cb, void *opaque, virFreeCallback ff) { struct virFDStreamData *fdst = st->privateData; int ret = -1; if (!fdst) { streamsReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("stream is not open")); return -1; } virMutexLock(&fdst->lock); if (fdst->watch != 0) { streamsReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("stream already has a callback registered")); goto cleanup; } if ((fdst->watch = virEventAddHandle(fdst->fd, events, virFDStreamEvent, st, virFDStreamCallbackFree)) < 0) { streamsReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot register file watch on stream")); goto cleanup; } fdst->cbRemoved = false; fdst->cb = cb; fdst->opaque = opaque; fdst->ff = ff; fdst->events = events; fdst->abortCallbackCalled = false; virStreamRef(st); ret = 0; cleanup: virMutexUnlock(&fdst->lock); return ret; }
static int virFDStreamWrite(virStreamPtr st, const char *bytes, size_t nbytes) { struct virFDStreamData *fdst = st->privateData; int ret; if (nbytes > INT_MAX) { virReportSystemError(ERANGE, "%s", _("Too many bytes to write to stream")); return -1; } if (!fdst) { streamsReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("stream is not open")); return -1; } virMutexLock(&fdst->lock); if (fdst->length) { if (fdst->length == fdst->offset) { virReportSystemError(ENOSPC, "%s", _("cannot write to stream")); virMutexUnlock(&fdst->lock); return -1; } if ((fdst->length - fdst->offset) < nbytes) nbytes = fdst->length - fdst->offset; } retry: ret = write(fdst->fd, bytes, nbytes); if (ret < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) { ret = -2; } else if (errno == EINTR) { goto retry; } else { ret = -1; virReportSystemError(errno, "%s", _("cannot write to stream")); } } else if (fdst->length) { fdst->offset += ret; } virMutexUnlock(&fdst->lock); return ret; }
static int virFDStreamOpenInternal(virStreamPtr st, int fd, virCommandPtr cmd, int errfd, unsigned long long length) { struct virFDStreamData *fdst; VIR_DEBUG("st=%p fd=%d cmd=%p errfd=%d length=%llu", st, fd, cmd, errfd, length); if ((st->flags & VIR_STREAM_NONBLOCK) && virSetNonBlock(fd) < 0) return -1; if (VIR_ALLOC(fdst) < 0) { virReportOOMError(); return -1; } fdst->fd = fd; fdst->cmd = cmd; fdst->errfd = errfd; fdst->length = length; if (virMutexInit(&fdst->lock) < 0) { VIR_FREE(fdst); streamsReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unable to initialize mutex")); return -1; } st->driver = &virFDStreamDrv; st->privateData = fdst; return 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'; 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); 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; }