From: Richard Jones Date: Wed, 4 Nov 2009 23:15:26 +0000 (+0000) Subject: Generic partition creation interface. X-Git-Tag: 1.0.78~10 X-Git-Url: http://git.annexia.org/?p=libguestfs.git;a=commitdiff_plain;h=b1e1ca2f74a921b3f784537d59c617df29ea1d60 Generic partition creation interface. This commit introduces a generic partition creation interface which should be future-proof and extensible, and partially replaces the old sfdisk-based interface. The implementation is based on parted but is hopefully not too dependent on the particulars of parted. The following new calls are introduced: guestfs_part_init: Initialize a disk with a partition table. Unlike the sfdisk- based interface, we also support GPT and other partition types, which is essential to scale to devices larger than 2TB. guestfs_part_add: Add a partition to an existing disk. guestfs_part_disk: Convenience function which combines part_init & part_add, creating a single partition that covers the whole disk. guestfs_part_set_bootable: guestfs_part_set_name: Set various aspects of existing partitions. guestfs_part_list: List partitions on a device. This returns a programming-friendly list of partition structs (in contrast to sfdisk-l which cannot be parsed). guestfs_part_get_parttype: Return the partition table type, eg. "msdos" or "gpt". The following calls are planned, but not added currently: guestfs_part_get_bootable guestfs_part_get_name guestfs_part_set_type guestfs_part_get_type --- diff --git a/.gitignore b/.gitignore index c365865..b3869c5 100644 --- a/.gitignore +++ b/.gitignore @@ -117,6 +117,7 @@ java/com/redhat/et/libguestfs/GuestFS.java java/com/redhat/et/libguestfs/INotifyEvent.java java/com/redhat/et/libguestfs/IntBool.java java/com/redhat/et/libguestfs/LV.java +java/com/redhat/et/libguestfs/Partition.java java/com/redhat/et/libguestfs/PV.java java/com/redhat/et/libguestfs/Stat.java java/com/redhat/et/libguestfs/StatVFS.java diff --git a/daemon/Makefile.am b/daemon/Makefile.am index db311ab..72e1896 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -60,6 +60,7 @@ guestfsd_SOURCES = \ mount.c \ names.c \ ntfs.c \ + parted.c \ pingdaemon.c \ proto.c \ readdir.c \ diff --git a/daemon/parted.c b/daemon/parted.c new file mode 100644 index 0000000..e0183fb --- /dev/null +++ b/daemon/parted.c @@ -0,0 +1,357 @@ +/* libguestfs - the guestfsd daemon + * Copyright (C) 2009 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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. + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include "daemon.h" +#include "actions.h" + +/* Notes: + * + * Parted 1.9 sends error messages to stdout, hence use of the + * COMMAND_FLAG_FOLD_STDOUT_ON_STDERR flag. + * + * parted occasionally fails to do ioctl(BLKRRPART) on the device, + * apparently because of some internal race in the code. We attempt + * to detect and recover from this error if we can. + */ +static int +recover_blkrrpart (const char *device, const char *err) +{ + int r; + + if (!strstr (err, + "Error informing the kernel about modifications to partition")) + return -1; + + r = command (NULL, NULL, "/sbin/blockdev", "--rereadpt", device, NULL); + if (r == -1) + return -1; + + udev_settle (); + + return 0; +} + +#define RUN_PARTED(device,...) \ + do { \ + int r; \ + char *err; \ + \ + r = commandf (NULL, &err, COMMAND_FLAG_FOLD_STDOUT_ON_STDERR, \ + "/sbin/parted", "-s", "--", (device), __VA_ARGS__); \ + if (r == -1) { \ + if (recover_blkrrpart ((device), err) == -1) { \ + reply_with_error ("%s: parted: %s: %s", __func__, (device), err); \ + free (err); \ + return -1; \ + } \ + } \ + \ + free (err); \ + } while (0) + +static const char * +check_parttype (const char *parttype) +{ + /* Check and translate parttype. */ + if (strcmp (parttype, "aix") == 0 || + strcmp (parttype, "amiga") == 0 || + strcmp (parttype, "bsd") == 0 || + strcmp (parttype, "dasd") == 0 || + strcmp (parttype, "dvh") == 0 || + strcmp (parttype, "gpt") == 0 || + strcmp (parttype, "mac") == 0 || + strcmp (parttype, "msdos") == 0 || + strcmp (parttype, "pc98") == 0 || + strcmp (parttype, "sun") == 0) + return parttype; + else if (strcmp (parttype, "rdb") == 0) + return "amiga"; + else if (strcmp (parttype, "efi") == 0) + return "gpt"; + else if (strcmp (parttype, "mbr") == 0) + return "msdos"; + else + return NULL; +} + +int +do_part_init (const char *device, const char *parttype) +{ + parttype = check_parttype (parttype); + if (!parttype) { + reply_with_error ("part-init: unknown partition type: common choices are \"gpt\" and \"msdos\""); + return -1; + } + + RUN_PARTED (device, "mklabel", parttype, NULL); + + udev_settle (); + + return 0; +} + +int +do_part_add (const char *device, const char *prlogex, + int64_t startsect, int64_t endsect) +{ + char startstr[32]; + char endstr[32]; + + /* Check and translate prlogex. */ + if (strcmp (prlogex, "primary") == 0 || + strcmp (prlogex, "logical") == 0 || + strcmp (prlogex, "extended") == 0) + ; + else if (strcmp (prlogex, "p") == 0) + prlogex = "primary"; + else if (strcmp (prlogex, "l") == 0) + prlogex = "logical"; + else if (strcmp (prlogex, "e") == 0) + prlogex = "extended"; + else { + reply_with_error ("part-add: unknown partition type: %s: this should be \"primary\", \"logical\" or \"extended\"", prlogex); + return -1; + } + + if (startsect < 0) { + reply_with_error ("part-add: startsect cannot be negative"); + return -1; + } + /* but endsect can be negative */ + + snprintf (startstr, sizeof startstr, "%" PRIi64 "s", startsect); + snprintf (endstr, sizeof endstr, "%" PRIi64 "s", endsect); + + /* XXX Bug: If the partition table type (which we don't know in this + * function) is GPT, then this parted command sets the _partition + * name_ to prlogex, eg. "primary". I would essentially describe + * this as a bug in the parted mkpart command. + */ + RUN_PARTED (device, "mkpart", prlogex, startstr, endstr, NULL); + + udev_settle (); + + return 0; +} + +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 ("part-disk: unknown partition type: common choices are \"gpt\" and \"msdos\""); + return -1; + } + + /* Voooooodooooooooo (thanks Jim Meyering for working this out). */ + if (strcmp (parttype, "msdos") == 0) { + startstr = "1s"; + endstr = "-1s"; + } else if (strcmp (parttype, "gpt") == 0) { + startstr = "34s"; + endstr = "-34s"; + } else { + /* untested */ + startstr = "1s"; + endstr = "-1s"; + } + + RUN_PARTED (device, + "mklabel", parttype, + /* See comment about about the parted mkpart command. */ + "mkpart", strcmp (parttype, "gpt") == 0 ? "p1" : "primary", + startstr, endstr, NULL); + + udev_settle (); + + return 0; +} + +int +do_part_set_bootable (const char *device, int partnum, int bootable) +{ + char partstr[16]; + + snprintf (partstr, sizeof partstr, "%d", partnum); + + RUN_PARTED (device, "set", partstr, "boot", bootable ? "on" : "off", NULL); + + udev_settle (); + + return 0; +} + +int +do_part_set_name (const char *device, int partnum, const char *name) +{ + char partstr[16]; + + snprintf (partstr, sizeof partstr, "%d", partnum); + + RUN_PARTED (device, "name", partstr, name, NULL); + + udev_settle (); + + return 0; +} + +static char ** +print_partition_table (const char *device) +{ + char *out, *err; + int r; + char **lines; + + r = command (&out, &err, "/sbin/parted", "-m", "--", device, + "unit", "b", + "print", NULL); + if (r == -1) { + reply_with_error ("parted print: %s: %s", device, + /* Hack for parted 1.x which sends errors to stdout. */ + *err ? err : out); + free (out); + free (err); + return NULL; + } + free (err); + + lines = split_lines (out); + free (out); + + if (!lines) + return NULL; + + if (lines[0] == NULL || strcmp (lines[0], "BYT;") != 0) { + reply_with_error ("parted print: unknown signature, expected \"BYT;\" as first line of the output: %s", + lines[0] ? lines[0] : "(signature was null)"); + free_strings (lines); + return NULL; + } + + if (lines[1] == NULL) { + reply_with_error ("parted print: parted didn't return a line describing the device"); + free_strings (lines); + return NULL; + } + + return lines; +} + +char * +do_part_get_parttype (const char *device) +{ + char **lines; + char *r; + + lines = print_partition_table (device); + if (!lines) + return NULL; + + /* lines[1] is something like: + * "/dev/sda:1953525168s:scsi:512:512:msdos:ATA Hitachi HDT72101;" + */ + if (strtok (lines[1], ":") == NULL /* device */ + || strtok (NULL, ":") == NULL /* size */ + || strtok (NULL, ":") == NULL /* transport */ + || strtok (NULL, ":") == NULL /* sector size */ + || strtok (NULL, ":") == NULL /* physical sector size */ + || (r = strtok (NULL, ":")) == NULL /* return value */ + ) { + reply_with_error ("part_get_parttype: too few fields in output from parted print command: %s", lines[1]); + free_strings (lines); + return NULL; + } + + r = strdup (r); + if (!r) { + reply_with_perror ("strdup"); + free_strings (lines); + return NULL; + } + + free_strings (lines); + + return r; +} + +guestfs_int_partition_list * +do_part_list (const char *device) +{ + char **lines; + size_t row, nr_rows, i; + guestfs_int_partition_list *r; + + lines = print_partition_table (device); + if (!lines) + return NULL; + + /* lines[0] is "BYT;", lines[1] is the device line which we ignore, + * lines[2..] are the partitions themselves. Count how many. + */ + nr_rows = 0; + for (row = 2; lines[row] != NULL; ++row) + ++nr_rows; + + r = malloc (sizeof *r); + if (r == NULL) { + reply_with_perror ("malloc"); + goto error1; + } + r->guestfs_int_partition_list_len = nr_rows; + r->guestfs_int_partition_list_val = + malloc (nr_rows * sizeof (guestfs_int_partition)); + if (r->guestfs_int_partition_list_val == NULL) { + reply_with_perror ("malloc"); + goto error2; + } + + /* Now parse the lines. */ + for (i = 0, row = 2; lines[row] != NULL; ++i, ++row) { + if (sscanf (lines[row], "%d:%" SCNi64 "B:%" SCNi64 "B:%" SCNi64 "B", + &r->guestfs_int_partition_list_val[i].part_num, + &r->guestfs_int_partition_list_val[i].part_start, + &r->guestfs_int_partition_list_val[i].part_end, + &r->guestfs_int_partition_list_val[i].part_size) != 4) { + reply_with_error ("part_list: could not parse row from output of parted print command: %s", lines[row]); + goto error3; + } + } + + free_strings (lines); + return r; + + error3: + free (r->guestfs_int_partition_list_val); + error2: + free (r); + error1: + free_strings (lines); + return NULL; +} diff --git a/guestfish.pod b/guestfish.pod index 8ae1800..2508066 100644 --- a/guestfish.pod +++ b/guestfish.pod @@ -63,7 +63,7 @@ Remove C (in reality not such a great idea): #!/usr/bin/guestfish -f alloc /tmp/output.img 10M run - sfdisk /dev/sda 0 0 0 , + part-disk /dev/sda mbr mkfs ext2 /dev/sda1 =head2 Remote control diff --git a/guestfs.pod b/guestfs.pod index 33b84d7..fdac80a 100644 --- a/guestfs.pod +++ b/guestfs.pod @@ -217,29 +217,27 @@ L. =head2 PARTITIONING -To create MBR-style (ie. normal PC) partitions use one of the -C variants. These calls use the external -L command. +In the common case where you want to create a single partition +covering the whole disk, you should use the C +call: -The simplest call is: - - char *lines[] = { ",", NULL }; - guestfs_sfdiskM (g, "/dev/sda", lines); - -This will create a single partition on C called -C covering the whole disk. + const char *parttype = "mbr"; + if (disk_is_larger_than_2TB) + parttype = "gpt"; + guestfs_part_disk (g, "/dev/sda", parttype); In general MBR partitions are both unnecessarily complicated and depend on archaic details, namely the Cylinder-Head-Sector (CHS) -geometry of the disk. C allows you to specify sizes -in megabytes instead of cylinders, which is a small win. +geometry of the disk. C can be used to +create more complex arrangements where the relative sizes are +expressed in megabytes instead of cylinders, which is a small win. C will choose the nearest cylinder to approximate the requested size. There's a lot of crazy stuff to do with IDE and virtio disks having different, incompatible CHS geometries, that you -probably don't want to know about. My advice: make a single partition -to cover the whole disk, then use LVM on top. +probably don't want to know about. -In future we aim to provide access to libparted. +My advice: make a single partition to cover the whole disk, then use +LVM on top. =head2 UPLOADING diff --git a/java/Makefile.inc b/java/Makefile.inc index 03b6049..c76184f 100644 --- a/java/Makefile.inc +++ b/java/Makefile.inc @@ -29,4 +29,5 @@ java_built_sources = \ com/redhat/et/libguestfs/Version.java \ com/redhat/et/libguestfs/XAttr.java \ com/redhat/et/libguestfs/INotifyEvent.java \ + com/redhat/et/libguestfs/Partition.java \ com/redhat/et/libguestfs/GuestFS.java diff --git a/ocaml/t/guestfs_060_readdir.ml b/ocaml/t/guestfs_060_readdir.ml index 8035a09..f560700 100644 --- a/ocaml/t/guestfs_060_readdir.ml +++ b/ocaml/t/guestfs_060_readdir.ml @@ -28,7 +28,7 @@ let () = Guestfs.add_drive g "test.img"; Guestfs.launch g; - Guestfs.sfdisk g "/dev/sda" 0 0 0 [|","|]; + Guestfs.part_disk g "/dev/sda" "mbr"; Guestfs.mkfs g "ext2" "/dev/sda1"; Guestfs.mount g "/dev/sda1" "/"; Guestfs.mkdir g "/p"; diff --git a/perl/t/060-readdir.t b/perl/t/060-readdir.t index 898b44f..5ed5b7a 100644 --- a/perl/t/060-readdir.t +++ b/perl/t/060-readdir.t @@ -34,7 +34,7 @@ ok (1); $h->launch (); ok (1); -$h->sfdisk ("/dev/sda", 0, 0, 0, [","]); +$h->part_disk ("/dev/sda", "mbr"); ok (1); $h->mkfs ("ext2", "/dev/sda1"); ok (1); diff --git a/po/POTFILES.in b/po/POTFILES.in index d7d12f7..a125f2a 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -35,6 +35,7 @@ daemon/modprobe.c daemon/mount.c daemon/names.c daemon/ntfs.c +daemon/parted.c daemon/pingdaemon.c daemon/proto.c daemon/readdir.c diff --git a/recipes/tar2vm.sh b/recipes/tar2vm.sh index d71a5ef..713e9e3 100755 --- a/recipes/tar2vm.sh +++ b/recipes/tar2vm.sh @@ -3,7 +3,7 @@ guestfish <, with C megabytes."); ("mkfs", (RErr, [String "fstype"; Device "device"]), 42, [], [InitEmpty, Always, TestOutput ( - [["sfdiskM"; "/dev/sda"; ","]; + [["part_disk"; "/dev/sda"; "mbr"]; ["mkfs"; "ext2"; "/dev/sda1"]; ["mount"; "/dev/sda1"; "/"]; ["write_file"; "/new"; "new file contents"; "0"]; @@ -1451,7 +1451,8 @@ To create a single partition occupying the whole disk, you would pass C as a single element list, when the single element being the string C<,> (comma). -See also: C, C"); +See also: C, C, +C"); ("write_file", (RErr, [Pathname "path"; String "content"; Int "size"]), 44, [ProtocolLimitWarning], [InitBasicFS, Always, TestOutput ( @@ -1489,12 +1490,12 @@ use C."); ("umount", (RErr, [String "pathordevice"]), 45, [FishAlias "unmount"], [InitEmpty, Always, TestOutputListOfDevices ( - [["sfdiskM"; "/dev/sda"; ","]; + [["part_disk"; "/dev/sda"; "mbr"]; ["mkfs"; "ext2"; "/dev/sda1"]; ["mount"; "/dev/sda1"; "/"]; ["mounts"]], ["/dev/sda1"]); InitEmpty, Always, TestOutputList ( - [["sfdiskM"; "/dev/sda"; ","]; + [["part_disk"; "/dev/sda"; "mbr"]; ["mkfs"; "ext2"; "/dev/sda1"]; ["mount"; "/dev/sda1"; "/"]; ["umount"; "/"]; @@ -2034,7 +2035,7 @@ to find out what you can do."); ("lvremove", (RErr, [Device "device"]), 77, [], [InitEmpty, Always, TestOutputList ( - [["sfdiskM"; "/dev/sda"; ","]; + [["part_disk"; "/dev/sda"; "mbr"]; ["pvcreate"; "/dev/sda1"]; ["vgcreate"; "VG"; "/dev/sda1"]; ["lvcreate"; "LV1"; "VG"; "50"]; @@ -2042,7 +2043,7 @@ to find out what you can do."); ["lvremove"; "/dev/VG/LV1"]; ["lvs"]], ["/dev/VG/LV2"]); InitEmpty, Always, TestOutputList ( - [["sfdiskM"; "/dev/sda"; ","]; + [["part_disk"; "/dev/sda"; "mbr"]; ["pvcreate"; "/dev/sda1"]; ["vgcreate"; "VG"; "/dev/sda1"]; ["lvcreate"; "LV1"; "VG"; "50"]; @@ -2050,7 +2051,7 @@ to find out what you can do."); ["lvremove"; "/dev/VG"]; ["lvs"]], []); InitEmpty, Always, TestOutputList ( - [["sfdiskM"; "/dev/sda"; ","]; + [["part_disk"; "/dev/sda"; "mbr"]; ["pvcreate"; "/dev/sda1"]; ["vgcreate"; "VG"; "/dev/sda1"]; ["lvcreate"; "LV1"; "VG"; "50"]; @@ -2067,7 +2068,7 @@ the VG name, C."); ("vgremove", (RErr, [String "vgname"]), 78, [], [InitEmpty, Always, TestOutputList ( - [["sfdiskM"; "/dev/sda"; ","]; + [["part_disk"; "/dev/sda"; "mbr"]; ["pvcreate"; "/dev/sda1"]; ["vgcreate"; "VG"; "/dev/sda1"]; ["lvcreate"; "LV1"; "VG"; "50"]; @@ -2075,7 +2076,7 @@ the VG name, C."); ["vgremove"; "VG"]; ["lvs"]], []); InitEmpty, Always, TestOutputList ( - [["sfdiskM"; "/dev/sda"; ","]; + [["part_disk"; "/dev/sda"; "mbr"]; ["pvcreate"; "/dev/sda1"]; ["vgcreate"; "VG"; "/dev/sda1"]; ["lvcreate"; "LV1"; "VG"; "50"]; @@ -2091,7 +2092,7 @@ group (if any)."); ("pvremove", (RErr, [Device "device"]), 79, [], [InitEmpty, Always, TestOutputListOfDevices ( - [["sfdiskM"; "/dev/sda"; ","]; + [["part_disk"; "/dev/sda"; "mbr"]; ["pvcreate"; "/dev/sda1"]; ["vgcreate"; "VG"; "/dev/sda1"]; ["lvcreate"; "LV1"; "VG"; "50"]; @@ -2100,7 +2101,7 @@ group (if any)."); ["pvremove"; "/dev/sda1"]; ["lvs"]], []); InitEmpty, Always, TestOutputListOfDevices ( - [["sfdiskM"; "/dev/sda"; ","]; + [["part_disk"; "/dev/sda"; "mbr"]; ["pvcreate"; "/dev/sda1"]; ["vgcreate"; "VG"; "/dev/sda1"]; ["lvcreate"; "LV1"; "VG"; "50"]; @@ -2109,7 +2110,7 @@ group (if any)."); ["pvremove"; "/dev/sda1"]; ["vgs"]], []); InitEmpty, Always, TestOutputListOfDevices ( - [["sfdiskM"; "/dev/sda"; ","]; + [["part_disk"; "/dev/sda"; "mbr"]; ["pvcreate"; "/dev/sda1"]; ["vgcreate"; "VG"; "/dev/sda1"]; ["lvcreate"; "LV1"; "VG"; "50"]; @@ -2386,7 +2387,7 @@ the human-readable, canonical hex dump of the file."); ("zerofree", (RErr, [Device "device"]), 97, [], [InitNone, Always, TestOutput ( - [["sfdiskM"; "/dev/sda"; ","]; + [["part_disk"; "/dev/sda"; "mbr"]; ["mkfs"; "ext3"; "/dev/sda1"]; ["mount"; "/dev/sda1"; "/"]; ["write_file"; "/new"; "test file"; "0"]; @@ -2424,7 +2425,9 @@ This runs L option to modify just the single partition C (note: C counts from 1). For other parameters, see C. You should usually -pass C<0> for the cyls/heads/sectors parameters."); +pass C<0> for the cyls/heads/sectors parameters. + +See also: C"); ("sfdisk_l", (RString "partitions", [Device "device"]), 100, [], [], @@ -2432,7 +2435,9 @@ pass C<0> for the cyls/heads/sectors parameters."); "\ This displays the partition table on C, in the human-readable output of the L command. It is -not intended to be parsed."); +not intended to be parsed. + +See also: C"); ("sfdisk_kernel_geometry", (RString "partitions", [Device "device"]), 101, [], [], @@ -2484,7 +2489,7 @@ are activated or deactivated."); ("lvresize", (RErr, [Device "device"; Int "mbytes"]), 105, [], [InitNone, Always, TestOutput ( - [["sfdiskM"; "/dev/sda"; ","]; + [["part_disk"; "/dev/sda"; "mbr"]; ["pvcreate"; "/dev/sda1"]; ["vgcreate"; "VG"; "/dev/sda1"]; ["lvcreate"; "LV"; "VG"; "10"]; @@ -2577,11 +2582,11 @@ Sleep for C seconds."); ("ntfs_3g_probe", (RInt "status", [Bool "rw"; Device "device"]), 110, [], [InitNone, Always, TestOutputInt ( - [["sfdiskM"; "/dev/sda"; ","]; + [["part_disk"; "/dev/sda"; "mbr"]; ["mkfs"; "ntfs"; "/dev/sda1"]; ["ntfs_3g_probe"; "true"; "/dev/sda1"]], 0); InitNone, Always, TestOutputInt ( - [["sfdiskM"; "/dev/sda"; ","]; + [["part_disk"; "/dev/sda"; "mbr"]; ["mkfs"; "ext2"; "/dev/sda1"]; ["ntfs_3g_probe"; "true"; "/dev/sda1"]], 12)], "probe NTFS volume", @@ -2859,7 +2864,7 @@ the command C."); ("mkswap", (RErr, [Device "device"]), 130, [], [InitEmpty, Always, TestRun ( - [["sfdiskM"; "/dev/sda"; ","]; + [["part_disk"; "/dev/sda"; "mbr"]; ["mkswap"; "/dev/sda1"]])], "create a swap partition", "\ @@ -2867,7 +2872,7 @@ Create a swap partition on C."); ("mkswap_L", (RErr, [String "label"; Device "device"]), 131, [], [InitEmpty, Always, TestRun ( - [["sfdiskM"; "/dev/sda"; ","]; + [["part_disk"; "/dev/sda"; "mbr"]; ["mkswap_L"; "hello"; "/dev/sda1"]])], "create a swap partition with a label", "\ @@ -2880,7 +2885,7 @@ a limitation of the kernel or swap tools."); ("mkswap_U", (RErr, [String "uuid"; Device "device"]), 132, [], (let uuid = uuidgen () in [InitEmpty, Always, TestRun ( - [["sfdiskM"; "/dev/sda"; ","]; + [["part_disk"; "/dev/sda"; "mbr"]; ["mkswap_U"; uuid; "/dev/sda1"]])]), "create a swap partition with an explicit UUID", "\ @@ -3024,7 +3029,8 @@ only (rounded to the nearest cylinder) and you don't need to specify the cyls, heads and sectors parameters which were rarely if ever used anyway. -See also C and the L manpage."); +See also: C, the L manpage +and C"); ("zfile", (RString "description", [String "meth"; Pathname "path"]), 140, [DeprecatedBy "file"], [], @@ -3371,7 +3377,7 @@ This command disables the libguestfs appliance swap on file."); ("swapon_label", (RErr, [String "label"]), 174, [], [InitEmpty, Always, TestRun ( - [["sfdiskM"; "/dev/sdb"; ","]; + [["part_disk"; "/dev/sdb"; "mbr"]; ["mkswap_L"; "swapit"; "/dev/sdb1"]; ["swapon_label"; "swapit"]; ["swapoff_label"; "swapit"]; @@ -3536,7 +3542,7 @@ and C"); ("mkfs_b", (RErr, [String "fstype"; Int "blocksize"; Device "device"]), 187, [], [InitEmpty, Always, TestOutput ( - [["sfdiskM"; "/dev/sda"; ","]; + [["part_disk"; "/dev/sda"; "mbr"]; ["mkfs_b"; "ext2"; "4096"; "/dev/sda1"]; ["mount"; "/dev/sda1"; "/"]; ["write_file"; "/new"; "new file contents"; "0"]; @@ -3893,6 +3899,193 @@ bytes of the file, starting at C, from file C. This may read fewer bytes than requested. For further details see the L system call."); + ("part_init", (RErr, [Device "device"; String "parttype"]), 208, [], + [InitEmpty, Always, TestRun ( + [["part_init"; "/dev/sda"; "gpt"]])], + "create an empty partition table", + "\ +This creates an empty partition table on C of one of the +partition types listed below. Usually C should be +either C or C (for large disks). + +Initially there are no partitions. Following this, you should +call C for each partition required. + +Possible values for C are: + +=over 4 + +=item B | B + +Intel EFI / GPT partition table. + +This is recommended for >= 2 TB partitions that will be accessed +from Linux and Intel-based Mac OS X. It also has limited backwards +compatibility with the C format. + +=item B | B + +The standard PC \"Master Boot Record\" (MBR) format used +by MS-DOS and Windows. This partition type will B work +for device sizes up to 2 TB. For large disks we recommend +using C. + +=back + +Other partition table types that may work but are not +supported include: + +=over 4 + +=item B + +AIX disk labels. + +=item B | B + +Amiga \"Rigid Disk Block\" format. + +=item B + +BSD disk labels. + +=item B + +DASD, used on IBM mainframes. + +=item B + +MIPS/SGI volumes. + +=item B + +Old Mac partition format. Modern Macs use C. + +=item B + +NEC PC-98 format, common in Japan apparently. + +=item B + +Sun disk labels. + +=back"); + + ("part_add", (RErr, [Device "device"; String "prlogex"; Int64 "startsect"; Int64 "endsect"]), 209, [], + [InitEmpty, Always, TestRun ( + [["part_init"; "/dev/sda"; "mbr"]; + ["part_add"; "/dev/sda"; "primary"; "1"; "-1"]]); + InitEmpty, Always, TestRun ( + [["part_init"; "/dev/sda"; "gpt"]; + ["part_add"; "/dev/sda"; "primary"; "34"; "127"]; + ["part_add"; "/dev/sda"; "primary"; "128"; "-34"]]); + InitEmpty, Always, TestRun ( + [["part_init"; "/dev/sda"; "mbr"]; + ["part_add"; "/dev/sda"; "primary"; "32"; "127"]; + ["part_add"; "/dev/sda"; "primary"; "128"; "255"]; + ["part_add"; "/dev/sda"; "primary"; "256"; "511"]; + ["part_add"; "/dev/sda"; "primary"; "512"; "-1"]])], + "add a partition to the device", + "\ +This command adds a partition to C. If there is no partition +table on the device, call C first. + +The C parameter is the type of partition. Normally you +should pass C

or C here, but MBR partition tables also +support C (or C) and C (or C) partition +types. + +C and C are the start and end of the partition +in I. C may be negative, which means it counts +backwards from the end of the disk (C<-1> is the last sector). + +Creating a partition which covers the whole disk is not so easy. +Use C to do that."); + + ("part_disk", (RErr, [Device "device"; String "parttype"]), 210, [DangerWillRobinson], + [InitEmpty, Always, TestRun ( + [["part_disk"; "/dev/sda"; "mbr"]]); + InitEmpty, Always, TestRun ( + [["part_disk"; "/dev/sda"; "gpt"]])], + "partition whole disk with a single primary partition", + "\ +This command is simply a combination of C +followed by C to create a single primary partition +covering the whole disk. + +C is the partition table type, usually C or C, +but other possible values are described in C."); + + ("part_set_bootable", (RErr, [Device "device"; Int "partnum"; Bool "bootable"]), 211, [], + [InitEmpty, Always, TestRun ( + [["part_disk"; "/dev/sda"; "mbr"]; + ["part_set_bootable"; "/dev/sda"; "1"; "true"]])], + "make a partition bootable", + "\ +This sets the bootable flag on partition numbered C on +device C. Note that partitions are numbered from 1. + +The bootable flag is used by some PC BIOSes to determine which +partition to boot from. It is by no means universally recognized, +and in any case if your operating system installed a boot +sector on the device itself, then that takes precedence."); + + ("part_set_name", (RErr, [Device "device"; Int "partnum"; String "name"]), 212, [], + [InitEmpty, Always, TestRun ( + [["part_disk"; "/dev/sda"; "gpt"]; + ["part_set_name"; "/dev/sda"; "1"; "thepartname"]])], + "set partition name", + "\ +This sets the partition name on partition numbered C on +device C. Note that partitions are numbered from 1. + +The partition name can only be set on certain types of partition +table. This works on C but not on C partitions."); + + ("part_list", (RStructList ("partitions", "partition"), [Device "device"]), 213, [], + [], (* XXX Add a regression test for this. *) + "list partitions on a device", + "\ +This command parses the partition table on C and +returns the list of partitions found. + +The fields in the returned structure are: + +=over 4 + +=item B + +Partition number, counting from 1. + +=item B + +Start of the partition I. To get sectors you have to +divide by the device's sector size, see C. + +=item B + +End of the partition in bytes. + +=item B + +Size of the partition in bytes. + +=back"); + + ("part_get_parttype", (RString "parttype", [Device "device"]), 214, [], + [InitEmpty, Always, TestOutput ( + [["part_disk"; "/dev/sda"; "gpt"]; + ["part_get_parttype"; "/dev/sda"]], "gpt")], + "get the partition table type", + "\ +This command examines the partition table on C and +returns the partition table type (format) being used. + +Common return values include: C (a DOS/Windows style MBR +partition table), C (a GPT/EFI-style partition table). Other +values are possible, although unusual. See C +for a full list."); + ] let all_functions = non_daemon_functions @ daemon_functions @@ -4061,6 +4254,14 @@ let structs = [ "in_cookie", FUInt32; "in_name", FString; ]; + + (* Partition table entry. *) + "partition", [ + "part_num", FInt32; + "part_start", FBytes; + "part_end", FBytes; + "part_size", FBytes; + ]; ] (* end of structs *) (* Ugh, Java has to be different .. @@ -4077,6 +4278,7 @@ let java_structs = [ "version", "Version"; "xattr", "XAttr"; "inotify_event", "INotifyEvent"; + "partition", "Partition"; ] (* What structs are actually returned. *) @@ -5951,14 +6153,14 @@ and generate_one_test_body name i test_name init test = [["blockdev_setrw"; "/dev/sda"]; ["umount_all"]; ["lvm_remove_all"]; - ["sfdiskM"; "/dev/sda"; ","]] + ["part_disk"; "/dev/sda"; "mbr"]] | InitBasicFS -> pr " /* InitBasicFS for %s: create ext2 on /dev/sda1 */\n" test_name; List.iter (generate_test_command_call test_name) [["blockdev_setrw"; "/dev/sda"]; ["umount_all"]; ["lvm_remove_all"]; - ["sfdiskM"; "/dev/sda"; ","]; + ["part_disk"; "/dev/sda"; "mbr"]; ["mkfs"; "ext2"; "/dev/sda1"]; ["mount"; "/dev/sda1"; "/"]] | InitBasicFSonLVM -> @@ -5968,7 +6170,7 @@ and generate_one_test_body name i test_name init test = [["blockdev_setrw"; "/dev/sda"]; ["umount_all"]; ["lvm_remove_all"]; - ["sfdiskM"; "/dev/sda"; ","]; + ["part_disk"; "/dev/sda"; "mbr"]; ["pvcreate"; "/dev/sda1"]; ["vgcreate"; "VG"; "/dev/sda1"]; ["lvcreate"; "LV"; "VG"; "8"];