>From 89a57362b57ad13d4021b82c841120b48607bb8f Mon Sep 17 00:00:00 2001 From: Richard Jones 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 + +#include +#include +#include +#include +#include +#include + +#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, from file C. This may read fewer bytes than requested. For further details see the L 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 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 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 format. + +=item mac + +Old Mac partition format. Modern Macs use C. + +=item mbr | msdos + +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. + +=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. 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. (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 is C<0>, then this means the +end of the disk. So to create a single partition covering the +whole disk, use C = C = 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 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."); + ] let all_functions = non_daemon_functions @ daemon_functions -- 1.6.5.rc2