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