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