OSDN Git Service

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