OSDN Git Service

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