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