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