Re: qemu-send.c (was Re: Since we're sharing, here's my kvmctl script)

2008-06-12 Thread Chris Webb
Javier Guerra Giraldez <[EMAIL PROTECTED]> writes:

> On Wednesday 11 June 2008, Chris Webb wrote:
> > Hi. I have a small 'qemu-send' utility for talking to a running qemu/kvm
> > process whose monitor console listens on a filesystem socket, which I think
> > might be a useful building block when extending these kinds of script to do
> > things like migratation, pausing, and so on. The source is attached.
> 
> there's a utility called socat that let's you send text to/from TCP sockets 
> and unix-domain sockets.  it can even (temporarily) attach the terminal, or 
> use GNU's readline to regain interactive control of KVM/Qemu

Hi. Yes, I'm aware of socat, netcat, tcpclient et al. and even have a
similar pair of little unix/tcp/udp/syslogging utilities myself called
sk/skd which I initially used for scripting our local kvm management system.

However, it's a little bit clumsy to use these tools correctly from a shell
script if you want to get back the command output intact. You need to open
your connection to the unix server socket, wait for the prompt (skipping the
welcome banner), send the command, copy the response out until you get a
line '(qemu) ', then disconnect. For the same reason you can't do

  echo -e "GET / HTTP/1.1\n\n" >/dev/tcp/www.google.com/80
  cat /dev/tcp/www.google.com/80
  echo -e "GET / HTTP/1.1\n\n" >&3
  cat <&3

instead, you need to avoid disconnecting from the socket in the middle of
the command/response exchange.

(In fact, with qemu, it nearly works anyway: the new connection gets all the
output and the next prompt from the old one before the new banner, so you
just have a couple of extra prompts, a command echo and a banner at the top
and bottom to filter away. However, I'd be very reluctant to rely on this
behaviour, and in particular on it not losing output between connections.
The method I implemented in qemu-send.c should be robust again changes in
the way qemu handles its monitor sockets.)

To get the convenient syntax and behaviour I wanted, it felt easier
and cleaner to write the few lines of C needed for a standalone utility
rather than introduce a parsing shell script/function plus a dependency on
one of sk/socat/netcat/tcpclient. I suspect also that I'm just more
comfortable in C than sh; YMMV!

Cheers,

Chris.
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: qemu-send.c (was Re: Since we're sharing, here's my kvmctl script)

2008-06-11 Thread Javier Guerra Giraldez
On Wednesday 11 June 2008, Chris Webb wrote:
> Hi. I have a small 'qemu-send' utility for talking to a running qemu/kvm
> process whose monitor console listens on a filesystem socket, which I think
> might be a useful building block when extending these kinds of script to do
> things like migratation, pausing, and so on. The source is attached.

there's a utility called socat that let's you send text to/from TCP sockets 
and unix-domain sockets.  it can even (temporarily) attach the terminal, or 
use GNU's readline to regain interactive control of KVM/Qemu


-- 
Javier


signature.asc
Description: This is a digitally signed message part.


qemu-send.c (was Re: Since we're sharing, here's my kvmctl script)

2008-06-11 Thread Chris Webb
Freddie Cash <[EMAIL PROTECTED]> writes:

> For everyone's viewing (and critiquing, I guess) pleasure, I present
> my version of a kvmctl script.

Hi. I have a small 'qemu-send' utility for talking to a running qemu/kvm
process whose monitor console listens on a filesystem socket, which I think
might be a useful building block when extending these kinds of script to do
things like migratation, pausing, and so on. The source is attached.

It's careful to extract and pass on the correct command output from kvm and
waits for the (qemu) prompt to return before exiting, so you can do stuff
like

  qemu-send /var/run/vm.ctl migrate file:///var/statedumps/foo
  do-something-with-the-file /var/statedumps/foo

without any race problem, and

  qemu-send /tmp/vm.ctl 'info blockstats'

will list the right info without any extraneous command echo or prompt text
leaking out.

Any comments or feedback welcome, and please feel free to incorporate it
where useful.

> The only thing I haven't been able to figure out, is how to send a
> "shutdown" command from the host OS to the guest OS, such that the
> guest OS will do a proper shutdown sequence.  You have to switch to
> the VM console and manually tell it to shutdown.  :(

If you have the qemu monitor listening on a unix socket /var/run/vm.ctl,
i.e. if you've started the kvm with an argument like

  -monitor unix:/var/run/vm.ctl,server,nowait

you could send a graceful shutdown using

  qemu-send /var/run/vm.ctl system_powerdown

Best wishes,

Chris.
#include 
#include 
#include 
#include 
#include 
#include 
#include 

const char *prompt = "(qemu) ";

void echo(char *s, size_t n, int *skip) {
  char *p;

  for (p = s; *skip != 0 && p < n + s; p++, (*skip)--)
if ((p = memchr(p, '\n', n + s - p)) == NULL)
  return;

  if (p < n + s)
write(STDOUT_FILENO, p, n + s - p);
}

void getprompt(int fd, int skip, int eof) {
  char s[PIPE_BUF];
  int n, sl = 0;

  do {
if ((n = read(fd, s + sl, sizeof(s) - sl)) < 0) {
  perror("read");
  exit(EXIT_FAILURE);
} else
  sl += n;

if (n == 0) {
  echo(s, sl, &skip);
  exit(eof);
}

if (sl > strlen(prompt)) {
  echo(s, sl - strlen(prompt), &skip);
  memmove(s, s + sl - strlen(prompt), strlen(prompt));
  sl = strlen(prompt);
}
  } while (memcmp(s, prompt, strlen(prompt)));
}

void usage(char *progname) {
  fprintf(stderr, "\
Usage: %1$s [-n] [-q] SOCKET COMMAND\n\
   %1$s -t SOCKET\n\
Options:\n\
  -ndo not wait for command to finish before returning\n\
  -qdo not echo output from kvm/qemu to stdout\n\
  -ttest if kvm/qemu is listening on SOCKET without issuing a command\n\
", progname);
  exit(EXIT_FAILURE);
}

int main(int argc, char **argv) {
  int n, sock, quiet = 0, wait = 1, test = 0;
  struct sockaddr_un sockaddr;

  while ((n = getopt(argc, argv, "nqt")) > 0)
switch (n) {
  case 'n':
wait = 0;
break;
  case 'q':
quiet = 1;
break;
  case 't':
test = 1;
break;
  default:
usage(argv[0]);
}
  if ((argc -= optind) != (test ? 1 : 2))
usage(argv[0]);
  argv += optind;

  if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
perror("socket");
return EXIT_FAILURE;
  }

  sockaddr.sun_family = AF_UNIX;
  strcpy(sockaddr.sun_path, argv[0]);
  n = strlen(sockaddr.sun_path) + sizeof(sockaddr.sun_family);
  if (connect(sock, (struct sockaddr *) &sockaddr, n) < 0) {
if (test == 0)
  perror("connect");
return EXIT_FAILURE;
  }

  getprompt(sock, -1, EXIT_FAILURE);
  if (test == 0) {
write(sock, argv[1], strlen(argv[1]));
write(sock, "\n", 1);
if (wait)
  /* always discard first line because of command echo */
  getprompt(sock, quiet ? -1 : 1, EXIT_SUCCESS);
  }
  return EXIT_SUCCESS;
}