X-Git-Url: http://git.annexia.org/?p=libguestfs.git;a=blobdiff_plain;f=daemon%2Fguestfsd.c;h=2553ea2cd3046aae2828f886a1011aac2e7ebeb4;hp=c27d1b6e12082781e4e7b322a88f8a17775bb66f;hb=170f262f0413de843af62b968f6d12c1c476ae7f;hpb=15dbb6973a7af11b81df047194228ea86d46939b diff --git a/daemon/guestfsd.c b/daemon/guestfsd.c index c27d1b6..2553ea2 100644 --- a/daemon/guestfsd.c +++ b/daemon/guestfsd.c @@ -18,6 +18,8 @@ #include +#define _BSD_SOURCE /* for daemon(3) */ + #include #include #include @@ -26,14 +28,21 @@ #include #include #include +#include +#include +#include +#include + +#include "daemon.h" -static void xwrite (int sock, const void *buf, size_t len); static void usage (void); /* Also in guestfs.c */ #define VMCHANNEL_PORT "6666" #define VMCHANNEL_ADDR "10.0.2.4" +int verbose = 0; + int main (int argc, char *argv[]) { @@ -56,7 +65,7 @@ main (int argc, char *argv[]) struct addrinfo *res, *rr; struct addrinfo hints; XDR xdr; - unsigned len; + uint32_t len; for (;;) { c = getopt_long (argc, argv, options, long_options, NULL); @@ -101,6 +110,14 @@ main (int argc, char *argv[]) fclose (fp); buf[n] = '\0'; + /* Set the verbose flag. Not quite right because this will only + * set the flag if host and port aren't set on the command line. + * Don't worry about this for now. (XXX) + */ + verbose = strstr (buf, "guestfs_verbose=1") != NULL; + if (verbose) + printf ("verbose daemon enabled\n"); + p = strstr (buf, "guestfs="); if (p) { @@ -156,33 +173,32 @@ main (int argc, char *argv[]) /* Send the magic length message which indicates that * userspace is up inside the guest. */ - len = 0xf5f55ff5; + len = GUESTFS_LAUNCH_FLAG; xdrmem_create (&xdr, buf, sizeof buf, XDR_ENCODE); if (!xdr_uint32_t (&xdr, &len)) { fprintf (stderr, "xdr_uint32_t failed\n"); exit (1); } - xwrite (sock, buf, xdr_getpos (&xdr)); + (void) xwrite (sock, buf, xdr_getpos (&xdr)); xdr_destroy (&xdr); - /* XXX Fork into the background. */ - - - - - - - - + /* Fork into the background. */ + if (!dont_fork) { + if (daemon (0, 1) == -1) { + perror ("daemon"); + exit (1); + } + } - sleep (1000000); + /* Enter the main loop, reading and performing actions. */ + main_loop (sock); exit (0); } -static void +int xwrite (int sock, const void *buf, size_t len) { int r; @@ -191,11 +207,35 @@ xwrite (int sock, const void *buf, size_t len) r = write (sock, buf, len); if (r == -1) { perror ("write"); - exit (1); + return -1; + } + buf += r; + len -= r; + } + + return 0; +} + +int +xread (int sock, void *buf, size_t len) +{ + int r; + + while (len > 0) { + r = read (sock, buf, len); + if (r == -1) { + perror ("read"); + return -1; + } + if (r == 0) { + fprintf (stderr, "read: unexpected end of file on fd %d\n", sock); + return -1; } buf += r; len -= r; } + + return 0; } static void @@ -203,3 +243,257 @@ usage (void) { fprintf (stderr, "guestfsd [-f] [-h host -p port]\n"); } + +int +add_string (char ***argv, int *size, int *alloc, const char *str) +{ + char **new_argv; + char *new_str; + + if (*size >= *alloc) { + *alloc += 64; + new_argv = realloc (*argv, *alloc * sizeof (char *)); + if (new_argv == NULL) { + reply_with_perror ("realloc"); + free_strings (*argv); + return -1; + } + *argv = new_argv; + } + + if (str) { + new_str = strdup (str); + if (new_str == NULL) { + reply_with_perror ("strdup"); + free_strings (*argv); + } + } else + new_str = NULL; + + (*argv)[*size] = new_str; + + (*size)++; + return 0; +} + +int +count_strings (char * const* const argv) +{ + int argc; + + for (argc = 0; argv[argc] != NULL; ++argc) + ; + return argc; +} + +static int +compare (const void *vp1, const void *vp2) +{ + char * const *p1 = (char * const *) vp1; + char * const *p2 = (char * const *) vp2; + return strcmp (*p1, *p2); +} + +void +sort_strings (char **argv, int len) +{ + qsort (argv, len, sizeof (char *), compare); +} + +void +free_strings (char **argv) +{ + int argc; + + for (argc = 0; argv[argc] != NULL; ++argc) + free (argv[argc]); + free (argv); +} + +void +free_stringslen (char **argv, int len) +{ + int i; + + for (i = 0; i < len; ++i) + free (argv[i]); + free (argv); +} + +/* This is a more sane version of 'system(3)' for running external + * commands. It uses fork/execvp, so we don't need to worry about + * quoting of parameters, and it allows us to capture any error + * messages in a buffer. + */ +int +command (char **stdoutput, char **stderror, const char *name, ...) +{ + va_list args; + char **argv; + char *s; + int i, r; + + /* Collect the command line arguments into an array. */ + va_start (args, name); + + i = 2; + argv = malloc (sizeof (char *) * i); + argv[0] = (char *) name; + argv[1] = NULL; + + while ((s = va_arg (args, char *)) != NULL) { + argv = realloc (argv, sizeof (char *) * (++i)); + argv[i-2] = s; + argv[i-1] = NULL; + } + + va_end (args); + + r = commandv (stdoutput, stderror, argv); + + /* NB: Mustn't free the strings which are on the stack. */ + free (argv); + + return r; +} + +int +commandv (char **stdoutput, char **stderror, char * const* const argv) +{ + int so_size = 0, se_size = 0; + int so_fd[2], se_fd[2]; + int pid, r, quit, i; + fd_set rset, rset2; + char buf[256]; + + if (stdoutput) *stdoutput = NULL; + if (stderror) *stderror = NULL; + + if (verbose) { + printf ("%s", argv[0]); + for (i = 1; argv[i] != NULL; ++i) + printf (" %s", argv[i]); + printf ("\n"); + } + + if (pipe (so_fd) == -1 || pipe (se_fd) == -1) { + perror ("pipe"); + return -1; + } + + pid = fork (); + if (pid == -1) { + perror ("fork"); + return -1; + } + + if (pid == 0) { /* Child process. */ + close (0); + close (so_fd[0]); + close (se_fd[0]); + dup2 (so_fd[1], 1); + dup2 (se_fd[1], 2); + close (so_fd[1]); + close (se_fd[1]); + + execvp (argv[0], argv); + perror (argv[0]); + _exit (1); + } + + /* Parent process. */ + close (so_fd[1]); + close (se_fd[1]); + + FD_ZERO (&rset); + FD_SET (so_fd[0], &rset); + FD_SET (se_fd[0], &rset); + + quit = 0; + while (quit < 2) { + rset2 = rset; + r = select (MAX (so_fd[0], se_fd[0]) + 1, &rset2, NULL, NULL, NULL); + if (r == -1) { + perror ("select"); + waitpid (pid, NULL, 0); + return -1; + } + + if (FD_ISSET (so_fd[0], &rset2)) { /* something on stdout */ + r = read (so_fd[0], buf, sizeof buf); + if (r == -1) { + perror ("read"); + waitpid (pid, NULL, 0); + return -1; + } + if (r == 0) { FD_CLR (so_fd[0], &rset); quit++; } + + if (r > 0 && stdoutput) { + so_size += r; + *stdoutput = realloc (*stdoutput, so_size); + if (*stdoutput == NULL) { + perror ("realloc"); + *stdoutput = NULL; + continue; + } + memcpy (*stdoutput + so_size - r, buf, r); + } + } + + if (FD_ISSET (se_fd[0], &rset2)) { /* something on stderr */ + r = read (se_fd[0], buf, sizeof buf); + if (r == -1) { + perror ("read"); + waitpid (pid, NULL, 0); + return -1; + } + if (r == 0) { FD_CLR (se_fd[0], &rset); quit++; } + + if (r > 0 && stderror) { + se_size += r; + *stderror = realloc (*stderror, se_size); + if (*stderror == NULL) { + perror ("realloc"); + *stderror = NULL; + continue; + } + memcpy (*stderror + se_size - r, buf, r); + } + } + } + + /* Make sure the output buffers are \0-terminated. Also remove any + * trailing \n characters from the error buffer (not from stdout). + */ + if (stdoutput) { + *stdoutput = realloc (*stdoutput, so_size+1); + if (*stdoutput == NULL) { + perror ("realloc"); + *stdoutput = NULL; + } else + (*stdoutput)[so_size] = '\0'; + } + if (stderror) { + *stderror = realloc (*stderror, se_size+1); + if (*stderror == NULL) { + perror ("realloc"); + *stderror = NULL; + } else { + (*stderror)[se_size] = '\0'; + se_size--; + while (se_size >= 0 && (*stderror)[se_size] == '\n') + (*stderror)[se_size--] = '\0'; + } + } + + /* Get the exit status of the command. */ + waitpid (pid, &r, 0); + + if (WIFEXITED (r)) { + if (WEXITSTATUS (r) == 0) + return 0; + else + return -1; + } else + return -1; +}