[Libguestfs] [PATCH] Add support for getting and setting GPT partition type GUIDs

Matthew Booth mbooth at redhat.com
Fri Dec 14 13:54:24 UTC 2012


New APIs:
  part_set_gpt_type
  part_get_gpt_type
---
 appliance/packagelist.in |   1 +
 daemon/parted.c          | 129 +++++++++++++++++++++++++++++++++++++++++++++++
 generator/actions.ml     |  30 +++++++++++
 generator/tests_c_api.ml |   7 +++
 generator/types.ml       |   5 ++
 src/MAX_PROC_NR          |   2 +-
 6 files changed, 173 insertions(+), 1 deletion(-)

diff --git a/appliance/packagelist.in b/appliance/packagelist.in
index 3ad343b..9b0cc09 100644
--- a/appliance/packagelist.in
+++ b/appliance/packagelist.in
@@ -111,6 +111,7 @@ dosfstools
 file
 findutils
 gawk
+gdisk
 grep
 gzip
 jfsutils
diff --git a/daemon/parted.c b/daemon/parted.c
index cc9a84b..01ae91c 100644
--- a/daemon/parted.c
+++ b/daemon/parted.c
@@ -30,6 +30,7 @@
 
 GUESTFSD_EXT_CMD(str_parted, parted);
 GUESTFSD_EXT_CMD(str_sfdisk, sfdisk);
+GUESTFSD_EXT_CMD(str_sgdisk, sgdisk);
 
 /* Notes:
  *
@@ -802,3 +803,131 @@ do_part_set_mbr_id (const char *device, int partnum, int idbyte)
 
   return 0;
 }
+
+int
+do_part_set_gpt_type(const char *device, int partnum, const char *guid)
+{
+  if (partnum <= 0) {
+    reply_with_error ("partition number must be >= 1");
+    return -1;
+  }
+
+  char *typecode = NULL;
+  if (asprintf (&typecode, "%i:%s", partnum, guid) == -1) {
+    reply_with_perror ("asprintf");
+    return -1;
+  }
+
+  char *err = NULL;
+  int r = command (NULL, &err, str_sgdisk, device, "-t", typecode, NULL);
+
+  if (r == -1) {
+    reply_with_error ("%s %s -t %s: %s", str_sgdisk, device, typecode, err);
+    free (typecode);
+    free (err);
+    return -1;
+  }
+  free (typecode);
+  free (err);
+
+  return 0;
+}
+
+char *
+do_part_get_gpt_type(const char *device, int partnum)
+{
+  if (partnum <= 0) {
+    reply_with_error ("partition number must be >= 1");
+    return NULL;
+  }
+
+  char *partnum_str = NULL;
+  if (asprintf (&partnum_str, "%i", partnum) == -1) {
+    reply_with_perror ("asprintf");
+    return NULL;
+  }
+
+  char *out = NULL, *err = NULL;
+  int r = command (&out, &err, str_sgdisk, device, "-i", partnum_str, NULL);
+
+  if (r == -1) {
+    reply_with_error ("%s %s -i %s: %s", str_sgdisk, device, partnum_str, err);
+    free (partnum_str);
+    free (out);
+    free (err);
+    return NULL;
+  }
+  free (partnum_str);
+  free (err);
+
+  if (verbose)
+    fprintf (stderr, "Output of %s %s -i %i:\n", str_sgdisk, device, partnum);
+
+  char **lines = split_lines (out);
+  if (lines == NULL) {
+    reply_with_error ("'%s %s -i %i' returned no output",
+                      str_sgdisk, device, partnum);
+    free (out);
+    return NULL;
+  }
+
+  /* Parse the output of sgdisk -i:
+   * Partition GUID code: 21686148-6449-6E6F-744E-656564454649 (BIOS boot partition)
+   * Partition unique GUID: 19AEC5FE-D63A-4A15-9D37-6FCBFB873DC0
+   * First sector: 2048 (at 1024.0 KiB)
+   * Last sector: 411647 (at 201.0 MiB)
+   * Partition size: 409600 sectors (200.0 MiB)
+   * Attribute flags: 0000000000000000
+   * Partition name: 'EFI System Partition'
+   */
+  for (char **i = lines; *i != NULL; i++) {
+    char *line = *i;
+
+    if (verbose) fprintf (stderr, "%s\n", line);
+
+    /* Skip blank lines */
+    if (line[0] == '\0') continue;
+
+    /* Split the line in 2 at the colon */
+    char *colon = strchr (line, ':');
+    if (colon) {
+#define SEARCH "Partition GUID code"
+      if (colon - line == strlen(SEARCH) &&
+          memcmp (line, SEARCH, strlen(SEARCH)) == 0)
+      {
+#undef SEARCH
+        /* The value starts after the colon */
+        char *value = colon + 1;
+
+        /* Skip any leading whitespace */
+        value += strspn (value, " \t");
+
+        /* The value contains only valid GUID characters */
+        size_t value_len = strspn (value, "-0123456789ABCDEF");
+fprintf(stderr, "%zi: %s\n", value_len, value);
+
+        char *ret = malloc (value_len + 1);
+        if (ret == NULL) {
+          reply_with_perror ("malloc");
+          return NULL;
+        }
+
+        memcpy (ret, value, value_len);
+        ret[value_len] = '\0';
+        free (out);
+        return ret;
+      }
+    } else {
+      /* Ignore lines with no colon. Log to stderr so it will show up in
+       * LIBGUESTFS_DEBUG. */
+      fprintf (stderr, "get-gpt-type: unexpected sgdisk output ignored: %s",
+               line);
+    }
+  }
+  free (out);
+
+  /* If we got here it means we didn't find the Partition GUID code */
+  reply_with_error ("sgdisk output did not contain Partition GUID code. "
+                    "See LIBGUESTFS_DEBUG output for more details");
+  return NULL;
+}
diff --git a/generator/actions.ml b/generator/actions.ml
index f78d851..d8ec323 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -10692,6 +10692,36 @@ not always, the name of a Windows drive, eg. C<E:>." };
 Return the list of partitions in the volume named C<volume> in the disk
 group with GUID <diskgroup>." };
 
+  { defaults with
+    name = "part_set_gpt_type";
+    style = RErr, [Device "device"; Int "partnum"; String "guid"], [];
+    proc_nr = Some 392;
+    tests = [];
+    shortdesc = "set the type GUID of a GPT partition";
+    longdesc = "\
+Set the type GUID of numbered GPT partition C<partnum> to C<guid>. Return an
+error if the partition table of C<device> isn't GPT, or if C<guid> is not a
+valid GUID.
+
+See L<http://en.wikipedia.org/wiki/GUID_Partition_Table#Partition_type_GUIDs>
+for a useful list of type GUIDs." };
+
+  { defaults with
+    name = "part_get_gpt_type";
+    style = RString "guid", [Device "device"; Int "partnum"], [];
+    proc_nr = Some 393;
+    tests = [
+      InitGPT, Always, TestOutput (
+        [["part_set_gpt_type"; "/dev/sda"; "1";
+          "01234567-89AB-CDEF-0123-456789ABCDEF"];
+         ["part_get_gpt_type"; "/dev/sda"; "1"]],
+         "01234567-89AB-CDEF-0123-456789ABCDEF");
+    ];
+    shortdesc = "get the type GUID of a GPT partition";
+    longdesc = "\
+Return the type GUID of numbered GPT partition C<partnum>. Return an error if
+the partition table of C<device> isn't GPT." };
+
 ]
 
 (* Non-API meta-commands available only in guestfish.
diff --git a/generator/tests_c_api.ml b/generator/tests_c_api.ml
index 116a8b0..2aa78df 100644
--- a/generator/tests_c_api.ml
+++ b/generator/tests_c_api.ml
@@ -442,6 +442,13 @@ and generate_one_test_body name i test_name init test =
           ["umount_all"];
           ["lvm_remove_all"];
           ["part_disk"; "/dev/sda"; "mbr"]]
+   | InitGPT ->
+       pr "  /* InitGPT for %s: create /dev/sda1 */\n" test_name;
+       List.iter (generate_test_command_call test_name)
+         [["blockdev_setrw"; "/dev/sda"];
+          ["umount_all"];
+          ["lvm_remove_all"];
+          ["part_disk"; "/dev/sda"; "gpt"]]
    | InitBasicFS ->
        pr "  /* InitBasicFS for %s: create ext2 on /dev/sda1 */\n" test_name;
        List.iter (generate_test_command_call test_name)
diff --git a/generator/types.ml b/generator/types.ml
index cff3c6d..a2e3307 100644
--- a/generator/types.ml
+++ b/generator/types.ml
@@ -332,6 +332,11 @@ and test_init =
      * Note: for testing filesystem operations, it is quicker to use
      * InitScratchFS
      *)
+  | InitGPT
+
+    (* Identical to InitPartition, except that the partition table is GPT
+     * instead of MBR.
+     *)
   | InitBasicFS
 
     (* /dev/sda:
diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR
index b570ddb..25685cf 100644
--- a/src/MAX_PROC_NR
+++ b/src/MAX_PROC_NR
@@ -1 +1 @@
-391
+393
-- 
1.7.11.7




More information about the Libguestfs mailing list