Remove guestfs___print_timestamped_argv.
[libguestfs.git] / src / appliance.c
index 1740dfc..1df8c36 100644 (file)
@@ -1,5 +1,5 @@
 /* libguestfs
- * Copyright (C) 2010 Red Hat Inc.
+ * Copyright (C) 2010-2011 Red Hat Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -55,6 +55,7 @@ static int check_for_cached_appliance (guestfs_h *g, const char *supermin_path,
 static int build_supermin_appliance (guestfs_h *g, const char *supermin_path, const char *checksum, uid_t uid, char **kernel, char **initrd, char **appliance);
 static int hard_link_to_cached_appliance (guestfs_h *g, const char *cachedir, char **kernel, char **initrd, char **appliance);
 static int run_supermin_helper (guestfs_h *g, const char *supermin_path, const char *cachedir, size_t cdlen);
+static void print_febootstrap_command_line (guestfs_h *g, const char *argv[]);
 
 /* Locate or build the appliance.
  *
@@ -241,14 +242,14 @@ calculate_supermin_checksum (guestfs_h *g, const char *supermin_path)
   }
 
   if (pclose (pp) == -1) {
-    perror ("pclose");
+    warning (g, "pclose: %m");
     return NULL;
   }
 
   len = strlen (checksum);
 
   if (len < 16) {               /* sanity check */
-    fprintf (stderr, "libguestfs: internal error: febootstrap-supermin-helper -f checksum returned a short string\n");
+    warning (g, "febootstrap-supermin-helper -f checksum returned a short string");
     return NULL;
   }
 
@@ -308,7 +309,7 @@ check_for_cached_appliance (guestfs_h *g,
                             uid_t uid,
                             char **kernel, char **initrd, char **appliance)
 {
-  const char *tmpdir = guestfs_tmpdir ();
+  const char *tmpdir = guestfs___persistent_tmpdir ();
 
   /* len must be longer than the length of any pathname we can
    * generate in this function.
@@ -320,7 +321,6 @@ check_for_cached_appliance (guestfs_h *g,
   snprintf (filename, len, "%s/checksum", cachedir);
 
   (void) mkdir (cachedir, 0755);
-  (void) utime (cachedir, NULL);
 
   /* See if the cache directory exists and passes some simple checks
    * to make sure it has not been tampered with.
@@ -329,28 +329,34 @@ check_for_cached_appliance (guestfs_h *g,
   if (lstat (cachedir, &statbuf) == -1)
     return 0;
   if (statbuf.st_uid != uid) {
-    error (g, _("security: cached appliance %s is not owned by UID %d\n"),
+    error (g, _("security: cached appliance %s is not owned by UID %d"),
            filename, uid);
     return -1;
   }
   if (!S_ISDIR (statbuf.st_mode)) {
-    error (g, _("security: cached appliance %s is not a directory (mode %o)\n"),
+    error (g, _("security: cached appliance %s is not a directory (mode %o)"),
            filename, statbuf.st_mode);
     return -1;
   }
   if ((statbuf.st_mode & 0022) != 0) {
-    error (g, _("security: cached appliance %s is writable by group or other (mode %o)\n"),
+    error (g, _("security: cached appliance %s is writable by group or other (mode %o)"),
            cachedir, statbuf.st_mode);
     return -1;
   }
 
+  (void) utime (cachedir, NULL);
+
   garbage_collect_appliances (cachedir);
 
   /* Try to open and acquire a lock on the checksum file. */
   int fd = open (filename, O_RDONLY);
   if (fd == -1)
     return 0;
+#ifdef HAVE_FUTIMENS
   (void) futimens (fd, NULL);
+#else
+  (void) futimes (fd, NULL);
+#endif
   struct flock fl;
   fl.l_type = F_RDLCK;
   fl.l_whence = SEEK_SET;
@@ -418,7 +424,7 @@ build_supermin_appliance (guestfs_h *g,
   if (g->verbose)
     guestfs___print_timestamped_message (g, "begin building supermin appliance");
 
-  const char *tmpdir = guestfs_tmpdir ();
+  const char *tmpdir = guestfs___persistent_tmpdir ();
 
   /* len must be longer than the length of any pathname we can
    * generate in this function.
@@ -563,18 +569,23 @@ hard_link_to_cached_appliance (guestfs_h *g,
     perrorf (g, "link: %s %s", filename, *kernel);
     goto error;
   }
+  (void) lutimes (filename, NULL); /* lutimes because it's a symlink */
+
   snprintf (filename, len, "%s/initrd", cachedir);
   (void) unlink (*initrd);
   if (link (filename, *initrd) == -1) {
     perrorf (g, "link: %s %s", filename, *initrd);
     goto error;
   }
+  (void) utime (filename, NULL);
+
   snprintf (filename, len, "%s/root", cachedir);
   (void) unlink (*appliance);
   if (link (filename, *appliance) == -1) {
     perrorf (g, "link: %s %s", filename, *appliance);
     goto error;
   }
+  (void) utime (filename, NULL);
 
   return 0;
 
@@ -630,6 +641,9 @@ run_supermin_helper (guestfs_h *g, const char *supermin_path,
   argv[i++] = root;
   argv[i++] = NULL;
 
+  if (g->verbose)
+    print_febootstrap_command_line (g, argv);
+
   pid_t pid = fork ();
   if (pid == -1) {
     perrorf (g, "fork");
@@ -637,9 +651,6 @@ run_supermin_helper (guestfs_h *g, const char *supermin_path,
   }
 
   if (pid > 0) {                /* Parent. */
-    if (g->verbose)
-      guestfs___print_timestamped_argv (g, argv);
-
     int status;
     if (waitpid (pid, &status, 0) == -1) {
       perrorf (g, "waitpid");
@@ -664,6 +675,54 @@ run_supermin_helper (guestfs_h *g, const char *supermin_path,
   _exit (EXIT_FAILURE);
 }
 
+static void
+print_febootstrap_command_line (guestfs_h *g, const char *argv[])
+{
+  int i;
+  int needs_quote;
+  char *buf;
+  size_t len;
+
+  /* Calculate length of the buffer needed.  This is an overestimate. */
+  len = 0;
+  for (i = 0; argv[i] != NULL; ++i)
+    len += strlen (argv[i]) + 32;
+
+  buf = malloc (len);
+  if (buf == NULL) {
+    warning (g, "malloc: %m");
+    return;
+  }
+
+  len = 0;
+  for (i = 0; argv[i] != NULL; ++i) {
+    if (i > 0) {
+      strcpy (&buf[len], " ");
+      len++;
+    }
+
+    /* Does it need shell quoting?  This only deals with simple cases. */
+    needs_quote = strcspn (argv[i], " ") != strlen (argv[i]);
+
+    if (needs_quote) {
+      strcpy (&buf[len], "'");
+      len++;
+    }
+
+    strcpy (&buf[len], argv[i]);
+    len += strlen (argv[i]);
+
+    if (needs_quote) {
+      strcpy (&buf[len], "'");
+      len++;
+    }
+  }
+
+  guestfs___print_timestamped_message (g, "%s", buf);
+
+  free (buf);
+}
+
 /* Search elements of g->path, returning the first path element which
  * matches the predicate function 'pred'.
  *