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