Anonymous avatar Anonymous committed d94d268

Comments (0)

Files changed (9)

+
+-----------------------------------------------------------------------------
+
+This file is part of GNU fdisk 
+Copyright (C) 2006 Free Software Foundation Inc.
+
+This file may be modified and/or distributed without restriction.  This is
+not an invitation to misrepresent the history of GNU fdisk.
+
 DEFS = -DLOCALEDIR=\"$(localedir)\" @DEFS@
 LIBS = @LIBINTL@ @LIBS@
 
-sbin_PROGRAMS = cfdisk
+sbin_PROGRAMS = cfdisk fdisk
+
+fdisk_SOURCES = main.c		\
+		command.c	\
+		command.h	\
+		fdisk.c  	\
+		strlist.c	\
+		strlist.h	\
+		ui.c		\
+		ui.h
+
+fdisk_LDADD = $(PARTED_LIBS)
+
 
 cfdisk_SOURCES = cfdisk.c	\
 		common.c	\
         {NULL, 0, NULL, NULL}
 };
 
-
+/* Help should go here */
 static const char *help = N_(
      "Join us now and share the software;\n"
      "You'll be free, hackers, you'll be free.\n"
+/*
+    GNU fdisk - a clone of Linux fdisk.
+    This file originally from GNU Parted.
+
+    Copyright (C) 1999, 2000, 2006 Free Software Foundation, 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+*/
+
+#include "command.h"
+#include "ui.h"
+
+#include <parted/debug.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+FdiskCommand*
+fdisk_command_create (const StrList* names,
+		int (*method) (PedDisk** disk),
+		const StrList* summary,
+		const StrList* help,
+                const int non_interactive)
+{
+	FdiskCommand*	cmd;
+
+	cmd = malloc (sizeof (FdiskCommand));
+
+	assert(cmd != NULL);
+
+        if (non_interactive)
+                cmd->non_interactive = 1;
+        else
+                cmd->non_interactive = 0;
+                
+	cmd->names = (StrList*) names;
+	cmd->method = method;
+	cmd->summary = (StrList*) summary;
+	cmd->help = (StrList*) help;
+
+	return cmd;
+}
+
+void
+fdisk_command_destroy (FdiskCommand* cmd)
+{
+	str_list_destroy (cmd->names);
+	str_list_destroy (cmd->summary);
+	str_list_destroy (cmd->help);
+	free (cmd);
+}
+
+void
+fdisk_command_register (FdiskCommand** list, FdiskCommand* cmd)
+{
+	int	i;
+
+	for (i = 0; list [i]; i++);
+	
+	list [i] = cmd;
+	list [i + 1] = (FdiskCommand*) NULL;
+}
+
+FdiskCommand*
+fdisk_command_get (FdiskCommand** list, char* name)
+{
+	int		i;
+	int		partial_match = -1;
+	int		ambiguous = 0;
+
+	if (!name)
+		return NULL;
+
+	for (i=0; list [i]; i++) {
+		switch (str_list_match_any (list [i]->names, name)) {
+		case 2:
+			return list [i];
+
+		case 1:
+			if (!ambiguous) {
+				if (partial_match == -1) {
+					partial_match = i;
+				} else {
+					partial_match = -1;
+					ambiguous = 1;
+				}
+			}
+		}
+	}
+
+	if (partial_match == -1)
+		return NULL;
+	else
+		return list [partial_match];
+}
+
+StrList*
+fdisk_command_get_names (FdiskCommand** list)
+{
+	FdiskCommand**	walk;
+	StrList*	result = NULL;
+
+	for (walk = list; *walk; walk++)
+		result = str_list_join (result,
+					str_list_duplicate ((*walk)->names));
+	return result;
+}
+
+void
+fdisk_command_print_summary (FdiskCommand* cmd)
+{
+          if (cmd) {
+	          printf ("  ");
+	          str_list_print_wrap (cmd->summary, fdisk_screen_width(), 2, 8);
+   	  	  printf ("\n");
+	  }
+}
+
+void
+fdisk_command_print_help (FdiskCommand* cmd)
+{
+	fdisk_command_print_summary (cmd);
+	if (cmd->help) {
+		printf ("\n\t");
+		str_list_print_wrap (cmd->help, fdisk_screen_width(), 8, 8);
+	}
+}
+
+int
+fdisk_command_run (FdiskCommand* cmd, PedDisk **disk)
+{
+        return cmd->method (disk);
+}
+
+/*
+    GNU fdisk - a clone of Linux fdisk.
+    This file originally from GNU Parted.
+
+    Copyright (C) 1999, 2000, 2006 Free Software Foundation, 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+*/
+
+#ifndef COMMAND_H_INCLUDED
+#define COMMAND_H_INCLUDED
+
+#include <parted/parted.h>
+#include "strlist.h"
+
+typedef struct {
+	StrList*	names;
+	int		(*method) (PedDisk** disk);
+	StrList*	summary;
+	StrList*	help;
+        int             non_interactive:1;	
+} FdiskCommand;
+
+extern FdiskCommand* fdisk_command_create (const StrList* names,
+				int (*method) (PedDisk** disk),
+				const StrList* summary,
+				const StrList* help,
+                                int non_interactive);
+extern void fdisk_command_destroy (FdiskCommand* cmd);
+void fdisk_command_register (FdiskCommand** list, FdiskCommand* cmd);
+
+extern FdiskCommand* fdisk_command_get (FdiskCommand** list, char* name);
+extern StrList* fdisk_command_get_names (FdiskCommand** list);
+extern void fdisk_command_print_summary (FdiskCommand* cmd);
+extern void fdisk_command_print_help (FdiskCommand* cmd);
+extern int fdisk_command_run (FdiskCommand* cmd, PedDisk** disk);
+#endif /* COMMAND_H_INCLUDED */
+
+/*
+    GNU fdisk - a clone of Linux fdisk.
+
+    Copyright (C) 2006
+    Free Software Foundation, 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+*/
+
+#include "../config.h"
+#include "command.h"
+#include "ui.h"
+
+#define N_(String) String
+#if ENABLE_NLS
+#  include <libintl.h>
+#  include <locale.h>
+#  define _(String) dgettext (PACKAGE, String)
+#else
+#  define _(String) (String)
+#endif /* ENABLE_NLS */
+
+#include <parted/parted.h>
+#include <parted/debug.h>
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#ifdef ENABLE_MTRACE
+#include <mcheck.h>
+#endif
+
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+
+/* minimum amount of free space to leave, or maximum amount to gobble up,
+ * depending on your POV ;)
+ */
+#define MIN_FREESPACE		(1000 * 2)	/* 1000k */
+
+#define MEGABYTE_SECTORS (PED_MEGABYTE_SIZE / PED_SECTOR_SIZE_DEFAULT)
+
+#define BSD_DISKMAGIC 	((u_int32_t)0x82564557)
+#define BSD_BSIZE	8192
+
+struct bsdlabel {
+  unsigned int magic;
+  char unused[128];
+  unsigned int magic2;
+};
+
+typedef struct {
+	time_t	last_update;
+	time_t	predicted_time_left;
+} TimerContext;
+
+static struct option	options[] = {
+	/* name, has-arg, string-return-val, char-return-val */
+	{"help",	0, NULL, 'h'},
+	{"list",        0, NULL, 'l'},
+	{"interactive",	0, NULL, 'i'},
+	{"script",	0, NULL, 's'},
+	{"version",	0, NULL, 'v'},
+	{NULL,		0, NULL, 0}
+};
+#endif
+
+static char*	options_help [][2] = {
+	{"help",	N_("displays this help message")},
+	{"list",        N_("List partition table(s)")},
+	{"interactive",	N_("where necessary, prompts for user intervention")},
+	{"script",	N_("never prompts for user intervention")},
+	{"version",	N_("displays the version")},
+	{NULL,		NULL}
+};
+
+int fdisk_opt_script_mode;
+int fdisk_list_table;
+
+static char* number_msg = N_(
+"NUMBER is the partition number used by Linux.  On MS-DOS disk labels, the "
+"primary partitions number from 1 to 4, logical partitions from 5 onwards.\n");
+
+static char* label_type_msg_start = N_("LABEL-TYPE is one of: ");
+static char* flag_msg_start =	N_("FLAG is one of: ");
+static char* unit_msg_start =	N_("UNIT is one of: ");
+static char* part_type_msg =	N_("PART-TYPE is one of: primary, logical, "
+			           "extended\n");
+static char* fs_type_msg_start = N_("FS-TYPE is one of: ");
+static char* start_end_msg =	N_("START and END are disk locations, such as "
+		"4GB or 10%.  Negative values count from the end of the disk.  "
+                "For example, -1s specifies exactly the last sector.\n");
+static char* state_msg =	N_("STATE is one of: on, off\n");
+static char* device_msg =	N_("DEVICE is usually /dev/hda or /dev/sda\n");
+static char* name_msg =		N_("NAME is any word you want\n");
+static char* resize_msg_start = N_("The partition must have one of the "
+				   "following FS-TYPEs: ");
+
+static char* label_type_msg;
+static char* flag_msg;
+static char* unit_msg;
+
+static char* mkfs_fs_type_msg;
+static char* mkpart_fs_type_msg;
+static char* resize_fs_type_msg;
+
+static PedTimer* timer;
+static TimerContext timer_context;
+static FdiskCommand* fdisk_main_menu_commands[256] = {NULL};
+static FdiskCommand* fdisk_ex_menu_commands[256] = {NULL};
+static int in_ex_menu = 0;
+
+/* 0 = Disk was not altered.
+   1 = Disk was altered. */
+static int need_commit = 0;
+
+/* 0 = Sectors are the default unit.
+   1 = Cylinders are the default unit (Default).*/
+static int cylinder_unit = 1;
+
+static void _done (PedDevice* dev);
+
+static void
+_timer_handler (PedTimer* timer, void* context)
+{
+	TimerContext*	tcontext = (TimerContext*) context;
+	int		draw_this_time;
+
+	if (fdisk_opt_script_mode || !isatty(fileno(stdout)))
+		return;
+
+	if (tcontext->last_update != timer->now && timer->now > timer->start) {
+		tcontext->predicted_time_left
+			= timer->predicted_end - timer->now;
+		tcontext->last_update = timer->now;
+		draw_this_time = 1;
+	} else {
+		draw_this_time = 0;
+	}
+
+	if (draw_this_time) {
+		fdisk_wipe_line ();
+
+		if (timer->state_name)
+			printf ("%s... ", timer->state_name);
+		printf (_("%0.f%%\t(time left %.2d:%.2d)"),
+			100.0 * timer->frac,
+			tcontext->predicted_time_left / 60,
+			tcontext->predicted_time_left % 60);
+
+		fflush (stdout);
+	}
+}
+
+static int
+_partition_warn_busy (PedPartition* part)
+{
+	char* path = ped_partition_get_path (part);
+
+	if (ped_partition_is_busy (part)) {
+		ped_exception_throw (
+			PED_EXCEPTION_ERROR,
+			PED_EXCEPTION_CANCEL,
+			_("Partition %s is being used.  You must unmount it "
+			  "before you modify it with Parted."),
+			path);
+		ped_free (path);
+		return 0;
+	}
+	ped_free (path);
+	return 1;
+}
+
+static int
+_disk_warn_busy (PedDisk* disk)
+{
+	if (ped_device_is_busy (disk->dev)) {
+		if (ped_exception_throw (
+			PED_EXCEPTION_WARNING,
+			PED_EXCEPTION_IGNORE_CANCEL,
+			_("Partition(s) on %s are being used."),
+			disk->dev->path)
+				!= PED_EXCEPTION_IGNORE)
+			return 0;
+	}
+	return 1;
+}
+
+/* This function changes "sector" to "new_sector" if the new value lies
+ * within the required range.
+ */
+static int
+snap (PedSector* sector, PedSector new_sector, PedGeometry* range)
+{
+	PED_ASSERT (ped_geometry_test_sector_inside (range, *sector), return 0);
+	if (!ped_geometry_test_sector_inside (range, new_sector))
+		return 0;
+	*sector = new_sector;
+	return 1;
+}
+
+typedef enum {
+	MOVE_NO		= 0,
+	MOVE_STILL	= 1,
+	MOVE_UP		= 2,
+	MOVE_DOWN	= 4
+} EMoves;
+
+enum { /* Don't change these values */
+	SECT_START	=  0,
+	SECT_END	= -1
+};
+
+/* Find the prefered way to adjust the sector s inside range.
+ * If a move isn't allowed or is out of range it can't be selected.
+ * what contains SECT_START if the sector to adjust is a start sector
+ * or SECT_END if it's an end one.
+ * The prefered move is to the nearest allowed boundary of the part
+ * partition (if at equal distance: to start if SECT_START or to end
+ * if SECT_END).
+ * The distance is returned in dist.
+ */
+static EMoves
+prefer_snap (PedSector s, int what, PedGeometry* range, EMoves* allow,
+	     PedPartition* part, PedSector* dist)
+{
+	PedSector up_dist = -1, down_dist = -1;
+	PedSector new_sect;
+	EMoves move;
+
+	PED_ASSERT (what == SECT_START || what == SECT_END, return 0);
+
+	if (!(*allow & (MOVE_UP | MOVE_DOWN))) {
+		*dist = 0;
+		return MOVE_STILL;
+	}
+
+	if (*allow & MOVE_UP) {
+		new_sect = part->geom.end + 1 + what;
+		if (ped_geometry_test_sector_inside (range, new_sect))
+			up_dist = new_sect - s;
+		else
+			*allow &= ~MOVE_UP;
+	}
+
+	if (*allow & MOVE_DOWN) {
+		new_sect = part->geom.start + what;
+		if (ped_geometry_test_sector_inside (range, new_sect))
+			down_dist = s - new_sect;
+		else
+			*allow &= ~MOVE_DOWN;
+	}
+
+	move = MOVE_STILL;
+	if ((*allow & MOVE_UP) && (*allow & MOVE_DOWN)) {
+		if (down_dist < up_dist || (down_dist == up_dist
+					    && what == SECT_START) )
+			move = MOVE_DOWN;
+		else if (up_dist < down_dist || (down_dist == up_dist
+						 && what == SECT_END) )
+			move = MOVE_UP;
+		else
+			PED_ASSERT (0, return 0);
+	}
+
+	*dist = ( move == MOVE_DOWN ? down_dist :
+	        ( move == MOVE_UP   ? up_dist   :
+		  0 ) );
+	return move;
+}
+
+/* Snaps a partition to nearby partition boundaries.  This is useful for
+ * gobbling up small amounts of free space, and also for reinterpreting small
+ * changes to a partition as non-changes (eg: perhaps the user only wanted to
+ * resize the end of a partition).
+ * 	Note that this isn't the end of the story... this function is
+ * always called before the constraint solver kicks in.  So you don't need to
+ * worry too much about inadvertantly creating overlapping partitions, etc.
+ */
+static void
+snap_to_boundaries (PedGeometry* new_geom, PedGeometry* old_geom,
+		    PedDisk* disk,
+		    PedGeometry* start_range, PedGeometry* end_range)
+{
+	PedPartition*	start_part;
+	PedPartition*	end_part;
+	PedSector	start = new_geom->start;
+	PedSector	end = new_geom->end;
+	PedSector	start_dist = -1, end_dist = -1;
+	EMoves		start_allow, end_allow, start_want, end_want;
+	int		adjacent;
+
+	start_want = end_want = MOVE_NO;
+	start_allow = end_allow = MOVE_STILL | MOVE_UP | MOVE_DOWN;
+
+	start_part = ped_disk_get_partition_by_sector (disk, start);
+	end_part = ped_disk_get_partition_by_sector (disk, end);
+	adjacent = (start_part->geom.end + 1 == end_part->geom.start);
+
+	/* If we can snap to old_geom, then we will... */
+	/* and this will enforce the snaped positions  */
+	if (old_geom) {
+		if (snap (&start, old_geom->start, start_range))
+			start_allow = MOVE_STILL;
+		if (snap (&end, old_geom->end, end_range))
+			end_allow = MOVE_STILL;
+	}
+
+	/* If start and end are on the same partition, we */
+	/* don't allow them to cross. */
+	if (start_part == end_part) {
+		start_allow &= ~MOVE_UP;
+		end_allow &= ~MOVE_DOWN;
+	}
+
+	/* Let's find our way */
+	start_want = prefer_snap (start, SECT_START, start_range, &start_allow,
+				  start_part, &start_dist );
+	end_want = prefer_snap (end, SECT_END, end_range, &end_allow,
+				end_part, &end_dist );
+
+	PED_ASSERT (start_dist >= 0 && end_dist >= 0, return);
+
+	/* If start and end are on adjacent partitions,    */
+	/* and if they would prefer crossing, then refrain */
+	/* the farest to do so. */
+	if (adjacent && start_want == MOVE_UP && end_want == MOVE_DOWN) {
+		if (end_dist < start_dist) {
+			start_allow &= ~MOVE_UP;
+			start_want = prefer_snap (start, SECT_START,
+						  start_range, &start_allow,
+						  start_part, &start_dist );
+			PED_ASSERT (start_dist >= 0, return);
+		} else {
+			end_allow &= ~MOVE_DOWN;
+			end_want = prefer_snap (end, SECT_END,
+						end_range, &end_allow,
+						end_part, &end_dist );
+			PED_ASSERT (end_dist >= 0, return);
+		}
+	}
+
+	/* New positions */
+	start = ( start_want == MOVE_DOWN ? start_part->geom.start :
+		( start_want == MOVE_UP ? start_part->geom.end + 1 :
+		  start ) );
+	end = ( end_want == MOVE_DOWN ? end_part->geom.start - 1 :
+	      ( end_want == MOVE_UP ? end_part->geom.end :
+	        end ) );
+	PED_ASSERT (ped_geometry_test_sector_inside(start_range,start), return);
+	PED_ASSERT (ped_geometry_test_sector_inside (end_range, end), return);
+	PED_ASSERT (start <= end, return);
+	ped_geometry_set (new_geom, start, end - start + 1);
+}
+
+/* This functions constructs a constraint from the following information:
+ * 	start, is_start_exact, end, is_end_exact.
+ * 	
+ * If is_start_exact == 1, then the constraint requires start be as given in
+ * "start".  Otherwise, the constraint does not set any requirements on the
+ * start.
+ */
+static PedConstraint*
+constraint_from_start_end (PedDevice* dev, PedGeometry* range_start,
+                           PedGeometry* range_end)
+{
+	return ped_constraint_new (ped_alignment_any, ped_alignment_any,
+		range_start, range_end, 1, dev->length);
+}
+
+static PedConstraint*
+constraint_intersect_and_destroy (PedConstraint* a, PedConstraint* b)
+{
+	PedConstraint* result = ped_constraint_intersect (a, b);
+	ped_constraint_destroy (a);
+	ped_constraint_destroy (b);
+	return result;
+}
+
+static void 
+help_on (char* topic) 
+{ 
+        FdiskCommand*	cmd; 
+  
+        cmd = fdisk_command_get (fdisk_main_menu_commands, topic); 
+        if (!cmd) return;
+  
+        fdisk_command_print_help (cmd); 
+}
+
+static int
+do_check (PedDisk** disk)
+{
+	PedFileSystem*	fs;
+	PedPartition*	part = NULL;
+	int		part_num;
+
+	if (!fdisk_command_line_get_partition (_("Partition number?"), *disk, &part))
+		goto error;
+	if (!_partition_warn_busy (part))
+		goto error;
+
+	if (!ped_disk_check (*disk))
+		goto error;
+
+	fs = ped_file_system_open (&part->geom);
+	if (!fs)
+		goto error;
+	if (!ped_file_system_check (fs, timer))
+		goto error_close_fs;
+	ped_file_system_close (fs);
+	return 1;
+
+error_close_fs:
+	ped_file_system_close (fs);
+error:
+	return 0;
+}
+
+static int
+do_cp (PedDisk** disk)
+{
+	PedDisk*		src_disk;
+	PedDisk*		dst_disk;
+	PedDevice*		src_device;
+	PedPartition*		src = NULL;
+	PedPartition*		dst = NULL;
+	PedFileSystem*		src_fs;
+	PedFileSystem*		dst_fs;
+	PedFileSystemType*	dst_fs_type;
+
+	if (!command_line_prompt_boolean_question 
+	(_("WARNING: mkfs writes all data to disk automatically, continue"))) 
+		return 1;
+
+	dst_disk = ped_disk_new ((*disk)->dev);
+	if (!dst_disk)
+		goto error;
+
+	src_disk = dst_disk;
+	if (!fdisk_command_line_is_integer ()) {
+		if (!fdisk_command_line_get_disk (_("Source device?"), &src_disk))
+			goto error;
+	}
+
+	if (!fdisk_command_line_get_partition (_("Source partition number?"),
+					       src_disk, &src))
+		goto error;
+	if (src->type == PED_PARTITION_EXTENDED) {
+		ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+			_("Can't copy an extended partition."));
+		goto error;
+	}
+	if (!_partition_warn_busy (src))
+		goto error;
+
+	if (!fdisk_command_line_get_partition (_("Destination partition number?"),
+					 dst_disk, &dst))
+		goto error;
+	if (!_partition_warn_busy (dst))
+		goto error;
+
+/* do the copy */
+	src_fs = ped_file_system_open (&src->geom);
+	if (!src_fs)
+		goto error;
+	dst_fs = ped_file_system_copy (src_fs, &dst->geom, timer);
+	if (!dst_fs)
+		goto error_close_src_fs;
+	dst_fs_type = dst_fs->type;	/* may be different to src_fs->type */
+	ped_file_system_close (src_fs);
+	ped_file_system_close (dst_fs);
+
+/* update the partition table, close disks */
+	if (!ped_partition_set_system (dst, dst_fs_type))
+		goto error;
+	if (!ped_disk_commit (dst_disk))
+		goto error;
+	if (src_disk != dst_disk)
+		ped_disk_destroy (src_disk);
+	return 1;
+
+error_close_src_fs:
+	ped_file_system_close (src_fs);
+error:
+	return 0;
+}
+
+void 
+fdisk_print_options_help ()
+{ 
+        int		i; 
+
+ 	for (i=0; options_help [i][0]; i++) { 
+ 		printf ("  -%c, --%-23.23s %s\n", 
+ 			options_help [i][0][0], 
+ 			options_help [i][0], 
+ 			_(options_help [i][1])); 
+ 	} 
+}
+
+void
+fdisk_print_commands_help (FdiskCommand* cmds[])
+{
+	 int		i;
+  
+	if (cmds) {
+	for (i=0; cmds [i]; i++)
+      		fdisk_command_print_summary (cmds [i]);
+	} else {
+		if (in_ex_menu) {
+			for (i=0; fdisk_ex_menu_commands [i]; i++)
+				fdisk_command_print_summary (fdisk_ex_menu_commands [i]);
+    		} else {
+      			for (i=0; fdisk_ex_menu_commands [i]; i++)
+				fdisk_command_print_summary (fdisk_main_menu_commands [i]);
+    		}
+	}
+}
+
+static int
+do_help(PedDisk** disk)
+{
+	printf (_("Command action\n"));
+	if (in_ex_menu)
+		fdisk_print_commands_help(fdisk_ex_menu_commands);
+	else 
+	        fdisk_print_commands_help(fdisk_main_menu_commands);
+	return 1;
+}
+
+static int
+do_msdos_mklabel (PedDisk** disk)
+{
+	PedDevice               *dev = (*disk)->dev; /* Save the address of dev, 
+							because we are going to 
+							destroy disk. */ 
+	const PedDiskType*	type = ped_disk_type_get ("msdos");
+
+	ped_exception_fetch_all ();
+
+	if (!(*disk)) ped_exception_catch ();
+	ped_exception_leave_all ();
+
+	if (*disk) {
+		if (!_disk_warn_busy (*disk)) {
+			ped_disk_destroy (*disk);
+			goto error;
+		}
+		ped_disk_destroy (*disk);
+	}
+
+	*disk = ped_disk_new_fresh (dev, type);
+	if (!*disk)
+		goto error;
+
+	if (!need_commit) need_commit = 1;
+	
+	return 1;
+
+error:
+	return 0;
+}
+
+static int
+do_sun_mklabel (PedDisk** disk)
+{
+	PedDevice               *dev = (*disk)->dev; /* Save the address of dev, 
+							because we are going to 
+							destroy disk. */ 
+	const PedDiskType*	type = ped_disk_type_get ("sun");
+
+	ped_exception_fetch_all ();
+
+	if (!(*disk)) ped_exception_catch ();
+	ped_exception_leave_all ();
+
+	if (*disk) {
+		if (!_disk_warn_busy (*disk)) {
+			ped_disk_destroy (*disk);
+			goto error;
+		}
+		ped_disk_destroy (*disk);
+	}
+
+	*disk = ped_disk_new_fresh (dev, type);
+	if (!*disk)
+		goto error;
+
+	if (!need_commit) need_commit = 1;
+	
+	return 1;
+
+error:
+	return 0;
+}
+
+static int
+do_mklabel (PedDisk** disk)
+{
+	PedDevice               *dev = (*disk)->dev; /* Save the address of dev, 
+							because we are going to 
+							destroy disk. */ 
+	const PedDiskType*	type = ped_disk_probe (dev);
+
+	ped_exception_fetch_all ();
+
+	if (!(*disk)) ped_exception_catch ();
+	ped_exception_leave_all ();
+
+	if (*disk) {
+		if (!_disk_warn_busy (*disk)) {
+			ped_disk_destroy (*disk);
+			goto error;
+		}
+		ped_disk_destroy (*disk);
+	}
+
+	if (!fdisk_command_line_get_disk_type (_("New disk label type?"), &type))
+		goto error;
+
+	*disk = ped_disk_new_fresh (dev, type);
+	if (!*disk)
+		goto error;
+
+	if (!need_commit) need_commit = 1;
+	
+	return 1;
+
+error:
+	return 0;
+}
+
+static int
+do_mkfs (PedDisk** disk)
+{
+	PedPartition*		part = NULL;
+	const PedFileSystemType* type = ped_file_system_type_get ("ext2");
+	PedFileSystem*		fs;
+
+	if (!*disk)
+		goto error;
+
+	if (!command_line_prompt_boolean_question 
+	(_("WARNING: mkfs writes all data to disk automatically, continue"))) 
+	        return 1;
+	
+	if (!fdisk_command_line_get_partition (_("Partition number?"), *disk, &part))
+		goto error;
+	if (!_partition_warn_busy (part))
+		goto error;
+	if (!fdisk_command_line_get_fs_type (_("File system?"), &type))
+		goto error;
+
+	fs = ped_file_system_create (&part->geom, type, timer);
+	if (!fs)
+		goto error;
+	ped_file_system_close (fs);
+
+	if (!ped_partition_set_system (part, type))
+		goto error;
+	if (!ped_disk_commit (*disk))
+		goto error;
+	
+	return 1;
+
+error:
+	return 0;
+}
+
+static int
+do_mkpart (PedDisk **disk)
+{
+	PedPartition* 		 part;
+	PedPartitionType	 part_type;
+	const PedFileSystemType* fs_type = ped_file_system_type_get ("ext2");
+	PedSector		 start = 0, end = 0;
+	PedGeometry 		 *range_start = NULL, *range_end = NULL;
+	PedConstraint*		 constraint;
+	char*			 peek_word;
+
+	if (!fdisk_command_line_get_part_type (_("Partition type?"), *disk,
+					       &part_type))
+		goto error;
+
+	peek_word = fdisk_command_line_peek_word ();
+	if (part_type == PED_PARTITION_EXTENDED
+	    || (peek_word && isdigit (peek_word[0]))) {
+		fs_type = NULL;
+	} else {
+		if (!fdisk_command_line_get_fs_type (_("File system type?"),
+					       &fs_type))
+			goto error;
+	}
+	if (peek_word)
+		ped_free (peek_word);
+
+	if (!fdisk_command_line_get_sector (_("Start?"), (*disk)->dev, &start, &range_start))
+		goto error;
+	if (!fdisk_command_line_get_sector (_("End?"), (*disk)->dev, &end, &range_end))
+		goto error;
+	part = ped_partition_new (*disk, part_type, fs_type, start, end);
+	if (!part)
+		goto error;
+	snap_to_boundaries (&part->geom, NULL, *disk, range_start, range_end);
+	constraint = constraint_from_start_end ((*disk)->dev, range_start, range_end);
+	if (!constraint)
+		goto error_destroy_part;
+	if (!ped_disk_add_partition (*disk, part, constraint))
+		goto error_destroy_constraint;
+	ped_constraint_destroy (constraint);
+
+	if (range_start != NULL)
+		ped_geometry_destroy (range_start);
+	if (range_end != NULL)
+		ped_geometry_destroy (range_end);
+
+	if (!need_commit) need_commit = 1;
+
+	return 1;
+
+error_destroy_constraint:
+	ped_constraint_destroy (constraint);
+error_destroy_part:
+	ped_partition_destroy (part);
+error:
+	if (range_start != NULL)
+		ped_geometry_destroy (range_start);
+	if (range_end != NULL)
+		ped_geometry_destroy (range_end);
+	return 0;
+}
+
+static int
+do_mkpartfs (PedDisk** disk)
+{
+	PedPartition*       part;
+	PedPartitionType    part_type;
+	const PedFileSystemType* fs_type = ped_file_system_type_get ("ext2");
+	PedSector           start = 0, end = 0;
+	PedGeometry         *range_start = NULL, *range_end = NULL;
+	PedConstraint*      constraint;
+	PedFileSystem*      fs;
+
+	if (!*disk)
+		goto error;
+
+	if (!command_line_prompt_boolean_question 
+	(_("WARNING: mkpartfs writes all data to disk automatically, continue"))) 
+	        return 1;
+
+	if (!fdisk_command_line_get_part_type (_("Partition type?"), *disk,
+					 &part_type))
+		goto error;
+
+	if (part_type == PED_PARTITION_EXTENDED) {
+		ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+			_("An extended partition cannot hold a file system.  "
+			  "Did you want mkpart?"));
+		goto error;
+	}
+
+	if (!fdisk_command_line_get_fs_type (_("File system type?"), &fs_type))
+		goto error;
+	if (!fdisk_command_line_get_sector (_("Start?"), (*disk)->dev, &start,
+				      &range_start))
+		goto error;
+	if (!fdisk_command_line_get_sector (_("End?"), (*disk)->dev, &end, &range_end))
+		goto error;
+	part = ped_partition_new (*disk, part_type, fs_type, start, end);
+	if (!part)
+		goto error;
+	snap_to_boundaries (&part->geom, NULL, *disk, range_start, range_end);
+	constraint = constraint_intersect_and_destroy (
+			ped_file_system_get_create_constraint (fs_type, (*disk)->dev),
+			constraint_from_start_end ((*disk)->dev, range_start, range_end));
+	if (!ped_disk_add_partition (*disk, part, constraint))
+		goto error_destroy_constraint;
+	ped_constraint_destroy (constraint);
+
+	fs = ped_file_system_create (&part->geom, fs_type, timer);
+	if (!fs) 
+		goto error;
+	ped_file_system_close (fs);
+
+	if (!ped_partition_set_system (part, fs_type))
+		goto error;
+
+	if (!ped_disk_commit (*disk))
+		goto error;
+
+	if (need_commit) need_commit = 0;
+
+	if (range_start != NULL)
+		ped_geometry_destroy (range_start);
+	if (range_end != NULL)
+		ped_geometry_destroy (range_end);
+	return 1;
+
+error_destroy_constraint:
+	ped_constraint_destroy (constraint);
+error_destroy_part:
+	ped_partition_destroy (part);
+error:
+	if (range_start != NULL)
+		ped_geometry_destroy (range_start);
+	if (range_end != NULL)
+		ped_geometry_destroy (range_end);
+	return 0;
+}
+
+static int
+do_move (PedDisk** disk)
+{
+	PedPartition*	part = NULL;
+	PedFileSystem*	fs;
+	PedFileSystem*	fs_copy;
+	PedConstraint*	constraint;
+	PedSector	start = 0, end = 0;
+	PedGeometry     *range_start = NULL, *range_end = NULL;
+	PedGeometry	old_geom, new_geom;
+
+	if (!*disk)
+		goto error;
+
+	if (!command_line_prompt_boolean_question 
+	(_("WARNING: move writes all data to disk automatically, continue"))) 
+	        return 1;
+
+	if (!fdisk_command_line_get_partition (_("Partition number?"), *disk, &part))
+		goto error;
+	if (!_partition_warn_busy (part))
+		goto error;
+	if (part->type == PED_PARTITION_EXTENDED) {
+		ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+			_("Can't move an extended partition."));
+		goto error;
+	}
+	old_geom = part->geom;
+	fs = ped_file_system_open (&old_geom);
+	if (!fs)
+		goto error;
+
+	/* get new target */
+	if (!fdisk_command_line_get_sector (_("Start?"), (*disk)->dev, &start, &range_start))
+		goto error_close_fs;
+	end = start + old_geom.length - 1;
+	if (!fdisk_command_line_get_sector (_("End?"), (*disk)->dev, &end, &range_end))
+		goto error_close_fs;
+
+	/* set / test on "disk" */
+	if (!ped_geometry_init (&new_geom, (*disk)->dev, start, end - start + 1))
+		goto error_close_fs;
+	snap_to_boundaries (&new_geom, NULL, *disk, range_start, range_end);
+
+	constraint = constraint_intersect_and_destroy (
+			ped_file_system_get_copy_constraint (fs, (*disk)->dev),
+			constraint_from_start_end ((*disk)->dev, range_start, range_end));
+	if (!ped_disk_set_partition_geom (*disk, part, constraint,
+					  new_geom.start, new_geom.end))
+		goto error_destroy_constraint;
+	ped_constraint_destroy (constraint);
+	if (ped_geometry_test_overlap (&old_geom, &part->geom)) {
+		ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+			_("Can't move a partition onto itself.  Try using "
+			  "resize, perhaps?"));
+		goto error_close_fs;
+	}
+
+        /* do the move */
+	fs_copy = ped_file_system_copy (fs, &part->geom, timer);
+	if (!fs_copy)
+		goto error_close_fs;
+	ped_file_system_close (fs_copy);
+	ped_file_system_close (fs);
+	if (!ped_disk_commit (*disk))
+		goto error;
+	
+	if (need_commit) need_commit = 0;
+	
+	if (range_start != NULL)
+		ped_geometry_destroy (range_start);
+	if (range_end != NULL)
+		ped_geometry_destroy (range_end);
+	return 1;
+
+error_destroy_constraint:
+	ped_constraint_destroy (constraint);
+error_close_fs:
+	ped_file_system_close (fs);
+error:
+	if (range_start != NULL)
+		ped_geometry_destroy (range_start);
+	if (range_end != NULL)
+		ped_geometry_destroy (range_end);
+	return 0;
+}
+
+static int
+do_name (PedDisk** disk)
+{
+	PedPartition*	part = NULL;
+	char*		name;
+
+	if (!*disk)
+		goto error;
+
+	if (!fdisk_command_line_get_partition (_("Partition number?"), *disk, &part))
+		goto error;
+
+	name = fdisk_command_line_get_word (_("Partition name?"),
+					    ped_partition_get_name (part), NULL, 0);
+	if (!name)
+		goto error;
+	if (!ped_partition_set_name (part, name))
+		goto error_free_name;
+	free (name);
+
+	if (!need_commit) need_commit = 1;
+
+	return 1;
+
+error_free_name:
+	free (name);
+error:
+	return 0;
+}
+
+static void
+partition_print_flags (PedPartition* part)
+{
+	PedPartitionFlag	flag;
+	int			first_flag;
+
+	first_flag = 1;
+	for (flag = ped_partition_flag_next (0); flag;
+	     flag = ped_partition_flag_next (flag)) {
+		if (ped_partition_get_flag (part, flag)) {
+			if (first_flag)
+				first_flag = 0;
+			else
+				printf (", ");
+			printf (_(ped_partition_flag_get_name (flag)));
+		}
+	}
+}
+
+/* Prints a sector out, first in compact form, and then with a percentage.
+ * Eg: 32Gb (40%)
+ */
+static void
+print_sector_compact_and_percent (PedSector sector, PedDevice* dev)
+{
+	char* compact;
+	char* percent;
+
+	if (ped_unit_get_default() == PED_UNIT_PERCENT)
+		compact = ped_unit_format (dev, sector);
+	else
+		compact = ped_unit_format_custom (dev, sector,
+						  PED_UNIT_COMPACT);
+
+	percent = ped_unit_format_custom (dev, sector, PED_UNIT_PERCENT);
+
+	printf ("%s (%s)\n", compact, percent);
+
+	ped_free (compact);
+	ped_free (percent);
+}
+
+static int
+partition_print (PedPartition* part)
+{
+	PedFileSystem*	fs;
+	PedConstraint*	resize_constraint;
+
+	fs = ped_file_system_open (&part->geom);
+	if (!fs)
+		return 1;
+
+        printf ("\n");
+     
+	printf (_("Minor: %d\n"), part->num);
+	printf (_("Flags: ")); partition_print_flags (part); printf("\n");
+	printf (_("File System: %s\n"), fs->type->name);
+	printf (_("Size:         "));
+	print_sector_compact_and_percent (part->geom.length, part->geom.dev);
+
+	resize_constraint = ped_file_system_get_resize_constraint (fs);
+	if (resize_constraint) {
+		printf (_("Minimum size: "));
+		print_sector_compact_and_percent (resize_constraint->min_size,
+			part->geom.dev);
+		printf (_("Maximum size: "));
+		print_sector_compact_and_percent (resize_constraint->max_size,
+			part->geom.dev);
+		ped_constraint_destroy (resize_constraint);
+	}
+
+        printf ("\n");
+
+	ped_file_system_close (fs);
+	return 1;
+}
+
+static int
+do_quit (PedDisk** disk)
+{
+	_done ((*disk)->dev);
+
+	ped_disk_destroy (*disk);
+
+        exit (0);
+}
+
+static int
+is_bsd_partition (char* device, PedSector start, PedSector s_size) {
+	int fd;
+	struct bsdlabel *lbl;
+	u_char bootarea[BSD_BSIZE];
+
+	if (!device)
+		return 0;
+
+	fd = open (device, O_RDONLY);
+	if (fd < 0)
+		return 0;
+  
+	(void)lseek (fd, (off_t)start, SEEK_SET);
+  
+	/* read in the boot block area. */
+	if (read (fd, bootarea, BSD_BSIZE) != BSD_BSIZE) 
+		return 0;
+	close (fd);
+
+	lbl = (struct bsdlabel *)&(bootarea[s_size]);
+  
+	if (lbl->magic != BSD_DISKMAGIC
+	    || lbl->magic2 != BSD_DISKMAGIC) 
+		return 0;
+
+	return 1;
+}
+
+static int
+do_print (PedDisk **disk)
+{
+	PedPartition*		part;
+	int			has_extended;
+	int                     sect_size;
+	char* 			cyl_size;
+	PedCHSGeometry* 	chs;
+	PedSector               heads;
+	PedSector               sectors;
+	PedSector               cylinders;
+	PedSector		start;
+	PedSector		end;
+	PedSector		cyl_start;
+	PedSector		cyl_end;
+	PedSector               unit = ped_unit_get_default ();
+	PedSector		blocks;			
+	PedSector		sects_nbytes;
+
+	chs          = &((*disk)->dev)->hw_geom;
+	heads        = chs->heads;
+	sectors      = chs->sectors;
+	cylinders    = chs->cylinders;
+	sect_size    = (*disk)->dev->sector_size;
+	sects_nbytes = heads * sectors * sect_size;
+
+	cyl_size  = ped_unit_format_custom ((*disk)->dev,
+				heads * sectors,
+				PED_UNIT_BYTE);
+	cyl_size[strlen (cyl_size) - 1] = '\0';
+
+	PedSector total_drive_size = heads * sectors * cylinders * sect_size;
+	printf (_("Disk %s: %lld %s, %lld bytes\n"), (*disk)->dev->path, 
+		 total_drive_size >= 1000000000 ? 
+		 total_drive_size  / 1000000000 : 
+		 total_drive_size  / 1000000, 
+		(total_drive_size >= 1000000000) ? "GB" : "MB",
+		heads * sectors * cylinders * sect_size);
+
+	if (unit == PED_UNIT_SECTOR)
+		printf (_("%lld heads, %lld sectors/track, %lld cylinders, total %lld sectors\n"
+		  	"Units = sectors of %d * %d = %d bytes\n"),
+			heads, sectors, cylinders, (heads * sectors * cylinders), 1, 
+			sect_size, sect_size);
+	else
+		printf (_("%lld heads, %lld sectors/track, %lld cylinders\n"
+		  	"Units = cylinders of %lld * %d = %s bytes\n"),
+			heads, sectors, cylinders, (heads * sectors), 
+			sect_size, cyl_size);
+
+        printf ("\n");
+        
+	has_extended = ped_disk_type_check_feature ((*disk)->type,
+			       		 PED_DISK_TYPE_EXTENDED);
+
+  	unsigned int i = 0;
+	for (i = 0; i < (strlen ((*disk)->dev->path) - 5); i++)
+  		printf (" ");
+        printf ("%s %s %+10s %+11s %+11s %+4s %+7s ", _("Device"), _("Boot"),
+		_("Start"), _("End"), _("Blocks"), _("Id"), _("System"));
+	printf ("\n");
+	
+	PedSector total_cyl = heads * sectors;
+
+	for (part = ped_disk_next_partition (*disk, NULL); part;
+	     part = ped_disk_next_partition (*disk, part)) {
+
+		cyl_start     = (part->geom.start / (total_cyl)) + 1; 
+		cyl_end       = (part->geom.end   / (total_cyl)) + 1;
+
+	  	if (unit == PED_UNIT_SECTOR) {	
+			start     = (part->geom.start / total_cyl 
+				    	* total_cyl) + sectors; 
+		        end       = part->geom.end / total_cyl * total_cyl;
+			blocks    = ((cyl_end * total_cyl) 
+					- ((part->num == 1) ? 
+			(cyl_start * sectors) : (cyl_start * total_cyl))) 
+					/ (1024 / sect_size);
+		} else {
+		  	start     = cyl_start;
+			end       = cyl_end;
+			blocks    = ((end * total_cyl) - ((part->num == 1) ? 
+			(start * sectors) : (start * total_cyl))) / (1024 / sect_size);
+		}
+	
+		if (!ped_partition_is_active (part))
+	       		continue;
+
+		printf ("%s%d ", (*disk)->dev->path, part->num);
+
+		/* Check to see if we have a boot flag. */
+		if (ped_partition_get_flag (part, PED_PARTITION_BOOT)) {
+	  		printf ("  *  ");
+			printf ("%10lld %11lld %11lu ", start, end, blocks);
+
+			char *type = (char *)ped_partition_type_get_name (part->type);
+			if (part->fs_type 
+			    && !strcmp (part->fs_type->name, "linux-swap"))
+				printf ("%+4s %+21s ", _("82"), _("Linux Swap / Solaris"));
+			else if (is_bsd_partition ((*disk)->dev->path, 
+				part->geom.start * sect_size, sect_size))
+				printf ("%+4s %+17s ", _("a5"), _("Free/Net/OpenBSD"));
+			else if (!strcmp (type, "primary")) 
+				printf ("%+4s %+6s ", _("83"), _("Linux"));
+			else if (!strcmp (type, "extended"))
+				printf ("%+4s %+9s ", _("5"), _("Extended"));
+		} else {
+			printf ("%15lld %11lld %11lld ", start, end, blocks);
+			char *type = (char *)ped_partition_type_get_name (part->type);
+			if (part->fs_type 
+			    && !strcmp (part->fs_type->name, "linux-swap"))
+				printf ("%+4s %+21s ", _("82"), _("Linux Swap / Solaris"));
+			else if (is_bsd_partition ((*disk)->dev->path, 
+				part->geom.start * sect_size, sect_size))
+				printf ("%+4s %+17s ", _("a5"), _("Free/Net/OpenBSD"));
+			else if (!strcmp (type, "primary")) 
+				printf ("%+4s %+6s ", _("83"), _("Linux"));
+			else if (!strcmp (type, "extended"))
+				printf ("%+4s %+9s ", _("5"), _("Extended"));
+		}
+		printf ("\n");
+		start = end = blocks = 0;
+	}
+	ped_free (cyl_size);
+        printf ("\n");
+        
+	/*if (fdisk_list_table == 1)
+	  do_quit (disk);*/
+
+	return 1;
+
+error:
+	return 0;
+}
+
+static void 
+do_list_devices (PedDisk* disk) {
+        if (disk == NULL) {
+                PedDevice* dev = NULL;
+    
+                ped_device_probe_all ();
+    
+                while ((dev = ped_device_get_next (dev))) {
+                         if (!ped_device_open(dev))
+	                         break;
+     
+                         PedDisk *disk = ped_disk_new(dev);
+                         do_print (&disk);
+                         ped_disk_destroy(disk);
+                }
+        } else
+                do_print(&disk);
+        exit(0);
+}
+
+static PedPartitionType
+_disk_get_part_type_for_sector (PedDisk* disk, PedSector sector)
+{
+	PedPartition*	extended;
+
+	extended = ped_disk_extended_partition (disk);
+	if (!extended
+	    || !ped_geometry_test_sector_inside (&extended->geom, sector))
+		return 0;
+
+	return PED_PARTITION_LOGICAL;
+}
+
+/* This function checks if "part" contains a file system, and returs
+ * 	0 if either no file system was found, or the user declined to add it.
+ * 	1 if a file system was found, and the user chose to add it.
+ * 	-1 if the user chose to cancel the entire search.
+ */
+static int
+_rescue_add_partition (PedPartition* part)
+{
+	const PedFileSystemType*	fs_type;
+	PedGeometry*			probed;
+	PedExceptionOption		ex_opt;
+	PedConstraint*			constraint;
+	char*				found_start;
+	char*				found_end;
+
+	fs_type = ped_file_system_probe (&part->geom);
+	if (!fs_type)
+		return 0;
+	probed = ped_file_system_probe_specific (fs_type, &part->geom);
+	if (!probed)
+		return 0;
+
+	if (!ped_geometry_test_inside (&part->geom, probed)) {
+		ped_geometry_destroy (probed);
+		return 0;
+	}
+
+	constraint = ped_constraint_exact (probed);
+	if (!ped_disk_set_partition_geom (part->disk, part, constraint,
+					  probed->start, probed->end)) {
+		ped_constraint_destroy (constraint);
+		return 0;
+	}
+	ped_constraint_destroy (constraint);
+
+	found_start = ped_unit_format (probed->dev, probed->start);
+	found_end = ped_unit_format (probed->dev, probed->end);
+	ex_opt = ped_exception_throw (
+		PED_EXCEPTION_INFORMATION,
+		PED_EXCEPTION_YES_NO_CANCEL,
+		_("A %s %s partition was found at %s -> %s.  "
+		  "Do you want to add it to the partition table?"),
+		fs_type->name, ped_partition_type_get_name (part->type),
+		found_start, found_end);
+	ped_geometry_destroy (probed);
+	ped_free (found_start);
+	ped_free (found_end);
+
+	switch (ex_opt) {
+		case PED_EXCEPTION_CANCEL: return -1;
+		case PED_EXCEPTION_NO: return 0;
+	}
+
+	ped_partition_set_system (part, fs_type);
+	ped_disk_commit (part->disk);
+	return 1;
+}
+
+/* hack: we only iterate through the start, since most (all) fs's have their
+ * superblocks at the start.  We'll need to change this if we generalize
+ * for RAID, or something...
+ */
+static int
+_rescue_pass (PedDisk* disk, PedGeometry* start_range, PedGeometry* end_range)
+{
+	PedSector		start;
+	PedGeometry		start_geom_exact;
+	PedGeometry		entire_dev;
+	PedConstraint		constraint;
+	PedPartition*		part;
+	PedPartitionType	part_type;
+
+	part_type = _disk_get_part_type_for_sector (
+			disk, (start_range->start + end_range->end) / 2);
+
+	ped_geometry_init (&entire_dev, disk->dev, 0, disk->dev->length);
+
+	ped_timer_reset (timer);
+	ped_timer_set_state_name (timer, _("searching for file systems"));
+	for (start = start_range->start; start <= start_range->end; start++) {
+		ped_timer_update (timer, 1.0 * (start - start_range->start)
+					 / start_range->length);
+
+		ped_geometry_init (&start_geom_exact, disk->dev, start, 1);
+		ped_constraint_init (
+			&constraint, ped_alignment_any, ped_alignment_any,
+			&start_geom_exact, &entire_dev,
+			1, disk->dev->length);
+		part = ped_partition_new (disk, part_type, NULL, start,
+				end_range->end);
+		if (!part) {
+			ped_constraint_done (&constraint);
+			continue;
+		}
+
+		ped_exception_fetch_all ();
+		if (ped_disk_add_partition (disk, part, &constraint)) {
+			ped_exception_leave_all ();
+			switch (_rescue_add_partition (part)) {
+			case 1:
+				ped_constraint_done (&constraint);
+				return 1;
+
+			case 0:
+				ped_disk_remove_partition (disk, part);
+				break;
+
+			case -1:
+				goto error_remove_partition;
+			}
+		} else {
+			ped_exception_leave_all ();
+		}
+		ped_partition_destroy (part);
+		ped_constraint_done (&constraint);
+	}
+	ped_timer_update (timer, 1.0);
+
+	return 1;
+
+error_remove_partition:
+	ped_disk_remove_partition (disk, part);
+error_partition_destroy:
+	ped_partition_destroy (part);
+error_constraint_done:
+	ped_constraint_done (&constraint);
+error:
+	return 0;
+}
+
+static int
+do_rescue (PedDisk** disk)
+{
+	PedSector		start = 0, end = 0;
+	PedSector		fuzz;
+	PedGeometry		probe_start_region;
+	PedGeometry		probe_end_region;
+
+	if (!*disk)
+		goto error;
+
+	if (!command_line_prompt_boolean_question 
+	(_("WARNING: rescue writes all data to disk automatically, continue")))
+		return 1;
+
+	if (!fdisk_command_line_get_sector (_("Start?"), (*disk)->dev, &start, NULL))
+		goto error;
+	if (!fdisk_command_line_get_sector (_("End?"), (*disk)->dev, &end, NULL))
+		goto error;
+
+	fuzz = PED_MAX (PED_MIN ((end - start) / 10, MEGABYTE_SECTORS),
+		        MEGABYTE_SECTORS * 16);
+
+	ped_geometry_init (&probe_start_region, (*disk)->dev,
+			   PED_MAX(start - fuzz, 0),
+			   PED_MIN(2 * fuzz, ((*disk)->dev)->length - (start - fuzz)));
+	ped_geometry_init (&probe_end_region, (*disk)->dev,
+			   PED_MAX(end - fuzz, 0),
+			   PED_MIN(2 * fuzz, (*disk)->dev->length - (end - fuzz)));
+
+	if (!_rescue_pass (*disk, &probe_start_region, &probe_end_region))
+		goto error;
+
+	return 1;
+
+error:
+	return 0;
+}
+
+static int
+do_resize (PedDisk** disk)
+{
+	PedPartition		*part = NULL;
+	PedFileSystem		*fs;
+	PedConstraint		*constraint;
+	PedSector		start, end;
+	PedGeometry             *range_start = NULL, *range_end = NULL;
+	PedGeometry		new_geom;
+
+	if (!*disk)
+		goto error;
+
+	if (!command_line_prompt_boolean_question 
+	(_("WARNING: resize writes all data to disk automatically, continue")))
+	        return 1;
+
+	if (!fdisk_command_line_get_partition (_("Partition number?"), *disk, &part))
+		goto error;
+	if (part->type != PED_PARTITION_EXTENDED) {
+		if (!_partition_warn_busy (part))
+			goto error;
+	}
+
+	start = part->geom.start;
+	end = part->geom.end;
+	if (!fdisk_command_line_get_sector (_("Start?"), (*disk)->dev, &start, &range_start))
+		goto error;
+	if (!fdisk_command_line_get_sector (_("End?"), (*disk)->dev, &end, &range_end))
+		goto error;
+
+	if (!ped_geometry_init (&new_geom, (*disk)->dev, start, end - start + 1))
+		goto error;
+	snap_to_boundaries (&new_geom, &part->geom, *disk,
+			    range_start, range_end);
+
+	if (part->type == PED_PARTITION_EXTENDED) {
+		constraint = constraint_from_start_end ((*disk)->dev,
+				range_start, range_end);
+		if (!ped_disk_set_partition_geom (*disk, part, constraint,
+						  new_geom.start, new_geom.end))
+			goto error_destroy_constraint;
+		ped_partition_set_system (part, NULL);
+	} else {
+		fs = ped_file_system_open (&part->geom);
+		if (!fs)
+			goto error;
+		constraint = constraint_intersect_and_destroy (
+				ped_file_system_get_resize_constraint (fs),
+				constraint_from_start_end (
+					(*disk)->dev, range_start, range_end));
+		if (!ped_disk_set_partition_geom (*disk, part, constraint,
+						  new_geom.start, new_geom.end))
+			goto error_close_fs;
+		if (!ped_file_system_resize (fs, &part->geom, timer))
+			goto error_close_fs;
+		/* may have changed... eg fat16 -> fat32 */
+		ped_partition_set_system (part, fs->type);
+		ped_file_system_close (fs);
+	}
+
+	ped_constraint_destroy (constraint);
+	if (range_start != NULL)
+		ped_geometry_destroy (range_start);
+	if (range_end != NULL)
+		ped_geometry_destroy (range_end);
+	return 1;
+
+error_close_fs:
+	ped_file_system_close (fs);
+error_destroy_constraint:
+	ped_constraint_destroy (constraint);
+error:
+	if (range_start != NULL)
+		ped_geometry_destroy (range_start);
+	if (range_end != NULL)
+		ped_geometry_destroy (range_end);
+	return 0;
+}
+
+static int
+do_rm (PedDisk** disk)
+{
+	PedPartition*		part = NULL;
+
+	if (!fdisk_command_line_get_partition (_("Partition number?"), *disk, &part))
+		goto error;
+	if (!_partition_warn_busy (part))
+		goto error;
+
+	ped_disk_delete_partition (*disk, part);
+
+	if (!need_commit) need_commit = 1;
+
+	return 1;
+
+error:
+	return 0;
+}
+
+static int
+do_select (PedDisk** disk)
+{
+	PedDevice*      dev;
+	if (!fdisk_command_line_get_device (_("New device?"), &dev))
+		return 0;
+	if (!ped_device_open (dev))
+		return 0;
+
+	if (need_commit) 
+	        if (!command_line_prompt_boolean_question 
+		(_("WARNING: changes were made to the disk, "
+		   "are you sure you want to discard them")))
+	                return 1;
+
+	/* Destroy the current disk and open the new.*/
+	ped_disk_destroy (*disk);
+	if (!(*disk = ped_disk_new (dev)))
+	        return 0;
+	
+	/* Tell the user we are using the new device. */
+	fdisk_print_using_dev (dev);
+
+	if (need_commit) need_commit = 0;
+
+	return 1;
+}
+
+static int
+do_set (PedDisk** disk)
+{
+	PedPartition*		part = NULL;
+	PedPartitionFlag	flag;
+	int			state;
+
+	if (!(*disk))
+		goto error;
+
+	if (!fdisk_command_line_get_partition (_("Partition number?"), *disk, &part))
+		goto error;
+	if (!fdisk_command_line_get_part_flag (_("Flag to change?"), part, &flag))
+		goto error;
+	state = ped_partition_get_flag (part, flag);
+	if (!fdisk_command_line_get_state (_("New state?"), &state))
+		goto error;
+
+	if (!ped_partition_set_flag (part, flag, state))
+       	        goto error;
+
+	if (!need_commit) need_commit = 1;
+
+	return 1;
+
+error:
+	return 0;
+}
+
+static int
+do_toggle_boot_flag (PedDisk** disk)
+{
+	PedPartition*		part = NULL;
+	PedPartitionFlag	flag = PED_PARTITION_BOOT;
+	int			state;
+
+	if (!(*disk))
+		goto error;
+
+	if (!fdisk_command_line_get_partition (_("Partition number?"), *disk, &part))
+		goto error;
+
+	state = ((ped_partition_get_flag (part, flag)) ? 0 : 1);
+
+	if (!ped_partition_set_flag (part, flag, state))
+		goto error;
+
+	if (!need_commit) need_commit = 1;
+
+	return 1;
+
+error:
+	return 0;
+}
+
+static int
+do_unit (PedDisk** disk)
+{
+	if (cylinder_unit) {
+		printf ("%s\n", _("Changing display/entry units to sectors"));
+		PedUnit unit = ped_unit_get_by_name ("s");
+		ped_unit_set_default (unit);
+		cylinder_unit = 0;
+		return 1;
+	} else {
+		printf ("%s\n", _("Changing display/entry units to cylinders"));
+		PedUnit unit = ped_unit_get_by_name ("cyl");
+		ped_unit_set_default (unit);
+		cylinder_unit = 1;
+		return 1;
+	}
+}
+
+/*
+ * do_commit: write all configuration changes to disk.
+ */
+static int 
+do_commit (PedDisk **disk)
+{  
+	if ((*disk)->dev->boot_dirty && (*disk)->dev->type != PED_DEVICE_FILE) {
+	        ped_exception_throw (
+				     PED_EXCEPTION_WARNING,
+				     PED_EXCEPTION_OK,
+				     _("You should reinstall your boot loader before "
+				       "rebooting.  Read section 4 of the Parted User "
+				       "documentation for more information."));
+	}
+	if ((*disk)->dev->type != PED_DEVICE_FILE && !fdisk_opt_script_mode) {
+	        ped_exception_throw (
+				     PED_EXCEPTION_INFORMATION, PED_EXCEPTION_OK,
+				     _("Don't forget to update /etc/fstab, if "
+				       "necessary.\n"));
+	}
+
+	printf (_("\nWriting all changes to %s.\n"), _((*disk)->dev->path));
+	if (!ped_disk_commit (*disk))
+	        goto error;
+  
+	if (!ped_disk_commit_to_os (*disk))
+                goto error;
+  
+	/* After writing changes exit. */
+	do_quit (disk);
+
+        return 1;
+       
+ error:
+	return 0;
+}
+
+
+static int
+do_ex_menu (PedDisk** disk) {
+	int status;
+        
+	in_ex_menu = 1;
+
+	status = fdisk_interactive_menu (disk, 
+		fdisk_ex_menu_commands, 0);
+
+	in_ex_menu = 0;
+	return status;
+}
+
+static void
+_init_messages ()
+{
+	StrList*		list;
+	int			first;
+	PedFileSystemType*	fs_type;
+	PedDiskType*		disk_type;
+	PedPartitionFlag	part_flag;
+	PedUnit			unit;
+
+/* flags */
+	first = 1;
+	list = str_list_create (_(flag_msg_start), NULL);
+	for (part_flag = ped_partition_flag_next (0); part_flag;
+	     		part_flag = ped_partition_flag_next (part_flag)) {
+		if (first)
+			first = 0;
+		else
+			str_list_append (list, ", ");
+		str_list_append (list,
+				 _(ped_partition_flag_get_name (part_flag)));
+	}
+	str_list_append (list, "\n");
+
+	flag_msg = str_list_convert (list);
+	str_list_destroy (list);
+
+/* units */
+	first = 1;
+	list = str_list_create (_(unit_msg_start), NULL);
+	for (unit = PED_UNIT_FIRST; unit <= PED_UNIT_LAST; unit++) {
+		if (first)
+			first = 0;
+		else
+			str_list_append (list, ", ");
+		str_list_append (list, ped_unit_get_name (unit));
+	}
+	str_list_append (list, "\n");
+
+	unit_msg = str_list_convert (list);
+	str_list_destroy (list);
+
+/* disk type */
+	list = str_list_create (_(label_type_msg_start), NULL);
+
+	first = 1;
+	for (disk_type = ped_disk_type_get_next (NULL);
+	     disk_type; disk_type = ped_disk_type_get_next (disk_type)) {
+		if (disk_type->ops->write == NULL)
+			continue;
+
+		if (first)
+			first = 0;
+		else
+			str_list_append (list, ", ");
+		str_list_append (list, disk_type->name);
+	}
+	str_list_append (list, "\n");
+
+	label_type_msg = str_list_convert (list);
+	str_list_destroy (list);
+
+/* mkfs - file system types */
+	list = str_list_create (_(fs_type_msg_start), NULL);
+
+	first = 1;
+	for (fs_type = ped_file_system_type_get_next (NULL);
+	     fs_type; fs_type = ped_file_system_type_get_next (fs_type)) {
+		if (fs_type->ops->create == NULL)
+			continue;
+
+		if (first)
+			first = 0;
+		else
+			str_list_append (list, ", ");
+		str_list_append (list, fs_type->name);
+	}
+	str_list_append (list, "\n");
+
+	mkfs_fs_type_msg = str_list_convert (list);
+	str_list_destroy (list);
+
+/* mkpart - file system types */
+	list = str_list_create (_(fs_type_msg_start), NULL);
+
+	first = 1;
+	for (fs_type = ped_file_system_type_get_next (NULL);
+	     fs_type; fs_type = ped_file_system_type_get_next (fs_type)) {
+		if (first)
+			first = 0;
+		else
+			str_list_append (list, ", ");
+		str_list_append (list, fs_type->name);
+	}
+	str_list_append (list, "\n");
+
+	mkpart_fs_type_msg = str_list_convert (list);
+	str_list_destroy (list);
+
+/* resize - file system types */
+	list = str_list_create (_(resize_msg_start), NULL);
+
+	first = 1;
+	for (fs_type = ped_file_system_type_get_next (NULL);
+	     fs_type; fs_type = ped_file_system_type_get_next (fs_type)) {
+		if (fs_type->ops->resize == NULL)
+			continue;
+
+		if (first)
+			first = 0;
+		else
+			str_list_append (list, ", ");
+		str_list_append (list, fs_type->name);
+	}
+	str_list_append (list, "\n");
+
+	resize_fs_type_msg = str_list_convert (list);
+	str_list_destroy (list);
+}
+
+static void
+_done_messages ()
+{
+	free (flag_msg);
+	free (mkfs_fs_type_msg);
+	free (mkpart_fs_type_msg);
+	free (resize_fs_type_msg);
+	free (label_type_msg);
+}
+
+static void
+_init_ex_menu_commands () {
+	fdisk_command_register (fdisk_ex_menu_commands, fdisk_command_create (
+		str_list_create_unique ("v", _("v"), NULL),
+		do_move,
+		str_list_create (
+_("v           move a partition."),
+NULL),
+		str_list_create (_(number_msg), _(start_end_msg), NULL), 1));
+	fdisk_command_register (fdisk_ex_menu_commands, fdisk_command_create (
+		str_list_create_unique ("c", _("c"), NULL),
+		do_rescue,
+		str_list_create (
+_("c           rescue a lost partition."),
+NULL),
+		str_list_create (_(start_end_msg), NULL), 1));
+
+	fdisk_command_register (fdisk_ex_menu_commands, fdisk_command_create (
+		str_list_create_unique ("z", _("z"), NULL),
+		do_resize,
+		str_list_create (
+_("z           resize a partition and its file system."),
+NULL), NULL, 1));
+
+	fdisk_command_register (fdisk_ex_menu_commands, fdisk_command_create (
+		str_list_create_unique ("m", _("m"), NULL),
+		do_help,
+		str_list_create (
+_("m           prints general help, or help on a COMMAND."),
+NULL), NULL, 1));
+
+        fdisk_command_register (fdisk_ex_menu_commands, fdisk_command_create (
+		str_list_create_unique ("r", _("r"), NULL),
+		NULL,
+		str_list_create (
+_("r           return to the main menu."),
+NULL), NULL, 1));
+}
+
+static void
+_init_main_menu_commands () {
+	fdisk_command_register (fdisk_main_menu_commands, fdisk_command_create (
+		str_list_create_unique ("a", _("a"), NULL),
+		do_toggle_boot_flag,
+		str_list_create (
+_(" a   toggle bootable flag"),
+NULL), NULL, 1));
+
+	fdisk_command_register (fdisk_main_menu_commands, fdisk_command_create (
+		str_list_create_unique ("d", _("d"), NULL),
+		do_rm,
+		str_list_create (
+_(" d   delete a partition"),
+NULL), NULL, 1));
+
+	fdisk_command_register (fdisk_main_menu_commands, fdisk_command_create (
+		str_list_create_unique ("m", _("m"), NULL),
+		do_help,
+		str_list_create (
+_(" m   print this menu"),
+NULL), NULL, 1));
+
+	fdisk_command_register (fdisk_main_menu_commands, fdisk_command_create (
+		str_list_create_unique ("n", _("n"), NULL),
+		do_mkpart,
+		str_list_create (
+_(" n   add a new partition"),
+NULL), NULL, 1));
+
+	fdisk_command_register (fdisk_main_menu_commands, fdisk_command_create (
+		str_list_create_unique ("o", _("o"), NULL),
+		do_msdos_mklabel,
+		str_list_create (
+_(" o   create a new empty DOS partition table"),
+NULL), NULL, 1));
+
+	fdisk_command_register (fdisk_main_menu_commands, fdisk_command_create (
+		str_list_create_unique ("p", _("p"), NULL),
+		do_print,
+		str_list_create (
+_(" p   print the partition table"),
+NULL), NULL, 1));
+
+	fdisk_command_register (fdisk_main_menu_commands, fdisk_command_create (
+		str_list_create_unique ("q", _("q"), NULL),
+		do_quit,
+		str_list_create (
+_(" q   quit without saving changes"),
+NULL), NULL, 1));
+
+	fdisk_command_register (fdisk_main_menu_commands, fdisk_command_create (
+		str_list_create_unique ("s", _("s"), NULL),
+		do_sun_mklabel,
+		str_list_create (
+_(" s   create a new empty Sun disklabel"),
+NULL), NULL, 1));
+
+	fdisk_command_register (fdisk_main_menu_commands, fdisk_command_create (
+		str_list_create_unique ("u", _("u"), NULL),
+		do_unit,
+		str_list_create (
+_(" u   change display/entry units"),
+NULL), NULL, 1));
+
+        fdisk_command_register (fdisk_main_menu_commands, fdisk_command_create (
+		str_list_create_unique ("w", _("w"), NULL),
+		do_commit,
+		str_list_create (
+_(" w   write table to disk and exit"),
+NULL), NULL, 1));
+
+/*	fdisk_command_register (fdisk_main_menu_commands, fdisk_command_create (
+		str_list_create_unique ("x", _("x"), NULL),
+		do_ex_menu,
+		str_list_create (
+_(" x   extra functionality (experts only)"),
+NULL), NULL, 1));*/
+}
+
+static void
+_done_commands ()
+{
+	FdiskCommand**	walk;
+
+	for (walk = fdisk_main_menu_commands; *walk; walk++) {
+		fdisk_command_destroy (*walk);
+		*walk = NULL;
+	}
+
+	for (walk = fdisk_ex_menu_commands; *walk; walk++) {
+		fdisk_command_destroy (*walk);
+		*walk = NULL;
+	}
+}
+
+static void
+_init_i18n ()
+{
+/* intialize i18n */
+#ifdef ENABLE_NLS
+	setlocale(LC_ALL, "");
+	bindtextdomain(PACKAGE, LOCALEDIR);
+	textdomain(PACKAGE);
+#endif /* ENABLE_NLS */
+}
+
+static void
+_version ()
+{
+	printf ("%s for %s", interface_name, fdisk_prog_name);
+	exit (0);
+}
+
+static int
+_parse_options (int* argc_ptr, char*** argv_ptr)
+{
+	int	opt;
+
+	while (1)
+	{
+#ifdef HAVE_GETOPT_H
+		opt = getopt_long (*argc_ptr, *argv_ptr, "hlisv",
+				   options, NULL);
+#else
+		opt = getopt (*argc_ptr, *argv_ptr, "hlisv");
+#endif
+		if (opt == -1)
+			break;
+
+		switch (opt) {
+			case 'h': fdisk_help_msg (); break;
+			case 'l': fdisk_list_table = 1; break;
+			case 'i': fdisk_opt_script_mode = 0; break;
+			case 's': fdisk_opt_script_mode = 1; break;
+			case 'v': _version (); break;
+		}
+	}
+
+	*argc_ptr -= optind;
+	*argv_ptr += optind;
+	return 1;
+
+error:
+	return 0;
+}
+
+static PedDevice*
+_choose_device (int* argc_ptr, char*** argv_ptr)
+{
+	PedDevice*	dev;
+
+	/* specified on comand line? */
+	if (*argc_ptr) {
+		dev = ped_device_get ((*argv_ptr) [0]);
+		if (!dev)
+			return NULL;
+		(*argc_ptr)--;
+		(*argv_ptr)++;
+
+		if (!ped_device_open (dev))
+		  return NULL;
+		
+		return dev;
+	}
+	return NULL;	
+}
+
+static PedDevice*
+_init (int* argc_ptr, char*** argv_ptr)
+{
+	PedDevice*	dev;
+
+#ifdef ENABLE_MTRACE
+	mtrace();
+#endif
+
+	_init_i18n ();
+	if (!fdisk_init_ui ())
+		goto error;
+
+	_init_messages ();
+	_init_main_menu_commands ();
+	
+	if (!_parse_options (argc_ptr, argv_ptr))
+		goto error_done_commands;
+	dev = _choose_device (argc_ptr, argv_ptr);
+	if (!dev)
+		goto error_done_commands;
+
+	timer = ped_timer_new (_timer_handler, &timer_context);
+	if (!timer)
+		goto error_done_commands;
+	timer_context.last_update = 0;
+
+	return dev;
+
+error_done_commands:
+	_done_commands ();
+	_done_messages ();
+error_done_ui:
+	fdisk_done_ui ();
+error:
+	return NULL;
+}
+
+static void
+_done (PedDevice* dev)
+{
+	ped_device_close (dev);
+
+	ped_timer_destroy (timer);
+	_done_commands ();
+	_done_messages ();
+	fdisk_done_ui();
+}
+
+int
+fdisk (int argc, char** argv)
+{
+        PedDevice*	dev;
+	PedDisk*        disk; 
+	int		status;
+
+	if (argc <= 1) {
+	        fdisk_usage_msg();
+	        return -1;
+	}
+
+	dev = _init (&argc, &argv);
+
+	if (!dev && fdisk_list_table)
+	        /* List all devices. */
+	        do_list_devices (NULL);
+	else if (!dev)
+	        return 1;
+
+	disk = ped_disk_new (dev);
+
+	if (!disk) 
+	        return 1;
+
+	/* List the specified disk. */
+	if (fdisk_list_table)
+	         do_list_devices(disk);
+	
+	status = fdisk_interactive_mode (&disk, fdisk_main_menu_commands);
+	
+	return !status;
+}
+
+/*
+    GNU fdisk - a clone of Linux fdisk.
+
+    Copyright (C) 2006 Free Software Foundation, 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+*/
+
+extern int fdisk (int argc, char** argv);
+
+int
+main (int argc, char** argv)
+{
+        return fdisk (argc, argv);
+}
+
+/*
+    fdisk - Linux fdisk clone
+    This file originally from GNU Parted.
+    Copyright (C) 1999, 2000, 2001, 2002, 2006 Free Software Foundation, 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+*/
+
+#include <parted/parted.h>
+#include <parted/debug.h>
+
+#include <ctype.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <setjmp.h>
+
+#include "config.h"
+#include "command.h"
+#include "strlist.h"
+#include "ui.h"
+#define N_(String) String
+#if ENABLE_NLS
+#  include <libintl.h>
+#  include <locale.h>
+#  define _(String) dgettext (PACKAGE, String)
+#else
+#  define _(String) (String)
+#endif /* ENABLE_NLS */
+
+#ifdef HAVE_LIBREADLINE
+
+#ifdef HAVE_TERMCAP_H
+#include <termcap.h>
+#else
+extern int tgetnum (char* key);
+#endif
+
+#include <readline/readline.h>
+#include <readline/history.h>
+
+#ifndef HAVE_RL_COMPLETION_MATCHES
+#define rl_completion_matches completion_matches
+#endif
+
+#ifndef rl_compentry_func_t
+#define rl_compentry_func_t void
+#endif
+
+#endif /* HAVE_LIBREADLINE */
+char* interface_name = "GNU Fdisk 0.0.1";
+char* fdisk_prog_name = "GNU Parted " VERSION "\n";
+
+static char* banner_msg = N_(
+"Copyright (C) 1998 - 2006 Free Software Foundation, Inc.\n"
+"This program is free software, covered by the GNU General Public License.\n"
+"\n"
+"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.\n\n");
+
+static char* usage_msg = N_(
+"Usage: fdisk [OPTION]... [DEVICE]\n");