Mac OS X: Detect bindtextdomain.
[libguestfs.git] / fish / fish.c
1 /* guestfish - the filesystem interactive shell
2  * Copyright (C) 2009 Red Hat Inc.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 #include <config.h>
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <fcntl.h>
26 #include <getopt.h>
27 #include <signal.h>
28 #include <assert.h>
29 #include <sys/types.h>
30 #include <sys/wait.h>
31
32 #ifdef HAVE_LIBREADLINE
33 #include <readline/readline.h>
34 #include <readline/history.h>
35 #endif
36
37 #include <guestfs.h>
38
39 #include "fish.h"
40 #include "c-ctype.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   }
85   return 0;
86 }
87
88 static void __attribute__((noreturn))
89 usage (int status)
90 {
91   if (status != EXIT_SUCCESS)
92     fprintf (stderr, _("Try `%s --help' for more information.\n"),
93              program_name);
94   else {
95     fprintf (stdout,
96            _("%s: guest filesystem shell\n"
97              "%s lets you edit virtual machine filesystems\n"
98              "Copyright (C) 2009 Red Hat Inc.\n"
99              "Usage:\n"
100              "  %s [--options] cmd [: cmd : cmd ...]\n"
101              "  %s -i libvirt-domain\n"
102              "  %s -i disk-image(s)\n"
103              "or for interactive use:\n"
104              "  %s\n"
105              "or from a shell script:\n"
106              "  %s <<EOF\n"
107              "  cmd\n"
108              "  ...\n"
109              "  EOF\n"
110              "Options:\n"
111              "  -h|--cmd-help        List available commands\n"
112              "  -h|--cmd-help cmd    Display detailed help on 'cmd'\n"
113              "  -a|--add image       Add image\n"
114              "  -D|--no-dest-paths   Don't tab-complete paths from guest fs\n"
115              "  -f|--file file       Read commands from file\n"
116              "  -i|--inspector       Run virt-inspector to get disk mountpoints\n"
117              "  --listen             Listen for remote commands\n"
118              "  -m|--mount dev[:mnt] Mount dev on mnt (if omitted, /)\n"
119              "  -n|--no-sync         Don't autosync\n"
120              "  --remote[=pid]       Send commands to remote %s\n"
121              "  -r|--ro              Mount read-only\n"
122              "  --selinux            Enable SELinux support\n"
123              "  -v|--verbose         Verbose messages\n"
124              "  -x                   Echo each command before executing it\n"
125              "  -V|--version         Display version and exit\n"
126              "For more information,  see the manpage %s(1).\n"),
127              program_name, program_name, program_name,
128              program_name, program_name, program_name,
129              program_name, program_name, program_name);
130   }
131   exit (status);
132 }
133
134 int
135 main (int argc, char *argv[])
136 {
137   /* Set global program name that is not polluted with libtool artifacts.  */
138   set_program_name (argv[0]);
139
140   atexit (close_stdout);
141
142   setlocale (LC_ALL, "");
143   bindtextdomain (PACKAGE, LOCALEBASEDIR);
144   textdomain (PACKAGE);
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 (EXIT_FAILURE);
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 (STREQ (long_options[option_index].name, "listen"))
223         remote_control_listen = 1;
224       else if (STREQ (long_options[option_index].name, "remote")) {
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 (EXIT_FAILURE);
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 (EXIT_FAILURE);
238           }
239         }
240       } else if (STREQ (long_options[option_index].name, "selinux")) {
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 (EXIT_FAILURE);
246       }
247       break;
248
249     case 'a':
250       if (access (optarg, R_OK) != 0) {
251         perror (optarg);
252         exit (EXIT_FAILURE);
253       }
254       drv = malloc (sizeof (struct drv));
255       if (!drv) {
256         perror ("malloc");
257         exit (EXIT_FAILURE);
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 (EXIT_FAILURE);
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 (EXIT_SUCCESS);
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 (EXIT_FAILURE);
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 (EXIT_SUCCESS);
323
324     case 'x':
325       echo_commands = 1;
326       break;
327
328     case HELP_OPTION:
329       usage (EXIT_SUCCESS);
330
331     default:
332       usage (EXIT_FAILURE);
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 (EXIT_FAILURE);
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 (EXIT_FAILURE);
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 (EXIT_FAILURE);
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 (EXIT_FAILURE);
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 (EXIT_FAILURE);
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 (EXIT_FAILURE);
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 (EXIT_FAILURE);
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 (EXIT_FAILURE);
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 (EXIT_FAILURE);
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 (EXIT_SUCCESS);
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 NAME\n\n%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
478     /* Don't use guestfs_mount here because that will default to mount
479      * options -o sync,noatime.  For more information, see guestfs(3)
480      * section "LIBGUESTFS GOTCHAS".
481      */
482     const char *options = read_only ? "ro" : "";
483     r = guestfs_mount_options (g, options, mp->device, mp->mountpoint);
484     if (r == -1)
485       exit (EXIT_FAILURE);
486   }
487 }
488
489 static void
490 add_drives (struct drv *drv)
491 {
492   int r;
493
494   if (drv) {
495     add_drives (drv->next);
496     if (!read_only)
497       r = guestfs_add_drive (g, drv->filename);
498     else
499       r = guestfs_add_drive_ro (g, drv->filename);
500     if (r == -1)
501       exit (EXIT_FAILURE);
502   }
503 }
504
505 static void
506 interactive (void)
507 {
508   script (1);
509 }
510
511 static void
512 shell_script (void)
513 {
514   script (0);
515 }
516
517 #define FISH "><fs> "
518
519 static char *line_read = NULL;
520
521 static char *
522 rl_gets (int prompt)
523 {
524 #ifdef HAVE_LIBREADLINE
525
526   if (prompt) {
527     if (line_read) {
528       free (line_read);
529       line_read = NULL;
530     }
531
532     line_read = readline (prompt ? FISH : "");
533
534     if (line_read && *line_read)
535       add_history_line (line_read);
536
537     return line_read;
538   }
539
540 #endif /* HAVE_LIBREADLINE */
541
542   static char buf[8192];
543   int len;
544
545   if (prompt) printf (FISH);
546   line_read = fgets (buf, sizeof buf, stdin);
547
548   if (line_read) {
549     len = strlen (line_read);
550     if (len > 0 && buf[len-1] == '\n') buf[len-1] = '\0';
551   }
552
553   return line_read;
554 }
555
556 static void
557 script (int prompt)
558 {
559   char *buf;
560   char *cmd;
561   char *p, *pend;
562   char *argv[64];
563   int len;
564   int global_exit_on_error = !prompt;
565   int tilde_candidate;
566
567   if (prompt)
568     printf (_("\n"
569               "Welcome to guestfish, the libguestfs filesystem interactive shell for\n"
570               "editing virtual machine filesystems.\n"
571               "\n"
572               "Type: 'help' for help with commands\n"
573               "      'quit' to quit the shell\n"
574               "\n"));
575
576   while (!quit) {
577     char *pipe = NULL;
578
579     exit_on_error = global_exit_on_error;
580
581     buf = rl_gets (prompt);
582     if (!buf) {
583       quit = 1;
584       break;
585     }
586
587     /* Skip any initial whitespace before the command. */
588   again:
589     while (*buf && c_isspace (*buf))
590       buf++;
591
592     if (!*buf) continue;
593
594     /* If the next character is '#' then this is a comment. */
595     if (*buf == '#') continue;
596
597     /* If the next character is '!' then pass the whole lot to system(3). */
598     if (*buf == '!') {
599       int r;
600
601       r = system (buf+1);
602       if (exit_on_error) {
603         if (r == -1 ||
604             (WIFSIGNALED (r) &&
605              (WTERMSIG (r) == SIGINT || WTERMSIG (r) == SIGQUIT)) ||
606             WEXITSTATUS (r) != 0)
607           exit (EXIT_FAILURE);
608       }
609       continue;
610     }
611
612     /* If the next character is '-' allow the command to fail without
613      * exiting on error (just for this one command though).
614      */
615     if (*buf == '-') {
616       exit_on_error = 0;
617       buf++;
618       goto again;
619     }
620
621     /* Get the command (cannot be quoted). */
622     len = strcspn (buf, " \t");
623
624     if (len == 0) continue;
625
626     cmd = buf;
627     unsigned int i = 0;
628     if (buf[len] == '\0') {
629       argv[0] = NULL;
630       goto got_command;
631     }
632
633     buf[len] = '\0';
634     p = &buf[len+1];
635     p += strspn (p, " \t");
636
637     /* Get the parameters. */
638     while (*p && i < sizeof argv / sizeof argv[0]) {
639       tilde_candidate = 0;
640
641       /* Parameters which start with quotes or pipes are treated
642        * specially.  Bare parameters are delimited by whitespace.
643        */
644       if (*p == '"') {
645         p++;
646         len = strcspn (p, "\"");
647         if (p[len] == '\0') {
648           fprintf (stderr, _("%s: unterminated double quote\n"), program_name);
649           if (exit_on_error) exit (EXIT_FAILURE);
650           goto next_command;
651         }
652         if (p[len+1] && (p[len+1] != ' ' && p[len+1] != '\t')) {
653           fprintf (stderr,
654                    _("%s: command arguments not separated by whitespace\n"),
655                    program_name);
656           if (exit_on_error) exit (EXIT_FAILURE);
657           goto next_command;
658         }
659         p[len] = '\0';
660         pend = p[len+1] ? &p[len+2] : &p[len+1];
661       } else if (*p == '\'') {
662         p++;
663         len = strcspn (p, "'");
664         if (p[len] == '\0') {
665           fprintf (stderr, _("%s: unterminated single quote\n"), program_name);
666           if (exit_on_error) exit (EXIT_FAILURE);
667           goto next_command;
668         }
669         if (p[len+1] && (p[len+1] != ' ' && p[len+1] != '\t')) {
670           fprintf (stderr,
671                    _("%s: command arguments not separated by whitespace\n"),
672                    program_name);
673           if (exit_on_error) exit (EXIT_FAILURE);
674           goto next_command;
675         }
676         p[len] = '\0';
677         pend = p[len+1] ? &p[len+2] : &p[len+1];
678       } else if (*p == '|') {
679         *p = '\0';
680         pipe = p+1;
681         continue;
682         /*
683       } else if (*p == '[') {
684         int c = 1;
685         p++;
686         pend = p;
687         while (*pend && c != 0) {
688           if (*pend == '[') c++;
689           else if (*pend == ']') c--;
690           pend++;
691         }
692         if (c != 0) {
693           fprintf (stderr,
694                    _("%s: unterminated \"[...]\" sequence\n"), program_name);
695           if (exit_on_error) exit (EXIT_FAILURE);
696           goto next_command;
697         }
698         if (*pend && (*pend != ' ' && *pend != '\t')) {
699           fprintf (stderr,
700                    _("%s: command arguments not separated by whitespace\n"),
701                    program_name);
702           if (exit_on_error) exit (EXIT_FAILURE);
703           goto next_command;
704         }
705         *(pend-1) = '\0';
706         */
707       } else if (*p != ' ' && *p != '\t') {
708         /* If the first character is a ~ then note that this parameter
709          * is a candidate for ~username expansion.  NB this does not
710          * apply to quoted parameters.
711          */
712         tilde_candidate = *p == '~';
713         len = strcspn (p, " \t");
714         if (p[len]) {
715           p[len] = '\0';
716           pend = &p[len+1];
717         } else
718           pend = &p[len];
719       } else {
720         fprintf (stderr, _("%s: internal error parsing string at '%s'\n"),
721                  program_name, p);
722         abort ();
723       }
724
725       if (!tilde_candidate)
726         argv[i] = p;
727       else
728         argv[i] = try_tilde_expansion (p);
729       i++;
730       p = pend;
731
732       if (*p)
733         p += strspn (p, " \t");
734     }
735
736     if (i == sizeof argv / sizeof argv[0]) {
737       fprintf (stderr, _("%s: too many arguments\n"), program_name);
738       if (exit_on_error) exit (EXIT_FAILURE);
739       goto next_command;
740     }
741
742     argv[i] = NULL;
743
744   got_command:
745     if (issue_command (cmd, argv, pipe) == -1) {
746       if (exit_on_error) exit (EXIT_FAILURE);
747     }
748
749   next_command:;
750   }
751   if (prompt) printf ("\n");
752 }
753
754 static void
755 cmdline (char *argv[], int optind, int argc)
756 {
757   const char *cmd;
758   char **params;
759
760   exit_on_error = 1;
761
762   if (optind >= argc) return;
763
764   cmd = argv[optind++];
765   if (STREQ (cmd, ":")) {
766     fprintf (stderr, _("%s: empty command on command line\n"), program_name);
767     exit (EXIT_FAILURE);
768   }
769   params = &argv[optind];
770
771   /* Search for end of command list or ":" ... */
772   while (optind < argc && STRNEQ (argv[optind], ":"))
773     optind++;
774
775   if (optind == argc) {
776     if (issue_command (cmd, params, NULL) == -1) exit (EXIT_FAILURE);
777   } else {
778     argv[optind] = NULL;
779     if (issue_command (cmd, params, NULL) == -1) exit (EXIT_FAILURE);
780     cmdline (argv, optind+1, argc);
781   }
782 }
783
784 int
785 issue_command (const char *cmd, char *argv[], const char *pipecmd)
786 {
787   int argc;
788   int stdout_saved_fd = -1;
789   int pid = 0;
790   int i, r;
791
792   if (echo_commands) {
793     printf ("%s", cmd);
794     for (i = 0; argv[i] != NULL; ++i)
795       printf (" %s", argv[i]);
796     printf ("\n");
797   }
798
799   /* For | ... commands.  Annoyingly we can't use popen(3) here. */
800   if (pipecmd) {
801     int fd[2];
802
803     if (fflush (stdout) == EOF) {
804       perror ("failed to flush standard output");
805       return -1;
806     }
807     if (pipe (fd) < 0) {
808       perror ("pipe failed");
809       return -1;
810     }
811     pid = fork ();
812     if (pid == -1) {
813       perror ("fork");
814       return -1;
815     }
816
817     if (pid == 0) {             /* Child process. */
818       close (fd[1]);
819       if (dup2 (fd[0], 0) < 0) {
820         perror ("dup2 of stdin failed");
821         _exit (1);
822       }
823
824       r = system (pipecmd);
825       if (r == -1) {
826         perror (pipecmd);
827         _exit (1);
828       }
829       _exit (WEXITSTATUS (r));
830     }
831
832     if ((stdout_saved_fd = dup (1)) < 0) {
833       perror ("failed to dup stdout");
834       return -1;
835     }
836     close (fd[0]);
837     if (dup2 (fd[1], 1) < 0) {
838       perror ("failed to dup stdout");
839       close (stdout_saved_fd);
840       return -1;
841     }
842     close (fd[1]);
843   }
844
845   for (argc = 0; argv[argc] != NULL; ++argc)
846     ;
847
848   /* If --remote was set, then send this command to a remote process. */
849   if (remote_control)
850     r = rc_remote (remote_control, cmd, argc, argv, exit_on_error);
851
852   /* Otherwise execute it locally. */
853   else if (STRCASEEQ (cmd, "help")) {
854     if (argc == 0)
855       list_commands ();
856     else
857       display_command (argv[0]);
858     r = 0;
859   }
860   else if (STRCASEEQ (cmd, "quit") ||
861            STRCASEEQ (cmd, "exit") ||
862            STRCASEEQ (cmd, "q")) {
863     quit = 1;
864     r = 0;
865   }
866   else if (STRCASEEQ (cmd, "alloc") ||
867            STRCASEEQ (cmd, "allocate"))
868     r = do_alloc (cmd, argc, argv);
869   else if (STRCASEEQ (cmd, "echo"))
870     r = do_echo (cmd, argc, argv);
871   else if (STRCASEEQ (cmd, "edit") ||
872            STRCASEEQ (cmd, "vi") ||
873            STRCASEEQ (cmd, "emacs"))
874     r = do_edit (cmd, argc, argv);
875   else if (STRCASEEQ (cmd, "lcd"))
876     r = do_lcd (cmd, argc, argv);
877   else if (STRCASEEQ (cmd, "glob"))
878     r = do_glob (cmd, argc, argv);
879   else if (STRCASEEQ (cmd, "more") ||
880            STRCASEEQ (cmd, "less"))
881     r = do_more (cmd, argc, argv);
882   else if (STRCASEEQ (cmd, "reopen"))
883     r = do_reopen (cmd, argc, argv);
884   else if (STRCASEEQ (cmd, "sparse"))
885     r = do_sparse (cmd, argc, argv);
886   else if (STRCASEEQ (cmd, "time"))
887     r = do_time (cmd, argc, argv);
888   else
889     r = run_action (cmd, argc, argv);
890
891   /* Always flush stdout after every command, so that messages, results
892    * etc appear immediately.
893    */
894   if (fflush (stdout) == EOF) {
895     perror ("failed to flush standard output");
896     return -1;
897   }
898
899   if (pipecmd) {
900     close (1);
901     if (dup2 (stdout_saved_fd, 1) < 0) {
902       perror ("failed to dup2 standard output");
903       r = -1;
904     }
905     close (stdout_saved_fd);
906     if (waitpid (pid, NULL, 0) < 0) {
907       perror ("waiting for command to complete");
908       r = -1;
909     }
910   }
911
912   return r;
913 }
914
915 void
916 list_builtin_commands (void)
917 {
918   /* help and quit should appear at the top */
919   printf ("%-20s %s\n",
920           "help", _("display a list of commands or help on a command"));
921   printf ("%-20s %s\n",
922           "quit", _("quit guestfish"));
923
924   printf ("%-20s %s\n",
925           "alloc", _("allocate an image"));
926   printf ("%-20s %s\n",
927           "echo", _("display a line of text"));
928   printf ("%-20s %s\n",
929           "edit", _("edit a file in the image"));
930   printf ("%-20s %s\n",
931           "lcd", _("local change directory"));
932   printf ("%-20s %s\n",
933           "glob", _("expand wildcards in command"));
934   printf ("%-20s %s\n",
935           "more", _("view a file in the pager"));
936   printf ("%-20s %s\n",
937           "reopen", _("close and reopen libguestfs handle"));
938   printf ("%-20s %s\n",
939           "sparse", _("allocate a sparse image file"));
940   printf ("%-20s %s\n",
941           "time", _("measure time taken to run command"));
942
943   /* actions are printed after this (see list_commands) */
944 }
945
946 void
947 display_builtin_command (const char *cmd)
948 {
949   /* help for actions is auto-generated, see display_command */
950
951   if (STRCASEEQ (cmd, "alloc") ||
952       STRCASEEQ (cmd, "allocate"))
953     printf (_("alloc - allocate an image\n"
954               "     alloc <filename> <size>\n"
955               "\n"
956               "    This creates an empty (zeroed) file of the given size,\n"
957               "    and then adds so it can be further examined.\n"
958               "\n"
959               "    For more advanced image creation, see qemu-img utility.\n"
960               "\n"
961               "    Size can be specified (where <nn> means a number):\n"
962               "    <nn>             number of kilobytes\n"
963               "      eg: 1440       standard 3.5\" floppy\n"
964               "    <nn>K or <nn>KB  number of kilobytes\n"
965               "    <nn>M or <nn>MB  number of megabytes\n"
966               "    <nn>G or <nn>GB  number of gigabytes\n"
967               "    <nn>T or <nn>TB  number of terabytes\n"
968               "    <nn>P or <nn>PB  number of petabytes\n"
969               "    <nn>E or <nn>EB  number of exabytes\n"
970               "    <nn>sects        number of 512 byte sectors\n"));
971   else if (STRCASEEQ (cmd, "echo"))
972     printf (_("echo - display a line of text\n"
973               "     echo [<params> ...]\n"
974               "\n"
975               "    This echos the parameters to the terminal.\n"));
976   else if (STRCASEEQ (cmd, "edit") ||
977            STRCASEEQ (cmd, "vi") ||
978            STRCASEEQ (cmd, "emacs"))
979     printf (_("edit - edit a file in the image\n"
980               "     edit <filename>\n"
981               "\n"
982               "    This is used to edit a file.\n"
983               "\n"
984               "    It is the equivalent of (and is implemented by)\n"
985               "    running \"cat\", editing locally, and then \"write-file\".\n"
986               "\n"
987               "    Normally it uses $EDITOR, but if you use the aliases\n"
988               "    \"vi\" or \"emacs\" you will get those editors.\n"
989               "\n"
990               "    NOTE: This will not work reliably for large files\n"
991               "    (> 2 MB) or binary files containing \\0 bytes.\n"));
992   else if (STRCASEEQ (cmd, "lcd"))
993     printf (_("lcd - local change directory\n"
994               "    lcd <directory>\n"
995               "\n"
996               "    Change guestfish's current directory. This command is\n"
997               "    useful if you want to download files to a particular\n"
998               "    place.\n"));
999   else if (STRCASEEQ (cmd, "glob"))
1000     printf (_("glob - expand wildcards in command\n"
1001               "    glob <command> [<args> ...]\n"
1002               "\n"
1003               "    Glob runs <command> with wildcards expanded in any\n"
1004               "    command args.  Note that the command is run repeatedly\n"
1005               "    once for each expanded argument.\n"));
1006   else if (STRCASEEQ (cmd, "help"))
1007     printf (_("help - display a list of commands or help on a command\n"
1008               "     help cmd\n"
1009               "     help\n"));
1010   else if (STRCASEEQ (cmd, "more") ||
1011            STRCASEEQ (cmd, "less"))
1012     printf (_("more - view a file in the pager\n"
1013               "     more <filename>\n"
1014               "\n"
1015               "    This is used to view a file in the pager.\n"
1016               "\n"
1017               "    It is the equivalent of (and is implemented by)\n"
1018               "    running \"cat\" and using the pager.\n"
1019               "\n"
1020               "    Normally it uses $PAGER, but if you use the alias\n"
1021               "    \"less\" then it always uses \"less\".\n"
1022               "\n"
1023               "    NOTE: This will not work reliably for large files\n"
1024               "    (> 2 MB) or binary files containing \\0 bytes.\n"));
1025   else if (STRCASEEQ (cmd, "quit") ||
1026            STRCASEEQ (cmd, "exit") ||
1027            STRCASEEQ (cmd, "q"))
1028     printf (_("quit - quit guestfish\n"
1029               "     quit\n"));
1030   else if (STRCASEEQ (cmd, "reopen"))
1031     printf (_("reopen - close and reopen the libguestfs handle\n"
1032               "     reopen\n"
1033               "\n"
1034               "Close and reopen the libguestfs handle.  It is not necessary to use\n"
1035               "this normally, because the handle is closed properly when guestfish\n"
1036               "exits.  However this is occasionally useful for testing.\n"));
1037   else if (STRCASEEQ (cmd, "sparse"))
1038     printf (_("sparse - allocate a sparse image file\n"
1039               "     sparse <filename> <size>\n"
1040               "\n"
1041               "    This creates an empty sparse file of the given size,\n"
1042               "    and then adds so it can be further examined.\n"
1043               "\n"
1044               "    In all respects it works the same as the 'alloc'\n"
1045               "    command, except that the image file is allocated\n"
1046               "    sparsely, which means that disk blocks are not assigned\n"
1047               "    to the file until they are needed.  Sparse disk files\n"
1048               "    only use space when written to, but they are slower\n"
1049               "    and there is a danger you could run out of real disk\n"
1050               "    space during a write operation.\n"
1051               "\n"
1052               "    For more advanced image creation, see qemu-img utility.\n"
1053               "\n"
1054               "    Size can be specified (where <nn> means a number):\n"
1055               "    <nn>             number of kilobytes\n"
1056               "      eg: 1440       standard 3.5\" floppy\n"
1057               "    <nn>K or <nn>KB  number of kilobytes\n"
1058               "    <nn>M or <nn>MB  number of megabytes\n"
1059               "    <nn>G or <nn>GB  number of gigabytes\n"
1060               "    <nn>T or <nn>TB  number of terabytes\n"
1061               "    <nn>P or <nn>PB  number of petabytes\n"
1062               "    <nn>E or <nn>EB  number of exabytes\n"
1063               "    <nn>sects        number of 512 byte sectors\n"));
1064   else if (STRCASEEQ (cmd, "time"))
1065     printf (_("time - measure time taken to run command\n"
1066               "    time <command> [<args> ...]\n"
1067               "\n"
1068               "    This runs <command> as usual, and prints the elapsed\n"
1069               "    time afterwards.\n"));
1070   else
1071     fprintf (stderr, _("%s: command not known, use -h to list all commands\n"),
1072              cmd);
1073 }
1074
1075 void
1076 free_strings (char **argv)
1077 {
1078   int argc;
1079
1080   for (argc = 0; argv[argc] != NULL; ++argc)
1081     free (argv[argc]);
1082   free (argv);
1083 }
1084
1085 int
1086 count_strings (char *const *argv)
1087 {
1088   int c;
1089
1090   for (c = 0; argv[c]; ++c)
1091     ;
1092   return c;
1093 }
1094
1095 void
1096 print_strings (char *const *argv)
1097 {
1098   int argc;
1099
1100   for (argc = 0; argv[argc] != NULL; ++argc)
1101     printf ("%s\n", argv[argc]);
1102 }
1103
1104 void
1105 print_table (char *const *argv)
1106 {
1107   int i;
1108
1109   for (i = 0; argv[i] != NULL; i += 2)
1110     printf ("%s: %s\n", argv[i], argv[i+1]);
1111 }
1112
1113 int
1114 is_true (const char *str)
1115 {
1116   return
1117     STRCASENEQ (str, "0") &&
1118     STRCASENEQ (str, "f") &&
1119     STRCASENEQ (str, "false") &&
1120     STRCASENEQ (str, "n") &&
1121     STRCASENEQ (str, "no");
1122 }
1123
1124 /* Free strings from a non-NULL terminated char** */
1125 static void
1126 free_n_strings (char **str, size_t len)
1127 {
1128   size_t i;
1129
1130   for (i = 0; i < len; i++) {
1131     free (str[i]);
1132   }
1133   free (str);
1134 }
1135
1136 char **
1137 parse_string_list (const char *str)
1138 {
1139   char **argv = NULL;
1140   size_t argv_len = 0;
1141
1142   /* Current position pointer */
1143   const char *p = str;
1144
1145   /* Token might be simple:
1146    *  Token
1147    * or be quoted:
1148    *  'This is a single token'
1149    * or contain embedded single-quoted sections:
1150    *  This' is a sing'l'e to'ken
1151    *
1152    * The latter may seem over-complicated, but it's what a normal shell does.
1153    * Not doing it risks surprising somebody.
1154    *
1155    * This outer loop is over complete tokens.
1156    */
1157   while (*p) {
1158     char *tok = NULL;
1159     size_t tok_len = 0;
1160
1161     /* Skip leading whitespace */
1162     p += strspn (p, " \t");
1163
1164     char in_quote = 0;
1165
1166     /* This loop is over token 'fragments'. A token can be in multiple bits if
1167      * it contains single quotes. We also treat both sides of an escaped quote
1168      * as separate fragments because we can't just copy it: we have to remove
1169      * the \.
1170      */
1171     while (*p && (!c_isblank (*p) || in_quote)) {
1172       const char *end = p;
1173
1174       /* Check if the fragment starts with a quote */
1175       if ('\'' == *p) {
1176         /* Toggle in_quote */
1177         in_quote = !in_quote;
1178
1179         /* Skip the quote */
1180         p++; end++;
1181       }
1182
1183       /* If we're in a quote, look for an end quote */
1184       if (in_quote) {
1185         end += strcspn (end, "'");
1186       }
1187
1188       /* Otherwise, look for whitespace or a quote */
1189       else {
1190         end += strcspn (end, " \t'");
1191       }
1192
1193       /* Grow the token to accommodate the fragment */
1194       size_t tok_end = tok_len;
1195       tok_len += end - p;
1196       char *tok_new = realloc (tok, tok_len + 1);
1197       if (NULL == tok_new) {
1198         perror ("realloc");
1199         free_n_strings (argv, argv_len);
1200         free (tok);
1201         exit (EXIT_FAILURE);
1202       }
1203       tok = tok_new;
1204
1205       /* Check if we stopped on an escaped quote */
1206       if ('\'' == *end && end != p && *(end-1) == '\\') {
1207         /* Add everything before \' to the token */
1208         memcpy (&tok[tok_end], p, end - p - 1);
1209
1210         /* Add the quote */
1211         tok[tok_len-1] = '\'';
1212
1213         /* Already processed the quote */
1214         p = end + 1;
1215       }
1216
1217       else {
1218         /* Add the whole fragment */
1219         memcpy (&tok[tok_end], p, end - p);
1220
1221         p = end;
1222       }
1223     }
1224
1225     /* We've reached the end of a token. We shouldn't still be in quotes. */
1226     if (in_quote) {
1227       fprintf (stderr, _("Runaway quote in string \"%s\"\n"), str);
1228
1229       free_n_strings (argv, argv_len);
1230
1231       return NULL;
1232     }
1233
1234     /* Add this token if there is one. There might not be if there was
1235      * whitespace at the end of the input string */
1236     if (tok) {
1237       /* Add the NULL terminator */
1238       tok[tok_len] = '\0';
1239
1240       /* Add the argument to the argument list */
1241       argv_len++;
1242       char **argv_new = realloc (argv, sizeof (*argv) * argv_len);
1243       if (NULL == argv_new) {
1244         perror ("realloc");
1245         free_n_strings (argv, argv_len-1);
1246         free (tok);
1247         exit (EXIT_FAILURE);
1248       }
1249       argv = argv_new;
1250
1251       argv[argv_len-1] = tok;
1252     }
1253   }
1254
1255   /* NULL terminate the argument list */
1256   argv_len++;
1257   char **argv_new = realloc (argv, sizeof (*argv) * argv_len);
1258   if (NULL == argv_new) {
1259     perror ("realloc");
1260     free_n_strings (argv, argv_len-1);
1261     exit (EXIT_FAILURE);
1262   }
1263   argv = argv_new;
1264
1265   argv[argv_len-1] = NULL;
1266
1267   return argv;
1268 }
1269
1270 #ifdef HAVE_LIBREADLINE
1271 static char histfile[1024];
1272 static int nr_history_lines = 0;
1273 #endif
1274
1275 static void
1276 initialize_readline (void)
1277 {
1278 #ifdef HAVE_LIBREADLINE
1279   const char *home;
1280
1281   home = getenv ("HOME");
1282   if (home) {
1283     snprintf (histfile, sizeof histfile, "%s/.guestfish", home);
1284     using_history ();
1285     (void) read_history (histfile);
1286   }
1287
1288   rl_readline_name = "guestfish";
1289   rl_attempted_completion_function = do_completion;
1290 #endif
1291 }
1292
1293 static void
1294 cleanup_readline (void)
1295 {
1296 #ifdef HAVE_LIBREADLINE
1297   int fd;
1298
1299   if (histfile[0] != '\0') {
1300     fd = open (histfile, O_WRONLY|O_CREAT, 0644);
1301     if (fd == -1) {
1302       perror (histfile);
1303       return;
1304     }
1305     close (fd);
1306
1307     (void) append_history (nr_history_lines, histfile);
1308   }
1309 #endif
1310 }
1311
1312 static void
1313 add_history_line (const char *line)
1314 {
1315 #ifdef HAVE_LIBREADLINE
1316   add_history (line);
1317   nr_history_lines++;
1318 #endif
1319 }
1320
1321 int
1322 xwrite (int fd, const void *v_buf, size_t len)
1323 {
1324   int r;
1325   const char *buf = v_buf;
1326
1327   while (len > 0) {
1328     r = write (fd, buf, len);
1329     if (r == -1) {
1330       perror ("write");
1331       return -1;
1332     }
1333     buf += r;
1334     len -= r;
1335   }
1336
1337   return 0;
1338 }
1339
1340 /* Resolve the special "win:..." form for Windows-specific paths.
1341  * This always returns a newly allocated string which is freed by the
1342  * caller function in "cmds.c".
1343  */
1344 char *
1345 resolve_win_path (const char *path)
1346 {
1347   char *ret;
1348   size_t i;
1349
1350   if (STRCASENEQLEN (path, "win:", 4)) {
1351     ret = strdup (path);
1352     if (ret == NULL)
1353       perror ("strdup");
1354     return ret;
1355   }
1356
1357   path += 4;
1358
1359   /* Drop drive letter, if it's "C:". */
1360   if (STRCASEEQLEN (path, "c:", 2))
1361     path += 2;
1362
1363   if (!*path) {
1364     ret = strdup ("/");
1365     if (ret == NULL)
1366       perror ("strdup");
1367     return ret;
1368   }
1369
1370   ret = strdup (path);
1371   if (ret == NULL) {
1372     perror ("strdup");
1373     return NULL;
1374   }
1375
1376   /* Blindly convert any backslashes into forward slashes.  Is this good? */
1377   for (i = 0; i < strlen (ret); ++i)
1378     if (ret[i] == '\\')
1379       ret[i] = '/';
1380
1381   char *t = guestfs_case_sensitive_path (g, ret);
1382   free (ret);
1383   ret = t;
1384
1385   return ret;
1386 }