1 /*
   2     parted - a frontend to libparted
   3     Copyright (C) 1999, 2000, 2001, 2002, 2003, 2005, 2006, 2007
   4     Free Software Foundation, Inc.
   5 
   6     This program is free software; you can redistribute it and/or modify
   7     it under the terms of the GNU General Public License as published by
   8     the Free Software Foundation; either version 3 of the License, or
   9     (at your option) any later version.
  10 
  11     This program is distributed in the hope that it will be useful,
  12     but WITHOUT ANY WARRANTY; without even the implied warranty of
  13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14     GNU General Public License for more details.
  15 
  16     You should have received a copy of the GNU General Public License
  17     along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18 */
  19 
  20 /*
  21  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
  22  */
  23 
  24 #include <config.h>
  25 
  26 #include "closeout.h"
  27 #include "configmake.h"
  28 #include "version-etc.h"
  29 #include "command.h"
  30 #include "ui.h"
  31 #include "table.h"
  32 
  33 #define AUTHORS \
  34   "<http://parted.alioth.debian.org/cgi-bin/trac.cgi/browser/AUTHORS>"
  35 
  36 /* The official name of this program (e.g., no `g' prefix).  */
  37 #define PROGRAM_NAME "parted"
  38 
  39 #define N_(String) String
  40 #if ENABLE_NLS
  41 #  include <libintl.h>
  42 #  include <locale.h>
  43 #  define _(String) dgettext (PACKAGE, String)
  44 #else
  45 #  define _(String) (String)
  46 #endif /* ENABLE_NLS */
  47 
  48 #include <parted/parted.h>
  49 #include <parted/debug.h>
  50 
  51 #include <ctype.h>
  52 #include <stdarg.h>
  53 #include <stdlib.h>
  54 #include <string.h>
  55 #include <unistd.h>
  56 #include <limits.h>
  57 #include "xalloc.h"
  58 
  59 #ifdef ENABLE_MTRACE
  60 #include <mcheck.h>
  61 #endif
  62 
  63 #include <getopt.h>
  64 
  65 /* minimum amount of free space to leave, or maximum amount to gobble up */
  66 #define MIN_FREESPACE           (1000 * 2)      /* 1000k */
  67 
  68 static int MEGABYTE_SECTORS (PedDevice* dev)
  69 {
  70         return PED_MEGABYTE_SIZE / dev->sector_size;
  71 }
  72 
  73 /* For long options that have no equivalent short option, use a
  74    non-character as a pseudo short option, starting with CHAR_MAX + 1.  */
  75 enum
  76 {
  77   PRETEND_INPUT_TTY = CHAR_MAX + 1,
  78 };
  79 
  80 
  81 typedef struct {
  82         time_t  last_update;
  83         time_t  predicted_time_left;
  84 } TimerContext;
  85 
  86 static struct option    options[] = {
  87         /* name, has-arg, string-return-val, char-return-val */
  88         {"help",        0, NULL, 'h'},
  89         {"list",        0, NULL, 'l'},
  90         {"machine",     0, NULL, 'm'},
  91         {"script",      0, NULL, 's'},
  92         {"version",     0, NULL, 'v'},
  93         {"-pretend-input-tty", 0, NULL, PRETEND_INPUT_TTY},
  94         {NULL,          0, NULL, 0}
  95 };
  96 
  97 static char*    options_help [][2] = {
  98         {"help",        N_("displays this help message")},
  99         {"list",        N_("lists partition layout on all block devices")},
 100         {"machine",     N_("displays machine parseable output")},
 101         {"script",      N_("never prompts for user intervention")},
 102         {"version",     N_("displays the version")},
 103         {NULL,          NULL}
 104 };
 105 
 106 char *program_name;
 107 
 108 int     opt_script_mode = 0;
 109 int     pretend_input_tty = 0;
 110 int     opt_machine_mode = 0;
 111 int     disk_is_modified = 0;
 112 int     is_toggle_mode = 0;
 113 
 114 static char* number_msg = N_(
 115 "NUMBER is the partition number used by Linux.  On MS-DOS disk labels, the "
 116 "primary partitions number from 1 to 4, logical partitions from 5 onwards.\n");
 117 
 118 static char* label_type_msg_start = N_("LABEL-TYPE is one of: ");
 119 static char* flag_msg_start =   N_("FLAG is one of: ");
 120 static char* unit_msg_start =   N_("UNIT is one of: ");
 121 static char* part_type_msg =    N_("PART-TYPE is one of: primary, logical, "
 122                                    "extended\n");
 123 static char* fs_type_msg_start = N_("FS-TYPE is one of: ");
 124 static char* start_end_msg =    N_("START and END are disk locations, such as "
 125                 "4GB or 10%.  Negative values count from the end of the disk.  "
 126                 "For example, -1s specifies exactly the last sector.\n");
 127 static char* state_msg =        N_("STATE is one of: on, off\n");
 128 static char* device_msg =       N_("DEVICE is usually /dev/hda or /dev/sda\n");
 129 static char* name_msg =         N_("NAME is any word you want\n");
 130 static char* resize_msg_start = N_("The partition must have one of the "
 131                                    "following FS-TYPEs: ");
 132 
 133 static char* copyright_msg = N_(
 134 "Copyright (C) 1998 - 2006 Free Software Foundation, Inc.\n"
 135 "This program is free software, covered by the GNU General Public License.\n"
 136 "\n"
 137 "This program is distributed in the hope that it will be useful,\n"
 138 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
 139 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
 140 "GNU General Public License for more details.\n\n");
 141 
 142 static char* label_type_msg;
 143 static char* flag_msg;
 144 static char* unit_msg;
 145 
 146 static char* mkfs_fs_type_msg;
 147 static char* mkpart_fs_type_msg;
 148 static char* resize_fs_type_msg;
 149 
 150 static Command* commands [256] = {NULL};
 151 static PedTimer* g_timer;
 152 static TimerContext timer_context;
 153 
 154 static int _print_list ();
 155 static void _done (PedDevice* dev);
 156 
 157 static void
 158 _timer_handler (PedTimer* timer, void* context)
 159 {
 160         TimerContext*   tcontext = (TimerContext*) context;
 161         int             draw_this_time;
 162 
 163         if (opt_script_mode || !isatty(fileno(stdout)))
 164                 return;
 165 
 166         if (tcontext->last_update != timer->now && timer->now > timer->start) {
 167                 tcontext->predicted_time_left
 168                         = timer->predicted_end - timer->now;
 169                 tcontext->last_update = timer->now;
 170                 draw_this_time = 1;
 171         } else {
 172                 draw_this_time = 0;
 173         }
 174 
 175         if (draw_this_time) {
 176                 wipe_line ();
 177 
 178                 if (timer->state_name)
 179                         printf ("%s... ", timer->state_name);
 180                 printf (_("%0.f%%\t(time left %.2d:%.2d)"),
 181                         100.0 * timer->frac,
 182                         (int) (tcontext->predicted_time_left / 60),
 183                         (int) (tcontext->predicted_time_left % 60));
 184 
 185                 fflush (stdout);
 186         }
 187 }
 188 
 189 static int
 190 _partition_warn_busy (PedPartition* part)
 191 {
 192         char* path;
 193 
 194         if (ped_partition_is_busy (part)) {
 195                 path = ped_partition_get_path (part);
 196                 ped_exception_throw (
 197                         PED_EXCEPTION_ERROR,
 198                         PED_EXCEPTION_CANCEL,
 199                         _("Partition %s is being used. You must unmount it "
 200                           "before you modify it with Parted."),
 201                         path);
 202                 ped_free (path);
 203                 return 0;
 204         }
 205         return 1;
 206 }
 207 
 208 static int
 209 _disk_warn_busy (PedDisk* disk)
 210 {
 211         if (ped_device_is_busy (disk->dev))
 212                 return ped_exception_throw (
 213                         (opt_script_mode
 214                          ? PED_EXCEPTION_ERROR
 215                          : PED_EXCEPTION_WARNING),
 216                         PED_EXCEPTION_IGNORE_CANCEL,
 217                         _("Partition(s) on %s are being used."),
 218                         disk->dev->path) == PED_EXCEPTION_IGNORE;
 219 
 220         return 1;
 221 }
 222 
 223 static int
 224 _partition_warn_loss ()
 225 {
 226         return ped_exception_throw (
 227                 PED_EXCEPTION_WARNING,
 228                 PED_EXCEPTION_YES_NO,
 229                 _("The existing file system will be destroyed and "
 230                   "all data on the partition will be lost. Do "
 231                   "you want to continue?"), 
 232                 NULL) == PED_EXCEPTION_YES;
 233 }
 234 
 235 static int
 236 _disk_warn_loss (PedDisk* disk)
 237 {
 238         return ped_exception_throw (
 239                 PED_EXCEPTION_WARNING,
 240                 PED_EXCEPTION_YES_NO,
 241                 _("The existing disk label on %s will be destroyed "
 242                   "and all data on this disk will be lost. Do you "
 243                   "want to continue?"), 
 244                 disk->dev->path) == PED_EXCEPTION_YES;
 245 }
 246 
 247 /* This function changes "sector" to "new_sector" if the new value lies
 248  * within the required range.
 249  */
 250 static int
 251 snap (PedSector* sector, PedSector new_sector, PedGeometry* range)
 252 {
 253         PED_ASSERT (ped_geometry_test_sector_inside (range, *sector), return 0);
 254         if (!ped_geometry_test_sector_inside (range, new_sector))
 255                 return 0;
 256         *sector = new_sector;
 257         return 1;
 258 }
 259 
 260 typedef enum {
 261         MOVE_NO         = 0,
 262         MOVE_STILL      = 1,
 263         MOVE_UP         = 2,
 264         MOVE_DOWN       = 4
 265 } EMoves;
 266 
 267 enum { /* Don't change these values */
 268         SECT_START      =  0,
 269         SECT_END        = -1
 270 };
 271 
 272 /* Find the prefered way to adjust the sector s inside range.
 273  * If a move isn't allowed or is out of range it can't be selected.
 274  * what contains SECT_START if the sector to adjust is a start sector
 275  * or SECT_END if it's an end one.
 276  * The prefered move is to the nearest allowed boundary of the part
 277  * partition (if at equal distance: to start if SECT_START or to end
 278  * if SECT_END).
 279  * The distance is returned in dist.
 280  */
 281 static EMoves
 282 prefer_snap (PedSector s, int what, PedGeometry* range, EMoves* allow,
 283              PedPartition* part, PedSector* dist)
 284 {
 285         PedSector up_dist = -1, down_dist = -1;
 286         PedSector new_sect;
 287         EMoves move;
 288 
 289         PED_ASSERT (what == SECT_START || what == SECT_END, return 0);
 290 
 291         if (!(*allow & (MOVE_UP | MOVE_DOWN))) {
 292                 *dist = 0;
 293                 return MOVE_STILL;
 294         }
 295 
 296         if (*allow & MOVE_UP) {
 297                 new_sect = part->geom.end + 1 + what;
 298                 if (ped_geometry_test_sector_inside (range, new_sect))
 299                         up_dist = new_sect - s;
 300                 else
 301                         *allow &= ~MOVE_UP;
 302         }
 303 
 304         if (*allow & MOVE_DOWN) {
 305                 new_sect = part->geom.start + what;
 306                 if (ped_geometry_test_sector_inside (range, new_sect))
 307                         down_dist = s - new_sect;
 308                 else
 309                         *allow &= ~MOVE_DOWN;
 310         }
 311 
 312         move = MOVE_STILL;
 313         if ((*allow & MOVE_UP) && (*allow & MOVE_DOWN)) {
 314                 if (down_dist < up_dist || (down_dist == up_dist
 315                                             && what == SECT_START) )
 316                         move = MOVE_DOWN;
 317                 else if (up_dist < down_dist || (down_dist == up_dist
 318                                                  && what == SECT_END) )
 319                         move = MOVE_UP;
 320                 else
 321                         PED_ASSERT (0, return 0);
 322         } else if (*allow & MOVE_UP)
 323                 move = MOVE_UP;
 324         else if (*allow & MOVE_DOWN)
 325                 move = MOVE_DOWN;
 326 
 327         *dist = ( move == MOVE_DOWN ? down_dist :
 328                 ( move == MOVE_UP   ? up_dist   :
 329                   0 ) );
 330         return move;
 331 }
 332 
 333 /* Snaps a partition to nearby partition boundaries.  This is useful for
 334  * gobbling up small amounts of free space, and also for reinterpreting small
 335  * changes to a partition as non-changes (eg: perhaps the user only wanted to
 336  * resize the end of a partition).
 337  *      Note that this isn't the end of the story... this function is
 338  * always called before the constraint solver kicks in.  So you don't need to
 339  * worry too much about inadvertantly creating overlapping partitions, etc.
 340  */
 341 static void
 342 snap_to_boundaries (PedGeometry* new_geom, PedGeometry* old_geom,
 343                     PedDisk* disk,
 344                     PedGeometry* start_range, PedGeometry* end_range)
 345 {
 346         PedPartition*   start_part;
 347         PedPartition*   end_part;
 348         PedSector       start = new_geom->start;
 349         PedSector       end = new_geom->end;
 350         PedSector       start_dist = -1, end_dist = -1;
 351         EMoves          start_allow, end_allow, start_want, end_want;
 352         int             adjacent;
 353 
 354         start_want = end_want = MOVE_NO;
 355         start_allow = end_allow = MOVE_STILL | MOVE_UP | MOVE_DOWN;
 356 
 357         start_part = ped_disk_get_partition_by_sector (disk, start);
 358         end_part = ped_disk_get_partition_by_sector (disk, end);
 359         adjacent = (start_part->geom.end + 1 == end_part->geom.start);
 360 
 361         /* If we can snap to old_geom, then we will... */
 362         /* and this will enforce the snapped positions  */
 363         if (old_geom) {
 364                 if (snap (&start, old_geom->start, start_range))
 365                         start_allow = MOVE_STILL;
 366                 if (snap (&end, old_geom->end, end_range))
 367                         end_allow = MOVE_STILL;
 368         }
 369 
 370         /* If start and end are on the same partition, we */
 371         /* don't allow them to cross. */
 372         if (start_part == end_part) {
 373                 start_allow &= ~MOVE_UP;
 374                 end_allow &= ~MOVE_DOWN;
 375         }
 376 
 377         /* Let's find our way */
 378         start_want = prefer_snap (start, SECT_START, start_range, &start_allow,
 379                                   start_part, &start_dist );
 380         end_want = prefer_snap (end, SECT_END, end_range, &end_allow,
 381                                 end_part, &end_dist );
 382 
 383         PED_ASSERT (start_dist >= 0 && end_dist >= 0, return);
 384 
 385         /* If start and end are on adjacent partitions,    */
 386         /* and if they would prefer crossing, then refrain */
 387         /* the farthest to do so. */
 388         if (adjacent && start_want == MOVE_UP && end_want == MOVE_DOWN) {
 389                 if (end_dist < start_dist) {
 390                         start_allow &= ~MOVE_UP;
 391                         start_want = prefer_snap (start, SECT_START,
 392                                                   start_range, &start_allow,
 393                                                   start_part, &start_dist );
 394                         PED_ASSERT (start_dist >= 0, return);
 395                 } else {
 396                         end_allow &= ~MOVE_DOWN;
 397                         end_want = prefer_snap (end, SECT_END,
 398                                                 end_range, &end_allow,
 399                                                 end_part, &end_dist );
 400                         PED_ASSERT (end_dist >= 0, return);
 401                 }
 402         }
 403 
 404         /* New positions */
 405         start = ( start_want == MOVE_DOWN ? start_part->geom.start :
 406                 ( start_want == MOVE_UP ? start_part->geom.end + 1 :
 407                   start ) );
 408         end = ( end_want == MOVE_DOWN ? end_part->geom.start - 1 :
 409               ( end_want == MOVE_UP ? end_part->geom.end :
 410                 end ) );
 411         PED_ASSERT (ped_geometry_test_sector_inside(start_range,start), return);
 412         PED_ASSERT (ped_geometry_test_sector_inside (end_range, end), return);
 413         PED_ASSERT (start <= end,
 414                     PED_DEBUG (0, "start = %d, end = %d\n", start, end));
 415         ped_geometry_set (new_geom, start, end - start + 1);
 416 }
 417 
 418 /* This functions constructs a constraint from the following information:
 419  *      start, is_start_exact, end, is_end_exact.
 420  *      
 421  * If is_start_exact == 1, then the constraint requires start be as given in
 422  * "start".  Otherwise, the constraint does not set any requirements on the
 423  * start.
 424  */
 425 static PedConstraint*
 426 constraint_from_start_end (PedDevice* dev, PedGeometry* range_start,
 427                            PedGeometry* range_end)
 428 {
 429         return ped_constraint_new (ped_alignment_any, ped_alignment_any,
 430                 range_start, range_end, 1, dev->length);
 431 }
 432 
 433 static PedConstraint*
 434 constraint_intersect_and_destroy (PedConstraint* a, PedConstraint* b)
 435 {
 436         PedConstraint* result = ped_constraint_intersect (a, b);
 437         ped_constraint_destroy (a);
 438         ped_constraint_destroy (b);
 439         return result;
 440 }
 441 
 442 void
 443 help_on (char* topic)
 444 {
 445         Command*        cmd;
 446 
 447         cmd = command_get (commands, topic);
 448         if (!cmd) return;
 449 
 450         command_print_help (cmd);
 451 }
 452 
 453 static int
 454 do_check (PedDevice** dev)
 455 {
 456         PedDisk*        disk;
 457         PedFileSystem*  fs;
 458         PedPartition*   part = NULL;
 459 
 460         disk = ped_disk_new (*dev);
 461         if (!disk)
 462                 goto error;
 463 
 464         if (!command_line_get_partition (_("Partition number?"), disk, &part))
 465                 goto error_destroy_disk;
 466         if (!_partition_warn_busy (part))
 467                 goto error_destroy_disk;
 468 
 469         if (!ped_disk_check (disk))
 470                 goto error_destroy_disk;
 471 
 472         fs = ped_file_system_open (&part->geom);
 473         if (!fs)
 474                 goto error_destroy_disk;
 475         if (!ped_file_system_check (fs, g_timer))
 476                 goto error_close_fs;
 477         ped_file_system_close (fs);
 478         ped_disk_destroy (disk);
 479         return 1;
 480 
 481 error_close_fs:
 482         ped_file_system_close (fs);
 483 error_destroy_disk:
 484         ped_disk_destroy (disk);
 485 error:
 486         return 0;
 487 }
 488 
 489 static int
 490 do_cp (PedDevice** dev)
 491 {
 492         PedDisk*                src_disk;
 493         PedDisk*                dst_disk;
 494         PedPartition*           src = NULL;
 495         PedPartition*           dst = NULL;
 496         PedFileSystem*          src_fs;
 497         PedFileSystem*          dst_fs;
 498         PedFileSystemType*      dst_fs_type;
 499 
 500         dst_disk = ped_disk_new (*dev);
 501         if (!dst_disk)
 502                 goto error;
 503 
 504         src_disk = dst_disk;
 505         if (!command_line_is_integer ()) {
 506                 if (!command_line_get_disk (_("Source device?"), &src_disk))
 507                         goto error_destroy_disk;
 508         }
 509 
 510         if (!command_line_get_partition (_("Source partition number?"),
 511                                          src_disk, &src))
 512                 goto error_destroy_disk;
 513         if (src->type == PED_PARTITION_EXTENDED) {
 514                 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
 515                         _("Can't copy an extended partition."));
 516                 goto error_destroy_disk;
 517         }
 518         if (!_partition_warn_busy (src))
 519                 goto error_destroy_disk;
 520 
 521         if (!command_line_get_partition (_("Destination partition number?"),
 522                                          dst_disk, &dst))
 523                 goto error_destroy_disk;
 524         if (!_partition_warn_busy (dst))
 525                 goto error_destroy_disk;
 526 
 527 /* do the copy */
 528         src_fs = ped_file_system_open (&src->geom);
 529         if (!src_fs)
 530                 goto error_destroy_disk;
 531         dst_fs = ped_file_system_copy (src_fs, &dst->geom, g_timer);
 532         if (!dst_fs)
 533                 goto error_close_src_fs;
 534         dst_fs_type = dst_fs->type;     /* may be different to src_fs->type */
 535         ped_file_system_close (src_fs);
 536         ped_file_system_close (dst_fs);
 537 
 538 /* update the partition table, close disks */
 539         if (!ped_partition_set_system (dst, dst_fs_type))
 540                 goto error_destroy_disk;
 541         if (!ped_disk_commit (dst_disk))
 542                 goto error_destroy_disk;
 543         if (src_disk != dst_disk)
 544                 ped_disk_destroy (src_disk);
 545         ped_disk_destroy (dst_disk);
 546 
 547         if ((*dev)->type != PED_DEVICE_FILE)
 548                 disk_is_modified = 1;
 549 
 550         return 1;
 551 
 552 error_close_src_fs:
 553         ped_file_system_close (src_fs);
 554 error_destroy_disk:
 555         if (src_disk && src_disk != dst_disk)
 556                 ped_disk_destroy (src_disk);
 557         ped_disk_destroy (dst_disk);
 558 error:
 559         return 0;
 560 }
 561 
 562 void
 563 print_commands_help ()
 564 {
 565         int             i;
 566 
 567         for (i=0; commands [i]; i++)
 568                 command_print_summary (commands [i]);
 569 }
 570 
 571 void
 572 print_options_help ()
 573 {
 574         int             i;
 575 
 576         for (i=0; options_help [i][0]; i++) {
 577                 printf ("  -%c, --%-23.23s %s\n",
 578                         options_help [i][0][0],
 579                         options_help [i][0],
 580                         _(options_help [i][1]));
 581         }
 582 }
 583 
 584 int
 585 do_help (PedDevice** dev)
 586 {
 587         if (command_line_get_word_count ()) {
 588                 char*   word = command_line_pop_word ();
 589                 if (word) {
 590                         help_on (word);
 591                         free (word);
 592                 }
 593         } else {
 594                 print_commands_help();
 595         }
 596         return 1;
 597 }
 598 
 599 static int
 600 do_mklabel (PedDevice** dev)
 601 {
 602         PedDisk*                disk;
 603         const PedDiskType*      type = ped_disk_probe (*dev);
 604 
 605         ped_exception_fetch_all ();
 606         disk = ped_disk_new (*dev);
 607         if (!disk) ped_exception_catch ();
 608         ped_exception_leave_all ();
 609 
 610         if (disk) {
 611                 if (!_disk_warn_busy (disk))
 612                         goto error_destroy_disk;
 613                 if (!opt_script_mode && !_disk_warn_loss (disk))
 614                         goto error_destroy_disk;
 615 
 616                 ped_disk_destroy (disk);
 617         }
 618 
 619         if (!command_line_get_disk_type (_("New disk label type?"), &type))
 620                 goto error;
 621 
 622         disk = ped_disk_new_fresh (*dev, type);
 623         if (!disk)
 624                 goto error;
 625 
 626         if (!ped_disk_commit (disk))
 627                 goto error_destroy_disk;
 628         ped_disk_destroy (disk);
 629 
 630         if ((*dev)->type != PED_DEVICE_FILE)
 631                 disk_is_modified = 1;
 632 
 633         return 1;
 634 
 635 error_destroy_disk:
 636         ped_disk_destroy (disk);
 637 error:
 638         return 0;
 639 }
 640 
 641 static int
 642 do_mkfs (PedDevice** dev)
 643 {
 644         PedDisk*                disk;
 645         PedPartition*           part = NULL;
 646         const PedFileSystemType* type = ped_file_system_type_get ("ext2");
 647         PedFileSystem*          fs;
 648 
 649         disk = ped_disk_new (*dev);
 650         if (!disk)
 651                 goto error;
 652 
 653         if  (!opt_script_mode && !_partition_warn_loss())
 654                 goto error_destroy_disk;
 655 
 656         if (!command_line_get_partition (_("Partition number?"), disk, &part))
 657                 goto error_destroy_disk;
 658         if (!_partition_warn_busy (part))
 659                 goto error_destroy_disk;
 660         if (!command_line_get_fs_type (_("File system type?"), &type))
 661                 goto error_destroy_disk;
 662 
 663         fs = ped_file_system_create (&part->geom, type, g_timer);
 664         if (!fs)
 665                 goto error_destroy_disk;
 666         ped_file_system_close (fs);
 667 
 668         if (!ped_partition_set_system (part, type))
 669                 goto error_destroy_disk;
 670         if (ped_partition_is_flag_available (part, PED_PARTITION_LBA))
 671                 ped_partition_set_flag (part, PED_PARTITION_LBA, 1);
 672         if (!ped_disk_commit (disk))
 673                 goto error_destroy_disk;
 674         ped_disk_destroy (disk);
 675 
 676         if ((*dev)->type != PED_DEVICE_FILE)
 677                 disk_is_modified = 1;
 678 
 679         return 1;
 680 
 681 error_destroy_disk:
 682         ped_disk_destroy (disk);
 683 error:
 684         return 0;
 685 }
 686 
 687 static int
 688 do_mkpart (PedDevice** dev)
 689 {
 690         PedDisk*                 disk;
 691         PedPartition*            part;
 692         PedPartitionType         part_type;
 693         const PedFileSystemType* fs_type = ped_file_system_type_get ("ext2");
 694         PedSector                start = 0, end = 0;
 695         PedGeometry              *range_start = NULL, *range_end = NULL;
 696         PedConstraint*           user_constraint;
 697         PedConstraint*           dev_constraint;
 698         PedConstraint*           final_constraint;
 699         char*                    peek_word;
 700         char*                    part_name = NULL;
 701         char                     *start_usr = NULL, *end_usr = NULL;
 702         char                     *start_sol = NULL, *end_sol = NULL;
 703         
 704         disk = ped_disk_new (*dev);
 705         if (!disk)
 706                 goto error;
 707 
 708         if (!ped_disk_type_check_feature (disk->type, PED_DISK_TYPE_EXTENDED)) {
 709                 part_type = PED_PARTITION_NORMAL;
 710         } else {
 711                 if (!command_line_get_part_type (_("Partition type?"),
 712                                                 disk, &part_type))
 713                         goto error_destroy_disk;
 714         }
 715 
 716         if (ped_disk_type_check_feature (disk->type,
 717                                          PED_DISK_TYPE_PARTITION_NAME)) 
 718                 part_name = command_line_get_word (_("Partition name?"),
 719                                                    "", NULL, 1); 
 720                 
 721         peek_word = command_line_peek_word ();
 722         if (part_type == PED_PARTITION_EXTENDED
 723             || (peek_word && isdigit (peek_word[0]))) {
 724                 fs_type = NULL;
 725         } else {
 726                 if (!command_line_get_fs_type (_("File system type?"),
 727                                                &fs_type))
 728                         goto error_destroy_disk;
 729         }
 730         if (peek_word)
 731                 ped_free (peek_word);
 732 
 733         if (!command_line_get_sector (_("Start?"), *dev, &start, &range_start))
 734                 goto error_destroy_disk;
 735         if (!command_line_get_sector (_("End?"), *dev, &end, &range_end))
 736                 goto error_destroy_disk;
 737         
 738         /* processing starts here */
 739         part = ped_partition_new (disk, part_type, fs_type, start, end);
 740         if (!part)
 741                 goto error_destroy_disk;
 742 
 743         snap_to_boundaries (&part->geom, NULL, disk, range_start, range_end);
 744 
 745         /* create constraints */
 746         user_constraint = constraint_from_start_end (*dev, range_start,
 747                         range_end);
 748         PED_ASSERT (user_constraint != NULL, return 0);
 749 
 750         dev_constraint = ped_device_get_constraint (*dev);
 751         PED_ASSERT (dev_constraint != NULL, return 0);
 752 
 753         final_constraint = ped_constraint_intersect (user_constraint,
 754                         dev_constraint);
 755         if (!final_constraint)
 756                 goto error_destroy_simple_constraints;
 757 
 758         /* subject to partition constraint */
 759         ped_exception_fetch_all();
 760         if (!ped_disk_add_partition (disk, part, final_constraint)) {
 761                 ped_exception_leave_all();
 762                
 763                 if (ped_disk_add_partition (disk, part,
 764                                         ped_constraint_any (*dev))) {
 765                         start_usr = ped_unit_format (*dev, start);
 766                         end_usr   = ped_unit_format (*dev, end);
 767                         start_sol = ped_unit_format (*dev, part->geom.start);
 768                         end_sol   = ped_unit_format (*dev, part->geom.end);
 769 
 770                         switch (ped_exception_throw (
 771                                 PED_EXCEPTION_WARNING,
 772                                 PED_EXCEPTION_YES_NO,
 773                                 _("You requested a partition from %s to %s.\n"
 774                                   "The closest location we can manage is "
 775                                   "%s to %s.  "
 776                                   "Is this still acceptable to you?"),
 777                                 start_usr, end_usr, start_sol, end_sol))
 778                         {
 779                                 case PED_EXCEPTION_YES:
 780                                         /* all is well in this state */
 781                                         break;
 782                                 case PED_EXCEPTION_NO:
 783                                 case PED_EXCEPTION_UNHANDLED:
 784                                 default:
 785                                         /* undo partition addition */
 786                                         goto error_remove_part;
 787                         }
 788                 } else {
 789                         goto error_remove_part;
 790                 }
 791         } else {
 792                 ped_exception_leave_all();
 793         }
 794         ped_exception_catch();
 795 
 796         /* set minor attributes */
 797         if (part_name)
 798                 PED_ASSERT (ped_partition_set_name (part, part_name), return 0);
 799         if (!ped_partition_set_system (part, fs_type))
 800                 goto error_destroy_disk;
 801         if (ped_partition_is_flag_available (part, PED_PARTITION_LBA))
 802                 ped_partition_set_flag (part, PED_PARTITION_LBA, 1);
 803         
 804         if (!ped_disk_commit (disk))
 805                 goto error_destroy_disk;
 806         
 807         /* clean up */
 808         ped_constraint_destroy (final_constraint);
 809         ped_constraint_destroy (user_constraint);
 810         ped_constraint_destroy (dev_constraint);
 811 
 812         ped_disk_destroy (disk);
 813         
 814         if (range_start != NULL)
 815                 ped_geometry_destroy (range_start);
 816         if (range_end != NULL)
 817                 ped_geometry_destroy (range_end);
 818         
 819         if (start_usr != NULL)
 820                 ped_free (start_usr);
 821         if (end_usr != NULL)
 822                 ped_free (end_usr);
 823         if (start_sol != NULL)
 824                 ped_free (start_sol);
 825         if (end_sol != NULL)
 826                 ped_free (end_sol);
 827 
 828         if ((*dev)->type != PED_DEVICE_FILE)
 829                 disk_is_modified = 1;
 830 
 831         return 1;
 832 
 833 error_remove_part:
 834         ped_disk_remove_partition (disk, part);
 835         ped_constraint_destroy (final_constraint);
 836 error_destroy_simple_constraints:
 837         ped_constraint_destroy (user_constraint);
 838         ped_constraint_destroy (dev_constraint);
 839         ped_partition_destroy (part);
 840 error_destroy_disk:
 841         ped_disk_destroy (disk);
 842 error:
 843         if (range_start != NULL)
 844                 ped_geometry_destroy (range_start);
 845         if (range_end != NULL)
 846                 ped_geometry_destroy (range_end);
 847 
 848         if (start_usr != NULL)
 849                 ped_free (start_usr);
 850         if (end_usr != NULL)
 851                 ped_free (end_usr);
 852         if (start_sol != NULL)
 853                 ped_free (start_sol);
 854         if (end_sol != NULL)
 855                 ped_free (end_sol);
 856 
 857         return 0;
 858 }
 859 
 860 static int
 861 do_mkpartfs (PedDevice** dev)
 862 {
 863         PedDisk*            disk;
 864         PedPartition*       part;
 865         PedPartitionType    part_type;
 866         const PedFileSystemType* fs_type = ped_file_system_type_get ("ext2");
 867         PedSector           start = 0, end = 0;
 868         PedGeometry         *range_start = NULL, *range_end = NULL;
 869         PedConstraint*      user_constraint;
 870         PedConstraint*      dev_constraint;
 871         PedConstraint*      final_constraint;
 872         PedFileSystem*      fs;
 873         char*               part_name = NULL;
 874         char                *start_usr = NULL, *end_usr = NULL;
 875         char                *start_sol = NULL, *end_sol = NULL;
 876 
 877         disk = ped_disk_new (*dev);
 878         if (!disk)
 879                 goto error;
 880 
 881         if (!ped_disk_type_check_feature (disk->type, PED_DISK_TYPE_EXTENDED)) {
 882                 part_type = PED_PARTITION_NORMAL;
 883         } else {
 884                 if (!command_line_get_part_type (_("Partition type?"),
 885                                                 disk, &part_type))
 886                         goto error_destroy_disk;
 887         }
 888 
 889         if (ped_disk_type_check_feature (disk->type,
 890                                          PED_DISK_TYPE_PARTITION_NAME)) 
 891                 part_name = command_line_get_word (_("Partition name?"),
 892                                                    "", NULL, 1); 
 893 
 894         if (part_type == PED_PARTITION_EXTENDED) {
 895                 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
 896                         _("An extended partition cannot hold a file system.  "
 897                           "Did you want mkpart?"));
 898                 goto error_destroy_disk;
 899         }
 900 
 901         if (!command_line_get_fs_type (_("File system type?"), &fs_type))
 902                 goto error_destroy_disk;
 903         if (!command_line_get_sector (_("Start?"), *dev, &start,
 904                                       &range_start))
 905                 goto error_destroy_disk;
 906         if (!command_line_get_sector (_("End?"), *dev, &end, &range_end))
 907                 goto error_destroy_disk;
 908 
 909         /* attempt to create the partition now */
 910         part = ped_partition_new (disk, part_type, fs_type, start, end);
 911         if (!part)
 912                 goto error_destroy_disk;
 913 
 914         snap_to_boundaries (&part->geom, NULL, disk, range_start, range_end);
 915 
 916         /* create constraints */
 917         user_constraint = constraint_from_start_end (*dev, range_start,
 918                                                                 range_end);
 919         PED_ASSERT (user_constraint != NULL, return 0);
 920 
 921         dev_constraint = ped_device_get_constraint (*dev);
 922         PED_ASSERT (dev_constraint != NULL, return 0);
 923 
 924         final_constraint = ped_constraint_intersect (user_constraint,
 925                                                      dev_constraint);
 926         if (!final_constraint)
 927                 goto error_destroy_simple_constraints;
 928 
 929         /* subject to partition constraint */
 930         ped_exception_fetch_all();
 931         if (!ped_disk_add_partition (disk, part, final_constraint)) {
 932                 ped_exception_leave_all();
 933                
 934                 if (ped_disk_add_partition (disk, part,
 935                                         ped_constraint_any (*dev))) {
 936                         start_usr = ped_unit_format (*dev, start);
 937                         end_usr   = ped_unit_format (*dev, end);
 938                         start_sol = ped_unit_format (*dev, part->geom.start);
 939                         end_sol   = ped_unit_format (*dev, part->geom.end);
 940 
 941                         switch (ped_exception_throw (
 942                                 PED_EXCEPTION_WARNING,
 943                                 PED_EXCEPTION_YES_NO,
 944                                 _("You requested a partition from %s to %s.\n"
 945                                   "The closest location we can manage is "
 946                                   "%s to %s.  "
 947                                   "Is this still acceptable to you?"),
 948                                 start_usr, end_usr, start_sol, end_sol)) {
 949                                 case PED_EXCEPTION_YES:
 950                                         /* all is well in this state */
 951                                         break;
 952                                 case PED_EXCEPTION_NO:
 953                                 case PED_EXCEPTION_UNHANDLED:
 954                                 default:
 955                                         /* undo partition addition */
 956                                         goto error_remove_part;
 957                         }
 958                 } else {
 959                         goto error_remove_part;
 960                 }
 961         } else {
 962                 ped_exception_leave_all();
 963         }
 964         ped_exception_catch();
 965 
 966         /* set LBA flag automatically if available */
 967         if (ped_partition_is_flag_available (part, PED_PARTITION_LBA))
 968                 ped_partition_set_flag (part, PED_PARTITION_LBA, 1);
 969 
 970         /* fs creation */
 971         fs = ped_file_system_create (&part->geom, fs_type, g_timer);
 972         if (!fs) 
 973                 goto error_destroy_disk;
 974         ped_file_system_close (fs);
 975 
 976         if (!ped_partition_set_system (part, fs_type))
 977                 goto error_destroy_disk;
 978 
 979         if (!ped_disk_commit (disk))
 980                 goto error_destroy_disk;
 981 
 982         /* clean up */
 983         ped_constraint_destroy (final_constraint);
 984         ped_constraint_destroy (user_constraint);
 985         ped_constraint_destroy (dev_constraint);
 986 
 987         ped_disk_destroy (disk);
 988 
 989         if (range_start != NULL)
 990                 ped_geometry_destroy (range_start);
 991         if (range_end != NULL)
 992                 ped_geometry_destroy (range_end);
 993 
 994         if (start_usr != NULL)
 995                 ped_free (start_usr);
 996         if (end_usr != NULL)
 997                 ped_free (end_usr);
 998         if (start_sol != NULL)
 999                 ped_free (start_sol);
1000         if (end_sol != NULL)
1001                 ped_free (end_sol);
1002 
1003         if ((*dev)->type != PED_DEVICE_FILE)
1004                 disk_is_modified = 1;
1005 
1006         return 1;
1007 
1008 error_remove_part:
1009         ped_disk_remove_partition (disk, part);
1010         ped_constraint_destroy (final_constraint);
1011 error_destroy_simple_constraints:
1012         ped_constraint_destroy (user_constraint);
1013         ped_constraint_destroy (dev_constraint);
1014         ped_partition_destroy (part);
1015 error_destroy_disk:
1016         ped_disk_destroy (disk);
1017 error:
1018         if (range_start != NULL)
1019                 ped_geometry_destroy (range_start);
1020         if (range_end != NULL)
1021                 ped_geometry_destroy (range_end);
1022 
1023         if (start_usr != NULL)
1024                 ped_free (start_usr);
1025         if (end_usr != NULL)
1026                 ped_free (end_usr);
1027         if (start_sol != NULL)
1028                 ped_free (start_sol);
1029         if (end_sol != NULL)
1030                 ped_free (end_sol);
1031 
1032         return 0;
1033 }
1034 
1035 static int
1036 do_move (PedDevice** dev)
1037 {
1038         PedDisk*        disk;
1039         PedPartition*   part = NULL;
1040         PedFileSystem*  fs;
1041         PedFileSystem*  fs_copy;
1042         PedConstraint*  constraint;
1043         PedSector       start = 0, end = 0;
1044         PedGeometry     *range_start = NULL, *range_end = NULL;
1045         PedGeometry     old_geom, new_geom;
1046 
1047         disk = ped_disk_new (*dev);
1048         if (!disk)
1049                 goto error;
1050 
1051         if (!command_line_get_partition (_("Partition number?"), disk, &part))
1052                 goto error_destroy_disk;
1053         if (!_partition_warn_busy (part))
1054                 goto error_destroy_disk;
1055         if (part->type == PED_PARTITION_EXTENDED) {
1056                 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
1057                         _("Can't move an extended partition."));
1058                 goto error_destroy_disk;
1059         }
1060         old_geom = part->geom;
1061         fs = ped_file_system_open (&old_geom);
1062         if (!fs)
1063                 goto error_destroy_disk;
1064 
1065         /* get new target */
1066         if (!command_line_get_sector (_("Start?"), *dev, &start, &range_start))
1067                 goto error_close_fs;
1068         end = start + old_geom.length - 1;
1069         if (!command_line_get_sector (_("End?"), *dev, &end, &range_end))
1070                 goto error_close_fs;
1071 
1072         /* set / test on "disk" */
1073         if (!ped_geometry_init (&new_geom, *dev, start, end - start + 1))
1074                 goto error_close_fs;
1075         snap_to_boundaries (&new_geom, NULL, disk, range_start, range_end);
1076 
1077         constraint = constraint_intersect_and_destroy (
1078                         ped_file_system_get_copy_constraint (fs, *dev),
1079                         constraint_from_start_end(*dev,range_start,range_end));
1080         if (!ped_disk_set_partition_geom (disk, part, constraint,
1081                                           new_geom.start, new_geom.end))
1082                 goto error_destroy_constraint;
1083         ped_constraint_destroy (constraint);
1084         if (ped_geometry_test_overlap (&old_geom, &part->geom)) {
1085                 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
1086                         _("Can't move a partition onto itself.  Try using "
1087                           "resize, perhaps?"));
1088                 goto error_close_fs;
1089         }
1090 
1091         /* do the move */
1092         fs_copy = ped_file_system_copy (fs, &part->geom, g_timer);
1093         if (!fs_copy)
1094                 goto error_close_fs;
1095         ped_file_system_close (fs_copy);
1096         ped_file_system_close (fs);
1097         if (!ped_disk_commit (disk))
1098                 goto error_destroy_disk;
1099         ped_disk_destroy (disk);
1100         if (range_start != NULL)
1101                 ped_geometry_destroy (range_start);
1102         if (range_end != NULL)
1103                 ped_geometry_destroy (range_end);
1104 
1105         if ((*dev)->type != PED_DEVICE_FILE)
1106                 disk_is_modified = 1;
1107 
1108         return 1;
1109 
1110 error_destroy_constraint:
1111         ped_constraint_destroy (constraint);
1112 error_close_fs:
1113         ped_file_system_close (fs);
1114 error_destroy_disk:
1115         ped_disk_destroy (disk);
1116 error:
1117         if (range_start != NULL)
1118                 ped_geometry_destroy (range_start);
1119         if (range_end != NULL)
1120                 ped_geometry_destroy (range_end);
1121         return 0;
1122 }
1123 
1124 static int
1125 do_name (PedDevice** dev)
1126 {
1127         PedDisk*        disk;
1128         PedPartition*   part = NULL;
1129         char*           name;
1130 
1131         disk = ped_disk_new (*dev);
1132         if (!disk)
1133                 goto error;
1134 
1135         if (!command_line_get_partition (_("Partition number?"), disk, &part))
1136                 goto error_destroy_disk;
1137 
1138         name = command_line_get_word (_("Partition name?"),
1139                         ped_partition_get_name (part), NULL, 0);
1140         if (!name)
1141                 goto error_destroy_disk;
1142         if (!ped_partition_set_name (part, name))
1143                 goto error_free_name;
1144         free (name);
1145 
1146         if (!ped_disk_commit (disk))
1147                 goto error_destroy_disk;
1148         ped_disk_destroy (disk);
1149         return 1;
1150 
1151 error_free_name:
1152         free (name);
1153 error_destroy_disk:
1154         ped_disk_destroy (disk);
1155 error:
1156         return 0;
1157 }
1158 
1159 static char*
1160 partition_print_flags (PedPartition* part)
1161 {
1162         PedPartitionFlag        flag;
1163         int                     first_flag;
1164         const char*             name;
1165         char*                   res = ped_malloc(1); 
1166         void*                   _res = res;
1167 
1168         *res = '\0';
1169 
1170         first_flag = 1;
1171         for (flag = ped_partition_flag_next (0); flag;
1172              flag = ped_partition_flag_next (flag)) {
1173                 if (ped_partition_get_flag (part, flag)) {
1174                         if (first_flag)
1175                                 first_flag = 0;
1176                         else {
1177                                 _res = res;
1178                                 ped_realloc (&_res, strlen (res)
1179                                                            + 1 + 2);
1180                                 res = _res;
1181                                 strncat (res, ", ", 2);
1182                         }
1183 
1184                         name = _(ped_partition_flag_get_name (flag));
1185                         _res = res;
1186                         ped_realloc (&_res, strlen (res) + 1
1187                                                    + strlen (name));
1188                         res = _res;
1189                         strncat (res, name, 21);
1190                 }
1191         }
1192 
1193         return res;
1194 }
1195 
1196 /* Prints a sector out, first in compact form, and then with a percentage.
1197  * Eg: 32Gb (40%)
1198  */
1199 static void
1200 print_sector_compact_and_percent (PedSector sector, PedDevice* dev)
1201 {
1202         char* compact;
1203         char* percent;
1204 
1205         if (ped_unit_get_default() == PED_UNIT_PERCENT)
1206                 compact = ped_unit_format (dev, sector);
1207         else
1208                 compact = ped_unit_format_custom (dev, sector,
1209                                                   PED_UNIT_COMPACT);
1210 
1211         percent = ped_unit_format_custom (dev, sector, PED_UNIT_PERCENT);
1212 
1213         printf ("%s (%s)\n", compact, percent);
1214 
1215         ped_free (compact);
1216         ped_free (percent);
1217 }
1218 
1219 static int
1220 partition_print (PedPartition* part)
1221 {
1222         PedFileSystem*  fs;
1223         PedConstraint*  resize_constraint;
1224         char*           flags;
1225 
1226         fs = ped_file_system_open (&part->geom);
1227         if (!fs)
1228                 return 1;
1229 
1230         putchar ('\n');
1231 
1232         flags = partition_print_flags (part);
1233      
1234         printf (_("Minor: %d\n"), part->num);
1235         printf (_("Flags: %s\n"), flags);
1236         printf (_("File System: %s\n"), fs->type->name);
1237         fputs (_("Size:         "), stdout);
1238         print_sector_compact_and_percent (part->geom.length, part->geom.dev);
1239 
1240         resize_constraint = ped_file_system_get_resize_constraint (fs);
1241         if (resize_constraint) {
1242                 fputs (_("Minimum size: "), stdout);
1243                 print_sector_compact_and_percent (resize_constraint->min_size,
1244                         part->geom.dev);
1245                 fputs (_("Maximum size: "), stdout);
1246                 print_sector_compact_and_percent (resize_constraint->max_size,
1247                         part->geom.dev);
1248                 ped_constraint_destroy (resize_constraint);
1249         }
1250 
1251         putchar ('\n');
1252 
1253         ped_free (flags);
1254         ped_file_system_close (fs);
1255 
1256         return 1;
1257 }
1258 
1259 static int
1260 do_print (PedDevice** dev)
1261 {
1262         PedUnit         default_unit;
1263         PedDisk*        disk;
1264         Table*          table;
1265         int             has_extended;
1266         int             has_name;
1267         int             has_devices_arg = 0;
1268         int             has_free_arg = 0;
1269         int             has_list_arg = 0;
1270         int             has_num_arg = 0;
1271         char*           transport[13] = {"unknown", "scsi", "ide", "dac960",
1272                                          "cpqarray", "file", "ataraid", "i2o",
1273                                          "ubd", "dasd", "viodasd", "sx8", "dm"};
1274         char*           peek_word;
1275         char*           start;
1276         char*           end;
1277         char*           size;
1278         const char*     name;
1279         char*           tmp;
1280         wchar_t*        table_rendered;
1281 
1282         disk = ped_disk_new (*dev);
1283         if (!disk)
1284                 goto error;
1285 
1286         peek_word = command_line_peek_word ();
1287         if (peek_word) {
1288                 if (strncmp (peek_word, "devices", 7) == 0) {
1289                         command_line_pop_word();
1290                         has_devices_arg = 1;
1291                 }
1292                 else if (strncmp (peek_word, "free", 4) == 0) {
1293                         command_line_pop_word ();
1294                         has_free_arg = 1;
1295                 } 
1296                 else if (strncmp (peek_word, "list", 4) == 0 ||
1297                          strncmp (peek_word, "all", 3) == 0) {
1298                         command_line_pop_word();
1299                         has_list_arg = 1;
1300                 }
1301                 else
1302                         has_num_arg = isdigit(peek_word[0]);
1303 
1304                 ped_free (peek_word);
1305         }
1306 
1307         if (has_devices_arg) {
1308                 char*           dev_name;
1309                 PedDevice*      current_dev = NULL;
1310 
1311                 ped_device_probe_all();
1312 
1313                 while ((current_dev = ped_device_get_next(current_dev))) {
1314                         end = ped_unit_format_byte (current_dev,
1315                                              current_dev->length
1316                                              * current_dev->sector_size);
1317                         printf ("%s (%s)\n", current_dev->path, end);
1318                         ped_free (end);
1319                 }    
1320 
1321                 dev_name = xstrdup ((*dev)->path);
1322                 ped_device_free_all ();
1323 
1324                 *dev = ped_device_get (dev_name);
1325                 if (!*dev)
1326                         return 0;
1327                 if (!ped_device_open (*dev))
1328                         return 0;
1329 
1330                 ped_free (dev_name);
1331 
1332                 return 1;
1333         }
1334 
1335         else if (has_list_arg) 
1336                 return _print_list ();
1337 
1338         else if (has_num_arg) {
1339                 PedPartition*   part = NULL;
1340                 int             status = 0;
1341                 if (command_line_get_partition ("", disk, &part))
1342                         status = partition_print (part);
1343                 ped_disk_destroy (disk);
1344                 return status;
1345         }
1346 
1347         start = ped_unit_format (*dev, 0);
1348         default_unit = ped_unit_get_default ();
1349         end = ped_unit_format_byte (*dev, (*dev)->length * (*dev)->sector_size
1350                                     - (default_unit == PED_UNIT_CHS ||
1351                                        default_unit == PED_UNIT_CYLINDER));
1352 
1353         if (opt_machine_mode) {
1354             switch (default_unit) {
1355                 case PED_UNIT_CHS:      puts ("CHS;");
1356                                         break;
1357                 case PED_UNIT_CYLINDER: puts ("CYL;");
1358                                         break;
1359                 default:                puts ("BYT;");
1360                                         break;
1361 
1362             }
1363             printf ("%s:%s:%s:%lld:%lld:%s:%s;\n",
1364                     (*dev)->path, end, transport[(*dev)->type],
1365                     (*dev)->sector_size, (*dev)->phys_sector_size,
1366                     disk->type->name, (*dev)->model);
1367         } else {
1368             printf (_("Model: %s (%s)\n"), 
1369                     (*dev)->model, transport[(*dev)->type]);
1370             printf (_("Disk %s: %s\n"), (*dev)->path, end);
1371             printf (_("Sector size (logical/physical): %lldB/%lldB\n"),
1372                     (*dev)->sector_size, (*dev)->phys_sector_size);
1373         }
1374 
1375         ped_free (start);
1376         ped_free (end);
1377 
1378         if (ped_unit_get_default () == PED_UNIT_CHS
1379             || ped_unit_get_default () == PED_UNIT_CYLINDER) {
1380                 PedCHSGeometry* chs = &(*dev)->bios_geom;
1381                 char* cyl_size = ped_unit_format_custom (*dev,
1382                                         chs->heads * chs->sectors,
1383                                         PED_UNIT_KILOBYTE);
1384                 
1385                 if (opt_machine_mode) {
1386                     printf ("%d:%d:%d:%s;\n",
1387                             chs->cylinders, chs->heads, chs->sectors, cyl_size);
1388                 } else {
1389                     printf (_("BIOS cylinder,head,sector geometry: %d,%d,%d.  "
1390                               "Each cylinder is %s.\n"),
1391                             chs->cylinders, chs->heads, chs->sectors, cyl_size);
1392                 }
1393 
1394                 ped_free (cyl_size);
1395         }
1396 
1397         if (!opt_machine_mode) {
1398             printf (_("Partition Table: %s\n"), disk->type->name);
1399             putchar ('\n');
1400         }
1401         
1402         has_extended = ped_disk_type_check_feature (disk->type,
1403                                          PED_DISK_TYPE_EXTENDED);
1404         has_name = ped_disk_type_check_feature (disk->type,
1405                                          PED_DISK_TYPE_PARTITION_NAME);
1406 
1407         
1408         PedPartition* part;
1409         if (!opt_machine_mode) {
1410             StrList *row1;
1411 
1412             if (ped_unit_get_default() == PED_UNIT_CHS) {
1413                     row1 = str_list_create (_("Number"), _("Start"),
1414                                                _("End"), NULL);
1415             } else {
1416                     row1 = str_list_create (_("Number"), _("Start"),
1417                                                _("End"), _("Size"), NULL);
1418             }
1419 
1420             if (has_extended)
1421                     str_list_append (row1, _("Type"));
1422 
1423             str_list_append (row1, _("File system"));
1424 
1425             if (has_name)
1426                     str_list_append (row1, _("Name"));
1427 
1428             str_list_append (row1, _("Flags"));
1429 
1430 
1431             table = table_new (str_list_length(row1));
1432 
1433             table_add_row_from_strlist (table, row1);
1434 
1435             for (part = ped_disk_next_partition (disk, NULL); part;
1436                  part = ped_disk_next_partition (disk, part)) {
1437 
1438                     if ((!has_free_arg && !ped_partition_is_active(part)) ||
1439                         part->type & PED_PARTITION_METADATA)
1440                             continue;
1441 
1442                     tmp = ped_malloc (4);
1443 
1444                     if (part->num >= 0)
1445                             sprintf (tmp, "%2d ", part->num);
1446                     else
1447                             sprintf (tmp, "%2s ", "");
1448 
1449                     StrList *row = str_list_create (tmp, NULL);
1450 
1451                     start = ped_unit_format (*dev, part->geom.start);
1452                     end = ped_unit_format_byte (
1453                             *dev,
1454                             (part->geom.end + 1) * (*dev)->sector_size - 1);
1455                     size = ped_unit_format (*dev, part->geom.length);
1456                     if (ped_unit_get_default() == PED_UNIT_CHS) {
1457                             str_list_append (row, start);
1458                             str_list_append (row, end);
1459                     } else {
1460                             str_list_append (row, start);
1461                             str_list_append (row, end);
1462                             str_list_append (row, size);
1463                     }
1464 
1465                     if (!(part->type & PED_PARTITION_FREESPACE)) {
1466                             if (has_extended) {
1467                                 name = ped_partition_type_get_name (part->type);
1468                                 str_list_append (row, name);
1469                             }
1470 
1471                             str_list_append (row, part->fs_type ?
1472                                              part->fs_type->name : "");
1473 
1474                             if (has_name) {
1475                                     name = ped_partition_get_name (part);
1476                                     str_list_append (row, name);
1477                             }
1478 
1479                             str_list_append (row, partition_print_flags (part));
1480                     } else {
1481                             if (has_extended)
1482                                     str_list_append (row, "");
1483                             str_list_append (row, _("Free Space"));
1484                             if (has_name)
1485                                     str_list_append (row, "");
1486                             str_list_append (row, "");
1487                     }
1488 
1489                     //PED_ASSERT (row.cols == caption.cols)
1490                     table_add_row_from_strlist (table, row);
1491                     str_list_destroy (row);
1492             }
1493 
1494             table_rendered = table_render (table); 
1495 #ifdef ENABLE_NLS
1496             printf("%ls\n", table_rendered);
1497 #else
1498             printf("%s\n", table_rendered);
1499 #endif
1500             ped_free (table_rendered);
1501             table_destroy (table);
1502             str_list_destroy (row1);
1503 
1504         } else {
1505     
1506             for (part = ped_disk_next_partition (disk, NULL); part;
1507                  part = ped_disk_next_partition (disk, part)) {
1508 
1509                 if ((!has_free_arg && !ped_partition_is_active(part)) ||
1510                         part->type & PED_PARTITION_METADATA)
1511                             continue; 
1512                 
1513                 if (part->num >= 0)
1514                     printf ("%d:", part->num);
1515                 else
1516                     fputs ("1:", stdout);
1517 
1518                 printf ("%s:", ped_unit_format (*dev, part->geom.start));
1519                 printf ("%s:", ped_unit_format_byte (
1520                                 *dev,
1521                                 (part->geom.end + 1) * 
1522                                 (*dev)->sector_size - 1));
1523 
1524                 if (ped_unit_get_default() != PED_UNIT_CHS)
1525                     printf ("%s:", ped_unit_format (*dev,
1526                                                     part->geom.length));
1527                     
1528                 if (!(part->type & PED_PARTITION_FREESPACE)) {
1529 
1530                     if (part->fs_type)
1531                         printf ("%s:", part->fs_type->name);
1532                     else
1533                         putchar (':');
1534 
1535                     if (has_name) 
1536                         printf ("%s:", _(ped_partition_get_name (part)));
1537                     else
1538                         putchar (':');
1539 
1540                     printf ("%s;\n", partition_print_flags (part));
1541 
1542                 } else {
1543                     puts ("free;");
1544                 }
1545             }
1546         }
1547 
1548         ped_disk_destroy (disk);
1549 
1550         return 1;
1551 
1552         ped_disk_destroy (disk);
1553 error:
1554         return 0;
1555 }
1556 
1557 static int
1558 _print_list ()
1559 {
1560         PedDevice *current_dev = NULL;
1561 
1562         ped_device_probe_all();
1563 
1564         while ((current_dev = ped_device_get_next(current_dev))) {
1565                 do_print (&current_dev);
1566                 putchar ('\n');
1567         }    
1568 
1569         return 1;
1570 }
1571 
1572 static int
1573 do_quit (PedDevice** dev)
1574 {
1575         _done (*dev);
1576         exit (0);
1577 }
1578 
1579 static PedPartitionType
1580 _disk_get_part_type_for_sector (PedDisk* disk, PedSector sector)
1581 {
1582         PedPartition*   extended;
1583 
1584         extended = ped_disk_extended_partition (disk);
1585         if (!extended
1586             || !ped_geometry_test_sector_inside (&extended->geom, sector))
1587                 return 0;
1588 
1589         return PED_PARTITION_LOGICAL;
1590 }
1591 
1592 /* This function checks if "part" contains a file system, and returs
1593  *      0 if either no file system was found, or the user declined to add it.
1594  *      1 if a file system was found, and the user chose to add it.
1595  *      -1 if the user chose to cancel the entire search.
1596  */
1597 static int
1598 _rescue_add_partition (PedPartition* part)
1599 {
1600         const PedFileSystemType*        fs_type;
1601         PedGeometry*                    probed;
1602         PedExceptionOption              ex_opt;
1603         PedConstraint*                  constraint;
1604         char*                           found_start;
1605         char*                           found_end;
1606 
1607         fs_type = ped_file_system_probe (&part->geom);
1608         if (!fs_type)
1609                 return 0;
1610         probed = ped_file_system_probe_specific (fs_type, &part->geom);
1611         if (!probed)
1612                 return 0;
1613 
1614         if (!ped_geometry_test_inside (&part->geom, probed)) {
1615                 ped_geometry_destroy (probed);
1616                 return 0;
1617         }
1618 
1619         constraint = ped_constraint_exact (probed);
1620         if (!ped_disk_set_partition_geom (part->disk, part, constraint,
1621                                           probed->start, probed->end)) {
1622                 ped_constraint_destroy (constraint);
1623                 return 0;
1624         }
1625         ped_constraint_destroy (constraint);
1626 
1627         found_start = ped_unit_format (probed->dev, probed->start);
1628         found_end = ped_unit_format (probed->dev, probed->end);
1629         ex_opt = ped_exception_throw (
1630                 PED_EXCEPTION_INFORMATION,
1631                 PED_EXCEPTION_YES_NO_CANCEL,
1632                 _("A %s %s partition was found at %s -> %s.  "
1633                   "Do you want to add it to the partition table?"),
1634                 fs_type->name, ped_partition_type_get_name (part->type),
1635                 found_start, found_end);
1636         ped_geometry_destroy (probed);
1637         ped_free (found_start);
1638         ped_free (found_end);
1639 
1640         switch (ex_opt) {
1641                 case PED_EXCEPTION_CANCEL: return -1;
1642                 case PED_EXCEPTION_NO: return 0;
1643                 default: break;
1644         }
1645 
1646         ped_partition_set_system (part, fs_type);
1647         ped_disk_commit (part->disk);
1648         return 1;
1649 }
1650 
1651 /* hack: we only iterate through the start, since most (all) fs's have their
1652  * superblocks at the start.  We'll need to change this if we generalize
1653  * for RAID, or something...
1654  */
1655 static int
1656 _rescue_pass (PedDisk* disk, PedGeometry* start_range, PedGeometry* end_range)
1657 {
1658         PedSector               start;
1659         PedGeometry             start_geom_exact;
1660         PedGeometry             entire_dev;
1661         PedConstraint           constraint;
1662         PedPartition*           part;
1663         PedPartitionType        part_type;
1664 
1665         part_type = _disk_get_part_type_for_sector (
1666                         disk, (start_range->start + end_range->end) / 2);
1667 
1668         ped_geometry_init (&entire_dev, disk->dev, 0, disk->dev->length);
1669 
1670         ped_timer_reset (g_timer);
1671         ped_timer_set_state_name (g_timer, _("searching for file systems"));
1672         for (start = start_range->start; start <= start_range->end; start++) {
1673                 ped_timer_update (g_timer, 1.0 * (start - start_range->start)
1674                                          / start_range->length);
1675 
1676                 ped_geometry_init (&start_geom_exact, disk->dev, start, 1);
1677                 ped_constraint_init (
1678                         &constraint, ped_alignment_any, ped_alignment_any,
1679                         &start_geom_exact, &entire_dev,
1680                         1, disk->dev->length);
1681                 part = ped_partition_new (disk, part_type, NULL, start,
1682                                 end_range->end);
1683                 if (!part) {
1684                         ped_constraint_done (&constraint);
1685                         continue;
1686                 }
1687 
1688                 ped_exception_fetch_all ();
1689                 if (ped_disk_add_partition (disk, part, &constraint)) {
1690                         ped_exception_leave_all ();
1691                         switch (_rescue_add_partition (part)) {
1692                         case 1:
1693                                 ped_constraint_done (&constraint);
1694                                 return 1;
1695 
1696                         case 0:
1697                                 ped_disk_remove_partition (disk, part);
1698                                 break;
1699 
1700                         case -1:
1701                                 goto error_remove_partition;
1702                         }
1703                 } else {
1704                         ped_exception_leave_all ();
1705                 }
1706                 ped_partition_destroy (part);
1707                 ped_constraint_done (&constraint);
1708         }
1709         ped_timer_update (g_timer, 1.0);
1710 
1711         return 1;
1712 
1713 error_remove_partition:
1714         ped_disk_remove_partition (disk, part);
1715         ped_partition_destroy (part);
1716         ped_constraint_done (&constraint);
1717         return 0;
1718 }
1719 
1720 static int
1721 do_rescue (PedDevice** dev)
1722 {
1723         PedDisk*                disk;
1724         PedSector               start = 0, end = 0;
1725         PedSector               fuzz;
1726         PedGeometry             probe_start_region;
1727         PedGeometry             probe_end_region;
1728 
1729         disk = ped_disk_new (*dev);
1730         if (!disk)
1731                 goto error;
1732 
1733         if (!command_line_get_sector (_("Start?"), *dev, &start, NULL))
1734                 goto error_destroy_disk;
1735         if (!command_line_get_sector (_("End?"), *dev, &end, NULL))
1736                 goto error_destroy_disk;
1737 
1738         fuzz = PED_MAX (PED_MIN ((end - start) / 10, MEGABYTE_SECTORS(*dev)),
1739                         MEGABYTE_SECTORS(*dev) * 16);
1740 
1741         ped_geometry_init (&probe_start_region, *dev,
1742                            PED_MAX(start - fuzz, 0),
1743                            PED_MIN(2 * fuzz, (*dev)->length - (start - fuzz)));
1744         ped_geometry_init (&probe_end_region, *dev,
1745                            PED_MAX(end - fuzz, 0),
1746                            PED_MIN(2 * fuzz, (*dev)->length - (end - fuzz)));
1747 
1748         if (!_rescue_pass (disk, &probe_start_region, &probe_end_region))
1749                 goto error_destroy_disk;
1750 
1751         ped_disk_destroy (disk);
1752 
1753         if ((*dev)->type != PED_DEVICE_FILE)
1754                 disk_is_modified = 1;
1755 
1756         return 1;
1757 
1758 error_destroy_disk:
1759         ped_disk_destroy (disk);
1760 error:
1761         return 0;
1762 }
1763 
1764 static int
1765 do_resize (PedDevice** dev)
1766 {
1767         PedDisk                 *disk;
1768         PedPartition            *part = NULL;
1769         PedFileSystem           *fs;
1770         PedConstraint           *constraint;
1771         PedSector               start, end;
1772         PedGeometry             *range_start = NULL, *range_end = NULL;
1773         PedGeometry             new_geom;
1774 
1775         disk = ped_disk_new (*dev);
1776         if (!disk)
1777                 goto error;
1778 
1779         if (!command_line_get_partition (_("Partition number?"), disk, &part))
1780                 goto error_destroy_disk;
1781         if (part->type != PED_PARTITION_EXTENDED) {
1782                 if (!_partition_warn_busy (part))
1783                         goto error_destroy_disk;
1784         }
1785 
1786         start = part->geom.start;
1787         end = part->geom.end;
1788         if (!command_line_get_sector (_("Start?"), *dev, &start, &range_start))
1789                 goto error_destroy_disk;
1790         if (!command_line_get_sector (_("End?"), *dev, &end, &range_end))
1791                 goto error_destroy_disk;
1792 
1793         if (!ped_geometry_init (&new_geom, *dev, start, end - start + 1))
1794                 goto error_destroy_disk;
1795         snap_to_boundaries (&new_geom, &part->geom, disk,
1796                             range_start, range_end);
1797 
1798         if (part->type == PED_PARTITION_EXTENDED) {
1799                 constraint = constraint_from_start_end (*dev,
1800                                 range_start, range_end);
1801                 if (!ped_disk_set_partition_geom (disk, part, constraint,
1802                                                   new_geom.start, new_geom.end))
1803                         goto error_destroy_constraint;
1804                 ped_partition_set_system (part, NULL);
1805         } else {
1806                 fs = ped_file_system_open (&part->geom);
1807                 if (!fs)
1808                         goto error_destroy_disk;
1809                 constraint = constraint_intersect_and_destroy (
1810                                 ped_file_system_get_resize_constraint (fs),
1811                                 constraint_from_start_end (
1812                                         *dev, range_start, range_end));
1813                 if (!ped_disk_set_partition_geom (disk, part, constraint,
1814                                                   new_geom.start, new_geom.end))
1815                         goto error_close_fs;
1816                 if (!ped_file_system_resize (fs, &part->geom, g_timer))
1817                         goto error_close_fs;
1818                 /* may have changed... eg fat16 -> fat32 */
1819                 ped_partition_set_system (part, fs->type);
1820                 ped_file_system_close (fs);
1821         }
1822 
1823         ped_disk_commit (disk);
1824         ped_constraint_destroy (constraint);
1825         ped_disk_destroy (disk);
1826         if (range_start != NULL)
1827                 ped_geometry_destroy (range_start);
1828         if (range_end != NULL)
1829                 ped_geometry_destroy (range_end);
1830 
1831         if ((*dev)->type != PED_DEVICE_FILE)
1832                 disk_is_modified = 1;
1833 
1834         return 1;
1835 
1836 error_close_fs:
1837         ped_file_system_close (fs);
1838 error_destroy_constraint:
1839         ped_constraint_destroy (constraint);
1840 error_destroy_disk:
1841         ped_disk_destroy (disk);
1842 error:
1843         if (range_start != NULL)
1844                 ped_geometry_destroy (range_start);
1845         if (range_end != NULL)
1846                 ped_geometry_destroy (range_end);
1847         return 0;
1848 }
1849 
1850 static int
1851 do_rm (PedDevice** dev)
1852 {
1853         PedDisk*                disk;
1854         PedPartition*           part = NULL;
1855 
1856         disk = ped_disk_new (*dev);
1857         if (!disk)
1858                 goto error;
1859 
1860         if (!command_line_get_partition (_("Partition number?"), disk, &part))
1861                 goto error_destroy_disk;
1862         if (!_partition_warn_busy (part))
1863                 goto error_destroy_disk;
1864 
1865         ped_disk_delete_partition (disk, part);
1866         ped_disk_commit (disk);
1867         ped_disk_destroy (disk);
1868 
1869         if ((*dev)->type != PED_DEVICE_FILE)
1870                 disk_is_modified = 1;
1871 
1872         return 1;
1873 
1874 error_destroy_disk:
1875         ped_disk_destroy (disk);
1876 error:
1877         return 0;
1878 }
1879 
1880 static int
1881 do_select (PedDevice** dev)
1882 {
1883         PedDevice*      new_dev = *dev;
1884 
1885         if (!command_line_get_device (_("New device?"), &new_dev))
1886                 return 0;
1887         if (!ped_device_open (new_dev))
1888                 return 0;
1889 
1890         ped_device_close (*dev);
1891         *dev = new_dev;
1892         print_using_dev (*dev);
1893         return 1;
1894 }
1895 
1896 static int
1897 do_set (PedDevice** dev)
1898 {
1899         PedDisk*                disk;
1900         PedPartition*           part = NULL;
1901         PedPartitionFlag        flag;
1902         int                     state;
1903         
1904         disk = ped_disk_new (*dev);
1905         if (!disk)
1906                 goto error;
1907         
1908         if (!command_line_get_partition (_("Partition number?"), disk, &part))
1909                 goto error_destroy_disk;
1910         if (!command_line_get_part_flag (_("Flag to Invert?"), part, &flag))
1911                 goto error_destroy_disk;
1912         state = (ped_partition_get_flag (part, flag) == 0 ? 1 : 0);      
1913         
1914         if (!is_toggle_mode) {
1915                 if (!command_line_get_state (_("New state?"), &state))
1916                             goto error_destroy_disk;
1917         }
1918     
1919         if (!ped_partition_set_flag (part, flag, state))
1920                         goto error_destroy_disk;
1921         if (!ped_disk_commit (disk))
1922                         goto error_destroy_disk;
1923         ped_disk_destroy (disk);
1924 
1925         if ((*dev)->type != PED_DEVICE_FILE)
1926                 disk_is_modified = 1;
1927 
1928             return 1;
1929 
1930 error_destroy_disk:
1931         ped_disk_destroy (disk);
1932 error:
1933         return 0;
1934 }
1935 
1936 static int
1937 do_toggle (PedDevice **dev)
1938 {
1939         int result;
1940         
1941         is_toggle_mode = 1;
1942         result = do_set (dev);
1943         is_toggle_mode = 0;
1944 
1945         return result;
1946 }
1947 
1948 static int
1949 do_unit (PedDevice** dev)
1950 {
1951         PedUnit unit = ped_unit_get_default ();
1952         if (!command_line_get_unit (_("Unit?"), &unit))
1953                 return 0;
1954         ped_unit_set_default (unit);
1955         return 1;
1956 }
1957 
1958 static int
1959 do_version (PedDevice** dev)
1960 {
1961     printf ("\n%s\n%s",
1962             prog_name,
1963             _(copyright_msg));
1964     return 1;
1965 }
1966 
1967 static void
1968 _init_messages ()
1969 {
1970         StrList*                list;
1971         int                     first;
1972         PedFileSystemType*      fs_type;
1973         PedDiskType*            disk_type;
1974         PedPartitionFlag        part_flag;
1975         PedUnit                 unit;
1976 
1977 /* flags */
1978         first = 1;
1979         list = str_list_create (_(flag_msg_start), NULL);
1980         for (part_flag = ped_partition_flag_next (0); part_flag;
1981                         part_flag = ped_partition_flag_next (part_flag)) {
1982                 if (first)
1983                         first = 0;
1984                 else
1985                         str_list_append (list, ", ");
1986                 str_list_append (list,
1987                                  _(ped_partition_flag_get_name (part_flag)));
1988         }
1989         str_list_append (list, "\n");
1990 
1991         flag_msg = str_list_convert (list);
1992         str_list_destroy (list);
1993 
1994 /* units */
1995         first = 1;
1996         list = str_list_create (_(unit_msg_start), NULL);
1997         for (unit = PED_UNIT_FIRST; unit <= PED_UNIT_LAST; unit++) {
1998                 if (first)
1999                         first = 0;
2000                 else
2001                         str_list_append (list, ", ");
2002                 str_list_append (list, ped_unit_get_name (unit));
2003         }
2004         str_list_append (list, "\n");
2005 
2006         unit_msg = str_list_convert (list);
2007         str_list_destroy (list);
2008 
2009 /* disk type */
2010         list = str_list_create (_(label_type_msg_start), NULL);
2011 
2012         first = 1;
2013         for (disk_type = ped_disk_type_get_next (NULL);
2014              disk_type; disk_type = ped_disk_type_get_next (disk_type)) {
2015                 if (disk_type->ops->write == NULL)
2016                         continue;
2017 
2018                 if (first)
2019                         first = 0;
2020                 else
2021                         str_list_append (list, ", ");
2022                 str_list_append (list, disk_type->name);
2023         }
2024         str_list_append (list, "\n");
2025 
2026         label_type_msg = str_list_convert (list);
2027         str_list_destroy (list);
2028 
2029 /* mkfs - file system types */
2030         list = str_list_create (_(fs_type_msg_start), NULL);
2031 
2032         first = 1;
2033         for (fs_type = ped_file_system_type_get_next (NULL);
2034              fs_type; fs_type = ped_file_system_type_get_next (fs_type)) {
2035                 if (fs_type->ops->create == NULL)
2036                         continue;
2037 
2038                 if (first)
2039                         first = 0;
2040                 else
2041                         str_list_append (list, ", ");
2042                 str_list_append (list, fs_type->name);
2043         }
2044         str_list_append (list, "\n");
2045 
2046         mkfs_fs_type_msg = str_list_convert (list);
2047         str_list_destroy (list);
2048 
2049 /* mkpart - file system types */
2050         list = str_list_create (_(fs_type_msg_start), NULL);
2051 
2052         first = 1;
2053         for (fs_type = ped_file_system_type_get_next (NULL);
2054              fs_type; fs_type = ped_file_system_type_get_next (fs_type)) {
2055                 if (first)
2056                         first = 0;
2057                 else
2058                         str_list_append (list, ", ");
2059                 str_list_append (list, fs_type->name);
2060         }
2061         str_list_append (list, "\n");
2062 
2063         mkpart_fs_type_msg = str_list_convert (list);
2064         str_list_destroy (list);
2065 
2066 /* resize - file system types */
2067         list = str_list_create (_(resize_msg_start), NULL);
2068 
2069         first = 1;
2070         for (fs_type = ped_file_system_type_get_next (NULL);
2071              fs_type; fs_type = ped_file_system_type_get_next (fs_type)) {
2072                 if (fs_type->ops->resize == NULL)
2073                         continue;
2074 
2075                 if (first)
2076                         first = 0;
2077                 else
2078                         str_list_append (list, ", ");
2079                 str_list_append (list, fs_type->name);
2080         }
2081         str_list_append (list, "\n");
2082 
2083         resize_fs_type_msg = str_list_convert (list);
2084         str_list_destroy (list);
2085 }
2086 
2087 static void
2088 _done_messages ()
2089 {
2090         free (flag_msg);
2091         free (mkfs_fs_type_msg);
2092         free (mkpart_fs_type_msg);
2093         free (resize_fs_type_msg);
2094         free (label_type_msg);
2095 }
2096 
2097 static void
2098 _init_commands ()
2099 {
2100         command_register (commands, command_create (
2101                 str_list_create_unique ("check", _("check"), NULL),
2102                 do_check,
2103                 str_list_create (
2104 _("check NUMBER                             do a simple check on the file "
2105   "system"),
2106 NULL),
2107                 str_list_create (_(number_msg), NULL), 1));
2108 
2109         command_register (commands, command_create (
2110                 str_list_create_unique ("cp", _("cp"), NULL),
2111                 do_cp,
2112                 str_list_create (
2113 _("cp [FROM-DEVICE] FROM-NUMBER TO-NUMBER   copy file system to another "
2114   "partition"),
2115 NULL),
2116                 str_list_create (_(number_msg), _(device_msg), NULL), 1));
2117 
2118         command_register (commands, command_create (
2119                 str_list_create_unique ("help", _("help"), NULL),
2120                 do_help,
2121                 str_list_create (
2122 _("help [COMMAND]                           print general help, or help "
2123   "on COMMAND"),
2124 NULL),
2125                 NULL, 1));
2126 
2127         command_register (commands, command_create (
2128                 str_list_create_unique ("mklabel", _("mklabel"), "mktable", _("mktable"), NULL),
2129                 do_mklabel,
2130                 str_list_create (
2131 _("mklabel,mktable LABEL-TYPE               create a new disklabel "
2132   "(partition table)"),
2133 NULL),
2134                 str_list_create (label_type_msg, NULL), 1));
2135 
2136         command_register (commands, command_create (
2137                 str_list_create_unique ("mkfs", _("mkfs"), NULL),
2138                 do_mkfs,
2139                 str_list_create (
2140 _("mkfs NUMBER FS-TYPE                      make a FS-TYPE file "
2141   "system on partititon NUMBER"),
2142 NULL),
2143                 str_list_create (_(number_msg), _(mkfs_fs_type_msg), NULL), 1));
2144 
2145         command_register (commands, command_create (
2146                 str_list_create_unique ("mkpart", _("mkpart"), NULL),
2147                 do_mkpart,
2148                 str_list_create (
2149 _("mkpart PART-TYPE [FS-TYPE] START END     make a partition"),
2150 NULL),
2151                 str_list_create (_(part_type_msg),
2152                                  _(mkpart_fs_type_msg),
2153                                  _(start_end_msg),
2154                                  "\n",
2155 _("'mkpart' makes a partition without creating a new file system on the "
2156   "partition.  FS-TYPE may be specified to set an appropriate partition ID.\n"),
2157 NULL), 1));
2158 
2159         command_register (commands, command_create (
2160                 str_list_create_unique ("mkpartfs", _("mkpartfs"), NULL),
2161                 do_mkpartfs,
2162                 str_list_create (
2163 _("mkpartfs PART-TYPE FS-TYPE START END     make a partition with a "
2164   "file system"),
2165 NULL),
2166         str_list_create (_(part_type_msg), _(start_end_msg), NULL), 1));
2167 
2168 command_register (commands, command_create (
2169         str_list_create_unique ("move", _("move"), NULL),
2170         do_move,
2171         str_list_create (
2172 _("move NUMBER START END                    move partition NUMBER"),
2173 NULL),
2174         str_list_create (_(number_msg), _(start_end_msg), NULL), 1));
2175 
2176 command_register (commands, command_create (
2177         str_list_create_unique ("name", _("name"), NULL),
2178         do_name,
2179         str_list_create (
2180 _("name NUMBER NAME                         name partition NUMBER as NAME"),
2181 NULL),
2182         str_list_create (_(number_msg), _(name_msg), NULL), 1));
2183 
2184 command_register (commands, command_create (
2185         str_list_create_unique ("print", _("print"), NULL),
2186         do_print,
2187         str_list_create (
2188 _("print [devices|free|list,all|NUMBER]     display the partition table, "
2189   "available devices, free space, all found partitions, or a particular "
2190   "partition"),
2191 NULL),
2192         str_list_create (
2193 _("Without arguments, 'print' displays the entire partition table. However "
2194   "with the following arguments it performs various other actions.\n"),
2195 _("  devices   : display all active block devices\n"),
2196 _("  free      : display information about free unpartitioned space on the "
2197   "current block device\n"),
2198 _("  list, all : display the partition tables of all active block devices\n"),
2199 _("  NUMBER    : display more detailed information about this particular "
2200   "partition\n"),
2201 NULL), 1));
2202 
2203 command_register (commands, command_create (
2204         str_list_create_unique ("quit", _("quit"), NULL),
2205         do_quit,
2206         str_list_create (
2207 _("quit                                     exit program"),
2208 NULL),
2209         NULL, 1));
2210 
2211 command_register (commands, command_create (
2212         str_list_create_unique ("rescue", _("rescue"), NULL),
2213         do_rescue,
2214         str_list_create (
2215 _("rescue START END                         rescue a lost partition near "
2216 "START and END"),
2217 NULL),
2218         str_list_create (_(start_end_msg), NULL), 1));
2219 
2220 command_register (commands, command_create (
2221         str_list_create_unique ("resize", _("resize"), NULL),
2222         do_resize,
2223         str_list_create (
2224 _("resize NUMBER START END                  resize partition NUMBER and "
2225 "its file system"),
2226 NULL),
2227         str_list_create (_(number_msg),
2228                          _(start_end_msg),
2229                          _(resize_fs_type_msg), NULL), 1));
2230 
2231 command_register (commands, command_create (
2232         str_list_create_unique ("rm", _("rm"), NULL),
2233         do_rm,
2234         str_list_create (
2235 _("rm NUMBER                                delete partition NUMBER"),
2236 NULL),
2237         str_list_create (_(number_msg), NULL), 1));
2238 
2239 command_register (commands, command_create (
2240         str_list_create_unique ("select", _("select"), NULL),
2241         do_select,
2242         str_list_create (
2243 _("select DEVICE                            choose the device to edit"),
2244 NULL),
2245         str_list_create (_(device_msg), NULL), 1));
2246 
2247 command_register (commands, command_create (
2248                 str_list_create_unique ("set", _("set"), NULL),
2249                 do_set,
2250                 str_list_create (
2251 _("set NUMBER FLAG STATE                    change the FLAG on partition "
2252   "NUMBER"),
2253 NULL),
2254         str_list_create (_(number_msg), flag_msg, _(state_msg), NULL), 1));
2255 
2256 command_register (commands, command_create (
2257         str_list_create_unique ("toggle", _("toggle"), NULL),
2258         do_toggle,
2259         str_list_create (
2260 _("toggle [NUMBER [FLAG]]                   toggle the state of FLAG on "
2261   "partition NUMBER"),
2262 NULL),
2263         str_list_create (_(number_msg), flag_msg, NULL), 1));
2264 
2265 command_register (commands, command_create (
2266         str_list_create_unique ("unit", _("unit"), NULL),
2267         do_unit,
2268         str_list_create (
2269 _("unit UNIT                                set the default unit to UNIT"),
2270 NULL),
2271         str_list_create (unit_msg, NULL), 1));
2272 
2273 command_register (commands, command_create (
2274         str_list_create_unique ("version", _("version"), NULL),
2275         do_version,
2276         str_list_create (
2277 _("version                                  display the version number "
2278 "and copyright information of GNU Parted"),
2279 NULL),
2280         str_list_create (
2281 _("'version' displays copyright and version information corresponding to this "
2282 "copy of GNU Parted\n"),
2283 NULL), 1));
2284 
2285 }
2286 
2287 static void
2288 _done_commands ()
2289 {
2290 Command**       walk;
2291 
2292 for (walk = commands; *walk; walk++) {
2293         command_destroy (*walk);
2294         *walk = NULL;
2295 }
2296 }
2297 
2298 static void
2299 _init_i18n ()
2300 {
2301 /* intialize i18n */
2302 #ifdef ENABLE_NLS
2303 setlocale(LC_ALL, "");
2304 bindtextdomain(PACKAGE, LOCALEDIR);
2305 textdomain(PACKAGE);
2306 #endif /* ENABLE_NLS */
2307 }
2308 
2309 void
2310 _version ()
2311 {
2312   version_etc (stdout, PROGRAM_NAME, PACKAGE_NAME, VERSION, AUTHORS,
2313                (char *) NULL);
2314 }
2315 
2316 static int
2317 _parse_options (int* argc_ptr, char*** argv_ptr)
2318 {
2319 int     opt, help = 0, list = 0, version = 0, wrong = 0;
2320 
2321 while (1)
2322 {
2323         opt = getopt_long (*argc_ptr, *argv_ptr, "hilmsv",
2324                            options, NULL);
2325         if (opt == -1)
2326                 break;
2327 
2328         switch (opt) {
2329                 case 'h': help = 1; break;
2330                 case 'l': list = 1; break;
2331                 case 'm': opt_machine_mode = 1; break;
2332                 case 's': opt_script_mode = 1; break;
2333                 case 'v': version = 1; break;
2334                 case PRETEND_INPUT_TTY:
2335                   pretend_input_tty = 1;
2336                   break;
2337                 default:  wrong = 1; break;
2338         }
2339 }
2340 
2341 if (wrong == 1) {
2342         fprintf (stderr,
2343                  _("Usage: %s [-hlmsv] [DEVICE [COMMAND [PARAMETERS]]...]\n"),
2344                  program_name);
2345         return 0;
2346 }
2347 
2348 if (version == 1) {
2349         _version ();
2350         exit (EXIT_SUCCESS);
2351 }
2352 
2353 if (help == 1) {
2354         help_msg ();
2355         exit (EXIT_SUCCESS);
2356 }
2357 
2358 if (list == 1) {
2359         _print_list ();
2360         exit (EXIT_SUCCESS);
2361 }
2362 
2363 *argc_ptr -= optind;
2364 *argv_ptr += optind;
2365 return 1;
2366 }
2367 
2368 static PedDevice*
2369 _choose_device (int* argc_ptr, char*** argv_ptr)
2370 {
2371 PedDevice*      dev;
2372 
2373 /* specified on comand line? */
2374 if (*argc_ptr) {
2375         dev = ped_device_get ((*argv_ptr) [0]);
2376         if (!dev)
2377                 return NULL;
2378         (*argc_ptr)--;
2379         (*argv_ptr)++;
2380 } else {
2381 retry:
2382         ped_device_probe_all ();
2383         dev = ped_device_get_next (NULL);
2384         if (!dev) {
2385                 if (ped_exception_throw (PED_EXCEPTION_ERROR,
2386                         PED_EXCEPTION_RETRY_CANCEL,
2387                         _("No device found"))
2388                                 == PED_EXCEPTION_RETRY)
2389                         goto retry;
2390                 else
2391                         return NULL;
2392         }
2393 }
2394 
2395 if (!ped_device_open (dev))
2396         return NULL;
2397 return dev;     
2398 }
2399 
2400 static PedDevice*
2401 _init (int* argc_ptr, char*** argv_ptr)
2402 {
2403 PedDevice*      dev;
2404 
2405 #ifdef ENABLE_MTRACE
2406 mtrace();
2407 #endif
2408 
2409 _init_i18n ();
2410 if (!init_ui ())
2411         goto error;
2412 _init_messages ();
2413 _init_commands ();
2414 
2415 if (!_parse_options (argc_ptr, argv_ptr))
2416         goto error_done_commands;
2417 
2418 #ifdef HAVE_GETUID
2419         if (getuid() != 0 && !opt_script_mode) {
2420             puts (_("WARNING: You are not superuser.  Watch out for "
2421                     "permissions."));
2422         }
2423 #endif
2424 
2425 dev = _choose_device (argc_ptr, argv_ptr);
2426 if (!dev)
2427         goto error_done_commands;
2428 
2429 g_timer = ped_timer_new (_timer_handler, &timer_context);
2430 if (!g_timer)
2431         goto error_done_commands;
2432 timer_context.last_update = 0;
2433 
2434 return dev;
2435 
2436 error_done_commands:
2437 _done_commands ();
2438 _done_messages ();
2439 done_ui ();
2440 error:
2441 return NULL;
2442 }
2443 
2444 static void
2445 _done (PedDevice* dev)
2446 {
2447 if (dev->boot_dirty && dev->type != PED_DEVICE_FILE) {
2448         ped_exception_throw (
2449                 PED_EXCEPTION_WARNING,
2450                 PED_EXCEPTION_OK,
2451         _("You should reinstall your boot loader before "
2452           "rebooting.  Read section 4 of the Parted User "
2453           "documentation for more information."));
2454 }
2455 
2456 #if !defined(__sun)
2457 if (!opt_script_mode && !opt_machine_mode && disk_is_modified) {
2458         ped_exception_throw (
2459                 PED_EXCEPTION_INFORMATION, PED_EXCEPTION_OK,
2460                 _("You may need to update /etc/fstab.\n"));
2461 }
2462 #endif
2463 
2464 ped_device_close (dev);
2465 
2466 ped_timer_destroy (g_timer);
2467 _done_commands ();
2468 _done_messages ();
2469 done_ui();
2470 }
2471 
2472 int
2473 main (int argc, char** argv)
2474 {
2475         PedDevice*      dev;
2476         int             status;
2477 
2478         program_name = argv[0];
2479         atexit (close_stdout);
2480 
2481         dev = _init (&argc, &argv);
2482         if (!dev)
2483                 return 1;
2484 
2485         if (argc || opt_script_mode)
2486                 status = non_interactive_mode (&dev, commands, argc, argv);
2487         else
2488                 status = interactive_mode (&dev, commands);
2489 
2490         _done (dev);
2491 
2492         return !status;
2493 }