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