Version 1.9.10.
[libguestfs.git] / fish / fish.c
index 566d769..b62c098 100644 (file)
@@ -1,5 +1,5 @@
 /* guestfish - the filesystem interactive shell
- * Copyright (C) 2009-2010 Red Hat Inc.
+ * Copyright (C) 2009-2011 Red Hat Inc.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -61,6 +61,7 @@ static void shell_script (void);
 static void script (int prompt);
 static void cmdline (char *argv[], int optind, int argc);
 static struct parsed_command parse_command_line (char *buf, int *exit_on_error_rtn);
+static int execute_and_inline (const char *cmd, int exit_on_error);
 static void initialize_readline (void);
 static void cleanup_readline (void);
 #ifdef HAVE_LIBREADLINE
@@ -73,6 +74,7 @@ static int override_progress_bars = -1;
 guestfs_h *g;
 
 int read_only = 0;
+int live = 0;
 int quit = 0;
 int verbose = 0;
 int remote_control_listen = 0;
@@ -123,6 +125,7 @@ usage (int status)
              "  -i|--inspector       Automatically mount filesystems\n"
              "  --keys-from-stdin    Read passphrases from stdin\n"
              "  --listen             Listen for remote commands\n"
+             "  --live               Connect to a live virtual machine\n"
              "  -m|--mount dev[:mnt] Mount dev on mnt (if omitted, /)\n"
              "  -n|--no-sync         Don't autosync\n"
              "  -N|--new type        Create prepared disk (test1.img, ...)\n"
@@ -172,6 +175,7 @@ main (int argc, char *argv[])
     { "inspector", 0, 0, 'i' },
     { "keys-from-stdin", 0, 0, 0 },
     { "listen", 0, 0, 0 },
+    { "live", 0, 0, 0 },
     { "mount", 1, 0, 'm' },
     { "new", 1, 0, 'N' },
     { "no-dest-paths", 0, 0, 'D' },
@@ -276,6 +280,8 @@ main (int argc, char *argv[])
           format = optarg;
       } else if (STREQ (long_options[option_index].name, "csh")) {
         remote_control_csh = 1;
+      } else if (STREQ (long_options[option_index].name, "live")) {
+        live = 1;
       } else {
         fprintf (stderr, _("%s: unknown long option: %s (%d)\n"),
                  program_name, long_options[option_index].name, option_index);
@@ -677,7 +683,10 @@ parse_command_line (char *buf, int *exit_on_error_rtn)
   int r;
   const size_t argv_len = sizeof pcmd.argv / sizeof pcmd.argv[0];
 
-  pcmd.pipe = NULL;
+  /* Note that pcmd.pipe must be set to NULL for correct usage.  Other
+   * fields do not need to be, but this silences a gcc warning.
+   */
+  memset (&pcmd, 0, sizeof pcmd);
 
  again:
   /* Skip any initial whitespace before the command. */
@@ -708,6 +717,18 @@ parse_command_line (char *buf, int *exit_on_error_rtn)
     return pcmd;
   }
 
+  /* If the next two characters are "<!" then pass the command to
+   * popen(3), read the result and execute it as guestfish commands.
+   */
+  if (buf[0] == '<' && buf[1] == '!') {
+    int r = execute_and_inline (&buf[2], *exit_on_error_rtn);
+    if (r == -1)
+      pcmd.status = -1;
+    else
+      pcmd.status = 0;
+    return pcmd;
+  }
+
   /* If the next character is '-' allow the command to fail without
    * exiting on error (just for this one command though).
    */
@@ -823,6 +844,50 @@ parse_command_line (char *buf, int *exit_on_error_rtn)
   return pcmd;
 }
 
+/* Used to handle "<!" (execute command and inline result). */
+static int
+execute_and_inline (const char *cmd, int global_exit_on_error)
+{
+  FILE *pp;
+  char *line = NULL;
+  size_t len = 0;
+  ssize_t n;
+  int exit_on_error;
+  struct parsed_command pcmd;
+
+  pp = popen (cmd, "r");
+  if (!pp) {
+    perror ("popen");
+    return -1;
+  }
+
+  while ((n = getline (&line, &len, pp)) != -1) {
+    exit_on_error = global_exit_on_error;
+
+    /* Chomp final line ending which parse_command_line would not expect. */
+    if (n > 0 && line[n-1] == '\n')
+      line[n-1] = '\0';
+
+    pcmd = parse_command_line (line, &exit_on_error);
+    if (pcmd.status == -1 && exit_on_error)
+      exit (EXIT_FAILURE);
+    if (pcmd.status == 1) {
+      if (issue_command (pcmd.cmd, pcmd.argv, pcmd.pipe, exit_on_error) == -1) {
+        if (exit_on_error) exit (EXIT_FAILURE);
+      }
+    }
+  }
+
+  free (line);
+
+  if (pclose (pp) == -1) {
+    perror ("pclose");
+    return -1;
+  }
+
+  return 0;
+}
+
 static void
 cmdline (char *argv[], int optind, int argc)
 {