Richard W.M. Jones
2009-Nov-04 23:31 UTC
[Libguestfs] [PATCH] Generic partition creation interface.
This creates a generic partition table interface. One immediate advantage is that you can create GPT partitions which can be larger than 2 TB. For example, here is a 1 exabyte partition: ><fs> sparse /mnt/tmp/test/test.img 1E ><fs> run ><fs> part-init gpt /dev/vda ><fs> part-add /dev/vda primary 0 0 ><fs> list-devices /dev/vda ><fs> list-partitions /dev/vda1 ><fs> blockdev-getsize64 /dev/vda1 1099511627775983104 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 -------------- next part -------------->From 89a57362b57ad13d4021b82c841120b48607bb8f Mon Sep 17 00:00:00 2001From: Richard Jones <rjones at redhat.com> Date: Wed, 4 Nov 2009 23:15:26 +0000 Subject: [PATCH] Generic partition creation interface. The current sfdisk interface works, but is somewhat limited since it can only deal with MBR-style partitions. For disks larger than 2TB, MBR partitions are unsuitable and we need to provide access to other partition table types (eg. GPT). This commit introduces a generic partition creation interface which should be future-proof and extensible. The implementation is based on parted. --- appliance/packagelist.in | 1 + daemon/Makefile.am | 1 + daemon/parted.c | 170 ++++++++++++++++++++++++++++++++++++++++++++++ po/POTFILES.in | 1 + src/MAX_PROC_NR | 2 +- src/generator.ml | 103 ++++++++++++++++++++++++++++ 6 files changed, 277 insertions(+), 1 deletions(-) create mode 100644 daemon/parted.c diff --git a/appliance/packagelist.in b/appliance/packagelist.in index 7363668..f7bd83a 100644 --- a/appliance/packagelist.in +++ b/appliance/packagelist.in @@ -40,6 +40,7 @@ lvm2 module-init-tools net-tools ntfs-3g +parted procps strace zerofree 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..032a64e --- /dev/null +++ b/daemon/parted.c @@ -0,0 +1,170 @@ +/* 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 <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <inttypes.h> +#include <string.h> +#include <unistd.h> + +#include "daemon.h" +#include "actions.h" + +/* XXX parted sends error messages to stdout!!! This is an upstream + * parted bug and I have no intention of fixing it here. + */ + +int +do_part_init (const char *parttype, const char *device) +{ + char *err; + int r; + + /* 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) + ; + else if (strcmp (parttype, "rdb") == 0) + parttype = "amiga"; + else if (strcmp (parttype, "efi") == 0) + parttype = "gpt"; + else if (strcmp (parttype, "mbr") == 0) + parttype = "msdos"; + else { + reply_with_error ("part-init: unknown partition type: %s: common choices are \"gpt\" and \"msdos\"", parttype); + return -1; + } + + r = command (NULL, &err, + "/sbin/parted", "-s", device, "mklabel", parttype, NULL); + if (r == -1) { + reply_with_perror ("part-init: %s: %s", device, err); + free (err); + return -1; + } + + free (err); + + udev_settle (); + + return 0; +} + +int +do_part_add (const char *device, const char *prlogex, + int64_t startmb, int64_t endmb) +{ + char *err; + int r; + 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 (startmb < 0) { + reply_with_error ("part-add: startmb cannot be negative"); + return -1; + } + + if (endmb < 0) { + reply_with_error ("part-add: endmb cannot be negative"); + return -1; + } + + /* Special value of endmb meaning "to the end of the disk". + * Unfortunately parted doesn't make this easy - we have to work out + * how big the disk is ourselves. + */ + if (endmb == 0) { + endmb = do_blockdev_getsize64 (device); + if (endmb == -1) + /* do_blockdev_getsize64 has called reply_with_error */ + return -1; + + /* That's bytes, convert to MB. */ + endmb /= 1024L * 1024; + } + + snprintf (startstr, sizeof startstr, "%" PRIi64, startmb); + snprintf (endstr, sizeof endstr, "%" PRIi64, endmb); + + r = command (NULL, &err, + "/sbin/parted", "-s", device, "mkpart", + prlogex, startstr, endstr, NULL); + if (r == -1) { + reply_with_perror ("part-add: %s: %s", device, err); + free (err); + return -1; + } + + free (err); + + udev_settle (); + + return 0; +} + +int +do_part_bootable (const char *device, int partnum, int bootable) +{ + char *err; + int r; + char partstr[16]; + + snprintf (partstr, sizeof partstr, "%d", partnum); + + r = command (NULL, &err, + "/sbin/parted", "-s", device, "set", partstr, "boot", + bootable ? "on" : "off", NULL); + if (r == -1) { + reply_with_perror ("part-bootable: %s: %s", device, err); + free (err); + return -1; + } + + free (err); + + udev_settle (); + + return 0; +} 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/src/MAX_PROC_NR b/src/MAX_PROC_NR index c92ba56..cd7da05 100644 --- a/src/MAX_PROC_NR +++ b/src/MAX_PROC_NR @@ -1 +1 @@ -207 +210 diff --git a/src/generator.ml b/src/generator.ml index a06e208..7960ea6 100755 --- a/src/generator.ml +++ b/src/generator.ml @@ -3893,6 +3893,109 @@ bytes of the file, starting at C<offset>, from file C<path>. This may read fewer bytes than requested. For further details see the L<pread(2)> system call."); + ("part_init", (RErr, [String "parttype"; Device "device"]), 208, [], + [InitEmpty, Always, TestRun ( + [["part_init"; "gpt"; "/dev/sda"]])], + "create an empty partition table", + "\ +This creates an empty partition table on C<device> of one of the +partition types listed below. Usually C<parttype> should be +either C<msdos> or C<gpt> (for large disks). + +Initially there are no partitions. Following this, you should +call C<guestfs_part_add> for each partition required. + +Possible values for C<parttype> are: + +=over 4 + +=item aix + +AIX disk labels. + +=item amiga | rdb + +Amiga \"Rigid Disk Block\" format. + +=item bsd + +BSD disk labels. + +=item dasd + +DASD, used on IBM mainframes. + +=item dvh + +MIPS/SGI volumes. + +=item efi | gpt + +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<mbr> format. + +=item mac + +Old Mac partition format. Modern Macs use C<gpt>. + +=item mbr | msdos + +The standard PC \"Master Boot Record\" (MBR) format used +by MS-DOS and Windows. This partition type will B<only> work +for device sizes up to 2 TB. For large disks we recommend +using C<gpt>. + +=item pc98 + +NEC PC-98 format, common in Japan apparently. + +=item sun + +Sun disk labels. + +=back"); + + ("part_add", (RErr, [Device "device"; String "prlogex"; Int64 "startmb"; Int64 "endmb"]), 209, [], + [InitEmpty, Always, TestRun ( + [["part_init"; "mbr"; "/dev/sda"]; + ["part_add"; "/dev/sda"; "primary"; "0"; "0"]])], + "add a partition to the device", + "\ +This command adds a partition to C<device>. If there is no partition +table on the device, call C<guestfs_part_init> first. + +The C<prlogex> parameter is the type of partition. Normally you +should pass C<p> or C<primary> here, but MBR partition tables also +support C<l> (or C<logical>) and C<e> (or C<extended>) partition +types. + +C<startmb> and C<endmb> are the start and end of the partition +in I<megabytes>. (Usually partitions cannot be placed on +arbitrary boundaries, so these are just hints and the partitions +will be placed as close as possible). + +As a special case, if C<endmb> is C<0>, then this means the +end of the disk. So to create a single partition covering the +whole disk, use C<startmb> = C<endmb> = 0."); + + ("part_bootable", (RErr, [Device "device"; Int "partnum"; Bool "bootable"]), 210, [], + [InitEmpty, Always, TestRun ( + [["part_init"; "mbr"; "/dev/sda"]; + ["part_add"; "/dev/sda"; "primary"; "0"; "0"]; + ["part_bootable"; "/dev/sda"; "1"; "true"]])], + "make a partition bootable", + "\ +This sets the bootable flag on partition numbered C<partnum> on +device C<device>. 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."); + ] let all_functions = non_daemon_functions @ daemon_functions -- 1.6.5.rc2
Richard W.M. Jones
2009-Nov-05 09:16 UTC
[Libguestfs] [PATCH VERSION 2] Generic partition creation interface.
This just tidies us the API over the previous version: (1) part-init now takes the parameters in (device, parttype) order, so it's consistent with the other calls. (2) guestfs_part_bootable -> guestfs_part_set_bootable, so we can add guestfs_part_get_bootable in future. (3) The documentation for part-init is changed to make it clear that only MS-DOS and GPT partition table types are supported. The others are best-effort. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones libguestfs lets you edit virtual machines. Supports shell scripting, bindings from many languages. http://et.redhat.com/~rjones/libguestfs/ See what it can do: http://et.redhat.com/~rjones/libguestfs/recipes.html -------------- next part -------------->From 55293a5e70d16ab166d46b5b7f724ea94603a0f2 Mon Sep 17 00:00:00 2001From: Richard Jones <rjones at redhat.com> Date: Wed, 4 Nov 2009 23:15:26 +0000 Subject: [PATCH] Generic partition creation interface. The current sfdisk interface works, but is somewhat limited since it can only deal with MBR-style partitions. For disks larger than 2TB, MBR partitions are unsuitable and we need to provide access to other partition table types (eg. GPT). This commit introduces a generic partition creation interface which should be future-proof and extensible. The implementation is based on parted. --- appliance/packagelist.in | 1 + daemon/Makefile.am | 1 + daemon/parted.c | 170 ++++++++++++++++++++++++++++++++++++++++++++++ po/POTFILES.in | 1 + src/MAX_PROC_NR | 2 +- src/generator.ml | 110 ++++++++++++++++++++++++++++++ 6 files changed, 284 insertions(+), 1 deletions(-) create mode 100644 daemon/parted.c diff --git a/appliance/packagelist.in b/appliance/packagelist.in index 7363668..f7bd83a 100644 --- a/appliance/packagelist.in +++ b/appliance/packagelist.in @@ -40,6 +40,7 @@ lvm2 module-init-tools net-tools ntfs-3g +parted procps strace zerofree 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..da108e9 --- /dev/null +++ b/daemon/parted.c @@ -0,0 +1,170 @@ +/* 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 <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <inttypes.h> +#include <string.h> +#include <unistd.h> + +#include "daemon.h" +#include "actions.h" + +/* XXX parted sends error messages to stdout!!! This is an upstream + * parted bug and I have no intention of fixing it here. + */ + +int +do_part_init (const char *device, const char *parttype) +{ + char *err; + int r; + + /* 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) + ; + else if (strcmp (parttype, "rdb") == 0) + parttype = "amiga"; + else if (strcmp (parttype, "efi") == 0) + parttype = "gpt"; + else if (strcmp (parttype, "mbr") == 0) + parttype = "msdos"; + else { + reply_with_error ("part-init: unknown partition type: %s: common choices are \"gpt\" and \"msdos\"", parttype); + return -1; + } + + r = command (NULL, &err, + "/sbin/parted", "-s", device, "mklabel", parttype, NULL); + if (r == -1) { + reply_with_perror ("part-init: %s: %s", device, err); + free (err); + return -1; + } + + free (err); + + udev_settle (); + + return 0; +} + +int +do_part_add (const char *device, const char *prlogex, + int64_t startmb, int64_t endmb) +{ + char *err; + int r; + 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 (startmb < 0) { + reply_with_error ("part-add: startmb cannot be negative"); + return -1; + } + + if (endmb < 0) { + reply_with_error ("part-add: endmb cannot be negative"); + return -1; + } + + /* Special value of endmb meaning "to the end of the disk". + * Unfortunately parted doesn't make this easy - we have to work out + * how big the disk is ourselves. + */ + if (endmb == 0) { + endmb = do_blockdev_getsize64 (device); + if (endmb == -1) + /* do_blockdev_getsize64 has called reply_with_error */ + return -1; + + /* That's bytes, convert to MB. */ + endmb /= 1024L * 1024; + } + + snprintf (startstr, sizeof startstr, "%" PRIi64, startmb); + snprintf (endstr, sizeof endstr, "%" PRIi64, endmb); + + r = command (NULL, &err, + "/sbin/parted", "-s", device, "mkpart", + prlogex, startstr, endstr, NULL); + if (r == -1) { + reply_with_perror ("part-add: %s: %s", device, err); + free (err); + return -1; + } + + free (err); + + udev_settle (); + + return 0; +} + +int +do_part_set_bootable (const char *device, int partnum, int bootable) +{ + char *err; + int r; + char partstr[16]; + + snprintf (partstr, sizeof partstr, "%d", partnum); + + r = command (NULL, &err, + "/sbin/parted", "-s", device, "set", partstr, "boot", + bootable ? "on" : "off", NULL); + if (r == -1) { + reply_with_perror ("part-bootable: %s: %s", device, err); + free (err); + return -1; + } + + free (err); + + udev_settle (); + + return 0; +} 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/src/MAX_PROC_NR b/src/MAX_PROC_NR index c92ba56..cd7da05 100644 --- a/src/MAX_PROC_NR +++ b/src/MAX_PROC_NR @@ -1 +1 @@ -207 +210 diff --git a/src/generator.ml b/src/generator.ml index a06e208..209c3b3 100755 --- a/src/generator.ml +++ b/src/generator.ml @@ -3893,6 +3893,116 @@ bytes of the file, starting at C<offset>, from file C<path>. This may read fewer bytes than requested. For further details see the L<pread(2)> 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<device> of one of the +partition types listed below. Usually C<parttype> should be +either C<msdos> or C<gpt> (for large disks). + +Initially there are no partitions. Following this, you should +call C<guestfs_part_add> for each partition required. + +Possible values for C<parttype> are: + +=over 4 + +=item B<efi> | B<gpt> + +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<mbr> format. + +=item B<mbr> | B<msdos> + +The standard PC \"Master Boot Record\" (MBR) format used +by MS-DOS and Windows. This partition type will B<only> work +for device sizes up to 2 TB. For large disks we recommend +using C<gpt>. + +=back + +Other partition table types that may work but are not +supported include: + +=over 4 + +=item B<aix> + +AIX disk labels. + +=item B<amiga> | B<rdb> + +Amiga \"Rigid Disk Block\" format. + +=item B<bsd> + +BSD disk labels. + +=item B<dasd> + +DASD, used on IBM mainframes. + +=item B<dvh> + +MIPS/SGI volumes. + +=item B<mac> + +Old Mac partition format. Modern Macs use C<gpt>. + +=item B<pc98> + +NEC PC-98 format, common in Japan apparently. + +=item B<sun> + +Sun disk labels. + +=back"); + + ("part_add", (RErr, [Device "device"; String "prlogex"; Int64 "startmb"; Int64 "endmb"]), 209, [], + [InitEmpty, Always, TestRun ( + [["part_init"; "/dev/sda"; "mbr"]; + ["part_add"; "/dev/sda"; "primary"; "0"; "0"]])], + "add a partition to the device", + "\ +This command adds a partition to C<device>. If there is no partition +table on the device, call C<guestfs_part_init> first. + +The C<prlogex> parameter is the type of partition. Normally you +should pass C<p> or C<primary> here, but MBR partition tables also +support C<l> (or C<logical>) and C<e> (or C<extended>) partition +types. + +C<startmb> and C<endmb> are the start and end of the partition +in I<megabytes>. (Usually partitions cannot be placed on +arbitrary boundaries, so these are just hints and the partitions +will be placed as close as possible). + +As a special case, if C<endmb> is C<0>, then this means the +end of the disk. So to create a single partition covering the +whole disk, use C<startmb> = C<endmb> = 0."); + + ("part_set_bootable", (RErr, [Device "device"; Int "partnum"; Bool "bootable"]), 210, [], + [InitEmpty, Always, TestRun ( + [["part_init"; "/dev/sda"; "mbr"]; + ["part_add"; "/dev/sda"; "primary"; "0"; "0"]; + ["part_set_bootable"; "/dev/sda"; "1"; "true"]])], + "make a partition bootable", + "\ +This sets the bootable flag on partition numbered C<partnum> on +device C<device>. 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."); + ] let all_functions = non_daemon_functions @ daemon_functions -- 1.6.5.rc2