OSDN Git Service

ac1b1768b8a1023864b9c497d4b891846b8171aa
[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 #include <stdbool.h>
21
22 #include "closeout.h"
23 #include "configmake.h"
24 #include "version-etc.h"
25 #include "command.h"
26 #include "ui.h"
27 #include "progname.h"
28 #include "table.h"
29
30 #define AUTHORS \
31   "<http://parted.alioth.debian.org/cgi-bin/trac.cgi/browser/AUTHORS>"
32
33 /* The official name of this program (e.g., no `g' prefix).  */
34 #define PROGRAM_NAME "parted"
35
36 #define N_(String) String
37 #if ENABLE_NLS
38 #  include <libintl.h>
39 #  include <locale.h>
40 #  define _(String) dgettext (PACKAGE, String)
41 #else
42 #  define _(String) (String)
43 #endif /* ENABLE_NLS */
44
45 #include <parted/parted.h>
46 #include <parted/debug.h>
47
48 #include <ctype.h>
49 #include <stdarg.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <unistd.h>
53 #include <limits.h>
54 #include "xalloc.h"
55
56 #ifdef ENABLE_MTRACE
57 #include <mcheck.h>
58 #endif
59
60 #include <getopt.h>
61
62 /* minimum amount of free space to leave, or maximum amount to gobble up */
63 #define MIN_FREESPACE           (1000 * 2)      /* 1000k */
64
65 static int MEGABYTE_SECTORS (PedDevice* dev)
66 {
67         return PED_MEGABYTE_SIZE / dev->sector_size;
68 }
69
70 /* For long options that have no equivalent short option, use a
71    non-character as a pseudo short option, starting with CHAR_MAX + 1.  */
72 enum
73 {
74   PRETEND_INPUT_TTY = CHAR_MAX + 1,
75 };
76
77
78 typedef struct {
79         time_t  last_update;
80         time_t  predicted_time_left;
81 } TimerContext;
82
83 static struct option const options[] = {
84         /* name, has-arg, string-return-val, char-return-val */
85         {"help",        0, NULL, 'h'},
86         {"list",        0, NULL, 'l'},
87         {"machine",     0, NULL, 'm'},
88         {"script",      0, NULL, 's'},
89         {"version",     0, NULL, 'v'},
90         {"-pretend-input-tty", 0, NULL, PRETEND_INPUT_TTY},
91         {NULL,          0, NULL, 0}
92 };
93
94 static const char *const options_help [][2] = {
95         {"help",        N_("displays this help message")},
96         {"list",        N_("lists partition layout on all block devices")},
97         {"machine",     N_("displays machine parseable output")},
98         {"script",      N_("never prompts for user intervention")},
99         {"version",     N_("displays the version")},
100         {NULL,          NULL}
101 };
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 const 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 const char* label_type_msg_start = N_("LABEL-TYPE is one of: ");
114 static const char* flag_msg_start =   N_("FLAG is one of: ");
115 static const char* unit_msg_start =   N_("UNIT is one of: ");
116 static const char* part_type_msg =    N_("PART-TYPE is one of: primary, logical, "
117                                    "extended\n");
118 static const char* fs_type_msg_start = N_("FS-TYPE is one of: ");
119 static const 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 const char* state_msg =        N_("STATE is one of: on, off\n");
123 static const char* device_msg =       N_("DEVICE is usually /dev/hda or /dev/sda\n");
124 static const char* name_msg =         N_("NAME is any word you want\n");
125 static const char* resize_msg_start = N_("The partition must have one of the "
126                                    "following FS-TYPEs: ");
127
128 static const 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                 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         free (peek_word);
737
738         if (!command_line_get_sector (_("Start?"), *dev, &start, &range_start))
739                 goto error_destroy_disk;
740         if (!command_line_get_sector (_("End?"), *dev, &end, &range_end))
741                 goto error_destroy_disk;
742
743         /* processing starts here */
744         part = ped_partition_new (disk, part_type, fs_type, start, end);
745         if (!part)
746                 goto error_destroy_disk;
747
748         snap_to_boundaries (&part->geom, NULL, disk, range_start, range_end);
749
750         /* create constraints */
751         user_constraint = constraint_from_start_end (*dev, range_start,
752                         range_end);
753         PED_ASSERT (user_constraint != NULL, return 0);
754
755         dev_constraint = ped_device_get_constraint (*dev);
756         PED_ASSERT (dev_constraint != NULL, return 0);
757
758         final_constraint = ped_constraint_intersect (user_constraint,
759                         dev_constraint);
760         ped_constraint_destroy (user_constraint);
761         ped_constraint_destroy (dev_constraint);
762         if (!final_constraint)
763                 goto error_destroy_simple_constraints;
764
765         /* subject to partition constraint */
766         ped_exception_fetch_all();
767         bool added_ok = ped_disk_add_partition (disk, part, final_constraint);
768         ped_constraint_destroy (final_constraint);
769         if (!added_ok) {
770                 ped_exception_leave_all();
771
772                 if (ped_disk_add_partition (disk, part,
773                                         ped_constraint_any (*dev))) {
774                         start_usr = ped_unit_format (*dev, start);
775                         end_usr   = ped_unit_format (*dev, end);
776                         start_sol = ped_unit_format (*dev, part->geom.start);
777                         end_sol   = ped_unit_format (*dev, part->geom.end);
778
779                         /* In script mode failure to use specified values is fatal.
780                          * However, in interactive mode, it merely elicits a warning
781                          * and a prompt for whether to proceed.  The same appies for
782                          * do_mkpartfs function.
783                          */
784                         switch (ped_exception_throw (
785                                 (opt_script_mode
786                                  ? PED_EXCEPTION_ERROR
787                                  : PED_EXCEPTION_WARNING),
788                                 (opt_script_mode
789                                  ? PED_EXCEPTION_CANCEL
790                                  : PED_EXCEPTION_YES_NO),
791                                 _("You requested a partition from %s to %s.\n"
792                                   "The closest location we can manage is "
793                                   "%s to %s.%s"),
794                                 start_usr, end_usr, start_sol, end_sol,
795                                 (opt_script_mode ? ""
796                                  : _("\nIs this still acceptable to you?"))))
797                         {
798                                 case PED_EXCEPTION_YES:
799                                         /* all is well in this state */
800                                         break;
801                                 case PED_EXCEPTION_NO:
802                                 case PED_EXCEPTION_UNHANDLED:
803                                 default:
804                                         /* undo partition addition */
805                                         goto error_remove_part;
806                         }
807                 } else {
808                         goto error_remove_part;
809                 }
810         } else {
811                 ped_exception_leave_all();
812         }
813         ped_exception_catch();
814
815         /* set minor attributes */
816         if (part_name)
817                 PED_ASSERT (ped_partition_set_name (part, part_name), return 0);
818         if (!ped_partition_set_system (part, fs_type))
819                 goto error_destroy_disk;
820         if (ped_partition_is_flag_available (part, PED_PARTITION_LBA))
821                 ped_partition_set_flag (part, PED_PARTITION_LBA, 1);
822
823         if (!ped_disk_commit (disk))
824                 goto error_destroy_disk;
825
826         /* clean up */
827         ped_disk_destroy (disk);
828
829         if (range_start != NULL)
830                 ped_geometry_destroy (range_start);
831         if (range_end != NULL)
832                 ped_geometry_destroy (range_end);
833
834         free (start_usr);
835         free (end_usr);
836         free (start_sol);
837         free (end_sol);
838
839         if ((*dev)->type != PED_DEVICE_FILE)
840                 disk_is_modified = 1;
841
842         return 1;
843
844 error_remove_part:
845         ped_disk_remove_partition (disk, part);
846 error_destroy_simple_constraints:
847         ped_partition_destroy (part);
848 error_destroy_disk:
849         ped_disk_destroy (disk);
850 error:
851         if (range_start != NULL)
852                 ped_geometry_destroy (range_start);
853         if (range_end != NULL)
854                 ped_geometry_destroy (range_end);
855
856         free (start_usr);
857         free (end_usr);
858         free (start_sol);
859         free (end_sol);
860
861         return 0;
862 }
863
864 static int
865 do_mkpartfs (PedDevice** dev)
866 {
867         PedDisk*            disk;
868         PedPartition*       part;
869         PedPartitionType    part_type;
870         const PedFileSystemType* fs_type = ped_file_system_type_get ("ext2");
871         PedSector           start = 0, end = 0;
872         PedGeometry         *range_start = NULL, *range_end = NULL;
873         PedConstraint*      user_constraint;
874         PedConstraint*      dev_constraint;
875         PedConstraint*      final_constraint;
876         PedFileSystem*      fs;
877         char*               part_name = NULL;
878         char                *start_usr = NULL, *end_usr = NULL;
879         char                *start_sol = NULL, *end_sol = NULL;
880
881         disk = ped_disk_new (*dev);
882         if (!disk)
883                 goto error;
884
885         if (!ped_disk_type_check_feature (disk->type, PED_DISK_TYPE_EXTENDED)) {
886                 part_type = PED_PARTITION_NORMAL;
887         } else {
888                 if (!command_line_get_part_type (_("Partition type?"),
889                                                 disk, &part_type))
890                         goto error_destroy_disk;
891         }
892
893         if (ped_disk_type_check_feature (disk->type,
894                                          PED_DISK_TYPE_PARTITION_NAME))
895                 part_name = command_line_get_word (_("Partition name?"),
896                                                    "", NULL, 1);
897
898         if (part_type == PED_PARTITION_EXTENDED) {
899                 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
900                         _("An extended partition cannot hold a file system.  "
901                           "Did you want mkpart?"));
902                 goto error_destroy_disk;
903         }
904
905         if (!command_line_get_fs_type (_("File system type?"), &fs_type))
906                 goto error_destroy_disk;
907         if (!command_line_get_sector (_("Start?"), *dev, &start,
908                                       &range_start))
909                 goto error_destroy_disk;
910         if (!command_line_get_sector (_("End?"), *dev, &end, &range_end))
911                 goto error_destroy_disk;
912
913         /* attempt to create the partition now */
914         part = ped_partition_new (disk, part_type, fs_type, start, end);
915         if (!part)
916                 goto error_destroy_disk;
917
918         snap_to_boundaries (&part->geom, NULL, disk, range_start, range_end);
919
920         /* create constraints */
921         user_constraint = constraint_from_start_end (*dev, range_start,
922                                                                 range_end);
923         PED_ASSERT (user_constraint != NULL, return 0);
924
925         dev_constraint = ped_device_get_constraint (*dev);
926         PED_ASSERT (dev_constraint != NULL, return 0);
927
928         final_constraint = ped_constraint_intersect (user_constraint,
929                                                      dev_constraint);
930         ped_constraint_destroy (user_constraint);
931         ped_constraint_destroy (dev_constraint);
932         if (!final_constraint)
933                 goto error_destroy_simple_constraints;
934
935         /* subject to partition constraint */
936         ped_exception_fetch_all();
937         bool added_ok = ped_disk_add_partition (disk, part, final_constraint);
938         ped_constraint_destroy (final_constraint);
939         if (!added_ok) {
940                 ped_exception_leave_all();
941
942                 if (ped_disk_add_partition (disk, part,
943                                         ped_constraint_any (*dev))) {
944                         start_usr = ped_unit_format (*dev, start);
945                         end_usr   = ped_unit_format (*dev, end);
946                         start_sol = ped_unit_format (*dev, part->geom.start);
947                         end_sol   = ped_unit_format (*dev, part->geom.end);
948
949                         switch (ped_exception_throw (
950                                 (opt_script_mode
951                                  ? PED_EXCEPTION_ERROR
952                                  : PED_EXCEPTION_WARNING),
953                                 (opt_script_mode
954                                  ? PED_EXCEPTION_CANCEL
955                                  : PED_EXCEPTION_YES_NO),
956                                 _("You requested a partition from %s to %s.\n"
957                                   "The closest location we can manage is "
958                                   "%s to %s.%s"),
959                                 start_usr, end_usr, start_sol, end_sol,
960                                 (opt_script_mode ? ""
961                                  : _("\nIs this still acceptable to you?"))))
962                         {
963                                 case PED_EXCEPTION_YES:
964                                         /* all is well in this state */
965                                         break;
966                                 case PED_EXCEPTION_NO:
967                                 case PED_EXCEPTION_UNHANDLED:
968                                 default:
969                                         /* undo partition addition */
970                                         goto error_remove_part;
971                         }
972                 } else {
973                         goto error_remove_part;
974                 }
975         } else {
976                 ped_exception_leave_all();
977         }
978         ped_exception_catch();
979
980         /* set LBA flag automatically if available */
981         if (ped_partition_is_flag_available (part, PED_PARTITION_LBA))
982                 ped_partition_set_flag (part, PED_PARTITION_LBA, 1);
983
984         /* fs creation */
985         fs = ped_file_system_create (&part->geom, fs_type, g_timer);
986         if (!fs)
987                 goto error_destroy_disk;
988         ped_file_system_close (fs);
989
990         if (!ped_partition_set_system (part, fs_type))
991                 goto error_destroy_disk;
992
993         if (!ped_disk_commit (disk))
994                 goto error_destroy_disk;
995
996         /* clean up */
997
998         ped_disk_destroy (disk);
999
1000         if (range_start != NULL)
1001                 ped_geometry_destroy (range_start);
1002         if (range_end != NULL)
1003                 ped_geometry_destroy (range_end);
1004
1005         free (start_usr);
1006         free (end_usr);
1007         free (start_sol);
1008         free (end_sol);
1009
1010         if ((*dev)->type != PED_DEVICE_FILE)
1011                 disk_is_modified = 1;
1012
1013         return 1;
1014
1015 error_remove_part:
1016         ped_disk_remove_partition (disk, part);
1017 error_destroy_simple_constraints:
1018         ped_partition_destroy (part);
1019 error_destroy_disk:
1020         ped_disk_destroy (disk);
1021 error:
1022         if (range_start != NULL)
1023                 ped_geometry_destroy (range_start);
1024         if (range_end != NULL)
1025                 ped_geometry_destroy (range_end);
1026
1027         free (start_usr);
1028         free (end_usr);
1029         free (start_sol);
1030         free (end_sol);
1031
1032         return 0;
1033 }
1034
1035 static int
1036 do_move (PedDevice** dev)
1037 {
1038         PedDisk*        disk;
1039         PedPartition*   part = NULL;
1040         PedFileSystem*  fs;
1041         PedFileSystem*  fs_copy;
1042         PedConstraint*  constraint;
1043         PedSector       start = 0, end = 0;
1044         PedGeometry     *range_start = NULL, *range_end = NULL;
1045         PedGeometry     old_geom, new_geom;
1046
1047         disk = ped_disk_new (*dev);
1048         if (!disk)
1049                 goto error;
1050
1051         if (!command_line_get_partition (_("Partition number?"), disk, &part))
1052                 goto error_destroy_disk;
1053         if (!_partition_warn_busy (part))
1054                 goto error_destroy_disk;
1055         if (part->type == PED_PARTITION_EXTENDED) {
1056                 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
1057                         _("Can't move an extended partition."));
1058                 goto error_destroy_disk;
1059         }
1060         old_geom = part->geom;
1061         fs = ped_file_system_open (&old_geom);
1062         if (!fs)
1063                 goto error_destroy_disk;
1064
1065         /* get new target */
1066         if (!command_line_get_sector (_("Start?"), *dev, &start, &range_start))
1067                 goto error_close_fs;
1068         end = start + old_geom.length - 1;
1069         if (!command_line_get_sector (_("End?"), *dev, &end, &range_end))
1070                 goto error_close_fs;
1071
1072         /* set / test on "disk" */
1073         if (!ped_geometry_init (&new_geom, *dev, start, end - start + 1))
1074                 goto error_close_fs;
1075         snap_to_boundaries (&new_geom, NULL, disk, range_start, range_end);
1076
1077         constraint = constraint_intersect_and_destroy (
1078                         ped_file_system_get_copy_constraint (fs, *dev),
1079                         constraint_from_start_end(*dev,range_start,range_end));
1080         if (!ped_disk_set_partition_geom (disk, part, constraint,
1081                                           new_geom.start, new_geom.end))
1082                 goto error_destroy_constraint;
1083         ped_constraint_destroy (constraint);
1084         if (ped_geometry_test_overlap (&old_geom, &part->geom)) {
1085                 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
1086                         _("Can't move a partition onto itself.  Try using "
1087                           "resize, perhaps?"));
1088                 goto error_close_fs;
1089         }
1090
1091         /* do the move */
1092         fs_copy = ped_file_system_copy (fs, &part->geom, g_timer);
1093         if (!fs_copy)
1094                 goto error_close_fs;
1095         ped_file_system_close (fs_copy);
1096         ped_file_system_close (fs);
1097         if (!ped_disk_commit (disk))
1098                 goto error_destroy_disk;
1099         ped_disk_destroy (disk);
1100         if (range_start != NULL)
1101                 ped_geometry_destroy (range_start);
1102         if (range_end != NULL)
1103                 ped_geometry_destroy (range_end);
1104
1105         if ((*dev)->type != PED_DEVICE_FILE)
1106                 disk_is_modified = 1;
1107
1108         return 1;
1109
1110 error_destroy_constraint:
1111         ped_constraint_destroy (constraint);
1112 error_close_fs:
1113         ped_file_system_close (fs);
1114 error_destroy_disk:
1115         ped_disk_destroy (disk);
1116 error:
1117         if (range_start != NULL)
1118                 ped_geometry_destroy (range_start);
1119         if (range_end != NULL)
1120                 ped_geometry_destroy (range_end);
1121         return 0;
1122 }
1123
1124 static int
1125 do_name (PedDevice** dev)
1126 {
1127         PedDisk*        disk;
1128         PedPartition*   part = NULL;
1129         char*           name;
1130
1131         disk = ped_disk_new (*dev);
1132         if (!disk)
1133                 goto error;
1134
1135         if (!command_line_get_partition (_("Partition number?"), disk, &part))
1136                 goto error_destroy_disk;
1137
1138         name = command_line_get_word (_("Partition name?"),
1139                         ped_partition_get_name (part), NULL, 0);
1140         if (!name)
1141                 goto error_destroy_disk;
1142         if (!ped_partition_set_name (part, name))
1143                 goto error_free_name;
1144         free (name);
1145
1146         if (!ped_disk_commit (disk))
1147                 goto error_destroy_disk;
1148         ped_disk_destroy (disk);
1149         return 1;
1150
1151 error_free_name:
1152         free (name);
1153 error_destroy_disk:
1154         ped_disk_destroy (disk);
1155 error:
1156         return 0;
1157 }
1158
1159 static char*
1160 partition_print_flags (PedPartition* part)
1161 {
1162         PedPartitionFlag        flag;
1163         int                     first_flag;
1164         const char*             name;
1165         char*                   res = ped_malloc(1);
1166         void*                   _res = res;
1167
1168         *res = '\0';
1169
1170         first_flag = 1;
1171         for (flag = ped_partition_flag_next (0); flag;
1172              flag = ped_partition_flag_next (flag)) {
1173                 if (ped_partition_get_flag (part, flag)) {
1174                         if (first_flag)
1175                                 first_flag = 0;
1176                         else {
1177                                 _res = res;
1178                                 ped_realloc (&_res, strlen (res)
1179                                                            + 1 + 2);
1180                                 res = _res;
1181                                 strncat (res, ", ", 2);
1182                         }
1183
1184                         name = _(ped_partition_flag_get_name (flag));
1185                         _res = res;
1186                         ped_realloc (&_res, strlen (res) + 1
1187                                                    + strlen (name));
1188                         res = _res;
1189                         strncat (res, name, 21);
1190                 }
1191         }
1192
1193         return res;
1194 }
1195
1196 /* Prints a sector out, first in compact form, and then with a percentage.
1197  * Eg: 32Gb (40%)
1198  */
1199 static void
1200 print_sector_compact_and_percent (PedSector sector, PedDevice* dev)
1201 {
1202         char* compact;
1203         char* percent;
1204
1205         if (ped_unit_get_default() == PED_UNIT_PERCENT)
1206                 compact = ped_unit_format (dev, sector);
1207         else
1208                 compact = ped_unit_format_custom (dev, sector,
1209                                                   PED_UNIT_COMPACT);
1210
1211         percent = ped_unit_format_custom (dev, sector, PED_UNIT_PERCENT);
1212
1213         printf ("%s (%s)\n", compact, percent);
1214
1215         free (compact);
1216         free (percent);
1217 }
1218
1219 static int
1220 partition_print (PedPartition* part)
1221 {
1222         PedFileSystem*  fs;
1223         PedConstraint*  resize_constraint;
1224         char*           flags;
1225
1226         fs = ped_file_system_open (&part->geom);
1227         if (!fs)
1228                 return 1;
1229
1230         putchar ('\n');
1231
1232         flags = partition_print_flags (part);
1233
1234         printf (_("Minor: %d\n"), part->num);
1235         printf (_("Flags: %s\n"), flags);
1236         printf (_("File System: %s\n"), fs->type->name);
1237         fputs (_("Size:         "), stdout);
1238         print_sector_compact_and_percent (part->geom.length, part->geom.dev);
1239
1240         resize_constraint = ped_file_system_get_resize_constraint (fs);
1241         if (resize_constraint) {
1242                 fputs (_("Minimum size: "), stdout);
1243                 print_sector_compact_and_percent (resize_constraint->min_size,
1244                         part->geom.dev);
1245                 fputs (_("Maximum size: "), stdout);
1246                 print_sector_compact_and_percent (resize_constraint->max_size,
1247                         part->geom.dev);
1248                 ped_constraint_destroy (resize_constraint);
1249         }
1250
1251         putchar ('\n');
1252
1253         free (flags);
1254         ped_file_system_close (fs);
1255
1256         return 1;
1257 }
1258
1259 static int
1260 do_print (PedDevice** dev)
1261 {
1262         PedUnit         default_unit;
1263         PedDisk*        disk;
1264         Table*          table;
1265         int             has_extended;
1266         int             has_name;
1267         int             has_devices_arg = 0;
1268         int             has_free_arg = 0;
1269         int             has_list_arg = 0;
1270         int             has_num_arg = 0;
1271         const char *const transport[] = {"unknown", "scsi", "ide", "dac960",
1272                                          "cpqarray", "file", "ataraid", "i2o",
1273                                          "ubd", "dasd", "viodasd", "sx8", "dm",
1274                                          "xvd", "sd/mmc", "virtblk"};
1275         char*           peek_word;
1276         char*           start;
1277         char*           end;
1278         char*           size;
1279         const char*     name;
1280         char*           tmp;
1281         char*           flags;
1282         wchar_t*        table_rendered;
1283
1284         disk = ped_disk_new (*dev);
1285         if (!disk)
1286                 goto error;
1287
1288         peek_word = command_line_peek_word ();
1289         if (peek_word) {
1290                 if (strncmp (peek_word, "devices", 7) == 0) {
1291                         command_line_pop_word();
1292                         has_devices_arg = 1;
1293                 }
1294                 else if (strncmp (peek_word, "free", 4) == 0) {
1295                         command_line_pop_word ();
1296                         has_free_arg = 1;
1297                 }
1298                 else if (strncmp (peek_word, "list", 4) == 0 ||
1299                          strncmp (peek_word, "all", 3) == 0) {
1300                         command_line_pop_word();
1301                         has_list_arg = 1;
1302                 }
1303                 else
1304                         has_num_arg = isdigit(peek_word[0]);
1305
1306                 free (peek_word);
1307         }
1308
1309         if (has_devices_arg) {
1310                 char*           dev_name;
1311                 PedDevice*      current_dev = NULL;
1312
1313                 ped_device_probe_all();
1314
1315                 while ((current_dev = ped_device_get_next(current_dev))) {
1316                         end = ped_unit_format_byte (current_dev,
1317                                              current_dev->length
1318                                              * current_dev->sector_size);
1319                         printf ("%s (%s)\n", current_dev->path, end);
1320                         free (end);
1321                 }
1322
1323                 dev_name = xstrdup ((*dev)->path);
1324                 ped_device_free_all ();
1325
1326                 *dev = ped_device_get (dev_name);
1327                 if (!*dev)
1328                         return 0;
1329                 if (!ped_device_open (*dev))
1330                         return 0;
1331
1332                 free (dev_name);
1333
1334                 return 1;
1335         }
1336
1337         else if (has_list_arg)
1338                 return _print_list ();
1339
1340         else if (has_num_arg) {
1341                 PedPartition*   part = NULL;
1342                 int             status = 0;
1343                 if (command_line_get_partition ("", disk, &part))
1344                         status = partition_print (part);
1345                 ped_disk_destroy (disk);
1346                 return status;
1347         }
1348
1349         start = ped_unit_format (*dev, 0);
1350         default_unit = ped_unit_get_default ();
1351         end = ped_unit_format_byte (*dev, (*dev)->length * (*dev)->sector_size
1352                                     - (default_unit == PED_UNIT_CHS ||
1353                                        default_unit == PED_UNIT_CYLINDER));
1354
1355         if (opt_machine_mode) {
1356             switch (default_unit) {
1357                 case PED_UNIT_CHS:      puts ("CHS;");
1358                                         break;
1359                 case PED_UNIT_CYLINDER: puts ("CYL;");
1360                                         break;
1361                 default:                puts ("BYT;");
1362                                         break;
1363
1364             }
1365             printf ("%s:%s:%s:%lld:%lld:%s:%s;\n",
1366                     (*dev)->path, end, transport[(*dev)->type],
1367                     (*dev)->sector_size, (*dev)->phys_sector_size,
1368                     disk->type->name, (*dev)->model);
1369         } else {
1370             printf (_("Model: %s (%s)\n"),
1371                     (*dev)->model, transport[(*dev)->type]);
1372             printf (_("Disk %s: %s\n"), (*dev)->path, end);
1373             printf (_("Sector size (logical/physical): %lldB/%lldB\n"),
1374                     (*dev)->sector_size, (*dev)->phys_sector_size);
1375         }
1376
1377         free (start);
1378         free (end);
1379
1380         if (ped_unit_get_default () == PED_UNIT_CHS
1381             || ped_unit_get_default () == PED_UNIT_CYLINDER) {
1382                 PedCHSGeometry* chs = &(*dev)->bios_geom;
1383                 char* cyl_size = ped_unit_format_custom (*dev,
1384                                         chs->heads * chs->sectors,
1385                                         PED_UNIT_KILOBYTE);
1386
1387                 if (opt_machine_mode) {
1388                     printf ("%d:%d:%d:%s;\n",
1389                             chs->cylinders, chs->heads, chs->sectors, cyl_size);
1390                 } else {
1391                     printf (_("BIOS cylinder,head,sector geometry: %d,%d,%d.  "
1392                               "Each cylinder is %s.\n"),
1393                             chs->cylinders, chs->heads, chs->sectors, cyl_size);
1394                 }
1395
1396                 free (cyl_size);
1397         }
1398
1399         if (!opt_machine_mode) {
1400             printf (_("Partition Table: %s\n"), disk->type->name);
1401             putchar ('\n');
1402         }
1403
1404         has_extended = ped_disk_type_check_feature (disk->type,
1405                                          PED_DISK_TYPE_EXTENDED);
1406         has_name = ped_disk_type_check_feature (disk->type,
1407                                          PED_DISK_TYPE_PARTITION_NAME);
1408
1409
1410         PedPartition* part;
1411         if (!opt_machine_mode) {
1412             StrList *row1;
1413
1414             if (ped_unit_get_default() == PED_UNIT_CHS) {
1415                     row1 = str_list_create (_("Number"), _("Start"),
1416                                                _("End"), NULL);
1417             } else {
1418                     row1 = str_list_create (_("Number"), _("Start"),
1419                                                _("End"), _("Size"), NULL);
1420             }
1421
1422             if (has_extended)
1423                     str_list_append (row1, _("Type"));
1424
1425             str_list_append (row1, _("File system"));
1426
1427             if (has_name)
1428                     str_list_append (row1, _("Name"));
1429
1430             str_list_append (row1, _("Flags"));
1431
1432
1433             table = table_new (str_list_length(row1));
1434
1435             table_add_row_from_strlist (table, row1);
1436
1437             for (part = ped_disk_next_partition (disk, NULL); part;
1438                  part = ped_disk_next_partition (disk, part)) {
1439
1440                     if ((!has_free_arg && !ped_partition_is_active(part)) ||
1441                         part->type & PED_PARTITION_METADATA)
1442                             continue;
1443
1444                     tmp = ped_malloc (4);
1445
1446                     if (part->num >= 0)
1447                             sprintf (tmp, "%2d ", part->num);
1448                     else
1449                             sprintf (tmp, "%2s ", "");
1450
1451                     StrList *row = str_list_create (tmp, NULL);
1452
1453                     start = ped_unit_format (*dev, part->geom.start);
1454                     end = ped_unit_format_byte (
1455                             *dev,
1456                             (part->geom.end + 1) * (*dev)->sector_size - 1);
1457                     size = ped_unit_format (*dev, part->geom.length);
1458                     if (ped_unit_get_default() == PED_UNIT_CHS) {
1459                             str_list_append (row, start);
1460                             str_list_append (row, end);
1461                     } else {
1462                             str_list_append (row, start);
1463                             str_list_append (row, end);
1464                             str_list_append (row, size);
1465                     }
1466
1467                     if (!(part->type & PED_PARTITION_FREESPACE)) {
1468                             if (has_extended) {
1469                                 name = ped_partition_type_get_name (part->type);
1470                                 str_list_append (row, name);
1471                             }
1472
1473                             str_list_append (row, part->fs_type ?
1474                                              part->fs_type->name : "");
1475
1476                             if (has_name) {
1477                                     name = ped_partition_get_name (part);
1478                                     str_list_append (row, name);
1479                             }
1480
1481                             flags = partition_print_flags (part);
1482                             str_list_append (row, flags);
1483                             free (flags);
1484                     } else {
1485                             if (has_extended)
1486                                     str_list_append (row, "");
1487                             str_list_append (row, _("Free Space"));
1488                             if (has_name)
1489                                     str_list_append (row, "");
1490                             str_list_append (row, "");
1491                     }
1492
1493                     //PED_ASSERT (row.cols == caption.cols)
1494                     table_add_row_from_strlist (table, row);
1495                     str_list_destroy (row);
1496                     free (tmp);
1497                     free (start);
1498                     free (end);
1499                     free (size);
1500             }
1501
1502             table_rendered = table_render (table);
1503 #ifdef ENABLE_NLS
1504             printf("%ls\n", table_rendered);
1505 #else
1506             printf("%s\n", table_rendered);
1507 #endif
1508             free (table_rendered);
1509             table_destroy (table);
1510             str_list_destroy (row1);
1511
1512         } else {
1513
1514             for (part = ped_disk_next_partition (disk, NULL); part;
1515                  part = ped_disk_next_partition (disk, part)) {
1516
1517                 if ((!has_free_arg && !ped_partition_is_active(part)) ||
1518                         part->type & PED_PARTITION_METADATA)
1519                             continue;
1520
1521                 if (part->num >= 0)
1522                     printf ("%d:", part->num);
1523                 else
1524                     fputs ("1:", stdout);
1525
1526                 char *s = ped_unit_format (*dev, part->geom.start);
1527                 printf ("%s:", s);
1528                 free (s);
1529                 s = ped_unit_format_byte (*dev,
1530                                           (part->geom.end + 1) *
1531                                           (*dev)->sector_size - 1);
1532                 printf ("%s:", s);
1533                 free (s);
1534
1535                 if (ped_unit_get_default() != PED_UNIT_CHS) {
1536                     s = ped_unit_format (*dev, part->geom.length);
1537                     printf ("%s:", s);
1538                     free (s);
1539                 }
1540
1541                 if (!(part->type & PED_PARTITION_FREESPACE)) {
1542
1543                     if (part->fs_type)
1544                         printf ("%s:", part->fs_type->name);
1545                     else
1546                         putchar (':');
1547
1548                     if (has_name)
1549                         printf ("%s:", _(ped_partition_get_name (part)));
1550                     else
1551                         putchar (':');
1552
1553                     printf ("%s;\n", partition_print_flags (part));
1554
1555                 } else {
1556                     puts ("free;");
1557                 }
1558             }
1559         }
1560
1561         ped_disk_destroy (disk);
1562
1563         return 1;
1564
1565         ped_disk_destroy (disk);
1566 error:
1567         return 0;
1568 }
1569
1570 static int
1571 _print_list ()
1572 {
1573         PedDevice *current_dev = NULL;
1574
1575         ped_device_probe_all();
1576
1577         while ((current_dev = ped_device_get_next(current_dev))) {
1578                 do_print (&current_dev);
1579                 putchar ('\n');
1580         }
1581
1582         return 1;
1583 }
1584
1585 static int
1586 do_quit (PedDevice** dev)
1587 {
1588         _done (*dev);
1589         exit (0);
1590 }
1591
1592 static PedPartitionType
1593 _disk_get_part_type_for_sector (PedDisk* disk, PedSector sector)
1594 {
1595         PedPartition*   extended;
1596
1597         extended = ped_disk_extended_partition (disk);
1598         if (!extended
1599             || !ped_geometry_test_sector_inside (&extended->geom, sector))
1600                 return 0;
1601
1602         return PED_PARTITION_LOGICAL;
1603 }
1604
1605 /* This function checks if "part" contains a file system, and returs
1606  *      0 if either no file system was found, or the user declined to add it.
1607  *      1 if a file system was found, and the user chose to add it.
1608  *      -1 if the user chose to cancel the entire search.
1609  */
1610 static int
1611 _rescue_add_partition (PedPartition* part)
1612 {
1613         const PedFileSystemType*        fs_type;
1614         PedGeometry*                    probed;
1615         PedExceptionOption              ex_opt;
1616         PedConstraint*                  constraint;
1617         char*                           found_start;
1618         char*                           found_end;
1619
1620         fs_type = ped_file_system_probe (&part->geom);
1621         if (!fs_type)
1622                 return 0;
1623         probed = ped_file_system_probe_specific (fs_type, &part->geom);
1624         if (!probed)
1625                 return 0;
1626
1627         if (!ped_geometry_test_inside (&part->geom, probed)) {
1628                 ped_geometry_destroy (probed);
1629                 return 0;
1630         }
1631
1632         constraint = ped_constraint_exact (probed);
1633         if (!ped_disk_set_partition_geom (part->disk, part, constraint,
1634                                           probed->start, probed->end)) {
1635                 ped_constraint_destroy (constraint);
1636                 return 0;
1637         }
1638         ped_constraint_destroy (constraint);
1639
1640         found_start = ped_unit_format (probed->dev, probed->start);
1641         found_end = ped_unit_format (probed->dev, probed->end);
1642         ex_opt = ped_exception_throw (
1643                 PED_EXCEPTION_INFORMATION,
1644                 PED_EXCEPTION_YES_NO_CANCEL,
1645                 _("A %s %s partition was found at %s -> %s.  "
1646                   "Do you want to add it to the partition table?"),
1647                 fs_type->name, ped_partition_type_get_name (part->type),
1648                 found_start, found_end);
1649         ped_geometry_destroy (probed);
1650         free (found_start);
1651         free (found_end);
1652
1653         switch (ex_opt) {
1654                 case PED_EXCEPTION_CANCEL: return -1;
1655                 case PED_EXCEPTION_NO: return 0;
1656                 default: break;
1657         }
1658
1659         ped_partition_set_system (part, fs_type);
1660         ped_disk_commit (part->disk);
1661         return 1;
1662 }
1663
1664 /* hack: we only iterate through the start, since most (all) fs's have their
1665  * superblocks at the start.  We'll need to change this if we generalize
1666  * for RAID, or something...
1667  */
1668 static int
1669 _rescue_pass (PedDisk* disk, PedGeometry* start_range, PedGeometry* end_range)
1670 {
1671         PedSector               start;
1672         PedGeometry             start_geom_exact;
1673         PedGeometry             entire_dev;
1674         PedConstraint           constraint;
1675         PedPartition*           part;
1676         PedPartitionType        part_type;
1677
1678         part_type = _disk_get_part_type_for_sector (
1679                         disk, (start_range->start + end_range->end) / 2);
1680
1681         ped_geometry_init (&entire_dev, disk->dev, 0, disk->dev->length);
1682
1683         ped_timer_reset (g_timer);
1684         ped_timer_set_state_name (g_timer, _("searching for file systems"));
1685         for (start = start_range->start; start <= start_range->end; start++) {
1686                 ped_timer_update (g_timer, 1.0 * (start - start_range->start)
1687                                          / start_range->length);
1688
1689                 ped_geometry_init (&start_geom_exact, disk->dev, start, 1);
1690                 ped_constraint_init (
1691                         &constraint, ped_alignment_any, ped_alignment_any,
1692                         &start_geom_exact, &entire_dev,
1693                         1, disk->dev->length);
1694                 part = ped_partition_new (disk, part_type, NULL, start,
1695                                 end_range->end);
1696                 if (!part) {
1697                         ped_constraint_done (&constraint);
1698                         continue;
1699                 }
1700
1701                 ped_exception_fetch_all ();
1702                 if (ped_disk_add_partition (disk, part, &constraint)) {
1703                         ped_exception_leave_all ();
1704                         switch (_rescue_add_partition (part)) {
1705                         case 1:
1706                                 ped_constraint_done (&constraint);
1707                                 return 1;
1708
1709                         case 0:
1710                                 ped_disk_remove_partition (disk, part);
1711                                 break;
1712
1713                         case -1:
1714                                 goto error_remove_partition;
1715                         }
1716                 } else {
1717                         ped_exception_leave_all ();
1718                 }
1719                 ped_partition_destroy (part);
1720                 ped_constraint_done (&constraint);
1721         }
1722         ped_timer_update (g_timer, 1.0);
1723
1724         return 1;
1725
1726 error_remove_partition:
1727         ped_disk_remove_partition (disk, part);
1728         ped_partition_destroy (part);
1729         ped_constraint_done (&constraint);
1730         return 0;
1731 }
1732
1733 static int
1734 do_rescue (PedDevice** dev)
1735 {
1736         PedDisk*                disk;
1737         PedSector               start = 0, end = 0;
1738         PedSector               fuzz;
1739         PedGeometry             probe_start_region;
1740         PedGeometry             probe_end_region;
1741
1742         disk = ped_disk_new (*dev);
1743         if (!disk)
1744                 goto error;
1745
1746         if (!command_line_get_sector (_("Start?"), *dev, &start, NULL))
1747                 goto error_destroy_disk;
1748         if (!command_line_get_sector (_("End?"), *dev, &end, NULL))
1749                 goto error_destroy_disk;
1750
1751         fuzz = PED_MAX (PED_MIN ((end - start) / 10, MEGABYTE_SECTORS(*dev)),
1752                         MEGABYTE_SECTORS(*dev) * 16);
1753
1754         ped_geometry_init (&probe_start_region, *dev,
1755                            PED_MAX(start - fuzz, 0),
1756                            PED_MIN(2 * fuzz, (*dev)->length - (start - fuzz)));
1757         ped_geometry_init (&probe_end_region, *dev,
1758                            PED_MAX(end - fuzz, 0),
1759                            PED_MIN(2 * fuzz, (*dev)->length - (end - fuzz)));
1760
1761         if (!_rescue_pass (disk, &probe_start_region, &probe_end_region))
1762                 goto error_destroy_disk;
1763
1764         ped_disk_destroy (disk);
1765
1766         if ((*dev)->type != PED_DEVICE_FILE)
1767                 disk_is_modified = 1;
1768
1769         return 1;
1770
1771 error_destroy_disk:
1772         ped_disk_destroy (disk);
1773 error:
1774         return 0;
1775 }
1776
1777 static int
1778 do_resize (PedDevice** dev)
1779 {
1780         PedDisk                 *disk;
1781         PedPartition            *part = NULL;
1782         PedFileSystem           *fs;
1783         PedConstraint           *constraint;
1784         PedSector               start, end;
1785         PedGeometry             *range_start = NULL, *range_end = NULL;
1786         PedGeometry             new_geom;
1787
1788         disk = ped_disk_new (*dev);
1789         if (!disk)
1790                 goto error;
1791
1792         if (!command_line_get_partition (_("Partition number?"), disk, &part))
1793                 goto error_destroy_disk;
1794         if (part->type != PED_PARTITION_EXTENDED) {
1795                 if (!_partition_warn_busy (part))
1796                         goto error_destroy_disk;
1797         }
1798
1799         start = part->geom.start;
1800         end = part->geom.end;
1801         if (!command_line_get_sector (_("Start?"), *dev, &start, &range_start))
1802                 goto error_destroy_disk;
1803         if (!command_line_get_sector (_("End?"), *dev, &end, &range_end))
1804                 goto error_destroy_disk;
1805
1806         if (!ped_geometry_init (&new_geom, *dev, start, end - start + 1))
1807                 goto error_destroy_disk;
1808         snap_to_boundaries (&new_geom, &part->geom, disk,
1809                             range_start, range_end);
1810
1811         if (part->type == PED_PARTITION_EXTENDED) {
1812                 constraint = constraint_from_start_end (*dev,
1813                                 range_start, range_end);
1814                 if (!ped_disk_set_partition_geom (disk, part, constraint,
1815                                                   new_geom.start, new_geom.end))
1816                         goto error_destroy_constraint;
1817                 ped_partition_set_system (part, NULL);
1818         } else {
1819                 fs = ped_file_system_open (&part->geom);
1820                 if (!fs)
1821                         goto error_destroy_disk;
1822                 constraint = constraint_intersect_and_destroy (
1823                                 ped_file_system_get_resize_constraint (fs),
1824                                 constraint_from_start_end (
1825                                         *dev, range_start, range_end));
1826                 if (!ped_disk_set_partition_geom (disk, part, constraint,
1827                                                   new_geom.start, new_geom.end))
1828                         goto error_close_fs;
1829                 if (!ped_file_system_resize (fs, &part->geom, g_timer))
1830                         goto error_close_fs;
1831                 /* may have changed... eg fat16 -> fat32 */
1832                 ped_partition_set_system (part, fs->type);
1833                 ped_file_system_close (fs);
1834         }
1835
1836         ped_disk_commit (disk);
1837         ped_constraint_destroy (constraint);
1838         ped_disk_destroy (disk);
1839         if (range_start != NULL)
1840                 ped_geometry_destroy (range_start);
1841         if (range_end != NULL)
1842                 ped_geometry_destroy (range_end);
1843
1844         if ((*dev)->type != PED_DEVICE_FILE)
1845                 disk_is_modified = 1;
1846
1847         return 1;
1848
1849 error_close_fs:
1850         ped_file_system_close (fs);
1851 error_destroy_constraint:
1852         ped_constraint_destroy (constraint);
1853 error_destroy_disk:
1854         ped_disk_destroy (disk);
1855 error:
1856         if (range_start != NULL)
1857                 ped_geometry_destroy (range_start);
1858         if (range_end != NULL)
1859                 ped_geometry_destroy (range_end);
1860         return 0;
1861 }
1862
1863 static int
1864 do_rm (PedDevice** dev)
1865 {
1866         PedDisk*                disk;
1867         PedPartition*           part = NULL;
1868
1869         disk = ped_disk_new (*dev);
1870         if (!disk)
1871                 goto error;
1872
1873         if (!command_line_get_partition (_("Partition number?"), disk, &part))
1874                 goto error_destroy_disk;
1875         if (!_partition_warn_busy (part))
1876                 goto error_destroy_disk;
1877
1878         ped_disk_delete_partition (disk, part);
1879         ped_disk_commit (disk);
1880         ped_disk_destroy (disk);
1881
1882         if ((*dev)->type != PED_DEVICE_FILE)
1883                 disk_is_modified = 1;
1884
1885         return 1;
1886
1887 error_destroy_disk:
1888         ped_disk_destroy (disk);
1889 error:
1890         return 0;
1891 }
1892
1893 static int
1894 do_select (PedDevice** dev)
1895 {
1896         PedDevice*      new_dev = *dev;
1897
1898         if (!command_line_get_device (_("New device?"), &new_dev))
1899                 return 0;
1900         if (!ped_device_open (new_dev))
1901                 return 0;
1902
1903         ped_device_close (*dev);
1904         *dev = new_dev;
1905         print_using_dev (*dev);
1906         return 1;
1907 }
1908
1909 static int
1910 do_set (PedDevice** dev)
1911 {
1912         PedDisk*                disk;
1913         PedPartition*           part = NULL;
1914         PedPartitionFlag        flag;
1915         int                     state;
1916
1917         disk = ped_disk_new (*dev);
1918         if (!disk)
1919                 goto error;
1920
1921         if (!command_line_get_partition (_("Partition number?"), disk, &part))
1922                 goto error_destroy_disk;
1923         if (!command_line_get_part_flag (_("Flag to Invert?"), part, &flag))
1924                 goto error_destroy_disk;
1925         state = (ped_partition_get_flag (part, flag) == 0 ? 1 : 0);
1926
1927         if (!is_toggle_mode) {
1928                 if (!command_line_get_state (_("New state?"), &state))
1929                             goto error_destroy_disk;
1930         }
1931
1932         if (!ped_partition_set_flag (part, flag, state))
1933                         goto error_destroy_disk;
1934         if (!ped_disk_commit (disk))
1935                         goto error_destroy_disk;
1936         ped_disk_destroy (disk);
1937
1938         if ((*dev)->type != PED_DEVICE_FILE)
1939                 disk_is_modified = 1;
1940
1941             return 1;
1942
1943 error_destroy_disk:
1944         ped_disk_destroy (disk);
1945 error:
1946         return 0;
1947 }
1948
1949 static int
1950 do_toggle (PedDevice **dev)
1951 {
1952         int result;
1953
1954         is_toggle_mode = 1;
1955         result = do_set (dev);
1956         is_toggle_mode = 0;
1957
1958         return result;
1959 }
1960
1961 static int
1962 do_unit (PedDevice** dev)
1963 {
1964         PedUnit unit = ped_unit_get_default ();
1965         if (!command_line_get_unit (_("Unit?"), &unit))
1966                 return 0;
1967         ped_unit_set_default (unit);
1968         return 1;
1969 }
1970
1971 static int
1972 do_version ()
1973 {
1974     printf ("\n%s\n%s",
1975             prog_name,
1976             _(copyright_msg));
1977     return 1;
1978 }
1979
1980 static void
1981 _init_messages ()
1982 {
1983         StrList*                list;
1984         int                     first;
1985         PedFileSystemType*      fs_type;
1986         PedDiskType*            disk_type;
1987         PedPartitionFlag        part_flag;
1988         PedUnit                 unit;
1989
1990 /* flags */
1991         first = 1;
1992         list = str_list_create (_(flag_msg_start), NULL);
1993         for (part_flag = ped_partition_flag_next (0); part_flag;
1994                         part_flag = ped_partition_flag_next (part_flag)) {
1995                 if (first)
1996                         first = 0;
1997                 else
1998                         str_list_append (list, ", ");
1999                 str_list_append (list,
2000                                  _(ped_partition_flag_get_name (part_flag)));
2001         }
2002         str_list_append (list, "\n");
2003
2004         flag_msg = str_list_convert (list);
2005         str_list_destroy (list);
2006
2007 /* units */
2008         first = 1;
2009         list = str_list_create (_(unit_msg_start), NULL);
2010         for (unit = PED_UNIT_FIRST; unit <= PED_UNIT_LAST; unit++) {
2011                 if (first)
2012                         first = 0;
2013                 else
2014                         str_list_append (list, ", ");
2015                 str_list_append (list, ped_unit_get_name (unit));
2016         }
2017         str_list_append (list, "\n");
2018
2019         unit_msg = str_list_convert (list);
2020         str_list_destroy (list);
2021
2022 /* disk type */
2023         list = str_list_create (_(label_type_msg_start), NULL);
2024
2025         first = 1;
2026         for (disk_type = ped_disk_type_get_next (NULL);
2027              disk_type; disk_type = ped_disk_type_get_next (disk_type)) {
2028                 if (disk_type->ops->write == NULL)
2029                         continue;
2030
2031                 if (first)
2032                         first = 0;
2033                 else
2034                         str_list_append (list, ", ");
2035                 str_list_append (list, disk_type->name);
2036         }
2037         str_list_append (list, "\n");
2038
2039         label_type_msg = str_list_convert (list);
2040         str_list_destroy (list);
2041
2042 /* mkfs - file system types */
2043         list = str_list_create (_(fs_type_msg_start), NULL);
2044
2045         first = 1;
2046         for (fs_type = ped_file_system_type_get_next (NULL);
2047              fs_type; fs_type = ped_file_system_type_get_next (fs_type)) {
2048                 if (fs_type->ops->create == NULL)
2049                         continue;
2050
2051                 if (first)
2052                         first = 0;
2053                 else
2054                         str_list_append (list, ", ");
2055                 str_list_append (list, fs_type->name);
2056         }
2057         str_list_append (list, "\n");
2058
2059         mkfs_fs_type_msg = str_list_convert (list);
2060         str_list_destroy (list);
2061
2062 /* mkpart - file system types */
2063         list = str_list_create (_(fs_type_msg_start), NULL);
2064
2065         first = 1;
2066         for (fs_type = ped_file_system_type_get_next (NULL);
2067              fs_type; fs_type = ped_file_system_type_get_next (fs_type)) {
2068                 if (first)
2069                         first = 0;
2070                 else
2071                         str_list_append (list, ", ");
2072                 str_list_append (list, fs_type->name);
2073         }
2074         str_list_append (list, "\n");
2075
2076         mkpart_fs_type_msg = str_list_convert (list);
2077         str_list_destroy (list);
2078
2079 /* resize - file system types */
2080         list = str_list_create (_(resize_msg_start), NULL);
2081
2082         first = 1;
2083         for (fs_type = ped_file_system_type_get_next (NULL);
2084              fs_type; fs_type = ped_file_system_type_get_next (fs_type)) {
2085                 if (fs_type->ops->resize == NULL)
2086                         continue;
2087
2088                 if (first)
2089                         first = 0;
2090                 else
2091                         str_list_append (list, ", ");
2092                 str_list_append (list, fs_type->name);
2093         }
2094         str_list_append (list, "\n");
2095
2096         resize_fs_type_msg = str_list_convert (list);
2097         str_list_destroy (list);
2098 }
2099
2100 static void
2101 _done_messages ()
2102 {
2103         free (flag_msg);
2104         free (mkfs_fs_type_msg);
2105         free (mkpart_fs_type_msg);
2106         free (resize_fs_type_msg);
2107         free (label_type_msg);
2108 }
2109
2110 static void
2111 _init_commands ()
2112 {
2113         command_register (commands, command_create (
2114                 str_list_create_unique ("check", _("check"), NULL),
2115                 do_check,
2116                 str_list_create (
2117 _("check NUMBER                             do a simple check on the file "
2118   "system"),
2119 NULL),
2120                 str_list_create (_(number_msg), NULL), 1));
2121
2122         command_register (commands, command_create (
2123                 str_list_create_unique ("cp", _("cp"), NULL),
2124                 do_cp,
2125                 str_list_create (
2126 _("cp [FROM-DEVICE] FROM-NUMBER TO-NUMBER   copy file system to another "
2127   "partition"),
2128 NULL),
2129                 str_list_create (_(number_msg), _(device_msg), NULL), 1));
2130
2131         command_register (commands, command_create (
2132                 str_list_create_unique ("help", _("help"), NULL),
2133                 do_help,
2134                 str_list_create (
2135 _("help [COMMAND]                           print general help, or help "
2136   "on COMMAND"),
2137 NULL),
2138                 NULL, 1));
2139
2140         command_register (commands, command_create (
2141                 str_list_create_unique ("mklabel", _("mklabel"), "mktable", _("mktable"), NULL),
2142                 do_mklabel,
2143                 str_list_create (
2144 _("mklabel,mktable LABEL-TYPE               create a new disklabel "
2145   "(partition table)"),
2146 NULL),
2147                 str_list_create (label_type_msg, NULL), 1));
2148
2149         command_register (commands, command_create (
2150                 str_list_create_unique ("mkfs", _("mkfs"), NULL),
2151                 do_mkfs,
2152                 str_list_create (
2153 _("mkfs NUMBER FS-TYPE                      make a FS-TYPE file "
2154   "system on partititon NUMBER"),
2155 NULL),
2156                 str_list_create (_(number_msg), _(mkfs_fs_type_msg), NULL), 1));
2157
2158         command_register (commands, command_create (
2159                 str_list_create_unique ("mkpart", _("mkpart"), NULL),
2160                 do_mkpart,
2161                 str_list_create (
2162 _("mkpart PART-TYPE [FS-TYPE] START END     make a partition"),
2163 NULL),
2164                 str_list_create (_(part_type_msg),
2165                                  _(mkpart_fs_type_msg),
2166                                  _(start_end_msg),
2167                                  "\n",
2168 _("'mkpart' makes a partition without creating a new file system on the "
2169   "partition.  FS-TYPE may be specified to set an appropriate partition ID.\n"),
2170 NULL), 1));
2171
2172         command_register (commands, command_create (
2173                 str_list_create_unique ("mkpartfs", _("mkpartfs"), NULL),
2174                 do_mkpartfs,
2175                 str_list_create (
2176 _("mkpartfs PART-TYPE FS-TYPE START END     make a partition with a "
2177   "file system"),
2178 NULL),
2179         str_list_create (_(part_type_msg), _(start_end_msg), NULL), 1));
2180
2181 command_register (commands, command_create (
2182         str_list_create_unique ("move", _("move"), NULL),
2183         do_move,
2184         str_list_create (
2185 _("move NUMBER START END                    move partition NUMBER"),
2186 NULL),
2187         str_list_create (_(number_msg), _(start_end_msg), NULL), 1));
2188
2189 command_register (commands, command_create (
2190         str_list_create_unique ("name", _("name"), NULL),
2191         do_name,
2192         str_list_create (
2193 _("name NUMBER NAME                         name partition NUMBER as NAME"),
2194 NULL),
2195         str_list_create (_(number_msg), _(name_msg), NULL), 1));
2196
2197 command_register (commands, command_create (
2198         str_list_create_unique ("print", _("print"), NULL),
2199         do_print,
2200         str_list_create (
2201 _("print [devices|free|list,all|NUMBER]     display the partition table, "
2202   "available devices, free space, all found partitions, or a particular "
2203   "partition"),
2204 NULL),
2205         str_list_create (
2206 _("Without arguments, 'print' displays the entire partition table. However "
2207   "with the following arguments it performs various other actions.\n"),
2208 _("  devices   : display all active block devices\n"),
2209 _("  free      : display information about free unpartitioned space on the "
2210   "current block device\n"),
2211 _("  list, all : display the partition tables of all active block devices\n"),
2212 _("  NUMBER    : display more detailed information about this particular "
2213   "partition\n"),
2214 NULL), 1));
2215
2216 command_register (commands, command_create (
2217         str_list_create_unique ("quit", _("quit"), NULL),
2218         do_quit,
2219         str_list_create (
2220 _("quit                                     exit program"),
2221 NULL),
2222         NULL, 1));
2223
2224 command_register (commands, command_create (
2225         str_list_create_unique ("rescue", _("rescue"), NULL),
2226         do_rescue,
2227         str_list_create (
2228 _("rescue START END                         rescue a lost partition near "
2229 "START and END"),
2230 NULL),
2231         str_list_create (_(start_end_msg), NULL), 1));
2232
2233 command_register (commands, command_create (
2234         str_list_create_unique ("resize", _("resize"), NULL),
2235         do_resize,
2236         str_list_create (
2237 _("resize NUMBER START END                  resize partition NUMBER and "
2238 "its file system"),
2239 NULL),
2240         str_list_create (_(number_msg),
2241                          _(start_end_msg),
2242                          _(resize_fs_type_msg), NULL), 1));
2243
2244 command_register (commands, command_create (
2245         str_list_create_unique ("rm", _("rm"), NULL),
2246         do_rm,
2247         str_list_create (
2248 _("rm NUMBER                                delete partition NUMBER"),
2249 NULL),
2250         str_list_create (_(number_msg), NULL), 1));
2251
2252 command_register (commands, command_create (
2253         str_list_create_unique ("select", _("select"), NULL),
2254         do_select,
2255         str_list_create (
2256 _("select DEVICE                            choose the device to edit"),
2257 NULL),
2258         str_list_create (_(device_msg), NULL), 1));
2259
2260 command_register (commands, command_create (
2261                 str_list_create_unique ("set", _("set"), NULL),
2262                 do_set,
2263                 str_list_create (
2264 _("set NUMBER FLAG STATE                    change the FLAG on partition "
2265   "NUMBER"),
2266 NULL),
2267         str_list_create (_(number_msg), flag_msg, _(state_msg), NULL), 1));
2268
2269 command_register (commands, command_create (
2270         str_list_create_unique ("toggle", _("toggle"), NULL),
2271         do_toggle,
2272         str_list_create (
2273 _("toggle [NUMBER [FLAG]]                   toggle the state of FLAG on "
2274   "partition NUMBER"),
2275 NULL),
2276         str_list_create (_(number_msg), flag_msg, NULL), 1));
2277
2278 command_register (commands, command_create (
2279         str_list_create_unique ("unit", _("unit"), NULL),
2280         do_unit,
2281         str_list_create (
2282 _("unit UNIT                                set the default unit to UNIT"),
2283 NULL),
2284         str_list_create (unit_msg, NULL), 1));
2285
2286 command_register (commands, command_create (
2287         str_list_create_unique ("version", _("version"), NULL),
2288         do_version,
2289         str_list_create (
2290 _("version                                  display the version number "
2291 "and copyright information of GNU Parted"),
2292 NULL),
2293         str_list_create (
2294 _("'version' displays copyright and version information corresponding to this "
2295 "copy of GNU Parted\n"),
2296 NULL), 1));
2297
2298 }
2299
2300 static void
2301 _done_commands ()
2302 {
2303 Command**       walk;
2304
2305 for (walk = commands; *walk; walk++) {
2306         command_destroy (*walk);
2307         *walk = NULL;
2308 }
2309 }
2310
2311 static void
2312 _init_i18n ()
2313 {
2314 /* intialize i18n */
2315 #ifdef ENABLE_NLS
2316 setlocale(LC_ALL, "");
2317 bindtextdomain(PACKAGE, LOCALEDIR);
2318 textdomain(PACKAGE);
2319 #endif /* ENABLE_NLS */
2320 }
2321
2322 void
2323 _version ()
2324 {
2325   version_etc (stdout, PROGRAM_NAME, PACKAGE_NAME, VERSION, AUTHORS,
2326                (char *) NULL);
2327 }
2328
2329 static int
2330 _parse_options (int* argc_ptr, char*** argv_ptr)
2331 {
2332 int     opt, help = 0, list = 0, version = 0, wrong = 0;
2333
2334 while (1)
2335 {
2336         opt = getopt_long (*argc_ptr, *argv_ptr, "hlmsv",
2337                            options, NULL);
2338         if (opt == -1)
2339                 break;
2340
2341         switch (opt) {
2342                 case 'h': help = 1; break;
2343                 case 'l': list = 1; break;
2344                 case 'm': opt_machine_mode = 1; break;
2345                 case 's': opt_script_mode = 1; break;
2346                 case 'v': version = 1; break;
2347                 case PRETEND_INPUT_TTY:
2348                   pretend_input_tty = 1;
2349                   break;
2350                 default:  wrong = 1; break;
2351         }
2352 }
2353
2354 if (wrong == 1) {
2355         fprintf (stderr,
2356                  _("Usage: %s [-hlmsv] [DEVICE [COMMAND [PARAMETERS]]...]\n"),
2357                  program_name);
2358         return 0;
2359 }
2360
2361 if (version == 1) {
2362         _version ();
2363         exit (EXIT_SUCCESS);
2364 }
2365
2366 if (help == 1) {
2367         help_msg ();
2368         exit (EXIT_SUCCESS);
2369 }
2370
2371 if (list == 1) {
2372         _print_list ();
2373         exit (EXIT_SUCCESS);
2374 }
2375
2376 *argc_ptr -= optind;
2377 *argv_ptr += optind;
2378 return 1;
2379 }
2380
2381 static PedDevice*
2382 _choose_device (int* argc_ptr, char*** argv_ptr)
2383 {
2384 PedDevice*      dev;
2385
2386 /* specified on comand line? */
2387 if (*argc_ptr) {
2388         dev = ped_device_get ((*argv_ptr) [0]);
2389         if (!dev)
2390                 return NULL;
2391         (*argc_ptr)--;
2392         (*argv_ptr)++;
2393 } else {
2394 retry:
2395         ped_device_probe_all ();
2396         dev = ped_device_get_next (NULL);
2397         if (!dev) {
2398                 if (ped_exception_throw (PED_EXCEPTION_ERROR,
2399                         PED_EXCEPTION_RETRY_CANCEL,
2400                         _("No device found"))
2401                                 == PED_EXCEPTION_RETRY)
2402                         goto retry;
2403                 else
2404                         return NULL;
2405         }
2406 }
2407
2408 if (!ped_device_open (dev))
2409         return NULL;
2410 return dev;
2411 }
2412
2413 static PedDevice*
2414 _init (int* argc_ptr, char*** argv_ptr)
2415 {
2416 PedDevice*      dev;
2417
2418 #ifdef ENABLE_MTRACE
2419 mtrace();
2420 #endif
2421
2422 _init_i18n ();
2423 if (!init_ui ())
2424         goto error;
2425 _init_messages ();
2426 _init_commands ();
2427
2428 if (!_parse_options (argc_ptr, argv_ptr))
2429         goto error_done_commands;
2430
2431 #ifdef HAVE_GETUID
2432         if (getuid() != 0 && !opt_script_mode) {
2433             puts (_("WARNING: You are not superuser.  Watch out for "
2434                     "permissions."));
2435         }
2436 #endif
2437
2438 dev = _choose_device (argc_ptr, argv_ptr);
2439 if (!dev)
2440         goto error_done_commands;
2441
2442 g_timer = ped_timer_new (_timer_handler, &timer_context);
2443 if (!g_timer)
2444         goto error_done_commands;
2445 timer_context.last_update = 0;
2446
2447 return dev;
2448
2449 error_done_commands:
2450 _done_commands ();
2451 _done_messages ();
2452 done_ui ();
2453 error:
2454 return NULL;
2455 }
2456
2457 static void
2458 _done (PedDevice* dev)
2459 {
2460 if (dev->boot_dirty && dev->type != PED_DEVICE_FILE) {
2461         ped_exception_throw (
2462                 PED_EXCEPTION_WARNING,
2463                 PED_EXCEPTION_OK,
2464         _("You should reinstall your boot loader before "
2465           "rebooting.  Read section 4 of the Parted User "
2466           "documentation for more information."));
2467 }
2468 if (!opt_script_mode && !opt_machine_mode && disk_is_modified) {
2469         ped_exception_throw (
2470                 PED_EXCEPTION_INFORMATION, PED_EXCEPTION_OK,
2471                 _("You may need to update /etc/fstab.\n"));
2472 }
2473
2474 ped_device_close (dev);
2475
2476 ped_timer_destroy (g_timer);
2477 _done_commands ();
2478 _done_messages ();
2479 done_ui();
2480 }
2481
2482 int
2483 main (int argc, char** argv)
2484 {
2485         PedDevice*      dev;
2486         int             status;
2487
2488         set_program_name (argv[0]);
2489         atexit (close_stdout);
2490
2491         dev = _init (&argc, &argv);
2492         if (!dev)
2493                 return 1;
2494
2495         if (argc || opt_script_mode)
2496                 status = non_interactive_mode (&dev, commands, argc, argv);
2497         else
2498                 status = interactive_mode (&dev, commands);
2499
2500         _done (dev);
2501
2502         return !status;
2503 }