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