xref: /onnv-gate/usr/src/cmd/parted/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
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
sigaction(int signum,const struct * sigaction,struct * sigaction)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
screen_width()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
wipe_line()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*
command_generator(char * text,int state)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**
complete_function(char * text,int start,int end)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
_add_history_unique(const char * line)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
_dump_history()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
_dump_history(void)294 _dump_history (void)
295 {
296 }
297 
298 #endif /* HAVE_LIBREADLINE */
299 
300 static void
mask_signal()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
reset_env(int quit)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
sa_sigint_handler(int signum,siginfo_t * info,void * ucontext)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
s_sigint_handler(int signum)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
sa_sigsegv_handler(int signum,siginfo_t * info,void * ucontext)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
s_sigsegv_handler(int signum)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
sa_sigfpe_handler(int signum,siginfo_t * info,void * ucontext)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
s_sigfpe_handler(int signum)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
sa_sigill_handler(int signum,siginfo_t * info,void * ucontext)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
s_sigill_handler(int signum)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*
_readline(const char * prompt,const StrList * possibilities)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
option_get_next(PedExceptionOption options,PedExceptionOption current)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
_print_exception_text(PedException * ex)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
exception_handler(PedException * ex)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
command_line_push_word(const char * word)652 command_line_push_word (const char* word)
653 {
654         command_line = str_list_append (command_line, word);
655 }
656 
657 char*
command_line_pop_word()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
command_line_flush()674 command_line_flush ()
675 {
676         str_list_destroy (command_line);
677         command_line = NULL;
678 }
679 
680 char*
command_line_peek_word()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
command_line_get_word_count()690 command_line_get_word_count ()
691 {
692         return str_list_length (command_line);
693 }
694 
695 static int
_str_is_spaces(const char * str)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
command_line_push_line(const char * line,int multi_word)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*
realloc_and_cat(char * str,const char * append)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*
_construct_prompt(const char * head,const char * def,const StrList * possibilities)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
command_line_prompt_words(const char * prompt,const char * def,const StrList * possibilities,int multi_word)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*
command_line_get_word(const char * prompt,const char * def,const StrList * possibilities,int multi_word)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
command_line_get_integer(const char * prompt,int * value)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
command_line_get_sector(const char * prompt,PedDevice * dev,PedSector * value,PedGeometry ** range)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
command_line_get_state(const char * prompt,int * value)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
command_line_get_device(const char * prompt,PedDevice ** value)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
command_line_get_disk(const char * prompt,PedDisk ** value)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
command_line_get_partition(const char * prompt,PedDisk * disk,PedPartition ** value)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
command_line_get_fs_type(const char * prompt,const PedFileSystemType * (* value))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
command_line_get_disk_type(const char * prompt,const PedDiskType * (* value))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
command_line_get_part_flag(const char * prompt,const PedPartition * part,PedPartitionFlag * flag)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
_can_create_primary(const PedDisk * disk)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
_can_create_extended(const PedDisk * disk)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
_can_create_logical(const PedDisk * disk)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
command_line_get_part_type(const char * prompt,const PedDisk * disk,PedPartitionType * type)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
command_line_get_ex_opt(const char * prompt,PedExceptionOption options)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
command_line_get_unit(const char * prompt,PedUnit * unit)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
command_line_is_integer()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
init_ex_opt_str()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
done_ex_opt_str()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
init_state_str()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
done_state_str()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
init_fs_type_str()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
init_disk_type_str()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
init_ui()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
done_ui()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
help_msg()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
print_using_dev(PedDevice * dev)1453 print_using_dev (PedDevice* dev)
1454 {
1455         printf (_("Using %s\n"), dev->path);
1456 }
1457 
1458 int
interactive_mode(PedDevice ** dev,Command * cmd_list[])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
non_interactive_mode(PedDevice ** dev,Command * cmd_list[],int argc,char * argv[])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 }
1543