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
64static 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.  */
71enum
72{
73  PRETEND_INPUT_TTY = CHAR_MAX + 1,
74};
75
76
77typedef struct {
78        time_t  last_update;
79        time_t  predicted_time_left;
80} TimerContext;
81
82static 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
93static 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
102char *program_name;
103
104int     opt_script_mode = 0;
105int     pretend_input_tty = 0;
106int     opt_machine_mode = 0;
107int     disk_is_modified = 0;
108int     is_toggle_mode = 0;
109
110static 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
114static char* label_type_msg_start = N_("LABEL-TYPE is one of: ");
115static char* flag_msg_start =   N_("FLAG is one of: ");
116static char* unit_msg_start =   N_("UNIT is one of: ");
117static char* part_type_msg =    N_("PART-TYPE is one of: primary, logical, "
118                                   "extended\n");
119static char* fs_type_msg_start = N_("FS-TYPE is one of: ");
120static 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");
123static char* state_msg =        N_("STATE is one of: on, off\n");
124static char* device_msg =       N_("DEVICE is usually /dev/hda or /dev/sda\n");
125static char* name_msg =         N_("NAME is any word you want\n");
126static char* resize_msg_start = N_("The partition must have one of the "
127                                   "following FS-TYPEs: ");
128
129static 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
138static char* label_type_msg;
139static char* flag_msg;
140static char* unit_msg;
141
142static char* mkfs_fs_type_msg;
143static char* mkpart_fs_type_msg;
144static char* resize_fs_type_msg;
145
146static Command* commands [256] = {NULL};
147static PedTimer* g_timer;
148static TimerContext timer_context;
149
150static int _print_list ();
151static void _done (PedDevice* dev);
152
153static 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
185static 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
204static 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
219static 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
231static 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 */
246static int
247snap (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
256typedef enum {
257        MOVE_NO         = 0,
258        MOVE_STILL      = 1,
259        MOVE_UP         = 2,
260        MOVE_DOWN       = 4
261} EMoves;
262
263enum { /* 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 */
277static EMoves
278prefer_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 */
337static void
338snap_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 */
421static PedConstraint*
422constraint_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
429static PedConstraint*
430constraint_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
438void
439help_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
449static int
450do_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
477error_close_fs:
478        ped_file_system_close (fs);
479error_destroy_disk:
480        ped_disk_destroy (disk);
481error:
482        return 0;
483}
484
485static int
486do_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
548error_close_src_fs:
549        ped_file_system_close (src_fs);
550error_destroy_disk:
551        if (src_disk && src_disk != dst_disk)
552                ped_disk_destroy (src_disk);
553        ped_disk_destroy (dst_disk);
554error:
555        return 0;
556}
557
558void
559print_commands_help ()
560{
561        int             i;
562
563        for (i=0; commands [i]; i++)
564                command_print_summary (commands [i]);
565}
566
567void
568print_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
580int
581do_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
595static int
596do_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
631error_destroy_disk:
632        ped_disk_destroy (disk);
633error:
634        return 0;
635}
636
637static int
638do_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
677error_destroy_disk:
678        ped_disk_destroy (disk);
679error:
680        return 0;
681}
682
683static int
684do_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
829error_remove_part:
830        ped_disk_remove_partition (disk, part);
831        ped_constraint_destroy (final_constraint);
832error_destroy_simple_constraints:
833        ped_constraint_destroy (user_constraint);
834        ped_constraint_destroy (dev_constraint);
835        ped_partition_destroy (part);
836error_destroy_disk:
837        ped_disk_destroy (disk);
838error:
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
856static int
857do_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
1004error_remove_part:
1005        ped_disk_remove_partition (disk, part);
1006        ped_constraint_destroy (final_constraint);
1007error_destroy_simple_constraints:
1008        ped_constraint_destroy (user_constraint);
1009        ped_constraint_destroy (dev_constraint);
1010        ped_partition_destroy (part);
1011error_destroy_disk:
1012        ped_disk_destroy (disk);
1013error:
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
1031static int
1032do_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
1106error_destroy_constraint:
1107        ped_constraint_destroy (constraint);
1108error_close_fs:
1109        ped_file_system_close (fs);
1110error_destroy_disk:
1111        ped_disk_destroy (disk);
1112error:
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
1120static int
1121do_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
1147error_free_name:
1148        free (name);
1149error_destroy_disk:
1150        ped_disk_destroy (disk);
1151error:
1152        return 0;
1153}
1154
1155static char*
1156partition_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 */
1195static void
1196print_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
1215static int
1216partition_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
1255static int
1256do_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);
1549error:
1550        return 0;
1551}
1552
1553static 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
1568static int
1569do_quit (PedDevice** dev)
1570{
1571        _done (*dev);
1572        exit (0);
1573}
1574
1575static 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 */
1593static 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 */
1651static 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
1709error_remove_partition:
1710        ped_disk_remove_partition (disk, part);
1711        ped_partition_destroy (part);
1712        ped_constraint_done (&constraint);
1713        return 0;
1714}
1715
1716static int
1717do_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
1754error_destroy_disk:
1755        ped_disk_destroy (disk);
1756error:
1757        return 0;
1758}
1759
1760static int
1761do_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
1832error_close_fs:
1833        ped_file_system_close (fs);
1834error_destroy_constraint:
1835        ped_constraint_destroy (constraint);
1836error_destroy_disk:
1837        ped_disk_destroy (disk);
1838error:
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
1846static int
1847do_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
1870error_destroy_disk:
1871        ped_disk_destroy (disk);
1872error:
1873        return 0;
1874}
1875
1876static int
1877do_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
1892static int
1893do_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
1926error_destroy_disk:
1927        ped_disk_destroy (disk);
1928error:
1929        return 0;
1930}
1931
1932static int
1933do_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
1944static int
1945do_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
1954static int
1955do_version ()
1956{
1957    printf ("\n%s\n%s",
1958            prog_name,
1959            _(copyright_msg));
1960    return 1;
1961}
1962
1963static 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
2083static 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
2093static 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"),
2102NULL),
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"),
2111NULL),
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"),
2120NULL),
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)"),
2129NULL),
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"),
2138NULL),
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"),
2146NULL),
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"),
2153NULL), 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"),
2161NULL),
2162        str_list_create (_(part_type_msg), _(start_end_msg), NULL), 1));
2163
2164command_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"),
2169NULL),
2170        str_list_create (_(number_msg), _(start_end_msg), NULL), 1));
2171
2172command_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"),
2177NULL),
2178        str_list_create (_(number_msg), _(name_msg), NULL), 1));
2179
2180command_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"),
2187NULL),
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"),
2197NULL), 1));
2198
2199command_register (commands, command_create (
2200        str_list_create_unique ("quit", _("quit"), NULL),
2201        do_quit,
2202        str_list_create (
2203_("quit                                     exit program"),
2204NULL),
2205        NULL, 1));
2206
2207command_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"),
2213NULL),
2214        str_list_create (_(start_end_msg), NULL), 1));
2215
2216command_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"),
2222NULL),
2223        str_list_create (_(number_msg),
2224                         _(start_end_msg),
2225                         _(resize_fs_type_msg), NULL), 1));
2226
2227command_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"),
2232NULL),
2233        str_list_create (_(number_msg), NULL), 1));
2234
2235command_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"),
2240NULL),
2241        str_list_create (_(device_msg), NULL), 1));
2242
2243command_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"),
2249NULL),
2250        str_list_create (_(number_msg), flag_msg, _(state_msg), NULL), 1));
2251
2252command_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"),
2258NULL),
2259        str_list_create (_(number_msg), flag_msg, NULL), 1));
2260
2261command_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"),
2266NULL),
2267        str_list_create (unit_msg, NULL), 1));
2268
2269command_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"),
2275NULL),
2276        str_list_create (
2277_("'version' displays copyright and version information corresponding to this "
2278"copy of GNU Parted\n"),
2279NULL), 1));
2280
2281}
2282
2283static void
2284_done_commands ()
2285{
2286Command**       walk;
2287
2288for (walk = commands; *walk; walk++) {
2289        command_destroy (*walk);
2290        *walk = NULL;
2291}
2292}
2293
2294static void
2295_init_i18n ()
2296{
2297/* intialize i18n */
2298#ifdef ENABLE_NLS
2299setlocale(LC_ALL, "");
2300bindtextdomain(PACKAGE, LOCALEDIR);
2301textdomain(PACKAGE);
2302#endif /* ENABLE_NLS */
2303}
2304
2305void
2306_version ()
2307{
2308  version_etc (stdout, PROGRAM_NAME, PACKAGE_NAME, VERSION, AUTHORS,
2309               (char *) NULL);
2310}
2311
2312static int
2313_parse_options (int* argc_ptr, char*** argv_ptr)
2314{
2315int     opt, help = 0, list = 0, version = 0, wrong = 0;
2316
2317while (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
2337if (wrong == 1) {
2338        fprintf (stderr,
2339                 _("Usage: %s [-hlmsv] [DEVICE [COMMAND [PARAMETERS]]...]\n"),
2340                 program_name);
2341        return 0;
2342}
2343
2344if (version == 1) {
2345        _version ();
2346        exit (EXIT_SUCCESS);
2347}
2348
2349if (help == 1) {
2350        help_msg ();
2351        exit (EXIT_SUCCESS);
2352}
2353
2354if (list == 1) {
2355        _print_list ();
2356        exit (EXIT_SUCCESS);
2357}
2358
2359*argc_ptr -= optind;
2360*argv_ptr += optind;
2361return 1;
2362}
2363
2364static PedDevice*
2365_choose_device (int* argc_ptr, char*** argv_ptr)
2366{
2367PedDevice*      dev;
2368
2369/* specified on comand line? */
2370if (*argc_ptr) {
2371        dev = ped_device_get ((*argv_ptr) [0]);
2372        if (!dev)
2373                return NULL;
2374        (*argc_ptr)--;
2375        (*argv_ptr)++;
2376} else {
2377retry:
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
2391if (!ped_device_open (dev))
2392        return NULL;
2393return dev;
2394}
2395
2396static PedDevice*
2397_init (int* argc_ptr, char*** argv_ptr)
2398{
2399PedDevice*      dev;
2400
2401#ifdef ENABLE_MTRACE
2402mtrace();
2403#endif
2404
2405_init_i18n ();
2406if (!init_ui ())
2407        goto error;
2408_init_messages ();
2409_init_commands ();
2410
2411if (!_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
2421dev = _choose_device (argc_ptr, argv_ptr);
2422if (!dev)
2423        goto error_done_commands;
2424
2425g_timer = ped_timer_new (_timer_handler, &timer_context);
2426if (!g_timer)
2427        goto error_done_commands;
2428timer_context.last_update = 0;
2429
2430return dev;
2431
2432error_done_commands:
2433_done_commands ();
2434_done_messages ();
2435done_ui ();
2436error:
2437return NULL;
2438}
2439
2440static void
2441_done (PedDevice* dev)
2442{
2443if (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)
2453if (!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
2460ped_device_close (dev);
2461
2462ped_timer_destroy (g_timer);
2463_done_commands ();
2464_done_messages ();
2465done_ui();
2466}
2467
2468int
2469main (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