blob: fb311e2efce512fc898b93f61a0b88cb5e7f7489 [file] [log] [blame] [edit]
/*
parted - a frontend to libparted
Copyright (C) 1999, 2000, 2001, 2002, 2006, 2007
Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <parted/parted.h>
#include <parted/debug.h>
#include <ctype.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <setjmp.h>
#include <config.h>
#include "command.h"
#include "strlist.h"
#include "ui.h"
#define N_(String) String
#if ENABLE_NLS
# include <libintl.h>
# include <locale.h>
# define _(String) dgettext (PACKAGE, String)
#else
# define _(String) (String)
#endif /* ENABLE_NLS */
#ifdef HAVE_LIBREADLINE
#ifdef HAVE_TERMCAP_H
#include <termcap.h>
#else
extern int tgetnum (char* key);
#endif
#include <readline/readline.h>
#include <readline/history.h>
#ifndef HAVE_RL_COMPLETION_MATCHES
#define rl_completion_matches completion_matches
#endif
#ifndef rl_compentry_func_t
#define rl_compentry_func_t void
#endif
#endif /* HAVE_LIBREADLINE */
#ifndef SA_SIGINFO
# ifndef HAVE_SIGACTION
struct sigaction {
};
static inline int
sigaction (int signum, const struct* sigaction, struct* sigaction)
{
}
# endif /* HAVE_SIGACTON */
struct siginfo_t {
int si_code;
};
#endif /* SA_SIGINFO */
#ifndef SEGV_MAPERR
# define SEGV_MAPERR (INTMAX - 1)
#endif
#ifndef SEGV_ACCERR
# define SEGV_ACCERR (INTMAX - 2)
#endif
#ifndef FPE_INTDIV
# define FPE_INTDIV (INTMAX - 1)
#endif
#ifndef FPE_INTOVF
# define FPE_INTOVF (INTMAX - 2)
#endif
#ifndef FPE_FLTDIV
# define FPE_FLTDIV (INTMAX - 3)
#endif
#ifndef FPE_FLTOVF
# define FPE_FLTOVF (INTMAX - 4)
#endif
#ifndef FPE_FLTUND
# define FPE_FLTUND (INTMAX - 5)
#endif
#ifndef FPE_FLTRES
# define FPE_FLTRES (INTMAX - 6)
#endif
#ifndef FPE_FLTINV
# define FPE_FLTINV (INTMAX - 7)
#endif
#ifndef FPE_FLTSUB
# define FPE_FLTSUB (INTMAX - 8)
#endif
#ifndef ILL_ILLOPC
# define ILL_ILLOPC (INTMAX - 1)
#endif
#ifndef ILL_ILLOPN
# define ILL_ILLOPN (INTMAX - 2)
#endif
#ifndef ILL_ILLADR
# define ILL_ILLADR (INTMAX - 3)
#endif
#ifndef ILL_ILLTRP
# define ILL_ILLTRP (INTMAX - 4)
#endif
#ifndef ILL_PRVOPC
# define ILL_PRVOPC (INTMAX - 5)
#endif
#ifndef ILL_PRVREG
# define ILL_PRVREG (INTMAX - 6)
#endif
#ifndef ILL_COPROC
# define ILL_COPROC (INTMAX - 7)
#endif
#ifndef ILL_BADSTK
# define ILL_BADSTK (INTMAX - 8)
#endif
char* prog_name = "GNU Parted " VERSION "\n";
static char* banner_msg = N_(
"Welcome to GNU Parted! Type 'help' to view a list of commands.\n");
static char* usage_msg = N_(
"Usage: parted [OPTION]... [DEVICE [COMMAND [PARAMETERS]...]...]\n"
"Apply COMMANDs with PARAMETERS to DEVICE. If no COMMAND(s) are given, "
"run in\ninteractive mode.\n");
static char* bug_msg = N_(
"\n\nYou found a bug in GNU Parted! Here's what you have to do:\n\n"
"Don't panic! The bug has most likely not affected any of your data.\n"
"Help us to fix this bug by doing the following:\n\n"
"Check whether the bug has already been fixed by checking\n"
"the last version of GNU Parted that you can find at:\n\n"
"\thttp://ftp.gnu.org/gnu/parted/\n\n"
"Please check this version prior to bug reporting.\n\n"
"If this has not been fixed yet or if you don't know how to check,\n"
"please visit the GNU Parted website:\n\n"
"\thttp://www.gnu.org/software/parted\n\n"
"for further information.\n\n"
"Your report should contain the version of this release (%s)\n"
"along with the error message below, the output of\n\n"
"\tparted DEVICE unit co print unit s print\n\n"
"and the following history of commands you entered.\n"
"Also include any additional information about your setup you\n"
"consider important.\n");
#define MAX_WORDS 1024
static StrList* command_line;
static Command** commands;
static StrList* ex_opt_str [64];
static StrList* on_list;
static StrList* off_list;
static StrList* on_off_list;
static StrList* fs_type_list;
static StrList* disk_type_list;
static struct {
const StrList* possibilities;
const StrList* cur_pos;
int in_readline;
sigjmp_buf jmp_state;
} readline_state;
static struct sigaction sig_segv;
static struct sigaction sig_int;
static struct sigaction sig_fpe;
static struct sigaction sig_ill;
volatile int got_ctrl_c = 0; /* used in exception_handler */
int
screen_width ()
{
int width = 0;
if (opt_script_mode || pretend_input_tty)
return 32768; /* no wrapping ;) */
/* HACK: don't specify termcap separately - it'll annoy the users. */
#ifdef HAVE_LIBREADLINE
width = tgetnum ("co");
#endif
if (width <= 0)
width = 80;
return width;
}
void
wipe_line ()
{
if (opt_script_mode)
return;
/* yuck */
fputs ("\r "
" \r", stdout);
}
#ifdef HAVE_LIBREADLINE
/* returns matching commands for text */
static char*
command_generator (char* text, int state)
{
if (!state)
readline_state.cur_pos = readline_state.possibilities;
while (readline_state.cur_pos) {
const StrList* cur = readline_state.cur_pos;
readline_state.cur_pos = cur->next;
if (str_list_match_node (cur, text))
return str_list_convert_node (cur);
}
return NULL;
}
/* completion function for readline() */
char**
complete_function (char* text, int start, int end)
{
return rl_completion_matches (text,
(rl_compentry_func_t*) command_generator);
}
static void
_add_history_unique (const char* line)
{
HIST_ENTRY* last_entry = current_history ();
if (!strlen (line))
return;
if (!last_entry || strcmp (last_entry->line, line))
add_history ((char*) line);
}
/* Prints command history, to be used before aborting */
static void
_dump_history ()
{
int i = 0;
HIST_ENTRY** all_entries = history_list ();
fputs (_("\nCommand History:\n"), stdout);
while (all_entries[i]) {
puts(all_entries[i++]->line);
}
}
#else
/* Print nothing because Readline is absent. */
static inline void
_dump_history (void)
{
}
#endif /* HAVE_LIBREADLINE */
static void
mask_signal()
{
sigset_t curr;
sigset_t prev;
sigfillset(&curr);
sigprocmask(SIG_SETMASK, &curr, &prev);
}
/* Resets the environment by jumping to the initial state
* saved during ui intitialisation.
* Pass 1 as the parameter if you want to quit parted,
* 0 if you just want to reset to the command prompt.
*/
static void
reset_env (int quit)
{
int in_readline = readline_state.in_readline;
readline_state.in_readline = 0;
if (in_readline) {
putchar ('\n');
if (quit)
exit (0);
siglongjmp (readline_state.jmp_state, 1);
}
}
/* Signal handler for SIGINT using 'sigaction'. */
static void
sa_sigint_handler (int signum, siginfo_t* info, void *ucontext)
{
if (info)
sigaction (SIGINT, &sig_int, NULL);
got_ctrl_c = 1;
reset_env (0);
}
/* Signal handler for SIGINT using 'signal'. */
static void
s_sigint_handler (int signum)
{
signal (SIGINT, &s_sigint_handler);
mask_signal ();
sa_sigint_handler (signum, NULL, NULL);
}
/* Signal handler for SIGSEGV using 'sigaction'. */
static void
sa_sigsegv_handler (int signum, siginfo_t* info, void* ucontext)
{
printf (bug_msg, VERSION);
_dump_history ();
if (!info)
abort ();
sigaction (SIGSEGV, &sig_segv, NULL);
switch (info->si_code) {
case SEGV_MAPERR:
fputs(_("\nError: SEGV_MAPERR (Address not mapped "
"to object)\n"), stdout);
PED_ASSERT(0, break); /* Force a backtrace */
break;
case SEGV_ACCERR:
fputs(_("\nError: SEGV_ACCERR (Invalid permissions "
"for mapped object)\n"), stdout);
break;
default:
fputs(_("\nError: A general SIGSEGV signal was "
"encountered.\n"), stdout);
PED_ASSERT(0, break); /* Force a backtrace */
break;
}
abort ();
}
/* Signal handler for SIGSEGV using 'signal'. */
static void
s_sigsegv_handler (int signum)
{
signal (SIGSEGV, &s_sigsegv_handler);
mask_signal ();
sa_sigsegv_handler (signum, NULL, NULL);
}
/* Signal handler for SIGFPE using 'sigaction'. */
static void
sa_sigfpe_handler (int signum, siginfo_t* info, void* ucontext)
{
printf (bug_msg, VERSION);
_dump_history ();
if (!info)
abort ();
sigaction (SIGFPE, &sig_fpe, NULL);
switch (info->si_code) {
case FPE_INTDIV:
fputs(_("\nError: FPE_INTDIV (Integer: "
"divide by zero)"), stdout);
break;
case FPE_INTOVF:
fputs(_("\nError: FPE_INTOVF (Integer: "
"overflow)"), stdout);
break;
case FPE_FLTDIV:
fputs(_("\nError: FPE_FLTDIV (Float: "
"divide by zero)"), stdout);
break;
case FPE_FLTOVF:
fputs(_("\nError: FPE_FLTOVF (Float: "
"overflow)"), stdout);
break;
case FPE_FLTUND:
fputs(_("\nError: FPE_FLTUND (Float: "
"underflow)"), stdout);
break;
case FPE_FLTRES:
fputs(_("\nError: FPE_FLTRES (Float: "
"inexact result)"), stdout);
break;
case FPE_FLTINV:
fputs(_("\nError: FPE_FLTINV (Float: "
"invalid operation)"), stdout);
break;
case FPE_FLTSUB:
fputs(_("\nError: FPE_FLTSUB (Float: "
"subscript out of range)"), stdout);
break;
default:
fputs(_("\nError: A general SIGFPE signal "
"was encountered."), stdout);
break;
}
abort ();
}
/* Signal handler for SIGFPE using 'signal'. */
static void
s_sigfpe_handler (int signum)
{
signal (SIGFPE, &s_sigfpe_handler);
mask_signal ();
sa_sigfpe_handler (signum, NULL, NULL);
}
/* Signal handler for SIGILL using 'sigaction'. */
static void
sa_sigill_handler (int signum, siginfo_t* info, void* ucontext)
{
printf (bug_msg, VERSION);
_dump_history ();
if (!info)
abort();
sigaction (SIGILL, &sig_ill, NULL);
switch (info->si_code) {
case ILL_ILLOPC:
fputs(_("\nError: ILL_ILLOPC "
"(Illegal Opcode)"), stdout);
break;
case ILL_ILLOPN:
fputs(_("\nError: ILL_ILLOPN "
"(Illegal Operand)"), stdout);
break;
case ILL_ILLADR:
fputs(_("\nError: ILL_ILLADR "
"(Illegal addressing mode)"), stdout);
break;
case ILL_ILLTRP:
fputs(_("\nError: ILL_ILLTRP "
"(Illegal Trap)"), stdout);
break;
case ILL_PRVOPC:
fputs(_("\nError: ILL_PRVOPC "
"(Privileged Opcode)"), stdout);
break;
case ILL_PRVREG:
fputs(_("\nError: ILL_PRVREG "
"(Privileged Register)"), stdout);
break;
case ILL_COPROC:
fputs(_("\nError: ILL_COPROC "
"(Coprocessor Error)"), stdout);
break;
case ILL_BADSTK:
fputs(_("\nError: ILL_BADSTK "
"(Internal Stack Error)"), stdout);
break;
default:
fputs(_("\nError: A general SIGILL "
"signal was encountered."), stdout);
break;
}
abort ();
}
/* Signal handler for SIGILL using 'signal'. */
static void
s_sigill_handler (int signum)
{
signal (SIGILL, &s_sigill_handler);
mask_signal ();
sa_sigill_handler (signum, NULL, NULL);
}
static char*
_readline (const char* prompt, const StrList* possibilities)
{
char* line;
readline_state.possibilities = possibilities;
readline_state.cur_pos = NULL;
readline_state.in_readline = 1;
if (sigsetjmp (readline_state.jmp_state,1))
return NULL;
wipe_line ();
#ifdef HAVE_LIBREADLINE
if (!opt_script_mode) {
/* XXX: why isn't prompt const? */
line = readline ((char*) prompt);
if (line)
_add_history_unique (line);
} else
#endif
{
fputs (prompt, stdout);
fflush (stdout);
line = (char*) malloc (256);
if (fgets (line, 256, stdin) && strcmp (line, "") != 0)
line [strlen (line) - 1] = 0; /* kill trailing CR */
else {
free (line);
line = NULL;
}
}
readline_state.in_readline = 0;
return line;
}
static PedExceptionOption
option_get_next (PedExceptionOption options, PedExceptionOption current)
{
PedExceptionOption i;
if (current == 0)
i = PED_EXCEPTION_OPTION_FIRST;
else
i = current * 2;
for (; i <= options; i *= 2) {
if (options & i)
return i;
}
return 0;
}
static void
_print_exception_text (PedException* ex)
{
StrList* text;
wipe_line ();
if (ex->type == PED_EXCEPTION_BUG) {
printf (bug_msg, VERSION);
text = str_list_create ("\n", ex->message, "\n\n", NULL);
} else {
text = str_list_create (
_(ped_exception_get_type_string (ex->type)),
": ", ex->message, "\n", NULL);
}
str_list_print_wrap (text, screen_width (), 0, 0);
str_list_destroy (text);
}
static PedExceptionOption
exception_handler (PedException* ex)
{
PedExceptionOption opt;
_print_exception_text (ex);
/* only one choice? Take it ;-) */
opt = option_get_next (ex->options, 0);
if (!option_get_next (ex->options, opt))
return opt;
/* script-mode: don't handle the exception */
if (opt_script_mode || (!isatty (0) && !pretend_input_tty))
return PED_EXCEPTION_UNHANDLED;
got_ctrl_c = 0;
do {
opt = command_line_get_ex_opt ("", ex->options);
} while (opt == PED_EXCEPTION_UNHANDLED
&& (isatty (0) || pretend_input_tty) && !got_ctrl_c);
if (got_ctrl_c) {
got_ctrl_c = 0;
opt = PED_EXCEPTION_UNHANDLED;
}
return opt;
}
void
command_line_push_word (const char* word)
{
command_line = str_list_append (command_line, word);
}
char*
command_line_pop_word ()
{
char* result;
StrList* next;
PED_ASSERT (command_line != NULL, return NULL);
result = str_list_convert_node (command_line);
next = command_line->next;
str_list_destroy_node (command_line);
command_line = next;
return result;
}
void
command_line_flush ()
{
str_list_destroy (command_line);
command_line = NULL;
}
char*
command_line_peek_word ()
{
if (command_line)
return str_list_convert_node (command_line);
else
return NULL;
}
int
command_line_get_word_count ()
{
return str_list_length (command_line);
}
static int
_str_is_spaces (const char* str)
{
while (isspace (*str))
str++;
return *str == 0;
}
/* "multi_word mode" is the "normal" mode... many words can be typed,
* delimited by spaces, etc.
* In single-word mode, only one word is parsed per line.
* Leading and trailing spaces are removed. For example: " a b c "
* is a single word "a b c". The motivation for this mode is partition
* names, etc. In single-word mode, the empty string is a word.
* (but not in multi-word mode).
*/
void
command_line_push_line (const char* line, int multi_word)
{
int quoted = 0;
char quote_char = 0;
char this_word [256];
int i;
do {
while (*line == ' ')
line++;
i = 0;
for (; *line; line++) {
if (*line == ' ' && !quoted) {
if (multi_word)
break;
/* single word: check for trailing spaces + eol */
if (_str_is_spaces (line))
break;
}
if (!quoted && strchr ("'\"", *line)) {
quoted = 1;
quote_char = *line;
continue;
}
if (quoted && *line == quote_char) {
quoted = 0;
continue;
}
/* hack: escape characters */
if (quoted && line[0] == '\\' && line[1])
line++;
this_word [i++] = *line;
}
if (i || !multi_word) {
this_word [i] = 0;
command_line_push_word (this_word);
}
} while (*line && multi_word);
}
static char*
realloc_and_cat (char* str, const char* append)
{
int length = strlen (str) + strlen (append) + 1;
char* new_str = realloc (str, length);
strcat (new_str, append);
return new_str;
}
static char*
_construct_prompt (const char* head, const char* def,
const StrList* possibilities)
{
char* prompt = strdup (head);
if (def && possibilities)
PED_ASSERT (str_list_match_any (possibilities, def),
return NULL);
if (possibilities && str_list_length (possibilities) < 8) {
const StrList* walk;
if (strlen (prompt))
prompt = realloc_and_cat (prompt, " ");
for (walk = possibilities; walk; walk = walk->next) {
if (walk != possibilities)
prompt = realloc_and_cat (prompt, "/");
if (def && str_list_match_node (walk, def) == 2) {
prompt = realloc_and_cat (prompt, "[");
prompt = realloc_and_cat (prompt, def);
prompt = realloc_and_cat (prompt, "]");
} else {
char* text = str_list_convert_node (walk);
prompt = realloc_and_cat (prompt, text);
free (text);
}
}
prompt = realloc_and_cat (prompt, "? ");
} else if (def) {
if (strlen (prompt))
prompt = realloc_and_cat (prompt, " ");
prompt = realloc_and_cat (prompt, "[");
prompt = realloc_and_cat (prompt, def);
prompt = realloc_and_cat (prompt, "]? ");
} else {
if (strlen (prompt))
prompt = realloc_and_cat (prompt, " ");
}
return prompt;
}
void
command_line_prompt_words (const char* prompt, const char* def,
const StrList* possibilities, int multi_word)
{
char* line;
char* real_prompt;
char* _def = (char*) def;
int _def_needs_free = 0;
if (!def && str_list_length (possibilities) == 1) {
_def = str_list_convert_node (possibilities);
_def_needs_free = 1;
}
if (opt_script_mode) {
if (_def)
command_line_push_line (_def, 0);
return;
}
do {
real_prompt = _construct_prompt (prompt, _def, possibilities);
line = _readline (real_prompt, possibilities);
free (real_prompt);
if (!line)
break;
if (!strlen (line)) {
if (_def)
command_line_push_line (_def, 0);
} else {
command_line_push_line (line, multi_word);
}
free (line);
} while (!command_line_get_word_count () && !_def);
if (_def_needs_free)
free (_def);
}
/**
* Get a word from command line.
*
* \param possibilities a StrList of valid strings, NULL if all are valid.
* \param multi_word whether multiple words are allowed.
*
* \return The word(s), or NULL if empty.
*/
char*
command_line_get_word (const char* prompt, const char* def,
const StrList* possibilities, int multi_word)
{
do {
if (command_line_get_word_count ()) {
char* result = command_line_pop_word ();
StrList* result_node;
if (!possibilities)
return result;
result_node = str_list_match (possibilities, result);
free (result);
if (result_node)
return str_list_convert_node (result_node);
command_line_flush ();
}
command_line_prompt_words (prompt, def, possibilities,
multi_word);
} while (command_line_get_word_count ());
return NULL;
}
int
command_line_get_integer (const char* prompt, int* value)
{
char def_str [10];
char* input;
int valid;
snprintf (def_str, 10, "%d", *value);
input = command_line_get_word (prompt, *value ? def_str : NULL,
NULL, 1);
if (!input)
return 0;
valid = sscanf (input, "%d", value);
free (input);
return valid;
}
int
command_line_get_sector (const char* prompt, PedDevice* dev, PedSector* value,
PedGeometry** range)
{
char* def_str;
char* input;
int valid;
def_str = ped_unit_format (dev, *value);
input = command_line_get_word (prompt, *value ? def_str : NULL,
NULL, 1);
/* def_str might have rounded *value a little bit. If the user picked
* the default, make sure the selected sector is identical to the
* default.
*/
if (input && *value && !strcmp (input, def_str)) {
if (range) {
*range = ped_geometry_new (dev, *value, 1);
ped_free (def_str);
return *range != NULL;
}
ped_free (def_str);
return 1;
}
ped_free (def_str);
if (!input) {
*value = 0;
if (range)
*range = NULL;
return 0;
}
valid = ped_unit_parse (input, dev, value, range);
free (input);
return valid;
}
int
command_line_get_state (const char* prompt, int* value)
{
char* def_word;
char* input;
if (*value)
def_word = str_list_convert_node (on_list);
else
def_word = str_list_convert_node (off_list);
input = command_line_get_word (prompt, def_word, on_off_list, 1);
free (def_word);
if (!input)
return 0;
if (str_list_match_any (on_list, input))
*value = 1;
else
*value = 0;
free (input);
return 1;
}
int
command_line_get_device (const char* prompt, PedDevice** value)
{
char* def_dev_name = *value ? (*value)->path : NULL;
char* dev_name;
PedDevice* dev;
dev_name = command_line_get_word (prompt, def_dev_name, NULL, 1);
if (!dev_name)
return 0;
dev = ped_device_get (dev_name);
free (dev_name);
if (!dev)
return 0;
*value = dev;
return 1;
}
int
command_line_get_disk (const char* prompt, PedDisk** value)
{
PedDevice* dev = *value ? (*value)->dev : NULL;
if (!command_line_get_device (prompt, &dev))
return 0;
if (dev != (*value)->dev) {
PedDisk* new_disk = ped_disk_new (dev);
if (!new_disk)
return 0;
*value = new_disk;
}
return 1;
}
int
command_line_get_partition (const char* prompt, PedDisk* disk,
PedPartition** value)
{
PedPartition* part;
/* Flawed logic, doesn't seem to work?!
check = ped_disk_next_partition (disk, part);
part = ped_disk_next_partition (disk, check);
if (part == NULL) {
*value = check;
printf (_("The (only) primary partition has "
"been automatically selected\n"));
return 1;
} else {
*/
int num = (*value) ? (*value)->num : 0;
if (!command_line_get_integer (prompt, &num)) {
ped_exception_throw (PED_EXCEPTION_ERROR,
PED_EXCEPTION_CANCEL,
_("Expecting a partition number."));
return 0;
}
part = ped_disk_get_partition (disk, num);
if (!part) {
ped_exception_throw (PED_EXCEPTION_ERROR,
PED_EXCEPTION_CANCEL,
_("Partition doesn't exist."));
return 0;
}
*value = part;
return 1;
//}
}
int
command_line_get_fs_type (const char* prompt, const PedFileSystemType*(* value))
{
char* fs_type_name;
PedFileSystemType* fs_type;
fs_type_name = command_line_get_word (prompt,
*value ? (*value)->name : NULL,
fs_type_list, 1);
if (!fs_type_name) {
ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
_("Expecting a file system type."));
return 0;
}
fs_type = ped_file_system_type_get (fs_type_name);
if (!fs_type) {
ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
_("Unknown file system type \"%s\"."),
fs_type_name);
return 0;
}
free (fs_type_name);
*value = fs_type;
return 1;
}
int
command_line_get_disk_type (const char* prompt, const PedDiskType*(* value))
{
char* disk_type_name;
disk_type_name = command_line_get_word (prompt,
*value ? (*value)->name : NULL,
disk_type_list, 1);
if (!disk_type_name) {
ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
_("Expecting a disk label type."));
return 0;
}
*value = ped_disk_type_get (disk_type_name);
free (disk_type_name);
PED_ASSERT (*value != NULL, return 0);
return 1;
}
int
command_line_get_part_flag (const char* prompt, const PedPartition* part,
PedPartitionFlag* flag)
{
StrList* opts = NULL;
PedPartitionFlag walk = 0;
char* flag_name;
while ( (walk = ped_partition_flag_next (walk)) ) {
if (ped_partition_is_flag_available (part, walk)) {
const char* walk_name;
walk_name = ped_partition_flag_get_name (walk);
opts = str_list_append (opts, walk_name);
opts = str_list_append_unique (opts, _(walk_name));
}
}
flag_name = command_line_get_word (prompt, NULL, opts, 1);
str_list_destroy (opts);
if (flag_name) {
*flag = ped_partition_flag_get_by_name (flag_name);
ped_free (flag_name);
return 1;
} else
return 0;
}
static int
_can_create_primary (const PedDisk* disk)
{
int i;
for (i = 1; i <= ped_disk_get_max_primary_partition_count (disk); i++) {
if (!ped_disk_get_partition (disk, i))
return 1;
}
return 0;
}
static int
_can_create_extended (const PedDisk* disk)
{
if (!_can_create_primary (disk))
return 0;
if (!ped_disk_type_check_feature (disk->type, PED_DISK_TYPE_EXTENDED))
return 0;
if (ped_disk_extended_partition (disk))
return 0;
return 1;
}
static int
_can_create_logical (const PedDisk* disk)
{
if (!ped_disk_type_check_feature (disk->type, PED_DISK_TYPE_EXTENDED))
return 0;
return ped_disk_extended_partition (disk) != 0;
}
int
command_line_get_part_type (const char* prompt, const PedDisk* disk,
PedPartitionType* type)
{
StrList* opts = NULL;
char* type_name;
if (_can_create_primary (disk)) {
opts = str_list_append_unique (opts, "primary");
opts = str_list_append_unique (opts, _("primary"));
}
if (_can_create_extended (disk)) {
opts = str_list_append_unique (opts, "extended");
opts = str_list_append_unique (opts, _("extended"));
}
if (_can_create_logical (disk)) {
opts = str_list_append_unique (opts, "logical");
opts = str_list_append_unique (opts, _("logical"));
}
if (!opts) {
ped_exception_throw (
PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
_("Can't create any more partitions."));
return 0;
}
type_name = command_line_get_word (prompt, NULL, opts, 1);
str_list_destroy (opts);
if (!type_name) {
ped_exception_throw (
PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
_("Expecting a partition type."));
return 0;
}
if (!strcmp (type_name, "primary")
|| !strcmp (type_name, _("primary"))) {
*type = 0;
}
if (!strcmp (type_name, "extended")
|| !strcmp (type_name, _("extended"))) {
*type = PED_PARTITION_EXTENDED;
}
if (!strcmp (type_name, "logical")
|| !strcmp (type_name, _("logical"))) {
*type = PED_PARTITION_LOGICAL;
}
free (type_name);
return 1;
}
PedExceptionOption
command_line_get_ex_opt (const char* prompt, PedExceptionOption options)
{
StrList* options_strlist = NULL;
PedExceptionOption opt;
char* opt_name;
for (opt = option_get_next (options, 0); opt;
opt = option_get_next (options, opt)) {
options_strlist = str_list_append_unique (options_strlist,
_(ped_exception_get_option_string (opt)));
options_strlist = str_list_append_unique (options_strlist,
ped_exception_get_option_string (opt));
}
opt_name = command_line_get_word (prompt, NULL, options_strlist, 1);
if (!opt_name)
return PED_EXCEPTION_UNHANDLED;
str_list_destroy (options_strlist);
opt = PED_EXCEPTION_OPTION_FIRST;
while (1) {
if (strcmp (opt_name,
ped_exception_get_option_string (opt)) == 0)
break;
if (strcmp (opt_name,
_(ped_exception_get_option_string (opt))) == 0)
break;
opt = option_get_next (options, opt);
}
free (opt_name);
return opt;
}
int
command_line_get_unit (const char* prompt, PedUnit* unit)
{
StrList* opts = NULL;
PedUnit walk;
char* unit_name;
const char* default_unit_name;
for (walk = PED_UNIT_FIRST; walk <= PED_UNIT_LAST; walk++)
opts = str_list_append (opts, ped_unit_get_name (walk));
default_unit_name = ped_unit_get_name (ped_unit_get_default ());
unit_name = command_line_get_word (prompt, default_unit_name, opts, 1);
str_list_destroy (opts);
if (unit_name) {
*unit = ped_unit_get_by_name (unit_name);
free (unit_name);
return 1;
} else
return 0;
}
int
command_line_is_integer ()
{
char* word;
int is_integer;
int scratch;
word = command_line_peek_word ();
if (!word)
return 0;
is_integer = sscanf (word, "%d", &scratch);
free (word);
return is_integer;
}
static int
init_ex_opt_str ()
{
int i;
PedExceptionOption opt;
for (i = 0; (1 << i) <= PED_EXCEPTION_OPTION_LAST; i++) {
opt = (1 << i);
ex_opt_str [i]
= str_list_create (
ped_exception_get_option_string (opt),
_(ped_exception_get_option_string (opt)),
NULL);
if (!ex_opt_str [i])
return 0;
}
ex_opt_str [i] = NULL;
return 1;
}
static void
done_ex_opt_str ()
{
int i;
for (i=0; ex_opt_str [i]; i++)
str_list_destroy (ex_opt_str [i]);
}
static int
init_state_str ()
{
on_list = str_list_create_unique (_("on"), "on", NULL);
off_list = str_list_create_unique (_("off"), "off", NULL);
on_off_list = str_list_join (str_list_duplicate (on_list),
str_list_duplicate (off_list));
return 1;
}
static void
done_state_str ()
{
str_list_destroy (on_list);
str_list_destroy (off_list);
str_list_destroy (on_off_list);
}
static int
init_fs_type_str ()
{
PedFileSystemType* walk;
fs_type_list = NULL;
for (walk = ped_file_system_type_get_next (NULL); walk;
walk = ped_file_system_type_get_next (walk))
{
fs_type_list = str_list_insert (fs_type_list, walk->name);
if (!fs_type_list)
return 0;
}
return 1;
}
static int
init_disk_type_str ()
{
PedDiskType* walk;
disk_type_list = NULL;
for (walk = ped_disk_type_get_next (NULL); walk;
walk = ped_disk_type_get_next (walk))
{
disk_type_list = str_list_insert (disk_type_list, walk->name);
if (!disk_type_list)
return 0;
}
return 1;
}
int
init_ui ()
{
if (!init_ex_opt_str ()
|| !init_state_str ()
|| !init_fs_type_str ()
|| !init_disk_type_str ())
return 0;
ped_exception_set_handler (exception_handler);
#ifdef HAVE_LIBREADLINE
rl_initialize ();
rl_attempted_completion_function = (CPPFunction*) complete_function;
readline_state.in_readline = 0;
#endif
#ifdef SA_SIGINFO
sigset_t curr;
sigfillset (&curr);
sig_segv.sa_sigaction = &sa_sigsegv_handler;
sig_int.sa_sigaction = &sa_sigint_handler;
sig_fpe.sa_sigaction = &sa_sigfpe_handler;
sig_ill.sa_sigaction = &sa_sigill_handler;
sig_segv.sa_mask =
sig_int.sa_mask =
sig_fpe.sa_mask =
sig_ill.sa_mask = curr;
sig_segv.sa_flags =
sig_int.sa_flags =
sig_fpe.sa_flags =
sig_ill.sa_flags = SA_SIGINFO;
sigaction (SIGSEGV, &sig_segv, NULL);
sigaction (SIGINT, &sig_int, NULL);
sigaction (SIGFPE, &sig_fpe, NULL);
sigaction (SIGILL, &sig_ill, NULL);
#else
signal (SIGSEGV, s_sigsegv_handler);
signal (SIGINT, s_sigint_handler);
signal (SIGFPE, s_sigfpe_handler);
signal (SIGILL, s_sigill_handler);
#endif /* SA_SIGINFO */
return 1;
}
void
done_ui ()
{
ped_exception_set_handler (NULL);
done_ex_opt_str ();
done_state_str ();
str_list_destroy (fs_type_list);
str_list_destroy (disk_type_list);
}
void
help_msg ()
{
fputs (_(usage_msg), stdout);
putchar ('\n');
fputs (_("OPTIONs:"), stdout);
putchar ('\n');
print_options_help ();
putchar ('\n');
fputs (_("COMMANDs:"), stdout);
putchar ('\n');
print_commands_help ();
exit (0);
}
void
print_using_dev (PedDevice* dev)
{
printf (_("Using %s\n"), dev->path);
}
int
interactive_mode (PedDevice** dev, Command* cmd_list[])
{
StrList* list;
StrList* command_names = command_get_names (cmd_list);
commands = cmd_list; /* FIXME yucky, nasty, evil hack */
fputs (prog_name, stdout);
print_using_dev (*dev);
list = str_list_create (_(banner_msg), NULL);
str_list_print_wrap (list, screen_width (), 0, 0);
str_list_destroy (list);
while (1) {
char* word;
Command* cmd;
while (!command_line_get_word_count ()) {
if (feof (stdin)) {
putchar ('\n');
return 1;
}
command_line_prompt_words ("(parted)", NULL,
command_names, 1);
}
word = command_line_pop_word ();
if (word) {
cmd = command_get (commands, word);
free (word);
if (cmd) {
if (!command_run (cmd, dev))
command_line_flush ();
} else
print_commands_help ();
}
}
return 1;
}
int
non_interactive_mode (PedDevice** dev, Command* cmd_list[],
int argc, char* argv[])
{
int i;
Command* cmd;
commands = cmd_list; /* FIXME yucky, nasty, evil hack */
for (i = 0; i < argc; i++)
command_line_push_line (argv [i], 1);
while (command_line_get_word_count ()) {
char* word;
word = command_line_pop_word ();
if (!word)
break;
cmd = command_get (commands, word);
free (word);
if (!cmd) {
help_msg ();
goto error;
}
if (!(cmd->non_interactive)) {
fputs(_("This command does not make sense in "
"non-interactive mode.\n"), stdout);
exit(1);
goto error;
}
if (!command_run (cmd, dev))
goto error;
}
return 1;
error:
return 0;
}