fish: Correction for online help for 'edit' and 'more' commands.
[libguestfs.git] / fish / fish.c
1 /* guestfish - the filesystem interactive shell
2  * Copyright (C) 2009-2010 Red Hat Inc.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 #include <config.h>
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <inttypes.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <getopt.h>
28 #include <signal.h>
29 #include <sys/types.h>
30 #include <sys/wait.h>
31 #include <locale.h>
32 #include <langinfo.h>
33 #include <termios.h>
34
35 #ifdef HAVE_LIBREADLINE
36 #include <readline/readline.h>
37 #include <readline/history.h>
38 #endif
39
40 #include <guestfs.h>
41
42 #include "fish.h"
43 #include "c-ctype.h"
44 #include "closeout.h"
45 #include "progname.h"
46
47 /* List of drives added via -a, -d or -N options. */
48 struct drv {
49   struct drv *next;
50   enum { drv_a, drv_d, drv_N } type;
51   union {
52     struct {
53       char *filename;       /* disk filename */
54     } a;
55     struct {
56       char *guest;          /* guest name */
57     } d;
58     struct {
59       char *filename;       /* disk filename (testX.img) */
60       prep_data *data;      /* prepared type */
61       char *device;         /* device inside the appliance */
62     } N;
63   };
64 };
65
66 struct mp {
67   struct mp *next;
68   char *device;
69   char *mountpoint;
70 };
71
72 static void set_up_terminal (void);
73 static char add_drives (struct drv *drv, char next_drive);
74 static void prepare_drives (struct drv *drv);
75 static void mount_mps (struct mp *mp);
76 static int launch (void);
77 static void interactive (void);
78 static void shell_script (void);
79 static void script (int prompt);
80 static void cmdline (char *argv[], int optind, int argc);
81 static void initialize_readline (void);
82 static void cleanup_readline (void);
83 #ifdef HAVE_LIBREADLINE
84 static void add_history_line (const char *);
85 #endif
86
87 static int override_progress_bars = -1;
88
89 /* Currently open libguestfs handle. */
90 guestfs_h *g;
91
92 int read_only = 0;
93 int quit = 0;
94 int verbose = 0;
95 int remote_control_listen = 0;
96 int remote_control = 0;
97 int exit_on_error = 1;
98 int command_num = 0;
99 int keys_from_stdin = 0;
100 const char *libvirt_uri = NULL;
101 int inspector = 0;
102 int utf8_mode = 0;
103 int have_terminfo = 0;
104 int progress_bars = 0;
105
106 static void __attribute__((noreturn))
107 usage (int status)
108 {
109   if (status != EXIT_SUCCESS)
110     fprintf (stderr, _("Try `%s --help' for more information.\n"),
111              program_name);
112   else {
113     fprintf (stdout,
114            _("%s: guest filesystem shell\n"
115              "%s lets you edit virtual machine filesystems\n"
116              "Copyright (C) 2009-2010 Red Hat Inc.\n"
117              "Usage:\n"
118              "  %s [--options] cmd [: cmd : cmd ...]\n"
119              "  %s [--ro] -i -a disk-image\n"
120              "  %s [--ro] -i -d libvirt-domain\n"
121              "or for interactive use:\n"
122              "  %s\n"
123              "or from a shell script:\n"
124              "  %s <<EOF\n"
125              "  cmd\n"
126              "  ...\n"
127              "  EOF\n"
128              "Options:\n"
129              "  -h|--cmd-help        List available commands\n"
130              "  -h|--cmd-help cmd    Display detailed help on 'cmd'\n"
131              "  -a|--add image       Add image\n"
132              "  -c|--connect uri     Specify libvirt URI for -d option\n"
133              "  -d|--domain guest    Add disks from libvirt guest\n"
134              "  -D|--no-dest-paths   Don't tab-complete paths from guest fs\n"
135              "  -f|--file file       Read commands from file\n"
136              "  -i|--inspector       Automatically mount filesystems\n"
137              "  --keys-from-stdin    Read passphrases from stdin\n"
138              "  --listen             Listen for remote commands\n"
139              "  -m|--mount dev[:mnt] Mount dev on mnt (if omitted, /)\n"
140              "  -n|--no-sync         Don't autosync\n"
141              "  -N|--new type        Create prepared disk (test1.img, ...)\n"
142              "  --progress-bars      Enable progress bars even when not interactive\n"
143              "  --no-progress-bars   Disable progress bars\n"
144              "  --remote[=pid]       Send commands to remote %s\n"
145              "  -r|--ro              Mount read-only\n"
146              "  --selinux            Enable SELinux support\n"
147              "  -v|--verbose         Verbose messages\n"
148              "  -x                   Echo each command before executing it\n"
149              "  -V|--version         Display version and exit\n"
150              "For more information, see the manpage %s(1).\n"),
151              program_name, program_name, program_name,
152              program_name, program_name, program_name,
153              program_name, program_name, program_name);
154   }
155   exit (status);
156 }
157
158 int
159 main (int argc, char *argv[])
160 {
161   /* Set global program name that is not polluted with libtool artifacts.  */
162   set_program_name (argv[0]);
163
164   atexit (close_stdout);
165
166   setlocale (LC_ALL, "");
167   bindtextdomain (PACKAGE, LOCALEBASEDIR);
168   textdomain (PACKAGE);
169
170   set_up_terminal ();
171
172   enum { HELP_OPTION = CHAR_MAX + 1 };
173
174   static const char *options = "a:c:d:Df:h::im:nN:rv?Vx";
175   static const struct option long_options[] = {
176     { "add", 1, 0, 'a' },
177     { "cmd-help", 2, 0, 'h' },
178     { "connect", 1, 0, 'c' },
179     { "domain", 1, 0, 'd' },
180     { "file", 1, 0, 'f' },
181     { "help", 0, 0, HELP_OPTION },
182     { "inspector", 0, 0, 'i' },
183     { "keys-from-stdin", 0, 0, 0 },
184     { "listen", 0, 0, 0 },
185     { "mount", 1, 0, 'm' },
186     { "new", 1, 0, 'N' },
187     { "no-dest-paths", 0, 0, 'D' },
188     { "no-sync", 0, 0, 'n' },
189     { "progress-bars", 0, 0, 0 },
190     { "no-progress-bars", 0, 0, 0 },
191     { "remote", 2, 0, 0 },
192     { "ro", 0, 0, 'r' },
193     { "selinux", 0, 0, 0 },
194     { "verbose", 0, 0, 'v' },
195     { "version", 0, 0, 'V' },
196     { 0, 0, 0, 0 }
197   };
198   struct drv *drvs = NULL;
199   struct drv *drv;
200   struct mp *mps = NULL;
201   struct mp *mp;
202   char *p, *file = NULL;
203   int c;
204   int option_index;
205   struct sigaction sa;
206   int next_prepared_drive = 1;
207
208   initialize_readline ();
209
210   memset (&sa, 0, sizeof sa);
211   sa.sa_handler = SIG_IGN;
212   sa.sa_flags = SA_RESTART;
213   sigaction (SIGPIPE, &sa, NULL);
214
215   /* guestfs_create is meant to be a lightweight operation, so
216    * it's OK to do it early here.
217    */
218   g = guestfs_create ();
219   if (g == NULL) {
220     fprintf (stderr, _("guestfs_create: failed to create handle\n"));
221     exit (EXIT_FAILURE);
222   }
223
224   guestfs_set_autosync (g, 1);
225
226   /* If developing, add ./appliance to the path.  Note that libtools
227    * interferes with this because uninstalled guestfish is a shell
228    * script that runs the real program with an absolute path.  Detect
229    * that too.
230    *
231    * BUT if LIBGUESTFS_PATH environment variable is already set by
232    * the user, then don't override it.
233    */
234   if (getenv ("LIBGUESTFS_PATH") == NULL &&
235       argv[0] &&
236       (argv[0][0] != '/' || strstr (argv[0], "/.libs/lt-") != NULL))
237     guestfs_set_path (g, "appliance:" GUESTFS_DEFAULT_PATH);
238
239   /* CAUTION: we are careful to modify argv[0] here, only after
240    * using it just above.
241    *
242    * getopt_long uses argv[0], so give it the sanitized name.  Save a copy
243    * of the original, in case it's needed below.
244    */
245   char *real_argv0 = argv[0];
246   argv[0] = bad_cast (program_name);
247
248   for (;;) {
249     c = getopt_long (argc, argv, options, long_options, &option_index);
250     if (c == -1) break;
251
252     switch (c) {
253     case 0:                     /* options which are long only */
254       if (STREQ (long_options[option_index].name, "listen"))
255         remote_control_listen = 1;
256       else if (STREQ (long_options[option_index].name, "remote")) {
257         if (optarg) {
258           if (sscanf (optarg, "%d", &remote_control) != 1) {
259             fprintf (stderr, _("%s: --listen=PID: PID was not a number: %s\n"),
260                      program_name, optarg);
261             exit (EXIT_FAILURE);
262           }
263         } else {
264           p = getenv ("GUESTFISH_PID");
265           if (!p || sscanf (p, "%d", &remote_control) != 1) {
266             fprintf (stderr, _("%s: remote: $GUESTFISH_PID must be set"
267                                " to the PID of the remote process\n"),
268                      program_name);
269             exit (EXIT_FAILURE);
270           }
271         }
272       } else if (STREQ (long_options[option_index].name, "selinux")) {
273         guestfs_set_selinux (g, 1);
274       } else if (STREQ (long_options[option_index].name, "keys-from-stdin")) {
275         keys_from_stdin = 1;
276       } else if (STREQ (long_options[option_index].name, "progress-bars")) {
277         override_progress_bars = 1;
278       } else if (STREQ (long_options[option_index].name, "no-progress-bars")) {
279         override_progress_bars = 0;
280       } else {
281         fprintf (stderr, _("%s: unknown long option: %s (%d)\n"),
282                  program_name, long_options[option_index].name, option_index);
283         exit (EXIT_FAILURE);
284       }
285       break;
286
287     case 'a':
288       if (access (optarg, R_OK) != 0) {
289         perror (optarg);
290         exit (EXIT_FAILURE);
291       }
292       drv = malloc (sizeof (struct drv));
293       if (!drv) {
294         perror ("malloc");
295         exit (EXIT_FAILURE);
296       }
297       drv->type = drv_a;
298       drv->a.filename = optarg;
299       drv->next = drvs;
300       drvs = drv;
301       break;
302
303     case 'c':
304       libvirt_uri = optarg;
305       break;
306
307     case 'd':
308       drv = malloc (sizeof (struct drv));
309       if (!drv) {
310         perror ("malloc");
311         exit (EXIT_FAILURE);
312       }
313       drv->type = drv_d;
314       drv->d.guest = optarg;
315       drv->next = drvs;
316       drvs = drv;
317       break;
318
319     case 'N':
320       if (STRCASEEQ (optarg, "list") ||
321           STRCASEEQ (optarg, "help") ||
322           STRCASEEQ (optarg, "h") ||
323           STRCASEEQ (optarg, "?")) {
324         list_prepared_drives ();
325         exit (EXIT_SUCCESS);
326       }
327       drv = malloc (sizeof (struct drv));
328       if (!drv) {
329         perror ("malloc");
330         exit (EXIT_FAILURE);
331       }
332       drv->type = drv_N;
333       if (asprintf (&drv->N.filename, "test%d.img",
334                     next_prepared_drive++) == -1) {
335         perror ("asprintf");
336         exit (EXIT_FAILURE);
337       }
338       drv->N.data = create_prepared_file (optarg, drv->N.filename);
339       drv->N.device = NULL;     /* filled in by add_drives */
340       drv->next = drvs;
341       drvs = drv;
342       break;
343
344     case 'D':
345       complete_dest_paths = 0;
346       break;
347
348     case 'f':
349       if (file) {
350         fprintf (stderr, _("%s: only one -f parameter can be given\n"),
351                  program_name);
352         exit (EXIT_FAILURE);
353       }
354       file = optarg;
355       break;
356
357     case 'h': {
358       int r = 0;
359
360       if (optarg)
361         r = display_command (optarg);
362       else if (argv[optind] && argv[optind][0] != '-')
363         r = display_command (argv[optind++]);
364       else
365         list_commands ();
366
367       exit (r == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
368     }
369
370     case 'i':
371       inspector = 1;
372       break;
373
374     case 'm':
375       mp = malloc (sizeof (struct mp));
376       if (!mp) {
377         perror ("malloc");
378         exit (EXIT_FAILURE);
379       }
380       p = strchr (optarg, ':');
381       if (p) {
382         *p = '\0';
383         mp->mountpoint = p+1;
384       } else
385         mp->mountpoint = bad_cast ("/");
386       mp->device = optarg;
387       mp->next = mps;
388       mps = mp;
389       break;
390
391     case 'n':
392       guestfs_set_autosync (g, 0);
393       break;
394
395     case 'r':
396       read_only = 1;
397       break;
398
399     case 'v':
400       verbose++;
401       guestfs_set_verbose (g, verbose);
402       break;
403
404     case 'V': {
405       struct guestfs_version *v = guestfs_version (g);
406       printf ("%s %"PRIi64".%"PRIi64".%"PRIi64"%s\n", program_name,
407               v->major, v->minor, v->release, v->extra);
408       exit (EXIT_SUCCESS);
409     }
410
411     case 'x':
412       guestfs_set_trace (g, 1);
413       break;
414
415     case HELP_OPTION:
416       usage (EXIT_SUCCESS);
417
418     default:
419       usage (EXIT_FAILURE);
420     }
421   }
422
423   /* Old-style -i syntax?  Since -a/-d/-N and -i was disallowed
424    * previously, if we have -i without any drives but with something
425    * on the command line, it must be old-style syntax.
426    */
427   if (inspector && drvs == NULL && optind < argc) {
428     while (optind < argc) {
429       if (strchr (argv[optind], '/') ||
430           access (argv[optind], F_OK) == 0) { /* simulate -a option */
431         drv = malloc (sizeof (struct drv));
432         if (!drv) {
433           perror ("malloc");
434           exit (EXIT_FAILURE);
435         }
436         drv->type = drv_a;
437         drv->a.filename = argv[optind];
438         drv->next = drvs;
439         drvs = drv;
440       } else {                  /* simulate -d option */
441         drv = malloc (sizeof (struct drv));
442         if (!drv) {
443           perror ("malloc");
444           exit (EXIT_FAILURE);
445         }
446         drv->type = drv_d;
447         drv->d.guest = argv[optind];
448         drv->next = drvs;
449         drvs = drv;
450       }
451
452       optind++;
453     }
454   }
455
456   /* If we've got drives to add, add them now. */
457   add_drives (drvs, 'a');
458
459   /* If we've got mountpoints or prepared drives or -i option, we must
460    * launch the guest and mount them.
461    */
462   if (next_prepared_drive > 1 || mps != NULL || inspector) {
463     /* RHBZ#612178: If --listen flag is given, then we will fork into
464      * the background in rc_listen().  However you can't do this while
465      * holding a libguestfs handle open because the recovery process
466      * will think the main program has died and kill qemu.  Therefore
467      * don't use the recovery process for this case.  (A better
468      * solution would be to call launch () etc after the fork, but
469      * that greatly complicates the code here).
470      */
471     if (remote_control_listen)
472       guestfs_set_recovery_proc (g, 0);
473
474     if (launch () == -1) exit (EXIT_FAILURE);
475
476     if (inspector)
477       inspect_mount ();
478
479     prepare_drives (drvs);
480     mount_mps (mps);
481   }
482
483   /* Remote control? */
484   if (remote_control_listen && remote_control) {
485     fprintf (stderr,
486              _("%s: cannot use --listen and --remote options at the same time\n"),
487              program_name);
488     exit (EXIT_FAILURE);
489   }
490
491   if (remote_control_listen) {
492     if (optind < argc) {
493       fprintf (stderr,
494                _("%s: extra parameters on the command line with --listen flag\n"),
495                program_name);
496       exit (EXIT_FAILURE);
497     }
498     if (file) {
499       fprintf (stderr,
500                _("%s: cannot use --listen and --file options at the same time\n"),
501                program_name);
502       exit (EXIT_FAILURE);
503     }
504     rc_listen ();
505   }
506
507   /* -f (file) parameter? */
508   if (file) {
509     close (0);
510     if (open (file, O_RDONLY) == -1) {
511       perror (file);
512       exit (EXIT_FAILURE);
513     }
514   }
515
516   /* Decide if we display progress bars. */
517   progress_bars =
518     override_progress_bars >= 0
519     ? override_progress_bars
520     : (optind >= argc && isatty (0));
521
522   if (progress_bars)
523     guestfs_set_progress_callback (g, progress_callback, NULL);
524
525   /* Interactive, shell script, or command(s) on the command line? */
526   if (optind >= argc) {
527     if (isatty (0))
528       interactive ();
529     else
530       shell_script ();
531   }
532   else
533     cmdline (argv, optind, argc);
534
535   cleanup_readline ();
536
537   exit (EXIT_SUCCESS);
538 }
539
540 /* The <term.h> header file which defines this has "issues". */
541 extern int tgetent (char *, const char *);
542
543 static void
544 set_up_terminal (void)
545 {
546   /* http://www.cl.cam.ac.uk/~mgk25/unicode.html#activate */
547   utf8_mode = STREQ (nl_langinfo (CODESET), "UTF-8");
548
549   char *term = getenv ("TERM");
550   if (term == NULL) {
551     //fprintf (stderr, _("guestfish: TERM (terminal type) not defined.\n"));
552     return;
553   }
554
555   int r = tgetent (NULL, term);
556   if (r == -1) {
557     fprintf (stderr, _("guestfish: could not access termcap or terminfo database.\n"));
558     return;
559   }
560   if (r == 0) {
561     fprintf (stderr, _("guestfish: terminal type \"%s\" not defined.\n"),
562              term);
563     return;
564   }
565
566   have_terminfo = 1;
567 }
568
569 void
570 pod2text (const char *name, const char *shortdesc, const char *str)
571 {
572   FILE *fp;
573
574   fp = popen ("pod2text", "w");
575   if (fp == NULL) {
576     /* pod2text failed, maybe not found, so let's just print the
577      * source instead, since that's better than doing nothing.
578      */
579     printf ("%s - %s\n\n%s\n", name, shortdesc, str);
580     return;
581   }
582   fprintf (fp, "=head1 NAME\n\n%s - %s\n\n", name, shortdesc);
583   fputs (str, fp);
584   pclose (fp);
585 }
586
587 /* List is built in reverse order, so mount them in reverse order. */
588 static void
589 mount_mps (struct mp *mp)
590 {
591   int r;
592
593   if (mp) {
594     mount_mps (mp->next);
595
596     /* Don't use guestfs_mount here because that will default to mount
597      * options -o sync,noatime.  For more information, see guestfs(3)
598      * section "LIBGUESTFS GOTCHAS".
599      */
600     const char *options = read_only ? "ro" : "";
601     r = guestfs_mount_options (g, options, mp->device, mp->mountpoint);
602     if (r == -1) {
603       /* Display possible mountpoints before exiting. */
604       char **fses = guestfs_list_filesystems (g);
605       if (fses == NULL || fses[0] == NULL)
606         goto out;
607       fprintf (stderr,
608                _("guestfish: '%s' could not be mounted.  Did you mean one of these?\n"),
609                mp->device);
610       size_t i;
611       for (i = 0; fses[i] != NULL; i += 2)
612         fprintf (stderr, "\t%s (%s)\n", fses[i], fses[i+1]);
613
614     out:
615       exit (EXIT_FAILURE);
616     }
617   }
618 }
619
620 static char
621 add_drives (struct drv *drv, char next_drive)
622 {
623   int r;
624
625   if (next_drive > 'z') {
626     fprintf (stderr,
627              _("guestfish: too many drives added on the command line\n"));
628     exit (EXIT_FAILURE);
629   }
630
631   if (drv) {
632     next_drive = add_drives (drv->next, next_drive);
633
634     switch (drv->type) {
635     case drv_a:
636       if (!read_only)
637         r = guestfs_add_drive (g, drv->a.filename);
638       else
639         r = guestfs_add_drive_ro (g, drv->a.filename);
640       if (r == -1)
641         exit (EXIT_FAILURE);
642
643       next_drive++;
644       break;
645
646     case drv_d:
647       r = add_libvirt_drives (drv->d.guest);
648       if (r == -1)
649         exit (EXIT_FAILURE);
650
651       next_drive += r;
652       break;
653
654     case drv_N:
655       /* -N option is not affected by --ro */
656       r = guestfs_add_drive (g, drv->N.filename);
657       if (r == -1)
658         exit (EXIT_FAILURE);
659
660       if (asprintf (&drv->N.device, "/dev/sd%c", next_drive) == -1) {
661         perror ("asprintf");
662         exit (EXIT_FAILURE);
663       }
664
665       next_drive++;
666       break;
667
668     default: /* keep GCC happy */
669       abort ();
670     }
671   }
672
673   return next_drive;
674 }
675
676 static void
677 prepare_drives (struct drv *drv)
678 {
679   if (drv) {
680     prepare_drives (drv->next);
681     if (drv->type == drv_N)
682       prepare_drive (drv->N.filename, drv->N.data, drv->N.device);
683   }
684 }
685
686 static int
687 launch (void)
688 {
689   if (guestfs_is_config (g)) {
690     if (guestfs_launch (g) == -1)
691       return -1;
692   }
693   return 0;
694 }
695
696 static void
697 interactive (void)
698 {
699   script (1);
700 }
701
702 static void
703 shell_script (void)
704 {
705   script (0);
706 }
707
708 #define FISH "><fs> "
709
710 static char *line_read = NULL;
711
712 static char *
713 rl_gets (int prompt)
714 {
715 #ifdef HAVE_LIBREADLINE
716
717   if (prompt) {
718     if (line_read) {
719       free (line_read);
720       line_read = NULL;
721     }
722
723     line_read = readline (prompt ? FISH : "");
724
725     if (line_read && *line_read)
726       add_history_line (line_read);
727
728     return line_read;
729   }
730
731 #endif /* HAVE_LIBREADLINE */
732
733   static char buf[8192];
734   int len;
735
736   if (prompt) printf (FISH);
737   line_read = fgets (buf, sizeof buf, stdin);
738
739   if (line_read) {
740     len = strlen (line_read);
741     if (len > 0 && buf[len-1] == '\n') buf[len-1] = '\0';
742   }
743
744   return line_read;
745 }
746
747 static void
748 script (int prompt)
749 {
750   char *buf;
751   char *cmd;
752   char *p, *pend;
753   char *argv[64];
754   int len;
755   int global_exit_on_error = !prompt;
756   int tilde_candidate;
757
758   if (prompt) {
759     printf (_("\n"
760               "Welcome to guestfish, the libguestfs filesystem interactive shell for\n"
761               "editing virtual machine filesystems.\n"
762               "\n"
763               "Type: 'help' for a list of commands\n"
764               "      'man' to read the manual\n"
765               "      'quit' to quit the shell\n"
766               "\n"));
767
768     if (inspector) {
769       print_inspect_prompt ();
770       printf ("\n");
771     }
772   }
773
774   while (!quit) {
775     char *pipe = NULL;
776
777     exit_on_error = global_exit_on_error;
778
779     buf = rl_gets (prompt);
780     if (!buf) {
781       quit = 1;
782       break;
783     }
784
785     /* Skip any initial whitespace before the command. */
786   again:
787     while (*buf && c_isspace (*buf))
788       buf++;
789
790     if (!*buf) continue;
791
792     /* If the next character is '#' then this is a comment. */
793     if (*buf == '#') continue;
794
795     /* If the next character is '!' then pass the whole lot to system(3). */
796     if (*buf == '!') {
797       int r;
798
799       r = system (buf+1);
800       if (exit_on_error) {
801         if (r == -1 ||
802             (WIFSIGNALED (r) &&
803              (WTERMSIG (r) == SIGINT || WTERMSIG (r) == SIGQUIT)) ||
804             WEXITSTATUS (r) != 0)
805           exit (EXIT_FAILURE);
806       }
807       continue;
808     }
809
810     /* If the next character is '-' allow the command to fail without
811      * exiting on error (just for this one command though).
812      */
813     if (*buf == '-') {
814       exit_on_error = 0;
815       buf++;
816       goto again;
817     }
818
819     /* Get the command (cannot be quoted). */
820     len = strcspn (buf, " \t");
821
822     if (len == 0) continue;
823
824     cmd = buf;
825     unsigned int i = 0;
826     if (buf[len] == '\0') {
827       argv[0] = NULL;
828       goto got_command;
829     }
830
831     buf[len] = '\0';
832     p = &buf[len+1];
833     p += strspn (p, " \t");
834
835     /* Get the parameters. */
836     while (*p && i < sizeof argv / sizeof argv[0]) {
837       tilde_candidate = 0;
838
839       /* Parameters which start with quotes or pipes are treated
840        * specially.  Bare parameters are delimited by whitespace.
841        */
842       if (*p == '"') {
843         p++;
844         len = strcspn (p, "\"");
845         if (p[len] == '\0') {
846           fprintf (stderr, _("%s: unterminated double quote\n"), program_name);
847           if (exit_on_error) exit (EXIT_FAILURE);
848           goto next_command;
849         }
850         if (p[len+1] && (p[len+1] != ' ' && p[len+1] != '\t')) {
851           fprintf (stderr,
852                    _("%s: command arguments not separated by whitespace\n"),
853                    program_name);
854           if (exit_on_error) exit (EXIT_FAILURE);
855           goto next_command;
856         }
857         p[len] = '\0';
858         pend = p[len+1] ? &p[len+2] : &p[len+1];
859       } else if (*p == '\'') {
860         p++;
861         len = strcspn (p, "'");
862         if (p[len] == '\0') {
863           fprintf (stderr, _("%s: unterminated single quote\n"), program_name);
864           if (exit_on_error) exit (EXIT_FAILURE);
865           goto next_command;
866         }
867         if (p[len+1] && (p[len+1] != ' ' && p[len+1] != '\t')) {
868           fprintf (stderr,
869                    _("%s: command arguments not separated by whitespace\n"),
870                    program_name);
871           if (exit_on_error) exit (EXIT_FAILURE);
872           goto next_command;
873         }
874         p[len] = '\0';
875         pend = p[len+1] ? &p[len+2] : &p[len+1];
876       } else if (*p == '|') {
877         *p = '\0';
878         pipe = p+1;
879         continue;
880         /*
881       } else if (*p == '[') {
882         int c = 1;
883         p++;
884         pend = p;
885         while (*pend && c != 0) {
886           if (*pend == '[') c++;
887           else if (*pend == ']') c--;
888           pend++;
889         }
890         if (c != 0) {
891           fprintf (stderr,
892                    _("%s: unterminated \"[...]\" sequence\n"), program_name);
893           if (exit_on_error) exit (EXIT_FAILURE);
894           goto next_command;
895         }
896         if (*pend && (*pend != ' ' && *pend != '\t')) {
897           fprintf (stderr,
898                    _("%s: command arguments not separated by whitespace\n"),
899                    program_name);
900           if (exit_on_error) exit (EXIT_FAILURE);
901           goto next_command;
902         }
903         *(pend-1) = '\0';
904         */
905       } else if (*p != ' ' && *p != '\t') {
906         /* If the first character is a ~ then note that this parameter
907          * is a candidate for ~username expansion.  NB this does not
908          * apply to quoted parameters.
909          */
910         tilde_candidate = *p == '~';
911         len = strcspn (p, " \t");
912         if (p[len]) {
913           p[len] = '\0';
914           pend = &p[len+1];
915         } else
916           pend = &p[len];
917       } else {
918         fprintf (stderr, _("%s: internal error parsing string at '%s'\n"),
919                  program_name, p);
920         abort ();
921       }
922
923       if (!tilde_candidate)
924         argv[i] = p;
925       else
926         argv[i] = try_tilde_expansion (p);
927       i++;
928       p = pend;
929
930       if (*p)
931         p += strspn (p, " \t");
932     }
933
934     if (i == sizeof argv / sizeof argv[0]) {
935       fprintf (stderr, _("%s: too many arguments\n"), program_name);
936       if (exit_on_error) exit (EXIT_FAILURE);
937       goto next_command;
938     }
939
940     argv[i] = NULL;
941
942   got_command:
943     if (issue_command (cmd, argv, pipe) == -1) {
944       if (exit_on_error) exit (EXIT_FAILURE);
945     }
946
947   next_command:;
948   }
949   if (prompt) printf ("\n");
950 }
951
952 static void
953 cmdline (char *argv[], int optind, int argc)
954 {
955   const char *cmd;
956   char **params;
957
958   exit_on_error = 1;
959
960   if (optind >= argc) return;
961
962   cmd = argv[optind++];
963   if (STREQ (cmd, ":")) {
964     fprintf (stderr, _("%s: empty command on command line\n"), program_name);
965     exit (EXIT_FAILURE);
966   }
967
968   /* Allow -cmd on the command line to mean (temporarily) override
969    * the normal exit on error (RHBZ#578407).
970    */
971   if (cmd[0] == '-') {
972     exit_on_error = 0;
973     cmd++;
974   }
975
976   params = &argv[optind];
977
978   /* Search for end of command list or ":" ... */
979   while (optind < argc && STRNEQ (argv[optind], ":"))
980     optind++;
981
982   if (optind == argc) {
983     if (issue_command (cmd, params, NULL) == -1 && exit_on_error)
984         exit (EXIT_FAILURE);
985   } else {
986     argv[optind] = NULL;
987     if (issue_command (cmd, params, NULL) == -1 && exit_on_error)
988       exit (EXIT_FAILURE);
989     cmdline (argv, optind+1, argc);
990   }
991 }
992
993 int
994 issue_command (const char *cmd, char *argv[], const char *pipecmd)
995 {
996   int argc;
997   int stdout_saved_fd = -1;
998   int pid = 0;
999   int i, r;
1000
1001   reset_progress_bar ();
1002
1003   /* This counts the commands issued, starting at 1. */
1004   command_num++;
1005
1006   /* For | ... commands.  Annoyingly we can't use popen(3) here. */
1007   if (pipecmd) {
1008     int fd[2];
1009
1010     if (fflush (stdout) == EOF) {
1011       perror ("failed to flush standard output");
1012       return -1;
1013     }
1014     if (pipe (fd) < 0) {
1015       perror ("pipe failed");
1016       return -1;
1017     }
1018     pid = fork ();
1019     if (pid == -1) {
1020       perror ("fork");
1021       return -1;
1022     }
1023
1024     if (pid == 0) {             /* Child process. */
1025       close (fd[1]);
1026       if (dup2 (fd[0], 0) < 0) {
1027         perror ("dup2 of stdin failed");
1028         _exit (1);
1029       }
1030
1031       r = system (pipecmd);
1032       if (r == -1) {
1033         perror (pipecmd);
1034         _exit (1);
1035       }
1036       _exit (WEXITSTATUS (r));
1037     }
1038
1039     if ((stdout_saved_fd = dup (1)) < 0) {
1040       perror ("failed to dup stdout");
1041       return -1;
1042     }
1043     close (fd[0]);
1044     if (dup2 (fd[1], 1) < 0) {
1045       perror ("failed to dup stdout");
1046       close (stdout_saved_fd);
1047       return -1;
1048     }
1049     close (fd[1]);
1050   }
1051
1052   for (argc = 0; argv[argc] != NULL; ++argc)
1053     ;
1054
1055   /* If --remote was set, then send this command to a remote process. */
1056   if (remote_control)
1057     r = rc_remote (remote_control, cmd, argc, argv, exit_on_error);
1058
1059   /* Otherwise execute it locally. */
1060   else if (STRCASEEQ (cmd, "help")) {
1061     if (argc == 0) {
1062       list_commands ();
1063       r = 0;
1064     } else
1065       r = display_command (argv[0]);
1066   }
1067   else if (STRCASEEQ (cmd, "quit") ||
1068            STRCASEEQ (cmd, "exit") ||
1069            STRCASEEQ (cmd, "q")) {
1070     quit = 1;
1071     r = 0;
1072   }
1073   else if (STRCASEEQ (cmd, "alloc") ||
1074            STRCASEEQ (cmd, "allocate"))
1075     r = do_alloc (cmd, argc, argv);
1076   else if (STRCASEEQ (cmd, "copy-in") ||
1077            STRCASEEQ (cmd, "copy_in"))
1078     r = do_copy_in (cmd, argc, argv);
1079   else if (STRCASEEQ (cmd, "copy-out") ||
1080            STRCASEEQ (cmd, "copy_out"))
1081     r = do_copy_out (cmd, argc, argv);
1082   else if (STRCASEEQ (cmd, "echo"))
1083     r = do_echo (cmd, argc, argv);
1084   else if (STRCASEEQ (cmd, "edit") ||
1085            STRCASEEQ (cmd, "vi") ||
1086            STRCASEEQ (cmd, "emacs"))
1087     r = do_edit (cmd, argc, argv);
1088   else if (STRCASEEQ (cmd, "lcd"))
1089     r = do_lcd (cmd, argc, argv);
1090   else if (STRCASEEQ (cmd, "glob"))
1091     r = do_glob (cmd, argc, argv);
1092   else if (STRCASEEQ (cmd, "man") ||
1093            STRCASEEQ (cmd, "manual"))
1094     r = do_man (cmd, argc, argv);
1095   else if (STRCASEEQ (cmd, "more") ||
1096            STRCASEEQ (cmd, "less"))
1097     r = do_more (cmd, argc, argv);
1098   else if (STRCASEEQ (cmd, "reopen"))
1099     r = do_reopen (cmd, argc, argv);
1100   else if (STRCASEEQ (cmd, "sparse"))
1101     r = do_sparse (cmd, argc, argv);
1102   else if (STRCASEEQ (cmd, "supported"))
1103     r = do_supported (cmd, argc, argv);
1104   else if (STRCASEEQ (cmd, "time"))
1105     r = do_time (cmd, argc, argv);
1106   else
1107     r = run_action (cmd, argc, argv);
1108
1109   /* Always flush stdout after every command, so that messages, results
1110    * etc appear immediately.
1111    */
1112   if (fflush (stdout) == EOF) {
1113     perror ("failed to flush standard output");
1114     return -1;
1115   }
1116
1117   if (pipecmd) {
1118     close (1);
1119     if (dup2 (stdout_saved_fd, 1) < 0) {
1120       perror ("failed to dup2 standard output");
1121       r = -1;
1122     }
1123     close (stdout_saved_fd);
1124     if (waitpid (pid, NULL, 0) < 0) {
1125       perror ("waiting for command to complete");
1126       r = -1;
1127     }
1128   }
1129
1130   return r;
1131 }
1132
1133 void
1134 list_builtin_commands (void)
1135 {
1136   /* help, man and quit should appear at the top */
1137   printf ("%-20s %s\n",
1138           "help", _("display a list of commands or help on a command"));
1139   printf ("%-20s %s\n",
1140           "man", _("read the manual"));
1141   printf ("%-20s %s\n",
1142           "quit", _("quit guestfish"));
1143
1144   printf ("%-20s %s\n",
1145           "alloc", _("allocate an image"));
1146   printf ("%-20s %s\n",
1147           "copy-in", _("copy files into an image"));
1148   printf ("%-20s %s\n",
1149           "copy-out", _("copy files out of an image"));
1150   printf ("%-20s %s\n",
1151           "echo", _("display a line of text"));
1152   printf ("%-20s %s\n",
1153           "edit", _("edit a file in the image"));
1154   printf ("%-20s %s\n",
1155           "lcd", _("local change directory"));
1156   printf ("%-20s %s\n",
1157           "glob", _("expand wildcards in command"));
1158   printf ("%-20s %s\n",
1159           "more", _("view a file in the pager"));
1160   printf ("%-20s %s\n",
1161           "reopen", _("close and reopen libguestfs handle"));
1162   printf ("%-20s %s\n",
1163           "sparse", _("allocate a sparse image file"));
1164   printf ("%-20s %s\n",
1165           "supported", _("list supported groups of commands"));
1166   printf ("%-20s %s\n",
1167           "time", _("measure time taken to run command"));
1168
1169   /* actions are printed after this (see list_commands) */
1170 }
1171
1172 int
1173 display_builtin_command (const char *cmd)
1174 {
1175   /* help for actions is auto-generated, see display_command */
1176
1177   if (STRCASEEQ (cmd, "alloc") ||
1178       STRCASEEQ (cmd, "allocate")) {
1179     printf (_("alloc - allocate an image\n"
1180               "     alloc <filename> <size>\n"
1181               "\n"
1182               "    This creates an empty (zeroed) file of the given size,\n"
1183               "    and then adds so it can be further examined.\n"
1184               "\n"
1185               "    For more advanced image creation, see qemu-img utility.\n"
1186               "\n"
1187               "    Size can be specified using standard suffixes, eg. '1M'.\n"
1188               ));
1189     return 0;
1190   }
1191   else if (STRCASEEQ (cmd, "copy-in") ||
1192            STRCASEEQ (cmd, "copy_in")) {
1193     printf (_("copy-in - copy files into an image\n"
1194               "     copy-in <local> [<local> ...] <remotedir>\n"
1195               "\n"
1196               "    Copy local files or directories recursively into the\n"
1197               "    image, placing them on a remote directory.\n"
1198               ));
1199     return 0;
1200   }
1201   else if (STRCASEEQ (cmd, "copy-out") ||
1202            STRCASEEQ (cmd, "copy_out")) {
1203     printf (_("copy-out - copy files out of an image\n"
1204               "     copy-out <remote> [<remote> ...] <localdir>\n"
1205               "\n"
1206               "    Copy remote files or directories recursively out of the\n"
1207               "    image, placing them in a local directory.\n"
1208               ));
1209     return 0;
1210   }
1211   else if (STRCASEEQ (cmd, "echo")) {
1212     printf (_("echo - display a line of text\n"
1213               "     echo [<params> ...]\n"
1214               "\n"
1215               "    This echos the parameters to the terminal.\n"));
1216     return 0;
1217   }
1218   else if (STRCASEEQ (cmd, "edit") ||
1219            STRCASEEQ (cmd, "vi") ||
1220            STRCASEEQ (cmd, "emacs")) {
1221     printf (_("edit - edit a file in the image\n"
1222               "     edit <filename>\n"
1223               "\n"
1224               "    This is used to edit a file.\n"
1225               "\n"
1226               "    It is the equivalent of (and is implemented by)\n"
1227               "    running \"cat\", editing locally, and then \"write\".\n"
1228               "\n"
1229               "    Normally it uses $EDITOR, but if you use the aliases\n"
1230               "    \"vi\" or \"emacs\" you will get those editors.\n"));
1231     return 0;
1232   }
1233   else if (STRCASEEQ (cmd, "lcd")) {
1234     printf (_("lcd - local change directory\n"
1235               "    lcd <directory>\n"
1236               "\n"
1237               "    Change guestfish's current directory. This command is\n"
1238               "    useful if you want to download files to a particular\n"
1239               "    place.\n"));
1240     return 0;
1241   }
1242   else if (STRCASEEQ (cmd, "glob")) {
1243     printf (_("glob - expand wildcards in command\n"
1244               "    glob <command> [<args> ...]\n"
1245               "\n"
1246               "    Glob runs <command> with wildcards expanded in any\n"
1247               "    command args.  Note that the command is run repeatedly\n"
1248               "    once for each expanded argument.\n"));
1249     return 0;
1250   }
1251   else if (STRCASEEQ (cmd, "man") ||
1252            STRCASEEQ (cmd, "manual")) {
1253     printf (_("man - read the manual\n"
1254               "    man\n"
1255               "\n"
1256               "    Opens the manual page for guestfish.\n"));
1257     return 0;
1258   }
1259   else if (STRCASEEQ (cmd, "help")) {
1260     printf (_("help - display a list of commands or help on a command\n"
1261               "     help cmd\n"
1262               "     help\n"));
1263     return 0;
1264   }
1265   else if (STRCASEEQ (cmd, "more") ||
1266            STRCASEEQ (cmd, "less")) {
1267     printf (_("more - view a file in the pager\n"
1268               "     more <filename>\n"
1269               "\n"
1270               "    This is used to view a file in the pager.\n"
1271               "\n"
1272               "    It is the equivalent of (and is implemented by)\n"
1273               "    running \"cat\" and using the pager.\n"
1274               "\n"
1275               "    Normally it uses $PAGER, but if you use the alias\n"
1276               "    \"less\" then it always uses \"less\".\n"));
1277     return 0;
1278   }
1279   else if (STRCASEEQ (cmd, "quit") ||
1280            STRCASEEQ (cmd, "exit") ||
1281            STRCASEEQ (cmd, "q")) {
1282     printf (_("quit - quit guestfish\n"
1283               "     quit\n"));
1284     return 0;
1285   }
1286   else if (STRCASEEQ (cmd, "reopen")) {
1287     printf (_("reopen - close and reopen the libguestfs handle\n"
1288               "     reopen\n"
1289               "\n"
1290               "Close and reopen the libguestfs handle.  It is not necessary to use\n"
1291               "this normally, because the handle is closed properly when guestfish\n"
1292               "exits.  However this is occasionally useful for testing.\n"));
1293     return 0;
1294   }
1295   else if (STRCASEEQ (cmd, "sparse")) {
1296     printf (_("sparse - allocate a sparse image file\n"
1297               "     sparse <filename> <size>\n"
1298               "\n"
1299               "    This creates an empty sparse file of the given size,\n"
1300               "    and then adds so it can be further examined.\n"
1301               "\n"
1302               "    In all respects it works the same as the 'alloc'\n"
1303               "    command, except that the image file is allocated\n"
1304               "    sparsely, which means that disk blocks are not assigned\n"
1305               "    to the file until they are needed.  Sparse disk files\n"
1306               "    only use space when written to, but they are slower\n"
1307               "    and there is a danger you could run out of real disk\n"
1308               "    space during a write operation.\n"
1309               "\n"
1310               "    For more advanced image creation, see qemu-img utility.\n"
1311               "\n"
1312               "    Size can be specified using standard suffixes, eg. '1M'.\n"
1313               ));
1314     return 0;
1315   }
1316   else if (STRCASEEQ (cmd, "supported")) {
1317     printf (_("supported - list supported groups of commands\n"
1318               "     supported\n"
1319               "\n"
1320               "    This command returns a list of the optional groups\n"
1321               "    known to the daemon, and indicates which ones are\n"
1322               "    supported by this build of the libguestfs appliance.\n"
1323               "\n"
1324               "    See also guestfs(3) section AVAILABILITY.\n"
1325               ));
1326     return 0;
1327   }
1328   else if (STRCASEEQ (cmd, "time")) {
1329     printf (_("time - measure time taken to run command\n"
1330               "    time <command> [<args> ...]\n"
1331               "\n"
1332               "    This runs <command> as usual, and prints the elapsed\n"
1333               "    time afterwards.\n"));
1334     return 0;
1335   }
1336   else {
1337     fprintf (stderr, _("%s: command not known, use -h to list all commands\n"),
1338              cmd);
1339     return -1;
1340   }
1341 }
1342
1343 /* This is printed when the user types in an unknown command for the
1344  * first command issued.  A common case is the user doing:
1345  *   guestfish disk.img
1346  * expecting guestfish to open 'disk.img' (in fact, this tried to
1347  * run a command 'disk.img').
1348  */
1349 void
1350 extended_help_message (void)
1351 {
1352   fprintf (stderr,
1353            _("Did you mean to open a disk image?  guestfish -a disk.img\n"
1354              "For a list of commands:             guestfish -h\n"
1355              "For complete documentation:         man guestfish\n"));
1356 }
1357
1358 void
1359 free_strings (char **argv)
1360 {
1361   int argc;
1362
1363   for (argc = 0; argv[argc] != NULL; ++argc)
1364     free (argv[argc]);
1365   free (argv);
1366 }
1367
1368 int
1369 count_strings (char *const *argv)
1370 {
1371   int c;
1372
1373   for (c = 0; argv[c]; ++c)
1374     ;
1375   return c;
1376 }
1377
1378 void
1379 print_strings (char *const *argv)
1380 {
1381   int argc;
1382
1383   for (argc = 0; argv[argc] != NULL; ++argc)
1384     printf ("%s\n", argv[argc]);
1385 }
1386
1387 void
1388 print_table (char *const *argv)
1389 {
1390   int i;
1391
1392   for (i = 0; argv[i] != NULL; i += 2)
1393     printf ("%s: %s\n", argv[i], argv[i+1]);
1394 }
1395
1396 int
1397 is_true (const char *str)
1398 {
1399   return
1400     STRCASENEQ (str, "0") &&
1401     STRCASENEQ (str, "f") &&
1402     STRCASENEQ (str, "false") &&
1403     STRCASENEQ (str, "n") &&
1404     STRCASENEQ (str, "no");
1405 }
1406
1407 /* Free strings from a non-NULL terminated char** */
1408 static void
1409 free_n_strings (char **str, size_t len)
1410 {
1411   size_t i;
1412
1413   for (i = 0; i < len; i++) {
1414     free (str[i]);
1415   }
1416   free (str);
1417 }
1418
1419 char **
1420 parse_string_list (const char *str)
1421 {
1422   char **argv = NULL;
1423   size_t argv_len = 0;
1424
1425   /* Current position pointer */
1426   const char *p = str;
1427
1428   /* Token might be simple:
1429    *  Token
1430    * or be quoted:
1431    *  'This is a single token'
1432    * or contain embedded single-quoted sections:
1433    *  This' is a sing'l'e to'ken
1434    *
1435    * The latter may seem over-complicated, but it's what a normal shell does.
1436    * Not doing it risks surprising somebody.
1437    *
1438    * This outer loop is over complete tokens.
1439    */
1440   while (*p) {
1441     char *tok = NULL;
1442     size_t tok_len = 0;
1443
1444     /* Skip leading whitespace */
1445     p += strspn (p, " \t");
1446
1447     char in_quote = 0;
1448
1449     /* This loop is over token 'fragments'. A token can be in multiple bits if
1450      * it contains single quotes. We also treat both sides of an escaped quote
1451      * as separate fragments because we can't just copy it: we have to remove
1452      * the \.
1453      */
1454     while (*p && (!c_isblank (*p) || in_quote)) {
1455       const char *end = p;
1456
1457       /* Check if the fragment starts with a quote */
1458       if ('\'' == *p) {
1459         /* Toggle in_quote */
1460         in_quote = !in_quote;
1461
1462         /* Skip the quote */
1463         p++; end++;
1464       }
1465
1466       /* If we're in a quote, look for an end quote */
1467       if (in_quote) {
1468         end += strcspn (end, "'");
1469       }
1470
1471       /* Otherwise, look for whitespace or a quote */
1472       else {
1473         end += strcspn (end, " \t'");
1474       }
1475
1476       /* Grow the token to accommodate the fragment */
1477       size_t tok_end = tok_len;
1478       tok_len += end - p;
1479       char *tok_new = realloc (tok, tok_len + 1);
1480       if (NULL == tok_new) {
1481         perror ("realloc");
1482         free_n_strings (argv, argv_len);
1483         free (tok);
1484         exit (EXIT_FAILURE);
1485       }
1486       tok = tok_new;
1487
1488       /* Check if we stopped on an escaped quote */
1489       if ('\'' == *end && end != p && *(end-1) == '\\') {
1490         /* Add everything before \' to the token */
1491         memcpy (&tok[tok_end], p, end - p - 1);
1492
1493         /* Add the quote */
1494         tok[tok_len-1] = '\'';
1495
1496         /* Already processed the quote */
1497         p = end + 1;
1498       }
1499
1500       else {
1501         /* Add the whole fragment */
1502         memcpy (&tok[tok_end], p, end - p);
1503
1504         p = end;
1505       }
1506     }
1507
1508     /* We've reached the end of a token. We shouldn't still be in quotes. */
1509     if (in_quote) {
1510       fprintf (stderr, _("Runaway quote in string \"%s\"\n"), str);
1511
1512       free_n_strings (argv, argv_len);
1513
1514       return NULL;
1515     }
1516
1517     /* Add this token if there is one. There might not be if there was
1518      * whitespace at the end of the input string */
1519     if (tok) {
1520       /* Add the NULL terminator */
1521       tok[tok_len] = '\0';
1522
1523       /* Add the argument to the argument list */
1524       argv_len++;
1525       char **argv_new = realloc (argv, sizeof (*argv) * argv_len);
1526       if (NULL == argv_new) {
1527         perror ("realloc");
1528         free_n_strings (argv, argv_len-1);
1529         free (tok);
1530         exit (EXIT_FAILURE);
1531       }
1532       argv = argv_new;
1533
1534       argv[argv_len-1] = tok;
1535     }
1536   }
1537
1538   /* NULL terminate the argument list */
1539   argv_len++;
1540   char **argv_new = realloc (argv, sizeof (*argv) * argv_len);
1541   if (NULL == argv_new) {
1542     perror ("realloc");
1543     free_n_strings (argv, argv_len-1);
1544     exit (EXIT_FAILURE);
1545   }
1546   argv = argv_new;
1547
1548   argv[argv_len-1] = NULL;
1549
1550   return argv;
1551 }
1552
1553 #ifdef HAVE_LIBREADLINE
1554 static char histfile[1024];
1555 static int nr_history_lines = 0;
1556 #endif
1557
1558 static void
1559 initialize_readline (void)
1560 {
1561 #ifdef HAVE_LIBREADLINE
1562   const char *home;
1563
1564   home = getenv ("HOME");
1565   if (home) {
1566     snprintf (histfile, sizeof histfile, "%s/.guestfish", home);
1567     using_history ();
1568     (void) read_history (histfile);
1569   }
1570
1571   rl_readline_name = "guestfish";
1572   rl_attempted_completion_function = do_completion;
1573
1574   /* Note that .inputrc (or /etc/inputrc) is not read until the first
1575    * call the readline(), which happens later.  Therefore, these
1576    * provide default values which can be overridden by the user if
1577    * they wish.
1578    */
1579   (void) rl_variable_bind ("completion-ignore-case", "on");
1580 #endif
1581 }
1582
1583 static void
1584 cleanup_readline (void)
1585 {
1586 #ifdef HAVE_LIBREADLINE
1587   int fd;
1588
1589   if (histfile[0] != '\0') {
1590     fd = open (histfile, O_WRONLY|O_CREAT, 0644);
1591     if (fd == -1) {
1592       perror (histfile);
1593       return;
1594     }
1595     close (fd);
1596
1597 #ifdef HAVE_APPEND_HISTORY
1598     (void) append_history (nr_history_lines, histfile);
1599 #else
1600     (void) write_history (histfile);
1601 #endif
1602   }
1603 #endif
1604 }
1605
1606 #ifdef HAVE_LIBREADLINE
1607 static void
1608 add_history_line (const char *line)
1609 {
1610   add_history (line);
1611   nr_history_lines++;
1612 }
1613 #endif
1614
1615 int
1616 xwrite (int fd, const void *v_buf, size_t len)
1617 {
1618   int r;
1619   const char *buf = v_buf;
1620
1621   while (len > 0) {
1622     r = write (fd, buf, len);
1623     if (r == -1) {
1624       perror ("write");
1625       return -1;
1626     }
1627     buf += r;
1628     len -= r;
1629   }
1630
1631   return 0;
1632 }
1633
1634 /* Resolve the special "win:..." form for Windows-specific paths.
1635  * This always returns a newly allocated string which is freed by the
1636  * caller function in "cmds.c".
1637  */
1638 char *
1639 resolve_win_path (const char *path)
1640 {
1641   char *ret;
1642   size_t i;
1643
1644   if (STRCASENEQLEN (path, "win:", 4)) {
1645     ret = strdup (path);
1646     if (ret == NULL)
1647       perror ("strdup");
1648     return ret;
1649   }
1650
1651   path += 4;
1652
1653   /* Drop drive letter, if it's "C:". */
1654   if (STRCASEEQLEN (path, "c:", 2))
1655     path += 2;
1656
1657   if (!*path) {
1658     ret = strdup ("/");
1659     if (ret == NULL)
1660       perror ("strdup");
1661     return ret;
1662   }
1663
1664   ret = strdup (path);
1665   if (ret == NULL) {
1666     perror ("strdup");
1667     return NULL;
1668   }
1669
1670   /* Blindly convert any backslashes into forward slashes.  Is this good? */
1671   for (i = 0; i < strlen (ret); ++i)
1672     if (ret[i] == '\\')
1673       ret[i] = '/';
1674
1675   char *t = guestfs_case_sensitive_path (g, ret);
1676   free (ret);
1677   ret = t;
1678
1679   return ret;
1680 }
1681
1682 /* Resolve the special FileIn paths ("-" or "-<<END" or filename).
1683  * The caller (cmds.c) will call free_file_in after the command has
1684  * run which should clean up resources.
1685  */
1686 static char *file_in_heredoc (const char *endmarker);
1687 static char *file_in_tmpfile = NULL;
1688
1689 char *
1690 file_in (const char *arg)
1691 {
1692   char *ret;
1693
1694   if (STREQ (arg, "-")) {
1695     ret = strdup ("/dev/stdin");
1696     if (!ret) {
1697       perror ("strdup");
1698       return NULL;
1699     }
1700   }
1701   else if (STRPREFIX (arg, "-<<")) {
1702     const char *endmarker = &arg[3];
1703     if (*endmarker == '\0') {
1704       fprintf (stderr, "%s: missing end marker in -<< expression\n",
1705                program_name);
1706       return NULL;
1707     }
1708     ret = file_in_heredoc (endmarker);
1709     if (ret == NULL)
1710       return NULL;
1711   }
1712   else {
1713     ret = strdup (arg);
1714     if (!ret) {
1715       perror ("strdup");
1716       return NULL;
1717     }
1718   }
1719
1720   return ret;
1721 }
1722
1723 static char *
1724 file_in_heredoc (const char *endmarker)
1725 {
1726   static const char template[] = "/tmp/heredocXXXXXX";
1727   file_in_tmpfile = strdup (template);
1728   if (file_in_tmpfile == NULL) {
1729     perror ("strdup");
1730     return NULL;
1731   }
1732
1733   int fd = mkstemp (file_in_tmpfile);
1734   if (fd == -1) {
1735     perror ("mkstemp");
1736     goto error1;
1737   }
1738
1739   size_t markerlen = strlen (endmarker);
1740
1741   char buffer[BUFSIZ];
1742   int write_error = 0;
1743   while (fgets (buffer, sizeof buffer, stdin) != NULL) {
1744     /* Look for "END"<EOF> or "END\n" in input. */
1745     size_t blen = strlen (buffer);
1746     if (STREQLEN (buffer, endmarker, markerlen) &&
1747         (blen == markerlen ||
1748          (blen == markerlen+1 && buffer[markerlen] == '\n')))
1749       goto found_end;
1750
1751     if (xwrite (fd, buffer, blen) == -1) {
1752       if (!write_error) perror ("write");
1753       write_error = 1;
1754       /* continue reading up to the end marker */
1755     }
1756   }
1757
1758   /* Reached EOF of stdin without finding the end marker, which
1759    * is likely to be an error.
1760    */
1761   fprintf (stderr, "%s: end of input reached without finding '%s'\n",
1762            program_name, endmarker);
1763   goto error2;
1764
1765  found_end:
1766   if (write_error) {
1767     close (fd);
1768     goto error2;
1769   }
1770
1771   if (close (fd) == -1) {
1772     perror ("close");
1773     goto error2;
1774   }
1775
1776   return file_in_tmpfile;
1777
1778  error2:
1779   unlink (file_in_tmpfile);
1780
1781  error1:
1782   free (file_in_tmpfile);
1783   file_in_tmpfile = NULL;
1784   return NULL;
1785 }
1786
1787 void
1788 free_file_in (char *s)
1789 {
1790   if (file_in_tmpfile) {
1791     if (unlink (file_in_tmpfile) == -1)
1792       perror (file_in_tmpfile);
1793     file_in_tmpfile = NULL;
1794   }
1795
1796   /* Free the device or file name which was strdup'd in file_in().
1797    * Note it's not immediately clear, but for -<< heredocs,
1798    * s == file_in_tmpfile, so this frees up that buffer.
1799    */
1800   free (s);
1801 }
1802
1803 /* Resolve the special FileOut paths ("-" or filename).
1804  * The caller (cmds.c) will call free (str) after the command has run.
1805  */
1806 char *
1807 file_out (const char *arg)
1808 {
1809   char *ret;
1810
1811   if (STREQ (arg, "-"))
1812     ret = strdup ("/dev/stdout");
1813   else
1814     ret = strdup (arg);
1815
1816   if (!ret) {
1817     perror ("strdup");
1818     return NULL;
1819   }
1820   return ret;
1821 }
1822
1823 /* Read a passphrase ('Key') from /dev/tty with echo off.
1824  * The caller (cmds.c) will call free on the string afterwards.
1825  * Based on the code in cryptsetup file lib/utils.c.
1826  */
1827 char *
1828 read_key (const char *param)
1829 {
1830   FILE *infp, *outfp;
1831   struct termios orig, temp;
1832   char *ret = NULL;
1833
1834   /* Read and write to /dev/tty if available. */
1835   if (keys_from_stdin ||
1836       (infp = outfp = fopen ("/dev/tty", "w+")) == NULL) {
1837     infp = stdin;
1838     outfp = stdout;
1839   }
1840
1841   /* Print the prompt and set no echo. */
1842   int tty = isatty (fileno (infp));
1843   int tcset = 0;
1844   if (tty) {
1845     fprintf (outfp, _("Enter key or passphrase (\"%s\"): "), param);
1846
1847     if (tcgetattr (fileno (infp), &orig) == -1) {
1848       perror ("tcgetattr");
1849       goto error;
1850     }
1851     memcpy (&temp, &orig, sizeof temp);
1852     temp.c_lflag &= ~ECHO;
1853
1854     tcsetattr (fileno (infp), TCSAFLUSH, &temp);
1855     tcset = 1;
1856   }
1857
1858   size_t n = 0;
1859   ssize_t len;
1860   len = getline (&ret, &n, infp);
1861   if (len == -1) {
1862     perror ("getline");
1863     ret = NULL;
1864     goto error;
1865   }
1866
1867   /* Remove the terminating \n if there is one. */
1868   if (len > 0 && ret[len-1] == '\n')
1869     ret[len-1] = '\0';
1870
1871  error:
1872   /* Restore echo, close file descriptor. */
1873   if (tty && tcset) {
1874     printf ("\n");
1875     tcsetattr (fileno (infp), TCSAFLUSH, &orig);
1876   }
1877
1878   if (infp != stdin)
1879     fclose (infp); /* outfp == infp, so this is closed also */
1880
1881   return ret;
1882 }