[Libguestfs] [PATCH 2/6] daemon: Split out command() functions and CLEANUP_* macros into separate files.

Richard W.M. Jones rjones at redhat.com
Sat Dec 5 12:48:30 UTC 2015


Allows more sharing between the daemon and the inspection program.
---
 daemon/Makefile.am |   2 +
 daemon/cleanups.c  |  80 +++++++++++
 daemon/cleanups.h  |  47 +++++++
 daemon/command.c   | 383 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 daemon/command.h   |  40 ++++++
 daemon/daemon.h    |  46 +------
 daemon/guestfsd.c  | 342 -----------------------------------------------
 po/POTFILES        |   2 +
 8 files changed, 557 insertions(+), 385 deletions(-)
 create mode 100644 daemon/cleanups.c
 create mode 100644 daemon/cleanups.h
 create mode 100644 daemon/command.c
 create mode 100644 daemon/command.h

diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index c1a33e3..a4e3df7 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -96,6 +96,8 @@ guestfsd_SOURCES = \
 	cap.c \
 	checksum.c \
 	cmp.c \
+	command.c \
+	command.h \
 	compress.c \
 	copy.c \
 	cpio.c \
diff --git a/daemon/cleanups.c b/daemon/cleanups.c
new file mode 100644
index 0000000..5293ff2
--- /dev/null
+++ b/daemon/cleanups.c
@@ -0,0 +1,80 @@
+/* libguestfs - the guestfsd daemon
+ * Copyright (C) 2009-2015 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <augeas.h>
+
+#include "cleanups.h"
+
+/* Use by the CLEANUP_* macros.  Do not call these directly. */
+void
+cleanup_free (void *ptr)
+{
+  free (* (void **) ptr);
+}
+
+extern void free_strings (char **argv);
+
+void
+cleanup_free_string_list (void *ptr)
+{
+  free_strings (* (char ***) ptr);
+}
+
+void
+cleanup_unlink_free (void *ptr)
+{
+  char *filename = * (char **) ptr;
+
+  if (filename) {
+    unlink (filename);
+    free (filename);
+  }
+}
+
+void
+cleanup_close (void *ptr)
+{
+  int fd = * (int *) ptr;
+
+  if (fd >= 0)
+    close (fd);
+}
+
+void
+cleanup_aug_close (void *ptr)
+{
+  augeas *aug = * (augeas **) ptr;
+
+  if (aug != NULL)
+    aug_close (aug);
+}
+
+struct stringsbuf;
+extern void free_stringsbuf (struct stringsbuf *sb);
+
+void
+cleanup_free_stringsbuf (void *ptr)
+{
+  free_stringsbuf ((struct stringsbuf *) ptr);
+}
diff --git a/daemon/cleanups.h b/daemon/cleanups.h
new file mode 100644
index 0000000..b6ef2ff
--- /dev/null
+++ b/daemon/cleanups.h
@@ -0,0 +1,47 @@
+/* libguestfs - the guestfsd daemon
+ * Copyright (C) 2009-2015 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef GUESTFSD_CLEANUPS_H
+#define GUESTFSD_CLEANUPS_H
+
+/* Use by the CLEANUP_* macros. */
+extern void cleanup_free (void *ptr);
+extern void cleanup_free_string_list (void *ptr);
+extern void cleanup_unlink_free (void *ptr);
+extern void cleanup_close (void *ptr);
+extern void cleanup_aug_close (void *ptr);
+extern void cleanup_free_stringsbuf (void *ptr);
+
+#ifdef HAVE_ATTRIBUTE_CLEANUP
+#define CLEANUP_FREE __attribute__((cleanup(cleanup_free)))
+#define CLEANUP_FREE_STRING_LIST                        \
+    __attribute__((cleanup(cleanup_free_string_list)))
+#define CLEANUP_UNLINK_FREE __attribute__((cleanup(cleanup_unlink_free)))
+#define CLEANUP_CLOSE __attribute__((cleanup(cleanup_close)))
+#define CLEANUP_AUG_CLOSE __attribute__((cleanup(cleanup_aug_close)))
+#define CLEANUP_FREE_STRINGSBUF __attribute__((cleanup(cleanup_free_stringsbuf)))
+#else
+#define CLEANUP_FREE
+#define CLEANUP_FREE_STRING_LIST
+#define CLEANUP_UNLINK_FREE
+#define CLEANUP_CLOSE
+#define CLEANUP_AUG_CLOSE
+#define CLEANUP_FREE_STRINGSBUF
+#endif
+
+#endif /* GUESTFSD_CLEANUPS_H */
diff --git a/daemon/command.c b/daemon/command.c
new file mode 100644
index 0000000..fd46175
--- /dev/null
+++ b/daemon/command.c
@@ -0,0 +1,383 @@
+/* libguestfs - the guestfsd daemon
+ * Copyright (C) 2009-2015 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <error.h>
+#include <errno.h>
+
+#include "ignore-value.h"
+
+#include "command.h"
+#include "cleanups.h"
+
+extern int verbose;
+
+#ifndef MAX
+# define MAX(a,b) ((a)>(b)?(a):(b))
+#endif
+
+/* For improved readability dealing with pipe arrays */
+#define PIPE_READ 0
+#define PIPE_WRITE 1
+
+/* Easy ways to run external commands.  For full documentation, see
+ * 'commandrvf' below.
+ */
+int
+commandf (char **stdoutput, char **stderror, int flags, const char *name, ...)
+{
+  va_list args;
+  /* NB: Mustn't free the strings which are on the stack. */
+  CLEANUP_FREE const char **argv = NULL;
+  char *s;
+  size_t i;
+  int r;
+
+  /* Collect the command line arguments into an array. */
+  i = 2;
+  argv = malloc (sizeof (char *) * i);
+  if (argv == NULL) {
+    perror ("malloc");
+    return -1;
+  }
+  argv[0] = (char *) name;
+  argv[1] = NULL;
+
+  va_start (args, name);
+
+  while ((s = va_arg (args, char *)) != NULL) {
+    const char **p = realloc (argv, sizeof (char *) * (++i));
+    if (p == NULL) {
+      perror ("realloc");
+      va_end (args);
+      return -1;
+    }
+    argv = p;
+    argv[i-2] = s;
+    argv[i-1] = NULL;
+  }
+
+  va_end (args);
+
+  r = commandvf (stdoutput, stderror, flags, (const char * const*) argv);
+
+  return r;
+}
+
+/* Same as 'command', but we allow the status code from the
+ * subcommand to be non-zero, and return that status code.
+ * We still return -1 if there was some other error.
+ */
+int
+commandrf (char **stdoutput, char **stderror, int flags, const char *name, ...)
+{
+  va_list args;
+  CLEANUP_FREE const char **argv = NULL;
+  char *s;
+  int i, r;
+
+  /* Collect the command line arguments into an array. */
+  i = 2;
+  argv = malloc (sizeof (char *) * i);
+  if (argv == NULL) {
+    perror ("malloc");
+    return -1;
+  }
+  argv[0] = (char *) name;
+  argv[1] = NULL;
+
+  va_start (args, name);
+
+  while ((s = va_arg (args, char *)) != NULL) {
+    const char **p = realloc (argv, sizeof (char *) * (++i));
+    if (p == NULL) {
+      perror ("realloc");
+      va_end (args);
+      return -1;
+    }
+    argv = p;
+    argv[i-2] = s;
+    argv[i-1] = NULL;
+  }
+
+  va_end (args);
+
+  r = commandrvf (stdoutput, stderror, flags, argv);
+
+  return r;
+}
+
+/* Same as 'command', but passing an argv. */
+int
+commandvf (char **stdoutput, char **stderror, int flags,
+           char const *const *argv)
+{
+  int r;
+
+  r = commandrvf (stdoutput, stderror, flags, (void *) argv);
+  if (r == 0)
+    return 0;
+  else
+    return -1;
+}
+
+/* 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.
+ *
+ * If stdoutput is not NULL, then *stdoutput will return the stdout
+ * of the command.
+ *
+ * If stderror is not NULL, then *stderror will return the stderr
+ * of the command.  If there is a final \n character, it is removed
+ * so you can use the error string directly in a call to
+ * reply_with_error.
+ *
+ * Flags:
+ *
+ * COMMAND_FLAG_FOLD_STDOUT_ON_STDERR: For broken external commands
+ * that send error messages to stdout (hello, parted) but that don't
+ * have any useful stdout information, use this flag to capture the
+ * error messages in the *stderror buffer.  If using this flag,
+ * you should pass stdoutput as NULL because nothing could ever be
+ * captured in that buffer.
+ *
+ * COMMAND_FLAG_CHROOT_COPY_FILE_TO_STDIN: For running external
+ * commands on chrooted files correctly (see RHBZ#579608) specifying
+ * this flag causes another process to be forked which chroots into
+ * sysroot and just copies the input file to stdin of the specified
+ * command.  The file descriptor is ORed with the flags, and that file
+ * descriptor is always closed by this function.  See hexdump.c for an
+ * example of usage.
+ */
+int
+commandrvf (char **stdoutput, char **stderror, int flags,
+            char const* const *argv)
+{
+  size_t so_size = 0, se_size = 0;
+  int so_fd[2], se_fd[2];
+  int flag_copy_stdin = flags & COMMAND_FLAG_CHROOT_COPY_FILE_TO_STDIN;
+  int flag_copy_fd = flags & COMMAND_FLAG_FD_MASK;
+  pid_t pid;
+  int r, quit, i;
+  fd_set rset, rset2;
+  char buf[256];
+  char *p;
+
+  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");
+  }
+
+  /* Note: abort is used in a few places along the error paths early
+   * in this function.  This is because (a) cleaning up correctly is
+   * very complex at these places and (b) abort is used when a
+   * resource problems is indicated which would be due to much more
+   * serious issues - eg. memory or file descriptor leaks.  We
+   * wouldn't expect fork(2) or pipe(2) to fail in normal
+   * circumstances.
+   */
+
+  if (pipe (so_fd) == -1 || pipe (se_fd) == -1) {
+    error (0, errno, "pipe");
+    abort ();
+  }
+
+  pid = fork ();
+  if (pid == -1) {
+    error (0, errno, "fork");
+    abort ();
+  }
+
+  if (pid == 0) {		/* Child process running the command. */
+    signal (SIGALRM, SIG_DFL);
+    signal (SIGPIPE, SIG_DFL);
+    close (0);
+    if (flag_copy_stdin) {
+      dup2 (flag_copy_fd, STDIN_FILENO);
+    } else {
+      /* Set stdin to /dev/null (ignore failure) */
+      ignore_value (open ("/dev/null", O_RDONLY|O_CLOEXEC));
+    }
+    close (so_fd[PIPE_READ]);
+    close (se_fd[PIPE_READ]);
+    if (!(flags & COMMAND_FLAG_FOLD_STDOUT_ON_STDERR))
+      dup2 (so_fd[PIPE_WRITE], STDOUT_FILENO);
+    else
+      dup2 (se_fd[PIPE_WRITE], STDOUT_FILENO);
+    dup2 (se_fd[PIPE_WRITE], STDERR_FILENO);
+    close (so_fd[PIPE_WRITE]);
+    close (se_fd[PIPE_WRITE]);
+
+    ignore_value (chdir ("/"));
+
+    execvp (argv[0], (void *) argv);
+    perror (argv[0]);
+    _exit (EXIT_FAILURE);
+  }
+
+  /* Parent process. */
+  close (so_fd[PIPE_WRITE]);
+  close (se_fd[PIPE_WRITE]);
+
+  FD_ZERO (&rset);
+  FD_SET (so_fd[PIPE_READ], &rset);
+  FD_SET (se_fd[PIPE_READ], &rset);
+
+  quit = 0;
+  while (quit < 2) {
+  again:
+    rset2 = rset;
+    r = select (MAX (so_fd[PIPE_READ], se_fd[PIPE_READ]) + 1, &rset2,
+                NULL, NULL, NULL);
+    if (r == -1) {
+      if (errno == EINTR)
+        goto again;
+
+      perror ("select");
+    quit:
+      if (stdoutput) {
+        free (*stdoutput);
+        *stdoutput = NULL;
+      }
+      if (stderror) {
+        free (*stderror);
+        /* Need to return non-NULL *stderror here since most callers
+         * will try to print and then free the err string.
+         * Unfortunately recovery from strdup failure here is not
+         * possible.
+         */
+        *stderror = strdup ("error running external command, "
+                            "see debug output for details");
+      }
+      close (so_fd[PIPE_READ]);
+      close (se_fd[PIPE_READ]);
+      if (flag_copy_stdin) close (flag_copy_fd);
+      waitpid (pid, NULL, 0);
+      return -1;
+    }
+
+    if (FD_ISSET (so_fd[PIPE_READ], &rset2)) { /* something on stdout */
+      r = read (so_fd[PIPE_READ], buf, sizeof buf);
+      if (r == -1) {
+        perror ("read");
+        goto quit;
+      }
+      if (r == 0) { FD_CLR (so_fd[PIPE_READ], &rset); quit++; }
+
+      if (r > 0 && stdoutput) {
+        so_size += r;
+        p = realloc (*stdoutput, so_size);
+        if (p == NULL) {
+          perror ("realloc");
+          goto quit;
+        }
+        *stdoutput = p;
+        memcpy (*stdoutput + so_size - r, buf, r);
+      }
+    }
+
+    if (FD_ISSET (se_fd[PIPE_READ], &rset2)) { /* something on stderr */
+      r = read (se_fd[PIPE_READ], buf, sizeof buf);
+      if (r == -1) {
+        perror ("read");
+        goto quit;
+      }
+      if (r == 0) { FD_CLR (se_fd[PIPE_READ], &rset); quit++; }
+
+      if (r > 0) {
+        if (verbose)
+          ignore_value (write (STDERR_FILENO, buf, r));
+
+        if (stderror) {
+          se_size += r;
+          p = realloc (*stderror, se_size);
+          if (p == NULL) {
+            perror ("realloc");
+            goto quit;
+          }
+          *stderror = p;
+          memcpy (*stderror + se_size - r, buf, r);
+        }
+      }
+    }
+  }
+
+  close (so_fd[PIPE_READ]);
+  close (se_fd[PIPE_READ]);
+
+  /* Make sure the output buffers are \0-terminated.  Also remove any
+   * trailing \n characters from the error buffer (not from stdout).
+   */
+  if (stdoutput) {
+    void *q = realloc (*stdoutput, so_size+1);
+    if (q == NULL) {
+      perror ("realloc");
+      free (*stdoutput);
+    }
+    *stdoutput = q;
+    if (*stdoutput)
+      (*stdoutput)[so_size] = '\0';
+  }
+  if (stderror) {
+    void *q = realloc (*stderror, se_size+1);
+    if (q == NULL) {
+      perror ("realloc");
+      free (*stderror);
+    }
+    *stderror = q;
+    if (*stderror) {
+      (*stderror)[se_size] = '\0';
+      while (se_size > 0 && (*stderror)[se_size-1] == '\n') {
+        se_size--;
+        (*stderror)[se_size] = '\0';
+      }
+    }
+  }
+
+  if (flag_copy_stdin && close (flag_copy_fd) == -1) {
+    perror ("close");
+    return -1;
+  }
+
+  /* Get the exit status of the command. */
+  if (waitpid (pid, &r, 0) != pid) {
+    perror ("waitpid");
+    return -1;
+  }
+
+  if (WIFEXITED (r)) {
+    return WEXITSTATUS (r);
+  } else
+    return -1;
+}
diff --git a/daemon/command.h b/daemon/command.h
new file mode 100644
index 0000000..e935ae6
--- /dev/null
+++ b/daemon/command.h
@@ -0,0 +1,40 @@
+/* libguestfs - the guestfsd daemon
+ * Copyright (C) 2009-2015 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef GUESTFSD_COMMAND_H
+#define GUESTFSD_COMMAND_H
+
+#define command(out,err,name,...) commandf((out),(err),0,(name),__VA_ARGS__)
+#define commandr(out,err,name,...) commandrf((out),(err),0,(name),__VA_ARGS__)
+#define commandv(out,err,argv) commandvf((out),(err),0,(argv))
+#define commandrv(out,err,argv) commandrvf((out),(err),0,(argv))
+
+#define COMMAND_FLAG_FD_MASK                   (1024-1)
+#define COMMAND_FLAG_FOLD_STDOUT_ON_STDERR     1024
+#define COMMAND_FLAG_CHROOT_COPY_FILE_TO_STDIN 2048
+
+extern int commandf (char **stdoutput, char **stderror, int flags,
+                     const char *name, ...) __attribute__((sentinel));
+extern int commandrf (char **stdoutput, char **stderror, int flags,
+                      const char *name, ...) __attribute__((sentinel));
+extern int commandvf (char **stdoutput, char **stderror, int flags,
+                      char const *const *argv);
+extern int commandrvf (char **stdoutput, char **stderror, int flags,
+                       char const* const *argv);
+
+#endif /* GUESTFSD_COMMAND_H */
diff --git a/daemon/daemon.h b/daemon/daemon.h
index 7fbb2a2..7e454da 100644
--- a/daemon/daemon.h
+++ b/daemon/daemon.h
@@ -32,6 +32,9 @@
 
 #include "guestfs-internal-all.h"
 
+#include "cleanups.h"
+#include "command.h"
+
 /* Mountables */
 
 typedef struct {
@@ -117,27 +120,9 @@ extern char **split_lines (char *str);
 
 extern char **empty_list (void);
 
-#define command(out,err,name,...) commandf((out),(err),0,(name),__VA_ARGS__)
-#define commandr(out,err,name,...) commandrf((out),(err),0,(name),__VA_ARGS__)
-#define commandv(out,err,argv) commandvf((out),(err),0,(argv))
-#define commandrv(out,err,argv) commandrvf((out),(err),0,(argv))
-
 #define __external_command __attribute__((__section__(".guestfsd_ext_cmds")))
 #define GUESTFSD_EXT_CMD(___ext_cmd_var, ___ext_cmd_str) static const char ___ext_cmd_var[] __external_command = #___ext_cmd_str
 
-#define COMMAND_FLAG_FD_MASK                   (1024-1)
-#define COMMAND_FLAG_FOLD_STDOUT_ON_STDERR     1024
-#define COMMAND_FLAG_CHROOT_COPY_FILE_TO_STDIN 2048
-
-extern int commandf (char **stdoutput, char **stderror, int flags,
-                     const char *name, ...) __attribute__((sentinel));
-extern int commandrf (char **stdoutput, char **stderror, int flags,
-                      const char *name, ...) __attribute__((sentinel));
-extern int commandvf (char **stdoutput, char **stderror, int flags,
-                      char const *const *argv);
-extern int commandrvf (char **stdoutput, char **stderror, int flags,
-                       char const* const *argv);
-
 extern int is_power_of_2 (unsigned long v);
 
 extern void trim (char *str);
@@ -156,14 +141,6 @@ extern char *get_random_uuid (void);
 
 extern int asprintf_nowarn (char **strp, const char *fmt, ...);
 
-/* Use by the CLEANUP_* macros. */
-extern void cleanup_free (void *ptr);
-extern void cleanup_free_string_list (void *ptr);
-extern void cleanup_unlink_free (void *ptr);
-extern void cleanup_close (void *ptr);
-extern void cleanup_aug_close (void *ptr);
-extern void cleanup_free_stringsbuf (void *ptr);
-
 /*-- in names.c (auto-generated) --*/
 extern const char *function_names[];
 
@@ -451,21 +428,4 @@ is_zero (const char *buffer, size_t size)
     }                                                                   \
   } while (0)
 
-#ifdef HAVE_ATTRIBUTE_CLEANUP
-#define CLEANUP_FREE __attribute__((cleanup(cleanup_free)))
-#define CLEANUP_FREE_STRING_LIST                        \
-    __attribute__((cleanup(cleanup_free_string_list)))
-#define CLEANUP_UNLINK_FREE __attribute__((cleanup(cleanup_unlink_free)))
-#define CLEANUP_CLOSE __attribute__((cleanup(cleanup_close)))
-#define CLEANUP_AUG_CLOSE __attribute__((cleanup(cleanup_aug_close)))
-#define CLEANUP_FREE_STRINGSBUF __attribute__((cleanup(cleanup_free_stringsbuf)))
-#else
-#define CLEANUP_FREE
-#define CLEANUP_FREE_STRING_LIST
-#define CLEANUP_UNLINK_FREE
-#define CLEANUP_CLOSE
-#define CLEANUP_AUG_CLOSE
-#define CLEANUP_FREE_STRINGSBUF
-#endif
-
 #endif /* GUESTFSD_DAEMON_H */
diff --git a/daemon/guestfsd.c b/daemon/guestfsd.c
index 0a29aa6..a3e8868 100644
--- a/daemon/guestfsd.c
+++ b/daemon/guestfsd.c
@@ -68,10 +68,6 @@ GUESTFSD_EXT_CMD(str_uuidgen, uuidgen);
 # define O_CLOEXEC 0
 #endif
 
-/* For improved readability dealing with pipe arrays */
-#define PIPE_READ 0
-#define PIPE_WRITE 1
-
 /* If root device is an ext2 filesystem, this is the major and minor.
  * This is so we can ignore this device from the point of view of the
  * user, eg. in guestfs_list_devices and many other places.
@@ -752,344 +748,6 @@ join_strings (const char *separator, char *const *argv)
   return r;
 }
 
-/* Easy ways to run external commands.  For full documentation, see
- * 'commandrvf' below.
- */
-int
-commandf (char **stdoutput, char **stderror, int flags, const char *name, ...)
-{
-  va_list args;
-  /* NB: Mustn't free the strings which are on the stack. */
-  CLEANUP_FREE const char **argv = NULL;
-  char *s;
-  size_t i;
-  int r;
-
-  /* Collect the command line arguments into an array. */
-  i = 2;
-  argv = malloc (sizeof (char *) * i);
-  if (argv == NULL) {
-    perror ("malloc");
-    return -1;
-  }
-  argv[0] = (char *) name;
-  argv[1] = NULL;
-
-  va_start (args, name);
-
-  while ((s = va_arg (args, char *)) != NULL) {
-    const char **p = realloc (argv, sizeof (char *) * (++i));
-    if (p == NULL) {
-      perror ("realloc");
-      va_end (args);
-      return -1;
-    }
-    argv = p;
-    argv[i-2] = s;
-    argv[i-1] = NULL;
-  }
-
-  va_end (args);
-
-  r = commandvf (stdoutput, stderror, flags, (const char * const*) argv);
-
-  return r;
-}
-
-/* Same as 'command', but we allow the status code from the
- * subcommand to be non-zero, and return that status code.
- * We still return -1 if there was some other error.
- */
-int
-commandrf (char **stdoutput, char **stderror, int flags, const char *name, ...)
-{
-  va_list args;
-  CLEANUP_FREE const char **argv = NULL;
-  char *s;
-  int i, r;
-
-  /* Collect the command line arguments into an array. */
-  i = 2;
-  argv = malloc (sizeof (char *) * i);
-  if (argv == NULL) {
-    perror ("malloc");
-    return -1;
-  }
-  argv[0] = (char *) name;
-  argv[1] = NULL;
-
-  va_start (args, name);
-
-  while ((s = va_arg (args, char *)) != NULL) {
-    const char **p = realloc (argv, sizeof (char *) * (++i));
-    if (p == NULL) {
-      perror ("realloc");
-      va_end (args);
-      return -1;
-    }
-    argv = p;
-    argv[i-2] = s;
-    argv[i-1] = NULL;
-  }
-
-  va_end (args);
-
-  r = commandrvf (stdoutput, stderror, flags, argv);
-
-  return r;
-}
-
-/* Same as 'command', but passing an argv. */
-int
-commandvf (char **stdoutput, char **stderror, int flags,
-           char const *const *argv)
-{
-  int r;
-
-  r = commandrvf (stdoutput, stderror, flags, (void *) argv);
-  if (r == 0)
-    return 0;
-  else
-    return -1;
-}
-
-/* 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.
- *
- * If stdoutput is not NULL, then *stdoutput will return the stdout
- * of the command.
- *
- * If stderror is not NULL, then *stderror will return the stderr
- * of the command.  If there is a final \n character, it is removed
- * so you can use the error string directly in a call to
- * reply_with_error.
- *
- * Flags:
- *
- * COMMAND_FLAG_FOLD_STDOUT_ON_STDERR: For broken external commands
- * that send error messages to stdout (hello, parted) but that don't
- * have any useful stdout information, use this flag to capture the
- * error messages in the *stderror buffer.  If using this flag,
- * you should pass stdoutput as NULL because nothing could ever be
- * captured in that buffer.
- *
- * COMMAND_FLAG_CHROOT_COPY_FILE_TO_STDIN: For running external
- * commands on chrooted files correctly (see RHBZ#579608) specifying
- * this flag causes another process to be forked which chroots into
- * sysroot and just copies the input file to stdin of the specified
- * command.  The file descriptor is ORed with the flags, and that file
- * descriptor is always closed by this function.  See hexdump.c for an
- * example of usage.
- */
-int
-commandrvf (char **stdoutput, char **stderror, int flags,
-            char const* const *argv)
-{
-  size_t so_size = 0, se_size = 0;
-  int so_fd[2], se_fd[2];
-  int flag_copy_stdin = flags & COMMAND_FLAG_CHROOT_COPY_FILE_TO_STDIN;
-  int flag_copy_fd = flags & COMMAND_FLAG_FD_MASK;
-  pid_t pid;
-  int r, quit, i;
-  fd_set rset, rset2;
-  char buf[256];
-  char *p;
-
-  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");
-  }
-
-  /* Note: abort is used in a few places along the error paths early
-   * in this function.  This is because (a) cleaning up correctly is
-   * very complex at these places and (b) abort is used when a
-   * resource problems is indicated which would be due to much more
-   * serious issues - eg. memory or file descriptor leaks.  We
-   * wouldn't expect fork(2) or pipe(2) to fail in normal
-   * circumstances.
-   */
-
-  if (pipe (so_fd) == -1 || pipe (se_fd) == -1) {
-    error (0, errno, "pipe");
-    abort ();
-  }
-
-  pid = fork ();
-  if (pid == -1) {
-    error (0, errno, "fork");
-    abort ();
-  }
-
-  if (pid == 0) {		/* Child process running the command. */
-    signal (SIGALRM, SIG_DFL);
-    signal (SIGPIPE, SIG_DFL);
-    close (0);
-    if (flag_copy_stdin) {
-      dup2 (flag_copy_fd, STDIN_FILENO);
-    } else {
-      /* Set stdin to /dev/null (ignore failure) */
-      ignore_value (open ("/dev/null", O_RDONLY|O_CLOEXEC));
-    }
-    close (so_fd[PIPE_READ]);
-    close (se_fd[PIPE_READ]);
-    if (!(flags & COMMAND_FLAG_FOLD_STDOUT_ON_STDERR))
-      dup2 (so_fd[PIPE_WRITE], STDOUT_FILENO);
-    else
-      dup2 (se_fd[PIPE_WRITE], STDOUT_FILENO);
-    dup2 (se_fd[PIPE_WRITE], STDERR_FILENO);
-    close (so_fd[PIPE_WRITE]);
-    close (se_fd[PIPE_WRITE]);
-
-    ignore_value (chdir ("/"));
-
-    execvp (argv[0], (void *) argv);
-    perror (argv[0]);
-    _exit (EXIT_FAILURE);
-  }
-
-  /* Parent process. */
-  close (so_fd[PIPE_WRITE]);
-  close (se_fd[PIPE_WRITE]);
-
-  FD_ZERO (&rset);
-  FD_SET (so_fd[PIPE_READ], &rset);
-  FD_SET (se_fd[PIPE_READ], &rset);
-
-  quit = 0;
-  while (quit < 2) {
-  again:
-    rset2 = rset;
-    r = select (MAX (so_fd[PIPE_READ], se_fd[PIPE_READ]) + 1, &rset2,
-                NULL, NULL, NULL);
-    if (r == -1) {
-      if (errno == EINTR)
-        goto again;
-
-      perror ("select");
-    quit:
-      if (stdoutput) {
-        free (*stdoutput);
-        *stdoutput = NULL;
-      }
-      if (stderror) {
-        free (*stderror);
-        /* Need to return non-NULL *stderror here since most callers
-         * will try to print and then free the err string.
-         * Unfortunately recovery from strdup failure here is not
-         * possible.
-         */
-        *stderror = strdup ("error running external command, "
-                            "see debug output for details");
-      }
-      close (so_fd[PIPE_READ]);
-      close (se_fd[PIPE_READ]);
-      if (flag_copy_stdin) close (flag_copy_fd);
-      waitpid (pid, NULL, 0);
-      return -1;
-    }
-
-    if (FD_ISSET (so_fd[PIPE_READ], &rset2)) { /* something on stdout */
-      r = read (so_fd[PIPE_READ], buf, sizeof buf);
-      if (r == -1) {
-        perror ("read");
-        goto quit;
-      }
-      if (r == 0) { FD_CLR (so_fd[PIPE_READ], &rset); quit++; }
-
-      if (r > 0 && stdoutput) {
-        so_size += r;
-        p = realloc (*stdoutput, so_size);
-        if (p == NULL) {
-          perror ("realloc");
-          goto quit;
-        }
-        *stdoutput = p;
-        memcpy (*stdoutput + so_size - r, buf, r);
-      }
-    }
-
-    if (FD_ISSET (se_fd[PIPE_READ], &rset2)) { /* something on stderr */
-      r = read (se_fd[PIPE_READ], buf, sizeof buf);
-      if (r == -1) {
-        perror ("read");
-        goto quit;
-      }
-      if (r == 0) { FD_CLR (se_fd[PIPE_READ], &rset); quit++; }
-
-      if (r > 0) {
-        if (verbose)
-          ignore_value (write (STDERR_FILENO, buf, r));
-
-        if (stderror) {
-          se_size += r;
-          p = realloc (*stderror, se_size);
-          if (p == NULL) {
-            perror ("realloc");
-            goto quit;
-          }
-          *stderror = p;
-          memcpy (*stderror + se_size - r, buf, r);
-        }
-      }
-    }
-  }
-
-  close (so_fd[PIPE_READ]);
-  close (se_fd[PIPE_READ]);
-
-  /* Make sure the output buffers are \0-terminated.  Also remove any
-   * trailing \n characters from the error buffer (not from stdout).
-   */
-  if (stdoutput) {
-    void *q = realloc (*stdoutput, so_size+1);
-    if (q == NULL) {
-      perror ("realloc");
-      free (*stdoutput);
-    }
-    *stdoutput = q;
-    if (*stdoutput)
-      (*stdoutput)[so_size] = '\0';
-  }
-  if (stderror) {
-    void *q = realloc (*stderror, se_size+1);
-    if (q == NULL) {
-      perror ("realloc");
-      free (*stderror);
-    }
-    *stderror = q;
-    if (*stderror) {
-      (*stderror)[se_size] = '\0';
-      while (se_size > 0 && (*stderror)[se_size-1] == '\n') {
-        se_size--;
-        (*stderror)[se_size] = '\0';
-      }
-    }
-  }
-
-  if (flag_copy_stdin && close (flag_copy_fd) == -1) {
-    perror ("close");
-    return -1;
-  }
-
-  /* Get the exit status of the command. */
-  if (waitpid (pid, &r, 0) != pid) {
-    perror ("waitpid");
-    return -1;
-  }
-
-  if (WIFEXITED (r)) {
-    return WEXITSTATUS (r);
-  } else
-    return -1;
-}
-
 /* Split an output string into a NULL-terminated list of lines,
  * wrapped into a stringsbuf.
  * Typically this is used where we have run an external command
diff --git a/po/POTFILES b/po/POTFILES
index 9719afd..aca174d 100644
--- a/po/POTFILES
+++ b/po/POTFILES
@@ -25,7 +25,9 @@ daemon/blockdev.c
 daemon/btrfs.c
 daemon/cap.c
 daemon/checksum.c
+daemon/cleanups.c
 daemon/cmp.c
+daemon/command.c
 daemon/compress.c
 daemon/copy.c
 daemon/cpio.c
-- 
2.5.0




More information about the Libguestfs mailing list