daemon: debug segv correct use of dereferencing NULL.
[libguestfs.git] / daemon / guestfsd.c
index 3632889..38cfd1a 100644 (file)
@@ -13,7 +13,7 @@
  *
  * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
 #include <config.h>
@@ -103,7 +103,7 @@ winsock_init (void)
 
 /* Location to mount root device. */
 const char *sysroot = "/sysroot"; /* No trailing slash. */
-int sysroot_len = 8;
+size_t sysroot_len = 8;
 
 /* If set (the default), do 'umount-all' when performing autosync. */
 int autosync_umount = 1;
@@ -111,6 +111,9 @@ int autosync_umount = 1;
 /* Not used explicitly, but required by the gnulib 'error' module. */
 const char *program_name = "guestfsd";
 
+/* Name of the virtio-serial channel. */
+#define VIRTIO_SERIAL_CHANNEL "/dev/virtio-ports/org.libguestfs.channel.0"
+
 static void
 usage (void)
 {
@@ -236,9 +239,13 @@ main (int argc, char *argv[])
   _umask (0);
 #endif
 
+  /* Make a private copy of /etc/lvm so we can change the config (see
+   * daemon/lvm-filter.c).
+   */
+  copy_lvm ();
+
   /* Connect to virtio-serial channel. */
-  int sock = open ("/dev/virtio-ports/org.libguestfs.channel.0",
-                   O_RDWR | O_CLOEXEC);
+  int sock = open (VIRTIO_SERIAL_CHANNEL, O_RDWR | O_CLOEXEC);
   if (sock == -1) {
     fprintf (stderr,
              "\n"
@@ -253,7 +260,7 @@ main (int argc, char *argv[])
              "output to the libguestfs developers, either in a bug report\n"
              "or on the libguestfs redhat com mailing list.\n"
              "\n");
-    perror ("/dev/virtio-ports/org.libguestfs.channel.0");
+    perror (VIRTIO_SERIAL_CHANNEL);
     exit (EXIT_FAILURE);
   }
 
@@ -408,10 +415,9 @@ xread (int sock, void *v_buf, size_t len)
 }
 
 int
-add_string (char ***argv, int *size, int *alloc, const char *str)
+add_string_nodup (char ***argv, int *size, int *alloc, char *str)
 {
   char **new_argv;
-  char *new_str;
 
   if (*size >= *alloc) {
     *alloc += 64;
@@ -419,24 +425,36 @@ add_string (char ***argv, int *size, int *alloc, const char *str)
     if (new_argv == NULL) {
       reply_with_perror ("realloc");
       free_strings (*argv);
+      *argv = NULL;
       return -1;
     }
     *argv = new_argv;
   }
 
+  (*argv)[*size] = str;
+
+  (*size)++;
+  return 0;
+}
+
+int
+add_string (char ***argv, int *size, int *alloc, const char *str)
+{
+  char *new_str;
+
   if (str) {
     new_str = strdup (str);
     if (new_str == NULL) {
       reply_with_perror ("strdup");
       free_strings (*argv);
+      *argv = NULL;
+      return -1;
     }
-  } else
+  } else {
     new_str = NULL;
+  }
 
-  (*argv)[*size] = new_str;
-
-  (*size)++;
-  return 0;
+  return add_string_nodup (argv, size, alloc, new_str);
 }
 
 size_t
@@ -679,6 +697,7 @@ commandrvf (char **stdoutput, char **stderror, int flags,
   }
 
   if (pid == 0) {              /* Child process running the command. */
+    signal (SIGALRM, SIG_DFL);
     signal (SIGPIPE, SIG_DFL);
     close (0);
     if (flag_copy_stdin) {
@@ -687,7 +706,7 @@ commandrvf (char **stdoutput, char **stderror, int flags,
       close (stdin_fd[1]);
     } else {
       /* Set stdin to /dev/null (ignore failure) */
-      open ("/dev/null", O_RDONLY);
+      ignore_value (open ("/dev/null", O_RDONLY));
     }
     close (so_fd[0]);
     close (se_fd[0]);
@@ -768,13 +787,29 @@ commandrvf (char **stdoutput, char **stderror, int flags,
 
   quit = 0;
   while (quit < 2) {
+  again:
     rset2 = rset;
     r = select (MAX (so_fd[0], se_fd[0]) + 1, &rset2, NULL, NULL, NULL);
     if (r == -1) {
+      if (errno == EINTR)
+        goto again;
+
       perror ("select");
     quit:
-      if (stdoutput) free (*stdoutput);
-      if (stderror) free (*stderror);
+      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[0]);
       close (se_fd[0]);
       waitpid (pid, NULL, 0);