summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsrs5694 <srs5694@users.sourceforge.net>2010-01-12 18:18:17 -0500
committersrs5694 <srs5694@users.sourceforge.net>2010-01-12 18:18:17 -0500
commit73ba4794a4b05c4bf4ff191bff2e023e706744fb (patch)
treee3433173fb57b9573000825b40cd248788d424b1
parent1e09372bca227ffbfb9dda48160826d8f63ce9bb (diff)
downloadsgdisk-73ba4794a4b05c4bf4ff191bff2e023e706744fb.tar.gz
Added files for sgdisk program
-rw-r--r--sgdisk.8467
-rw-r--r--sgdisk.cc678
2 files changed, 719 insertions, 426 deletions
diff --git a/sgdisk.8 b/sgdisk.8
new file mode 100644
index 0000000..48a740d
--- /dev/null
+++ b/sgdisk.8
@@ -0,0 +1,467 @@
+.\" Copyright 2009 Roderick W. Smith (rodsmith@rodsbooks.com)
+.\" May be distributed under the GNU General Public License
+.TH "SGDISK" "8" "0.6.0" "Roderick W. Smith" "GPT fdisk Manual"
+.SH "NAME"
+sgdisk \- Command\-line GUID partition table (GPT) manipulator for Linux and Unix
+.SH "SYNOPSIS"
+.BI "sgdisk "
+[ options ]
+.I device
+
+.SH "DESCRIPTION"
+GPT fdisk is a text\-mode menu\-driven package for creation and manipulation of
+partition tables. It consists of two programs: the text\-mode interactive
+\fBgdisk\fR and the command\-line \fBsgdisk\fR. Either program will
+automatically convert an old\-style Master Boot Record (MBR) partition table
+or BSD disklabel stored without an MBR carrier partition to the newer Globally
+Unique Identifier (GUID) Partition Table (GPT) format, or will load a GUID
+partition table. This man page documents the command\-line \fBsgdisk\fR
+program.
+
+Some advanced data manipulation and
+recovery options require you to understand the distinctions between the
+main and backup data, as well as between the GPT headers and the partition
+tables. For information on MBR vs. GPT, as well as GPT terminology and
+structure, see the extended \fBgdisk\fR documentation at
+\fIhttp://www.rodsbooks.com/gdisk/\fR or consult Wikipedia.
+
+The \fBsgdisk\fR program employs a user interface that's based entirely on
+the command line, making it suitable for use in scripts or by experts who
+want to make one or two quick changes to a disk. (The program may query the
+user when certain errors are encountered, though.) The program's name is
+based on \fBsfdisk\fR, but the user options of the two programs are
+entirely different from one another.
+
+Ordinarily, \fBsgdisk\fR operates on disk device files, such as
+\fI/dev/sda\fR or \fI/dev/hda\fR under Linux, \fI/dev/disk0\fR under
+Mac OS X, or \fI/dev/ad0\fR or \fI/dev/da0\fR under FreeBSD. The program
+can also operate on disk image files, which can be either copies of whole
+disks (made with \fBdd\fR, for instance) or raw disk images used by
+emulators such as QEMU or VMWare. Note that only \fIraw\fR disk images
+are supported; \fBsgdisk\fR cannot work on compressed or other advanced
+disk image formats.
+
+The MBR partitioning system uses a combination of cylinder/head/sector
+(CHS) addressing and logical block addressing (LBA). The former is klunky
+and limiting. GPT drops CHS addressing and uses 64\-bit LBA mode
+exclusively. Thus, GPT data structures, and therefore
+\fBsgdisk\fR, do not need to deal with CHS geometries and all the problems
+they create.
+
+For best results, you should use an OS\-specific partition table
+program whenever possible. For example, you should make Mac OS X
+partitions with the Mac OS X Disk Utility program and Linux partitions
+with the Linux \fBgdisk\fR, \fBsgdisk\fR, or GNU Parted programs.
+
+Upon start, \fBsgdisk\fR attempts to identify the partition type in use on
+the disk. If it finds valid GPT data, \fBsgdisk\fR will use it. If
+\fBsgdisk\fR finds a valid MBR or BSD disklabel but no GPT data, it will
+attempt to convert the MBR or disklabel into GPT form. (BSD disklabels are
+likely to have unusable first and/or final partitions because they overlap
+with the GPT data structures, though.) GPT fdisk can identify, but not use
+data in, Apple Partition Map (APM) disks, which are used on 680x0\- and
+PowerPC\-based Macintoshes. If you specify any option that results in changes
+to an MBR or BSD disklabel, \fBsgdisk\fR ignores those changes unless the
+\fI\-g\fR (\fI\-\-mbrtogpt\fR) or \fI\-z\fR (\fI\-\-zap\fR) option is used.
+If you use the \fI\-g\fR option, \fBsgdisk\fR replaces the MBR or disklabel
+with a GPT. \fIThis action is potentially dangerous!\fR Your system may become
+unbootable, and partition type codes may become corrupted if the disk uses
+unrecognized type codes. Boot problems are particularly likely if you're
+multi\-booting with any GPT\-unaware OS.
+
+The MBR\-to\-GPT conversion will leave at least one gap in the partition
+numbering if the original MBR used logical partitions. These gaps are
+harmless, but you can eliminate them by using the \fI\-s\fR (\fI\-\-sort\fR)
+option, if you like. (Doing this may require you to update your
+\fI/etc/fstab\fR file.)
+
+When creating a fresh partition table, certain considerations may be in
+order:
+
+.TP
+.B *
+For data (non\-boot) disks, and for boot disks used on BIOS\-based computers
+with GRUB as the boot loader, partitions may be created in whatever order
+and in whatever sizes are desired.
+
+.TP
+.B *
+Boot disks for EFI\-based systems require an \fIEFI System
+Partition\fR (\fBsgdisk\fR internal code 0xEF00) formatted as FAT\-32.
+The recommended size of this partition is between 100 and 200 MiB.
+Boot\-related files are stored here. (Note that GNU Parted identifies
+such partitions as having the "boot flag" set.)
+
+.TP
+.B *
+Some boot loaders for BIOS\-based systems make use of a \fIBIOS Boot
+Partition\fR (\fBsgdisk\fR internal code 0xEF02), in which the secondary
+boot loader is stored, possibly without the benefit of a filesystem. This
+partition can typically be quite small (roughly 32 to 200 KiB), but you
+should consult your boot loader documentation for details.
+
+.TP
+.B *
+If Windows is to boot from a GPT disk, a partition of type \fIMicrosoft
+Reserved\fR (\fBsgdisk\fR
+internal code 0x0C01) is recommended. This partition should be about 128 MiB
+in size. It ordinarily follows the EFI System Partition and immediately
+precedes the Windows data partitions. (Note that GNU Parted creates all
+FAT partitions as this type, which actually makes the partition unusable
+for normal file storage in both Windows and Mac OS X.)
+
+.TP
+.B *
+Some OSes' GPT utilities create some blank space (typically 128 MiB) after
+each partition. The intent is to enable future disk utilities to use this
+space. Such free space is not required of GPT disks, but creating it may
+help in future disk maintenance.
+
+.SH "OPTIONS"
+Some options take no arguments, others take one argument (typically a partition
+number), and others take compound arguments with colon delimitation. For
+instance, \fI\-n\fR (\fI\-\-new\fR) takes a partition number, a starting
+sector number, and an ending sector number, as in \fBsgdisk \-n 2:2000:50000
+/dev/sdc\fR, which creates a new partition, numbered 2, starting at sector
+2000 an ending at sector 50,000, on \fI/dev/sdc\fR.
+
+Unrelated options may be combined; however, some such combinations will be
+nonsense (such as deleting a partition and then changing its GUID type code).
+\fBsgdisk\fR interprets options in the order in which they're entered, so
+effects can vary depending on order. For instance, \fBsgdisk \-s \-d 2\fR
+sorts the partition table entries and then deletes partition 2 from the
+newly\-sorted list; but \fBsgdisk \-d 2 \-s\fR deletes the original partition
+2 and then sorts the modified partition table.
+
+Error checking and opportunities to correct mistakes in \fBsgdisk\fR are
+minimal. Although the program endeavors to keep the GPT data structures legal,
+it does not prompt for verification before performing its actions. Unless you
+require a command\-line\-driven program, you should use the interactive
+\fBgdisk\fR instead of \fBsgdisk\fR, since \fBgdisk\fR allows you to
+quit without saving your changes, should you make a mistake.
+
+Although \fBsgdisk\fR is based on the same partition\-manipulation code as
+\fBgdisk\fR, \fBsgdisk\fR implements fewer features than its interactive
+sibling. Options available in \fBsgdisk\fR are:
+
+.TP
+.B \-a, \-\-set\-alignment=value
+Set the sector alignment multiple. GPT fdisk aligns the start of partitions
+to sectors that are multiples of this value, which defaults to 8 on disks
+larger than 800GiB with 512\-byte sectors and to 1 on smaller disks or those
+with non\-512\-byte sectors. This alignment value is necessary to obtain
+optimum performance with Western Digital Advanced Format and similar drives
+with larger physical than logical sector sizes.
+
+.TP
+.B \-b, \-\-backup=file
+Save partition data to a backup file. You can back up your current
+in\-memory partition table to a disk file using this option. The resulting
+file is a binary file consisting of the protective MBR, the main GPT
+header, the backup GPT header, and one copy of the partition table, in that
+order. Note that the backup is of the current in\-memory data structures, so
+if you launch the program, make changes, and then use this option, the
+backup will reflect your changes. If the GPT data structures are damaged,
+the backup may not accurately reflect the damaged state; instead, they
+will reflect GPT fdisk's first\-pass interpretation of the GPT.
+
+.TP
+.B \-c, \-\-change=partnum:name
+Change the GPT name of a partition. This name is encoded as a UTF\-16
+string, but \fBsgdisk\fR
+supports only ASCII characters as names. For the most part, Linux ignores
+the partition name, but it may be important in some OSes. GPT fdisk sets
+a default name based on the partition type code. If you want to set a name
+that includes a space, enclose it in quotation marks, as in
+\fIsgdisk \-c 1:"Sample Name" /dev/sdb\fR.
+
+.TP
+.B \-d, \-\-delete=partnum
+Delete a partition. This action deletes the entry from the partition table
+but does not disturb the data within the sectors originally allocated to
+the partition on the disk. If a corresponding hybrid MBR partition exists,
+\fBgdisk\fR deletes it, as well, and expands any adjacent 0xEE (EFI GPT)
+MBR protective partition to fill the new free space.
+
+.TP
+.B e, \-\-move\-second\-header
+Move backup GPT data structures to the end of the disk. Use this option if
+you've added disks to a RAID array, thus creating a virtual disk with space
+that follows the backup GPT data structures. This command moves the backup
+GPT data structures to the end of the disk, where they belong.
+
+.TP
+.B E, \-\-end\-of\-largest
+Displays the sector number of the end of the largest available block of
+sectors on the disk. A script may store this value and pass it back as
+part of \fI\-n\fR's option to create a partition. If no unallocated
+sectors are available, this function returns the value 0.
+
+.TP
+.B \-f, \-\-first\-in\-largest
+Displays the sector number of the start of the largest available block of
+sectors on the disk. A script may store this value and pass it back as
+part of \fI\-n\fR's option to create a partition. If no unallocated
+sectors are available, this function returns the value 0.
+
+.TP
+.B \-g, \-\-mbrtogpt
+Convert an MBR disk to a GPT disk. As a safety measure, use of this option
+is required on MBR or BSD disklabel disks if you intend to save your changes,
+in order to prevent accidentally damaging such disks.
+
+.TP
+.B \-i, \-\-info=partnum
+Show detailed partition information. The summary information produced by
+the \fI\-p\fR command necessarily omits many details, such as the partition's
+unique GUID and the translation of \fBsgdisk\fR's
+internal partition type code to a plain type name. The \fI\-i\fR option
+displays this information for a single partition.
+
+.TP
+.B \-l, \-\-load\-backup=file
+Load partition data from a backup file. This option is the reverse of the
+\fI\-b\fR option. Note that restoring partition data from anything
+but the original disk is not recommended.
+
+.TP
+.B \-L, \-\-list\-types
+Display a summary of partition types. GPT uses a GUID to identify
+partition types for particular OSes and purposes. For ease of data entry,
+\fBsgdisk\fR compresses these into two\-byte (four\-digit hexadecimal)
+values that are related to their equivalent MBR codes. Specifically, the
+MBR code is multiplied by hexadecimal 0x0100. For instance, the code for
+Linux swap space in MBR is 0x82, and it's 0x8200 in \fBgdisk\fR.
+A one\-to\-one correspondence is impossible, though. Most notably, many DOS,
+Windows, and Linux data partition codes correspond to a single GPT code
+(entered as 0x0700 in \fBsgdisk\fR). Some OSes use a single MBR code but
+employ many more codes in GPT. For these, \fBsgdisk\fR
+adds code numbers sequentially, such as 0xa500 for a FreeBSD disklabel,
+0xa501 for FreeBSD boot, 0xa502 for FreeBSD swap, and so on. Note that
+these two\-byte codes are unique to \fBgdisk\fR and \fBsgdisk\fR. This
+option does not require you to specify a valid disk device filename.
+
+.TP
+.B \-n, \-\-new=partnum:start:end
+Create a new partition. You enter a partition
+number, starting sector, and an ending sector. Both start and end sectors
+can be specified in absolute terms as sector numbers or as positions
+measured in kilobytes (K), megabytes (M), gigabytes (G), or terabytes (T);
+for instance, \fI\fB40M\fR\fR specifies a position 40MiB from the start of
+the disk. You can specify locations relative to the start or end of the
+specified default range by preceding the number by a '+' or '\-' symbol, as
+in \fI\fB+2G\fR\fR to specify a point 2GiB after the default start sector,
+or \fI\fB\-200M\fR\fR to specify a point 200MiB before the last available
+sector. Pressing the Enter key with no input specifies the default value,
+which is the start of the largest available block for the start sector and
+the end of the same block for the end sector.
+
+.TP
+.B \-o, \-\-clear
+Clear out all partition data. This includes GPT header data,
+all partition definitions, and the protective MBR.
+
+.TP
+.B \-p, \-\-print
+Display basic partition summary data. This includes partition
+numbers, starting and ending sector numbers, partition sizes,
+\fBsgdisk\fR's partition types codes, and partition names. For
+additional information, use the \fI\-i\fR (\fI\-\-info\fR) option.
+
+.TP
+.B \-P, \-\-pretend
+Pretend to make specified changes. In\-memory GPT data structures are
+altered according to other parameters, but changes are not written
+to disk.
+
+.TP
+.B \-s, \-\-sort
+Sort partition entries. GPT partition numbers need not match the order of
+partitions on the disk. If you want them to match, you can use this option.
+Note that some partitioning utilities sort partitions whenever they make
+changes. Such changes will be reflected in your device filenames, so you
+may need to edit \fI/etc/fstab\fR if you use this option.
+
+.TP
+.B \-t, \-\-typecode=partnum:hexcode
+Change a single partition's type code. You enter the type code using a
+two\-byte hexadecimal number, as described earlier.
+
+.TP
+.B \-T, \-\-transform\-bsd=partnum
+Transform BSD partitions into GPT partitions. This option works on BSD
+disklabels held within GPT (or converted MBR) partitions. Converted
+partitions' type codes are likely to need manual adjustment. \fBsgdisk\fR
+will attempt to convert BSD disklabels stored on the main disk when
+launched, but this conversion is likely to produce first and/or last
+partitions that are unusable. The many BSD variants means that the
+probability of \fBsgdisk\fR being unable to convert a BSD disklabel is
+high compared to the likelihood of problems with an MBR conversion.
+
+.TP
+.B \-\-usage
+Print a brief summary of available options.
+
+.TP
+.B \-v, \-\-verify
+Verify disk. This option checks for a variety of problems, such as
+incorrect CRCs and mismatched main and backup data. This option does not
+automatically correct most problems, though; for that, you must use
+options on the recovery & transformation menu. If no problems are found,
+this command displays a summary of unallocated disk space.
+
+.TP
+.B \-V, \-\-version
+Display program version information. This option may be used without
+specifying a device filename.
+
+.TP
+.B \-z, \-\-zap
+Zap (destroy) the GPT data structures and exit. Use this option if you want to
+repartition a GPT disk using \fBfdisk\fR or some other GPT\-unaware program.
+You'll be given the choice of preserving the existing MBR, in case it's a
+hybrid MBR with salvageable partitions or if you've already created new MBR
+partitions and want to erase the remnants of your GPT partitions. \fIIf you've
+already created new MBR partitions, it's conceivable that this option will
+damage the first and/or last MBR partitions!\fR Such an event is unlikely, but
+could occur if your new MBR partitions overlap the old GPT data structures.
+
+.TP
+.B \-?, \-\-help
+Print a summary of options.
+
+.SH "RETURN VALUES"
+\fBsgdisk\fR returns various values depending on its success or failure:
+
+.TP
+.B 0
+Normal program execution
+
+.TP
+.B 1
+Too few arguments
+
+.TP
+.B 4
+An error occurred while reading the partition table
+
+.TP
+.B 3
+Non\-GPT disk detected and no \fI\-g\fR option
+
+.TP
+.B 4
+An error prevented saving changes
+.SH "BUGS"
+As of January 2010 (version 0.6.0), \fBsgdisk\fR
+should be considered beta software. Known bugs and limitations include:
+
+.TP
+.B *
+The program compiles correctly only on Linux, FreeBSD, and Mac OS X. Linux
+versions for x86\-64 (64\-bit), x86 (32\-bit), and PowerPC (32\-bit) have been
+tested, with the x86\-64 version having seen the most testing.
+
+.TP
+.B *
+The FreeBSD version of the program can't write changes to the partition
+table to a disk when existing partitions on that disk are mounted. (The
+same problem exists with many other FreeBSD utilities, such as
+\fBgpt\fR, \fBfdisk\fR, and \fBdd\fR.)
+
+.TP
+.B *
+The fields used to display the start and end sector numbers for partitions
+in the \fI\-p\fR option are 14 characters wide. This translates to a limitation
+of about 45 PiB. On larger disks, the displayed columns will go out of
+alignment.
+
+.TP
+.B *
+Only ASCII characters are supported in the partition name field. If an
+existing partition uses non\-ASCII UTF\-16 characters, they're likely to be
+corrupted in the 'i' and 'p' menu options' displays; however, they should be
+preserved when loading and saving partitions.
+
+.TP
+.B *
+The program can load only up to 128 partitions (4 primary partitions and
+124 logical partitions) when converting from MBR format. This limit can
+be raised by changing the \fI#define MAX_MBR_PARTS\fR line in the
+\fImbr.h\fR source code file and recompiling; however, such a change
+will require using a larger\-than\-normal partition table. (The limit
+of 128 partitions was chosen because that number equals the 128 partitions
+supported by the most common partition table size.)
+
+.TP
+.B *
+Converting from MBR format sometimes fails because of insufficient space at
+the start or (more commonly) the end of the disk. Resizing the partition
+table (using the 's' option in the experts' menu) can sometimes overcome
+this problem; however, in extreme cases it may be necessary to resize a
+partition using GNU Parted or a similar tool prior to conversion with
+\fBgdisk\fR.
+
+.TP
+.B *
+MBR conversions work only if the disk has correct LBA partition
+descriptors. These descriptors should be present on any disk over 8 GiB in
+size or on smaller disks partitioned with any but very ancient software.
+
+.TP
+.B *
+BSD disklabel support can create first and/or last partitions that overlap
+with the GPT data structures. This can sometimes be compensated by
+adjusting the partition table size, but in extreme cases the affected
+partition(s) may need to be deleted.
+
+.TP
+.B *
+Because of the highly variable nature of BSD disklabel structures,
+conversions from this form may be unreliable \-\- partitions may be dropped,
+converted in a way that creates overlaps with other partitions, or
+converted with incorrect start or end values. Use this feature with
+caution!
+
+.TP
+.B *
+Booting after converting an MBR or BSD disklabel disk is likely to be
+disrupted. Sometimes re\-installing a boot loader will fix the problem, but
+other times you may need to switch boot loaders. Except on EFI\-based
+platforms, Windows through at least Windows 7 RC doesn't support booting
+from GPT disks. Creating a hybrid MBR (using the 'h' option on the recovery &
+transformation menu) or abandoning GPT in favor of MBR may be your only
+options in this case.
+
+.PP
+
+The support for big\-endian CPUs (PowerPC, for example) is new, as of version
+0.3.5. I advise using caution on that platform, particularly with the more
+obscure features of the program.
+
+.SH "AUTHORS"
+Primary author: Roderick W. Smith (rodsmith@rodsbooks.com)
+
+Contributors:
+
+* Yves Blusseau (1otnwmz02@sneakemail.com)
+
+* David Hubbard (david.c.hubbard@gmail.com)
+
+.SH "SEE ALSO"
+\fBcfdisk (8)\fR,
+\fBfdisk (8)\fR,
+\fBgdisk (8)\fR,
+\fBmkfs (8)\fR,
+\fBparted (8)\fR,
+\fBsfdisk (8)\fR
+
+\fIhttp://en.wikipedia.org/wiki/GUID_Partition_Table\fR
+
+\fIhttp://developer.apple.com/technotes/tn2006/tn2166.html\fR
+
+\fIhttp://www.rodsbooks.com/gdisk/\fR
+
+.SH "AVAILABILITY"
+The \fBsgdisk\fR command is part of the \fIGPT fdisk\fR package and is
+available from Rod Smith.
diff --git a/sgdisk.cc b/sgdisk.cc
index 9479afb..027e37f 100644
--- a/sgdisk.cc
+++ b/sgdisk.cc
@@ -1,464 +1,290 @@
// sgdisk.cc
-// Program modelled after Linux sfdisk, but it manipulates GPT partitions
-// rather than MBR partitions. This is effectively a new user interface
-// to my gdisk program.
+// Command-line-based version of gdisk. This program is named after sfdisk,
+// and it can serve a similar role (easily scripted, etc.), but it's used
+// strictly via command-line arguments, and it doesn't bear much resemblance
+// to sfdisk in actual use.
//
-// by Rod Smith, project began February 2009
+// by Rod Smith, project began February 2009; sgdisk begun January 2010.
/* This program is copyright (c) 2009, 2010 by Roderick W. Smith. It is distributed
under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
-//#include <iostream>
#include <stdio.h>
-#include <string.h>
-#include <getopt.h>
+#include <string>
+#include <popt.h>
+#include <errno.h>
#include "mbr.h"
#include "gpt.h"
#include "support.h"
+#include "parttypes.h"
+
+using namespace std;
#define MAX_OPTIONS 50
-// Function prototypes....
-/* void MainMenu(char* filename, struct GPTData* theGPT);
-void ShowCommands(void);
-void ExpertsMenu(char* filename, struct GPTData* theGPT);
-void ShowExpertCommands(void);
-void RecoveryMenu(char* filename, struct GPTData* theGPT);
-void ShowRecoveryCommands(void); */
+uint64_t GetInt(char* Info, int itemNum);
+string GetString(char* Info, int itemNum);
-enum Commands { NONE, LIST, VERIFY };
+int main(int argc, char *argv[]) {
+ GPTData theGPT;
+ int opt, i, numOptions = 0, saveData = 0, neverSaveData = 0;
+ int partNum = 0, deletePartNum = 0, infoPartNum = 0, bsdPartNum = 0, saveNonGPT = 1;
+ int alignment = 8, retval = 0, pretend = 0;
+ uint16_t hexCode;
+ uint32_t tableSize = 128;
+ uint64_t startSector, endSector;
+ char* device = NULL;
+ char *argument = NULL, *newPartInfo = NULL, *typeCode = NULL, *partName;
+ char *backupFile = NULL;
+ PartTypes typeHelper;
-struct Options {
- Commands theCommand;
- char* theArgument;
-}; // struct Options
+ poptContext poptCon;
+ struct poptOption theOptions[] =
+ {
+ {"set-alignment", 'a', POPT_ARG_INT, &alignment, 'a', "set sector alignment", "value"},
+ {"backup", 'b', POPT_ARG_STRING, &backupFile, 'b', "backup GPT to file", "file"},
+ {"change-name", 'c', POPT_ARG_STRING, &partName, 'c', "change partition's name", "partnum:name"},
+ {"delete", 'd', POPT_ARG_INT, &deletePartNum, 'd', "delete a partition", "partnum"},
+ {"move-second-header", 'e', POPT_ARG_NONE, NULL, 'e', "move second header to end of disk", ""},
+ {"end-of-largest", 'E', POPT_ARG_NONE, NULL, 'E', "show end of largest free block", ""},
+ {"first-in-largest", 'f', POPT_ARG_NONE, NULL, 'f', "show start of the largest free block", ""},
+ {"mbrtogpt", 'g', POPT_ARG_NONE, NULL, 'g', "convert MBR to GPT", ""},
+ {"info", 'i', POPT_ARG_INT, &infoPartNum, 'i', "show detailed information on partition", "partnum"},
+ {"load-backup", 'l', POPT_ARG_STRING, &backupFile, 'l', "load GPT backup from file", "file"},
+ {"list-types", 'L', POPT_ARG_NONE, NULL, 'L', "list known partition types", ""},
+ {"new", 'n', POPT_ARG_STRING, &newPartInfo, 'n', "create new partition", "partnum:start:end"},
+ {"clear", 'o', POPT_ARG_NONE, NULL, 'o', "clear partition table", ""},
+ {"print", 'p', POPT_ARG_NONE, NULL, 'p', "print partition table", ""},
+ {"pretend", 'P', POPT_ARG_NONE, NULL, 'P', "make changes in memory, but don't write them", ""},
+ {"sort", 's', POPT_ARG_NONE, NULL, 's', "sort partition table entries", ""},
+ {"resize-table", 'S', POPT_ARG_INT, &tableSize, 'S', "resize partition table", "numparts"},
+ {"typecode", 't', POPT_ARG_STRING, &typeCode, 't', "change partition type code", "partnum:hexcode"},
+ {"transform-bsd", 'T', POPT_ARG_INT, &bsdPartNum, 'T', "transform BSD disklabel partition to GPT", "partnum"},
+ {"verify", 'v', POPT_ARG_NONE, NULL, 'v', "check partition table integrity", ""},
+ {"version", 'V', POPT_ARG_NONE, NULL, 'V', "display version information", ""},
+ {"zap", 'z', POPT_ARG_NONE, NULL, 'z', "zap (destroy) GPT data structures", ""},
+ POPT_AUTOHELP { NULL, 0, 0, NULL, 0 }
+ };
-int verbose_flag;
+ // Create popt context...
+ poptCon = poptGetContext(NULL, argc, (const char**) argv, theOptions, 0);
-static struct option long_options[] =
-{
- {"verify", no_argument, NULL, 'v'},
- {"list", no_argument, NULL, 'l'},
- {0, 0, NULL, 0}
-};
+ poptSetOtherOptionHelp(poptCon, " [OPTION...] <device>");
-int ParseOptions(int argc, char* argv[], Options* theOptions, char** device);
+ if (argc < 2) {
+ poptPrintUsage(poptCon, stderr, 0);
+ exit(1);
+ }
-int main(int argc, char* argv[]) {
- GPTData theGPT;
- int doMore = 1, opt, i, numOptions = 0;
- char* device = NULL;
- Options theOptions[MAX_OPTIONS];
+ // Do one loop through the options to find the device filename and deal
+ // with options that don't require a device filename....
+ while ((opt = poptGetNextOpt(poptCon)) > 0) {
+ switch (opt) {
+ case 'L':
+ typeHelper.ShowTypes();
+ break;
+ case 'P':
+ pretend = 1;
+ break;
+ case 'V':
+ printf("GPT fdisk (sgdisk) version 0.5.4-pre1\n\n");
+ break;
+ default:
+ break;
+ } // switch
+ numOptions++;
+ } // while
- printf("GPT fdisk (sgdisk) version 0.5.4-pre1\n\n");
- numOptions = ParseOptions(argc, argv, theOptions, &device);
+ // Assume first non-option argument is the device filename....
+ device = (char*) poptGetArg(poptCon);
+ poptResetContext(poptCon);
if (device != NULL) {
+ theGPT.JustLooking(); // reset as necessary
+ theGPT.BeQuiet(); // Tell called functions to be less verbose & interactive
if (theGPT.LoadPartitions(device)) {
- for (i = 0; i < numOptions; i++) {
- switch (theOptions[i].theCommand) {
- case LIST:
- theGPT.JustLooking();
+ if ((theGPT.WhichWasUsed() == use_mbr) || (theGPT.WhichWasUsed() == use_bsd))
+ saveNonGPT = 0; // flag so we don't overwrite unless directed to do so
+ while ((opt = poptGetNextOpt(poptCon)) > 0) {
+ switch (opt) {
+ case 'a':
+ theGPT.SetAlignment(alignment);
+ break;
+ case 'b':
+ theGPT.SaveGPTBackup(backupFile);
+ free(backupFile);
+ break;
+ case 'c':
+ theGPT.JustLooking(0);
+ partNum = (int) GetInt(partName, 1) - 1;
+ if (theGPT.SetName(partNum, (char*) GetString(partName, 2).c_str())) {
+ saveData = 1;
+ } else {
+ fprintf(stderr, "Unable set set partition %d's name to '%s'!\n",
+ partNum + 1, GetString(partName, 2).c_str());
+ neverSaveData = 1;
+ } // if/else
+ free(partName);
+ break;
+ case 'd':
+ theGPT.JustLooking(0);
+ if (theGPT.DeletePartition(deletePartNum - 1) == 0) {
+ fprintf(stderr, "Error %d deleting partition!\n", errno);
+ neverSaveData = 1;
+ } else saveData = 1;
+ break;
+ case 'e':
+ theGPT.JustLooking(0);
+ theGPT.MoveSecondHeaderToEnd();
+ saveData = 1;
+ break;
+ case 'E':
+ printf("%llu\n", (unsigned long long) theGPT.FindLastAvailable(theGPT.FindFirstInLargest()));
+ break;
+ case 'f':
+ printf("%llu\n", (unsigned long long) theGPT.FindFirstInLargest());
+ break;
+ case 'g':
+ theGPT.JustLooking(0);
+ saveData = 1;
+ saveNonGPT = 1;
+ break;
+ case 'i':
+ theGPT.ShowPartDetails(infoPartNum - 1);
+ break;
+ case 'l':
+ if (theGPT.LoadGPTBackup(backupFile) == 1)
+ saveData = 1;
+ else {
+ saveData = 0;
+ neverSaveData = 1;
+ fprintf(stderr, "Error loading backup file!\n");
+ } // else
+ free(backupFile);
+ break;
+ case 'L':
+ break;
+ case 'n':
+ theGPT.JustLooking(0);
+ partNum = (int) GetInt(newPartInfo, 1) - 1;
+ startSector = GetInt(newPartInfo, 2);
+ endSector = GetInt(newPartInfo, 3);
+ if (theGPT.CreatePartition(partNum, startSector, endSector)) {
+ saveData = 1;
+ } else {
+ fprintf(stderr, "Could not create partition %d from %llu to %llu!\n",
+ partNum, startSector, endSector);
+ neverSaveData = 1;
+ } // if/else
+ free(newPartInfo);
+ break;
+ case 'o':
+ theGPT.JustLooking(0);
+ theGPT.ClearGPTData();
+ saveData = 1;
+ break;
+ case 'p':
theGPT.DisplayGPTData();
break;
- case VERIFY:
- theGPT.JustLooking();
+ case 'P':
+ pretend = 1;
+ break;
+ case 's':
+ theGPT.JustLooking(0);
+ theGPT.SortGPT();
+ saveData = 1;
+ break;
+ case 'S':
+ theGPT.JustLooking(0);
+ if (theGPT.SetGPTSize(tableSize) == 0)
+ neverSaveData = 1;
+ else
+ saveData = 1;
+ break;
+ case 't':
+ theGPT.JustLooking(0);
+ partNum = (int) GetInt(typeCode, 1) - 1;
+ sscanf(GetString(typeCode, 2).c_str(), "%x", &hexCode);
+ if (theGPT.ChangePartType(partNum, hexCode)) {
+ saveData = 1;
+ } else {
+ fprintf(stderr, "Could not change partition %d's type code to %x!\n",
+ partNum + 1, hexCode);
+ neverSaveData = 1;
+ } // if/else
+ free(typeCode);
+ break;
+ case 'T':
+ theGPT.JustLooking(0);
+ theGPT.XFormDisklabel(bsdPartNum);
+ saveData = 1;
+ break;
+ case 'v':
theGPT.Verify();
break;
- case NONE:
- printf("Usage: %s {-lv} device\n", argv[0]);
+ case 'z':
+ if (!pretend)
+ theGPT.DestroyGPT(-1);
+ saveNonGPT = 0;
+ break;
+ default:
+ printf("Unknown option (-%c)!\n", opt);
break;
} // switch
- } // for
- } // if loaded OK
+ } // while
+ if ((saveData) && (!neverSaveData) && (saveNonGPT) && (!pretend))
+ theGPT.SaveGPTData(1);
+ if (saveData && (!saveNonGPT)) {
+ printf("Non-GPT disk; not saving changes. Use -g to override.\n");
+ retval = 3;
+ } // if
+ if (neverSaveData) {
+ printf("Error encountered; not saving changes.\n");
+ retval = 4;
+ } // if
+ } else { // if loaded OK
+ retval = 2;
+ } // if/else loaded OK
} // if (device != NULL)
+ poptFreeContext(poptCon);
- return 0;
+ return retval;
} // main
-// Parse command-line options. Returns the number of arguments retrieved
-int ParseOptions(int argc, char* argv[], Options* theOptions, char** device) {
- int opt, i, numOptions = 0;
- int verbose_flag;
-
- // Use getopt() to extract commands and their arguments
- /* getopt_long stores the option index here. */
- int option_index = 0;
-
-// c = getopt_long (argc, argv, "abc:d:f:",
-// long_options, &option_index);
-
- while (((opt = getopt_long(argc, argv, "vl", long_options, &option_index)) != -1)
- && (numOptions < MAX_OPTIONS)) {
- printf("opt is %c, option_index is %d\n", opt, option_index);
- switch (opt) {
- case 'l':
- printf("Entering list option, numOptions = %d!\n", numOptions);
- theOptions[numOptions].theCommand = LIST;
- theOptions[numOptions++].theArgument = NULL;
- break;
- case 'v':
- theOptions[numOptions].theCommand = VERIFY;
- theOptions[numOptions++].theArgument = NULL;
- break;
- default:
- printf("Default switch; opt is %c\n", opt);
- break;
-// abort();
- } // switch
- } // while
-
- // Find non-option arguments. If the user types a legal command, there
- // will be only one of these: The device filename....
- opt = 0;
- printf("Searching for device filename; optind is %d\n", optind);
- for (i = optind; i < argc; i++) {
- *device = argv[i];
- printf("Setting device to %s\n", argv[i]);
- opt++;
- } // for
- if (opt > 1) {
- fprintf(stderr, "Warning! Found stray unrecognized arguments! Program may misbehave!\n");
- } // if
-
- return numOptions;
-} // ParseOptions()
-
-/* // Accept a command and execute it. Returns only when the user
-// wants to exit (such as after a 'w' or 'q' command).
-void MainMenu(char* filename, struct GPTData* theGPT) {
- char command, line[255], buFile[255];
- char* junk;
- int goOn = 1;
- PartTypes typeHelper;
- uint32_t temp1, temp2;
-
- do {
- printf("\nCommand (? for help): ");
- junk = fgets(line, 255, stdin);
- sscanf(line, "%c", &command);
- switch (command) {
- case 'b': case 'B':
- printf("Enter backup filename to save: ");
- junk = fgets(line, 255, stdin);
- sscanf(line, "%s", (char*) &buFile);
- theGPT->SaveGPTBackup(buFile);
- break;
- case 'c': case 'C':
- if (theGPT->GetPartRange(&temp1, &temp2) > 0)
- theGPT->SetName(theGPT->GetPartNum());
- else
- printf("No partitions\n");
- break;
- case 'd': case 'D':
- theGPT->DeletePartition();
- break;
- case 'i': case 'I':
- theGPT->ShowDetails();
- break;
- case 'l': case 'L':
- typeHelper.ShowTypes();
- break;
- case 'n': case 'N':
- theGPT->CreatePartition();
- break;
- case 'o': case 'O':
- printf("This option deletes all partitions and creates a new "
- "protective MBR.\nProceed? ");
- if (GetYN() == 'Y') {
- theGPT->ClearGPTData();
- theGPT->MakeProtectiveMBR();
- } // if
- break;
- case 'p': case 'P':
- theGPT->DisplayGPTData();
- break;
- case 'q': case 'Q':
- goOn = 0;
- break;
- case 'r': case 'R':
- RecoveryMenu(filename, theGPT);
- goOn = 0;
- break;
- case 's': case 'S':
- theGPT->SortGPT();
- printf("You may need to edit /etc/fstab and/or your boot loader configuration!\n");
- break;
- case 't': case 'T':
- theGPT->ChangePartType();
- break;
- case 'v': case 'V':
- if (theGPT->Verify() > 0) { // problems found
- printf("You may be able to correct the problems by using options on the experts\n"
- "menu (press 'x' at the command prompt). Good luck!\n");
- } // if
- break;
- case 'w': case 'W':
- if (theGPT->SaveGPTData() == 1)
- goOn = 0;
- break;
- case 'x': case 'X':
- ExpertsMenu(filename, theGPT);
- goOn = 0;
- break;
- default:
- ShowCommands();
- break;
- } // switch
- } while (goOn);
-} // MainMenu()
-
-void ShowCommands(void) {
- printf("b\tback up GPT data to a file\n");
- printf("c\tchange a partition's name\n");
- printf("d\tdelete a partition\n");
- printf("i\tshow detailed information on a partition\n");
- printf("l\tlist known partition types\n");
- printf("n\tadd a new partition\n");
- printf("o\tcreate a new empty GUID partition table (GPT)\n");
- printf("p\tprint the partition table\n");
- printf("q\tquit without saving changes\n");
- printf("r\trecovery and transformation options (experts only)\n");
- printf("s\tsort partitions\n");
- printf("t\tchange a partition's type code\n");
- printf("v\tverify disk\n");
- printf("w\twrite table to disk and exit\n");
- printf("x\textra functionality (experts only)\n");
- printf("?\tprint this menu\n");
-} // ShowCommands()
+// Extract integer data from argument string, which should be colon-delimited
+uint64_t GetInt(char* argument, int itemNum) {
+ int startPos = -1, endPos = -1;
+ uint64_t retval = 0;
+ string Info;
-// Accept a recovery & transformation menu command. Returns only when the user
-// issues an exit command, such as 'w' or 'q'.
-void RecoveryMenu(char* filename, struct GPTData* theGPT) {
- char command, line[255], buFile[255];
- char* junk;
- PartTypes typeHelper;
- uint32_t temp1;
- int goOn = 1;
+ Info = argument;
+ while (itemNum-- > 0) {
+ startPos = endPos + 1;
+ endPos = Info.find(':', startPos);
+ }
+ if (endPos == string::npos)
+ endPos = Info.length();
+ endPos--;
- do {
- printf("\nrecovery/transformation command (? for help): ");
- junk = fgets(line, 255, stdin);
- sscanf(line, "%c", &command);
- switch (command) {
- case 'b': case 'B':
- theGPT->RebuildMainHeader();
- break;
- case 'c': case 'C':
- printf("Warning! This will probably do weird things if you've converted an MBR to\n"
- "GPT form and haven't yet saved the GPT! Proceed? ");
- if (GetYN() == 'Y')
- theGPT->LoadSecondTableAsMain();
- break;
- case 'd': case 'D':
- theGPT->RebuildSecondHeader();
- break;
- case 'e': case 'E':
- printf("Warning! This will probably do weird things if you've converted an MBR to\n"
- "GPT form and haven't yet saved the GPT! Proceed? ");
- if (GetYN() == 'Y')
- theGPT->LoadMainTable();
- break;
- case 'f': case 'F':
- printf("Warning! This will destroy the currently defined partitions! Proceed? ");
- if (GetYN() == 'Y') {
- if (theGPT->LoadMBR(filename) == 1) { // successful load
- theGPT->XFormPartitions();
- } else {
- printf("Problem loading MBR! GPT is untouched; regenerating protective MBR!\n");
- theGPT->MakeProtectiveMBR();
- } // if/else
- } // if
- break;
- case 'g': case 'G':
- temp1 = theGPT->XFormToMBR();
- if (temp1 > 0) {
- printf("Converted %d partitions. Finalize and exit? ", temp1);
- if (GetYN() == 'Y') {
- if (theGPT->DestroyGPT(0) > 0)
- goOn = 0;
- } else {
- theGPT->MakeProtectiveMBR();
- printf("Note: New protective MBR created.\n");
- } // if/else
- } // if
- break;
- case 'h': case 'H':
- theGPT->MakeHybrid();
- break;
- case 'i': case 'I':
- theGPT->ShowDetails();
- break;
- case 'l': case 'L':
- printf("Enter backup filename to load: ");
- junk = fgets(line, 255, stdin);
- sscanf(line, "%s", (char*) &buFile);
- theGPT->LoadGPTBackup(buFile);
- break;
- case 'm': case 'M':
- MainMenu(filename, theGPT);
- goOn = 0;
- break;
- case 'o': case 'O':
- theGPT->DisplayMBRData();
- break;
- case 'p': case 'P':
- theGPT->DisplayGPTData();
- break;
- case 'q': case 'Q':
- goOn = 0;
- break;
- case 't': case 'T':
- theGPT->XFormDisklabel();
- break;
- case 'v': case 'V':
- theGPT->Verify();
- break;
- case 'w': case 'W':
- if (theGPT->SaveGPTData() == 1) {
- goOn = 0;
- } // if
- break;
- case 'x': case 'X':
- ExpertsMenu(filename, theGPT);
- goOn = 0;
- break;
- default:
- ShowRecoveryCommands();
- break;
- } // switch
- } while (goOn);
-} // RecoveryMenu()
+ sscanf(Info.substr(startPos, endPos - startPos + 1).c_str(), "%llu", &retval);
+/* printf("In GetInt(), startPos = %d, endPos = %d, retval = %llu\n", startPos,
+ endPos, (unsigned long long) retval); */
+ return retval;
+} // GetInt()
-void ShowRecoveryCommands(void) {
- printf("b\tuse backup GPT header (rebuilding main)\n");
- printf("c\tload backup partition table from disk (rebuilding main)\n");
- printf("d\tuse main GPT header (rebuilding backup)\n");
- printf("e\tload main partition table from disk (rebuilding backup)\n");
- printf("f\tload MBR and build fresh GPT from it\n");
- printf("g\tconvert GPT into MBR and exit\n");
- printf("h\tmake hybrid MBR\n");
- printf("i\tshow detailed information on a partition\n");
- printf("l\tload partition data from a backup file\n");
- printf("m\treturn to main menu\n");
- printf("o\tprint protective MBR data\n");
- printf("p\tprint the partition table\n");
- printf("q\tquit without saving changes\n");
- printf("t\ttransform BSD disklabel partition\n");
- printf("v\tverify disk\n");
- printf("w\twrite table to disk and exit\n");
- printf("x\textra functionality (experts only)\n");
- printf("?\tprint this menu\n");
-} // ShowRecoveryCommands()
+// Extract string data from argument string, which should be colon-delimited
+string GetString(char* argument, int itemNum) {
+ int startPos = -1, endPos = -1;
+ string Info;
-// Accept an experts' menu command. Returns only after the user
-// selects an exit command, such as 'w' or 'q'.
-void ExpertsMenu(char* filename, struct GPTData* theGPT) {
- char command, line[255];
- char* junk;
- PartTypes typeHelper;
- uint32_t pn;
- uint32_t temp1, temp2;
- int goOn = 1;
-
- do {
- printf("\nExpert command (? for help): ");
- junk = fgets(line, 255, stdin);
- sscanf(line, "%c", &command);
- switch (command) {
- case 'a': case 'A':
- if (theGPT->GetPartRange(&temp1, &temp2) > 0)
- theGPT->SetAttributes(theGPT->GetPartNum());
- else
- printf("No partitions\n");
- break;
- case 'c': case 'C':
- if (theGPT->GetPartRange(&temp1, &temp2) > 0) {
- pn = theGPT->GetPartNum();
- printf("Enter the partition's new unique GUID:\n");
- theGPT->SetPartitionGUID(pn, GetGUID());
- } else printf("No partitions\n");
- break;
- case 'd': case 'D':
- printf("The number of logical sectors per physical sector is %d.\n",
- theGPT->GetAlignment());
- break;
- case 'e': case 'E':
- printf("Relocating backup data structures to the end of the disk\n");
- theGPT->MoveSecondHeaderToEnd();
- break;
- case 'g': case 'G':
- printf("Enter the disk's unique GUID:\n");
- theGPT->SetDiskGUID(GetGUID());
- break;
- case 'i': case 'I':
- theGPT->ShowDetails();
- break;
- case 'l': case 'L':
- temp1 = GetNumber(1, 128, 8, "Enter the number of logical sectors in a physical sector on the\ndisk (1-128, default = 8): ");
- theGPT->SetAlignment(temp1);
- break;
- case 'm': case 'M':
- MainMenu(filename, theGPT);
- goOn = 0;
- break;
- case 'n': case 'N':
- theGPT->MakeProtectiveMBR();
- break;
- case 'o': case 'O':
- theGPT->DisplayMBRData();
- break;
- case 'p': case 'P':
- theGPT->DisplayGPTData();
- break;
- case 'q': case 'Q':
- goOn = 0;
- break;
- case 'r': case 'R':
- RecoveryMenu(filename, theGPT);
- goOn = 0;
- break;
- case 's': case 'S':
- theGPT->ResizePartitionTable();
- break;
- case 'v': case 'V':
- theGPT->Verify();
- break;
- case 'w': case 'W':
- if (theGPT->SaveGPTData() == 1) {
- goOn = 0;
- } // if
- break;
- case 'z': case 'Z':
- if (theGPT->DestroyGPT() == 1) {
- goOn = 0;
- }
- break;
- default:
- ShowExpertCommands();
- break;
- } // switch
- } while (goOn);
-} // ExpertsMenu()
+ Info = argument;
+ while (itemNum-- > 0) {
+ startPos = endPos + 1;
+ endPos = Info.find(':', startPos);
+ }
+ if (endPos == string::npos)
+ endPos = Info.length();
+ endPos--;
-void ShowExpertCommands(void) {
- printf("a\tset attributes\n");
- printf("c\tchange partition GUID\n");
- printf("d\tdisplay the number of logical sectors per physical sector\n");
- printf("e\trelocate backup data structures to the end of the disk\n");
- printf("g\tchange disk GUID\n");
- printf("i\tshow detailed information on a partition\n");
- printf("b\tset the number of logical sectors per physical sector\n");
- printf("m\treturn to main menu\n");
- printf("n\tcreate a new protective MBR\n");
- printf("o\tprint protective MBR data\n");
- printf("p\tprint the partition table\n");
- printf("q\tquit without saving changes\n");
- printf("r\trecovery and transformation options (experts only)\n");
- printf("s\tresize partition table\n");
- printf("v\tverify disk\n");
- printf("w\twrite table to disk and exit\n");
- printf("z\tzap (destroy) GPT data structures and exit\n");
- printf("?\tprint this menu\n");
-} // ShowExpertCommands()
-*/
+ return Info.substr(startPos, endPos - startPos + 1);
+} // GetString()