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