fish: If -m option fails, suggest a mountpoint.
[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               "\n"
1232               "    NOTE: This will not work reliably for large files\n"
1233               "    (> 2 MB) or binary files containing \\0 bytes.\n"));
1234     return 0;
1235   }
1236   else if (STRCASEEQ (cmd, "lcd")) {
1237     printf (_("lcd - local change directory\n"
1238               "    lcd <directory>\n"
1239               "\n"
1240               "    Change guestfish's current directory. This command is\n"
1241               "    useful if you want to download files to a particular\n"
1242               "    place.\n"));
1243     return 0;
1244   }
1245   else if (STRCASEEQ (cmd, "glob")) {
1246     printf (_("glob - expand wildcards in command\n"
1247               "    glob <command> [<args> ...]\n"
1248               "\n"
1249               "    Glob runs <command> with wildcards expanded in any\n"
1250               "    command args.  Note that the command is run repeatedly\n"
1251               "    once for each expanded argument.\n"));
1252     return 0;
1253   }
1254   else if (STRCASEEQ (cmd, "man") ||
1255            STRCASEEQ (cmd, "manual")) {
1256     printf (_("man - read the manual\n"
1257               "    man\n"
1258               "\n"
1259               "    Opens the manual page for guestfish.\n"));
1260     return 0;
1261   }
1262   else if (STRCASEEQ (cmd, "help")) {
1263     printf (_("help - display a list of commands or help on a command\n"
1264               "     help cmd\n"
1265               "     help\n"));
1266     return 0;
1267   }
1268   else if (STRCASEEQ (cmd, "more") ||
1269            STRCASEEQ (cmd, "less")) {
1270     printf (_("more - view a file in the pager\n"
1271               "     more <filename>\n"
1272               "\n"
1273               "    This is used to view a file in the pager.\n"
1274               "\n"
1275               "    It is the equivalent of (and is implemented by)\n"
1276               "    running \"cat\" and using the pager.\n"
1277               "\n"
1278               "    Normally it uses $PAGER, but if you use the alias\n"
1279               "    \"less\" then it always uses \"less\".\n"
1280               "\n"
1281               "    NOTE: This will not work reliably for large files\n"
1282               "    (> 2 MB) or binary files containing \\0 bytes.\n"));
1283     return 0;
1284   }
1285   else if (STRCASEEQ (cmd, "quit") ||
1286            STRCASEEQ (cmd, "exit") ||
1287            STRCASEEQ (cmd, "q")) {
1288     printf (_("quit - quit guestfish\n"
1289               "     quit\n"));
1290     return 0;
1291   }
1292   else if (STRCASEEQ (cmd, "reopen")) {
1293     printf (_("reopen - close and reopen the libguestfs handle\n"
1294               "     reopen\n"
1295               "\n"
1296               "Close and reopen the libguestfs handle.  It is not necessary to use\n"
1297               "this normally, because the handle is closed properly when guestfish\n"
1298               "exits.  However this is occasionally useful for testing.\n"));
1299     return 0;
1300   }
1301   else if (STRCASEEQ (cmd, "sparse")) {
1302     printf (_("sparse - allocate a sparse image file\n"
1303               "     sparse <filename> <size>\n"
1304               "\n"
1305               "    This creates an empty sparse file of the given size,\n"
1306               "    and then adds so it can be further examined.\n"
1307               "\n"
1308               "    In all respects it works the same as the 'alloc'\n"
1309               "    command, except that the image file is allocated\n"
1310               "    sparsely, which means that disk blocks are not assigned\n"
1311               "    to the file until they are needed.  Sparse disk files\n"
1312               "    only use space when written to, but they are slower\n"
1313               "    and there is a danger you could run out of real disk\n"
1314               "    space during a write operation.\n"
1315               "\n"
1316               "    For more advanced image creation, see qemu-img utility.\n"
1317               "\n"
1318               "    Size can be specified using standard suffixes, eg. '1M'.\n"
1319               ));
1320     return 0;
1321   }
1322   else if (STRCASEEQ (cmd, "supported")) {
1323     printf (_("supported - list supported groups of commands\n"
1324               "     supported\n"
1325               "\n"
1326               "    This command returns a list of the optional groups\n"
1327               "    known to the daemon, and indicates which ones are\n"
1328               "    supported by this build of the libguestfs appliance.\n"
1329               "\n"
1330               "    See also guestfs(3) section AVAILABILITY.\n"
1331               ));
1332     return 0;
1333   }
1334   else if (STRCASEEQ (cmd, "time")) {
1335     printf (_("time - measure time taken to run command\n"
1336               "    time <command> [<args> ...]\n"
1337               "\n"
1338               "    This runs <command> as usual, and prints the elapsed\n"
1339               "    time afterwards.\n"));
1340     return 0;
1341   }
1342   else {
1343     fprintf (stderr, _("%s: command not known, use -h to list all commands\n"),
1344              cmd);
1345     return -1;
1346   }
1347 }
1348
1349 /* This is printed when the user types in an unknown command for the
1350  * first command issued.  A common case is the user doing:
1351  *   guestfish disk.img
1352  * expecting guestfish to open 'disk.img' (in fact, this tried to
1353  * run a command 'disk.img').
1354  */
1355 void
1356 extended_help_message (void)
1357 {
1358   fprintf (stderr,
1359            _("Did you mean to open a disk image?  guestfish -a disk.img\n"
1360              "For a list of commands:             guestfish -h\n"
1361              "For complete documentation:         man guestfish\n"));
1362 }
1363
1364 void
1365 free_strings (char **argv)
1366 {
1367   int argc;
1368
1369   for (argc = 0; argv[argc] != NULL; ++argc)
1370     free (argv[argc]);
1371   free (argv);
1372 }
1373
1374 int
1375 count_strings (char *const *argv)
1376 {
1377   int c;
1378
1379   for (c = 0; argv[c]; ++c)
1380     ;
1381   return c;
1382 }
1383
1384 void
1385 print_strings (char *const *argv)
1386 {
1387   int argc;
1388
1389   for (argc = 0; argv[argc] != NULL; ++argc)
1390     printf ("%s\n", argv[argc]);
1391 }
1392
1393 void
1394 print_table (char *const *argv)
1395 {
1396   int i;
1397
1398   for (i = 0; argv[i] != NULL; i += 2)
1399     printf ("%s: %s\n", argv[i], argv[i+1]);
1400 }
1401
1402 int
1403 is_true (const char *str)
1404 {
1405   return
1406     STRCASENEQ (str, "0") &&
1407     STRCASENEQ (str, "f") &&
1408     STRCASENEQ (str, "false") &&
1409     STRCASENEQ (str, "n") &&
1410     STRCASENEQ (str, "no");
1411 }
1412
1413 /* Free strings from a non-NULL terminated char** */
1414 static void
1415 free_n_strings (char **str, size_t len)
1416 {
1417   size_t i;
1418
1419   for (i = 0; i < len; i++) {
1420     free (str[i]);
1421   }
1422   free (str);
1423 }
1424
1425 char **
1426 parse_string_list (const char *str)
1427 {
1428   char **argv = NULL;
1429   size_t argv_len = 0;
1430
1431   /* Current position pointer */
1432   const char *p = str;
1433
1434   /* Token might be simple:
1435    *  Token
1436    * or be quoted:
1437    *  'This is a single token'
1438    * or contain embedded single-quoted sections:
1439    *  This' is a sing'l'e to'ken
1440    *
1441    * The latter may seem over-complicated, but it's what a normal shell does.
1442    * Not doing it risks surprising somebody.
1443    *
1444    * This outer loop is over complete tokens.
1445    */
1446   while (*p) {
1447     char *tok = NULL;
1448     size_t tok_len = 0;
1449
1450     /* Skip leading whitespace */
1451     p += strspn (p, " \t");
1452
1453     char in_quote = 0;
1454
1455     /* This loop is over token 'fragments'. A token can be in multiple bits if
1456      * it contains single quotes. We also treat both sides of an escaped quote
1457      * as separate fragments because we can't just copy it: we have to remove
1458      * the \.
1459      */
1460     while (*p && (!c_isblank (*p) || in_quote)) {
1461       const char *end = p;
1462
1463       /* Check if the fragment starts with a quote */
1464       if ('\'' == *p) {
1465         /* Toggle in_quote */
1466         in_quote = !in_quote;
1467
1468         /* Skip the quote */
1469         p++; end++;
1470       }
1471
1472       /* If we're in a quote, look for an end quote */
1473       if (in_quote) {
1474         end += strcspn (end, "'");
1475       }
1476
1477       /* Otherwise, look for whitespace or a quote */
1478       else {
1479         end += strcspn (end, " \t'");
1480       }
1481
1482       /* Grow the token to accommodate the fragment */
1483       size_t tok_end = tok_len;
1484       tok_len += end - p;
1485       char *tok_new = realloc (tok, tok_len + 1);
1486       if (NULL == tok_new) {
1487         perror ("realloc");
1488         free_n_strings (argv, argv_len);
1489         free (tok);
1490         exit (EXIT_FAILURE);
1491       }
1492       tok = tok_new;
1493
1494       /* Check if we stopped on an escaped quote */
1495       if ('\'' == *end && end != p && *(end-1) == '\\') {
1496         /* Add everything before \' to the token */
1497         memcpy (&tok[tok_end], p, end - p - 1);
1498
1499         /* Add the quote */
1500         tok[tok_len-1] = '\'';
1501
1502         /* Already processed the quote */
1503         p = end + 1;
1504       }
1505
1506       else {
1507         /* Add the whole fragment */
1508         memcpy (&tok[tok_end], p, end - p);
1509
1510         p = end;
1511       }
1512     }
1513
1514     /* We've reached the end of a token. We shouldn't still be in quotes. */
1515     if (in_quote) {
1516       fprintf (stderr, _("Runaway quote in string \"%s\"\n"), str);
1517
1518       free_n_strings (argv, argv_len);
1519
1520       return NULL;
1521     }
1522
1523     /* Add this token if there is one. There might not be if there was
1524      * whitespace at the end of the input string */
1525     if (tok) {
1526       /* Add the NULL terminator */
1527       tok[tok_len] = '\0';
1528
1529       /* Add the argument to the argument list */
1530       argv_len++;
1531       char **argv_new = realloc (argv, sizeof (*argv) * argv_len);
1532       if (NULL == argv_new) {
1533         perror ("realloc");
1534         free_n_strings (argv, argv_len-1);
1535         free (tok);
1536         exit (EXIT_FAILURE);
1537       }
1538       argv = argv_new;
1539
1540       argv[argv_len-1] = tok;
1541     }
1542   }
1543
1544   /* NULL terminate the argument list */
1545   argv_len++;
1546   char **argv_new = realloc (argv, sizeof (*argv) * argv_len);
1547   if (NULL == argv_new) {
1548     perror ("realloc");
1549     free_n_strings (argv, argv_len-1);
1550     exit (EXIT_FAILURE);
1551   }
1552   argv = argv_new;
1553
1554   argv[argv_len-1] = NULL;
1555
1556   return argv;
1557 }
1558
1559 #ifdef HAVE_LIBREADLINE
1560 static char histfile[1024];
1561 static int nr_history_lines = 0;
1562 #endif
1563
1564 static void
1565 initialize_readline (void)
1566 {
1567 #ifdef HAVE_LIBREADLINE
1568   const char *home;
1569
1570   home = getenv ("HOME");
1571   if (home) {
1572     snprintf (histfile, sizeof histfile, "%s/.guestfish", home);
1573     using_history ();
1574     (void) read_history (histfile);
1575   }
1576
1577   rl_readline_name = "guestfish";
1578   rl_attempted_completion_function = do_completion;
1579
1580   /* Note that .inputrc (or /etc/inputrc) is not read until the first
1581    * call the readline(), which happens later.  Therefore, these
1582    * provide default values which can be overridden by the user if
1583    * they wish.
1584    */
1585   (void) rl_variable_bind ("completion-ignore-case", "on");
1586 #endif
1587 }
1588
1589 static void
1590 cleanup_readline (void)
1591 {
1592 #ifdef HAVE_LIBREADLINE
1593   int fd;
1594
1595   if (histfile[0] != '\0') {
1596     fd = open (histfile, O_WRONLY|O_CREAT, 0644);
1597     if (fd == -1) {
1598       perror (histfile);
1599       return;
1600     }
1601     close (fd);
1602
1603 #ifdef HAVE_APPEND_HISTORY
1604     (void) append_history (nr_history_lines, histfile);
1605 #else
1606     (void) write_history (histfile);
1607 #endif
1608   }
1609 #endif
1610 }
1611
1612 #ifdef HAVE_LIBREADLINE
1613 static void
1614 add_history_line (const char *line)
1615 {
1616   add_history (line);
1617   nr_history_lines++;
1618 }
1619 #endif
1620
1621 int
1622 xwrite (int fd, const void *v_buf, size_t len)
1623 {
1624   int r;
1625   const char *buf = v_buf;
1626
1627   while (len > 0) {
1628     r = write (fd, buf, len);
1629     if (r == -1) {
1630       perror ("write");
1631       return -1;
1632     }
1633     buf += r;
1634     len -= r;
1635   }
1636
1637   return 0;
1638 }
1639
1640 /* Resolve the special "win:..." form for Windows-specific paths.
1641  * This always returns a newly allocated string which is freed by the
1642  * caller function in "cmds.c".
1643  */
1644 char *
1645 resolve_win_path (const char *path)
1646 {
1647   char *ret;
1648   size_t i;
1649
1650   if (STRCASENEQLEN (path, "win:", 4)) {
1651     ret = strdup (path);
1652     if (ret == NULL)
1653       perror ("strdup");
1654     return ret;
1655   }
1656
1657   path += 4;
1658
1659   /* Drop drive letter, if it's "C:". */
1660   if (STRCASEEQLEN (path, "c:", 2))
1661     path += 2;
1662
1663   if (!*path) {
1664     ret = strdup ("/");
1665     if (ret == NULL)
1666       perror ("strdup");
1667     return ret;
1668   }
1669
1670   ret = strdup (path);
1671   if (ret == NULL) {
1672     perror ("strdup");
1673     return NULL;
1674   }
1675
1676   /* Blindly convert any backslashes into forward slashes.  Is this good? */
1677   for (i = 0; i < strlen (ret); ++i)
1678     if (ret[i] == '\\')
1679       ret[i] = '/';
1680
1681   char *t = guestfs_case_sensitive_path (g, ret);
1682   free (ret);
1683   ret = t;
1684
1685   return ret;
1686 }
1687
1688 /* Resolve the special FileIn paths ("-" or "-<<END" or filename).
1689  * The caller (cmds.c) will call free_file_in after the command has
1690  * run which should clean up resources.
1691  */
1692 static char *file_in_heredoc (const char *endmarker);
1693 static char *file_in_tmpfile = NULL;
1694
1695 char *
1696 file_in (const char *arg)
1697 {
1698   char *ret;
1699
1700   if (STREQ (arg, "-")) {
1701     ret = strdup ("/dev/stdin");
1702     if (!ret) {
1703       perror ("strdup");
1704       return NULL;
1705     }
1706   }
1707   else if (STRPREFIX (arg, "-<<")) {
1708     const char *endmarker = &arg[3];
1709     if (*endmarker == '\0') {
1710       fprintf (stderr, "%s: missing end marker in -<< expression\n",
1711                program_name);
1712       return NULL;
1713     }
1714     ret = file_in_heredoc (endmarker);
1715     if (ret == NULL)
1716       return NULL;
1717   }
1718   else {
1719     ret = strdup (arg);
1720     if (!ret) {
1721       perror ("strdup");
1722       return NULL;
1723     }
1724   }
1725
1726   return ret;
1727 }
1728
1729 static char *
1730 file_in_heredoc (const char *endmarker)
1731 {
1732   static const char template[] = "/tmp/heredocXXXXXX";
1733   file_in_tmpfile = strdup (template);
1734   if (file_in_tmpfile == NULL) {
1735     perror ("strdup");
1736     return NULL;
1737   }
1738
1739   int fd = mkstemp (file_in_tmpfile);
1740   if (fd == -1) {
1741     perror ("mkstemp");
1742     goto error1;
1743   }
1744
1745   size_t markerlen = strlen (endmarker);
1746
1747   char buffer[BUFSIZ];
1748   int write_error = 0;
1749   while (fgets (buffer, sizeof buffer, stdin) != NULL) {
1750     /* Look for "END"<EOF> or "END\n" in input. */
1751     size_t blen = strlen (buffer);
1752     if (STREQLEN (buffer, endmarker, markerlen) &&
1753         (blen == markerlen ||
1754          (blen == markerlen+1 && buffer[markerlen] == '\n')))
1755       goto found_end;
1756
1757     if (xwrite (fd, buffer, blen) == -1) {
1758       if (!write_error) perror ("write");
1759       write_error = 1;
1760       /* continue reading up to the end marker */
1761     }
1762   }
1763
1764   /* Reached EOF of stdin without finding the end marker, which
1765    * is likely to be an error.
1766    */
1767   fprintf (stderr, "%s: end of input reached without finding '%s'\n",
1768            program_name, endmarker);
1769   goto error2;
1770
1771  found_end:
1772   if (write_error) {
1773     close (fd);
1774     goto error2;
1775   }
1776
1777   if (close (fd) == -1) {
1778     perror ("close");
1779     goto error2;
1780   }
1781
1782   return file_in_tmpfile;
1783
1784  error2:
1785   unlink (file_in_tmpfile);
1786
1787  error1:
1788   free (file_in_tmpfile);
1789   file_in_tmpfile = NULL;
1790   return NULL;
1791 }
1792
1793 void
1794 free_file_in (char *s)
1795 {
1796   if (file_in_tmpfile) {
1797     if (unlink (file_in_tmpfile) == -1)
1798       perror (file_in_tmpfile);
1799     file_in_tmpfile = NULL;
1800   }
1801
1802   /* Free the device or file name which was strdup'd in file_in().
1803    * Note it's not immediately clear, but for -<< heredocs,
1804    * s == file_in_tmpfile, so this frees up that buffer.
1805    */
1806   free (s);
1807 }
1808
1809 /* Resolve the special FileOut paths ("-" or filename).
1810  * The caller (cmds.c) will call free (str) after the command has run.
1811  */
1812 char *
1813 file_out (const char *arg)
1814 {
1815   char *ret;
1816
1817   if (STREQ (arg, "-"))
1818     ret = strdup ("/dev/stdout");
1819   else
1820     ret = strdup (arg);
1821
1822   if (!ret) {
1823     perror ("strdup");
1824     return NULL;
1825   }
1826   return ret;
1827 }
1828
1829 /* Read a passphrase ('Key') from /dev/tty with echo off.
1830  * The caller (cmds.c) will call free on the string afterwards.
1831  * Based on the code in cryptsetup file lib/utils.c.
1832  */
1833 char *
1834 read_key (const char *param)
1835 {
1836   FILE *infp, *outfp;
1837   struct termios orig, temp;
1838   char *ret = NULL;
1839
1840   /* Read and write to /dev/tty if available. */
1841   if (keys_from_stdin ||
1842       (infp = outfp = fopen ("/dev/tty", "w+")) == NULL) {
1843     infp = stdin;
1844     outfp = stdout;
1845   }
1846
1847   /* Print the prompt and set no echo. */
1848   int tty = isatty (fileno (infp));
1849   int tcset = 0;
1850   if (tty) {
1851     fprintf (outfp, _("Enter key or passphrase (\"%s\"): "), param);
1852
1853     if (tcgetattr (fileno (infp), &orig) == -1) {
1854       perror ("tcgetattr");
1855       goto error;
1856     }
1857     memcpy (&temp, &orig, sizeof temp);
1858     temp.c_lflag &= ~ECHO;
1859
1860     tcsetattr (fileno (infp), TCSAFLUSH, &temp);
1861     tcset = 1;
1862   }
1863
1864   size_t n = 0;
1865   ssize_t len;
1866   len = getline (&ret, &n, infp);
1867   if (len == -1) {
1868     perror ("getline");
1869     ret = NULL;
1870     goto error;
1871   }
1872
1873   /* Remove the terminating \n if there is one. */
1874   if (len > 0 && ret[len-1] == '\n')
1875     ret[len-1] = '\0';
1876
1877  error:
1878   /* Restore echo, close file descriptor. */
1879   if (tty && tcset) {
1880     printf ("\n");
1881     tcsetattr (fileno (infp), TCSAFLUSH, &orig);
1882   }
1883
1884   if (infp != stdin)
1885     fclose (infp); /* outfp == infp, so this is closed also */
1886
1887   return ret;
1888 }