OSDN Git Service

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