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