Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
0
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;
}
Ejemplo n.º 3
0
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;
}
Ejemplo n.º 4
0
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;
}
Ejemplo n.º 5
0
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;
}
Ejemplo n.º 6
0
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;
}
Ejemplo n.º 7
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;
}