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