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