X-Git-Url: http://git.annexia.org/?p=libguestfs.git;a=blobdiff_plain;f=fish%2Ffish.c;h=68f26ed0b4d4b5f5b0c120c27feb1db3129ba8d8;hp=a630cdcaba7a8ea3abffc02a4489115fd0e7a77e;hb=581a7965faa5bf242ab3f8b7c259ab17c2e967f4;hpb=11a2ad8c9a1da7fe7f8142be69312d0cb5979e0a diff --git a/fish/fish.c b/fish/fish.c index a630cdc..68f26ed 100644 --- a/fish/fish.c +++ b/fish/fish.c @@ -29,6 +29,7 @@ #include #include #include +#include #ifdef HAVE_LIBREADLINE #include @@ -65,7 +66,9 @@ static void script (int prompt); static void cmdline (char *argv[], int optind, int argc); static void initialize_readline (void); static void cleanup_readline (void); +#ifdef HAVE_LIBREADLINE static void add_history_line (const char *); +#endif static void print_shell_quote (FILE *stream, const char *str); /* Currently open libguestfs handle. */ @@ -78,6 +81,7 @@ int remote_control_listen = 0; int remote_control = 0; int exit_on_error = 1; int command_num = 0; +int keys_from_stdin = 0; static void __attribute__((noreturn)) usage (int status) @@ -108,6 +112,7 @@ usage (int status) " -D|--no-dest-paths Don't tab-complete paths from guest fs\n" " -f|--file file Read commands from file\n" " -i|--inspector Run virt-inspector to get disk mountpoints\n" + " --keys-from-stdin Read passphrases from stdin\n" " --listen Listen for remote commands\n" " -m|--mount dev[:mnt] Mount dev on mnt (if omitted, /)\n" " -n|--no-sync Don't autosync\n" @@ -147,6 +152,7 @@ main (int argc, char *argv[]) { "file", 1, 0, 'f' }, { "help", 0, 0, HELP_OPTION }, { "inspector", 0, 0, 'i' }, + { "keys-from-stdin", 0, 0, 0 }, { "listen", 0, 0, 0 }, { "mount", 1, 0, 'm' }, { "new", 1, 0, 'N' }, @@ -237,6 +243,8 @@ main (int argc, char *argv[]) } } else if (STREQ (long_options[option_index].name, "selinux")) { guestfs_set_selinux (g, 1); + } else if (STREQ (long_options[option_index].name, "keys-from-stdin")) { + keys_from_stdin = 1; } else { fprintf (stderr, _("%s: unknown long option: %s (%d)\n"), program_name, long_options[option_index].name, option_index); @@ -302,14 +310,18 @@ main (int argc, char *argv[]) file = optarg; break; - case 'h': + case 'h': { + int r = 0; + if (optarg) - display_command (optarg); + r = display_command (optarg); else if (argv[optind] && argv[optind][0] != '-') - display_command (argv[optind++]); + r = display_command (argv[optind++]); else list_commands (); - exit (EXIT_SUCCESS); + + exit (r == 0 ? EXIT_SUCCESS : EXIT_FAILURE); + } case 'i': inspector = 1; @@ -470,6 +482,17 @@ main (int argc, char *argv[]) * guest and mount them. */ if (next_prepared_drive > 1 || mps != NULL) { + /* RHBZ#612178: If --listen flag is given, then we will fork into + * the background in rc_listen(). However you can't do this while + * holding a libguestfs handle open because the recovery process + * will think the main program has died and kill qemu. Therefore + * don't use the recovery process for this case. (A better + * solution would be to call launch () etc after the fork, but + * that greatly complicates the code here). + */ + if (remote_control_listen) + guestfs_set_recovery_proc (g, 0); + if (launch () == -1) exit (EXIT_FAILURE); prepare_drives (drvs); mount_mps (mps); @@ -955,11 +978,11 @@ issue_command (const char *cmd, char *argv[], const char *pipecmd) /* Otherwise execute it locally. */ else if (STRCASEEQ (cmd, "help")) { - if (argc == 0) + if (argc == 0) { list_commands (); - else - display_command (argv[0]); - r = 0; + r = 0; + } else + r = display_command (argv[0]); } else if (STRCASEEQ (cmd, "quit") || STRCASEEQ (cmd, "exit") || @@ -990,6 +1013,8 @@ issue_command (const char *cmd, char *argv[], const char *pipecmd) 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 @@ -1047,18 +1072,20 @@ list_builtin_commands (void) 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) */ } -void +int display_builtin_command (const char *cmd) { /* help for actions is auto-generated, see display_command */ if (STRCASEEQ (cmd, "alloc") || - STRCASEEQ (cmd, "allocate")) + STRCASEEQ (cmd, "allocate")) { printf (_("alloc - allocate an image\n" " alloc \n" "\n" @@ -1067,63 +1094,69 @@ display_builtin_command (const char *cmd) "\n" " For more advanced image creation, see qemu-img utility.\n" "\n" - " Size can be specified (where means a number):\n" - " number of kilobytes\n" - " eg: 1440 standard 3.5\" floppy\n" - " K or KB number of kilobytes\n" - " M or MB number of megabytes\n" - " G or GB number of gigabytes\n" - " T or TB number of terabytes\n" - " P or PB number of petabytes\n" - " E or EB number of exabytes\n" - " sects number of 512 byte sectors\n")); - else if (STRCASEEQ (cmd, "echo")) + " Size can be specified using standard suffixes, eg. '1M'.\n" + )); + return 0; + } + else if (STRCASEEQ (cmd, "echo")) { printf (_("echo - display a line of text\n" " echo [ ...]\n" "\n" " This echos the parameters to the terminal.\n")); + return 0; + } else if (STRCASEEQ (cmd, "edit") || STRCASEEQ (cmd, "vi") || - STRCASEEQ (cmd, "emacs")) + STRCASEEQ (cmd, "emacs")) { printf (_("edit - edit a file in the image\n" " edit \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-file\".\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")); - else if (STRCASEEQ (cmd, "lcd")) + return 0; + } + else if (STRCASEEQ (cmd, "lcd")) { printf (_("lcd - local change directory\n" " lcd \n" "\n" " Change guestfish's current directory. This command is\n" " useful if you want to download files to a particular\n" " place.\n")); - else if (STRCASEEQ (cmd, "glob")) + return 0; + } + else if (STRCASEEQ (cmd, "glob")) { printf (_("glob - expand wildcards in command\n" " glob [ ...]\n" "\n" " Glob runs 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")) + STRCASEEQ (cmd, "manual")) { printf (_("man - read the manual\n" " man\n" "\n" " Opens the manual page for guestfish.\n")); - else if (STRCASEEQ (cmd, "help")) + return 0; + } + else 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")) + STRCASEEQ (cmd, "less")) { printf (_("more - view a file in the pager\n" " more \n" "\n" @@ -1137,19 +1170,25 @@ display_builtin_command (const char *cmd) "\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")) + STRCASEEQ (cmd, "q")) { printf (_("quit - quit guestfish\n" " quit\n")); - else if (STRCASEEQ (cmd, "reopen")) + 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")); - else if (STRCASEEQ (cmd, "sparse")) + return 0; + } + else if (STRCASEEQ (cmd, "sparse")) { printf (_("sparse - allocate a sparse image file\n" " sparse \n" "\n" @@ -1166,25 +1205,35 @@ display_builtin_command (const char *cmd) "\n" " For more advanced image creation, see qemu-img utility.\n" "\n" - " Size can be specified (where means a number):\n" - " number of kilobytes\n" - " eg: 1440 standard 3.5\" floppy\n" - " K or KB number of kilobytes\n" - " M or MB number of megabytes\n" - " G or GB number of gigabytes\n" - " T or TB number of terabytes\n" - " P or PB number of petabytes\n" - " E or EB number of exabytes\n" - " sects number of 512 byte sectors\n")); - else if (STRCASEEQ (cmd, "time")) + " 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 [ ...]\n" "\n" " This runs as usual, and prints the elapsed\n" " time afterwards.\n")); - else + return 0; + } + else { fprintf (stderr, _("%s: command not known, use -h to list all commands\n"), cmd); + return -1; + } } /* This is printed when the user types in an unknown command for the @@ -1417,6 +1466,13 @@ initialize_readline (void) rl_readline_name = "guestfish"; rl_attempted_completion_function = do_completion; + + /* Note that .inputrc (or /etc/inputrc) is not read until the first + * call the readline(), which happens later. Therefore, these + * provide default values which can be overridden by the user if + * they wish. + */ + (void) rl_variable_bind ("completion-ignore-case", "on"); #endif } @@ -1443,14 +1499,14 @@ cleanup_readline (void) #endif } +#ifdef HAVE_LIBREADLINE static void add_history_line (const char *line) { -#ifdef HAVE_LIBREADLINE add_history (line); nr_history_lines++; -#endif } +#endif int xwrite (int fd, const void *v_buf, size_t len) @@ -1660,6 +1716,67 @@ file_out (const char *arg) return ret; } +/* Read a passphrase ('Key') from /dev/tty with echo off. + * The caller (cmds.c) will call free on the string afterwards. + * Based on the code in cryptsetup file lib/utils.c. + */ +char * +read_key (const char *param) +{ + FILE *infp, *outfp; + struct termios orig, temp; + char *ret = NULL; + + /* Read and write to /dev/tty if available. */ + if (keys_from_stdin || + (infp = outfp = fopen ("/dev/tty", "w+")) == NULL) { + infp = stdin; + outfp = stdout; + } + + /* Print the prompt and set no echo. */ + int tty = isatty (fileno (infp)); + int tcset = 0; + 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; + + tcsetattr (fileno (infp), TCSAFLUSH, &temp); + tcset = 1; + } + + size_t n = 0; + ssize_t len; + len = getline (&ret, &n, infp); + if (len == -1) { + perror ("getline"); + ret = NULL; + goto error; + } + + /* Remove the terminating \n if there is one. */ + if (len > 0 && ret[len-1] == '\n') + ret[len-1] = '\0'; + + error: + /* Restore echo, close file descriptor. */ + if (tty && tcset) { + printf ("\n"); + tcsetattr (fileno (infp), TCSAFLUSH, &orig); + } + + if (infp != stdin) + fclose (infp); /* outfp == infp, so this is closed also */ + + return ret; +} + static void print_shell_quote (FILE *stream, const char *str) {