ui.c revision 9663:ace9a2ac3683
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 50extern 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 69struct sigaction { 70}; 71 72static inline int 73sigaction (int signum, const struct* sigaction, struct* sigaction) 74{ 75} 76 77# endif /* HAVE_SIGACTON */ 78 79struct 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 157char* prog_name = "GNU Parted " VERSION "\n"; 158 159static char* banner_msg = N_( 160"Welcome to GNU Parted! Type 'help' to view a list of commands.\n"); 161 162static 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 167static 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 188static StrList* command_line; 189static Command** commands; 190static StrList* ex_opt_str [64]; 191static StrList* on_list; 192static StrList* off_list; 193static StrList* on_off_list; 194static StrList* fs_type_list; 195static StrList* disk_type_list; 196 197static struct { 198 const StrList* possibilities; 199 const StrList* cur_pos; 200 int in_readline; 201 sigjmp_buf jmp_state; 202} readline_state; 203 204static struct sigaction sig_segv; 205static struct sigaction sig_int; 206static struct sigaction sig_fpe; 207static struct sigaction sig_ill; 208 209volatile int got_ctrl_c = 0; /* used in exception_handler */ 210 211int 212screen_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 230void 231wipe_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 */ 243static char* 244command_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() */ 260char** 261complete_function (char* text, int start, int end) 262{ 263 return rl_completion_matches (text, 264 (rl_compentry_func_t*) command_generator); 265} 266 267static 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 */ 278static 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. */ 293static inline void 294_dump_history (void) 295{ 296} 297 298#endif /* HAVE_LIBREADLINE */ 299 300static void 301mask_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 */ 315static void 316reset_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'. */ 332static void 333sa_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'. */ 343static void 344s_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'. */ 352static void 353sa_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'. */ 387static void 388s_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'. */ 396static void 397sa_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'. */ 460static void 461s_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'. */ 469static void 470sa_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'. */ 532static void 533s_sigill_handler (int signum) 534{ 535 signal (SIGILL, &s_sigill_handler); 536 mask_signal (); 537 sa_sigill_handler (signum, NULL, NULL); 538} 539 540static 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 583static PedExceptionOption 584option_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 600static 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 620static PedExceptionOption 621exception_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 651void 652command_line_push_word (const char* word) 653{ 654 command_line = str_list_append (command_line, word); 655} 656 657char* 658command_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 673void 674command_line_flush () 675{ 676 str_list_destroy (command_line); 677 command_line = NULL; 678} 679 680char* 681command_line_peek_word () 682{ 683 if (command_line) 684 return str_list_convert_node (command_line); 685 else 686 return NULL; 687} 688 689int 690command_line_get_word_count () 691{ 692 return str_list_length (command_line); 693} 694 695static 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 */ 712void 713command_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 759static char* 760realloc_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 769static 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 814void 815command_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 */ 862char* 863command_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 893int 894command_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 910int 911command_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 951int 952command_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 973int 974command_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 993int 994command_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 1010int 1011command_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 1052int 1053command_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 1080int 1081command_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 1100int 1101command_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 1129static 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 1142static 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 1157static 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 1166int 1167command_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 1219PedExceptionOption 1220command_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 1253int 1254command_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 1276int 1277command_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 1292static int 1293init_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 1313static void 1314done_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 1322static int 1323init_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 1332static void 1333done_state_str () 1334{ 1335 str_list_destroy (on_list); 1336 str_list_destroy (off_list); 1337 str_list_destroy (on_off_list); 1338} 1339 1340static int 1341init_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 1358static int 1359init_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 1376int 1377init_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 1425void 1426done_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 1435void 1436help_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 1452void 1453print_using_dev (PedDevice* dev) 1454{ 1455 printf (_("Using %s\n"), dev->path); 1456} 1457 1458int 1459interactive_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 1503int 1504non_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 1540error: 1541 return 0; 1542} 1543