fish: Make exit_on_error into a completely local variable.
[libguestfs.git] / fish / fish.c
index 559d609..fbc364f 100644 (file)
@@ -30,7 +30,6 @@
 #include <sys/wait.h>
 #include <locale.h>
 #include <langinfo.h>
 #include <sys/wait.h>
 #include <locale.h>
 #include <langinfo.h>
-#include <termios.h>
 
 #ifdef HAVE_LIBREADLINE
 #include <readline/readline.h>
 
 #ifdef HAVE_LIBREADLINE
 #include <readline/readline.h>
@@ -68,8 +67,8 @@ int read_only = 0;
 int quit = 0;
 int verbose = 0;
 int remote_control_listen = 0;
 int quit = 0;
 int verbose = 0;
 int remote_control_listen = 0;
+int remote_control_csh = 0;
 int remote_control = 0;
 int remote_control = 0;
-int exit_on_error = 1;
 int command_num = 0;
 int keys_from_stdin = 0;
 int echo_keys = 0;
 int command_num = 0;
 int keys_from_stdin = 0;
 int echo_keys = 0;
@@ -106,6 +105,7 @@ usage (int status)
              "  -h|--cmd-help cmd    Display detailed help on 'cmd'\n"
              "  -a|--add image       Add image\n"
              "  -c|--connect uri     Specify libvirt URI for -d option\n"
              "  -h|--cmd-help cmd    Display detailed help on 'cmd'\n"
              "  -a|--add image       Add image\n"
              "  -c|--connect uri     Specify libvirt URI for -d option\n"
+             "  --csh                Make --listen csh-compatible\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"
              "  -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"
@@ -149,11 +149,12 @@ main (int argc, char *argv[])
 
   enum { HELP_OPTION = CHAR_MAX + 1 };
 
 
   enum { HELP_OPTION = CHAR_MAX + 1 };
 
-  static const char *options = "a:c:d:Df:h::im:nN:rv?Vx";
+  static const char *options = "a:c:d:Df:h::im:nN:rv?Vwx";
   static const struct option long_options[] = {
     { "add", 1, 0, 'a' },
     { "cmd-help", 2, 0, 'h' },
     { "connect", 1, 0, 'c' },
   static const struct option long_options[] = {
     { "add", 1, 0, 'a' },
     { "cmd-help", 2, 0, 'h' },
     { "connect", 1, 0, 'c' },
+    { "csh", 0, 0, 0 },
     { "domain", 1, 0, 'd' },
     { "echo-keys", 0, 0, 0 },
     { "file", 1, 0, 'f' },
     { "domain", 1, 0, 'd' },
     { "echo-keys", 0, 0, 0 },
     { "file", 1, 0, 'f' },
@@ -170,6 +171,7 @@ main (int argc, char *argv[])
     { "no-progress-bars", 0, 0, 0 },
     { "remote", 2, 0, 0 },
     { "ro", 0, 0, 'r' },
     { "no-progress-bars", 0, 0, 0 },
     { "remote", 2, 0, 0 },
     { "ro", 0, 0, 'r' },
+    { "rw", 0, 0, 'w' },
     { "selinux", 0, 0, 0 },
     { "verbose", 0, 0, 'v' },
     { "version", 0, 0, 'V' },
     { "selinux", 0, 0, 0 },
     { "verbose", 0, 0, 'v' },
     { "version", 0, 0, 'V' },
@@ -221,7 +223,7 @@ main (int argc, char *argv[])
    * getopt_long uses argv[0], so give it the sanitized name.  Save a copy
    * of the original, in case it's needed below.
    */
    * getopt_long uses argv[0], so give it the sanitized name.  Save a copy
    * of the original, in case it's needed below.
    */
-  char *real_argv0 = argv[0];
+  //char *real_argv0 = argv[0];
   argv[0] = bad_cast (program_name);
 
   for (;;) {
   argv[0] = bad_cast (program_name);
 
   for (;;) {
@@ -263,6 +265,8 @@ main (int argc, char *argv[])
           format = NULL;
         else
           format = optarg;
           format = NULL;
         else
           format = optarg;
+      } else if (STREQ (long_options[option_index].name, "csh")) {
+        remote_control_csh = 1;
       } else {
         fprintf (stderr, _("%s: unknown long option: %s (%d)\n"),
                  program_name, long_options[option_index].name, option_index);
       } else {
         fprintf (stderr, _("%s: unknown long option: %s (%d)\n"),
                  program_name, long_options[option_index].name, option_index);
@@ -334,6 +338,8 @@ main (int argc, char *argv[])
         exit (EXIT_FAILURE);
       }
       drv->type = drv_N;
         exit (EXIT_FAILURE);
       }
       drv->type = drv_N;
+      drv->device = NULL;
+      drv->nr_drives = -1;
       if (asprintf (&drv->N.filename, "test%d.img",
                     next_prepared_drive++) == -1) {
         perror ("asprintf");
       if (asprintf (&drv->N.filename, "test%d.img",
                     next_prepared_drive++) == -1) {
         perror ("asprintf");
@@ -341,7 +347,6 @@ main (int argc, char *argv[])
       }
       drv->N.data = create_prepared_file (optarg, drv->N.filename);
       drv->N.data_free = free_prep_data;
       }
       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;
       drv->next = drvs;
       drvs = drv;
       break;
@@ -358,6 +363,10 @@ main (int argc, char *argv[])
       OPTION_V;
       break;
 
       OPTION_V;
       break;
 
+    case 'w':
+      OPTION_w;
+      break;
+
     case 'x':
       OPTION_x;
       break;
     case 'x':
       OPTION_x;
       break;
@@ -521,31 +530,13 @@ set_up_terminal (void)
   have_terminfo = 1;
 }
 
   have_terminfo = 1;
 }
 
-void
-pod2text (const char *name, const char *shortdesc, const char *str)
-{
-  FILE *fp;
-
-  fp = popen ("pod2text", "w");
-  if (fp == NULL) {
-    /* pod2text failed, maybe not found, so let's just print the
-     * source instead, since that's better than doing nothing.
-     */
-    printf ("%s - %s\n\n%s\n", name, shortdesc, str);
-    return;
-  }
-  fprintf (fp, "=head1 NAME\n\n%s - %s\n\n", name, shortdesc);
-  fputs (str, fp);
-  pclose (fp);
-}
-
 static void
 prepare_drives (struct drv *drv)
 {
   if (drv) {
     prepare_drives (drv->next);
     if (drv->type == drv_N)
 static void
 prepare_drives (struct drv *drv)
 {
   if (drv) {
     prepare_drives (drv->next);
     if (drv->type == drv_N)
-      prepare_drive (drv->N.filename, drv->N.data, drv->N.device);
+      prepare_drive (drv->N.filename, drv->N.data, drv->device);
   }
 }
 
   }
 }
 
@@ -619,6 +610,7 @@ script (int prompt)
   char *argv[64];
   int len;
   int global_exit_on_error = !prompt;
   char *argv[64];
   int len;
   int global_exit_on_error = !prompt;
+  int exit_on_error;
   int tilde_candidate;
 
   if (prompt) {
   int tilde_candidate;
 
   if (prompt) {
@@ -626,7 +618,7 @@ script (int prompt)
               "Welcome to guestfish, the libguestfs filesystem interactive shell for\n"
               "editing virtual machine filesystems.\n"
               "\n"
               "Welcome to guestfish, the libguestfs filesystem interactive shell for\n"
               "editing virtual machine filesystems.\n"
               "\n"
-              "Type: 'help' for a list of commands\n"
+              "Type: 'help' for help on commands\n"
               "      'man' to read the manual\n"
               "      'quit' to quit the shell\n"
               "\n"));
               "      'man' to read the manual\n"
               "      'quit' to quit the shell\n"
               "\n"));
@@ -806,7 +798,7 @@ script (int prompt)
     argv[i] = NULL;
 
   got_command:
     argv[i] = NULL;
 
   got_command:
-    if (issue_command (cmd, argv, pipe) == -1) {
+    if (issue_command (cmd, argv, pipe, exit_on_error) == -1) {
       if (exit_on_error) exit (EXIT_FAILURE);
     }
 
       if (exit_on_error) exit (EXIT_FAILURE);
     }
 
@@ -820,6 +812,7 @@ cmdline (char *argv[], int optind, int argc)
 {
   const char *cmd;
   char **params;
 {
   const char *cmd;
   char **params;
+  int exit_on_error;
 
   exit_on_error = 1;
 
 
   exit_on_error = 1;
 
@@ -846,23 +839,28 @@ cmdline (char *argv[], int optind, int argc)
     optind++;
 
   if (optind == argc) {
     optind++;
 
   if (optind == argc) {
-    if (issue_command (cmd, params, NULL) == -1 && exit_on_error)
+    if (issue_command (cmd, params, NULL, exit_on_error) == -1 && exit_on_error)
         exit (EXIT_FAILURE);
   } else {
     argv[optind] = NULL;
         exit (EXIT_FAILURE);
   } else {
     argv[optind] = NULL;
-    if (issue_command (cmd, params, NULL) == -1 && exit_on_error)
+    if (issue_command (cmd, params, NULL, exit_on_error) == -1 && exit_on_error)
       exit (EXIT_FAILURE);
     cmdline (argv, optind+1, argc);
   }
 }
 
       exit (EXIT_FAILURE);
     cmdline (argv, optind+1, argc);
   }
 }
 
+/* Note: 'rc_exit_on_error_flag' is the exit_on_error flag that we
+ * pass to the remote server (when issuing --remote commands).  It
+ * does not cause issue_command itself to exit on error.
+ */
 int
 int
-issue_command (const char *cmd, char *argv[], const char *pipecmd)
+issue_command (const char *cmd, char *argv[], const char *pipecmd,
+               int rc_exit_on_error_flag)
 {
   int argc;
   int stdout_saved_fd = -1;
   int pid = 0;
 {
   int argc;
   int stdout_saved_fd = -1;
   int pid = 0;
-  int i, r;
+  int r;
 
   reset_progress_bar ();
 
 
   reset_progress_bar ();
 
@@ -920,12 +918,12 @@ issue_command (const char *cmd, char *argv[], const char *pipecmd)
 
   /* If --remote was set, then send this command to a remote process. */
   if (remote_control)
 
   /* If --remote was set, then send this command to a remote process. */
   if (remote_control)
-    r = rc_remote (remote_control, cmd, argc, argv, exit_on_error);
+    r = rc_remote (remote_control, cmd, argc, argv, rc_exit_on_error_flag);
 
   /* Otherwise execute it locally. */
   else if (STRCASEEQ (cmd, "help")) {
     if (argc == 0) {
 
   /* Otherwise execute it locally. */
   else if (STRCASEEQ (cmd, "help")) {
     if (argc == 0) {
-      list_commands ();
+      display_help ();
       r = 0;
     } else
       r = display_command (argv[0]);
       r = 0;
     } else
       r = display_command (argv[0]);
@@ -1480,66 +1478,3 @@ file_out (const char *arg)
   }
   return ret;
 }
   }
   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 (!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;
-    }
-  }
-
-  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;
-}