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