#include <guestfs.h>
#include "fish.h"
+#include "options.h"
+
#include "c-ctype.h"
#include "closeout.h"
#include "progname.h"
-/* List of drives added via -a, -d or -N options. */
-struct drv {
- struct drv *next;
- enum { drv_a, drv_d, drv_N } type;
- union {
- struct {
- char *filename; /* disk filename */
- } a;
- struct {
- char *guest; /* guest name */
- } d;
- struct {
- char *filename; /* disk filename (testX.img) */
- prep_data *data; /* prepared type */
- char *device; /* device inside the appliance */
- } N;
- };
-};
-
-struct mp {
- struct mp *next;
- char *device;
- char *mountpoint;
-};
-
static void set_up_terminal (void);
-static char add_drives (struct drv *drv, char next_drive);
static void prepare_drives (struct drv *drv);
-static void mount_mps (struct mp *mp);
static int launch (void);
static void interactive (void);
static void shell_script (void);
int exit_on_error = 1;
int command_num = 0;
int keys_from_stdin = 0;
+int echo_keys = 0;
const char *libvirt_uri = NULL;
int inspector = 0;
int utf8_mode = 0;
" -c|--connect uri Specify libvirt URI for -d option\n"
" -d|--domain guest Add disks from libvirt guest\n"
" -D|--no-dest-paths Don't tab-complete paths from guest fs\n"
+ " --echo-keys Don't turn off echo for passphrases\n"
" -f|--file file Read commands from file\n"
+ " --format[=raw|..] Force disk format for -a option\n"
" -i|--inspector Automatically mount filesystems\n"
" --keys-from-stdin Read passphrases from stdin\n"
" --listen Listen for remote commands\n"
" -r|--ro Mount read-only\n"
" --selinux Enable SELinux support\n"
" -v|--verbose Verbose messages\n"
- " -x Echo each command before executing it\n"
" -V|--version Display version and exit\n"
+ " -x Echo each command before executing it\n"
"For more information, see the manpage %s(1).\n"),
program_name, program_name, program_name,
program_name, program_name, program_name,
{ "cmd-help", 2, 0, 'h' },
{ "connect", 1, 0, 'c' },
{ "domain", 1, 0, 'd' },
+ { "echo-keys", 0, 0, 0 },
{ "file", 1, 0, 'f' },
+ { "format", 2, 0, 0 },
{ "help", 0, 0, HELP_OPTION },
{ "inspector", 0, 0, 'i' },
{ "keys-from-stdin", 0, 0, 0 },
struct mp *mps = NULL;
struct mp *mp;
char *p, *file = NULL;
+ const char *format = NULL;
int c;
int option_index;
struct sigaction sa;
exit (EXIT_FAILURE);
}
- guestfs_set_autosync (g, 1);
-
/* If developing, add ./appliance to the path. Note that libtools
* interferes with this because uninstalled guestfish is a shell
* script that runs the real program with an absolute path. Detect
override_progress_bars = 1;
} else if (STREQ (long_options[option_index].name, "no-progress-bars")) {
override_progress_bars = 0;
+ } else if (STREQ (long_options[option_index].name, "echo-keys")) {
+ echo_keys = 1;
+ } else if (STREQ (long_options[option_index].name, "format")) {
+ if (!optarg || STREQ (optarg, ""))
+ format = NULL;
+ else
+ format = optarg;
} else {
fprintf (stderr, _("%s: unknown long option: %s (%d)\n"),
program_name, long_options[option_index].name, option_index);
break;
case 'a':
- if (access (optarg, R_OK) != 0) {
- perror (optarg);
- exit (EXIT_FAILURE);
- }
- drv = malloc (sizeof (struct drv));
- if (!drv) {
- perror ("malloc");
- exit (EXIT_FAILURE);
- }
- drv->type = drv_a;
- drv->a.filename = optarg;
- drv->next = drvs;
- drvs = drv;
+ OPTION_a;
break;
case 'c':
- libvirt_uri = optarg;
+ OPTION_c;
break;
case 'd':
- drv = malloc (sizeof (struct drv));
- if (!drv) {
- perror ("malloc");
- exit (EXIT_FAILURE);
- }
- drv->type = drv_d;
- drv->d.guest = optarg;
- drv->next = drvs;
- drvs = drv;
- break;
-
- case 'N':
- if (STRCASEEQ (optarg, "list") ||
- STRCASEEQ (optarg, "help") ||
- STRCASEEQ (optarg, "h") ||
- STRCASEEQ (optarg, "?")) {
- list_prepared_drives ();
- exit (EXIT_SUCCESS);
- }
- drv = malloc (sizeof (struct drv));
- if (!drv) {
- perror ("malloc");
- exit (EXIT_FAILURE);
- }
- drv->type = drv_N;
- if (asprintf (&drv->N.filename, "test%d.img",
- next_prepared_drive++) == -1) {
- perror ("asprintf");
- exit (EXIT_FAILURE);
- }
- drv->N.data = create_prepared_file (optarg, drv->N.filename);
- drv->N.device = NULL; /* filled in by add_drives */
- drv->next = drvs;
- drvs = drv;
+ OPTION_d;
break;
case 'D':
}
case 'i':
- inspector = 1;
+ OPTION_i;
break;
case 'm':
- mp = malloc (sizeof (struct mp));
- if (!mp) {
- perror ("malloc");
- exit (EXIT_FAILURE);
- }
- p = strchr (optarg, ':');
- if (p) {
- *p = '\0';
- mp->mountpoint = p+1;
- } else
- mp->mountpoint = bad_cast ("/");
- mp->device = optarg;
- mp->next = mps;
- mps = mp;
+ OPTION_m;
break;
case 'n':
- guestfs_set_autosync (g, 0);
+ OPTION_n;
+ break;
+
+ case 'N':
+ if (STRCASEEQ (optarg, "list") ||
+ STRCASEEQ (optarg, "help") ||
+ STRCASEEQ (optarg, "h") ||
+ STRCASEEQ (optarg, "?")) {
+ list_prepared_drives ();
+ exit (EXIT_SUCCESS);
+ }
+ drv = malloc (sizeof (struct drv));
+ if (!drv) {
+ perror ("malloc");
+ exit (EXIT_FAILURE);
+ }
+ drv->type = drv_N;
+ if (asprintf (&drv->N.filename, "test%d.img",
+ next_prepared_drive++) == -1) {
+ perror ("asprintf");
+ exit (EXIT_FAILURE);
+ }
+ drv->N.data = create_prepared_file (optarg, drv->N.filename);
+ drv->N.data_free = free_prep_data;
+ drv->N.device = NULL; /* filled in by add_drives */
+ drv->next = drvs;
+ drvs = drv;
break;
case 'r':
- read_only = 1;
+ OPTION_r;
break;
case 'v':
- verbose++;
- guestfs_set_verbose (g, verbose);
+ OPTION_v;
break;
- case 'V': {
- struct guestfs_version *v = guestfs_version (g);
- printf ("%s %"PRIi64".%"PRIi64".%"PRIi64"%s\n", program_name,
- v->major, v->minor, v->release, v->extra);
- exit (EXIT_SUCCESS);
- }
+ case 'V':
+ OPTION_V;
+ break;
case 'x':
- guestfs_set_trace (g, 1);
+ OPTION_x;
break;
case HELP_OPTION:
}
drv->type = drv_a;
drv->a.filename = argv[optind];
+ drv->a.format = NULL;
drv->next = drvs;
drvs = drv;
} else { /* simulate -d option */
mount_mps (mps);
}
+ /* Free up data structures, no longer needed after this point. */
+ free_drives (drvs);
+ free_mps (mps);
+
/* Remote control? */
if (remote_control_listen && remote_control) {
fprintf (stderr,
pclose (fp);
}
-/* List is built in reverse order, so mount them in reverse order. */
-static void
-mount_mps (struct mp *mp)
-{
- int r;
-
- if (mp) {
- mount_mps (mp->next);
-
- /* Don't use guestfs_mount here because that will default to mount
- * options -o sync,noatime. For more information, see guestfs(3)
- * section "LIBGUESTFS GOTCHAS".
- */
- const char *options = read_only ? "ro" : "";
- r = guestfs_mount_options (g, options, mp->device, mp->mountpoint);
- if (r == -1) {
- /* Display possible mountpoints before exiting. */
- char **fses = guestfs_list_filesystems (g);
- if (fses == NULL || fses[0] == NULL)
- goto out;
- fprintf (stderr,
- _("guestfish: '%s' could not be mounted. Did you mean one of these?\n"),
- mp->device);
- size_t i;
- for (i = 0; fses[i] != NULL; i += 2)
- fprintf (stderr, "\t%s (%s)\n", fses[i], fses[i+1]);
-
- out:
- exit (EXIT_FAILURE);
- }
- }
-}
-
-static char
-add_drives (struct drv *drv, char next_drive)
-{
- int r;
-
- if (next_drive > 'z') {
- fprintf (stderr,
- _("guestfish: too many drives added on the command line\n"));
- exit (EXIT_FAILURE);
- }
-
- if (drv) {
- next_drive = add_drives (drv->next, next_drive);
-
- switch (drv->type) {
- case drv_a:
- if (!read_only)
- r = guestfs_add_drive (g, drv->a.filename);
- else
- r = guestfs_add_drive_ro (g, drv->a.filename);
- if (r == -1)
- exit (EXIT_FAILURE);
-
- next_drive++;
- break;
-
- case drv_d:
- r = add_libvirt_drives (drv->d.guest);
- if (r == -1)
- exit (EXIT_FAILURE);
-
- next_drive += r;
- break;
-
- case drv_N:
- /* -N option is not affected by --ro */
- r = guestfs_add_drive (g, drv->N.filename);
- if (r == -1)
- exit (EXIT_FAILURE);
-
- if (asprintf (&drv->N.device, "/dev/sd%c", next_drive) == -1) {
- perror ("asprintf");
- exit (EXIT_FAILURE);
- }
-
- next_drive++;
- break;
-
- default: /* keep GCC happy */
- abort ();
- }
- }
-
- return next_drive;
-}
-
static void
prepare_drives (struct drv *drv)
{
quit = 1;
r = 0;
}
- else if (STRCASEEQ (cmd, "alloc") ||
- STRCASEEQ (cmd, "allocate"))
- r = do_alloc (cmd, argc, argv);
- else if (STRCASEEQ (cmd, "copy-in") ||
- STRCASEEQ (cmd, "copy_in"))
- r = do_copy_in (cmd, argc, argv);
- else if (STRCASEEQ (cmd, "copy-out") ||
- STRCASEEQ (cmd, "copy_out"))
- r = do_copy_out (cmd, argc, argv);
- else if (STRCASEEQ (cmd, "echo"))
- r = do_echo (cmd, argc, argv);
- else if (STRCASEEQ (cmd, "edit") ||
- STRCASEEQ (cmd, "vi") ||
- STRCASEEQ (cmd, "emacs"))
- r = do_edit (cmd, argc, argv);
- else if (STRCASEEQ (cmd, "lcd"))
- r = do_lcd (cmd, argc, argv);
- else if (STRCASEEQ (cmd, "glob"))
- r = do_glob (cmd, argc, argv);
- else if (STRCASEEQ (cmd, "man") ||
- STRCASEEQ (cmd, "manual"))
- r = do_man (cmd, argc, argv);
- else if (STRCASEEQ (cmd, "more") ||
- STRCASEEQ (cmd, "less"))
- r = do_more (cmd, argc, argv);
- else if (STRCASEEQ (cmd, "reopen"))
- r = do_reopen (cmd, argc, argv);
- else if (STRCASEEQ (cmd, "sparse"))
- r = do_sparse (cmd, argc, argv);
- else if (STRCASEEQ (cmd, "supported"))
- r = do_supported (cmd, argc, argv);
- else if (STRCASEEQ (cmd, "time"))
- r = do_time (cmd, argc, argv);
else
r = run_action (cmd, argc, argv);
void
list_builtin_commands (void)
{
- /* help, man and quit should appear at the top */
+ /* help and quit should appear at the top */
printf ("%-20s %s\n",
"help", _("display a list of commands or help on a command"));
printf ("%-20s %s\n",
- "man", _("read the manual"));
- printf ("%-20s %s\n",
"quit", _("quit guestfish"));
- printf ("%-20s %s\n",
- "alloc", _("allocate an image"));
- printf ("%-20s %s\n",
- "copy-in", _("copy files into an image"));
- printf ("%-20s %s\n",
- "copy-out", _("copy files out of an image"));
- printf ("%-20s %s\n",
- "echo", _("display a line of text"));
- printf ("%-20s %s\n",
- "edit", _("edit a file in the image"));
- printf ("%-20s %s\n",
- "lcd", _("local change directory"));
- printf ("%-20s %s\n",
- "glob", _("expand wildcards in command"));
- printf ("%-20s %s\n",
- "more", _("view a file in the pager"));
- printf ("%-20s %s\n",
- "reopen", _("close and reopen libguestfs handle"));
- printf ("%-20s %s\n",
- "sparse", _("allocate a sparse image file"));
- printf ("%-20s %s\n",
- "supported", _("list supported groups of commands"));
- printf ("%-20s %s\n",
- "time", _("measure time taken to run command"));
-
/* actions are printed after this (see list_commands) */
}
{
/* help for actions is auto-generated, see display_command */
- if (STRCASEEQ (cmd, "alloc") ||
- STRCASEEQ (cmd, "allocate")) {
- printf (_("alloc - allocate an image\n"
- " alloc <filename> <size>\n"
- "\n"
- " This creates an empty (zeroed) file of the given size,\n"
- " and then adds so it can be further examined.\n"
- "\n"
- " For more advanced image creation, see qemu-img utility.\n"
- "\n"
- " Size can be specified using standard suffixes, eg. '1M'.\n"
- ));
- return 0;
- }
- else if (STRCASEEQ (cmd, "copy-in") ||
- STRCASEEQ (cmd, "copy_in")) {
- printf (_("copy-in - copy files into an image\n"
- " copy-in <local> [<local> ...] <remotedir>\n"
- "\n"
- " Copy local files or directories recursively into the\n"
- " image, placing them on a remote directory.\n"
- ));
- return 0;
- }
- else if (STRCASEEQ (cmd, "copy-out") ||
- STRCASEEQ (cmd, "copy_out")) {
- printf (_("copy-out - copy files out of an image\n"
- " copy-out <remote> [<remote> ...] <localdir>\n"
- "\n"
- " Copy remote files or directories recursively out of the\n"
- " image, placing them in a local directory.\n"
- ));
- return 0;
- }
- else if (STRCASEEQ (cmd, "echo")) {
- printf (_("echo - display a line of text\n"
- " echo [<params> ...]\n"
- "\n"
- " This echos the parameters to the terminal.\n"));
- return 0;
- }
- else if (STRCASEEQ (cmd, "edit") ||
- STRCASEEQ (cmd, "vi") ||
- STRCASEEQ (cmd, "emacs")) {
- printf (_("edit - edit a file in the image\n"
- " edit <filename>\n"
- "\n"
- " This is used to edit a file.\n"
- "\n"
- " It is the equivalent of (and is implemented by)\n"
- " running \"cat\", editing locally, and then \"write\".\n"
- "\n"
- " Normally it uses $EDITOR, but if you use the aliases\n"
- " \"vi\" or \"emacs\" you will get those editors.\n"
- "\n"
- " NOTE: This will not work reliably for large files\n"
- " (> 2 MB) or binary files containing \\0 bytes.\n"));
- return 0;
- }
- else if (STRCASEEQ (cmd, "lcd")) {
- printf (_("lcd - local change directory\n"
- " lcd <directory>\n"
- "\n"
- " Change guestfish's current directory. This command is\n"
- " useful if you want to download files to a particular\n"
- " place.\n"));
- return 0;
- }
- else if (STRCASEEQ (cmd, "glob")) {
- printf (_("glob - expand wildcards in command\n"
- " glob <command> [<args> ...]\n"
- "\n"
- " Glob runs <command> with wildcards expanded in any\n"
- " command args. Note that the command is run repeatedly\n"
- " once for each expanded argument.\n"));
- return 0;
- }
- else if (STRCASEEQ (cmd, "man") ||
- STRCASEEQ (cmd, "manual")) {
- printf (_("man - read the manual\n"
- " man\n"
- "\n"
- " Opens the manual page for guestfish.\n"));
- return 0;
- }
- else if (STRCASEEQ (cmd, "help")) {
+ if (STRCASEEQ (cmd, "help")) {
printf (_("help - display a list of commands or help on a command\n"
" help cmd\n"
" help\n"));
return 0;
}
- else if (STRCASEEQ (cmd, "more") ||
- STRCASEEQ (cmd, "less")) {
- printf (_("more - view a file in the pager\n"
- " more <filename>\n"
- "\n"
- " This is used to view a file in the pager.\n"
- "\n"
- " It is the equivalent of (and is implemented by)\n"
- " running \"cat\" and using the pager.\n"
- "\n"
- " Normally it uses $PAGER, but if you use the alias\n"
- " \"less\" then it always uses \"less\".\n"
- "\n"
- " NOTE: This will not work reliably for large files\n"
- " (> 2 MB) or binary files containing \\0 bytes.\n"));
- return 0;
- }
else if (STRCASEEQ (cmd, "quit") ||
STRCASEEQ (cmd, "exit") ||
STRCASEEQ (cmd, "q")) {
" quit\n"));
return 0;
}
- else if (STRCASEEQ (cmd, "reopen")) {
- printf (_("reopen - close and reopen the libguestfs handle\n"
- " reopen\n"
- "\n"
- "Close and reopen the libguestfs handle. It is not necessary to use\n"
- "this normally, because the handle is closed properly when guestfish\n"
- "exits. However this is occasionally useful for testing.\n"));
- return 0;
- }
- else if (STRCASEEQ (cmd, "sparse")) {
- printf (_("sparse - allocate a sparse image file\n"
- " sparse <filename> <size>\n"
- "\n"
- " This creates an empty sparse file of the given size,\n"
- " and then adds so it can be further examined.\n"
- "\n"
- " In all respects it works the same as the 'alloc'\n"
- " command, except that the image file is allocated\n"
- " sparsely, which means that disk blocks are not assigned\n"
- " to the file until they are needed. Sparse disk files\n"
- " only use space when written to, but they are slower\n"
- " and there is a danger you could run out of real disk\n"
- " space during a write operation.\n"
- "\n"
- " For more advanced image creation, see qemu-img utility.\n"
- "\n"
- " Size can be specified using standard suffixes, eg. '1M'.\n"
- ));
- return 0;
- }
- else if (STRCASEEQ (cmd, "supported")) {
- printf (_("supported - list supported groups of commands\n"
- " supported\n"
- "\n"
- " This command returns a list of the optional groups\n"
- " known to the daemon, and indicates which ones are\n"
- " supported by this build of the libguestfs appliance.\n"
- "\n"
- " See also guestfs(3) section AVAILABILITY.\n"
- ));
- return 0;
- }
- else if (STRCASEEQ (cmd, "time")) {
- printf (_("time - measure time taken to run command\n"
- " time <command> [<args> ...]\n"
- "\n"
- " This runs <command> as usual, and prints the elapsed\n"
- " time afterwards.\n"));
- return 0;
- }
else {
fprintf (stderr, _("%s: command not known, use -h to list all commands\n"),
cmd);
#else
(void) write_history (histfile);
#endif
+ clear_history ();
}
#endif
}
static char *
file_in_heredoc (const char *endmarker)
{
- static const char template[] = "/tmp/heredocXXXXXX";
+ TMP_TEMPLATE_ON_STACK (template);
file_in_tmpfile = strdup (template);
if (file_in_tmpfile == NULL) {
perror ("strdup");
if (tty) {
fprintf (outfp, _("Enter key or passphrase (\"%s\"): "), param);
- if (tcgetattr (fileno (infp), &orig) == -1) {
- perror ("tcgetattr");
- goto error;
- }
- memcpy (&temp, &orig, sizeof temp);
- temp.c_lflag &= ~ECHO;
+ if (!echo_keys) {
+ if (tcgetattr (fileno (infp), &orig) == -1) {
+ perror ("tcgetattr");
+ goto error;
+ }
+ memcpy (&temp, &orig, sizeof temp);
+ temp.c_lflag &= ~ECHO;
- tcsetattr (fileno (infp), TCSAFLUSH, &temp);
- tcset = 1;
+ tcsetattr (fileno (infp), TCSAFLUSH, &temp);
+ tcset = 1;
+ }
}
size_t n = 0;