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