156147a3ae0448cb1258a977da7f5f644302e185
[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 #define _GNU_SOURCE // for strchrnul
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <getopt.h>
29 #include <signal.h>
30 #include <assert.h>
31 #include <ctype.h>
32 #include <sys/types.h>
33 #include <sys/wait.h>
34
35 #ifdef HAVE_LIBREADLINE
36 #include <readline/readline.h>
37 #include <readline/history.h>
38 #endif
39
40 #include <guestfs.h>
41
42 #include "fish.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
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     if (guestfs_wait_ready (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   enum { HELP_OPTION = CHAR_MAX + 1 };
144
145   static const char *options = "a:Df:h::im:nrv?Vx";
146   static const struct option long_options[] = {
147     { "add", 1, 0, 'a' },
148     { "cmd-help", 2, 0, 'h' },
149     { "file", 1, 0, 'f' },
150     { "help", 0, 0, HELP_OPTION },
151     { "inspector", 0, 0, 'i' },
152     { "listen", 0, 0, 0 },
153     { "mount", 1, 0, 'm' },
154     { "no-dest-paths", 0, 0, 'D' },
155     { "no-sync", 0, 0, 'n' },
156     { "remote", 2, 0, 0 },
157     { "ro", 0, 0, 'r' },
158     { "selinux", 0, 0, 0 },
159     { "verbose", 0, 0, 'v' },
160     { "version", 0, 0, 'V' },
161     { 0, 0, 0, 0 }
162   };
163   struct drv *drvs = NULL;
164   struct drv *drv;
165   struct mp *mps = NULL;
166   struct mp *mp;
167   char *p, *file = NULL;
168   int c;
169   int inspector = 0;
170   int option_index;
171   struct sigaction sa;
172
173   initialize_readline ();
174
175   memset (&sa, 0, sizeof sa);
176   sa.sa_handler = SIG_IGN;
177   sa.sa_flags = SA_RESTART;
178   sigaction (SIGPIPE, &sa, NULL);
179
180   /* guestfs_create is meant to be a lightweight operation, so
181    * it's OK to do it early here.
182    */
183   g = guestfs_create ();
184   if (g == NULL) {
185     fprintf (stderr, _("guestfs_create: failed to create handle\n"));
186     exit (1);
187   }
188
189   guestfs_set_autosync (g, 1);
190
191   /* If developing, add ./appliance to the path.  Note that libtools
192    * interferes with this because uninstalled guestfish is a shell
193    * script that runs the real program with an absolute path.  Detect
194    * that too.
195    *
196    * BUT if LIBGUESTFS_PATH environment variable is already set by
197    * the user, then don't override it.
198    */
199   if (getenv ("LIBGUESTFS_PATH") == NULL &&
200       argv[0] &&
201       (argv[0][0] != '/' || strstr (argv[0], "/.libs/lt-") != NULL))
202     guestfs_set_path (g, "appliance:" GUESTFS_DEFAULT_PATH);
203
204   /* CAUTION: we are careful to modify argv[0] here, only after
205    * using it just above.
206    *
207    * getopt_long uses argv[0], so give it the sanitized name.  Save a copy
208    * of the original, in case it's needed in virt-inspector mode, below.
209    */
210   char *real_argv0 = argv[0];
211   argv[0] = bad_cast (program_name);
212
213   for (;;) {
214     c = getopt_long (argc, argv, options, long_options, &option_index);
215     if (c == -1) break;
216
217     switch (c) {
218     case 0:                     /* options which are long only */
219       if (strcmp (long_options[option_index].name, "listen") == 0)
220         remote_control_listen = 1;
221       else if (strcmp (long_options[option_index].name, "remote") == 0) {
222         if (optarg) {
223           if (sscanf (optarg, "%d", &remote_control) != 1) {
224             fprintf (stderr, _("%s: --listen=PID: PID was not a number: %s\n"),
225                      program_name, optarg);
226             exit (1);
227           }
228         } else {
229           p = getenv ("GUESTFISH_PID");
230           if (!p || sscanf (p, "%d", &remote_control) != 1) {
231             fprintf (stderr, _("%s: remote: $GUESTFISH_PID must be set"
232                                " to the PID of the remote process\n"),
233                      program_name);
234             exit (1);
235           }
236         }
237       } else if (strcmp (long_options[option_index].name, "selinux") == 0) {
238         guestfs_set_selinux (g, 1);
239       } else {
240         fprintf (stderr, _("%s: unknown long option: %s (%d)\n"),
241                  program_name, long_options[option_index].name, option_index);
242         exit (1);
243       }
244       break;
245
246     case 'a':
247       if (access (optarg, R_OK) != 0) {
248         perror (optarg);
249         exit (1);
250       }
251       drv = malloc (sizeof (struct drv));
252       if (!drv) {
253         perror ("malloc");
254         exit (1);
255       }
256       drv->filename = optarg;
257       drv->next = drvs;
258       drvs = drv;
259       break;
260
261     case 'D':
262       complete_dest_paths = 0;
263       break;
264
265     case 'f':
266       if (file) {
267         fprintf (stderr, _("%s: only one -f parameter can be given\n"),
268                  program_name);
269         exit (1);
270       }
271       file = optarg;
272       break;
273
274     case 'h':
275       if (optarg)
276         display_command (optarg);
277       else if (argv[optind] && argv[optind][0] != '-')
278         display_command (argv[optind++]);
279       else
280         list_commands ();
281       exit (0);
282
283     case 'i':
284       inspector = 1;
285       break;
286
287     case 'm':
288       mp = malloc (sizeof (struct mp));
289       if (!mp) {
290         perror ("malloc");
291         exit (1);
292       }
293       p = strchr (optarg, ':');
294       if (p) {
295         *p = '\0';
296         mp->mountpoint = p+1;
297       } else
298         mp->mountpoint = bad_cast ("/");
299       mp->device = optarg;
300       mp->next = mps;
301       mps = mp;
302       break;
303
304     case 'n':
305       guestfs_set_autosync (g, 0);
306       break;
307
308     case 'r':
309       read_only = 1;
310       break;
311
312     case 'v':
313       verbose++;
314       guestfs_set_verbose (g, verbose);
315       break;
316
317     case 'V':
318       printf ("%s %s\n", program_name, PACKAGE_VERSION);
319       exit (0);
320
321     case 'x':
322       echo_commands = 1;
323       break;
324
325     case HELP_OPTION:
326       usage (0);
327
328     default:
329       usage (1);
330     }
331   }
332
333   /* Inspector mode invalidates most of the other arguments. */
334   if (inspector) {
335     char cmd[1024];
336     int r;
337
338     if (drvs || mps || remote_control_listen || remote_control ||
339         guestfs_get_selinux (g)) {
340       fprintf (stderr, _("%s: cannot use -i option with -a, -m,"
341                          " --listen, --remote or --selinux\n"),
342                program_name);
343       exit (1);
344     }
345     if (optind >= argc) {
346       fprintf (stderr,
347            _("%s: -i requires a libvirt domain or path(s) to disk image(s)\n"),
348                program_name);
349       exit (1);
350     }
351
352     strcpy (cmd, "a=`virt-inspector");
353     while (optind < argc) {
354       if (strlen (cmd) + strlen (argv[optind]) + strlen (real_argv0) + 60
355           >= sizeof cmd) {
356         fprintf (stderr,
357                  _("%s: virt-inspector command too long for fixed-size buffer\n"),
358                  program_name);
359         exit (1);
360       }
361       strcat (cmd, " '");
362       strcat (cmd, argv[optind]);
363       strcat (cmd, "'");
364       optind++;
365     }
366
367     if (read_only)
368       strcat (cmd, " --ro-fish");
369     else
370       strcat (cmd, " --fish");
371
372     sprintf (&cmd[strlen(cmd)], "` && %s $a", real_argv0);
373
374     if (guestfs_get_verbose (g))
375       strcat (cmd, " -v");
376     if (!guestfs_get_autosync (g))
377       strcat (cmd, " -n");
378
379     if (verbose)
380       fprintf (stderr,
381                "%s -i: running virt-inspector command:\n%s\n", program_name, cmd);
382
383     r = system (cmd);
384     if (r == -1) {
385       perror ("system");
386       exit (1);
387     }
388     exit (WEXITSTATUS (r));
389   }
390
391   /* If we've got drives to add, add them now. */
392   add_drives (drvs);
393
394   /* If we've got mountpoints, we must launch the guest and mount them. */
395   if (mps != NULL) {
396     if (launch (g) == -1) exit (1);
397     mount_mps (mps);
398   }
399
400   /* Remote control? */
401   if (remote_control_listen && remote_control) {
402     fprintf (stderr,
403              _("%s: cannot use --listen and --remote options at the same time\n"),
404              program_name);
405     exit (1);
406   }
407
408   if (remote_control_listen) {
409     if (optind < argc) {
410       fprintf (stderr,
411                _("%s: extra parameters on the command line with --listen flag\n"),
412                program_name);
413       exit (1);
414     }
415     if (file) {
416       fprintf (stderr,
417                _("%s: cannot use --listen and --file options at the same time\n"),
418                program_name);
419       exit (1);
420     }
421     rc_listen ();
422   }
423
424   /* -f (file) parameter? */
425   if (file) {
426     close (0);
427     if (open (file, O_RDONLY) == -1) {
428       perror (file);
429       exit (1);
430     }
431   }
432
433   /* Interactive, shell script, or command(s) on the command line? */
434   if (optind >= argc) {
435     if (isatty (0))
436       interactive ();
437     else
438       shell_script ();
439   }
440   else
441     cmdline (argv, optind, argc);
442
443   cleanup_readline ();
444
445   exit (0);
446 }
447
448 void
449 pod2text (const char *name, const char *shortdesc, const char *str)
450 {
451   FILE *fp;
452
453   fp = popen ("pod2text", "w");
454   if (fp == NULL) {
455     /* pod2text failed, maybe not found, so let's just print the
456      * source instead, since that's better than doing nothing.
457      */
458     printf ("%s - %s\n\n%s\n", name, shortdesc, str);
459     return;
460   }
461   fprintf (fp, "=head1 %s - %s\n\n", name, shortdesc);
462   fputs (str, fp);
463   pclose (fp);
464 }
465
466 /* List is built in reverse order, so mount them in reverse order. */
467 static void
468 mount_mps (struct mp *mp)
469 {
470   int r;
471
472   if (mp) {
473     mount_mps (mp->next);
474     if (!read_only)
475       r = guestfs_mount (g, mp->device, mp->mountpoint);
476     else
477       r = guestfs_mount_ro (g, mp->device, mp->mountpoint);
478     if (r == -1)
479       exit (1);
480   }
481 }
482
483 static void
484 add_drives (struct drv *drv)
485 {
486   int r;
487
488   if (drv) {
489     add_drives (drv->next);
490     if (!read_only)
491       r = guestfs_add_drive (g, drv->filename);
492     else
493       r = guestfs_add_drive_ro (g, drv->filename);
494     if (r == -1)
495       exit (1);
496   }
497 }
498
499 static void
500 interactive (void)
501 {
502   script (1);
503 }
504
505 static void
506 shell_script (void)
507 {
508   script (0);
509 }
510
511 #define FISH "><fs> "
512
513 static char *line_read = NULL;
514
515 static char *
516 rl_gets (int prompt)
517 {
518 #ifdef HAVE_LIBREADLINE
519
520   if (prompt) {
521     if (line_read) {
522       free (line_read);
523       line_read = NULL;
524     }
525
526     line_read = readline (prompt ? FISH : "");
527
528     if (line_read && *line_read)
529       add_history_line (line_read);
530
531     return line_read;
532   }
533
534 #endif /* HAVE_LIBREADLINE */
535
536   static char buf[8192];
537   int len;
538
539   if (prompt) printf (FISH);
540   line_read = fgets (buf, sizeof buf, stdin);
541
542   if (line_read) {
543     len = strlen (line_read);
544     if (len > 0 && buf[len-1] == '\n') buf[len-1] = '\0';
545   }
546
547   return line_read;
548 }
549
550 static void
551 script (int prompt)
552 {
553   char *buf;
554   char *cmd;
555   char *p, *pend;
556   char *argv[64];
557   int len;
558   int global_exit_on_error = !prompt;
559   int tilde_candidate;
560
561   if (prompt)
562     printf (_("\n"
563               "Welcome to guestfish, the libguestfs filesystem interactive shell for\n"
564               "editing virtual machine filesystems.\n"
565               "\n"
566               "Type: 'help' for help with commands\n"
567               "      'quit' to quit the shell\n"
568               "\n"));
569
570   while (!quit) {
571     char *pipe = NULL;
572
573     exit_on_error = global_exit_on_error;
574
575     buf = rl_gets (prompt);
576     if (!buf) {
577       quit = 1;
578       break;
579     }
580
581     /* Skip any initial whitespace before the command. */
582   again:
583     while (*buf && isspace (*buf))
584       buf++;
585
586     if (!*buf) continue;
587
588     /* If the next character is '#' then this is a comment. */
589     if (*buf == '#') continue;
590
591     /* If the next character is '!' then pass the whole lot to system(3). */
592     if (*buf == '!') {
593       int r;
594
595       r = system (buf+1);
596       if (exit_on_error) {
597         if (r == -1 ||
598             (WIFSIGNALED (r) &&
599              (WTERMSIG (r) == SIGINT || WTERMSIG (r) == SIGQUIT)) ||
600             WEXITSTATUS (r) != 0)
601           exit (1);
602       }
603       continue;
604     }
605
606     /* If the next character is '-' allow the command to fail without
607      * exiting on error (just for this one command though).
608      */
609     if (*buf == '-') {
610       exit_on_error = 0;
611       buf++;
612       goto again;
613     }
614
615     /* Get the command (cannot be quoted). */
616     len = strcspn (buf, " \t");
617
618     if (len == 0) continue;
619
620     cmd = buf;
621     unsigned int i = 0;
622     if (buf[len] == '\0') {
623       argv[0] = NULL;
624       goto got_command;
625     }
626
627     buf[len] = '\0';
628     p = &buf[len+1];
629     p += strspn (p, " \t");
630
631     /* Get the parameters. */
632     while (*p && i < sizeof argv / sizeof argv[0]) {
633       tilde_candidate = 0;
634
635       /* Parameters which start with quotes or pipes are treated
636        * specially.  Bare parameters are delimited by whitespace.
637        */
638       if (*p == '"') {
639         p++;
640         len = strcspn (p, "\"");
641         if (p[len] == '\0') {
642           fprintf (stderr, _("%s: unterminated double quote\n"), program_name);
643           if (exit_on_error) exit (1);
644           goto next_command;
645         }
646         if (p[len+1] && (p[len+1] != ' ' && p[len+1] != '\t')) {
647           fprintf (stderr,
648                    _("%s: command arguments not separated by whitespace\n"),
649                    program_name);
650           if (exit_on_error) exit (1);
651           goto next_command;
652         }
653         p[len] = '\0';
654         pend = p[len+1] ? &p[len+2] : &p[len+1];
655       } else if (*p == '\'') {
656         p++;
657         len = strcspn (p, "'");
658         if (p[len] == '\0') {
659           fprintf (stderr, _("%s: unterminated single quote\n"), program_name);
660           if (exit_on_error) exit (1);
661           goto next_command;
662         }
663         if (p[len+1] && (p[len+1] != ' ' && p[len+1] != '\t')) {
664           fprintf (stderr,
665                    _("%s: command arguments not separated by whitespace\n"),
666                    program_name);
667           if (exit_on_error) exit (1);
668           goto next_command;
669         }
670         p[len] = '\0';
671         pend = p[len+1] ? &p[len+2] : &p[len+1];
672       } else if (*p == '|') {
673         *p = '\0';
674         pipe = p+1;
675         continue;
676         /*
677       } else if (*p == '[') {
678         int c = 1;
679         p++;
680         pend = p;
681         while (*pend && c != 0) {
682           if (*pend == '[') c++;
683           else if (*pend == ']') c--;
684           pend++;
685         }
686         if (c != 0) {
687           fprintf (stderr,
688                    _("%s: unterminated \"[...]\" sequence\n"), program_name);
689           if (exit_on_error) exit (1);
690           goto next_command;
691         }
692         if (*pend && (*pend != ' ' && *pend != '\t')) {
693           fprintf (stderr,
694                    _("%s: command arguments not separated by whitespace\n"),
695                    program_name);
696           if (exit_on_error) exit (1);
697           goto next_command;
698         }
699         *(pend-1) = '\0';
700         */
701       } else if (*p != ' ' && *p != '\t') {
702         /* If the first character is a ~ then note that this parameter
703          * is a candidate for ~username expansion.  NB this does not
704          * apply to quoted parameters.
705          */
706         tilde_candidate = *p == '~';
707         len = strcspn (p, " \t");
708         if (p[len]) {
709           p[len] = '\0';
710           pend = &p[len+1];
711         } else
712           pend = &p[len];
713       } else {
714         fprintf (stderr, _("%s: internal error parsing string at '%s'\n"),
715                  program_name, p);
716         abort ();
717       }
718
719       if (!tilde_candidate)
720         argv[i] = p;
721       else
722         argv[i] = try_tilde_expansion (p);
723       i++;
724       p = pend;
725
726       if (*p)
727         p += strspn (p, " \t");
728     }
729
730     if (i == sizeof argv / sizeof argv[0]) {
731       fprintf (stderr, _("%s: too many arguments\n"), program_name);
732       if (exit_on_error) exit (1);
733       goto next_command;
734     }
735
736     argv[i] = NULL;
737
738   got_command:
739     if (issue_command (cmd, argv, pipe) == -1) {
740       if (exit_on_error) exit (1);
741     }
742
743   next_command:;
744   }
745   if (prompt) printf ("\n");
746 }
747
748 static void
749 cmdline (char *argv[], int optind, int argc)
750 {
751   const char *cmd;
752   char **params;
753
754   exit_on_error = 1;
755
756   if (optind >= argc) return;
757
758   cmd = argv[optind++];
759   if (strcmp (cmd, ":") == 0) {
760     fprintf (stderr, _("%s: empty command on command line\n"), program_name);
761     exit (1);
762   }
763   params = &argv[optind];
764
765   /* Search for end of command list or ":" ... */
766   while (optind < argc && strcmp (argv[optind], ":") != 0)
767     optind++;
768
769   if (optind == argc) {
770     if (issue_command (cmd, params, NULL) == -1) exit (1);
771   } else {
772     argv[optind] = NULL;
773     if (issue_command (cmd, params, NULL) == -1) exit (1);
774     cmdline (argv, optind+1, argc);
775   }
776 }
777
778 int
779 issue_command (const char *cmd, char *argv[], const char *pipecmd)
780 {
781   int argc;
782   int stdout_saved_fd = -1;
783   int pid = 0;
784   int i, r;
785
786   if (echo_commands) {
787     printf ("%s", cmd);
788     for (i = 0; argv[i] != NULL; ++i)
789       printf (" %s", argv[i]);
790     printf ("\n");
791   }
792
793   /* For | ... commands.  Annoyingly we can't use popen(3) here. */
794   if (pipecmd) {
795     int fd[2];
796
797     if (fflush (stdout) == EOF) {
798       perror ("failed to flush standard output");
799       return -1;
800     }
801     if (pipe (fd) < 0) {
802       perror ("pipe failed");
803       return -1;
804     }
805     pid = fork ();
806     if (pid == -1) {
807       perror ("fork");
808       return -1;
809     }
810
811     if (pid == 0) {             /* Child process. */
812       close (fd[1]);
813       if (dup2 (fd[0], 0) < 0) {
814         perror ("dup2 of stdin failed");
815         _exit (1);
816       }
817
818       r = system (pipecmd);
819       if (r == -1) {
820         perror (pipecmd);
821         _exit (1);
822       }
823       _exit (WEXITSTATUS (r));
824     }
825
826     if ((stdout_saved_fd = dup (1)) < 0) {
827       perror ("failed to dup stdout");
828       return -1;
829     }
830     close (fd[0]);
831     if (dup2 (fd[1], 1) < 0) {
832       perror ("failed to dup stdout");
833       close (stdout_saved_fd);
834       return -1;
835     }
836     close (fd[1]);
837   }
838
839   for (argc = 0; argv[argc] != NULL; ++argc)
840     ;
841
842   /* If --remote was set, then send this command to a remote process. */
843   if (remote_control)
844     r = rc_remote (remote_control, cmd, argc, argv, exit_on_error);
845
846   /* Otherwise execute it locally. */
847   else if (strcasecmp (cmd, "help") == 0) {
848     if (argc == 0)
849       list_commands ();
850     else
851       display_command (argv[0]);
852     r = 0;
853   }
854   else if (strcasecmp (cmd, "quit") == 0 ||
855            strcasecmp (cmd, "exit") == 0 ||
856            strcasecmp (cmd, "q") == 0) {
857     quit = 1;
858     r = 0;
859   }
860   else if (strcasecmp (cmd, "alloc") == 0 ||
861            strcasecmp (cmd, "allocate") == 0)
862     r = do_alloc (cmd, argc, argv);
863   else if (strcasecmp (cmd, "echo") == 0)
864     r = do_echo (cmd, argc, argv);
865   else if (strcasecmp (cmd, "edit") == 0 ||
866            strcasecmp (cmd, "vi") == 0 ||
867            strcasecmp (cmd, "emacs") == 0)
868     r = do_edit (cmd, argc, argv);
869   else if (strcasecmp (cmd, "lcd") == 0)
870     r = do_lcd (cmd, argc, argv);
871   else if (strcasecmp (cmd, "glob") == 0)
872     r = do_glob (cmd, argc, argv);
873   else if (strcasecmp (cmd, "more") == 0 ||
874            strcasecmp (cmd, "less") == 0)
875     r = do_more (cmd, argc, argv);
876   else if (strcasecmp (cmd, "reopen") == 0)
877     r = do_reopen (cmd, argc, argv);
878   else if (strcasecmp (cmd, "time") == 0)
879     r = do_time (cmd, argc, argv);
880   else
881     r = run_action (cmd, argc, argv);
882
883   /* Always flush stdout after every command, so that messages, results
884    * etc appear immediately.
885    */
886   if (fflush (stdout) == EOF) {
887     perror ("failed to flush standard output");
888     return -1;
889   }
890
891   if (pipecmd) {
892     close (1);
893     if (dup2 (stdout_saved_fd, 1) < 0) {
894       perror ("failed to dup2 standard output");
895       r = -1;
896     }
897     close (stdout_saved_fd);
898     if (waitpid (pid, NULL, 0) < 0) {
899       perror ("waiting for command to complete");
900       r = -1;
901     }
902   }
903
904   return r;
905 }
906
907 void
908 list_builtin_commands (void)
909 {
910   /* help and quit should appear at the top */
911   printf ("%-20s %s\n",
912           "help", _("display a list of commands or help on a command"));
913   printf ("%-20s %s\n",
914           "quit", _("quit guestfish"));
915
916   printf ("%-20s %s\n",
917           "alloc", _("allocate an image"));
918   printf ("%-20s %s\n",
919           "echo", _("display a line of text"));
920   printf ("%-20s %s\n",
921           "edit", _("edit a file in the image"));
922   printf ("%-20s %s\n",
923           "lcd", _("local change directory"));
924   printf ("%-20s %s\n",
925           "glob", _("expand wildcards in command"));
926   printf ("%-20s %s\n",
927           "more", _("view a file in the pager"));
928   printf ("%-20s %s\n",
929           "reopen", _("close and reopen libguestfs handle"));
930   printf ("%-20s %s\n",
931           "time", _("measure time taken to run command"));
932
933   /* actions are printed after this (see list_commands) */
934 }
935
936 void
937 display_builtin_command (const char *cmd)
938 {
939   /* help for actions is auto-generated, see display_command */
940
941   if (strcasecmp (cmd, "alloc") == 0 ||
942       strcasecmp (cmd, "allocate") == 0)
943     printf (_("alloc - allocate an image\n"
944               "     alloc <filename> <size>\n"
945               "\n"
946               "    This creates an empty (zeroed) file of the given size,\n"
947               "    and then adds so it can be further examined.\n"
948               "\n"
949               "    For more advanced image creation, see qemu-img utility.\n"
950               "\n"
951               "    Size can be specified (where <nn> means a number):\n"
952               "    <nn>             number of kilobytes\n"
953               "      eg: 1440       standard 3.5\" floppy\n"
954               "    <nn>K or <nn>KB  number of kilobytes\n"
955               "    <nn>M or <nn>MB  number of megabytes\n"
956               "    <nn>G or <nn>GB  number of gigabytes\n"
957               "    <nn>sects        number of 512 byte sectors\n"));
958   else if (strcasecmp (cmd, "echo") == 0)
959     printf (_("echo - display a line of text\n"
960               "     echo [<params> ...]\n"
961               "\n"
962               "    This echos the parameters to the terminal.\n"));
963   else if (strcasecmp (cmd, "edit") == 0 ||
964            strcasecmp (cmd, "vi") == 0 ||
965            strcasecmp (cmd, "emacs") == 0)
966     printf (_("edit - edit a file in the image\n"
967               "     edit <filename>\n"
968               "\n"
969               "    This is used to edit a file.\n"
970               "\n"
971               "    It is the equivalent of (and is implemented by)\n"
972               "    running \"cat\", editing locally, and then \"write-file\".\n"
973               "\n"
974               "    Normally it uses $EDITOR, but if you use the aliases\n"
975               "    \"vi\" or \"emacs\" you will get those editors.\n"
976               "\n"
977               "    NOTE: This will not work reliably for large files\n"
978               "    (> 2 MB) or binary files containing \\0 bytes.\n"));
979   else if (strcasecmp (cmd, "lcd") == 0)
980     printf (_("lcd - local change directory\n"
981               "    lcd <directory>\n"
982               "\n"
983               "    Change guestfish's current directory. This command is\n"
984               "    useful if you want to download files to a particular\n"
985               "    place.\n"));
986   else if (strcasecmp (cmd, "glob") == 0)
987     printf (_("glob - expand wildcards in command\n"
988               "    glob <command> [<args> ...]\n"
989               "\n"
990               "    Glob runs <command> with wildcards expanded in any\n"
991               "    command args.  Note that the command is run repeatedly\n"
992               "    once for each expanded argument.\n"));
993   else if (strcasecmp (cmd, "help") == 0)
994     printf (_("help - display a list of commands or help on a command\n"
995               "     help cmd\n"
996               "     help\n"));
997   else if (strcasecmp (cmd, "more") == 0 ||
998            strcasecmp (cmd, "less") == 0)
999     printf (_("more - view a file in the pager\n"
1000               "     more <filename>\n"
1001               "\n"
1002               "    This is used to view a file in the pager.\n"
1003               "\n"
1004               "    It is the equivalent of (and is implemented by)\n"
1005               "    running \"cat\" and using the pager.\n"
1006               "\n"
1007               "    Normally it uses $PAGER, but if you use the alias\n"
1008               "    \"less\" then it always uses \"less\".\n"
1009               "\n"
1010               "    NOTE: This will not work reliably for large files\n"
1011               "    (> 2 MB) or binary files containing \\0 bytes.\n"));
1012   else if (strcasecmp (cmd, "quit") == 0 ||
1013            strcasecmp (cmd, "exit") == 0 ||
1014            strcasecmp (cmd, "q") == 0)
1015     printf (_("quit - quit guestfish\n"
1016               "     quit\n"));
1017   else if (strcasecmp (cmd, "reopen") == 0)
1018     printf (_("reopen - close and reopen the libguestfs handle\n"
1019               "     reopen\n"
1020               "\n"
1021               "Close and reopen the libguestfs handle.  It is not necessary to use\n"
1022               "this normally, because the handle is closed properly when guestfish\n"
1023               "exits.  However this is occasionally useful for testing.\n"));
1024   else if (strcasecmp (cmd, "time") == 0)
1025     printf (_("time - measure time taken to run command\n"
1026               "    time <command> [<args> ...]\n"
1027               "\n"
1028               "    This runs <command> as usual, and prints the elapsed\n"
1029               "    time afterwards.\n"));
1030   else
1031     fprintf (stderr, _("%s: command not known, use -h to list all commands\n"),
1032              cmd);
1033 }
1034
1035 void
1036 free_strings (char **argv)
1037 {
1038   int argc;
1039
1040   for (argc = 0; argv[argc] != NULL; ++argc)
1041     free (argv[argc]);
1042   free (argv);
1043 }
1044
1045 int
1046 count_strings (char *const *argv)
1047 {
1048   int c;
1049
1050   for (c = 0; argv[c]; ++c)
1051     ;
1052   return c;
1053 }
1054
1055 void
1056 print_strings (char *const *argv)
1057 {
1058   int argc;
1059
1060   for (argc = 0; argv[argc] != NULL; ++argc)
1061     printf ("%s\n", argv[argc]);
1062 }
1063
1064 void
1065 print_table (char *const *argv)
1066 {
1067   int i;
1068
1069   for (i = 0; argv[i] != NULL; i += 2)
1070     printf ("%s: %s\n", argv[i], argv[i+1]);
1071 }
1072
1073 int
1074 is_true (const char *str)
1075 {
1076   return
1077     strcasecmp (str, "0") != 0 &&
1078     strcasecmp (str, "f") != 0 &&
1079     strcasecmp (str, "false") != 0 &&
1080     strcasecmp (str, "n") != 0 &&
1081     strcasecmp (str, "no") != 0;
1082 }
1083
1084 /* XXX We could improve list parsing. */
1085 char **
1086 parse_string_list (const char *str)
1087 {
1088   char **argv;
1089   const char *p, *pend;
1090   int argc, i;
1091
1092   argc = 1;
1093   for (i = 0; str[i]; ++i)
1094     if (str[i] == ' ') argc++;
1095
1096   argv = malloc (sizeof (char *) * (argc+1));
1097   if (argv == NULL) { perror ("malloc"); exit (1); }
1098
1099   p = str;
1100   i = 0;
1101   while (*p) {
1102     pend = strchrnul (p, ' ');
1103     argv[i] = strndup (p, pend-p);
1104     i++;
1105     p = *pend == ' ' ? pend+1 : pend;
1106   }
1107   argv[i] = NULL;
1108
1109   return argv;
1110 }
1111
1112 #ifdef HAVE_LIBREADLINE
1113 static char histfile[1024];
1114 static int nr_history_lines = 0;
1115 #endif
1116
1117 static void
1118 initialize_readline (void)
1119 {
1120 #ifdef HAVE_LIBREADLINE
1121   const char *home;
1122
1123   home = getenv ("HOME");
1124   if (home) {
1125     snprintf (histfile, sizeof histfile, "%s/.guestfish", home);
1126     using_history ();
1127     (void) read_history (histfile);
1128   }
1129
1130   rl_readline_name = "guestfish";
1131   rl_attempted_completion_function = do_completion;
1132 #endif
1133 }
1134
1135 static void
1136 cleanup_readline (void)
1137 {
1138 #ifdef HAVE_LIBREADLINE
1139   int fd;
1140
1141   if (histfile[0] != '\0') {
1142     fd = open (histfile, O_WRONLY|O_CREAT, 0644);
1143     if (fd == -1) {
1144       perror (histfile);
1145       return;
1146     }
1147     close (fd);
1148
1149     (void) append_history (nr_history_lines, histfile);
1150   }
1151 #endif
1152 }
1153
1154 static void
1155 add_history_line (const char *line)
1156 {
1157 #ifdef HAVE_LIBREADLINE
1158   add_history (line);
1159   nr_history_lines++;
1160 #endif
1161 }
1162
1163 int
1164 xwrite (int fd, const void *v_buf, size_t len)
1165 {
1166   int r;
1167   const char *buf = v_buf;
1168
1169   while (len > 0) {
1170     r = write (fd, buf, len);
1171     if (r == -1) {
1172       perror ("write");
1173       return -1;
1174     }
1175     buf += r;
1176     len -= r;
1177   }
1178
1179   return 0;
1180 }