1 /* 2 parted - a frontend to libparted 3 Copyright (C) 1999, 2000, 2001, 2002, 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 <parted/parted.h> 21 #include <parted/debug.h> 22 23 #include <ctype.h> 24 #include <signal.h> 25 #include <stdlib.h> 26 #include <string.h> 27 #include <unistd.h> 28 #include <setjmp.h> 29 30 #include <config.h> 31 #include "command.h" 32 #include "strlist.h" 33 #include "ui.h" 34 #include "error.h" 35 36 #define N_(String) String 37 #if ENABLE_NLS 38 # include <libintl.h> 39 # include <locale.h> 40 # define _(String) dgettext (PACKAGE, String) 41 #else 42 # define _(String) (String) 43 #endif /* ENABLE_NLS */ 44 45 #ifdef HAVE_LIBREADLINE 46 47 #ifdef HAVE_TERMCAP_H 48 #include <termcap.h> 49 #else 50 extern int tgetnum (char* key); 51 #endif 52 53 #include <readline/readline.h> 54 #include <readline/history.h> 55 56 #ifndef HAVE_RL_COMPLETION_MATCHES 57 #define rl_completion_matches completion_matches 58 #endif 59 60 #ifndef rl_compentry_func_t 61 #define rl_compentry_func_t void 62 #endif 63 64 #endif /* HAVE_LIBREADLINE */ 65 66 #ifndef SA_SIGINFO 67 # ifndef HAVE_SIGACTION 68 69 struct sigaction { 70 }; 71 72 static inline int 73 sigaction (int signum, const struct* sigaction, struct* sigaction) 74 { 75 } 76 77 # endif /* HAVE_SIGACTON */ 78 79 struct siginfo_t { 80 int si_code; 81 }; 82 83 #endif /* SA_SIGINFO */ 84 85 #ifndef SEGV_MAPERR 86 # define SEGV_MAPERR (INTMAX - 1) 87 #endif 88 89 #ifndef SEGV_ACCERR 90 # define SEGV_ACCERR (INTMAX - 2) 91 #endif 92 93 #ifndef FPE_INTDIV 94 # define FPE_INTDIV (INTMAX - 1) 95 #endif 96 97 #ifndef FPE_INTOVF 98 # define FPE_INTOVF (INTMAX - 2) 99 #endif 100 101 #ifndef FPE_FLTDIV 102 # define FPE_FLTDIV (INTMAX - 3) 103 #endif 104 105 #ifndef FPE_FLTOVF 106 # define FPE_FLTOVF (INTMAX - 4) 107 #endif 108 109 #ifndef FPE_FLTUND 110 # define FPE_FLTUND (INTMAX - 5) 111 #endif 112 113 #ifndef FPE_FLTRES 114 # define FPE_FLTRES (INTMAX - 6) 115 #endif 116 117 #ifndef FPE_FLTINV 118 # define FPE_FLTINV (INTMAX - 7) 119 #endif 120 121 #ifndef FPE_FLTSUB 122 # define FPE_FLTSUB (INTMAX - 8) 123 #endif 124 125 #ifndef ILL_ILLOPC 126 # define ILL_ILLOPC (INTMAX - 1) 127 #endif 128 129 #ifndef ILL_ILLOPN 130 # define ILL_ILLOPN (INTMAX - 2) 131 #endif 132 133 #ifndef ILL_ILLADR 134 # define ILL_ILLADR (INTMAX - 3) 135 #endif 136 137 #ifndef ILL_ILLTRP 138 # define ILL_ILLTRP (INTMAX - 4) 139 #endif 140 141 #ifndef ILL_PRVOPC 142 # define ILL_PRVOPC (INTMAX - 5) 143 #endif 144 145 #ifndef ILL_PRVREG 146 # define ILL_PRVREG (INTMAX - 6) 147 #endif 148 149 #ifndef ILL_COPROC 150 # define ILL_COPROC (INTMAX - 7) 151 #endif 152 153 #ifndef ILL_BADSTK 154 # define ILL_BADSTK (INTMAX - 8) 155 #endif 156 157 char* prog_name = "GNU Parted " VERSION "\n"; 158 159 static char* banner_msg = N_( 160 "Welcome to GNU Parted! Type 'help' to view a list of commands.\n"); 161 162 static char* usage_msg = N_( 163 "Usage: parted [OPTION]... [DEVICE [COMMAND [PARAMETERS]...]...]\n" 164 "Apply COMMANDs with PARAMETERS to DEVICE. If no COMMAND(s) are given, " 165 "run in\ninteractive mode.\n"); 166 167 static char* bug_msg = N_( 168 "\n\nYou found a bug in GNU Parted! Here's what you have to do:\n\n" 169 "Don't panic! The bug has most likely not affected any of your data.\n" 170 "Help us to fix this bug by doing the following:\n\n" 171 "Check whether the bug has already been fixed by checking\n" 172 "the last version of GNU Parted that you can find at:\n\n" 173 "\thttp://ftp.gnu.org/gnu/parted/\n\n" 174 "Please check this version prior to bug reporting.\n\n" 175 "If this has not been fixed yet or if you don't know how to check,\n" 176 "please visit the GNU Parted website:\n\n" 177 "\thttp://www.gnu.org/software/parted\n\n" 178 "for further information.\n\n" 179 "Your report should contain the version of this release (%s)\n" 180 "along with the error message below, the output of\n\n" 181 "\tparted DEVICE unit co print unit s print\n\n" 182 "and the following history of commands you entered.\n" 183 "Also include any additional information about your setup you\n" 184 "consider important.\n"); 185 186 #define MAX_WORDS 1024 187 188 static StrList* command_line; 189 static Command** commands; 190 static StrList* ex_opt_str [64]; 191 static StrList* on_list; 192 static StrList* off_list; 193 static StrList* on_off_list; 194 static StrList* fs_type_list; 195 static StrList* disk_type_list; 196 197 static struct { 198 const StrList* possibilities; 199 const StrList* cur_pos; 200 int in_readline; 201 sigjmp_buf jmp_state; 202 } readline_state; 203 204 static struct sigaction sig_segv; 205 static struct sigaction sig_int; 206 static struct sigaction sig_fpe; 207 static struct sigaction sig_ill; 208 209 volatile int got_ctrl_c = 0; /* used in exception_handler */ 210 211 int 212 screen_width () 213 { 214 int width = 0; 215 216 if (opt_script_mode || pretend_input_tty) 217 return 32768; /* no wrapping ;) */ 218 219 /* HACK: don't specify termcap separately - it'll annoy the users. */ 220 #ifdef HAVE_LIBREADLINE 221 width = tgetnum ("co"); 222 #endif 223 224 if (width <= 0) 225 width = 80; 226 227 return width; 228 } 229 230 void 231 wipe_line () 232 { 233 if (opt_script_mode) 234 return; 235 236 /* yuck */ 237 fputs ("\r " 238 " \r", stdout); 239 } 240 241 #ifdef HAVE_LIBREADLINE 242 /* returns matching commands for text */ 243 static char* 244 command_generator (char* text, int state) 245 { 246 if (!state) 247 readline_state.cur_pos = readline_state.possibilities; 248 249 while (readline_state.cur_pos) { 250 const StrList* cur = readline_state.cur_pos; 251 readline_state.cur_pos = cur->next; 252 if (str_list_match_node (cur, text)) 253 return str_list_convert_node (cur); 254 } 255 256 return NULL; 257 } 258 259 /* completion function for readline() */ 260 char** 261 complete_function (char* text, int start, int end) 262 { 263 return rl_completion_matches (text, 264 (rl_compentry_func_t*) command_generator); 265 } 266 267 static void 268 _add_history_unique (const char* line) 269 { 270 HIST_ENTRY* last_entry = current_history (); 271 if (!strlen (line)) 272 return; 273 if (!last_entry || strcmp (last_entry->line, line)) 274 add_history ((char*) line); 275 } 276 277 /* Prints command history, to be used before aborting */ 278 static void 279 _dump_history () 280 { 281 int i = 0; 282 HIST_ENTRY** all_entries = history_list (); 283 284 fputs (_("\nCommand History:\n"), stdout); 285 while (all_entries[i]) { 286 puts(all_entries[i++]->line); 287 } 288 } 289 290 #else 291 292 /* Print nothing because Readline is absent. */ 293 static inline void 294 _dump_history (void) 295 { 296 } 297 298 #endif /* HAVE_LIBREADLINE */ 299 300 static void 301 mask_signal() 302 { 303 sigset_t curr; 304 sigset_t prev; 305 306 sigfillset(&curr); 307 sigprocmask(SIG_SETMASK, &curr, &prev); 308 } 309 310 /* Resets the environment by jumping to the initial state 311 * saved during ui intitialisation. 312 * Pass 1 as the parameter if you want to quit parted, 313 * 0 if you just want to reset to the command prompt. 314 */ 315 static void 316 reset_env (int quit) 317 { 318 int in_readline = readline_state.in_readline; 319 320 readline_state.in_readline = 0; 321 322 if (in_readline) { 323 putchar ('\n'); 324 if (quit) 325 exit (0); 326 327 siglongjmp (readline_state.jmp_state, 1); 328 } 329 } 330 331 /* Signal handler for SIGINT using 'sigaction'. */ 332 static void 333 sa_sigint_handler (int signum, siginfo_t* info, void *ucontext) 334 { 335 if (info) 336 sigaction (SIGINT, &sig_int, NULL); 337 338 got_ctrl_c = 1; 339 reset_env (0); 340 } 341 342 /* Signal handler for SIGINT using 'signal'. */ 343 static void 344 s_sigint_handler (int signum) 345 { 346 signal (SIGINT, &s_sigint_handler); 347 mask_signal (); 348 sa_sigint_handler (signum, NULL, NULL); 349 } 350 351 /* Signal handler for SIGSEGV using 'sigaction'. */ 352 static void 353 sa_sigsegv_handler (int signum, siginfo_t* info, void* ucontext) 354 { 355 printf (bug_msg, VERSION); 356 _dump_history (); 357 358 if (!info) 359 abort (); 360 361 sigaction (SIGSEGV, &sig_segv, NULL); 362 363 switch (info->si_code) { 364 365 case SEGV_MAPERR: 366 fputs(_("\nError: SEGV_MAPERR (Address not mapped " 367 "to object)\n"), stdout); 368 PED_ASSERT(0, break); /* Force a backtrace */ 369 break; 370 371 case SEGV_ACCERR: 372 fputs(_("\nError: SEGV_ACCERR (Invalid permissions " 373 "for mapped object)\n"), stdout); 374 break; 375 376 default: 377 fputs(_("\nError: A general SIGSEGV signal was " 378 "encountered.\n"), stdout); 379 PED_ASSERT(0, break); /* Force a backtrace */ 380 break; 381 } 382 383 abort (); 384 } 385 386 /* Signal handler for SIGSEGV using 'signal'. */ 387 static void 388 s_sigsegv_handler (int signum) 389 { 390 signal (SIGSEGV, &s_sigsegv_handler); 391 mask_signal (); 392 sa_sigsegv_handler (signum, NULL, NULL); 393 } 394 395 /* Signal handler for SIGFPE using 'sigaction'. */ 396 static void 397 sa_sigfpe_handler (int signum, siginfo_t* info, void* ucontext) 398 { 399 printf (bug_msg, VERSION); 400 _dump_history (); 401 402 if (!info) 403 abort (); 404 405 sigaction (SIGFPE, &sig_fpe, NULL); 406 407 switch (info->si_code) { 408 409 case FPE_INTDIV: 410 fputs(_("\nError: FPE_INTDIV (Integer: " 411 "divide by zero)"), stdout); 412 break; 413 414 case FPE_INTOVF: 415 fputs(_("\nError: FPE_INTOVF (Integer: " 416 "overflow)"), stdout); 417 break; 418 419 case FPE_FLTDIV: 420 fputs(_("\nError: FPE_FLTDIV (Float: " 421 "divide by zero)"), stdout); 422 break; 423 424 case FPE_FLTOVF: 425 fputs(_("\nError: FPE_FLTOVF (Float: " 426 "overflow)"), stdout); 427 break; 428 429 case FPE_FLTUND: 430 fputs(_("\nError: FPE_FLTUND (Float: " 431 "underflow)"), stdout); 432 break; 433 434 case FPE_FLTRES: 435 fputs(_("\nError: FPE_FLTRES (Float: " 436 "inexact result)"), stdout); 437 break; 438 439 case FPE_FLTINV: 440 fputs(_("\nError: FPE_FLTINV (Float: " 441 "invalid operation)"), stdout); 442 break; 443 444 case FPE_FLTSUB: 445 fputs(_("\nError: FPE_FLTSUB (Float: " 446 "subscript out of range)"), stdout); 447 break; 448 449 default: 450 fputs(_("\nError: A general SIGFPE signal " 451 "was encountered."), stdout); 452 break; 453 454 } 455 456 abort (); 457 } 458 459 /* Signal handler for SIGFPE using 'signal'. */ 460 static void 461 s_sigfpe_handler (int signum) 462 { 463 signal (SIGFPE, &s_sigfpe_handler); 464 mask_signal (); 465 sa_sigfpe_handler (signum, NULL, NULL); 466 } 467 468 /* Signal handler for SIGILL using 'sigaction'. */ 469 static void 470 sa_sigill_handler (int signum, siginfo_t* info, void* ucontext) 471 { 472 printf (bug_msg, VERSION); 473 _dump_history (); 474 475 if (!info) 476 abort(); 477 478 sigaction (SIGILL, &sig_ill, NULL); 479 480 switch (info->si_code) { 481 482 case ILL_ILLOPC: 483 fputs(_("\nError: ILL_ILLOPC " 484 "(Illegal Opcode)"), stdout); 485 break; 486 487 case ILL_ILLOPN: 488 fputs(_("\nError: ILL_ILLOPN " 489 "(Illegal Operand)"), stdout); 490 break; 491 492 case ILL_ILLADR: 493 fputs(_("\nError: ILL_ILLADR " 494 "(Illegal addressing mode)"), stdout); 495 break; 496 497 case ILL_ILLTRP: 498 fputs(_("\nError: ILL_ILLTRP " 499 "(Illegal Trap)"), stdout); 500 break; 501 502 case ILL_PRVOPC: 503 fputs(_("\nError: ILL_PRVOPC " 504 "(Privileged Opcode)"), stdout); 505 break; 506 507 case ILL_PRVREG: 508 fputs(_("\nError: ILL_PRVREG " 509 "(Privileged Register)"), stdout); 510 break; 511 512 case ILL_COPROC: 513 fputs(_("\nError: ILL_COPROC " 514 "(Coprocessor Error)"), stdout); 515 break; 516 517 case ILL_BADSTK: 518 fputs(_("\nError: ILL_BADSTK " 519 "(Internal Stack Error)"), stdout); 520 break; 521 522 default: 523 fputs(_("\nError: A general SIGILL " 524 "signal was encountered."), stdout); 525 break; 526 } 527 528 abort (); 529 } 530 531 /* Signal handler for SIGILL using 'signal'. */ 532 static void 533 s_sigill_handler (int signum) 534 { 535 signal (SIGILL, &s_sigill_handler); 536 mask_signal (); 537 sa_sigill_handler (signum, NULL, NULL); 538 } 539 540 static char* 541 _readline (const char* prompt, const StrList* possibilities) 542 { 543 char* line; 544 545 readline_state.possibilities = possibilities; 546 readline_state.cur_pos = NULL; 547 readline_state.in_readline = 1; 548 549 if (sigsetjmp (readline_state.jmp_state,1)) 550 return NULL; 551 552 wipe_line (); 553 #ifdef HAVE_LIBREADLINE 554 if (!opt_script_mode) { 555 /* XXX: why isn't prompt const? */ 556 line = readline ((char*) prompt); 557 if (line) 558 _add_history_unique (line); 559 } else 560 #endif 561 { 562 fputs (prompt, stdout); 563 fflush (stdout); 564 line = (char*) malloc (256); 565 if (fgets (line, 256, stdin) && strcmp (line, "") != 0) { 566 #ifndef HAVE_LIBREADLINE 567 /* Echo the input line, to be consistent with 568 how readline-5.2 works. */ 569 fputs (line, stdout); 570 fflush (stdout); 571 #endif 572 line [strlen (line) - 1] = 0; /* kill trailing CR */ 573 } else { 574 free (line); 575 line = NULL; 576 } 577 } 578 579 readline_state.in_readline = 0; 580 return line; 581 } 582 583 static PedExceptionOption 584 option_get_next (PedExceptionOption options, PedExceptionOption current) 585 { 586 PedExceptionOption i; 587 588 if (current == 0) 589 i = PED_EXCEPTION_OPTION_FIRST; 590 else 591 i = current * 2; 592 593 for (; i <= options; i *= 2) { 594 if (options & i) 595 return i; 596 } 597 return 0; 598 } 599 600 static void 601 _print_exception_text (PedException* ex) 602 { 603 StrList* text; 604 605 wipe_line (); 606 607 if (ex->type == PED_EXCEPTION_BUG) { 608 printf (bug_msg, VERSION); 609 text = str_list_create ("\n", ex->message, "\n\n", NULL); 610 } else { 611 text = str_list_create ( 612 _(ped_exception_get_type_string (ex->type)), 613 ": ", ex->message, "\n", NULL); 614 } 615 616 str_list_print_wrap (text, screen_width (), 0, 0); 617 str_list_destroy (text); 618 } 619 620 static PedExceptionOption 621 exception_handler (PedException* ex) 622 { 623 PedExceptionOption opt; 624 625 _print_exception_text (ex); 626 627 /* only one choice? Take it ;-) */ 628 opt = option_get_next (ex->options, 0); 629 if (!option_get_next (ex->options, opt)) 630 return opt; 631 632 /* script-mode: don't handle the exception */ 633 if (opt_script_mode || (!isatty (0) && !pretend_input_tty)) 634 return PED_EXCEPTION_UNHANDLED; 635 636 got_ctrl_c = 0; 637 638 do { 639 opt = command_line_get_ex_opt ("", ex->options); 640 } while (opt == PED_EXCEPTION_UNHANDLED 641 && (isatty (0) || pretend_input_tty) && !got_ctrl_c); 642 643 if (got_ctrl_c) { 644 got_ctrl_c = 0; 645 opt = PED_EXCEPTION_UNHANDLED; 646 } 647 648 return opt; 649 } 650 651 void 652 command_line_push_word (const char* word) 653 { 654 command_line = str_list_append (command_line, word); 655 } 656 657 char* 658 command_line_pop_word () 659 { 660 char* result; 661 StrList* next; 662 663 PED_ASSERT (command_line != NULL, return NULL); 664 665 result = str_list_convert_node (command_line); 666 next = command_line->next; 667 668 str_list_destroy_node (command_line); 669 command_line = next; 670 return result; 671 } 672 673 void 674 command_line_flush () 675 { 676 str_list_destroy (command_line); 677 command_line = NULL; 678 } 679 680 char* 681 command_line_peek_word () 682 { 683 if (command_line) 684 return str_list_convert_node (command_line); 685 else 686 return NULL; 687 } 688 689 int 690 command_line_get_word_count () 691 { 692 return str_list_length (command_line); 693 } 694 695 static int 696 _str_is_spaces (const char* str) 697 { 698 while (isspace (*str)) 699 str++; 700 701 return *str == 0; 702 } 703 704 /* "multi_word mode" is the "normal" mode... many words can be typed, 705 * delimited by spaces, etc. 706 * In single-word mode, only one word is parsed per line. 707 * Leading and trailing spaces are removed. For example: " a b c " 708 * is a single word "a b c". The motivation for this mode is partition 709 * names, etc. In single-word mode, the empty string is a word. 710 * (but not in multi-word mode). 711 */ 712 void 713 command_line_push_line (const char* line, int multi_word) 714 { 715 int quoted = 0; 716 char quote_char = 0; 717 char this_word [256]; 718 int i; 719 720 do { 721 while (*line == ' ') 722 line++; 723 724 i = 0; 725 for (; *line; line++) { 726 if (*line == ' ' && !quoted) { 727 if (multi_word) 728 break; 729 730 /* single word: check for trailing spaces + eol */ 731 if (_str_is_spaces (line)) 732 break; 733 } 734 735 if (!quoted && strchr ("'\"", *line)) { 736 quoted = 1; 737 quote_char = *line; 738 continue; 739 } 740 741 if (quoted && *line == quote_char) { 742 quoted = 0; 743 continue; 744 } 745 746 /* hack: escape characters */ 747 if (quoted && line[0] == '\\' && line[1]) 748 line++; 749 750 this_word [i++] = *line; 751 } 752 if (i || !multi_word) { 753 this_word [i] = 0; 754 command_line_push_word (this_word); 755 } 756 } while (*line && multi_word); 757 } 758 759 static char* 760 realloc_and_cat (char* str, const char* append) 761 { 762 int length = strlen (str) + strlen (append) + 1; 763 char* new_str = realloc (str, length); 764 765 strcat (new_str, append); 766 return new_str; 767 } 768 769 static char* 770 _construct_prompt (const char* head, const char* def, 771 const StrList* possibilities) 772 { 773 char* prompt = strdup (head); 774 775 if (def && possibilities) 776 PED_ASSERT (str_list_match_any (possibilities, def), 777 return NULL); 778 779 if (possibilities && str_list_length (possibilities) < 8) { 780 const StrList* walk; 781 782 if (strlen (prompt)) 783 prompt = realloc_and_cat (prompt, " "); 784 785 for (walk = possibilities; walk; walk = walk->next) { 786 if (walk != possibilities) 787 prompt = realloc_and_cat (prompt, "/"); 788 789 if (def && str_list_match_node (walk, def) == 2) { 790 prompt = realloc_and_cat (prompt, "["); 791 prompt = realloc_and_cat (prompt, def); 792 prompt = realloc_and_cat (prompt, "]"); 793 } else { 794 char* text = str_list_convert_node (walk); 795 prompt = realloc_and_cat (prompt, text); 796 free (text); 797 } 798 } 799 prompt = realloc_and_cat (prompt, "? "); 800 } else if (def) { 801 if (strlen (prompt)) 802 prompt = realloc_and_cat (prompt, " "); 803 prompt = realloc_and_cat (prompt, "["); 804 prompt = realloc_and_cat (prompt, def); 805 prompt = realloc_and_cat (prompt, "]? "); 806 } else { 807 if (strlen (prompt)) 808 prompt = realloc_and_cat (prompt, " "); 809 } 810 811 return prompt; 812 } 813 814 void 815 command_line_prompt_words (const char* prompt, const char* def, 816 const StrList* possibilities, int multi_word) 817 { 818 char* line; 819 char* real_prompt; 820 char* _def = (char*) def; 821 int _def_needs_free = 0; 822 823 if (!def && str_list_length (possibilities) == 1) { 824 _def = str_list_convert_node (possibilities); 825 _def_needs_free = 1; 826 } 827 828 if (opt_script_mode) { 829 if (_def) 830 command_line_push_line (_def, 0); 831 return; 832 } 833 834 do { 835 real_prompt = _construct_prompt (prompt, _def, possibilities); 836 line = _readline (real_prompt, possibilities); 837 free (real_prompt); 838 if (!line) 839 break; 840 841 if (!strlen (line)) { 842 if (_def) 843 command_line_push_line (_def, 0); 844 } else { 845 command_line_push_line (line, multi_word); 846 } 847 free (line); 848 } while (!command_line_get_word_count () && !_def); 849 850 if (_def_needs_free) 851 free (_def); 852 } 853 854 /** 855 * Get a word from command line. 856 * 857 * \param possibilities a StrList of valid strings, NULL if all are valid. 858 * \param multi_word whether multiple words are allowed. 859 * 860 * \return The word(s), or NULL if empty. 861 */ 862 char* 863 command_line_get_word (const char* prompt, const char* def, 864 const StrList* possibilities, int multi_word) 865 { 866 do { 867 if (command_line_get_word_count ()) { 868 char* result = command_line_pop_word (); 869 StrList* result_node; 870 871 if (!possibilities) 872 return result; 873 874 result_node = str_list_match (possibilities, result); 875 if (result_node == NULL) 876 error (0, 0, _("invalid token: %s"), result); 877 free (result); 878 if (result_node) 879 return str_list_convert_node (result_node); 880 881 command_line_flush (); 882 if (opt_script_mode) 883 return NULL; 884 } 885 886 command_line_prompt_words (prompt, def, possibilities, 887 multi_word); 888 } while (command_line_get_word_count ()); 889 890 return NULL; 891 } 892 893 int 894 command_line_get_integer (const char* prompt, int* value) 895 { 896 char def_str [10]; 897 char* input; 898 int valid; 899 900 snprintf (def_str, 10, "%d", *value); 901 input = command_line_get_word (prompt, *value ? def_str : NULL, 902 NULL, 1); 903 if (!input) 904 return 0; 905 valid = sscanf (input, "%d", value); 906 free (input); 907 return valid; 908 } 909 910 int 911 command_line_get_sector (const char* prompt, PedDevice* dev, PedSector* value, 912 PedGeometry** range) 913 { 914 char* def_str; 915 char* input; 916 int valid; 917 918 def_str = ped_unit_format (dev, *value); 919 input = command_line_get_word (prompt, *value ? def_str : NULL, 920 NULL, 1); 921 922 /* def_str might have rounded *value a little bit. If the user picked 923 * the default, make sure the selected sector is identical to the 924 * default. 925 */ 926 if (input && *value && !strcmp (input, def_str)) { 927 if (range) { 928 *range = ped_geometry_new (dev, *value, 1); 929 ped_free (def_str); 930 return *range != NULL; 931 } 932 933 ped_free (def_str); 934 return 1; 935 } 936 937 ped_free (def_str); 938 if (!input) { 939 *value = 0; 940 if (range) 941 *range = NULL; 942 return 0; 943 } 944 945 valid = ped_unit_parse (input, dev, value, range); 946 947 free (input); 948 return valid; 949 } 950 951 int 952 command_line_get_state (const char* prompt, int* value) 953 { 954 char* def_word; 955 char* input; 956 957 if (*value) 958 def_word = str_list_convert_node (on_list); 959 else 960 def_word = str_list_convert_node (off_list); 961 input = command_line_get_word (prompt, def_word, on_off_list, 1); 962 free (def_word); 963 if (!input) 964 return 0; 965 if (str_list_match_any (on_list, input)) 966 *value = 1; 967 else 968 *value = 0; 969 free (input); 970 return 1; 971 } 972 973 int 974 command_line_get_device (const char* prompt, PedDevice** value) 975 { 976 char* def_dev_name = *value ? (*value)->path : NULL; 977 char* dev_name; 978 PedDevice* dev; 979 980 dev_name = command_line_get_word (prompt, def_dev_name, NULL, 1); 981 if (!dev_name) 982 return 0; 983 984 dev = ped_device_get (dev_name); 985 free (dev_name); 986 if (!dev) 987 return 0; 988 989 *value = dev; 990 return 1; 991 } 992 993 int 994 command_line_get_disk (const char* prompt, PedDisk** value) 995 { 996 PedDevice* dev = *value ? (*value)->dev : NULL; 997 998 if (!command_line_get_device (prompt, &dev)) 999 return 0; 1000 1001 if (dev != (*value)->dev) { 1002 PedDisk* new_disk = ped_disk_new (dev); 1003 if (!new_disk) 1004 return 0; 1005 *value = new_disk; 1006 } 1007 return 1; 1008 } 1009 1010 int 1011 command_line_get_partition (const char* prompt, PedDisk* disk, 1012 PedPartition** value) 1013 { 1014 PedPartition* part; 1015 1016 /* Flawed logic, doesn't seem to work?! 1017 check = ped_disk_next_partition (disk, part); 1018 part = ped_disk_next_partition (disk, check); 1019 1020 if (part == NULL) { 1021 1022 *value = check; 1023 printf (_("The (only) primary partition has " 1024 "been automatically selected\n")); 1025 return 1; 1026 1027 } else { 1028 */ 1029 int num = (*value) ? (*value)->num : 0; 1030 1031 if (!command_line_get_integer (prompt, &num)) { 1032 ped_exception_throw (PED_EXCEPTION_ERROR, 1033 PED_EXCEPTION_CANCEL, 1034 _("Expecting a partition number.")); 1035 return 0; 1036 } 1037 1038 part = ped_disk_get_partition (disk, num); 1039 1040 if (!part) { 1041 ped_exception_throw (PED_EXCEPTION_ERROR, 1042 PED_EXCEPTION_CANCEL, 1043 _("Partition doesn't exist.")); 1044 return 0; 1045 } 1046 1047 *value = part; 1048 return 1; 1049 //} 1050 } 1051 1052 int 1053 command_line_get_fs_type (const char* prompt, const PedFileSystemType*(* value)) 1054 { 1055 char* fs_type_name; 1056 PedFileSystemType* fs_type; 1057 1058 fs_type_name = command_line_get_word (prompt, 1059 *value ? (*value)->name : NULL, 1060 fs_type_list, 1); 1061 if (!fs_type_name) { 1062 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, 1063 _("Expecting a file system type.")); 1064 return 0; 1065 } 1066 1067 fs_type = ped_file_system_type_get (fs_type_name); 1068 if (!fs_type) { 1069 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, 1070 _("Unknown file system type \"%s\"."), 1071 fs_type_name); 1072 return 0; 1073 } 1074 1075 free (fs_type_name); 1076 *value = fs_type; 1077 return 1; 1078 } 1079 1080 int 1081 command_line_get_disk_type (const char* prompt, const PedDiskType*(* value)) 1082 { 1083 char* disk_type_name; 1084 1085 disk_type_name = command_line_get_word (prompt, 1086 *value ? (*value)->name : NULL, 1087 disk_type_list, 1); 1088 if (!disk_type_name) { 1089 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, 1090 _("Expecting a disk label type.")); 1091 return 0; 1092 } 1093 1094 *value = ped_disk_type_get (disk_type_name); 1095 free (disk_type_name); 1096 PED_ASSERT (*value != NULL, return 0); 1097 return 1; 1098 } 1099 1100 int 1101 command_line_get_part_flag (const char* prompt, const PedPartition* part, 1102 PedPartitionFlag* flag) 1103 { 1104 StrList* opts = NULL; 1105 PedPartitionFlag walk = 0; 1106 char* flag_name; 1107 1108 while ( (walk = ped_partition_flag_next (walk)) ) { 1109 if (ped_partition_is_flag_available (part, walk)) { 1110 const char* walk_name; 1111 1112 walk_name = ped_partition_flag_get_name (walk); 1113 opts = str_list_append (opts, walk_name); 1114 opts = str_list_append_unique (opts, _(walk_name)); 1115 } 1116 } 1117 1118 flag_name = command_line_get_word (prompt, NULL, opts, 1); 1119 str_list_destroy (opts); 1120 1121 if (flag_name) { 1122 *flag = ped_partition_flag_get_by_name (flag_name); 1123 ped_free (flag_name); 1124 return 1; 1125 } else 1126 return 0; 1127 } 1128 1129 static int 1130 _can_create_primary (const PedDisk* disk) 1131 { 1132 int i; 1133 1134 for (i = 1; i <= ped_disk_get_max_primary_partition_count (disk); i++) { 1135 if (!ped_disk_get_partition (disk, i)) 1136 return 1; 1137 } 1138 1139 return 0; 1140 } 1141 1142 static int 1143 _can_create_extended (const PedDisk* disk) 1144 { 1145 if (!_can_create_primary (disk)) 1146 return 0; 1147 1148 if (!ped_disk_type_check_feature (disk->type, PED_DISK_TYPE_EXTENDED)) 1149 return 0; 1150 1151 if (ped_disk_extended_partition (disk)) 1152 return 0; 1153 1154 return 1; 1155 } 1156 1157 static int 1158 _can_create_logical (const PedDisk* disk) 1159 { 1160 if (!ped_disk_type_check_feature (disk->type, PED_DISK_TYPE_EXTENDED)) 1161 return 0; 1162 1163 return ped_disk_extended_partition (disk) != 0; 1164 } 1165 1166 int 1167 command_line_get_part_type (const char* prompt, const PedDisk* disk, 1168 PedPartitionType* type) 1169 { 1170 StrList* opts = NULL; 1171 char* type_name; 1172 1173 if (_can_create_primary (disk)) { 1174 opts = str_list_append_unique (opts, "primary"); 1175 opts = str_list_append_unique (opts, _("primary")); 1176 } 1177 if (_can_create_extended (disk)) { 1178 opts = str_list_append_unique (opts, "extended"); 1179 opts = str_list_append_unique (opts, _("extended")); 1180 } 1181 if (_can_create_logical (disk)) { 1182 opts = str_list_append_unique (opts, "logical"); 1183 opts = str_list_append_unique (opts, _("logical")); 1184 } 1185 if (!opts) { 1186 ped_exception_throw ( 1187 PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, 1188 _("Can't create any more partitions.")); 1189 return 0; 1190 } 1191 1192 type_name = command_line_get_word (prompt, NULL, opts, 1); 1193 str_list_destroy (opts); 1194 1195 if (!type_name) { 1196 ped_exception_throw ( 1197 PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, 1198 _("Expecting a partition type.")); 1199 return 0; 1200 } 1201 1202 if (!strcmp (type_name, "primary") 1203 || !strcmp (type_name, _("primary"))) { 1204 *type = 0; 1205 } 1206 if (!strcmp (type_name, "extended") 1207 || !strcmp (type_name, _("extended"))) { 1208 *type = PED_PARTITION_EXTENDED; 1209 } 1210 if (!strcmp (type_name, "logical") 1211 || !strcmp (type_name, _("logical"))) { 1212 *type = PED_PARTITION_LOGICAL; 1213 } 1214 1215 free (type_name); 1216 return 1; 1217 } 1218 1219 PedExceptionOption 1220 command_line_get_ex_opt (const char* prompt, PedExceptionOption options) 1221 { 1222 StrList* options_strlist = NULL; 1223 PedExceptionOption opt; 1224 char* opt_name; 1225 1226 for (opt = option_get_next (options, 0); opt; 1227 opt = option_get_next (options, opt)) { 1228 options_strlist = str_list_append_unique (options_strlist, 1229 _(ped_exception_get_option_string (opt))); 1230 options_strlist = str_list_append_unique (options_strlist, 1231 ped_exception_get_option_string (opt)); 1232 } 1233 1234 opt_name = command_line_get_word (prompt, NULL, options_strlist, 1); 1235 if (!opt_name) 1236 return PED_EXCEPTION_UNHANDLED; 1237 str_list_destroy (options_strlist); 1238 1239 opt = PED_EXCEPTION_OPTION_FIRST; 1240 while (1) { 1241 if (strcmp (opt_name, 1242 ped_exception_get_option_string (opt)) == 0) 1243 break; 1244 if (strcmp (opt_name, 1245 _(ped_exception_get_option_string (opt))) == 0) 1246 break; 1247 opt = option_get_next (options, opt); 1248 } 1249 free (opt_name); 1250 return opt; 1251 } 1252 1253 int 1254 command_line_get_unit (const char* prompt, PedUnit* unit) 1255 { 1256 StrList* opts = NULL; 1257 PedUnit walk; 1258 char* unit_name; 1259 const char* default_unit_name; 1260 1261 for (walk = PED_UNIT_FIRST; walk <= PED_UNIT_LAST; walk++) 1262 opts = str_list_append (opts, ped_unit_get_name (walk)); 1263 1264 default_unit_name = ped_unit_get_name (ped_unit_get_default ()); 1265 unit_name = command_line_get_word (prompt, default_unit_name, opts, 1); 1266 str_list_destroy (opts); 1267 1268 if (unit_name) { 1269 *unit = ped_unit_get_by_name (unit_name); 1270 free (unit_name); 1271 return 1; 1272 } else 1273 return 0; 1274 } 1275 1276 int 1277 command_line_is_integer () 1278 { 1279 char* word; 1280 int is_integer; 1281 int scratch; 1282 1283 word = command_line_peek_word (); 1284 if (!word) 1285 return 0; 1286 1287 is_integer = sscanf (word, "%d", &scratch); 1288 free (word); 1289 return is_integer; 1290 } 1291 1292 static int 1293 init_ex_opt_str () 1294 { 1295 int i; 1296 PedExceptionOption opt; 1297 1298 for (i = 0; (1 << i) <= PED_EXCEPTION_OPTION_LAST; i++) { 1299 opt = (1 << i); 1300 ex_opt_str [i] 1301 = str_list_create ( 1302 ped_exception_get_option_string (opt), 1303 _(ped_exception_get_option_string (opt)), 1304 NULL); 1305 if (!ex_opt_str [i]) 1306 return 0; 1307 } 1308 1309 ex_opt_str [i] = NULL; 1310 return 1; 1311 } 1312 1313 static void 1314 done_ex_opt_str () 1315 { 1316 int i; 1317 1318 for (i=0; ex_opt_str [i]; i++) 1319 str_list_destroy (ex_opt_str [i]); 1320 } 1321 1322 static int 1323 init_state_str () 1324 { 1325 on_list = str_list_create_unique (_("on"), "on", NULL); 1326 off_list = str_list_create_unique (_("off"), "off", NULL); 1327 on_off_list = str_list_join (str_list_duplicate (on_list), 1328 str_list_duplicate (off_list)); 1329 return 1; 1330 } 1331 1332 static void 1333 done_state_str () 1334 { 1335 str_list_destroy (on_list); 1336 str_list_destroy (off_list); 1337 str_list_destroy (on_off_list); 1338 } 1339 1340 static int 1341 init_fs_type_str () 1342 { 1343 PedFileSystemType* walk; 1344 1345 fs_type_list = NULL; 1346 1347 for (walk = ped_file_system_type_get_next (NULL); walk; 1348 walk = ped_file_system_type_get_next (walk)) 1349 { 1350 fs_type_list = str_list_insert (fs_type_list, walk->name); 1351 if (!fs_type_list) 1352 return 0; 1353 } 1354 1355 return 1; 1356 } 1357 1358 static int 1359 init_disk_type_str () 1360 { 1361 PedDiskType* walk; 1362 1363 disk_type_list = NULL; 1364 1365 for (walk = ped_disk_type_get_next (NULL); walk; 1366 walk = ped_disk_type_get_next (walk)) 1367 { 1368 disk_type_list = str_list_insert (disk_type_list, walk->name); 1369 if (!disk_type_list) 1370 return 0; 1371 } 1372 1373 return 1; 1374 } 1375 1376 int 1377 init_ui () 1378 { 1379 if (!init_ex_opt_str () 1380 || !init_state_str () 1381 || !init_fs_type_str () 1382 || !init_disk_type_str ()) 1383 return 0; 1384 ped_exception_set_handler (exception_handler); 1385 1386 #ifdef HAVE_LIBREADLINE 1387 rl_initialize (); 1388 rl_attempted_completion_function = (CPPFunction*) complete_function; 1389 readline_state.in_readline = 0; 1390 #endif 1391 1392 #ifdef SA_SIGINFO 1393 sigset_t curr; 1394 sigfillset (&curr); 1395 1396 sig_segv.sa_sigaction = &sa_sigsegv_handler; 1397 sig_int.sa_sigaction = &sa_sigint_handler; 1398 sig_fpe.sa_sigaction = &sa_sigfpe_handler; 1399 sig_ill.sa_sigaction = &sa_sigill_handler; 1400 1401 sig_segv.sa_mask = 1402 sig_int.sa_mask = 1403 sig_fpe.sa_mask = 1404 sig_ill.sa_mask = curr; 1405 1406 sig_segv.sa_flags = 1407 sig_int.sa_flags = 1408 sig_fpe.sa_flags = 1409 sig_ill.sa_flags = SA_SIGINFO; 1410 1411 sigaction (SIGSEGV, &sig_segv, NULL); 1412 sigaction (SIGINT, &sig_int, NULL); 1413 sigaction (SIGFPE, &sig_fpe, NULL); 1414 sigaction (SIGILL, &sig_ill, NULL); 1415 #else 1416 signal (SIGSEGV, s_sigsegv_handler); 1417 signal (SIGINT, s_sigint_handler); 1418 signal (SIGFPE, s_sigfpe_handler); 1419 signal (SIGILL, s_sigill_handler); 1420 #endif /* SA_SIGINFO */ 1421 1422 return 1; 1423 } 1424 1425 void 1426 done_ui () 1427 { 1428 ped_exception_set_handler (NULL); 1429 done_ex_opt_str (); 1430 done_state_str (); 1431 str_list_destroy (fs_type_list); 1432 str_list_destroy (disk_type_list); 1433 } 1434 1435 void 1436 help_msg () 1437 { 1438 fputs (_(usage_msg), stdout); 1439 1440 putchar ('\n'); 1441 fputs (_("OPTIONs:"), stdout); 1442 putchar ('\n'); 1443 print_options_help (); 1444 1445 putchar ('\n'); 1446 fputs (_("COMMANDs:"), stdout); 1447 putchar ('\n'); 1448 print_commands_help (); 1449 exit (0); 1450 } 1451 1452 void 1453 print_using_dev (PedDevice* dev) 1454 { 1455 printf (_("Using %s\n"), dev->path); 1456 } 1457 1458 int 1459 interactive_mode (PedDevice** dev, Command* cmd_list[]) 1460 { 1461 StrList* list; 1462 StrList* command_names = command_get_names (cmd_list); 1463 1464 commands = cmd_list; /* FIXME yucky, nasty, evil hack */ 1465 1466 fputs (prog_name, stdout); 1467 1468 print_using_dev (*dev); 1469 1470 list = str_list_create (_(banner_msg), NULL); 1471 str_list_print_wrap (list, screen_width (), 0, 0); 1472 str_list_destroy (list); 1473 1474 while (1) { 1475 char* word; 1476 Command* cmd; 1477 1478 while (!command_line_get_word_count ()) { 1479 if (feof (stdin)) { 1480 putchar ('\n'); 1481 return 1; 1482 } 1483 command_line_prompt_words ("(parted)", NULL, 1484 command_names, 1); 1485 } 1486 1487 word = command_line_pop_word (); 1488 if (word) { 1489 cmd = command_get (commands, word); 1490 free (word); 1491 if (cmd) { 1492 if (!command_run (cmd, dev)) 1493 command_line_flush (); 1494 } else 1495 print_commands_help (); 1496 } 1497 } 1498 1499 return 1; 1500 } 1501 1502 1503 int 1504 non_interactive_mode (PedDevice** dev, Command* cmd_list[], 1505 int argc, char* argv[]) 1506 { 1507 int i; 1508 Command* cmd; 1509 1510 commands = cmd_list; /* FIXME yucky, nasty, evil hack */ 1511 1512 for (i = 0; i < argc; i++) 1513 command_line_push_line (argv [i], 1); 1514 1515 while (command_line_get_word_count ()) { 1516 char* word; 1517 1518 word = command_line_pop_word (); 1519 if (!word) 1520 break; 1521 1522 cmd = command_get (commands, word); 1523 free (word); 1524 if (!cmd) { 1525 help_msg (); 1526 goto error; 1527 } 1528 if (!(cmd->non_interactive)) { 1529 fputs(_("This command does not make sense in " 1530 "non-interactive mode.\n"), stdout); 1531 exit(1); 1532 goto error; 1533 } 1534 1535 if (!command_run (cmd, dev)) 1536 goto error; 1537 } 1538 return 1; 1539 1540 error: 1541 return 0; 1542 }