48ba4590dab1eb690c842b42317c36da74317880
[libguestfs.git] / fish / fish.c
1 /* guestfish - the filesystem interactive shell
2  * Copyright (C) 2009 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
33 #ifdef HAVE_LIBREADLINE
34 #include <readline/readline.h>
35 #include <readline/history.h>
36 #endif
37
38 #include <guestfs.h>
39
40 #include "fish.h"
41 #include "c-ctype.h"
42 #include "closeout.h"
43 #include "progname.h"
44
45 struct mp {
46   struct mp *next;
47   char *device;
48   char *mountpoint;
49 };
50
51 struct drv {
52   struct drv *next;
53   char *filename;
54 };
55
56 static void add_drives (struct drv *drv);
57 static void mount_mps (struct mp *mp);
58 static void interactive (void);
59 static void shell_script (void);
60 static void script (int prompt);
61 static void cmdline (char *argv[], int optind, int argc);
62 static void initialize_readline (void);
63 static void cleanup_readline (void);
64 #ifdef HAVE_LIBREADLINE
65 static void add_history_line (const char *);
66 #endif
67
68 /* Currently open libguestfs handle. */
69 guestfs_h *g;
70
71 int read_only = 0;
72 int quit = 0;
73 int verbose = 0;
74 int remote_control_listen = 0;
75 int remote_control = 0;
76 int exit_on_error = 1;
77 int command_num = 0;
78
79 int
80 launch (guestfs_h *_g)
81 {
82   assert (_g == g);
83
84   if (guestfs_is_config (g)) {
85     if (guestfs_launch (g) == -1)
86       return -1;
87   }
88   return 0;
89 }
90
91 static void __attribute__((noreturn))
92 usage (int status)
93 {
94   if (status != EXIT_SUCCESS)
95     fprintf (stderr, _("Try `%s --help' for more information.\n"),
96              program_name);
97   else {
98     fprintf (stdout,
99            _("%s: guest filesystem shell\n"
100              "%s lets you edit virtual machine filesystems\n"
101              "Copyright (C) 2009 Red Hat Inc.\n"
102              "Usage:\n"
103              "  %s [--options] cmd [: cmd : cmd ...]\n"
104              "  %s -i libvirt-domain\n"
105              "  %s -i disk-image(s)\n"
106              "or for interactive use:\n"
107              "  %s\n"
108              "or from a shell script:\n"
109              "  %s <<EOF\n"
110              "  cmd\n"
111              "  ...\n"
112              "  EOF\n"
113              "Options:\n"
114              "  -h|--cmd-help        List available commands\n"
115              "  -h|--cmd-help cmd    Display detailed help on 'cmd'\n"
116              "  -a|--add image       Add image\n"
117              "  -D|--no-dest-paths   Don't tab-complete paths from guest fs\n"
118              "  -f|--file file       Read commands from file\n"
119              "  -i|--inspector       Run virt-inspector to get disk mountpoints\n"
120              "  --listen             Listen for remote commands\n"
121              "  -m|--mount dev[:mnt] Mount dev on mnt (if omitted, /)\n"
122              "  -n|--no-sync         Don't autosync\n"
123              "  --remote[=pid]       Send commands to remote %s\n"
124              "  -r|--ro              Mount read-only\n"
125              "  --selinux            Enable SELinux support\n"
126              "  -v|--verbose         Verbose messages\n"
127              "  -x                   Echo each command before executing it\n"
128              "  -V|--version         Display version and exit\n"
129              "For more information,  see the manpage %s(1).\n"),
130              program_name, program_name, program_name,
131              program_name, program_name, program_name,
132              program_name, program_name, program_name);
133   }
134   exit (status);
135 }
136
137 int
138 main (int argc, char *argv[])
139 {
140   /* Set global program name that is not polluted with libtool artifacts.  */
141   set_program_name (argv[0]);
142
143   atexit (close_stdout);
144
145   setlocale (LC_ALL, "");
146   bindtextdomain (PACKAGE, LOCALEBASEDIR);
147   textdomain (PACKAGE);
148
149   enum { HELP_OPTION = CHAR_MAX + 1 };
150
151   static const char *options = "a:Df:h::im:nrv?Vx";
152   static const struct option long_options[] = {
153     { "add", 1, 0, 'a' },
154     { "cmd-help", 2, 0, 'h' },
155     { "file", 1, 0, 'f' },
156     { "help", 0, 0, HELP_OPTION },
157     { "inspector", 0, 0, 'i' },
158     { "listen", 0, 0, 0 },
159     { "mount", 1, 0, 'm' },
160     { "no-dest-paths", 0, 0, 'D' },
161     { "no-sync", 0, 0, 'n' },
162     { "remote", 2, 0, 0 },
163     { "ro", 0, 0, 'r' },
164     { "selinux", 0, 0, 0 },
165     { "verbose", 0, 0, 'v' },
166     { "version", 0, 0, 'V' },
167     { 0, 0, 0, 0 }
168   };
169   struct drv *drvs = NULL;
170   struct drv *drv;
171   struct mp *mps = NULL;
172   struct mp *mp;
173   char *p, *file = NULL;
174   int c;
175   int inspector = 0;
176   int option_index;
177   struct sigaction sa;
178
179   initialize_readline ();
180
181   memset (&sa, 0, sizeof sa);
182   sa.sa_handler = SIG_IGN;
183   sa.sa_flags = SA_RESTART;
184   sigaction (SIGPIPE, &sa, NULL);
185
186   /* guestfs_create is meant to be a lightweight operation, so
187    * it's OK to do it early here.
188    */
189   g = guestfs_create ();
190   if (g == NULL) {
191     fprintf (stderr, _("guestfs_create: failed to create handle\n"));
192     exit (EXIT_FAILURE);
193   }
194
195   guestfs_set_autosync (g, 1);
196
197   /* If developing, add ./appliance to the path.  Note that libtools
198    * interferes with this because uninstalled guestfish is a shell
199    * script that runs the real program with an absolute path.  Detect
200    * that too.
201    *
202    * BUT if LIBGUESTFS_PATH environment variable is already set by
203    * the user, then don't override it.
204    */
205   if (getenv ("LIBGUESTFS_PATH") == NULL &&
206       argv[0] &&
207       (argv[0][0] != '/' || strstr (argv[0], "/.libs/lt-") != NULL))
208     guestfs_set_path (g, "appliance:" GUESTFS_DEFAULT_PATH);
209
210   /* CAUTION: we are careful to modify argv[0] here, only after
211    * using it just above.
212    *
213    * getopt_long uses argv[0], so give it the sanitized name.  Save a copy
214    * of the original, in case it's needed in virt-inspector mode, below.
215    */
216   char *real_argv0 = argv[0];
217   argv[0] = bad_cast (program_name);
218
219   for (;;) {
220     c = getopt_long (argc, argv, options, long_options, &option_index);
221     if (c == -1) break;
222
223     switch (c) {
224     case 0:                     /* options which are long only */
225       if (STREQ (long_options[option_index].name, "listen"))
226         remote_control_listen = 1;
227       else if (STREQ (long_options[option_index].name, "remote")) {
228         if (optarg) {
229           if (sscanf (optarg, "%d", &remote_control) != 1) {
230             fprintf (stderr, _("%s: --listen=PID: PID was not a number: %s\n"),
231                      program_name, optarg);
232             exit (EXIT_FAILURE);
233           }
234         } else {
235           p = getenv ("GUESTFISH_PID");
236           if (!p || sscanf (p, "%d", &remote_control) != 1) {
237             fprintf (stderr, _("%s: remote: $GUESTFISH_PID must be set"
238                                " to the PID of the remote process\n"),
239                      program_name);
240             exit (EXIT_FAILURE);
241           }
242         }
243       } else if (STREQ (long_options[option_index].name, "selinux")) {
244         guestfs_set_selinux (g, 1);
245       } else {
246         fprintf (stderr, _("%s: unknown long option: %s (%d)\n"),
247                  program_name, long_options[option_index].name, option_index);
248         exit (EXIT_FAILURE);
249       }
250       break;
251
252     case 'a':
253       if (access (optarg, R_OK) != 0) {
254         perror (optarg);
255         exit (EXIT_FAILURE);
256       }
257       drv = malloc (sizeof (struct drv));
258       if (!drv) {
259         perror ("malloc");
260         exit (EXIT_FAILURE);
261       }
262       drv->filename = optarg;
263       drv->next = drvs;
264       drvs = drv;
265       break;
266
267     case 'D':
268       complete_dest_paths = 0;
269       break;
270
271     case 'f':
272       if (file) {
273         fprintf (stderr, _("%s: only one -f parameter can be given\n"),
274                  program_name);
275         exit (EXIT_FAILURE);
276       }
277       file = optarg;
278       break;
279
280     case 'h':
281       if (optarg)
282         display_command (optarg);
283       else if (argv[optind] && argv[optind][0] != '-')
284         display_command (argv[optind++]);
285       else
286         list_commands ();
287       exit (EXIT_SUCCESS);
288
289     case 'i':
290       inspector = 1;
291       break;
292
293     case 'm':
294       mp = malloc (sizeof (struct mp));
295       if (!mp) {
296         perror ("malloc");
297         exit (EXIT_FAILURE);
298       }
299       p = strchr (optarg, ':');
300       if (p) {
301         *p = '\0';
302         mp->mountpoint = p+1;
303       } else
304         mp->mountpoint = bad_cast ("/");
305       mp->device = optarg;
306       mp->next = mps;
307       mps = mp;
308       break;
309
310     case 'n':
311       guestfs_set_autosync (g, 0);
312       break;
313
314     case 'r':
315       read_only = 1;
316       break;
317
318     case 'v':
319       verbose++;
320       guestfs_set_verbose (g, verbose);
321       break;
322
323     case 'V':
324       printf ("%s %s\n", program_name, PACKAGE_VERSION);
325       exit (EXIT_SUCCESS);
326
327     case 'x':
328       guestfs_set_trace (g, 1);
329       break;
330
331     case HELP_OPTION:
332       usage (EXIT_SUCCESS);
333
334     default:
335       usage (EXIT_FAILURE);
336     }
337   }
338
339   /* Inspector mode invalidates most of the other arguments. */
340   if (inspector) {
341     char cmd[1024];
342     int r;
343
344     if (drvs || mps || remote_control_listen || remote_control ||
345         guestfs_get_selinux (g)) {
346       fprintf (stderr, _("%s: cannot use -i option with -a, -m,"
347                          " --listen, --remote or --selinux\n"),
348                program_name);
349       exit (EXIT_FAILURE);
350     }
351     if (optind >= argc) {
352       fprintf (stderr,
353            _("%s: -i requires a libvirt domain or path(s) to disk image(s)\n"),
354                program_name);
355       exit (EXIT_FAILURE);
356     }
357
358     strcpy (cmd, "a=`virt-inspector");
359     while (optind < argc) {
360       if (strlen (cmd) + strlen (argv[optind]) + strlen (real_argv0) + 60
361           >= sizeof cmd) {
362         fprintf (stderr,
363                  _("%s: virt-inspector command too long for fixed-size buffer\n"),
364                  program_name);
365         exit (EXIT_FAILURE);
366       }
367       strcat (cmd, " '");
368       strcat (cmd, argv[optind]);
369       strcat (cmd, "'");
370       optind++;
371     }
372
373     if (read_only)
374       strcat (cmd, " --ro-fish");
375     else
376       strcat (cmd, " --fish");
377
378     sprintf (&cmd[strlen(cmd)], "` && %s $a", real_argv0);
379
380     if (guestfs_get_verbose (g))
381       strcat (cmd, " -v");
382     if (!guestfs_get_autosync (g))
383       strcat (cmd, " -n");
384     if (guestfs_get_trace (g))
385       strcat (cmd, " -x");
386
387     if (verbose)
388       fprintf (stderr,
389                "%s -i: running virt-inspector command:\n%s\n", program_name, cmd);
390
391     r = system (cmd);
392     if (r == -1) {
393       perror ("system");
394       exit (EXIT_FAILURE);
395     }
396     exit (WEXITSTATUS (r));
397   }
398
399   /* If we've got drives to add, add them now. */
400   add_drives (drvs);
401
402   /* If we've got mountpoints, we must launch the guest and mount them. */
403   if (mps != NULL) {
404     if (launch (g) == -1) exit (EXIT_FAILURE);
405     mount_mps (mps);
406   }
407
408   /* Remote control? */
409   if (remote_control_listen && remote_control) {
410     fprintf (stderr,
411              _("%s: cannot use --listen and --remote options at the same time\n"),
412              program_name);
413     exit (EXIT_FAILURE);
414   }
415
416   if (remote_control_listen) {
417     if (optind < argc) {
418       fprintf (stderr,
419                _("%s: extra parameters on the command line with --listen flag\n"),
420                program_name);
421       exit (EXIT_FAILURE);
422     }
423     if (file) {
424       fprintf (stderr,
425                _("%s: cannot use --listen and --file options at the same time\n"),
426                program_name);
427       exit (EXIT_FAILURE);
428     }
429     rc_listen ();
430   }
431
432   /* -f (file) parameter? */
433   if (file) {
434     close (0);
435     if (open (file, O_RDONLY) == -1) {
436       perror (file);
437       exit (EXIT_FAILURE);
438     }
439   }
440
441   /* Interactive, shell script, or command(s) on the command line? */
442   if (optind >= argc) {
443     if (isatty (0))
444       interactive ();
445     else
446       shell_script ();
447   }
448   else
449     cmdline (argv, optind, argc);
450
451   cleanup_readline ();
452
453   exit (EXIT_SUCCESS);
454 }
455
456 void
457 pod2text (const char *name, const char *shortdesc, const char *str)
458 {
459   FILE *fp;
460
461   fp = popen ("pod2text", "w");
462   if (fp == NULL) {
463     /* pod2text failed, maybe not found, so let's just print the
464      * source instead, since that's better than doing nothing.
465      */
466     printf ("%s - %s\n\n%s\n", name, shortdesc, str);
467     return;
468   }
469   fprintf (fp, "=head1 NAME\n\n%s - %s\n\n", name, shortdesc);
470   fputs (str, fp);
471   pclose (fp);
472 }
473
474 /* List is built in reverse order, so mount them in reverse order. */
475 static void
476 mount_mps (struct mp *mp)
477 {
478   int r;
479
480   if (mp) {
481     mount_mps (mp->next);
482
483     /* Don't use guestfs_mount here because that will default to mount
484      * options -o sync,noatime.  For more information, see guestfs(3)
485      * section "LIBGUESTFS GOTCHAS".
486      */
487     const char *options = read_only ? "ro" : "";
488     r = guestfs_mount_options (g, options, mp->device, mp->mountpoint);
489     if (r == -1)
490       exit (EXIT_FAILURE);
491   }
492 }
493
494 static void
495 add_drives (struct drv *drv)
496 {
497   int r;
498
499   if (drv) {
500     add_drives (drv->next);
501     if (!read_only)
502       r = guestfs_add_drive (g, drv->filename);
503     else
504       r = guestfs_add_drive_ro (g, drv->filename);
505     if (r == -1)
506       exit (EXIT_FAILURE);
507   }
508 }
509
510 static void
511 interactive (void)
512 {
513   script (1);
514 }
515
516 static void
517 shell_script (void)
518 {
519   script (0);
520 }
521
522 #define FISH "><fs> "
523
524 static char *line_read = NULL;
525
526 static char *
527 rl_gets (int prompt)
528 {
529 #ifdef HAVE_LIBREADLINE
530
531   if (prompt) {
532     if (line_read) {
533       free (line_read);
534       line_read = NULL;
535     }
536
537     line_read = readline (prompt ? FISH : "");
538
539     if (line_read && *line_read)
540       add_history_line (line_read);
541
542     return line_read;
543   }
544
545 #endif /* HAVE_LIBREADLINE */
546
547   static char buf[8192];
548   int len;
549
550   if (prompt) printf (FISH);
551   line_read = fgets (buf, sizeof buf, stdin);
552
553   if (line_read) {
554     len = strlen (line_read);
555     if (len > 0 && buf[len-1] == '\n') buf[len-1] = '\0';
556   }
557
558   return line_read;
559 }
560
561 static void
562 script (int prompt)
563 {
564   char *buf;
565   char *cmd;
566   char *p, *pend;
567   char *argv[64];
568   int len;
569   int global_exit_on_error = !prompt;
570   int tilde_candidate;
571
572   if (prompt)
573     printf (_("\n"
574               "Welcome to guestfish, the libguestfs filesystem interactive shell for\n"
575               "editing virtual machine filesystems.\n"
576               "\n"
577               "Type: 'help' for help with commands\n"
578               "      'quit' to quit the shell\n"
579               "\n"));
580
581   while (!quit) {
582     char *pipe = NULL;
583
584     exit_on_error = global_exit_on_error;
585
586     buf = rl_gets (prompt);
587     if (!buf) {
588       quit = 1;
589       break;
590     }
591
592     /* Skip any initial whitespace before the command. */
593   again:
594     while (*buf && c_isspace (*buf))
595       buf++;
596
597     if (!*buf) continue;
598
599     /* If the next character is '#' then this is a comment. */
600     if (*buf == '#') continue;
601
602     /* If the next character is '!' then pass the whole lot to system(3). */
603     if (*buf == '!') {
604       int r;
605
606       r = system (buf+1);
607       if (exit_on_error) {
608         if (r == -1 ||
609             (WIFSIGNALED (r) &&
610              (WTERMSIG (r) == SIGINT || WTERMSIG (r) == SIGQUIT)) ||
611             WEXITSTATUS (r) != 0)
612           exit (EXIT_FAILURE);
613       }
614       continue;
615     }
616
617     /* If the next character is '-' allow the command to fail without
618      * exiting on error (just for this one command though).
619      */
620     if (*buf == '-') {
621       exit_on_error = 0;
622       buf++;
623       goto again;
624     }
625
626     /* Get the command (cannot be quoted). */
627     len = strcspn (buf, " \t");
628
629     if (len == 0) continue;
630
631     cmd = buf;
632     unsigned int i = 0;
633     if (buf[len] == '\0') {
634       argv[0] = NULL;
635       goto got_command;
636     }
637
638     buf[len] = '\0';
639     p = &buf[len+1];
640     p += strspn (p, " \t");
641
642     /* Get the parameters. */
643     while (*p && i < sizeof argv / sizeof argv[0]) {
644       tilde_candidate = 0;
645
646       /* Parameters which start with quotes or pipes are treated
647        * specially.  Bare parameters are delimited by whitespace.
648        */
649       if (*p == '"') {
650         p++;
651         len = strcspn (p, "\"");
652         if (p[len] == '\0') {
653           fprintf (stderr, _("%s: unterminated double quote\n"), program_name);
654           if (exit_on_error) exit (EXIT_FAILURE);
655           goto next_command;
656         }
657         if (p[len+1] && (p[len+1] != ' ' && p[len+1] != '\t')) {
658           fprintf (stderr,
659                    _("%s: command arguments not separated by whitespace\n"),
660                    program_name);
661           if (exit_on_error) exit (EXIT_FAILURE);
662           goto next_command;
663         }
664         p[len] = '\0';
665         pend = p[len+1] ? &p[len+2] : &p[len+1];
666       } else if (*p == '\'') {
667         p++;
668         len = strcspn (p, "'");
669         if (p[len] == '\0') {
670           fprintf (stderr, _("%s: unterminated single quote\n"), program_name);
671           if (exit_on_error) exit (EXIT_FAILURE);
672           goto next_command;
673         }
674         if (p[len+1] && (p[len+1] != ' ' && p[len+1] != '\t')) {
675           fprintf (stderr,
676                    _("%s: command arguments not separated by whitespace\n"),
677                    program_name);
678           if (exit_on_error) exit (EXIT_FAILURE);
679           goto next_command;
680         }
681         p[len] = '\0';
682         pend = p[len+1] ? &p[len+2] : &p[len+1];
683       } else if (*p == '|') {
684         *p = '\0';
685         pipe = p+1;
686         continue;
687         /*
688       } else if (*p == '[') {
689         int c = 1;
690         p++;
691         pend = p;
692         while (*pend && c != 0) {
693           if (*pend == '[') c++;
694           else if (*pend == ']') c--;
695           pend++;
696         }
697         if (c != 0) {
698           fprintf (stderr,
699                    _("%s: unterminated \"[...]\" sequence\n"), program_name);
700           if (exit_on_error) exit (EXIT_FAILURE);
701           goto next_command;
702         }
703         if (*pend && (*pend != ' ' && *pend != '\t')) {
704           fprintf (stderr,
705                    _("%s: command arguments not separated by whitespace\n"),
706                    program_name);
707           if (exit_on_error) exit (EXIT_FAILURE);
708           goto next_command;
709         }
710         *(pend-1) = '\0';
711         */
712       } else if (*p != ' ' && *p != '\t') {
713         /* If the first character is a ~ then note that this parameter
714          * is a candidate for ~username expansion.  NB this does not
715          * apply to quoted parameters.
716          */
717         tilde_candidate = *p == '~';
718         len = strcspn (p, " \t");
719         if (p[len]) {
720           p[len] = '\0';
721           pend = &p[len+1];
722         } else
723           pend = &p[len];
724       } else {
725         fprintf (stderr, _("%s: internal error parsing string at '%s'\n"),
726                  program_name, p);
727         abort ();
728       }
729
730       if (!tilde_candidate)
731         argv[i] = p;
732       else
733         argv[i] = try_tilde_expansion (p);
734       i++;
735       p = pend;
736
737       if (*p)
738         p += strspn (p, " \t");
739     }
740
741     if (i == sizeof argv / sizeof argv[0]) {
742       fprintf (stderr, _("%s: too many arguments\n"), program_name);
743       if (exit_on_error) exit (EXIT_FAILURE);
744       goto next_command;
745     }
746
747     argv[i] = NULL;
748
749   got_command:
750     if (issue_command (cmd, argv, pipe) == -1) {
751       if (exit_on_error) exit (EXIT_FAILURE);
752     }
753
754   next_command:;
755   }
756   if (prompt) printf ("\n");
757 }
758
759 static void
760 cmdline (char *argv[], int optind, int argc)
761 {
762   const char *cmd;
763   char **params;
764
765   exit_on_error = 1;
766
767   if (optind >= argc) return;
768
769   cmd = argv[optind++];
770   if (STREQ (cmd, ":")) {
771     fprintf (stderr, _("%s: empty command on command line\n"), program_name);
772     exit (EXIT_FAILURE);
773   }
774
775   /* Allow -cmd on the command line to mean (temporarily) override
776    * the normal exit on error (RHBZ#578407).
777    */
778   if (cmd[0] == '-') {
779     exit_on_error = 0;
780     cmd++;
781   }
782
783   params = &argv[optind];
784
785   /* Search for end of command list or ":" ... */
786   while (optind < argc && STRNEQ (argv[optind], ":"))
787     optind++;
788
789   if (optind == argc) {
790     if (issue_command (cmd, params, NULL) == -1 && exit_on_error)
791         exit (EXIT_FAILURE);
792   } else {
793     argv[optind] = NULL;
794     if (issue_command (cmd, params, NULL) == -1 && exit_on_error)
795       exit (EXIT_FAILURE);
796     cmdline (argv, optind+1, argc);
797   }
798 }
799
800 int
801 issue_command (const char *cmd, char *argv[], const char *pipecmd)
802 {
803   int argc;
804   int stdout_saved_fd = -1;
805   int pid = 0;
806   int i, r;
807
808   /* This counts the commands issued, starting at 1. */
809   command_num++;
810
811   /* For | ... commands.  Annoyingly we can't use popen(3) here. */
812   if (pipecmd) {
813     int fd[2];
814
815     if (fflush (stdout) == EOF) {
816       perror ("failed to flush standard output");
817       return -1;
818     }
819     if (pipe (fd) < 0) {
820       perror ("pipe failed");
821       return -1;
822     }
823     pid = fork ();
824     if (pid == -1) {
825       perror ("fork");
826       return -1;
827     }
828
829     if (pid == 0) {             /* Child process. */
830       close (fd[1]);
831       if (dup2 (fd[0], 0) < 0) {
832         perror ("dup2 of stdin failed");
833         _exit (1);
834       }
835
836       r = system (pipecmd);
837       if (r == -1) {
838         perror (pipecmd);
839         _exit (1);
840       }
841       _exit (WEXITSTATUS (r));
842     }
843
844     if ((stdout_saved_fd = dup (1)) < 0) {
845       perror ("failed to dup stdout");
846       return -1;
847     }
848     close (fd[0]);
849     if (dup2 (fd[1], 1) < 0) {
850       perror ("failed to dup stdout");
851       close (stdout_saved_fd);
852       return -1;
853     }
854     close (fd[1]);
855   }
856
857   for (argc = 0; argv[argc] != NULL; ++argc)
858     ;
859
860   /* If --remote was set, then send this command to a remote process. */
861   if (remote_control)
862     r = rc_remote (remote_control, cmd, argc, argv, exit_on_error);
863
864   /* Otherwise execute it locally. */
865   else if (STRCASEEQ (cmd, "help")) {
866     if (argc == 0)
867       list_commands ();
868     else
869       display_command (argv[0]);
870     r = 0;
871   }
872   else if (STRCASEEQ (cmd, "quit") ||
873            STRCASEEQ (cmd, "exit") ||
874            STRCASEEQ (cmd, "q")) {
875     quit = 1;
876     r = 0;
877   }
878   else if (STRCASEEQ (cmd, "alloc") ||
879            STRCASEEQ (cmd, "allocate"))
880     r = do_alloc (cmd, argc, argv);
881   else if (STRCASEEQ (cmd, "echo"))
882     r = do_echo (cmd, argc, argv);
883   else if (STRCASEEQ (cmd, "edit") ||
884            STRCASEEQ (cmd, "vi") ||
885            STRCASEEQ (cmd, "emacs"))
886     r = do_edit (cmd, argc, argv);
887   else if (STRCASEEQ (cmd, "lcd"))
888     r = do_lcd (cmd, argc, argv);
889   else if (STRCASEEQ (cmd, "glob"))
890     r = do_glob (cmd, argc, argv);
891   else if (STRCASEEQ (cmd, "more") ||
892            STRCASEEQ (cmd, "less"))
893     r = do_more (cmd, argc, argv);
894   else if (STRCASEEQ (cmd, "reopen"))
895     r = do_reopen (cmd, argc, argv);
896   else if (STRCASEEQ (cmd, "sparse"))
897     r = do_sparse (cmd, argc, argv);
898   else if (STRCASEEQ (cmd, "time"))
899     r = do_time (cmd, argc, argv);
900   else
901     r = run_action (cmd, argc, argv);
902
903   /* Always flush stdout after every command, so that messages, results
904    * etc appear immediately.
905    */
906   if (fflush (stdout) == EOF) {
907     perror ("failed to flush standard output");
908     return -1;
909   }
910
911   if (pipecmd) {
912     close (1);
913     if (dup2 (stdout_saved_fd, 1) < 0) {
914       perror ("failed to dup2 standard output");
915       r = -1;
916     }
917     close (stdout_saved_fd);
918     if (waitpid (pid, NULL, 0) < 0) {
919       perror ("waiting for command to complete");
920       r = -1;
921     }
922   }
923
924   return r;
925 }
926
927 void
928 list_builtin_commands (void)
929 {
930   /* help and quit should appear at the top */
931   printf ("%-20s %s\n",
932           "help", _("display a list of commands or help on a command"));
933   printf ("%-20s %s\n",
934           "quit", _("quit guestfish"));
935
936   printf ("%-20s %s\n",
937           "alloc", _("allocate an image"));
938   printf ("%-20s %s\n",
939           "echo", _("display a line of text"));
940   printf ("%-20s %s\n",
941           "edit", _("edit a file in the image"));
942   printf ("%-20s %s\n",
943           "lcd", _("local change directory"));
944   printf ("%-20s %s\n",
945           "glob", _("expand wildcards in command"));
946   printf ("%-20s %s\n",
947           "more", _("view a file in the pager"));
948   printf ("%-20s %s\n",
949           "reopen", _("close and reopen libguestfs handle"));
950   printf ("%-20s %s\n",
951           "sparse", _("allocate a sparse image file"));
952   printf ("%-20s %s\n",
953           "time", _("measure time taken to run command"));
954
955   /* actions are printed after this (see list_commands) */
956 }
957
958 void
959 display_builtin_command (const char *cmd)
960 {
961   /* help for actions is auto-generated, see display_command */
962
963   if (STRCASEEQ (cmd, "alloc") ||
964       STRCASEEQ (cmd, "allocate"))
965     printf (_("alloc - allocate an image\n"
966               "     alloc <filename> <size>\n"
967               "\n"
968               "    This creates an empty (zeroed) file of the given size,\n"
969               "    and then adds so it can be further examined.\n"
970               "\n"
971               "    For more advanced image creation, see qemu-img utility.\n"
972               "\n"
973               "    Size can be specified (where <nn> means a number):\n"
974               "    <nn>             number of kilobytes\n"
975               "      eg: 1440       standard 3.5\" floppy\n"
976               "    <nn>K or <nn>KB  number of kilobytes\n"
977               "    <nn>M or <nn>MB  number of megabytes\n"
978               "    <nn>G or <nn>GB  number of gigabytes\n"
979               "    <nn>T or <nn>TB  number of terabytes\n"
980               "    <nn>P or <nn>PB  number of petabytes\n"
981               "    <nn>E or <nn>EB  number of exabytes\n"
982               "    <nn>sects        number of 512 byte sectors\n"));
983   else if (STRCASEEQ (cmd, "echo"))
984     printf (_("echo - display a line of text\n"
985               "     echo [<params> ...]\n"
986               "\n"
987               "    This echos the parameters to the terminal.\n"));
988   else if (STRCASEEQ (cmd, "edit") ||
989            STRCASEEQ (cmd, "vi") ||
990            STRCASEEQ (cmd, "emacs"))
991     printf (_("edit - edit a file in the image\n"
992               "     edit <filename>\n"
993               "\n"
994               "    This is used to edit a file.\n"
995               "\n"
996               "    It is the equivalent of (and is implemented by)\n"
997               "    running \"cat\", editing locally, and then \"write-file\".\n"
998               "\n"
999               "    Normally it uses $EDITOR, but if you use the aliases\n"
1000               "    \"vi\" or \"emacs\" you will get those editors.\n"
1001               "\n"
1002               "    NOTE: This will not work reliably for large files\n"
1003               "    (> 2 MB) or binary files containing \\0 bytes.\n"));
1004   else if (STRCASEEQ (cmd, "lcd"))
1005     printf (_("lcd - local change directory\n"
1006               "    lcd <directory>\n"
1007               "\n"
1008               "    Change guestfish's current directory. This command is\n"
1009               "    useful if you want to download files to a particular\n"
1010               "    place.\n"));
1011   else if (STRCASEEQ (cmd, "glob"))
1012     printf (_("glob - expand wildcards in command\n"
1013               "    glob <command> [<args> ...]\n"
1014               "\n"
1015               "    Glob runs <command> with wildcards expanded in any\n"
1016               "    command args.  Note that the command is run repeatedly\n"
1017               "    once for each expanded argument.\n"));
1018   else if (STRCASEEQ (cmd, "help"))
1019     printf (_("help - display a list of commands or help on a command\n"
1020               "     help cmd\n"
1021               "     help\n"));
1022   else if (STRCASEEQ (cmd, "more") ||
1023            STRCASEEQ (cmd, "less"))
1024     printf (_("more - view a file in the pager\n"
1025               "     more <filename>\n"
1026               "\n"
1027               "    This is used to view a file in the pager.\n"
1028               "\n"
1029               "    It is the equivalent of (and is implemented by)\n"
1030               "    running \"cat\" and using the pager.\n"
1031               "\n"
1032               "    Normally it uses $PAGER, but if you use the alias\n"
1033               "    \"less\" then it always uses \"less\".\n"
1034               "\n"
1035               "    NOTE: This will not work reliably for large files\n"
1036               "    (> 2 MB) or binary files containing \\0 bytes.\n"));
1037   else if (STRCASEEQ (cmd, "quit") ||
1038            STRCASEEQ (cmd, "exit") ||
1039            STRCASEEQ (cmd, "q"))
1040     printf (_("quit - quit guestfish\n"
1041               "     quit\n"));
1042   else if (STRCASEEQ (cmd, "reopen"))
1043     printf (_("reopen - close and reopen the libguestfs handle\n"
1044               "     reopen\n"
1045               "\n"
1046               "Close and reopen the libguestfs handle.  It is not necessary to use\n"
1047               "this normally, because the handle is closed properly when guestfish\n"
1048               "exits.  However this is occasionally useful for testing.\n"));
1049   else if (STRCASEEQ (cmd, "sparse"))
1050     printf (_("sparse - allocate a sparse image file\n"
1051               "     sparse <filename> <size>\n"
1052               "\n"
1053               "    This creates an empty sparse file of the given size,\n"
1054               "    and then adds so it can be further examined.\n"
1055               "\n"
1056               "    In all respects it works the same as the 'alloc'\n"
1057               "    command, except that the image file is allocated\n"
1058               "    sparsely, which means that disk blocks are not assigned\n"
1059               "    to the file until they are needed.  Sparse disk files\n"
1060               "    only use space when written to, but they are slower\n"
1061               "    and there is a danger you could run out of real disk\n"
1062               "    space during a write operation.\n"
1063               "\n"
1064               "    For more advanced image creation, see qemu-img utility.\n"
1065               "\n"
1066               "    Size can be specified (where <nn> means a number):\n"
1067               "    <nn>             number of kilobytes\n"
1068               "      eg: 1440       standard 3.5\" floppy\n"
1069               "    <nn>K or <nn>KB  number of kilobytes\n"
1070               "    <nn>M or <nn>MB  number of megabytes\n"
1071               "    <nn>G or <nn>GB  number of gigabytes\n"
1072               "    <nn>T or <nn>TB  number of terabytes\n"
1073               "    <nn>P or <nn>PB  number of petabytes\n"
1074               "    <nn>E or <nn>EB  number of exabytes\n"
1075               "    <nn>sects        number of 512 byte sectors\n"));
1076   else if (STRCASEEQ (cmd, "time"))
1077     printf (_("time - measure time taken to run command\n"
1078               "    time <command> [<args> ...]\n"
1079               "\n"
1080               "    This runs <command> as usual, and prints the elapsed\n"
1081               "    time afterwards.\n"));
1082   else
1083     fprintf (stderr, _("%s: command not known, use -h to list all commands\n"),
1084              cmd);
1085 }
1086
1087 /* This is printed when the user types in an unknown command for the
1088  * first command issued.  A common case is the user doing:
1089  *   guestfish disk.img
1090  * expecting guestfish to open 'disk.img' (in fact, this tried to
1091  * run a command 'disk.img').
1092  */
1093 void
1094 extended_help_message (void)
1095 {
1096   fprintf (stderr,
1097            _("Did you mean to open a disk image?  guestfish -a disk.img\n"
1098              "For a list of commands:             guestfish -h\n"
1099              "For complete documentation:         man guestfish\n"));
1100 }
1101
1102 void
1103 free_strings (char **argv)
1104 {
1105   int argc;
1106
1107   for (argc = 0; argv[argc] != NULL; ++argc)
1108     free (argv[argc]);
1109   free (argv);
1110 }
1111
1112 int
1113 count_strings (char *const *argv)
1114 {
1115   int c;
1116
1117   for (c = 0; argv[c]; ++c)
1118     ;
1119   return c;
1120 }
1121
1122 void
1123 print_strings (char *const *argv)
1124 {
1125   int argc;
1126
1127   for (argc = 0; argv[argc] != NULL; ++argc)
1128     printf ("%s\n", argv[argc]);
1129 }
1130
1131 void
1132 print_table (char *const *argv)
1133 {
1134   int i;
1135
1136   for (i = 0; argv[i] != NULL; i += 2)
1137     printf ("%s: %s\n", argv[i], argv[i+1]);
1138 }
1139
1140 int
1141 is_true (const char *str)
1142 {
1143   return
1144     STRCASENEQ (str, "0") &&
1145     STRCASENEQ (str, "f") &&
1146     STRCASENEQ (str, "false") &&
1147     STRCASENEQ (str, "n") &&
1148     STRCASENEQ (str, "no");
1149 }
1150
1151 /* Free strings from a non-NULL terminated char** */
1152 static void
1153 free_n_strings (char **str, size_t len)
1154 {
1155   size_t i;
1156
1157   for (i = 0; i < len; i++) {
1158     free (str[i]);
1159   }
1160   free (str);
1161 }
1162
1163 char **
1164 parse_string_list (const char *str)
1165 {
1166   char **argv = NULL;
1167   size_t argv_len = 0;
1168
1169   /* Current position pointer */
1170   const char *p = str;
1171
1172   /* Token might be simple:
1173    *  Token
1174    * or be quoted:
1175    *  'This is a single token'
1176    * or contain embedded single-quoted sections:
1177    *  This' is a sing'l'e to'ken
1178    *
1179    * The latter may seem over-complicated, but it's what a normal shell does.
1180    * Not doing it risks surprising somebody.
1181    *
1182    * This outer loop is over complete tokens.
1183    */
1184   while (*p) {
1185     char *tok = NULL;
1186     size_t tok_len = 0;
1187
1188     /* Skip leading whitespace */
1189     p += strspn (p, " \t");
1190
1191     char in_quote = 0;
1192
1193     /* This loop is over token 'fragments'. A token can be in multiple bits if
1194      * it contains single quotes. We also treat both sides of an escaped quote
1195      * as separate fragments because we can't just copy it: we have to remove
1196      * the \.
1197      */
1198     while (*p && (!c_isblank (*p) || in_quote)) {
1199       const char *end = p;
1200
1201       /* Check if the fragment starts with a quote */
1202       if ('\'' == *p) {
1203         /* Toggle in_quote */
1204         in_quote = !in_quote;
1205
1206         /* Skip the quote */
1207         p++; end++;
1208       }
1209
1210       /* If we're in a quote, look for an end quote */
1211       if (in_quote) {
1212         end += strcspn (end, "'");
1213       }
1214
1215       /* Otherwise, look for whitespace or a quote */
1216       else {
1217         end += strcspn (end, " \t'");
1218       }
1219
1220       /* Grow the token to accommodate the fragment */
1221       size_t tok_end = tok_len;
1222       tok_len += end - p;
1223       char *tok_new = realloc (tok, tok_len + 1);
1224       if (NULL == tok_new) {
1225         perror ("realloc");
1226         free_n_strings (argv, argv_len);
1227         free (tok);
1228         exit (EXIT_FAILURE);
1229       }
1230       tok = tok_new;
1231
1232       /* Check if we stopped on an escaped quote */
1233       if ('\'' == *end && end != p && *(end-1) == '\\') {
1234         /* Add everything before \' to the token */
1235         memcpy (&tok[tok_end], p, end - p - 1);
1236
1237         /* Add the quote */
1238         tok[tok_len-1] = '\'';
1239
1240         /* Already processed the quote */
1241         p = end + 1;
1242       }
1243
1244       else {
1245         /* Add the whole fragment */
1246         memcpy (&tok[tok_end], p, end - p);
1247
1248         p = end;
1249       }
1250     }
1251
1252     /* We've reached the end of a token. We shouldn't still be in quotes. */
1253     if (in_quote) {
1254       fprintf (stderr, _("Runaway quote in string \"%s\"\n"), str);
1255
1256       free_n_strings (argv, argv_len);
1257
1258       return NULL;
1259     }
1260
1261     /* Add this token if there is one. There might not be if there was
1262      * whitespace at the end of the input string */
1263     if (tok) {
1264       /* Add the NULL terminator */
1265       tok[tok_len] = '\0';
1266
1267       /* Add the argument to the argument list */
1268       argv_len++;
1269       char **argv_new = realloc (argv, sizeof (*argv) * argv_len);
1270       if (NULL == argv_new) {
1271         perror ("realloc");
1272         free_n_strings (argv, argv_len-1);
1273         free (tok);
1274         exit (EXIT_FAILURE);
1275       }
1276       argv = argv_new;
1277
1278       argv[argv_len-1] = tok;
1279     }
1280   }
1281
1282   /* NULL terminate the argument list */
1283   argv_len++;
1284   char **argv_new = realloc (argv, sizeof (*argv) * argv_len);
1285   if (NULL == argv_new) {
1286     perror ("realloc");
1287     free_n_strings (argv, argv_len-1);
1288     exit (EXIT_FAILURE);
1289   }
1290   argv = argv_new;
1291
1292   argv[argv_len-1] = NULL;
1293
1294   return argv;
1295 }
1296
1297 #ifdef HAVE_LIBREADLINE
1298 static char histfile[1024];
1299 static int nr_history_lines = 0;
1300 #endif
1301
1302 static void
1303 initialize_readline (void)
1304 {
1305 #ifdef HAVE_LIBREADLINE
1306   const char *home;
1307
1308   home = getenv ("HOME");
1309   if (home) {
1310     snprintf (histfile, sizeof histfile, "%s/.guestfish", home);
1311     using_history ();
1312     (void) read_history (histfile);
1313   }
1314
1315   rl_readline_name = "guestfish";
1316   rl_attempted_completion_function = do_completion;
1317 #endif
1318 }
1319
1320 static void
1321 cleanup_readline (void)
1322 {
1323 #ifdef HAVE_LIBREADLINE
1324   int fd;
1325
1326   if (histfile[0] != '\0') {
1327     fd = open (histfile, O_WRONLY|O_CREAT, 0644);
1328     if (fd == -1) {
1329       perror (histfile);
1330       return;
1331     }
1332     close (fd);
1333
1334 #ifdef HAVE_APPEND_HISTORY
1335     (void) append_history (nr_history_lines, histfile);
1336 #else
1337     (void) write_history (histfile);
1338 #endif
1339   }
1340 #endif
1341 }
1342
1343 #ifdef HAVE_LIBREADLINE
1344 static void
1345 add_history_line (const char *line)
1346 {
1347   add_history (line);
1348   nr_history_lines++;
1349 }
1350 #endif
1351
1352 int
1353 xwrite (int fd, const void *v_buf, size_t len)
1354 {
1355   int r;
1356   const char *buf = v_buf;
1357
1358   while (len > 0) {
1359     r = write (fd, buf, len);
1360     if (r == -1) {
1361       perror ("write");
1362       return -1;
1363     }
1364     buf += r;
1365     len -= r;
1366   }
1367
1368   return 0;
1369 }
1370
1371 /* Resolve the special "win:..." form for Windows-specific paths.
1372  * This always returns a newly allocated string which is freed by the
1373  * caller function in "cmds.c".
1374  */
1375 char *
1376 resolve_win_path (const char *path)
1377 {
1378   char *ret;
1379   size_t i;
1380
1381   if (STRCASENEQLEN (path, "win:", 4)) {
1382     ret = strdup (path);
1383     if (ret == NULL)
1384       perror ("strdup");
1385     return ret;
1386   }
1387
1388   path += 4;
1389
1390   /* Drop drive letter, if it's "C:". */
1391   if (STRCASEEQLEN (path, "c:", 2))
1392     path += 2;
1393
1394   if (!*path) {
1395     ret = strdup ("/");
1396     if (ret == NULL)
1397       perror ("strdup");
1398     return ret;
1399   }
1400
1401   ret = strdup (path);
1402   if (ret == NULL) {
1403     perror ("strdup");
1404     return NULL;
1405   }
1406
1407   /* Blindly convert any backslashes into forward slashes.  Is this good? */
1408   for (i = 0; i < strlen (ret); ++i)
1409     if (ret[i] == '\\')
1410       ret[i] = '/';
1411
1412   char *t = guestfs_case_sensitive_path (g, ret);
1413   free (ret);
1414   ret = t;
1415
1416   return ret;
1417 }