syntax: Remove unused assert.h header.
[libguestfs.git] / fish / fish.c
1 /* guestfish - the filesystem interactive shell
2  * Copyright (C) 2009-2010 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 <inttypes.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <getopt.h>
28 #include <signal.h>
29 #include <sys/types.h>
30 #include <sys/wait.h>
31 #include <locale.h>
32 #include <langinfo.h>
33 #include <termios.h>
34
35 #ifdef HAVE_LIBREADLINE
36 #include <readline/readline.h>
37 #include <readline/history.h>
38 #endif
39
40 #include <guestfs.h>
41
42 #include "fish.h"
43 #include "c-ctype.h"
44 #include "closeout.h"
45 #include "progname.h"
46
47 /* List of drives added via -a, -d or -N options. */
48 struct drv {
49   struct drv *next;
50   enum { drv_a, drv_d, drv_N } type;
51   union {
52     struct {
53       char *filename;       /* disk filename */
54     } a;
55     struct {
56       char *guest;          /* guest name */
57     } d;
58     struct {
59       char *filename;       /* disk filename (testX.img) */
60       prep_data *data;      /* prepared type */
61       char *device;         /* device inside the appliance */
62     } N;
63   };
64 };
65
66 struct mp {
67   struct mp *next;
68   char *device;
69   char *mountpoint;
70 };
71
72 static void set_up_terminal (void);
73 static char add_drives (struct drv *drv, char next_drive);
74 static void prepare_drives (struct drv *drv);
75 static void mount_mps (struct mp *mp);
76 static int launch (void);
77 static void interactive (void);
78 static void shell_script (void);
79 static void script (int prompt);
80 static void cmdline (char *argv[], int optind, int argc);
81 static void initialize_readline (void);
82 static void cleanup_readline (void);
83 #ifdef HAVE_LIBREADLINE
84 static void add_history_line (const char *);
85 #endif
86
87 static int override_progress_bars = -1;
88
89 /* Currently open libguestfs handle. */
90 guestfs_h *g;
91
92 int read_only = 0;
93 int quit = 0;
94 int verbose = 0;
95 int remote_control_listen = 0;
96 int remote_control = 0;
97 int exit_on_error = 1;
98 int command_num = 0;
99 int keys_from_stdin = 0;
100 const char *libvirt_uri = NULL;
101 int inspector = 0;
102 int utf8_mode = 0;
103 int have_terminfo = 0;
104 int progress_bars = 0;
105
106 static void __attribute__((noreturn))
107 usage (int status)
108 {
109   if (status != EXIT_SUCCESS)
110     fprintf (stderr, _("Try `%s --help' for more information.\n"),
111              program_name);
112   else {
113     fprintf (stdout,
114            _("%s: guest filesystem shell\n"
115              "%s lets you edit virtual machine filesystems\n"
116              "Copyright (C) 2009 Red Hat Inc.\n"
117              "Usage:\n"
118              "  %s [--options] cmd [: cmd : cmd ...]\n"
119              "  %s -i libvirt-domain\n"
120              "  %s -i disk-image(s)\n"
121              "or for interactive use:\n"
122              "  %s\n"
123              "or from a shell script:\n"
124              "  %s <<EOF\n"
125              "  cmd\n"
126              "  ...\n"
127              "  EOF\n"
128              "Options:\n"
129              "  -h|--cmd-help        List available commands\n"
130              "  -h|--cmd-help cmd    Display detailed help on 'cmd'\n"
131              "  -a|--add image       Add image\n"
132              "  -c|--connect uri     Specify libvirt URI for -d option\n"
133              "  -d|--domain guest    Add disks from libvirt guest\n"
134              "  -D|--no-dest-paths   Don't tab-complete paths from guest fs\n"
135              "  -f|--file file       Read commands from file\n"
136              "  -i|--inspector       Automatically mount filesystems\n"
137              "  --keys-from-stdin    Read passphrases from stdin\n"
138              "  --listen             Listen for remote commands\n"
139              "  -m|--mount dev[:mnt] Mount dev on mnt (if omitted, /)\n"
140              "  -n|--no-sync         Don't autosync\n"
141              "  -N|--new type        Create prepared disk (test1.img, ...)\n"
142              "  --progress-bars      Enable progress bars even when not interactive\n"
143              "  --no-progress-bars   Disable progress bars\n"
144              "  --remote[=pid]       Send commands to remote %s\n"
145              "  -r|--ro              Mount read-only\n"
146              "  --selinux            Enable SELinux support\n"
147              "  -v|--verbose         Verbose messages\n"
148              "  -x                   Echo each command before executing it\n"
149              "  -V|--version         Display version and exit\n"
150              "For more information,  see the manpage %s(1).\n"),
151              program_name, program_name, program_name,
152              program_name, program_name, program_name,
153              program_name, program_name, program_name);
154   }
155   exit (status);
156 }
157
158 int
159 main (int argc, char *argv[])
160 {
161   /* Set global program name that is not polluted with libtool artifacts.  */
162   set_program_name (argv[0]);
163
164   atexit (close_stdout);
165
166   setlocale (LC_ALL, "");
167   bindtextdomain (PACKAGE, LOCALEBASEDIR);
168   textdomain (PACKAGE);
169
170   set_up_terminal ();
171
172   enum { HELP_OPTION = CHAR_MAX + 1 };
173
174   static const char *options = "a:c:d:Df:h::im:nN:rv?Vx";
175   static const struct option long_options[] = {
176     { "add", 1, 0, 'a' },
177     { "cmd-help", 2, 0, 'h' },
178     { "connect", 1, 0, 'c' },
179     { "domain", 1, 0, 'd' },
180     { "file", 1, 0, 'f' },
181     { "help", 0, 0, HELP_OPTION },
182     { "inspector", 0, 0, 'i' },
183     { "keys-from-stdin", 0, 0, 0 },
184     { "listen", 0, 0, 0 },
185     { "mount", 1, 0, 'm' },
186     { "new", 1, 0, 'N' },
187     { "no-dest-paths", 0, 0, 'D' },
188     { "no-sync", 0, 0, 'n' },
189     { "progress-bars", 0, 0, 0 },
190     { "no-progress-bars", 0, 0, 0 },
191     { "remote", 2, 0, 0 },
192     { "ro", 0, 0, 'r' },
193     { "selinux", 0, 0, 0 },
194     { "verbose", 0, 0, 'v' },
195     { "version", 0, 0, 'V' },
196     { 0, 0, 0, 0 }
197   };
198   struct drv *drvs = NULL;
199   struct drv *drv;
200   struct mp *mps = NULL;
201   struct mp *mp;
202   char *p, *file = NULL;
203   int c;
204   int option_index;
205   struct sigaction sa;
206   int next_prepared_drive = 1;
207
208   initialize_readline ();
209
210   memset (&sa, 0, sizeof sa);
211   sa.sa_handler = SIG_IGN;
212   sa.sa_flags = SA_RESTART;
213   sigaction (SIGPIPE, &sa, NULL);
214
215   /* guestfs_create is meant to be a lightweight operation, so
216    * it's OK to do it early here.
217    */
218   g = guestfs_create ();
219   if (g == NULL) {
220     fprintf (stderr, _("guestfs_create: failed to create handle\n"));
221     exit (EXIT_FAILURE);
222   }
223
224   guestfs_set_autosync (g, 1);
225
226   /* If developing, add ./appliance to the path.  Note that libtools
227    * interferes with this because uninstalled guestfish is a shell
228    * script that runs the real program with an absolute path.  Detect
229    * that too.
230    *
231    * BUT if LIBGUESTFS_PATH environment variable is already set by
232    * the user, then don't override it.
233    */
234   if (getenv ("LIBGUESTFS_PATH") == NULL &&
235       argv[0] &&
236       (argv[0][0] != '/' || strstr (argv[0], "/.libs/lt-") != NULL))
237     guestfs_set_path (g, "appliance:" GUESTFS_DEFAULT_PATH);
238
239   /* CAUTION: we are careful to modify argv[0] here, only after
240    * using it just above.
241    *
242    * getopt_long uses argv[0], so give it the sanitized name.  Save a copy
243    * of the original, in case it's needed below.
244    */
245   char *real_argv0 = argv[0];
246   argv[0] = bad_cast (program_name);
247
248   for (;;) {
249     c = getopt_long (argc, argv, options, long_options, &option_index);
250     if (c == -1) break;
251
252     switch (c) {
253     case 0:                     /* options which are long only */
254       if (STREQ (long_options[option_index].name, "listen"))
255         remote_control_listen = 1;
256       else if (STREQ (long_options[option_index].name, "remote")) {
257         if (optarg) {
258           if (sscanf (optarg, "%d", &remote_control) != 1) {
259             fprintf (stderr, _("%s: --listen=PID: PID was not a number: %s\n"),
260                      program_name, optarg);
261             exit (EXIT_FAILURE);
262           }
263         } else {
264           p = getenv ("GUESTFISH_PID");
265           if (!p || sscanf (p, "%d", &remote_control) != 1) {
266             fprintf (stderr, _("%s: remote: $GUESTFISH_PID must be set"
267                                " to the PID of the remote process\n"),
268                      program_name);
269             exit (EXIT_FAILURE);
270           }
271         }
272       } else if (STREQ (long_options[option_index].name, "selinux")) {
273         guestfs_set_selinux (g, 1);
274       } else if (STREQ (long_options[option_index].name, "keys-from-stdin")) {
275         keys_from_stdin = 1;
276       } else if (STREQ (long_options[option_index].name, "progress-bars")) {
277         override_progress_bars = 1;
278       } else if (STREQ (long_options[option_index].name, "no-progress-bars")) {
279         override_progress_bars = 0;
280       } else {
281         fprintf (stderr, _("%s: unknown long option: %s (%d)\n"),
282                  program_name, long_options[option_index].name, option_index);
283         exit (EXIT_FAILURE);
284       }
285       break;
286
287     case 'a':
288       if (access (optarg, R_OK) != 0) {
289         perror (optarg);
290         exit (EXIT_FAILURE);
291       }
292       drv = malloc (sizeof (struct drv));
293       if (!drv) {
294         perror ("malloc");
295         exit (EXIT_FAILURE);
296       }
297       drv->type = drv_a;
298       drv->a.filename = optarg;
299       drv->next = drvs;
300       drvs = drv;
301       break;
302
303     case 'c':
304       libvirt_uri = optarg;
305       break;
306
307     case 'd':
308       drv = malloc (sizeof (struct drv));
309       if (!drv) {
310         perror ("malloc");
311         exit (EXIT_FAILURE);
312       }
313       drv->type = drv_d;
314       drv->d.guest = optarg;
315       drv->next = drvs;
316       drvs = drv;
317       break;
318
319     case 'N':
320       if (STRCASEEQ (optarg, "list") ||
321           STRCASEEQ (optarg, "help") ||
322           STRCASEEQ (optarg, "h") ||
323           STRCASEEQ (optarg, "?")) {
324         list_prepared_drives ();
325         exit (EXIT_SUCCESS);
326       }
327       drv = malloc (sizeof (struct drv));
328       if (!drv) {
329         perror ("malloc");
330         exit (EXIT_FAILURE);
331       }
332       drv->type = drv_N;
333       if (asprintf (&drv->N.filename, "test%d.img",
334                     next_prepared_drive++) == -1) {
335         perror ("asprintf");
336         exit (EXIT_FAILURE);
337       }
338       drv->N.data = create_prepared_file (optarg, drv->N.filename);
339       drv->N.device = NULL;     /* filled in by add_drives */
340       drv->next = drvs;
341       drvs = drv;
342       break;
343
344     case 'D':
345       complete_dest_paths = 0;
346       break;
347
348     case 'f':
349       if (file) {
350         fprintf (stderr, _("%s: only one -f parameter can be given\n"),
351                  program_name);
352         exit (EXIT_FAILURE);
353       }
354       file = optarg;
355       break;
356
357     case 'h': {
358       int r = 0;
359
360       if (optarg)
361         r = display_command (optarg);
362       else if (argv[optind] && argv[optind][0] != '-')
363         r = display_command (argv[optind++]);
364       else
365         list_commands ();
366
367       exit (r == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
368     }
369
370     case 'i':
371       inspector = 1;
372       break;
373
374     case 'm':
375       mp = malloc (sizeof (struct mp));
376       if (!mp) {
377         perror ("malloc");
378         exit (EXIT_FAILURE);
379       }
380       p = strchr (optarg, ':');
381       if (p) {
382         *p = '\0';
383         mp->mountpoint = p+1;
384       } else
385         mp->mountpoint = bad_cast ("/");
386       mp->device = optarg;
387       mp->next = mps;
388       mps = mp;
389       break;
390
391     case 'n':
392       guestfs_set_autosync (g, 0);
393       break;
394
395     case 'r':
396       read_only = 1;
397       break;
398
399     case 'v':
400       verbose++;
401       guestfs_set_verbose (g, verbose);
402       break;
403
404     case 'V': {
405       struct guestfs_version *v = guestfs_version (g);
406       printf ("%s %"PRIi64".%"PRIi64".%"PRIi64"%s\n", program_name,
407               v->major, v->minor, v->release, v->extra);
408       exit (EXIT_SUCCESS);
409     }
410
411     case 'x':
412       guestfs_set_trace (g, 1);
413       break;
414
415     case HELP_OPTION:
416       usage (EXIT_SUCCESS);
417
418     default:
419       usage (EXIT_FAILURE);
420     }
421   }
422
423   /* Old-style -i syntax?  Since -a/-d/-N and -i was disallowed
424    * previously, if we have -i without any drives but with something
425    * on the command line, it must be old-style syntax.
426    */
427   if (inspector && drvs == NULL && optind < argc) {
428     while (optind < argc) {
429       if (strchr (argv[optind], '/') ||
430           access (argv[optind], F_OK) == 0) { /* simulate -a option */
431         drv = malloc (sizeof (struct drv));
432         if (!drv) {
433           perror ("malloc");
434           exit (EXIT_FAILURE);
435         }
436         drv->type = drv_a;
437         drv->a.filename = argv[optind];
438         drv->next = drvs;
439         drvs = drv;
440       } else {                  /* simulate -d option */
441         drv = malloc (sizeof (struct drv));
442         if (!drv) {
443           perror ("malloc");
444           exit (EXIT_FAILURE);
445         }
446         drv->type = drv_d;
447         drv->d.guest = argv[optind];
448         drv->next = drvs;
449         drvs = drv;
450       }
451
452       optind++;
453     }
454   }
455
456   /* If we've got drives to add, add them now. */
457   add_drives (drvs, 'a');
458
459   /* If we've got mountpoints or prepared drives or -i option, we must
460    * launch the guest and mount them.
461    */
462   if (next_prepared_drive > 1 || mps != NULL || inspector) {
463     /* RHBZ#612178: If --listen flag is given, then we will fork into
464      * the background in rc_listen().  However you can't do this while
465      * holding a libguestfs handle open because the recovery process
466      * will think the main program has died and kill qemu.  Therefore
467      * don't use the recovery process for this case.  (A better
468      * solution would be to call launch () etc after the fork, but
469      * that greatly complicates the code here).
470      */
471     if (remote_control_listen)
472       guestfs_set_recovery_proc (g, 0);
473
474     if (launch () == -1) exit (EXIT_FAILURE);
475
476     if (inspector)
477       inspect_mount ();
478
479     prepare_drives (drvs);
480     mount_mps (mps);
481   }
482
483   /* Remote control? */
484   if (remote_control_listen && remote_control) {
485     fprintf (stderr,
486              _("%s: cannot use --listen and --remote options at the same time\n"),
487              program_name);
488     exit (EXIT_FAILURE);
489   }
490
491   if (remote_control_listen) {
492     if (optind < argc) {
493       fprintf (stderr,
494                _("%s: extra parameters on the command line with --listen flag\n"),
495                program_name);
496       exit (EXIT_FAILURE);
497     }
498     if (file) {
499       fprintf (stderr,
500                _("%s: cannot use --listen and --file options at the same time\n"),
501                program_name);
502       exit (EXIT_FAILURE);
503     }
504     rc_listen ();
505   }
506
507   /* -f (file) parameter? */
508   if (file) {
509     close (0);
510     if (open (file, O_RDONLY) == -1) {
511       perror (file);
512       exit (EXIT_FAILURE);
513     }
514   }
515
516   /* Decide if we display progress bars. */
517   progress_bars =
518     override_progress_bars >= 0
519     ? override_progress_bars
520     : (optind >= argc && isatty (0));
521
522   if (progress_bars)
523     guestfs_set_progress_callback (g, progress_callback, NULL);
524
525   /* Interactive, shell script, or command(s) on the command line? */
526   if (optind >= argc) {
527     if (isatty (0))
528       interactive ();
529     else
530       shell_script ();
531   }
532   else
533     cmdline (argv, optind, argc);
534
535   cleanup_readline ();
536
537   exit (EXIT_SUCCESS);
538 }
539
540 /* The <term.h> header file which defines this has "issues". */
541 extern int tgetent (char *, const char *);
542
543 static void
544 set_up_terminal (void)
545 {
546   /* http://www.cl.cam.ac.uk/~mgk25/unicode.html#activate */
547   utf8_mode = STREQ (nl_langinfo (CODESET), "UTF-8");
548
549   char *term = getenv ("TERM");
550   if (term == NULL) {
551     //fprintf (stderr, _("guestfish: TERM (terminal type) not defined.\n"));
552     return;
553   }
554
555   int r = tgetent (NULL, term);
556   if (r == -1) {
557     fprintf (stderr, _("guestfish: could not access termcap or terminfo database.\n"));
558     return;
559   }
560   if (r == 0) {
561     fprintf (stderr, _("guestfish: terminal type \"%s\" not defined.\n"),
562              term);
563     return;
564   }
565
566   have_terminfo = 1;
567 }
568
569 void
570 pod2text (const char *name, const char *shortdesc, const char *str)
571 {
572   FILE *fp;
573
574   fp = popen ("pod2text", "w");
575   if (fp == NULL) {
576     /* pod2text failed, maybe not found, so let's just print the
577      * source instead, since that's better than doing nothing.
578      */
579     printf ("%s - %s\n\n%s\n", name, shortdesc, str);
580     return;
581   }
582   fprintf (fp, "=head1 NAME\n\n%s - %s\n\n", name, shortdesc);
583   fputs (str, fp);
584   pclose (fp);
585 }
586
587 /* List is built in reverse order, so mount them in reverse order. */
588 static void
589 mount_mps (struct mp *mp)
590 {
591   int r;
592
593   if (mp) {
594     mount_mps (mp->next);
595
596     /* Don't use guestfs_mount here because that will default to mount
597      * options -o sync,noatime.  For more information, see guestfs(3)
598      * section "LIBGUESTFS GOTCHAS".
599      */
600     const char *options = read_only ? "ro" : "";
601     r = guestfs_mount_options (g, options, mp->device, mp->mountpoint);
602     if (r == -1)
603       exit (EXIT_FAILURE);
604   }
605 }
606
607 static char
608 add_drives (struct drv *drv, char next_drive)
609 {
610   int r;
611
612   if (next_drive > 'z') {
613     fprintf (stderr,
614              _("guestfish: too many drives added on the command line\n"));
615     exit (EXIT_FAILURE);
616   }
617
618   if (drv) {
619     next_drive = add_drives (drv->next, next_drive);
620
621     switch (drv->type) {
622     case drv_a:
623       if (!read_only)
624         r = guestfs_add_drive (g, drv->a.filename);
625       else
626         r = guestfs_add_drive_ro (g, drv->a.filename);
627       if (r == -1)
628         exit (EXIT_FAILURE);
629
630       next_drive++;
631       break;
632
633     case drv_d:
634       r = add_libvirt_drives (drv->d.guest);
635       if (r == -1)
636         exit (EXIT_FAILURE);
637
638       next_drive += r;
639       break;
640
641     case drv_N:
642       /* -N option is not affected by --ro */
643       r = guestfs_add_drive (g, drv->N.filename);
644       if (r == -1)
645         exit (EXIT_FAILURE);
646
647       if (asprintf (&drv->N.device, "/dev/sd%c", next_drive) == -1) {
648         perror ("asprintf");
649         exit (EXIT_FAILURE);
650       }
651
652       next_drive++;
653       break;
654
655     default: /* keep GCC happy */
656       abort ();
657     }
658   }
659
660   return next_drive;
661 }
662
663 static void
664 prepare_drives (struct drv *drv)
665 {
666   if (drv) {
667     prepare_drives (drv->next);
668     if (drv->type == drv_N)
669       prepare_drive (drv->N.filename, drv->N.data, drv->N.device);
670   }
671 }
672
673 static int
674 launch (void)
675 {
676   if (guestfs_is_config (g)) {
677     if (guestfs_launch (g) == -1)
678       return -1;
679   }
680   return 0;
681 }
682
683 static void
684 interactive (void)
685 {
686   script (1);
687 }
688
689 static void
690 shell_script (void)
691 {
692   script (0);
693 }
694
695 #define FISH "><fs> "
696
697 static char *line_read = NULL;
698
699 static char *
700 rl_gets (int prompt)
701 {
702 #ifdef HAVE_LIBREADLINE
703
704   if (prompt) {
705     if (line_read) {
706       free (line_read);
707       line_read = NULL;
708     }
709
710     line_read = readline (prompt ? FISH : "");
711
712     if (line_read && *line_read)
713       add_history_line (line_read);
714
715     return line_read;
716   }
717
718 #endif /* HAVE_LIBREADLINE */
719
720   static char buf[8192];
721   int len;
722
723   if (prompt) printf (FISH);
724   line_read = fgets (buf, sizeof buf, stdin);
725
726   if (line_read) {
727     len = strlen (line_read);
728     if (len > 0 && buf[len-1] == '\n') buf[len-1] = '\0';
729   }
730
731   return line_read;
732 }
733
734 static void
735 script (int prompt)
736 {
737   char *buf;
738   char *cmd;
739   char *p, *pend;
740   char *argv[64];
741   int len;
742   int global_exit_on_error = !prompt;
743   int tilde_candidate;
744
745   if (prompt) {
746     printf (_("\n"
747               "Welcome to guestfish, the libguestfs filesystem interactive shell for\n"
748               "editing virtual machine filesystems.\n"
749               "\n"
750               "Type: 'help' for a list of commands\n"
751               "      'man' to read the manual\n"
752               "      'quit' to quit the shell\n"
753               "\n"));
754
755     if (inspector) {
756       print_inspect_prompt ();
757       printf ("\n");
758     }
759   }
760
761   while (!quit) {
762     char *pipe = NULL;
763
764     exit_on_error = global_exit_on_error;
765
766     buf = rl_gets (prompt);
767     if (!buf) {
768       quit = 1;
769       break;
770     }
771
772     /* Skip any initial whitespace before the command. */
773   again:
774     while (*buf && c_isspace (*buf))
775       buf++;
776
777     if (!*buf) continue;
778
779     /* If the next character is '#' then this is a comment. */
780     if (*buf == '#') continue;
781
782     /* If the next character is '!' then pass the whole lot to system(3). */
783     if (*buf == '!') {
784       int r;
785
786       r = system (buf+1);
787       if (exit_on_error) {
788         if (r == -1 ||
789             (WIFSIGNALED (r) &&
790              (WTERMSIG (r) == SIGINT || WTERMSIG (r) == SIGQUIT)) ||
791             WEXITSTATUS (r) != 0)
792           exit (EXIT_FAILURE);
793       }
794       continue;
795     }
796
797     /* If the next character is '-' allow the command to fail without
798      * exiting on error (just for this one command though).
799      */
800     if (*buf == '-') {
801       exit_on_error = 0;
802       buf++;
803       goto again;
804     }
805
806     /* Get the command (cannot be quoted). */
807     len = strcspn (buf, " \t");
808
809     if (len == 0) continue;
810
811     cmd = buf;
812     unsigned int i = 0;
813     if (buf[len] == '\0') {
814       argv[0] = NULL;
815       goto got_command;
816     }
817
818     buf[len] = '\0';
819     p = &buf[len+1];
820     p += strspn (p, " \t");
821
822     /* Get the parameters. */
823     while (*p && i < sizeof argv / sizeof argv[0]) {
824       tilde_candidate = 0;
825
826       /* Parameters which start with quotes or pipes are treated
827        * specially.  Bare parameters are delimited by whitespace.
828        */
829       if (*p == '"') {
830         p++;
831         len = strcspn (p, "\"");
832         if (p[len] == '\0') {
833           fprintf (stderr, _("%s: unterminated double quote\n"), program_name);
834           if (exit_on_error) exit (EXIT_FAILURE);
835           goto next_command;
836         }
837         if (p[len+1] && (p[len+1] != ' ' && p[len+1] != '\t')) {
838           fprintf (stderr,
839                    _("%s: command arguments not separated by whitespace\n"),
840                    program_name);
841           if (exit_on_error) exit (EXIT_FAILURE);
842           goto next_command;
843         }
844         p[len] = '\0';
845         pend = p[len+1] ? &p[len+2] : &p[len+1];
846       } else if (*p == '\'') {
847         p++;
848         len = strcspn (p, "'");
849         if (p[len] == '\0') {
850           fprintf (stderr, _("%s: unterminated single quote\n"), program_name);
851           if (exit_on_error) exit (EXIT_FAILURE);
852           goto next_command;
853         }
854         if (p[len+1] && (p[len+1] != ' ' && p[len+1] != '\t')) {
855           fprintf (stderr,
856                    _("%s: command arguments not separated by whitespace\n"),
857                    program_name);
858           if (exit_on_error) exit (EXIT_FAILURE);
859           goto next_command;
860         }
861         p[len] = '\0';
862         pend = p[len+1] ? &p[len+2] : &p[len+1];
863       } else if (*p == '|') {
864         *p = '\0';
865         pipe = p+1;
866         continue;
867         /*
868       } else if (*p == '[') {
869         int c = 1;
870         p++;
871         pend = p;
872         while (*pend && c != 0) {
873           if (*pend == '[') c++;
874           else if (*pend == ']') c--;
875           pend++;
876         }
877         if (c != 0) {
878           fprintf (stderr,
879                    _("%s: unterminated \"[...]\" sequence\n"), program_name);
880           if (exit_on_error) exit (EXIT_FAILURE);
881           goto next_command;
882         }
883         if (*pend && (*pend != ' ' && *pend != '\t')) {
884           fprintf (stderr,
885                    _("%s: command arguments not separated by whitespace\n"),
886                    program_name);
887           if (exit_on_error) exit (EXIT_FAILURE);
888           goto next_command;
889         }
890         *(pend-1) = '\0';
891         */
892       } else if (*p != ' ' && *p != '\t') {
893         /* If the first character is a ~ then note that this parameter
894          * is a candidate for ~username expansion.  NB this does not
895          * apply to quoted parameters.
896          */
897         tilde_candidate = *p == '~';
898         len = strcspn (p, " \t");
899         if (p[len]) {
900           p[len] = '\0';
901           pend = &p[len+1];
902         } else
903           pend = &p[len];
904       } else {
905         fprintf (stderr, _("%s: internal error parsing string at '%s'\n"),
906                  program_name, p);
907         abort ();
908       }
909
910       if (!tilde_candidate)
911         argv[i] = p;
912       else
913         argv[i] = try_tilde_expansion (p);
914       i++;
915       p = pend;
916
917       if (*p)
918         p += strspn (p, " \t");
919     }
920
921     if (i == sizeof argv / sizeof argv[0]) {
922       fprintf (stderr, _("%s: too many arguments\n"), program_name);
923       if (exit_on_error) exit (EXIT_FAILURE);
924       goto next_command;
925     }
926
927     argv[i] = NULL;
928
929   got_command:
930     if (issue_command (cmd, argv, pipe) == -1) {
931       if (exit_on_error) exit (EXIT_FAILURE);
932     }
933
934   next_command:;
935   }
936   if (prompt) printf ("\n");
937 }
938
939 static void
940 cmdline (char *argv[], int optind, int argc)
941 {
942   const char *cmd;
943   char **params;
944
945   exit_on_error = 1;
946
947   if (optind >= argc) return;
948
949   cmd = argv[optind++];
950   if (STREQ (cmd, ":")) {
951     fprintf (stderr, _("%s: empty command on command line\n"), program_name);
952     exit (EXIT_FAILURE);
953   }
954
955   /* Allow -cmd on the command line to mean (temporarily) override
956    * the normal exit on error (RHBZ#578407).
957    */
958   if (cmd[0] == '-') {
959     exit_on_error = 0;
960     cmd++;
961   }
962
963   params = &argv[optind];
964
965   /* Search for end of command list or ":" ... */
966   while (optind < argc && STRNEQ (argv[optind], ":"))
967     optind++;
968
969   if (optind == argc) {
970     if (issue_command (cmd, params, NULL) == -1 && exit_on_error)
971         exit (EXIT_FAILURE);
972   } else {
973     argv[optind] = NULL;
974     if (issue_command (cmd, params, NULL) == -1 && exit_on_error)
975       exit (EXIT_FAILURE);
976     cmdline (argv, optind+1, argc);
977   }
978 }
979
980 int
981 issue_command (const char *cmd, char *argv[], const char *pipecmd)
982 {
983   int argc;
984   int stdout_saved_fd = -1;
985   int pid = 0;
986   int i, r;
987
988   reset_progress_bar ();
989
990   /* This counts the commands issued, starting at 1. */
991   command_num++;
992
993   /* For | ... commands.  Annoyingly we can't use popen(3) here. */
994   if (pipecmd) {
995     int fd[2];
996
997     if (fflush (stdout) == EOF) {
998       perror ("failed to flush standard output");
999       return -1;
1000     }
1001     if (pipe (fd) < 0) {
1002       perror ("pipe failed");
1003       return -1;
1004     }
1005     pid = fork ();
1006     if (pid == -1) {
1007       perror ("fork");
1008       return -1;
1009     }
1010
1011     if (pid == 0) {             /* Child process. */
1012       close (fd[1]);
1013       if (dup2 (fd[0], 0) < 0) {
1014         perror ("dup2 of stdin failed");
1015         _exit (1);
1016       }
1017
1018       r = system (pipecmd);
1019       if (r == -1) {
1020         perror (pipecmd);
1021         _exit (1);
1022       }
1023       _exit (WEXITSTATUS (r));
1024     }
1025
1026     if ((stdout_saved_fd = dup (1)) < 0) {
1027       perror ("failed to dup stdout");
1028       return -1;
1029     }
1030     close (fd[0]);
1031     if (dup2 (fd[1], 1) < 0) {
1032       perror ("failed to dup stdout");
1033       close (stdout_saved_fd);
1034       return -1;
1035     }
1036     close (fd[1]);
1037   }
1038
1039   for (argc = 0; argv[argc] != NULL; ++argc)
1040     ;
1041
1042   /* If --remote was set, then send this command to a remote process. */
1043   if (remote_control)
1044     r = rc_remote (remote_control, cmd, argc, argv, exit_on_error);
1045
1046   /* Otherwise execute it locally. */
1047   else if (STRCASEEQ (cmd, "help")) {
1048     if (argc == 0) {
1049       list_commands ();
1050       r = 0;
1051     } else
1052       r = display_command (argv[0]);
1053   }
1054   else if (STRCASEEQ (cmd, "quit") ||
1055            STRCASEEQ (cmd, "exit") ||
1056            STRCASEEQ (cmd, "q")) {
1057     quit = 1;
1058     r = 0;
1059   }
1060   else if (STRCASEEQ (cmd, "alloc") ||
1061            STRCASEEQ (cmd, "allocate"))
1062     r = do_alloc (cmd, argc, argv);
1063   else if (STRCASEEQ (cmd, "copy-in") ||
1064            STRCASEEQ (cmd, "copy_in"))
1065     r = do_copy_in (cmd, argc, argv);
1066   else if (STRCASEEQ (cmd, "copy-out") ||
1067            STRCASEEQ (cmd, "copy_out"))
1068     r = do_copy_out (cmd, argc, argv);
1069   else if (STRCASEEQ (cmd, "echo"))
1070     r = do_echo (cmd, argc, argv);
1071   else if (STRCASEEQ (cmd, "edit") ||
1072            STRCASEEQ (cmd, "vi") ||
1073            STRCASEEQ (cmd, "emacs"))
1074     r = do_edit (cmd, argc, argv);
1075   else if (STRCASEEQ (cmd, "lcd"))
1076     r = do_lcd (cmd, argc, argv);
1077   else if (STRCASEEQ (cmd, "glob"))
1078     r = do_glob (cmd, argc, argv);
1079   else if (STRCASEEQ (cmd, "man") ||
1080            STRCASEEQ (cmd, "manual"))
1081     r = do_man (cmd, argc, argv);
1082   else if (STRCASEEQ (cmd, "more") ||
1083            STRCASEEQ (cmd, "less"))
1084     r = do_more (cmd, argc, argv);
1085   else if (STRCASEEQ (cmd, "reopen"))
1086     r = do_reopen (cmd, argc, argv);
1087   else if (STRCASEEQ (cmd, "sparse"))
1088     r = do_sparse (cmd, argc, argv);
1089   else if (STRCASEEQ (cmd, "supported"))
1090     r = do_supported (cmd, argc, argv);
1091   else if (STRCASEEQ (cmd, "time"))
1092     r = do_time (cmd, argc, argv);
1093   else
1094     r = run_action (cmd, argc, argv);
1095
1096   /* Always flush stdout after every command, so that messages, results
1097    * etc appear immediately.
1098    */
1099   if (fflush (stdout) == EOF) {
1100     perror ("failed to flush standard output");
1101     return -1;
1102   }
1103
1104   if (pipecmd) {
1105     close (1);
1106     if (dup2 (stdout_saved_fd, 1) < 0) {
1107       perror ("failed to dup2 standard output");
1108       r = -1;
1109     }
1110     close (stdout_saved_fd);
1111     if (waitpid (pid, NULL, 0) < 0) {
1112       perror ("waiting for command to complete");
1113       r = -1;
1114     }
1115   }
1116
1117   return r;
1118 }
1119
1120 void
1121 list_builtin_commands (void)
1122 {
1123   /* help, man and quit should appear at the top */
1124   printf ("%-20s %s\n",
1125           "help", _("display a list of commands or help on a command"));
1126   printf ("%-20s %s\n",
1127           "man", _("read the manual"));
1128   printf ("%-20s %s\n",
1129           "quit", _("quit guestfish"));
1130
1131   printf ("%-20s %s\n",
1132           "alloc", _("allocate an image"));
1133   printf ("%-20s %s\n",
1134           "copy-in", _("copy files into an image"));
1135   printf ("%-20s %s\n",
1136           "copy-out", _("copy files out of an image"));
1137   printf ("%-20s %s\n",
1138           "echo", _("display a line of text"));
1139   printf ("%-20s %s\n",
1140           "edit", _("edit a file in the image"));
1141   printf ("%-20s %s\n",
1142           "lcd", _("local change directory"));
1143   printf ("%-20s %s\n",
1144           "glob", _("expand wildcards in command"));
1145   printf ("%-20s %s\n",
1146           "more", _("view a file in the pager"));
1147   printf ("%-20s %s\n",
1148           "reopen", _("close and reopen libguestfs handle"));
1149   printf ("%-20s %s\n",
1150           "sparse", _("allocate a sparse image file"));
1151   printf ("%-20s %s\n",
1152           "supported", _("list supported groups of commands"));
1153   printf ("%-20s %s\n",
1154           "time", _("measure time taken to run command"));
1155
1156   /* actions are printed after this (see list_commands) */
1157 }
1158
1159 int
1160 display_builtin_command (const char *cmd)
1161 {
1162   /* help for actions is auto-generated, see display_command */
1163
1164   if (STRCASEEQ (cmd, "alloc") ||
1165       STRCASEEQ (cmd, "allocate")) {
1166     printf (_("alloc - allocate an image\n"
1167               "     alloc <filename> <size>\n"
1168               "\n"
1169               "    This creates an empty (zeroed) file of the given size,\n"
1170               "    and then adds so it can be further examined.\n"
1171               "\n"
1172               "    For more advanced image creation, see qemu-img utility.\n"
1173               "\n"
1174               "    Size can be specified using standard suffixes, eg. '1M'.\n"
1175               ));
1176     return 0;
1177   }
1178   else if (STRCASEEQ (cmd, "copy-in") ||
1179            STRCASEEQ (cmd, "copy_in")) {
1180     printf (_("copy-in - copy files into an image\n"
1181               "     copy-in <local> [<local> ...] <remotedir>\n"
1182               "\n"
1183               "    Copy local files or directories recursively into the\n"
1184               "    image, placing them on a remote directory.\n"
1185               ));
1186     return 0;
1187   }
1188   else if (STRCASEEQ (cmd, "copy-out") ||
1189            STRCASEEQ (cmd, "copy_out")) {
1190     printf (_("copy-out - copy files out of an image\n"
1191               "     copy-out <remote> [<remote> ...] <localdir>\n"
1192               "\n"
1193               "    Copy remote files or directories recursively out of the\n"
1194               "    image, placing them in a local directory.\n"
1195               ));
1196     return 0;
1197   }
1198   else if (STRCASEEQ (cmd, "echo")) {
1199     printf (_("echo - display a line of text\n"
1200               "     echo [<params> ...]\n"
1201               "\n"
1202               "    This echos the parameters to the terminal.\n"));
1203     return 0;
1204   }
1205   else if (STRCASEEQ (cmd, "edit") ||
1206            STRCASEEQ (cmd, "vi") ||
1207            STRCASEEQ (cmd, "emacs")) {
1208     printf (_("edit - edit a file in the image\n"
1209               "     edit <filename>\n"
1210               "\n"
1211               "    This is used to edit a file.\n"
1212               "\n"
1213               "    It is the equivalent of (and is implemented by)\n"
1214               "    running \"cat\", editing locally, and then \"write\".\n"
1215               "\n"
1216               "    Normally it uses $EDITOR, but if you use the aliases\n"
1217               "    \"vi\" or \"emacs\" you will get those editors.\n"
1218               "\n"
1219               "    NOTE: This will not work reliably for large files\n"
1220               "    (> 2 MB) or binary files containing \\0 bytes.\n"));
1221     return 0;
1222   }
1223   else if (STRCASEEQ (cmd, "lcd")) {
1224     printf (_("lcd - local change directory\n"
1225               "    lcd <directory>\n"
1226               "\n"
1227               "    Change guestfish's current directory. This command is\n"
1228               "    useful if you want to download files to a particular\n"
1229               "    place.\n"));
1230     return 0;
1231   }
1232   else if (STRCASEEQ (cmd, "glob")) {
1233     printf (_("glob - expand wildcards in command\n"
1234               "    glob <command> [<args> ...]\n"
1235               "\n"
1236               "    Glob runs <command> with wildcards expanded in any\n"
1237               "    command args.  Note that the command is run repeatedly\n"
1238               "    once for each expanded argument.\n"));
1239     return 0;
1240   }
1241   else if (STRCASEEQ (cmd, "man") ||
1242            STRCASEEQ (cmd, "manual")) {
1243     printf (_("man - read the manual\n"
1244               "    man\n"
1245               "\n"
1246               "    Opens the manual page for guestfish.\n"));
1247     return 0;
1248   }
1249   else if (STRCASEEQ (cmd, "help")) {
1250     printf (_("help - display a list of commands or help on a command\n"
1251               "     help cmd\n"
1252               "     help\n"));
1253     return 0;
1254   }
1255   else if (STRCASEEQ (cmd, "more") ||
1256            STRCASEEQ (cmd, "less")) {
1257     printf (_("more - view a file in the pager\n"
1258               "     more <filename>\n"
1259               "\n"
1260               "    This is used to view a file in the pager.\n"
1261               "\n"
1262               "    It is the equivalent of (and is implemented by)\n"
1263               "    running \"cat\" and using the pager.\n"
1264               "\n"
1265               "    Normally it uses $PAGER, but if you use the alias\n"
1266               "    \"less\" then it always uses \"less\".\n"
1267               "\n"
1268               "    NOTE: This will not work reliably for large files\n"
1269               "    (> 2 MB) or binary files containing \\0 bytes.\n"));
1270     return 0;
1271   }
1272   else if (STRCASEEQ (cmd, "quit") ||
1273            STRCASEEQ (cmd, "exit") ||
1274            STRCASEEQ (cmd, "q")) {
1275     printf (_("quit - quit guestfish\n"
1276               "     quit\n"));
1277     return 0;
1278   }
1279   else if (STRCASEEQ (cmd, "reopen")) {
1280     printf (_("reopen - close and reopen the libguestfs handle\n"
1281               "     reopen\n"
1282               "\n"
1283               "Close and reopen the libguestfs handle.  It is not necessary to use\n"
1284               "this normally, because the handle is closed properly when guestfish\n"
1285               "exits.  However this is occasionally useful for testing.\n"));
1286     return 0;
1287   }
1288   else if (STRCASEEQ (cmd, "sparse")) {
1289     printf (_("sparse - allocate a sparse image file\n"
1290               "     sparse <filename> <size>\n"
1291               "\n"
1292               "    This creates an empty sparse file of the given size,\n"
1293               "    and then adds so it can be further examined.\n"
1294               "\n"
1295               "    In all respects it works the same as the 'alloc'\n"
1296               "    command, except that the image file is allocated\n"
1297               "    sparsely, which means that disk blocks are not assigned\n"
1298               "    to the file until they are needed.  Sparse disk files\n"
1299               "    only use space when written to, but they are slower\n"
1300               "    and there is a danger you could run out of real disk\n"
1301               "    space during a write operation.\n"
1302               "\n"
1303               "    For more advanced image creation, see qemu-img utility.\n"
1304               "\n"
1305               "    Size can be specified using standard suffixes, eg. '1M'.\n"
1306               ));
1307     return 0;
1308   }
1309   else if (STRCASEEQ (cmd, "supported")) {
1310     printf (_("supported - list supported groups of commands\n"
1311               "     supported\n"
1312               "\n"
1313               "    This command returns a list of the optional groups\n"
1314               "    known to the daemon, and indicates which ones are\n"
1315               "    supported by this build of the libguestfs appliance.\n"
1316               "\n"
1317               "    See also guestfs(3) section AVAILABILITY.\n"
1318               ));
1319     return 0;
1320   }
1321   else if (STRCASEEQ (cmd, "time")) {
1322     printf (_("time - measure time taken to run command\n"
1323               "    time <command> [<args> ...]\n"
1324               "\n"
1325               "    This runs <command> as usual, and prints the elapsed\n"
1326               "    time afterwards.\n"));
1327     return 0;
1328   }
1329   else {
1330     fprintf (stderr, _("%s: command not known, use -h to list all commands\n"),
1331              cmd);
1332     return -1;
1333   }
1334 }
1335
1336 /* This is printed when the user types in an unknown command for the
1337  * first command issued.  A common case is the user doing:
1338  *   guestfish disk.img
1339  * expecting guestfish to open 'disk.img' (in fact, this tried to
1340  * run a command 'disk.img').
1341  */
1342 void
1343 extended_help_message (void)
1344 {
1345   fprintf (stderr,
1346            _("Did you mean to open a disk image?  guestfish -a disk.img\n"
1347              "For a list of commands:             guestfish -h\n"
1348              "For complete documentation:         man guestfish\n"));
1349 }
1350
1351 void
1352 free_strings (char **argv)
1353 {
1354   int argc;
1355
1356   for (argc = 0; argv[argc] != NULL; ++argc)
1357     free (argv[argc]);
1358   free (argv);
1359 }
1360
1361 int
1362 count_strings (char *const *argv)
1363 {
1364   int c;
1365
1366   for (c = 0; argv[c]; ++c)
1367     ;
1368   return c;
1369 }
1370
1371 void
1372 print_strings (char *const *argv)
1373 {
1374   int argc;
1375
1376   for (argc = 0; argv[argc] != NULL; ++argc)
1377     printf ("%s\n", argv[argc]);
1378 }
1379
1380 void
1381 print_table (char *const *argv)
1382 {
1383   int i;
1384
1385   for (i = 0; argv[i] != NULL; i += 2)
1386     printf ("%s: %s\n", argv[i], argv[i+1]);
1387 }
1388
1389 int
1390 is_true (const char *str)
1391 {
1392   return
1393     STRCASENEQ (str, "0") &&
1394     STRCASENEQ (str, "f") &&
1395     STRCASENEQ (str, "false") &&
1396     STRCASENEQ (str, "n") &&
1397     STRCASENEQ (str, "no");
1398 }
1399
1400 /* Free strings from a non-NULL terminated char** */
1401 static void
1402 free_n_strings (char **str, size_t len)
1403 {
1404   size_t i;
1405
1406   for (i = 0; i < len; i++) {
1407     free (str[i]);
1408   }
1409   free (str);
1410 }
1411
1412 char **
1413 parse_string_list (const char *str)
1414 {
1415   char **argv = NULL;
1416   size_t argv_len = 0;
1417
1418   /* Current position pointer */
1419   const char *p = str;
1420
1421   /* Token might be simple:
1422    *  Token
1423    * or be quoted:
1424    *  'This is a single token'
1425    * or contain embedded single-quoted sections:
1426    *  This' is a sing'l'e to'ken
1427    *
1428    * The latter may seem over-complicated, but it's what a normal shell does.
1429    * Not doing it risks surprising somebody.
1430    *
1431    * This outer loop is over complete tokens.
1432    */
1433   while (*p) {
1434     char *tok = NULL;
1435     size_t tok_len = 0;
1436
1437     /* Skip leading whitespace */
1438     p += strspn (p, " \t");
1439
1440     char in_quote = 0;
1441
1442     /* This loop is over token 'fragments'. A token can be in multiple bits if
1443      * it contains single quotes. We also treat both sides of an escaped quote
1444      * as separate fragments because we can't just copy it: we have to remove
1445      * the \.
1446      */
1447     while (*p && (!c_isblank (*p) || in_quote)) {
1448       const char *end = p;
1449
1450       /* Check if the fragment starts with a quote */
1451       if ('\'' == *p) {
1452         /* Toggle in_quote */
1453         in_quote = !in_quote;
1454
1455         /* Skip the quote */
1456         p++; end++;
1457       }
1458
1459       /* If we're in a quote, look for an end quote */
1460       if (in_quote) {
1461         end += strcspn (end, "'");
1462       }
1463
1464       /* Otherwise, look for whitespace or a quote */
1465       else {
1466         end += strcspn (end, " \t'");
1467       }
1468
1469       /* Grow the token to accommodate the fragment */
1470       size_t tok_end = tok_len;
1471       tok_len += end - p;
1472       char *tok_new = realloc (tok, tok_len + 1);
1473       if (NULL == tok_new) {
1474         perror ("realloc");
1475         free_n_strings (argv, argv_len);
1476         free (tok);
1477         exit (EXIT_FAILURE);
1478       }
1479       tok = tok_new;
1480
1481       /* Check if we stopped on an escaped quote */
1482       if ('\'' == *end && end != p && *(end-1) == '\\') {
1483         /* Add everything before \' to the token */
1484         memcpy (&tok[tok_end], p, end - p - 1);
1485
1486         /* Add the quote */
1487         tok[tok_len-1] = '\'';
1488
1489         /* Already processed the quote */
1490         p = end + 1;
1491       }
1492
1493       else {
1494         /* Add the whole fragment */
1495         memcpy (&tok[tok_end], p, end - p);
1496
1497         p = end;
1498       }
1499     }
1500
1501     /* We've reached the end of a token. We shouldn't still be in quotes. */
1502     if (in_quote) {
1503       fprintf (stderr, _("Runaway quote in string \"%s\"\n"), str);
1504
1505       free_n_strings (argv, argv_len);
1506
1507       return NULL;
1508     }
1509
1510     /* Add this token if there is one. There might not be if there was
1511      * whitespace at the end of the input string */
1512     if (tok) {
1513       /* Add the NULL terminator */
1514       tok[tok_len] = '\0';
1515
1516       /* Add the argument to the argument list */
1517       argv_len++;
1518       char **argv_new = realloc (argv, sizeof (*argv) * argv_len);
1519       if (NULL == argv_new) {
1520         perror ("realloc");
1521         free_n_strings (argv, argv_len-1);
1522         free (tok);
1523         exit (EXIT_FAILURE);
1524       }
1525       argv = argv_new;
1526
1527       argv[argv_len-1] = tok;
1528     }
1529   }
1530
1531   /* NULL terminate the argument list */
1532   argv_len++;
1533   char **argv_new = realloc (argv, sizeof (*argv) * argv_len);
1534   if (NULL == argv_new) {
1535     perror ("realloc");
1536     free_n_strings (argv, argv_len-1);
1537     exit (EXIT_FAILURE);
1538   }
1539   argv = argv_new;
1540
1541   argv[argv_len-1] = NULL;
1542
1543   return argv;
1544 }
1545
1546 #ifdef HAVE_LIBREADLINE
1547 static char histfile[1024];
1548 static int nr_history_lines = 0;
1549 #endif
1550
1551 static void
1552 initialize_readline (void)
1553 {
1554 #ifdef HAVE_LIBREADLINE
1555   const char *home;
1556
1557   home = getenv ("HOME");
1558   if (home) {
1559     snprintf (histfile, sizeof histfile, "%s/.guestfish", home);
1560     using_history ();
1561     (void) read_history (histfile);
1562   }
1563
1564   rl_readline_name = "guestfish";
1565   rl_attempted_completion_function = do_completion;
1566
1567   /* Note that .inputrc (or /etc/inputrc) is not read until the first
1568    * call the readline(), which happens later.  Therefore, these
1569    * provide default values which can be overridden by the user if
1570    * they wish.
1571    */
1572   (void) rl_variable_bind ("completion-ignore-case", "on");
1573 #endif
1574 }
1575
1576 static void
1577 cleanup_readline (void)
1578 {
1579 #ifdef HAVE_LIBREADLINE
1580   int fd;
1581
1582   if (histfile[0] != '\0') {
1583     fd = open (histfile, O_WRONLY|O_CREAT, 0644);
1584     if (fd == -1) {
1585       perror (histfile);
1586       return;
1587     }
1588     close (fd);
1589
1590 #ifdef HAVE_APPEND_HISTORY
1591     (void) append_history (nr_history_lines, histfile);
1592 #else
1593     (void) write_history (histfile);
1594 #endif
1595   }
1596 #endif
1597 }
1598
1599 #ifdef HAVE_LIBREADLINE
1600 static void
1601 add_history_line (const char *line)
1602 {
1603   add_history (line);
1604   nr_history_lines++;
1605 }
1606 #endif
1607
1608 int
1609 xwrite (int fd, const void *v_buf, size_t len)
1610 {
1611   int r;
1612   const char *buf = v_buf;
1613
1614   while (len > 0) {
1615     r = write (fd, buf, len);
1616     if (r == -1) {
1617       perror ("write");
1618       return -1;
1619     }
1620     buf += r;
1621     len -= r;
1622   }
1623
1624   return 0;
1625 }
1626
1627 /* Resolve the special "win:..." form for Windows-specific paths.
1628  * This always returns a newly allocated string which is freed by the
1629  * caller function in "cmds.c".
1630  */
1631 char *
1632 resolve_win_path (const char *path)
1633 {
1634   char *ret;
1635   size_t i;
1636
1637   if (STRCASENEQLEN (path, "win:", 4)) {
1638     ret = strdup (path);
1639     if (ret == NULL)
1640       perror ("strdup");
1641     return ret;
1642   }
1643
1644   path += 4;
1645
1646   /* Drop drive letter, if it's "C:". */
1647   if (STRCASEEQLEN (path, "c:", 2))
1648     path += 2;
1649
1650   if (!*path) {
1651     ret = strdup ("/");
1652     if (ret == NULL)
1653       perror ("strdup");
1654     return ret;
1655   }
1656
1657   ret = strdup (path);
1658   if (ret == NULL) {
1659     perror ("strdup");
1660     return NULL;
1661   }
1662
1663   /* Blindly convert any backslashes into forward slashes.  Is this good? */
1664   for (i = 0; i < strlen (ret); ++i)
1665     if (ret[i] == '\\')
1666       ret[i] = '/';
1667
1668   char *t = guestfs_case_sensitive_path (g, ret);
1669   free (ret);
1670   ret = t;
1671
1672   return ret;
1673 }
1674
1675 /* Resolve the special FileIn paths ("-" or "-<<END" or filename).
1676  * The caller (cmds.c) will call free_file_in after the command has
1677  * run which should clean up resources.
1678  */
1679 static char *file_in_heredoc (const char *endmarker);
1680 static char *file_in_tmpfile = NULL;
1681
1682 char *
1683 file_in (const char *arg)
1684 {
1685   char *ret;
1686
1687   if (STREQ (arg, "-")) {
1688     ret = strdup ("/dev/stdin");
1689     if (!ret) {
1690       perror ("strdup");
1691       return NULL;
1692     }
1693   }
1694   else if (STRPREFIX (arg, "-<<")) {
1695     const char *endmarker = &arg[3];
1696     if (*endmarker == '\0') {
1697       fprintf (stderr, "%s: missing end marker in -<< expression\n",
1698                program_name);
1699       return NULL;
1700     }
1701     ret = file_in_heredoc (endmarker);
1702     if (ret == NULL)
1703       return NULL;
1704   }
1705   else {
1706     ret = strdup (arg);
1707     if (!ret) {
1708       perror ("strdup");
1709       return NULL;
1710     }
1711   }
1712
1713   return ret;
1714 }
1715
1716 static char *
1717 file_in_heredoc (const char *endmarker)
1718 {
1719   static const char template[] = "/tmp/heredocXXXXXX";
1720   file_in_tmpfile = strdup (template);
1721   if (file_in_tmpfile == NULL) {
1722     perror ("strdup");
1723     return NULL;
1724   }
1725
1726   int fd = mkstemp (file_in_tmpfile);
1727   if (fd == -1) {
1728     perror ("mkstemp");
1729     goto error1;
1730   }
1731
1732   size_t markerlen = strlen (endmarker);
1733
1734   char buffer[BUFSIZ];
1735   int write_error = 0;
1736   while (fgets (buffer, sizeof buffer, stdin) != NULL) {
1737     /* Look for "END"<EOF> or "END\n" in input. */
1738     size_t blen = strlen (buffer);
1739     if (STREQLEN (buffer, endmarker, markerlen) &&
1740         (blen == markerlen ||
1741          (blen == markerlen+1 && buffer[markerlen] == '\n')))
1742       goto found_end;
1743
1744     if (xwrite (fd, buffer, blen) == -1) {
1745       if (!write_error) perror ("write");
1746       write_error = 1;
1747       /* continue reading up to the end marker */
1748     }
1749   }
1750
1751   /* Reached EOF of stdin without finding the end marker, which
1752    * is likely to be an error.
1753    */
1754   fprintf (stderr, "%s: end of input reached without finding '%s'\n",
1755            program_name, endmarker);
1756   goto error2;
1757
1758  found_end:
1759   if (write_error) {
1760     close (fd);
1761     goto error2;
1762   }
1763
1764   if (close (fd) == -1) {
1765     perror ("close");
1766     goto error2;
1767   }
1768
1769   return file_in_tmpfile;
1770
1771  error2:
1772   unlink (file_in_tmpfile);
1773
1774  error1:
1775   free (file_in_tmpfile);
1776   file_in_tmpfile = NULL;
1777   return NULL;
1778 }
1779
1780 void
1781 free_file_in (char *s)
1782 {
1783   if (file_in_tmpfile) {
1784     if (unlink (file_in_tmpfile) == -1)
1785       perror (file_in_tmpfile);
1786     file_in_tmpfile = NULL;
1787   }
1788
1789   /* Free the device or file name which was strdup'd in file_in().
1790    * Note it's not immediately clear, but for -<< heredocs,
1791    * s == file_in_tmpfile, so this frees up that buffer.
1792    */
1793   free (s);
1794 }
1795
1796 /* Resolve the special FileOut paths ("-" or filename).
1797  * The caller (cmds.c) will call free (str) after the command has run.
1798  */
1799 char *
1800 file_out (const char *arg)
1801 {
1802   char *ret;
1803
1804   if (STREQ (arg, "-"))
1805     ret = strdup ("/dev/stdout");
1806   else
1807     ret = strdup (arg);
1808
1809   if (!ret) {
1810     perror ("strdup");
1811     return NULL;
1812   }
1813   return ret;
1814 }
1815
1816 /* Read a passphrase ('Key') from /dev/tty with echo off.
1817  * The caller (cmds.c) will call free on the string afterwards.
1818  * Based on the code in cryptsetup file lib/utils.c.
1819  */
1820 char *
1821 read_key (const char *param)
1822 {
1823   FILE *infp, *outfp;
1824   struct termios orig, temp;
1825   char *ret = NULL;
1826
1827   /* Read and write to /dev/tty if available. */
1828   if (keys_from_stdin ||
1829       (infp = outfp = fopen ("/dev/tty", "w+")) == NULL) {
1830     infp = stdin;
1831     outfp = stdout;
1832   }
1833
1834   /* Print the prompt and set no echo. */
1835   int tty = isatty (fileno (infp));
1836   int tcset = 0;
1837   if (tty) {
1838     fprintf (outfp, _("Enter key or passphrase (\"%s\"): "), param);
1839
1840     if (tcgetattr (fileno (infp), &orig) == -1) {
1841       perror ("tcgetattr");
1842       goto error;
1843     }
1844     memcpy (&temp, &orig, sizeof temp);
1845     temp.c_lflag &= ~ECHO;
1846
1847     tcsetattr (fileno (infp), TCSAFLUSH, &temp);
1848     tcset = 1;
1849   }
1850
1851   size_t n = 0;
1852   ssize_t len;
1853   len = getline (&ret, &n, infp);
1854   if (len == -1) {
1855     perror ("getline");
1856     ret = NULL;
1857     goto error;
1858   }
1859
1860   /* Remove the terminating \n if there is one. */
1861   if (len > 0 && ret[len-1] == '\n')
1862     ret[len-1] = '\0';
1863
1864  error:
1865   /* Restore echo, close file descriptor. */
1866   if (tty && tcset) {
1867     printf ("\n");
1868     tcsetattr (fileno (infp), TCSAFLUSH, &orig);
1869   }
1870
1871   if (infp != stdin)
1872     fclose (infp); /* outfp == infp, so this is closed also */
1873
1874   return ret;
1875 }