Fix detection of optional libvirt support in virt-inspector.
[libguestfs.git] / fish / fish.c
1 /* guestfish - the filesystem interactive shell
2  * Copyright (C) 2009 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 #define _GNU_SOURCE // for strchrnul
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <getopt.h>
29 #include <signal.h>
30 #include <assert.h>
31 #include <ctype.h>
32
33 #ifdef HAVE_LIBREADLINE
34 #include <readline/readline.h>
35 #include <readline/history.h>
36 #endif
37
38 #include <guestfs.h>
39
40 #include "fish.h"
41
42 struct mp {
43   struct mp *next;
44   char *device;
45   char *mountpoint;
46 };
47
48 struct drv {
49   struct drv *next;
50   char *filename;
51 };
52
53 static void add_drives (struct drv *drv);
54 static void mount_mps (struct mp *mp);
55 static void interactive (void);
56 static void shell_script (void);
57 static void script (int prompt);
58 static void cmdline (char *argv[], int optind, int argc);
59 static void initialize_readline (void);
60 static void cleanup_readline (void);
61 static void add_history_line (const char *);
62
63 /* Currently open libguestfs handle. */
64 guestfs_h *g;
65
66 int read_only = 0;
67 int quit = 0;
68 int verbose = 0;
69
70 int
71 launch (guestfs_h *_g)
72 {
73   assert (_g == g);
74
75   if (guestfs_is_config (g)) {
76     if (guestfs_launch (g) == -1)
77       return -1;
78     if (guestfs_wait_ready (g) == -1)
79       return -1;
80   }
81   return 0;
82 }
83
84 static void
85 usage (void)
86 {
87   fprintf (stderr,
88            _("guestfish: guest filesystem shell\n"
89              "guestfish lets you edit virtual machine filesystems\n"
90              "Copyright (C) 2009 Red Hat Inc.\n"
91              "Usage:\n"
92              "  guestfish [--options] cmd [: cmd : cmd ...]\n"
93              "  guestfish -i libvirt-domain\n"
94              "  guestfish -i disk-image(s)\n"
95              "or for interactive use:\n"
96              "  guestfish\n"
97              "or from a shell script:\n"
98              "  guestfish <<EOF\n"
99              "  cmd\n"
100              "  ...\n"
101              "  EOF\n"
102              "Options:\n"
103              "  -h|--cmd-help        List available commands\n"
104              "  -h|--cmd-help cmd    Display detailed help on 'cmd'\n"
105              "  -a|--add image       Add image\n"
106              "  -D|--no-dest-paths   Don't tab-complete paths from guest fs\n"
107              "  -f|--file file       Read commands from file\n"
108              "  -i|--inspector       Run virt-inspector to get disk mountpoints\n"
109              "  -m|--mount dev[:mnt] Mount dev on mnt (if omitted, /)\n"
110              "  -n|--no-sync         Don't autosync\n"
111              "  -r|--ro              Mount read-only\n"
112              "  -v|--verbose         Verbose messages\n"
113              "  -V|--version         Display version and exit\n"
114              "For more information,  see the manpage guestfish(1).\n"));
115 }
116
117 int
118 main (int argc, char *argv[])
119 {
120   static const char *options = "a:f:h::im:nrv?V";
121   static struct option long_options[] = {
122     { "add", 1, 0, 'a' },
123     { "cmd-help", 2, 0, 'h' },
124     { "file", 1, 0, 'f' },
125     { "help", 0, 0, '?' },
126     { "inspector", 0, 0, 'i' },
127     { "mount", 1, 0, 'm' },
128     { "no-dest-paths", 0, 0, 'D' },
129     { "no-sync", 0, 0, 'n' },
130     { "ro", 0, 0, 'r' },
131     { "verbose", 0, 0, 'v' },
132     { "version", 0, 0, 'V' },
133     { 0, 0, 0, 0 }
134   };
135   struct drv *drvs = NULL;
136   struct drv *drv;
137   struct mp *mps = NULL;
138   struct mp *mp;
139   char *p, *file = NULL;
140   int c, inspector = 0;
141
142   initialize_readline ();
143
144   /* guestfs_create is meant to be a lightweight operation, so
145    * it's OK to do it early here.
146    */
147   g = guestfs_create ();
148   if (g == NULL) {
149     fprintf (stderr, _("guestfs_create: failed to create handle\n"));
150     exit (1);
151   }
152
153   guestfs_set_autosync (g, 1);
154
155   /* If developing, add ./appliance to the path.  Note that libtools
156    * interferes with this because uninstalled guestfish is a shell
157    * script that runs the real program with an absolute path.  Detect
158    * that too.
159    *
160    * BUT if LIBGUESTFS_PATH environment variable is already set by
161    * the user, then don't override it.
162    */
163   if (getenv ("LIBGUESTFS_PATH") == NULL &&
164       argv[0] &&
165       (argv[0][0] != '/' || strstr (argv[0], "/.libs/lt-") != NULL))
166     guestfs_set_path (g, "appliance:" GUESTFS_DEFAULT_PATH);
167
168   for (;;) {
169     c = getopt_long (argc, argv, options, long_options, NULL);
170     if (c == -1) break;
171
172     switch (c) {
173     case 'a':
174       if (access (optarg, R_OK) != 0) {
175         perror (optarg);
176         exit (1);
177       }
178       drv = malloc (sizeof (struct drv));
179       if (!drv) {
180         perror ("malloc");
181         exit (1);
182       }
183       drv->filename = optarg;
184       drv->next = drvs;
185       drvs = drv;
186       break;
187
188     case 'D':
189       complete_dest_paths = 0;
190       break;
191
192     case 'f':
193       if (file) {
194         fprintf (stderr, _("guestfish: only one -f parameter can be given\n"));
195         exit (1);
196       }
197       file = optarg;
198       break;
199
200     case 'h':
201       if (optarg)
202         display_command (optarg);
203       else if (argv[optind] && argv[optind][0] != '-')
204         display_command (argv[optind++]);
205       else
206         list_commands ();
207       exit (0);
208
209     case 'i':
210       inspector = 1;
211       break;
212
213     case 'm':
214       mp = malloc (sizeof (struct mp));
215       if (!mp) {
216         perror ("malloc");
217         exit (1);
218       }
219       p = strchr (optarg, ':');
220       if (p) {
221         *p = '\0';
222         mp->mountpoint = p+1;
223       } else
224         mp->mountpoint = "/";
225       mp->device = optarg;
226       mp->next = mps;
227       mps = mp;
228       break;
229
230     case 'n':
231       guestfs_set_autosync (g, 0);
232       break;
233
234     case 'r':
235       read_only = 1;
236       break;
237
238     case 'v':
239       verbose++;
240       guestfs_set_verbose (g, verbose);
241       break;
242
243     case 'V':
244       printf ("guestfish %s\n", PACKAGE_VERSION);
245       exit (0);
246
247     case '?':
248       usage ();
249       exit (0);
250
251     default:
252       fprintf (stderr, _("guestfish: unexpected command line option 0x%x\n"),
253                c);
254       exit (1);
255     }
256   }
257
258   /* Inspector mode invalidates most of the other arguments. */
259   if (inspector) {
260     char cmd[1024];
261     int r;
262
263     if (drvs || mps) {
264       fprintf (stderr, _("guestfish: cannot use -i option with -a or -m\n"));
265       exit (1);
266     }
267     if (optind >= argc) {
268       fprintf (stderr, _("guestfish -i requires a libvirt domain or path(s) to disk image(s)\n"));
269       exit (1);
270     }
271
272     strcpy (cmd, "a=`virt-inspector");
273     while (optind < argc) {
274       if (strlen (cmd) + strlen (argv[optind]) + strlen (argv[0]) + 60
275           >= sizeof cmd) {
276         fprintf (stderr, _("guestfish: virt-inspector command too long for fixed-size buffer\n"));
277         exit (1);
278       }
279       strcat (cmd, " '");
280       strcat (cmd, argv[optind]);
281       strcat (cmd, "'");
282       optind++;
283     }
284
285     if (read_only)
286       strcat (cmd, " --ro-fish");
287     else
288       strcat (cmd, " --fish");
289
290     sprintf (&cmd[strlen(cmd)], "` && %s $a", argv[0]);
291
292     if (guestfs_get_verbose (g))
293       strcat (cmd, " -v");
294     if (!guestfs_get_autosync (g))
295       strcat (cmd, " -n");
296
297     /*printf ("%s\n", cmd);*/
298
299     r = system (cmd);
300     if (r == -1) {
301       perror ("system");
302       exit (1);
303     }
304     exit (WEXITSTATUS (r));
305   }
306
307   /* If we've got drives to add, add them now. */
308   add_drives (drvs);
309
310   /* If we've got mountpoints, we must launch the guest and mount them. */
311   if (mps != NULL) {
312     if (launch (g) == -1) exit (1);
313     mount_mps (mps);
314   }
315
316   /* -f (file) parameter? */
317   if (file) {
318     close (0);
319     if (open (file, O_RDONLY) == -1) {
320       perror (file);
321       exit (1);
322     }
323   }
324
325   /* Interactive, shell script, or command(s) on the command line? */
326   if (optind >= argc) {
327     if (isatty (0))
328       interactive ();
329     else
330       shell_script ();
331   }
332   else
333     cmdline (argv, optind, argc);
334
335   cleanup_readline ();
336
337   exit (0);
338 }
339
340 void
341 pod2text (const char *heading, const char *str)
342 {
343   FILE *fp;
344
345   fp = popen ("pod2text", "w");
346   if (fp == NULL) {
347     /* pod2text failed, maybe not found, so let's just print the
348      * source instead, since that's better than doing nothing.
349      */
350     printf ("%s\n\n%s\n", heading, str);
351     return;
352   }
353   fputs ("=head1 ", fp);
354   fputs (heading, fp);
355   fputs ("\n\n", fp);
356   fputs (str, fp);
357   pclose (fp);
358 }
359
360 /* List is built in reverse order, so mount them in reverse order. */
361 static void
362 mount_mps (struct mp *mp)
363 {
364   int r;
365
366   if (mp) {
367     mount_mps (mp->next);
368     if (!read_only)
369       r = guestfs_mount (g, mp->device, mp->mountpoint);
370     else
371       r = guestfs_mount_ro (g, mp->device, mp->mountpoint);
372     if (r == -1)
373       exit (1);
374   }
375 }
376
377 static void
378 add_drives (struct drv *drv)
379 {
380   int r;
381
382   if (drv) {
383     add_drives (drv->next);
384     if (!read_only)
385       r = guestfs_add_drive (g, drv->filename);
386     else
387       r = guestfs_add_drive_ro (g, drv->filename);
388     if (r == -1)
389       exit (1);
390   }
391 }
392
393 static void
394 interactive (void)
395 {
396   script (1);
397 }
398
399 static void
400 shell_script (void)
401 {
402   script (0);
403 }
404
405 #define FISH "><fs> "
406
407 static char *line_read = NULL;
408
409 static char *
410 rl_gets (int prompt)
411 {
412 #ifdef HAVE_LIBREADLINE
413
414   if (prompt) {
415     if (line_read) {
416       free (line_read);
417       line_read = NULL;
418     }
419
420     line_read = readline (prompt ? FISH : "");
421
422     if (line_read && *line_read)
423       add_history_line (line_read);
424
425     return line_read;
426   }
427
428 #endif /* HAVE_LIBREADLINE */
429
430   static char buf[8192];
431   int len;
432
433   if (prompt) printf (FISH);
434   line_read = fgets (buf, sizeof buf, stdin);
435
436   if (line_read) {
437     len = strlen (line_read);
438     if (len > 0 && buf[len-1] == '\n') buf[len-1] = '\0';
439   }
440
441   return line_read;
442 }
443
444 static void
445 script (int prompt)
446 {
447   char *buf;
448   char *cmd;
449   char *p, *pend;
450   char *argv[64];
451   int i, len;
452   int global_exit_on_error = !prompt;
453   int exit_on_error;
454
455   if (prompt)
456     printf (_("\n"
457               "Welcome to guestfish, the libguestfs filesystem interactive shell for\n"
458               "editing virtual machine filesystems.\n"
459               "\n"
460               "Type: 'help' for help with commands\n"
461               "      'quit' to quit the shell\n"
462               "\n"));
463
464   while (!quit) {
465     exit_on_error = global_exit_on_error;
466
467     buf = rl_gets (prompt);
468     if (!buf) {
469       quit = 1;
470       break;
471     }
472
473     /* Skip any initial whitespace before the command. */
474   again:
475     while (*buf && isspace (*buf))
476       buf++;
477
478     if (!*buf) continue;
479
480     /* If the next character is '#' then this is a comment. */
481     if (*buf == '#') continue;
482
483     /* If the next character is '!' then pass the whole lot to system(3). */
484     if (*buf == '!') {
485       int r;
486
487       r = system (buf+1);
488       if (exit_on_error) {
489         if (r == -1 ||
490             (WIFSIGNALED (r) &&
491              (WTERMSIG (r) == SIGINT || WTERMSIG (r) == SIGQUIT)) ||
492             WEXITSTATUS (r) != 0)
493           exit (1);
494       }
495       continue;
496     }
497
498     /* If the next character is '-' allow the command to fail without
499      * exiting on error (just for this one command though).
500      */
501     if (*buf == '-') {
502       exit_on_error = 0;
503       buf++;
504       goto again;
505     }
506
507     /* Get the command (cannot be quoted). */
508     len = strcspn (buf, " \t");
509
510     if (len == 0) continue;
511
512     cmd = buf;
513     i = 0;
514     if (buf[len] == '\0') {
515       argv[0] = NULL;
516       goto got_command;
517     }
518
519     buf[len] = '\0';
520     p = &buf[len+1];
521     p += strspn (p, " \t");
522
523     /* Get the parameters. */
524     while (*p && i < sizeof argv / sizeof argv[0]) {
525       /* Parameters which start with quotes or square brackets
526        * are treated specially.  Bare parameters are delimited
527        * by whitespace.
528        */
529       if (*p == '"') {
530         p++;
531         len = strcspn (p, "\"");
532         if (p[len] == '\0') {
533           fprintf (stderr, _("guestfish: unterminated double quote\n"));
534           if (exit_on_error) exit (1);
535           goto next_command;
536         }
537         if (p[len+1] && (p[len+1] != ' ' && p[len+1] != '\t')) {
538           fprintf (stderr, _("guestfish: command arguments not separated by whitespace\n"));
539           if (exit_on_error) exit (1);
540           goto next_command;
541         }
542         p[len] = '\0';
543         pend = p[len+1] ? &p[len+2] : &p[len+1];
544       } else if (*p == '\'') {
545         p++;
546         len = strcspn (p, "'");
547         if (p[len] == '\0') {
548           fprintf (stderr, _("guestfish: unterminated single quote\n"));
549           if (exit_on_error) exit (1);
550           goto next_command;
551         }
552         if (p[len+1] && (p[len+1] != ' ' && p[len+1] != '\t')) {
553           fprintf (stderr, _("guestfish: command arguments not separated by whitespace\n"));
554           if (exit_on_error) exit (1);
555           goto next_command;
556         }
557         p[len] = '\0';
558         pend = p[len+1] ? &p[len+2] : &p[len+1];
559         /*
560       } else if (*p == '[') {
561         int c = 1;
562         p++;
563         pend = p;
564         while (*pend && c != 0) {
565           if (*pend == '[') c++;
566           else if (*pend == ']') c--;
567           pend++;
568         }
569         if (c != 0) {
570           fprintf (stderr, _("guestfish: unterminated \"[...]\" sequence\n"));
571           if (exit_on_error) exit (1);
572           goto next_command;
573         }
574         if (*pend && (*pend != ' ' && *pend != '\t')) {
575           fprintf (stderr, _("guestfish: command arguments not separated by whitespace\n"));
576           if (exit_on_error) exit (1);
577           goto next_command;
578         }
579         *(pend-1) = '\0';
580         */
581       } else if (*p != ' ' && *p != '\t') {
582         len = strcspn (p, " \t");
583         if (p[len]) {
584           p[len] = '\0';
585           pend = &p[len+1];
586         } else
587           pend = &p[len];
588       } else {
589         fprintf (stderr, _("guestfish: internal error parsing string at '%s'\n"),
590                  p);
591         abort ();
592       }
593
594       argv[i++] = p;
595       p = pend;
596
597       if (*p)
598         p += strspn (p, " \t");
599     }
600
601     if (i == sizeof argv / sizeof argv[0]) {
602       fprintf (stderr, _("guestfish: too many arguments\n"));
603       if (exit_on_error) exit (1);
604       goto next_command;
605     }
606
607     argv[i] = NULL;
608
609   got_command:
610     if (issue_command (cmd, argv) == -1) {
611       if (exit_on_error) exit (1);
612     }
613
614   next_command:;
615   }
616   if (prompt) printf ("\n");
617 }
618
619 static void
620 cmdline (char *argv[], int optind, int argc)
621 {
622   const char *cmd;
623   char **params;
624
625   if (optind >= argc) return;
626
627   cmd = argv[optind++];
628   if (strcmp (cmd, ":") == 0) {
629     fprintf (stderr, _("guestfish: empty command on command line\n"));
630     exit (1);
631   }
632   params = &argv[optind];
633
634   /* Search for end of command list or ":" ... */
635   while (optind < argc && strcmp (argv[optind], ":") != 0)
636     optind++;
637
638   if (optind == argc) {
639     if (issue_command (cmd, params) == -1) exit (1);
640   } else {
641     argv[optind] = NULL;
642     if (issue_command (cmd, params) == -1) exit (1);
643     cmdline (argv, optind+1, argc);
644   }
645 }
646
647 int
648 issue_command (const char *cmd, char *argv[])
649 {
650   int argc;
651
652   for (argc = 0; argv[argc] != NULL; ++argc)
653     ;
654
655   if (strcasecmp (cmd, "help") == 0) {
656     if (argc == 0)
657       list_commands ();
658     else
659       display_command (argv[0]);
660     return 0;
661   }
662   else if (strcasecmp (cmd, "quit") == 0 ||
663            strcasecmp (cmd, "exit") == 0 ||
664            strcasecmp (cmd, "q") == 0) {
665     quit = 1;
666     return 0;
667   }
668   else if (strcasecmp (cmd, "alloc") == 0 ||
669            strcasecmp (cmd, "allocate") == 0)
670     return do_alloc (cmd, argc, argv);
671   else if (strcasecmp (cmd, "echo") == 0)
672     return do_echo (cmd, argc, argv);
673   else if (strcasecmp (cmd, "edit") == 0 ||
674            strcasecmp (cmd, "vi") == 0 ||
675            strcasecmp (cmd, "emacs") == 0)
676     return do_edit (cmd, argc, argv);
677   else if (strcasecmp (cmd, "lcd") == 0)
678     return do_lcd (cmd, argc, argv);
679   else if (strcasecmp (cmd, "glob") == 0)
680     return do_glob (cmd, argc, argv);
681   else
682     return run_action (cmd, argc, argv);
683 }
684
685 void
686 list_builtin_commands (void)
687 {
688   /* help and quit should appear at the top */
689   printf ("%-20s %s\n",
690           "help", _("display a list of commands or help on a command"));
691   printf ("%-20s %s\n",
692           "quit", _("quit guestfish"));
693
694   printf ("%-20s %s\n",
695           "alloc", _("allocate an image"));
696   printf ("%-20s %s\n",
697           "echo", _("display a line of text"));
698   printf ("%-20s %s\n",
699           "edit", _("edit a file in the image"));
700   printf ("%-20s %s\n",
701           "lcd", _("local change directory"));
702   printf ("%-20s %s\n",
703           "glob", _("expand wildcards in command"));
704
705   /* actions are printed after this (see list_commands) */
706 }
707
708 void
709 display_builtin_command (const char *cmd)
710 {
711   /* help for actions is auto-generated, see display_command */
712
713   if (strcasecmp (cmd, "alloc") == 0 ||
714       strcasecmp (cmd, "allocate") == 0)
715     printf (_("alloc - allocate an image\n"
716               "     alloc <filename> <size>\n"
717               "\n"
718               "    This creates an empty (zeroed) file of the given size,\n"
719               "    and then adds so it can be further examined.\n"
720               "\n"
721               "    For more advanced image creation, see qemu-img utility.\n"
722               "\n"
723               "    Size can be specified (where <nn> means a number):\n"
724               "    <nn>             number of kilobytes\n"
725               "      eg: 1440       standard 3.5\" floppy\n"
726               "    <nn>K or <nn>KB  number of kilobytes\n"
727               "    <nn>M or <nn>MB  number of megabytes\n"
728               "    <nn>G or <nn>GB  number of gigabytes\n"
729               "    <nn>sects        number of 512 byte sectors\n"));
730   else if (strcasecmp (cmd, "echo") == 0)
731     printf (_("echo - display a line of text\n"
732               "     echo [<params> ...]\n"
733               "\n"
734               "    This echos the parameters to the terminal.\n"));
735   else if (strcasecmp (cmd, "edit") == 0 ||
736            strcasecmp (cmd, "vi") == 0 ||
737            strcasecmp (cmd, "emacs") == 0)
738     printf (_("edit - edit a file in the image\n"
739               "     edit <filename>\n"
740               "\n"
741               "    This is used to edit a file.\n"
742               "\n"
743               "    It is the equivalent of (and is implemented by)\n"
744               "    running \"cat\", editing locally, and then \"write-file\".\n"
745               "\n"
746               "    Normally it uses $EDITOR, but if you use the aliases\n"
747               "    \"vi\" or \"emacs\" you will get those editors.\n"
748               "\n"
749               "    NOTE: This will not work reliably for large files\n"
750               "    (> 2 MB) or binary files containing \\0 bytes.\n"));
751   else if (strcasecmp (cmd, "lcd") == 0)
752     printf (_("lcd - local change directory\n"
753               "    lcd <directory>\n"
754               "\n"
755               "    Change guestfish's current directory. This command is\n"
756               "    useful if you want to download files to a particular\n"
757               "    place.\n"));
758   else if (strcasecmp (cmd, "glob") == 0)
759     printf (_("glob - expand wildcards in command\n"
760               "    glob <command> [<args> ...]\n"
761               "\n"
762               "    Glob runs <command> with wildcards expanded in any\n"
763               "    command args.  Note that the command is run repeatedly\n"
764               "    once for each expanded argument.\n"));
765   else if (strcasecmp (cmd, "help") == 0)
766     printf (_("help - display a list of commands or help on a command\n"
767               "     help cmd\n"
768               "     help\n"));
769   else if (strcasecmp (cmd, "quit") == 0 ||
770            strcasecmp (cmd, "exit") == 0 ||
771            strcasecmp (cmd, "q") == 0)
772     printf (_("quit - quit guestfish\n"
773               "     quit\n"));
774   else
775     fprintf (stderr, _("%s: command not known, use -h to list all commands\n"),
776              cmd);
777 }
778
779 void
780 free_strings (char **argv)
781 {
782   int argc;
783
784   for (argc = 0; argv[argc] != NULL; ++argc)
785     free (argv[argc]);
786   free (argv);
787 }
788
789 int
790 count_strings (char * const * const argv)
791 {
792   int c;
793
794   for (c = 0; argv[c]; ++c)
795     ;
796   return c;
797 }
798
799 void
800 print_strings (char * const * const argv)
801 {
802   int argc;
803
804   for (argc = 0; argv[argc] != NULL; ++argc)
805     printf ("%s\n", argv[argc]);
806 }
807
808 void
809 print_table (char * const * const argv)
810 {
811   int i;
812
813   for (i = 0; argv[i] != NULL; i += 2)
814     printf ("%s: %s\n", argv[i], argv[i+1]);
815 }
816
817 int
818 is_true (const char *str)
819 {
820   return
821     strcasecmp (str, "0") != 0 &&
822     strcasecmp (str, "f") != 0 &&
823     strcasecmp (str, "false") != 0 &&
824     strcasecmp (str, "n") != 0 &&
825     strcasecmp (str, "no") != 0;
826 }
827
828 /* XXX We could improve list parsing. */
829 char **
830 parse_string_list (const char *str)
831 {
832   char **argv;
833   const char *p, *pend;
834   int argc, i;
835
836   argc = 1;
837   for (i = 0; str[i]; ++i)
838     if (str[i] == ' ') argc++;
839
840   argv = malloc (sizeof (char *) * (argc+1));
841   if (argv == NULL) { perror ("malloc"); exit (1); }
842
843   p = str;
844   i = 0;
845   while (*p) {
846     pend = strchrnul (p, ' ');
847     argv[i] = strndup (p, pend-p);
848     i++;
849     p = *pend == ' ' ? pend+1 : pend;
850   }
851   argv[i] = NULL;
852
853   return argv;
854 }
855
856 #ifdef HAVE_LIBREADLINE
857 static char histfile[1024];
858 static int nr_history_lines = 0;
859 #endif
860
861 static void
862 initialize_readline (void)
863 {
864 #ifdef HAVE_LIBREADLINE
865   const char *home;
866
867   home = getenv ("HOME");
868   if (home) {
869     snprintf (histfile, sizeof histfile, "%s/.guestfish", home);
870     using_history ();
871     (void) read_history (histfile);
872   }
873
874   rl_readline_name = "guestfish";
875   rl_attempted_completion_function = do_completion;
876 #endif
877 }
878
879 static void
880 cleanup_readline (void)
881 {
882 #ifdef HAVE_LIBREADLINE
883   int fd;
884
885   if (histfile[0] != '\0') {
886     fd = open (histfile, O_WRONLY|O_CREAT, 0644);
887     if (fd == -1) {
888       perror (histfile);
889       return;
890     }
891     close (fd);
892
893     (void) append_history (nr_history_lines, histfile);
894   }
895 #endif
896 }
897
898 static void
899 add_history_line (const char *line)
900 {
901 #ifdef HAVE_LIBREADLINE
902   add_history (line);
903   nr_history_lines++;
904 #endif
905 }