OSDN Git Service

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