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