Version 1.7.6.
[libguestfs.git] / fish / fish.c
index cf547c4..5d7aac6 100644 (file)
 #include <fcntl.h>
 #include <getopt.h>
 #include <signal.h>
 #include <fcntl.h>
 #include <getopt.h>
 #include <signal.h>
-#include <assert.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <locale.h>
 #include <langinfo.h>
 #include <sys/types.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>
 #include <guestfs.h>
 
 #include "fish.h"
 #include <guestfs.h>
 
 #include "fish.h"
+#include "options.h"
+
 #include "c-ctype.h"
 #include "closeout.h"
 #include "progname.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 void set_up_terminal (void);
-static char add_drives (struct drv *drv, char next_drive);
 static void prepare_drives (struct drv *drv);
 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);
 static int launch (void);
 static void interactive (void);
 static void shell_script (void);
@@ -94,10 +67,12 @@ 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 exit_on_error = 1;
 int command_num = 0;
 int keys_from_stdin = 0;
 int remote_control = 0;
 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;
 const char *libvirt_uri = NULL;
 int inspector = 0;
 int utf8_mode = 0;
@@ -114,11 +89,11 @@ usage (int status)
     fprintf (stdout,
            _("%s: guest filesystem shell\n"
              "%s lets you edit virtual machine filesystems\n"
     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"
              "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"
              "or for interactive use:\n"
              "  %s\n"
              "or from a shell script:\n"
@@ -131,9 +106,12 @@ 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"
              "  -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"
              "  -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"
              "  -i|--inspector       Automatically mount filesystems\n"
              "  --keys-from-stdin    Read passphrases from stdin\n"
              "  --listen             Listen for remote commands\n"
@@ -146,9 +124,9 @@ usage (int status)
              "  -r|--ro              Mount read-only\n"
              "  --selinux            Enable SELinux support\n"
              "  -v|--verbose         Verbose messages\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"
              "  -V|--version         Display version and exit\n"
-             "For more information,  see the manpage %s(1).\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,
              program_name, program_name, program_name);
              program_name, program_name, program_name,
              program_name, program_name, program_name,
              program_name, program_name, program_name);
@@ -172,13 +150,16 @@ 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' },
     { "domain", 1, 0, 'd' },
+    { "echo-keys", 0, 0, 0 },
     { "file", 1, 0, 'f' },
     { "file", 1, 0, 'f' },
+    { "format", 2, 0, 0 },
     { "help", 0, 0, HELP_OPTION },
     { "inspector", 0, 0, 'i' },
     { "keys-from-stdin", 0, 0, 0 },
     { "help", 0, 0, HELP_OPTION },
     { "inspector", 0, 0, 'i' },
     { "keys-from-stdin", 0, 0, 0 },
@@ -191,6 +172,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' },
@@ -201,6 +183,7 @@ main (int argc, char *argv[])
   struct mp *mps = NULL;
   struct mp *mp;
   char *p, *file = NULL;
   struct mp *mps = NULL;
   struct mp *mp;
   char *p, *file = NULL;
+  const char *format = NULL;
   int c;
   int option_index;
   struct sigaction sa;
   int c;
   int option_index;
   struct sigaction sa;
@@ -222,8 +205,6 @@ main (int argc, char *argv[])
     exit (EXIT_FAILURE);
   }
 
     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
   /* 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
@@ -278,6 +259,15 @@ main (int argc, char *argv[])
         override_progress_bars = 1;
       } else if (STREQ (long_options[option_index].name, "no-progress-bars")) {
         override_progress_bars = 0;
         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 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);
@@ -286,60 +276,15 @@ main (int argc, char *argv[])
       break;
 
     case 'a':
       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':
       break;
 
     case 'c':
-      libvirt_uri = optarg;
+      OPTION_c;
       break;
 
     case 'd':
       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':
       break;
 
     case 'D':
@@ -369,48 +314,61 @@ main (int argc, char *argv[])
     }
 
     case 'i':
     }
 
     case 'i':
-      inspector = 1;
+      OPTION_i;
       break;
 
     case 'm':
       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':
       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':
       break;
 
     case 'r':
-      read_only = 1;
+      OPTION_r;
       break;
 
     case 'v':
       break;
 
     case 'v':
-      verbose++;
-      guestfs_set_verbose (g, verbose);
+      OPTION_v;
       break;
 
       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 'w':
+      OPTION_w;
+      break;
 
     case 'x':
 
     case 'x':
-      guestfs_set_trace (g, 1);
+      OPTION_x;
       break;
 
     case HELP_OPTION:
       break;
 
     case HELP_OPTION:
@@ -436,6 +394,7 @@ main (int argc, char *argv[])
         }
         drv->type = drv_a;
         drv->a.filename = argv[optind];
         }
         drv->type = drv_a;
         drv->a.filename = argv[optind];
+        drv->a.format = NULL;
         drv->next = drvs;
         drvs = drv;
       } else {                  /* simulate -d option */
         drv->next = drvs;
         drvs = drv;
       } else {                  /* simulate -d option */
@@ -481,6 +440,10 @@ main (int argc, char *argv[])
     mount_mps (mps);
   }
 
     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,
   /* Remote control? */
   if (remote_control_listen && remote_control) {
     fprintf (stderr,
@@ -585,82 +548,6 @@ pod2text (const char *name, const char *shortdesc, const char *str)
   pclose (fp);
 }
 
   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)
-      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)
 {
 static void
 prepare_drives (struct drv *drv)
 {
@@ -748,7 +635,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"));
@@ -1047,7 +934,7 @@ issue_command (const char *cmd, char *argv[], const char *pipecmd)
   /* 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]);
@@ -1058,39 +945,6 @@ issue_command (const char *cmd, char *argv[], const char *pipecmd)
     quit = 1;
     r = 0;
   }
     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);
 
   else
     r = run_action (cmd, argc, argv);
 
@@ -1121,39 +975,12 @@ issue_command (const char *cmd, char *argv[], const char *pipecmd)
 void
 list_builtin_commands (void)
 {
 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",
   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"));
 
           "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) */
 }
 
   /* actions are printed after this (see list_commands) */
 }
 
@@ -1162,114 +989,12 @@ display_builtin_command (const char *cmd)
 {
   /* help for actions is auto-generated, see display_command */
 
 {
   /* 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;
   }
     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")) {
   else if (STRCASEEQ (cmd, "quit") ||
            STRCASEEQ (cmd, "exit") ||
            STRCASEEQ (cmd, "q")) {
@@ -1277,56 +1002,6 @@ display_builtin_command (const char *cmd)
               "     quit\n"));
     return 0;
   }
               "     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 {
     fprintf (stderr, _("%s: command not known, use -h to list all commands\n"),
              cmd);
@@ -1593,6 +1268,7 @@ cleanup_readline (void)
 #else
     (void) write_history (histfile);
 #endif
 #else
     (void) write_history (histfile);
 #endif
+    clear_history ();
   }
 #endif
 }
   }
 #endif
 }
@@ -1717,7 +1393,7 @@ file_in (const char *arg)
 static char *
 file_in_heredoc (const char *endmarker)
 {
 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");
   file_in_tmpfile = strdup (template);
   if (file_in_tmpfile == NULL) {
     perror ("strdup");
@@ -1813,64 +1489,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 (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;
-}