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