mrc0mmand / rpms / libguestfs

Forked from rpms/libguestfs 3 years ago
Clone

Blame SOURCES/0185-p2v-Correct-parsing-of-proc-cmdline-including-quotin.patch

ffd6ed
From dfa319bc27420a611311834108e6807b300fc2b3 Mon Sep 17 00:00:00 2001
ffd6ed
From: "Richard W.M. Jones" <rjones@redhat.com>
ffd6ed
Date: Tue, 9 Jun 2015 17:53:05 +0100
ffd6ed
Subject: [PATCH] p2v: Correct parsing of /proc/cmdline, including quoting.
ffd6ed
ffd6ed
Fix the parsing of /proc/cmdline, including allowing double quoting of
ffd6ed
parameters.
ffd6ed
ffd6ed
This allows you to pass parameters to p2v on the command line which
ffd6ed
include spaces.
ffd6ed
ffd6ed
(cherry picked from commit 716244c33718c866edce9e7ee8f21ee612f53337)
ffd6ed
---
ffd6ed
 p2v/Makefile.am      |   1 +
ffd6ed
 p2v/kernel-cmdline.c | 193 +++++++++++++++++++++++++++++++++++++++++++++++++++
ffd6ed
 p2v/kernel.c         | 143 ++++++++++++++++----------------------
ffd6ed
 p2v/main.c           |  55 ++++-----------
ffd6ed
 p2v/p2v.h            |  10 ++-
ffd6ed
 po/POTFILES          |   1 +
ffd6ed
 6 files changed, 277 insertions(+), 126 deletions(-)
ffd6ed
 create mode 100644 p2v/kernel-cmdline.c
ffd6ed
ffd6ed
diff --git a/p2v/Makefile.am b/p2v/Makefile.am
ffd6ed
index c9d6b6f..cafe597 100644
ffd6ed
--- a/p2v/Makefile.am
ffd6ed
+++ b/p2v/Makefile.am
ffd6ed
@@ -49,6 +49,7 @@ virt_p2v_SOURCES = \
ffd6ed
 	copying.c \
ffd6ed
 	gui.c \
ffd6ed
 	kernel.c \
ffd6ed
+	kernel-cmdline.c \
ffd6ed
 	main.c \
ffd6ed
 	miniexpect.c \
ffd6ed
 	miniexpect.h \
ffd6ed
diff --git a/p2v/kernel-cmdline.c b/p2v/kernel-cmdline.c
ffd6ed
new file mode 100644
ffd6ed
index 0000000..142108a
ffd6ed
--- /dev/null
ffd6ed
+++ b/p2v/kernel-cmdline.c
ffd6ed
@@ -0,0 +1,193 @@
ffd6ed
+/* virt-p2v
ffd6ed
+ * Copyright (C) 2015 Red Hat Inc.
ffd6ed
+ *
ffd6ed
+ * This program is free software; you can redistribute it and/or modify
ffd6ed
+ * it under the terms of the GNU General Public License as published by
ffd6ed
+ * the Free Software Foundation; either version 2 of the License, or
ffd6ed
+ * (at your option) any later version.
ffd6ed
+ *
ffd6ed
+ * This program is distributed in the hope that it will be useful,
ffd6ed
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
ffd6ed
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
ffd6ed
+ * GNU General Public License for more details.
ffd6ed
+ *
ffd6ed
+ * You should have received a copy of the GNU General Public License
ffd6ed
+ * along with this program; if not, write to the Free Software
ffd6ed
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
ffd6ed
+ */
ffd6ed
+
ffd6ed
+/* Read /proc/cmdline.
ffd6ed
+ *
ffd6ed
+ * We only support double quoting, consistent with the Linux
ffd6ed
+ * documentation.
ffd6ed
+ * https://www.kernel.org/doc/Documentation/kernel-parameters.txt
ffd6ed
+ *
ffd6ed
+ * systemd supports single and double quoting and single character
ffd6ed
+ * escaping, but we don't support all that.
ffd6ed
+ *
ffd6ed
+ * Returns a list of key, value pairs, terminated by NULL.
ffd6ed
+ */
ffd6ed
+
ffd6ed
+#include <config.h>
ffd6ed
+
ffd6ed
+#include <stdio.h>
ffd6ed
+#include <stdlib.h>
ffd6ed
+#include <string.h>
ffd6ed
+#include <unistd.h>
ffd6ed
+#include <errno.h>
ffd6ed
+
ffd6ed
+#include "p2v.h"
ffd6ed
+
ffd6ed
+static void
ffd6ed
+add_null (char ***argv, size_t *lenp)
ffd6ed
+{
ffd6ed
+  (*lenp)++;
ffd6ed
+  *argv = realloc (*argv, *lenp * sizeof (char *));
ffd6ed
+  if (*argv == NULL) {
ffd6ed
+    perror ("realloc");
ffd6ed
+    exit (EXIT_FAILURE);
ffd6ed
+  }
ffd6ed
+  (*argv)[(*lenp)-1] = NULL;
ffd6ed
+}
ffd6ed
+
ffd6ed
+static void
ffd6ed
+add_string (char ***argv, size_t *lenp, const char *str, size_t len)
ffd6ed
+{
ffd6ed
+  add_null (argv, lenp);
ffd6ed
+  (*argv)[(*lenp)-1] = strndup (str, len);
ffd6ed
+  if ((*argv)[(*lenp)-1] == NULL) {
ffd6ed
+    perror ("strndup");
ffd6ed
+    exit (EXIT_FAILURE);
ffd6ed
+  }
ffd6ed
+}
ffd6ed
+
ffd6ed
+char **
ffd6ed
+parse_cmdline_string (const char *cmdline)
ffd6ed
+{
ffd6ed
+  char **ret = NULL;
ffd6ed
+  size_t len = 0;
ffd6ed
+  const char *p, *key = NULL, *value = NULL;
ffd6ed
+  enum {
ffd6ed
+    KEY_START = 0,
ffd6ed
+    KEY,
ffd6ed
+    VALUE_START,
ffd6ed
+    VALUE,
ffd6ed
+    VALUE_QUOTED
ffd6ed
+  } state = 0;
ffd6ed
+
ffd6ed
+  for (p = cmdline; *p; p++) {
ffd6ed
+    switch (state) {
ffd6ed
+    case KEY_START:             /* looking for the start of a key */
ffd6ed
+      if (*p == ' ') continue;
ffd6ed
+      key = p;
ffd6ed
+      state = KEY;
ffd6ed
+      break;
ffd6ed
+
ffd6ed
+    case KEY:                   /* reading key */
ffd6ed
+      if (*p == ' ') {
ffd6ed
+        add_string (&ret, &len, key, p-key);
ffd6ed
+        add_string (&ret, &len, "", 0);
ffd6ed
+        state = KEY_START;
ffd6ed
+      }
ffd6ed
+      else if (*p == '=') {
ffd6ed
+        add_string (&ret, &len, key, p-key);
ffd6ed
+        state = VALUE_START;
ffd6ed
+      }
ffd6ed
+      break;
ffd6ed
+
ffd6ed
+    case VALUE_START:           /* looking for the start of a value */
ffd6ed
+      if (*p == ' ') {
ffd6ed
+        add_string (&ret, &len, "", 0);
ffd6ed
+        state = KEY_START;
ffd6ed
+      }
ffd6ed
+      else if (*p == '"') {
ffd6ed
+        value = p+1;
ffd6ed
+        state = VALUE_QUOTED;
ffd6ed
+      }
ffd6ed
+      else {
ffd6ed
+        value = p;
ffd6ed
+        state = VALUE;
ffd6ed
+      }
ffd6ed
+      break;
ffd6ed
+
ffd6ed
+    case VALUE:                 /* reading unquoted value */
ffd6ed
+      if (*p == ' ') {
ffd6ed
+        add_string (&ret, &len, value, p-value);
ffd6ed
+        state = KEY_START;
ffd6ed
+      }
ffd6ed
+      break;
ffd6ed
+
ffd6ed
+    case VALUE_QUOTED:          /* reading quoted value */
ffd6ed
+      if (*p == '"') {
ffd6ed
+        add_string (&ret, &len, value, p-value);
ffd6ed
+        state = KEY_START;
ffd6ed
+      }
ffd6ed
+      break;
ffd6ed
+    }
ffd6ed
+  }
ffd6ed
+
ffd6ed
+  switch (state) {
ffd6ed
+  case KEY_START: break;
ffd6ed
+  case KEY:                     /* key followed by end of string */
ffd6ed
+    add_string (&ret, &len, key, p-key);
ffd6ed
+    add_string (&ret, &len, "", 0);
ffd6ed
+    break;
ffd6ed
+  case VALUE_START:             /* key= followed by end of string */
ffd6ed
+    add_string (&ret, &len, "", 0);
ffd6ed
+    break;
ffd6ed
+  case VALUE:                   /* key=value followed by end of string */
ffd6ed
+    add_string (&ret, &len, value, p-value);
ffd6ed
+    break;
ffd6ed
+  case VALUE_QUOTED:            /* unterminated key="value" */
ffd6ed
+    fprintf (stderr, "%s: warning: unterminated quoted string on kernel command line\n",
ffd6ed
+             guestfs_int_program_name);
ffd6ed
+    add_string (&ret, &len, value, p-value);
ffd6ed
+  }
ffd6ed
+
ffd6ed
+  add_null (&ret, &len;;
ffd6ed
+
ffd6ed
+  return ret;
ffd6ed
+}
ffd6ed
+
ffd6ed
+char **
ffd6ed
+parse_proc_cmdline (void)
ffd6ed
+{
ffd6ed
+  CLEANUP_FCLOSE FILE *fp = NULL;
ffd6ed
+  CLEANUP_FREE char *cmdline = NULL;
ffd6ed
+  size_t len = 0;
ffd6ed
+
ffd6ed
+  fp = fopen ("/proc/cmdline", "re");
ffd6ed
+  if (fp == NULL) {
ffd6ed
+    perror ("/proc/cmdline");
ffd6ed
+    return NULL;
ffd6ed
+  }
ffd6ed
+
ffd6ed
+  if (getline (&cmdline, &len, fp) == -1) {
ffd6ed
+    perror ("getline");
ffd6ed
+    return NULL;
ffd6ed
+  }
ffd6ed
+
ffd6ed
+  /* 'len' is not the length of the string, but the length of the
ffd6ed
+   * buffer.  We need to chomp the string.
ffd6ed
+   */
ffd6ed
+  len = strlen (cmdline);
ffd6ed
+
ffd6ed
+  if (len >= 1 && cmdline[len-1] == '\n')
ffd6ed
+    cmdline[len-1] = '\0';
ffd6ed
+
ffd6ed
+  return parse_cmdline_string (cmdline);
ffd6ed
+}
ffd6ed
+
ffd6ed
+const char *
ffd6ed
+get_cmdline_key (char **argv, const char *key)
ffd6ed
+{
ffd6ed
+  size_t i;
ffd6ed
+
ffd6ed
+  for (i = 0; argv[i] != NULL; i += 2) {
ffd6ed
+    if (STREQ (argv[i], key))
ffd6ed
+      return argv[i+1];
ffd6ed
+  }
ffd6ed
+
ffd6ed
+  /* Not found. */
ffd6ed
+  return NULL;
ffd6ed
+}
ffd6ed
diff --git a/p2v/kernel.c b/p2v/kernel.c
ffd6ed
index 481ac78..88d18bd 100644
ffd6ed
--- a/p2v/kernel.c
ffd6ed
+++ b/p2v/kernel.c
ffd6ed
@@ -35,46 +35,38 @@
ffd6ed
 static void notify_ui_callback (int type, const char *data);
ffd6ed
 
ffd6ed
 void
ffd6ed
-kernel_configuration (struct config *config, const char *cmdline)
ffd6ed
+kernel_configuration (struct config *config, char **cmdline, int cmdline_source)
ffd6ed
 {
ffd6ed
-  const char *r;
ffd6ed
-  size_t len;
ffd6ed
+  const char *p;
ffd6ed
 
ffd6ed
-  r = strstr (cmdline, "p2v.server=");
ffd6ed
-  assert (r); /* checked by caller */
ffd6ed
-  r += 5+6;
ffd6ed
-  len = strcspn (r, " ");
ffd6ed
+  p = get_cmdline_key (cmdline, "p2v.server");
ffd6ed
+  assert (p); /* checked by caller */
ffd6ed
   free (config->server);
ffd6ed
-  config->server = strndup (r, len);
ffd6ed
+  config->server = strdup (p);
ffd6ed
 
ffd6ed
-  r = strstr (cmdline, "p2v.port=");
ffd6ed
-  if (r) {
ffd6ed
-    r += 5+4;
ffd6ed
-    if (sscanf (r, "%d", &config->port) != 1) {
ffd6ed
+  p = get_cmdline_key (cmdline, "p2v.port");
ffd6ed
+  if (p) {
ffd6ed
+    if (sscanf (p, "%d", &config->port) != 1) {
ffd6ed
       fprintf (stderr, "%s: cannot parse p2v.port from kernel command line",
ffd6ed
                guestfs_int_program_name);
ffd6ed
       exit (EXIT_FAILURE);
ffd6ed
     }
ffd6ed
   }
ffd6ed
 
ffd6ed
-  r = strstr (cmdline, "p2v.username=");
ffd6ed
-  if (r) {
ffd6ed
-    r += 5+8;
ffd6ed
-    len = strcspn (r, " ");
ffd6ed
+  p = get_cmdline_key (cmdline, "p2v.username");
ffd6ed
+  if (p) {
ffd6ed
     free (config->username);
ffd6ed
-    config->username = strndup (r, len);
ffd6ed
+    config->username = strdup (p);
ffd6ed
   }
ffd6ed
 
ffd6ed
-  r = strstr (cmdline, "p2v.password=");
ffd6ed
-  if (r) {
ffd6ed
-    r += 5+8;
ffd6ed
-    len = strcspn (r, " ");
ffd6ed
+  p = get_cmdline_key (cmdline, "p2v.password");
ffd6ed
+  if (p) {
ffd6ed
     free (config->password);
ffd6ed
-    config->password = strndup (r, len);
ffd6ed
+    config->password = strdup (p);
ffd6ed
   }
ffd6ed
 
ffd6ed
-  r = strstr (cmdline, "p2v.sudo");
ffd6ed
-  if (r)
ffd6ed
+  p = get_cmdline_key (cmdline, "p2v.sudo");
ffd6ed
+  if (p)
ffd6ed
     config->sudo = 1;
ffd6ed
 
ffd6ed
   /* We should now be able to connect and interrogate virt-v2v
ffd6ed
@@ -88,30 +80,26 @@ kernel_configuration (struct config *config, const char *cmdline)
ffd6ed
     exit (EXIT_FAILURE);
ffd6ed
   }
ffd6ed
 
ffd6ed
-  r = strstr (cmdline, "p2v.name=");
ffd6ed
-  if (r) {
ffd6ed
-    r += 5+4;
ffd6ed
-    len = strcspn (r, " ");
ffd6ed
+  p = get_cmdline_key (cmdline, "p2v.name");
ffd6ed
+  if (p) {
ffd6ed
     free (config->guestname);
ffd6ed
-    config->guestname = strndup (r, len);
ffd6ed
+    config->guestname = strdup (p);
ffd6ed
   }
ffd6ed
 
ffd6ed
-  r = strstr (cmdline, "p2v.vcpus=");
ffd6ed
-  if (r) {
ffd6ed
-    r += 5+5;
ffd6ed
-    if (sscanf (r, "%d", &config->vcpus) != 1) {
ffd6ed
+  p = get_cmdline_key (cmdline, "p2v.vcpus");
ffd6ed
+  if (p) {
ffd6ed
+    if (sscanf (p, "%d", &config->vcpus) != 1) {
ffd6ed
       fprintf (stderr, "%s: cannot parse p2v.vcpus from kernel command line\n",
ffd6ed
                guestfs_int_program_name);
ffd6ed
       exit (EXIT_FAILURE);
ffd6ed
     }
ffd6ed
   }
ffd6ed
 
ffd6ed
-  r = strstr (cmdline, "p2v.memory=");
ffd6ed
-  if (r) {
ffd6ed
+  p = get_cmdline_key (cmdline, "p2v.memory");
ffd6ed
+  if (p) {
ffd6ed
     char mem_code[2];
ffd6ed
 
ffd6ed
-    r += 5+6;
ffd6ed
-    if (sscanf (r, "%" SCNu64 "%c", &config->memory, mem_code) != 1) {
ffd6ed
+    if (sscanf (p, "%" SCNu64 "%c", &config->memory, mem_code) != 1) {
ffd6ed
       fprintf (stderr, "%s: cannot parse p2v.memory from kernel command line\n",
ffd6ed
                guestfs_int_program_name);
ffd6ed
       exit (EXIT_FAILURE);
ffd6ed
@@ -128,88 +116,75 @@ kernel_configuration (struct config *config, const char *cmdline)
ffd6ed
     }
ffd6ed
   }
ffd6ed
 
ffd6ed
-  r = strstr (cmdline, "p2v.disks=");
ffd6ed
-  if (r) {
ffd6ed
+  p = get_cmdline_key (cmdline, "p2v.disks");
ffd6ed
+  if (p) {
ffd6ed
     CLEANUP_FREE char *t;
ffd6ed
 
ffd6ed
-    r += 5+5;
ffd6ed
-    len = strcspn (r, " ");
ffd6ed
-    t = strndup (r, len);
ffd6ed
+    t = strdup (p);
ffd6ed
     guestfs_int_free_string_list (config->disks);
ffd6ed
     config->disks = guestfs_int_split_string (',', t);
ffd6ed
   }
ffd6ed
 
ffd6ed
-  r = strstr (cmdline, "p2v.removable=");
ffd6ed
-  if (r) {
ffd6ed
+  p = get_cmdline_key (cmdline, "p2v.removable");
ffd6ed
+  if (p) {
ffd6ed
     CLEANUP_FREE char *t;
ffd6ed
 
ffd6ed
-    r += 5+9;
ffd6ed
-    len = strcspn (r, " ");
ffd6ed
-    t = strndup (r, len);
ffd6ed
+    t = strdup (p);
ffd6ed
     guestfs_int_free_string_list (config->removable);
ffd6ed
     config->removable = guestfs_int_split_string (',', t);
ffd6ed
   }
ffd6ed
 
ffd6ed
-  r = strstr (cmdline, "p2v.interfaces=");
ffd6ed
-  if (r) {
ffd6ed
+  p = get_cmdline_key (cmdline, "p2v.interfaces");
ffd6ed
+  if (p) {
ffd6ed
     CLEANUP_FREE char *t;
ffd6ed
 
ffd6ed
-    r += 5+10;
ffd6ed
-    len = strcspn (r, " ");
ffd6ed
-    t = strndup (r, len);
ffd6ed
+    t = strdup (p);
ffd6ed
     guestfs_int_free_string_list (config->interfaces);
ffd6ed
     config->interfaces = guestfs_int_split_string (',', t);
ffd6ed
   }
ffd6ed
 
ffd6ed
-  r = strstr (cmdline, "p2v.network=");
ffd6ed
-  if (r) {
ffd6ed
+  p = get_cmdline_key (cmdline, "p2v.network");
ffd6ed
+  if (p) {
ffd6ed
     CLEANUP_FREE char *t;
ffd6ed
 
ffd6ed
-    r += 5+7;
ffd6ed
-    len = strcspn (r, " ");
ffd6ed
-    t = strndup (r, len);
ffd6ed
+    t = strdup (p);
ffd6ed
     guestfs_int_free_string_list (config->network_map);
ffd6ed
     config->network_map = guestfs_int_split_string (',', t);
ffd6ed
   }
ffd6ed
 
ffd6ed
-  r = strstr (cmdline, "p2v.o=");
ffd6ed
-  if (r) {
ffd6ed
-    r += 5+1;
ffd6ed
-    len = strcspn (r, " ");
ffd6ed
+  p = get_cmdline_key (cmdline, "p2v.o");
ffd6ed
+  if (p) {
ffd6ed
     free (config->output);
ffd6ed
-    config->output = strndup (r, len);
ffd6ed
+    config->output = strdup (p);
ffd6ed
   }
ffd6ed
 
ffd6ed
-  r = strstr (cmdline, "p2v.oa=sparse");
ffd6ed
-  if (r)
ffd6ed
-    config->output_allocation = OUTPUT_ALLOCATION_SPARSE;
ffd6ed
-
ffd6ed
-  r = strstr (cmdline, "p2v.oa=preallocated");
ffd6ed
-  if (r)
ffd6ed
-    config->output_allocation = OUTPUT_ALLOCATION_PREALLOCATED;
ffd6ed
+  p = get_cmdline_key (cmdline, "p2v.oa");
ffd6ed
+  if (p) {
ffd6ed
+    if (STREQ (p, "sparse"))
ffd6ed
+      config->output_allocation = OUTPUT_ALLOCATION_SPARSE;
ffd6ed
+    else if (STREQ (p, "preallocated"))
ffd6ed
+      config->output_allocation = OUTPUT_ALLOCATION_PREALLOCATED;
ffd6ed
+    else
ffd6ed
+      fprintf (stderr, "%s: warning: don't know what p2v.oa=%s means\n",
ffd6ed
+               guestfs_int_program_name, p);
ffd6ed
+  }
ffd6ed
 
ffd6ed
-  r = strstr (cmdline, "p2v.oc=");
ffd6ed
-  if (r) {
ffd6ed
-    r += 5+2;
ffd6ed
-    len = strcspn (r, " ");
ffd6ed
+  p = get_cmdline_key (cmdline, "p2v.oc");
ffd6ed
+  if (p) {
ffd6ed
     free (config->output_connection);
ffd6ed
-    config->output_connection = strndup (r, len);
ffd6ed
+    config->output_connection = strdup (p);
ffd6ed
   }
ffd6ed
 
ffd6ed
-  r = strstr (cmdline, "p2v.of=");
ffd6ed
-  if (r) {
ffd6ed
-    r += 5+2;
ffd6ed
-    len = strcspn (r, " ");
ffd6ed
+  p = get_cmdline_key (cmdline, "p2v.of");
ffd6ed
+  if (p) {
ffd6ed
     free (config->output_format);
ffd6ed
-    config->output_format = strndup (r, len);
ffd6ed
+    config->output_format = strdup (p);
ffd6ed
   }
ffd6ed
 
ffd6ed
-  r = strstr (cmdline, "p2v.os=");
ffd6ed
-  if (r) {
ffd6ed
-    r += 5+2;
ffd6ed
-    len = strcspn (r, " ");
ffd6ed
+  p = get_cmdline_key (cmdline, "p2v.os");
ffd6ed
+  if (p) {
ffd6ed
     free (config->output_storage);
ffd6ed
-    config->output_storage = strndup (r, len);
ffd6ed
+    config->output_storage = strdup (p);
ffd6ed
   }
ffd6ed
 
ffd6ed
   /* Perform the conversion in text mode. */
ffd6ed
diff --git a/p2v/main.c b/p2v/main.c
ffd6ed
index 2dba1b8..4e67992 100644
ffd6ed
--- a/p2v/main.c
ffd6ed
+++ b/p2v/main.c
ffd6ed
@@ -44,7 +44,6 @@ char **all_interfaces;
ffd6ed
 static void set_config_defaults (struct config *config);
ffd6ed
 static void find_all_disks (void);
ffd6ed
 static void find_all_interfaces (void);
ffd6ed
-static char *read_cmdline (void);
ffd6ed
 static int cpuinfo_flags (void);
ffd6ed
 
ffd6ed
 enum { HELP_OPTION = CHAR_MAX + 1 };
ffd6ed
@@ -99,7 +98,8 @@ main (int argc, char *argv[])
ffd6ed
   gboolean gui_possible;
ffd6ed
   int c;
ffd6ed
   int option_index;
ffd6ed
-  char *cmdline = NULL;
ffd6ed
+  char **cmdline = NULL;
ffd6ed
+  int cmdline_source = 0;
ffd6ed
   struct config *config = new_config ();
ffd6ed
 
ffd6ed
   setlocale (LC_ALL, "");
ffd6ed
@@ -120,7 +120,8 @@ main (int argc, char *argv[])
ffd6ed
         display_long_options (long_options);
ffd6ed
       }
ffd6ed
       else if (STREQ (long_options[option_index].name, "cmdline")) {
ffd6ed
-        cmdline = strdup (optarg);
ffd6ed
+        cmdline = parse_cmdline_string (optarg);
ffd6ed
+        cmdline_source = CMDLINE_SOURCE_COMMAND_LINE;
ffd6ed
       }
ffd6ed
       else {
ffd6ed
         fprintf (stderr, _("%s: unknown long option: %s (%d)\n"),
ffd6ed
@@ -158,16 +159,18 @@ main (int argc, char *argv[])
ffd6ed
    * If /proc/cmdline contains p2v.debug then we enable verbose mode
ffd6ed
    * even for interactive configuration.
ffd6ed
    */
ffd6ed
-  if (cmdline == NULL)
ffd6ed
-    cmdline = read_cmdline ();
ffd6ed
-  if (cmdline == NULL)
ffd6ed
-    goto gui;
ffd6ed
+  if (cmdline == NULL) {
ffd6ed
+    cmdline = parse_proc_cmdline ();
ffd6ed
+    if (cmdline == NULL)
ffd6ed
+      goto gui;
ffd6ed
+    cmdline_source = CMDLINE_SOURCE_PROC_CMDLINE;
ffd6ed
+  }
ffd6ed
 
ffd6ed
-  if (strstr (cmdline, "p2v.debug"))
ffd6ed
+  if (get_cmdline_key (cmdline, "p2v.debug") != NULL)
ffd6ed
     config->verbose = 1;
ffd6ed
 
ffd6ed
-  if (strstr (cmdline, "p2v.server="))
ffd6ed
-    kernel_configuration (config, cmdline);
ffd6ed
+  if (get_cmdline_key (cmdline, "p2v.server") != NULL)
ffd6ed
+    kernel_configuration (config, cmdline, cmdline_source);
ffd6ed
   else {
ffd6ed
   gui:
ffd6ed
     if (!gui_possible)
ffd6ed
@@ -176,7 +179,7 @@ main (int argc, char *argv[])
ffd6ed
     gui_application (config);
ffd6ed
   }
ffd6ed
 
ffd6ed
-  free (cmdline);
ffd6ed
+  guestfs_int_free_string_list (cmdline);
ffd6ed
 
ffd6ed
   exit (EXIT_SUCCESS);
ffd6ed
 }
ffd6ed
@@ -498,36 +501,6 @@ find_all_interfaces (void)
ffd6ed
     qsort (all_interfaces, nr_interfaces, sizeof (char *), compare);
ffd6ed
 }
ffd6ed
 
ffd6ed
-/* Read /proc/cmdline. */
ffd6ed
-static char *
ffd6ed
-read_cmdline (void)
ffd6ed
-{
ffd6ed
-  CLEANUP_FCLOSE FILE *fp = NULL;
ffd6ed
-  char *ret = NULL;
ffd6ed
-  size_t len;
ffd6ed
-
ffd6ed
-  fp = fopen ("/proc/cmdline", "re");
ffd6ed
-  if (fp == NULL) {
ffd6ed
-    perror ("/proc/cmdline");
ffd6ed
-    return NULL;
ffd6ed
-  }
ffd6ed
-
ffd6ed
-  if (getline (&ret, &len, fp) == -1) {
ffd6ed
-    perror ("getline");
ffd6ed
-    return NULL;
ffd6ed
-  }
ffd6ed
-
ffd6ed
-  /* 'len' is not the length of the string, but the length of the
ffd6ed
-   * buffer.  We need to chomp the string.
ffd6ed
-   */
ffd6ed
-  len = strlen (ret);
ffd6ed
-
ffd6ed
-  if (len >= 1 && ret[len-1] == '\n')
ffd6ed
-    ret[len-1] = '\0';
ffd6ed
-
ffd6ed
-  return ret;
ffd6ed
-}
ffd6ed
-
ffd6ed
 /* Read the list of flags from /proc/cpuinfo. */
ffd6ed
 static int
ffd6ed
 cpuinfo_flags (void)
ffd6ed
diff --git a/p2v/p2v.h b/p2v/p2v.h
ffd6ed
index c5427a7..41d305d 100644
ffd6ed
--- a/p2v/p2v.h
ffd6ed
+++ b/p2v/p2v.h
ffd6ed
@@ -85,8 +85,16 @@ extern struct config *new_config (void);
ffd6ed
 extern struct config *copy_config (struct config *);
ffd6ed
 extern void free_config (struct config *);
ffd6ed
 
ffd6ed
+/* kernel-cmdline.c */
ffd6ed
+extern char **parse_cmdline_string (const char *cmdline);
ffd6ed
+extern char **parse_proc_cmdline (void);
ffd6ed
+extern const char *get_cmdline_key (char **cmdline, const char *key);
ffd6ed
+
ffd6ed
+#define CMDLINE_SOURCE_COMMAND_LINE 1 /* --cmdline */
ffd6ed
+#define CMDLINE_SOURCE_PROC_CMDLINE 2 /* /proc/cmdline */
ffd6ed
+
ffd6ed
 /* kernel.c */
ffd6ed
-extern void kernel_configuration (struct config *, const char *cmdline);
ffd6ed
+extern void kernel_configuration (struct config *, char **cmdline, int cmdline_source);
ffd6ed
 
ffd6ed
 /* gui.c */
ffd6ed
 extern void gui_application (struct config *);
ffd6ed
diff --git a/po/POTFILES b/po/POTFILES
ffd6ed
index 320710f..7c99fd0 100644
ffd6ed
--- a/po/POTFILES
ffd6ed
+++ b/po/POTFILES
ffd6ed
@@ -258,6 +258,7 @@ p2v/config.c
ffd6ed
 p2v/conversion.c
ffd6ed
 p2v/copying.c
ffd6ed
 p2v/gui.c
ffd6ed
+p2v/kernel-cmdline.c
ffd6ed
 p2v/kernel.c
ffd6ed
 p2v/main.c
ffd6ed
 p2v/miniexpect.c
ffd6ed
-- 
ffd6ed
1.8.3.1
ffd6ed