[libvirt] [PATCH 6/7] Re-write virsh console to use streams

Eric Blake eblake at redhat.com
Thu Aug 19 21:09:45 UTC 2010


On 08/17/2010 11:02 AM, Daniel P. Berrange wrote:
> This re-writes the 'virsh console' command so that it uses
> the new streams API. This lets it run remotely and/or as a
> non-root user. This requires that virsh be linked against
> the simple event loop from libvirtd in daemon/event.c
> As an added bonus, it can now connect to any console device,
> not just the first one.
> 
> * tools/Makefile.am: Link to event.c
> * tools/console.c, tools/console.h: Rewrite to use the
>   virDomainOpenConsole() APIs with streams
> * tools/virsh.c: Support choosing the console name
>   via --devname $NAME
> ---
>  tools/Makefile.am |    1 +
>  tools/console.c   |  330 ++++++++++++++++++++++++++++++++++++++++-------------
>  tools/console.h   |    2 +-
>  tools/virsh.c     |   76 ++++---------
>  4 files changed, 274 insertions(+), 135 deletions(-)

> +
> +struct virConsoleBuffer {
> +    size_t length;
> +    size_t offset;

s/size_t/off_t/ for offset? (but see below)

> +    char *data;
> +};
> +
> +typedef struct virConsole virConsole;
> +typedef virConsole *virConsolePtr;
> +struct virConsole {
> +    virStreamPtr st;
> +    int quit;

s/int/bool/, and adjust clients to use false/true instead of 0/1

> +
> +    int stdinWatch;
> +    int stdoutWatch;
> +
> +    struct virConsoleBuffer streamToTerminal;
> +    struct virConsoleBuffer terminalToStream;
> +};
> +
>  static int got_signal = 0;
>  static void do_signal(int sig ATTRIBUTE_UNUSED) {
>      got_signal = 1;
> @@ -61,22 +86,192 @@ cfmakeraw (struct termios *attr)
>  }
>  # endif /* !HAVE_CFMAKERAW */
>  
> -int vshRunConsole(const char *tty) {
> -    int ttyfd, ret = -1;
> +static void
> +virConsoleEventOnStream(virStreamPtr st,
> +                        int events, void *opaque)
> +{
> +    virConsolePtr con = opaque;
> +
> +    if (events & VIR_STREAM_EVENT_READABLE) {
> +        size_t avail = con->streamToTerminal.length -
> +            con->streamToTerminal.offset;

Oh, never mind.  size_t for offset is probably just fine after all.

> +        int got;
> +
> +        if (avail < 1024) {
> +            if (VIR_REALLOC_N(con->streamToTerminal.data,
> +                              con->streamToTerminal.length + 1024) < 0) {

/me Note to self - another VIR_EXPAND_N or VIR_RESIZE_N candidate.

> +                virReportOOMError();
> +                con->quit = 1;
> +                return;
> +            }
> +            con->streamToTerminal.length += 1024;
> +            avail += 1024;
> +        }
> +
> +        got = virStreamRecv(st,
> +                            con->streamToTerminal.data +
> +                            con->streamToTerminal.offset,
> +                            avail);
> +        if (got == -2)
> +            return; /* blocking */
> +        if (got <= 0) {
> +            con->quit = 1;
> +            return;
> +        }
> +        con->streamToTerminal.offset += got;
> +        if (con->streamToTerminal.offset)
> +            virEventUpdateHandleImpl(con->stdoutWatch,
> +                                     VIR_EVENT_HANDLE_WRITABLE);
> +    }
> +
> +    if (events & VIR_STREAM_EVENT_WRITABLE &&
> +        con->terminalToStream.offset) {
> +        ssize_t done;
> +        size_t avail;
> +        done = virStreamSend(con->st,
> +                             con->terminalToStream.data,
> +                             con->terminalToStream.offset);
> +        if (done == -2)
> +            return; /* blocking */
> +        if (done < 0) {
> +            virErrorPtr err = virGetLastError();
> +            con->quit = 1;
> +            return;
> +        }
> +        memmove(con->terminalToStream.data,
> +                con->terminalToStream.data + done,
> +                con->terminalToStream.offset - done);
> +        con->terminalToStream.offset -= done;
> +
> +        avail = con->terminalToStream.length - con->terminalToStream.offset;
> +        if (avail > 1024) {
> +            if (VIR_REALLOC_N(con->terminalToStream.data,
> +                              con->terminalToStream.offset + 1024) < 0)
> +            {}

/me Note to self - a VIR_SHRINK_N candidate.

> +            con->terminalToStream.length = con->terminalToStream.offset + 1024;
> +        }
> +    }
> +    if (!con->terminalToStream.offset)
> +        virStreamEventUpdateCallback(con->st,
> +                                     VIR_STREAM_EVENT_READABLE);
> +
> +    if (events & VIR_STREAM_EVENT_ERROR ||
> +        events & VIR_STREAM_EVENT_HANGUP) {
> +        con->quit = 1;
> +    }
> +}
> +
> +static void
> +virConsoleEventOnStdin(int watch ATTRIBUTE_UNUSED,
> +                       int fd ATTRIBUTE_UNUSED,
> +                       int events,
> +                       void *opaque)
> +{
> +    virConsolePtr con = opaque;
> +
> +    if (events & VIR_EVENT_HANDLE_READABLE) {
> +        size_t avail = con->terminalToStream.length -
> +            con->terminalToStream.offset;
> +        int got;
> +
> +        if (avail < 1024) {
> +            if (VIR_REALLOC_N(con->terminalToStream.data,
> +                              con->terminalToStream.length + 1024) < 0) {
> +                virReportOOMError();
> +                con->quit = 1;
> +                return;
> +            }
> +            con->terminalToStream.length += 1024;
> +            avail += 1024;
> +        }
> +
> +        got = read(fd,
> +                   con->terminalToStream.data +
> +                   con->terminalToStream.offset,
> +                   avail);
> +        if (got < 0) {
> +            if (errno != EAGAIN) {
> +                con->quit = 1;
> +            }
> +            return;
> +        }
> +        if (got == 0) {
> +            con->quit = 1;
> +            return;
> +        }
> +        if (con->terminalToStream.data[con->terminalToStream.offset] == CTRL_CLOSE_BRACKET) {
> +            con->quit = 1;
> +            return;
> +        }
> +
> +        con->terminalToStream.offset += got;
> +        if (con->terminalToStream.offset)
> +            virStreamEventUpdateCallback(con->st,
> +                                         VIR_STREAM_EVENT_READABLE |
> +                                         VIR_STREAM_EVENT_WRITABLE);
> +    }
> +
> +    if (events & VIR_EVENT_HANDLE_ERROR ||
> +        events & VIR_EVENT_HANDLE_HANGUP) {
> +        con->quit = 1;
> +    }
> +}
> +
> +static void
> +virConsoleEventOnStdout(int watch ATTRIBUTE_UNUSED,
> +                        int fd,
> +                        int events,
> +                        void *opaque)
> +{
> +    virConsolePtr con = opaque;
> +
> +    if (events & VIR_EVENT_HANDLE_WRITABLE &&
> +        con->streamToTerminal.offset) {
> +        ssize_t done;
> +        size_t avail;
> +        done = write(fd,
> +                     con->streamToTerminal.data,
> +                     con->streamToTerminal.offset);

Do we want to use safewrite here?

Conditional ACK, if those are deemed easy nits to fix.

-- 
Eric Blake   eblake at redhat.com    +1-801-349-2682
Libvirt virtualization library http://libvirt.org

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 619 bytes
Desc: OpenPGP digital signature
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20100819/68225201/attachment-0001.sig>


More information about the libvir-list mailing list