[Libguestfs] [PATCH] Add support for getting and setting GPT partition type GUIDs
Richard W.M. Jones
rjones at redhat.com
Fri Dec 14 16:14:28 UTC 2012
On Fri, Dec 14, 2012 at 03:53:27PM +0000, Matthew Booth wrote:
> New APIs:
> part_set_gpt_type
> part_get_gpt_type
> ---
> appliance/packagelist.in | 1 +
> daemon/parted.c | 125 +++++++++++++++++++++++++++++++++++++++++++++++
> generator/actions.ml | 31 ++++++++++++
> generator/tests_c_api.ml | 7 +++
> generator/types.ml | 5 ++
> src/MAX_PROC_NR | 2 +-
> 6 files changed, 170 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..5c080da 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,127 @@ 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 = commandf (NULL, &err, COMMAND_FLAG_FOLD_STDOUT_ON_STDERR,
> + 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 *err = NULL;
> + int r = commandf (NULL, &err, COMMAND_FLAG_FOLD_STDOUT_ON_STDERR,
> + 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 (err);
> + return NULL;
> + }
> + free (partnum_str);
> +
> + char **lines = split_lines (err);
> + if (lines == NULL) {
> + reply_with_error ("'%s %s -i %i' returned no output",
> + str_sgdisk, device, partnum);
> + free (err);
> + 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;
> +
> + /* 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");
> +
> + 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 (err);
> + return ret;
> + }
> + } else {
> + /* Ignore lines with no colon. Log to stderr so it will show up in
> + * LIBGUESTFS_DEBUG. */
> + if (verbose) {
> + fprintf (stderr, "get-gpt-type: unexpected sgdisk output ignored: %s\n",
> + line);
> + }
> + }
> + }
> + free (err);
> +
> + /* 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..9cdd369 100644
> --- a/generator/actions.ml
> +++ b/generator/actions.ml
> @@ -10692,6 +10692,37 @@ 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>. For MBR partitions,
> +return an appropriate GUID corresponding to the MBR type. Behaviour is undefined
> +for other partition types." };
> +
> ]
>
> (* 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..e6f56ec 100644
> --- a/generator/types.ml
> +++ b/generator/types.ml
> @@ -325,6 +325,11 @@ and test_init =
> *)
> | InitPartition
>
> + (* Identical to InitPartition, except that the partition table is GPT
> + * instead of MBR.
> + *)
> + | InitGPT
> +
> (* /dev/sda contains a single partition /dev/sda1, which is formatted
> * as ext2, empty [except for lost+found] and mounted on /.
> * No LVM.
> 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
ACK.
Rich.
--
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
virt-p2v converts physical machines to virtual machines. Boot with a
live CD or over the network (PXE) and turn machines into Xen guests.
http://et.redhat.com/~rjones/virt-p2v
More information about the Libguestfs
mailing list