union {
struct {
char *filename; /* disk filename */
+ const char *format; /* format (NULL == autodetect) */
} a;
struct {
char *guest; /* guest name */
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 void free_drives (struct drv *drv);
+static void free_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;
fprintf (stdout,
_("%s: guest filesystem shell\n"
"%s lets you edit virtual machine filesystems\n"
- "Copyright (C) 2009 Red Hat Inc.\n"
+ "Copyright (C) 2009-2010 Red Hat Inc.\n"
"Usage:\n"
" %s [--options] cmd [: cmd : cmd ...]\n"
- " %s -i libvirt-domain\n"
- " %s -i disk-image(s)\n"
+ " %s [--ro] -i -a disk-image\n"
+ " %s [--ro] -i -d libvirt-domain\n"
"or for interactive use:\n"
" %s\n"
"or from a shell script:\n"
" -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"
" -v|--verbose Verbose messages\n"
" -x Echo each command before executing it\n"
" -V|--version Display version and exit\n"
- "For more information, see the manpage %s(1).\n"),
+ "For more information, see the manpage %s(1).\n"),
program_name, program_name, program_name,
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;
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);
}
drv->type = drv_a;
drv->a.filename = optarg;
+ drv->a.format = format;
drv->next = drvs;
drvs = drv;
break;
}
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,
*/
const char *options = read_only ? "ro" : "";
r = guestfs_mount_options (g, options, mp->device, mp->mountpoint);
- if (r == -1)
+ 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);
+ }
}
}
add_drives (struct drv *drv, char next_drive)
{
int r;
+ struct guestfs_add_drive_opts_argv ad_optargs;
if (next_drive > 'z') {
fprintf (stderr,
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);
+ ad_optargs.bitmask = 0;
+ if (read_only) {
+ ad_optargs.bitmask |= GUESTFS_ADD_DRIVE_OPTS_READONLY_BITMASK;
+ ad_optargs.readonly = 1;
+ }
+ if (drv->a.format) {
+ ad_optargs.bitmask |= GUESTFS_ADD_DRIVE_OPTS_FORMAT_BITMASK;
+ ad_optargs.format = drv->a.format;
+ }
+ r = guestfs_add_drive_opts_argv (g, drv->a.filename, &ad_optargs);
if (r == -1)
exit (EXIT_FAILURE);
break;
case drv_N:
+ /* guestfs_add_drive (ie. autodetecting) should be safe here
+ * since we have just created the prepared disk. At the moment
+ * it will always be "raw" but in a theoretical future we might
+ * create other formats.
+ */
/* -N option is not affected by --ro */
r = guestfs_add_drive (g, drv->N.filename);
if (r == -1)
}
}
+static void
+free_drives (struct drv *drv)
+{
+ if (!drv) return;
+ free_drives (drv->next);
+
+ switch (drv->type) {
+ case drv_a: /* a.filename and a.format are optargs, don't free them */ break;
+ case drv_d: /* d.filename is optarg, don't free it */ break;
+ case drv_N:
+ free (drv->N.filename);
+ free (drv->N.device);
+ free_prep_data (drv->N.data);
+ break;
+ default: ; /* keep GCC happy */
+ }
+ free (drv);
+}
+
+static void
+free_mps (struct mp *mp)
+{
+ if (!mp) return;
+ free_mps (mp->next);
+
+ /* The drive and mountpoint fields are not allocated
+ * from the heap, so we should not free them here.
+ */
+
+ free (mp);
+}
+
static int
launch (void)
{
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;