Coverity: in daemon, free struct in RStruct, RStructList functions.
[libguestfs.git] / daemon / parted.c
index 2f928b0..2b70fdd 100644 (file)
@@ -1,5 +1,5 @@
 /* libguestfs - the guestfsd daemon
- * Copyright (C) 2009 Red Hat Inc.
+ * Copyright (C) 2009-2011 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
@@ -178,27 +178,21 @@ do_part_del (const char *device, int partnum)
 int
 do_part_disk (const char *device, const char *parttype)
 {
-  const char *startstr;
-  const char *endstr;
-
   parttype = check_parttype (parttype);
   if (!parttype) {
     reply_with_error ("unknown partition type: common choices are \"gpt\" and \"msdos\"");
     return -1;
   }
 
-  /* Voooooodooooooooo (thanks Jim Meyering for working this out). */
-  if (STREQ (parttype, "msdos")) {
-    startstr = "1s";
-    endstr = "-1s";
-  } else if (STREQ (parttype, "gpt")) {
-    startstr = "34s";
-    endstr = "-34s";
-  } else {
-    /* untested */
-    startstr = "1s";
-    endstr = "-1s";
-  }
+  /* Align all partitions created this way to 64 sectors, and leave
+   * the last 64 sectors at the end of the disk free.  This wastes
+   * 32K+32K = 64K on 512-byte sector disks.  The rationale is:
+   *
+   * - aligned operations are faster
+   * - GPT requires at least 34 sectors at the end of the disk.
+   */
+  const char *startstr = "64s";
+  const char *endstr = "-64s";
 
   RUN_PARTED (return -1,
               device,
@@ -293,21 +287,21 @@ test_parted_m_opt (void)
   if (result >= 0)
     return result;
 
-  if (verbose)
-    fprintf (stderr, "Testing if this parted supports '-m' option.\n");
-
   char *err = NULL;
   int r = commandr (NULL, &err, "parted", "-s", "-m", "/dev/null", NULL);
   if (r == -1) {
     /* Test failed, eg. missing or completely unusable parted binary. */
     reply_with_error ("could not run 'parted' command");
+    free (err);
     return -1;
   }
 
   if (err && strstr (err, "invalid option -- m"))
-    return result = 0;
-
-  return result = 1;
+    result = 0;
+  else
+    result = 1;
+  free (err);
+  return result;
 }
 
 static char *
@@ -334,9 +328,6 @@ print_partition_table (const char *device, int parted_has_m_opt)
   }
   free (err);
 
-  if (verbose)
-    fprintf (stderr, "parted output:\n%s<END>\n", out);
-
   return out;
 }
 
@@ -384,6 +375,14 @@ do_part_get_parttype (const char *device)
     }
 
     free_strings (lines);
+
+    /* If "loop" return an error (RHBZ#634246). */
+    if (STREQ (r, "loop")) {
+      free (r);
+      reply_with_error ("not a partitioned device");
+      return NULL;
+    }
+
     return r;
   }
   else {
@@ -412,6 +411,13 @@ do_part_get_parttype (const char *device)
       return NULL;
     }
 
+    /* If "loop" return an error (RHBZ#634246). */
+    if (STREQ (p, "loop")) {
+      free (p);
+      reply_with_error ("not a partitioned device");
+      return NULL;
+    }
+
     return p;                   /* caller frees */
   }
 }
@@ -567,15 +573,41 @@ do_part_get_bootable (const char *device, int partnum)
     /* New-style parsing using the "machine-readable" format from
      * 'parted -m'.
      *
-     * We want lines[1+partnum].
+     * Partitions may not be in any order, so we have to look for
+     * the matching partition number (RHBZ#602997).
      */
-    if (count_strings (lines) < (size_t) 1+partnum) {
-      reply_with_error ("partition number out of range: %d", partnum);
+    if (lines[0] == NULL || STRNEQ (lines[0], "BYT;")) {
+      reply_with_error ("unknown signature, expected \"BYT;\" as first line of the output: %s",
+                        lines[0] ? lines[0] : "(signature was null)");
+      free_strings (lines);
+      return -1;
+    }
+
+    if (lines[1] == NULL) {
+      reply_with_error ("parted didn't return a line describing the device");
+      free_strings (lines);
+      return -1;
+    }
+
+    size_t row;
+    int pnum;
+    for (row = 2; lines[row] != NULL; ++row) {
+      if (sscanf (lines[row], "%d:", &pnum) != 1) {
+        reply_with_error ("could not parse row from output of parted print command: %s", lines[row]);
+        free_strings (lines);
+        return -1;
+      }
+      if (pnum == partnum)
+        break;
+    }
+
+    if (lines[row] == NULL) {
+      reply_with_error ("partition number %d not found", partnum);
       free_strings (lines);
       return -1;
     }
 
-    char *boot = get_table_field (lines[1+partnum], 6);
+    char *boot = get_table_field (lines[row], 6);
     if (boot == NULL) {
       free_strings (lines);
       return -1;