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