[ostree] deploy: Rework kernel arguments, add --karg-append to "admin deploy"



commit b2d0ba7ac1e742586eeb3018d88e01dc436d5b4d
Author: Colin Walters <walters verbum org>
Date:   Thu Jan 16 13:04:00 2014 -0500

    deploy: Rework kernel arguments, add --karg-append to "admin deploy"
    
    The "ordered hash" code was really just for kernel arguments.  And it
    turns out it needs to be a multihash (for e.g. multiple console=
    arguments).
    
    So turn the OstreeOrderedHash into OstreeKernelArgs, and move the bits
    to split key=value and such into there.
    
    Now we're not making this public API yet - the public OstreeSysroot
    just takes char **kargs.  To facilitate code reuse between ostree/ and
    libostree/, make it a noinst libtool library.  It'll be duplicated in
    the binary and library, but that's OK for now.  We can investigate
    making OstreeKernelArgs public later.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=721136

 Makefile-libostree.am                  |   13 ++-
 Makefile-ostree.am                     |    2 +-
 src/libostree/ostree-kernel-args.c     |  263 ++++++++++++++++++++++++++++++++
 src/libostree/ostree-kernel-args.h     |   54 +++++++
 src/libostree/ostree-ordered-hash.c    |   83 ----------
 src/libostree/ostree-ordered-hash.h    |   44 ------
 src/libostree/ostree-sysroot-deploy.c  |   67 ++++-----
 src/libostree/ostree-sysroot-private.h |    8 +-
 src/libostree/ostree-sysroot.c         |   96 +-----------
 src/libostree/ostree-sysroot.h         |   18 +-
 src/ostree/ot-admin-builtin-deploy.c   |   61 +++++---
 src/ostree/ot-admin-builtin-upgrade.c  |   12 +-
 tests/test-admin-deploy-karg.sh        |   10 ++
 13 files changed, 425 insertions(+), 306 deletions(-)
---
diff --git a/Makefile-libostree.am b/Makefile-libostree.am
index b2b90bb..25ee18b 100644
--- a/Makefile-libostree.am
+++ b/Makefile-libostree.am
@@ -19,6 +19,15 @@
 
 include Makefile-libostree-defines.am
 
+noinst_LTLIBRARIES += libostree-kernel-args.la
+
+libostree_kernel_args_la_SOURCES = \
+       src/libostree/ostree-kernel-args.h \
+       src/libostree/ostree-kernel-args.c \
+       $(NULL)
+libostree_kernel_args_la_CFLAGS = $(OT_INTERNAL_GIO_UNIX_CFLAGS)
+libostree_kernel_args_la_LIBADD = $(OT_INTERNAL_GIO_UNIX_LIBS)
+
 lib_LTLIBRARIES += libostree-1.la
 
 libostreeincludedir = $(includedir)/ostree-1
@@ -59,8 +68,6 @@ libostree_1_la_SOURCES = \
        src/libostree/ostree-bootloader-syslinux.c \
        src/libostree/ostree-bootloader-uboot.h \
        src/libostree/ostree-bootloader-uboot.c \
-       src/libostree/ostree-ordered-hash.h \
-       src/libostree/ostree-ordered-hash.c \
        src/libostree/ostree-gpg-verifier.c \
        src/libostree/ostree-gpg-verifier.h \
        $(NULL)
@@ -72,7 +79,7 @@ endif
 
 libostree_1_la_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/src/libgsystem -I$(srcdir)/src/libotutil 
-I$(srcdir)/src/libostree -DLOCALEDIR=\"$(datadir)/locale\" $(OT_INTERNAL_GIO_UNIX_CFLAGS)
 libostree_1_la_LDFLAGS = -version-number 1:0:0 -Bsymbolic-functions -export-symbols-regex '^ostree_'
-libostree_1_la_LIBADD = libotutil.la $(OT_INTERNAL_GIO_UNIX_LIBS)
+libostree_1_la_LIBADD = libotutil.la libostree-kernel-args.la $(OT_INTERNAL_GIO_UNIX_LIBS)
 
 if USE_LIBARCHIVE
 libostree_1_la_CFLAGS += $(OT_DEP_LIBARCHIVE_CFLAGS)
diff --git a/Makefile-ostree.am b/Makefile-ostree.am
index a74603b..bb1ea50 100644
--- a/Makefile-ostree.am
+++ b/Makefile-ostree.am
@@ -65,7 +65,7 @@ ostree_SOURCES += \
        $(NULL)
 
 ostree_bin_shared_cflags = $(AM_CFLAGS) -I$(srcdir)/src/libgsystem -I$(srcdir)/src/libotutil 
-I$(srcdir)/src/libostree -I$(srcdir)/src/ostree  -DLOCALEDIR=\"$(datadir)/locale\"
-ostree_bin_shared_ldadd = libotutil.la libostree-1.la
+ostree_bin_shared_ldadd = libotutil.la libostree-kernel-args.la libostree-1.la
 
 ostree_CFLAGS = $(ostree_bin_shared_cflags) $(OT_INTERNAL_GIO_UNIX_CFLAGS)
 ostree_LDADD = $(ostree_bin_shared_ldadd) $(OT_INTERNAL_GIO_UNIX_LIBS)
diff --git a/src/libostree/ostree-kernel-args.c b/src/libostree/ostree-kernel-args.c
new file mode 100644
index 0000000..f31932e
--- /dev/null
+++ b/src/libostree/ostree-kernel-args.c
@@ -0,0 +1,263 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2013,2014 Colin Walters <walters verbum org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the licence or (at
+ * your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "ostree-kernel-args.h"
+
+#include <string.h>
+
+struct _OstreeKernelArgs {
+  GPtrArray  *order;
+  GHashTable *table;
+};
+
+static char *
+split_keyeq (char *arg)
+{
+  char *eq;
+      
+  eq = strchr (arg, '=');
+  if (eq)
+    {
+      /* Note key/val are in one malloc block,
+       * so we don't free val...
+       */
+      *eq = '\0';
+      return eq+1;
+    }
+  else
+    {
+      /* ...and this allows us to insert a constant
+       * string.
+       */
+      return "";
+    }
+}
+
+OstreeKernelArgs *
+_ostree_kernel_args_new (void)
+{
+  OstreeKernelArgs *ret;
+  ret = g_new0 (OstreeKernelArgs, 1);
+  ret->order = g_ptr_array_new_with_free_func (g_free);
+  ret->table = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                      NULL, (GDestroyNotify)g_ptr_array_unref);
+  return ret;
+}
+
+void
+_ostree_kernel_args_free (OstreeKernelArgs *kargs)
+{
+  if (!kargs)
+    return;
+  g_ptr_array_unref (kargs->order);
+  g_hash_table_unref (kargs->table);
+  g_free (kargs);
+}
+
+void
+_ostree_kernel_args_cleanup (void *loc)
+{
+  _ostree_kernel_args_free (*((OstreeKernelArgs**)loc));
+}
+
+void
+_ostree_kernel_args_replace_take (OstreeKernelArgs   *kargs,
+                                  char               *arg)
+{
+  gboolean existed;
+  GPtrArray *values = g_ptr_array_new_with_free_func (g_free);
+  const char *value = split_keyeq (arg);
+
+  existed = g_hash_table_remove (kargs->table, arg);
+  if (!existed)
+    g_ptr_array_add (kargs->order, arg);
+  g_ptr_array_add (values, g_strdup (value));
+  g_hash_table_replace (kargs->table, arg, values);
+}
+
+void
+_ostree_kernel_args_replace (OstreeKernelArgs  *kargs,
+                             const char        *arg)
+{
+  _ostree_kernel_args_replace_take (kargs, g_strdup (arg));
+}
+
+void
+_ostree_kernel_args_append (OstreeKernelArgs  *kargs,
+                            const char        *arg)
+{
+  gboolean existed = TRUE;
+  GPtrArray *values;
+  char *duped = g_strdup (arg);
+  const char *val = split_keyeq (duped);
+
+  values = g_hash_table_lookup (kargs->table, duped);
+  if (!values)
+    {
+      values = g_ptr_array_new_with_free_func (g_free);
+      existed = FALSE;
+    }
+
+  g_ptr_array_add (values, g_strdup (val));
+
+  if (!existed)
+    {
+      g_hash_table_replace (kargs->table, duped, values);
+      g_ptr_array_add (kargs->order, duped);
+    }
+  else
+    {
+      g_free (duped);
+    }
+}
+
+void
+_ostree_kernel_args_replace_argv (OstreeKernelArgs  *kargs,
+                                  char             **argv)
+{
+  char **strviter;
+
+  for (strviter = argv; strviter && *strviter; strviter++)
+    {
+      const char *arg = *strviter;
+      _ostree_kernel_args_replace (kargs, arg);
+    }
+}
+
+void
+_ostree_kernel_args_append_argv (OstreeKernelArgs  *kargs,
+                                 char            **argv)
+{
+  char **strviter;
+
+  for (strviter = argv; strviter && *strviter; strviter++)
+    {
+      const char *arg = *strviter;
+      _ostree_kernel_args_append (kargs, arg);
+    }
+}
+
+void
+_ostree_kernel_args_parse_append (OstreeKernelArgs *kargs,
+                                  const char       *options)
+{
+  char **args = NULL;
+  char **iter;
+
+  if (!options)
+    return;
+  
+  args = g_strsplit (options, " ", -1);
+  for (iter = args; *iter; iter++)
+    {
+      char *arg = *iter;
+      _ostree_kernel_args_append (kargs, arg);
+    }
+  g_strfreev (args);
+}
+
+OstreeKernelArgs *
+_ostree_kernel_args_from_string (const char *options)
+{
+  OstreeKernelArgs *ret;
+
+  ret = _ostree_kernel_args_new ();
+  _ostree_kernel_args_parse_append (ret, options);
+
+  return ret;
+}
+
+char **
+_ostree_kernel_args_to_strv (OstreeKernelArgs *kargs)
+{
+  GPtrArray *strv = g_ptr_array_new ();
+  guint i;
+
+  for (i = 0; i < kargs->order->len; i++)
+    {
+      const char *key = kargs->order->pdata[i];
+      GPtrArray *values = g_hash_table_lookup (kargs->table, key);
+      guint j;
+
+      g_assert (values != NULL);
+
+      for (j = 0; j < values->len; j++)
+        {
+          const char *value = values->pdata[j];
+
+          g_ptr_array_add (strv, g_strconcat (key, "=", value, NULL));
+        }
+    }
+  g_ptr_array_add (strv, NULL);
+
+  return (char**)g_ptr_array_free (strv, FALSE);
+}
+
+char *
+_ostree_kernel_args_to_string (OstreeKernelArgs *kargs)
+{
+  GString *buf = g_string_new ("");
+  gboolean first = TRUE;
+  guint i;
+
+  for (i = 0; i < kargs->order->len; i++)
+    {
+      const char *key = kargs->order->pdata[i];
+      GPtrArray *values = g_hash_table_lookup (kargs->table, key);
+      guint j;
+
+      g_assert (values != NULL);
+
+      for (j = 0; j < values->len; j++)
+        {
+          const char *value = values->pdata[j];
+
+          if (first)
+            first = FALSE;
+          else
+            g_string_append_c (buf, ' ');
+
+          if (value && *value)
+            {
+              g_string_append (buf, key);
+              g_string_append_c (buf, '=');
+              g_string_append (buf, value);
+            }
+          else
+            g_string_append (buf, key);
+        }
+    }
+
+  return g_string_free (buf, FALSE);
+}
+
+const char *
+_ostree_kernel_args_get_last_value (OstreeKernelArgs *kargs, const char *key)
+{
+  GPtrArray *values = g_hash_table_lookup (kargs->table, key);
+
+  if (!values)
+    return NULL;
+
+  g_assert (values->len > 0);
+  return (char*)values->pdata[values->len-1];
+}
diff --git a/src/libostree/ostree-kernel-args.h b/src/libostree/ostree-kernel-args.h
new file mode 100644
index 0000000..89d4fc9
--- /dev/null
+++ b/src/libostree/ostree-kernel-args.h
@@ -0,0 +1,54 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2013,2014 Colin Walters <walters verbum org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the licence or (at
+ * your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#pragma once
+
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+typedef struct _OstreeKernelArgs OstreeKernelArgs;
+
+OstreeKernelArgs *_ostree_kernel_args_new (void);
+void _ostree_kernel_args_free (OstreeKernelArgs *kargs);
+void _ostree_kernel_args_cleanup (void *loc);
+void _ostree_kernel_args_replace_take (OstreeKernelArgs  *kargs,
+                                       char              *key);
+void _ostree_kernel_args_replace (OstreeKernelArgs  *kargs,
+                                  const char        *key);
+void _ostree_kernel_args_replace_argv (OstreeKernelArgs  *kargs,
+                                       char             **argv);
+void _ostree_kernel_args_append (OstreeKernelArgs  *kargs,
+                                 const char     *key);
+void _ostree_kernel_args_append_argv (OstreeKernelArgs  *kargs,
+                                      char **argv);
+
+void _ostree_kernel_args_parse_append (OstreeKernelArgs *kargs,
+                                       const char *options);
+
+const char *_ostree_kernel_args_get_last_value (OstreeKernelArgs *kargs, const char *key);
+
+OstreeKernelArgs * _ostree_kernel_args_from_string (const char *options);
+
+char ** _ostree_kernel_args_to_strv (OstreeKernelArgs *kargs);
+char * _ostree_kernel_args_to_string (OstreeKernelArgs *kargs);
+
+G_END_DECLS
+
diff --git a/src/libostree/ostree-sysroot-deploy.c b/src/libostree/ostree-sysroot-deploy.c
index 749a375..4a21740 100644
--- a/src/libostree/ostree-sysroot-deploy.c
+++ b/src/libostree/ostree-sysroot-deploy.c
@@ -601,7 +601,7 @@ install_deployment_kernel (OstreeSysroot   *sysroot,
   gs_free char *version_key = NULL;
   gs_free char *ostree_kernel_arg = NULL;
   gs_free char *options_key = NULL;
-  __attribute__((cleanup(_ostree_ordered_hash_cleanup))) OstreeOrderedHash *ohash = NULL;
+  __attribute__((cleanup(_ostree_kernel_args_cleanup))) OstreeKernelArgs *kargs = NULL;
   const char *val;
   OstreeBootconfigParser *bootconfig;
   gsize len;
@@ -693,12 +693,14 @@ install_deployment_kernel (OstreeSysroot   *sysroot,
     }
 
   val = ostree_bootconfig_parser_get (bootconfig, "options");
-  ostree_kernel_arg = g_strdup_printf ("/ostree/boot.%d/%s/%s/%d",
+
+  ostree_kernel_arg = g_strdup_printf ("ostree=/ostree/boot.%d/%s/%s/%d",
                                        new_bootversion, osname, bootcsum,
                                        ostree_deployment_get_bootserial (deployment));
-  ohash = _ostree_sysroot_parse_kernel_args (val);
-  _ostree_ordered_hash_replace_key (ohash, "ostree", ostree_kernel_arg);
-  options_key = _ostree_sysroot_kernel_arg_string_serialize (ohash);
+  kargs = _ostree_kernel_args_from_string (val);
+  _ostree_kernel_args_replace_take (kargs, ostree_kernel_arg);
+  ostree_kernel_arg = NULL;
+  options_key = _ostree_kernel_args_to_string (kargs);
   ostree_bootconfig_parser_set (bootconfig, "options", options_key);
   
   if (!ostree_bootconfig_parser_write (ostree_deployment_get_bootconfig (deployment), bootconfpath,
@@ -773,14 +775,14 @@ bootconfig_counts_for_deployment_list (GPtrArray   *deployments)
       const char *boot_options = ostree_bootconfig_parser_get (bootconfig, "options");
       GChecksum *bootconfig_checksum = g_checksum_new (G_CHECKSUM_SHA256);
       const char *bootconfig_checksum_str;
-      __attribute__((cleanup(_ostree_ordered_hash_cleanup))) OstreeOrderedHash *ohash = NULL;
+      __attribute__((cleanup(_ostree_kernel_args_cleanup))) OstreeKernelArgs *kargs = NULL;
       gs_free char *boot_options_without_ostree = NULL;
       guint count;
       
       /* We checksum the kernel arguments *except* ostree= */
-      ohash = _ostree_sysroot_parse_kernel_args (boot_options);
-      _ostree_ordered_hash_replace_key (ohash, "ostree", "");
-      boot_options_without_ostree = _ostree_sysroot_kernel_arg_string_serialize (ohash);
+      kargs = _ostree_kernel_args_from_string (boot_options);
+      _ostree_kernel_args_replace (kargs, "ostree");
+      boot_options_without_ostree = _ostree_kernel_args_to_string (kargs);
 
       g_checksum_update (bootconfig_checksum, (guint8*)bootcsum, strlen (bootcsum));
       g_checksum_update (bootconfig_checksum, (guint8*)boot_options_without_ostree,
@@ -1049,13 +1051,13 @@ allocate_deployserial (OstreeSysroot           *self,
 }
                             
 /**
- * ostree_sysroot_deploy_one_tree:
+ * ostree_sysroot_deploy_tree:
  * @self: Sysroot
  * @osname: (allow-none): osname to use for merge deployment
  * @revision: Checksum to add
  * @origin: (allow-none): Origin to use for upgrades
- * @add_kernel_argv: (allow-none): Append these arguments to kernel configuration
  * @provided_merge_deployment: (allow-none): Use this deployment for merge path
+ * @override_kernel_argv: (allow-none) (array zero-terminated=1) (element-type utf8): Use these as kernel 
arguments; if %NULL, inherit options from provided_merge_deployment
  * @out_new_deployment: (out): The new deployment path
  * @cancellable: Cancellable
  * @error: Error
@@ -1064,15 +1066,15 @@ allocate_deployserial (OstreeSysroot           *self,
  * way merge with @provided_merge_deployment for configuration.
  */
 gboolean
-ostree_sysroot_deploy_one_tree (OstreeSysroot     *self,
-                                const char        *osname,
-                                const char        *revision,
-                                GKeyFile          *origin,
-                                char             **add_kernel_argv,
-                                OstreeDeployment  *provided_merge_deployment,
-                                OstreeDeployment **out_new_deployment,
-                                GCancellable      *cancellable,
-                                GError           **error)
+ostree_sysroot_deploy_tree (OstreeSysroot     *self,
+                            const char        *osname,
+                            const char        *revision,
+                            GKeyFile          *origin,
+                            OstreeDeployment  *provided_merge_deployment,
+                            char             **override_kernel_argv,
+                            OstreeDeployment **out_new_deployment,
+                            GCancellable      *cancellable,
+                            GError           **error)
 {
   gboolean ret = FALSE;
   gint new_deployserial;
@@ -1160,30 +1162,17 @@ ostree_sysroot_deploy_one_tree (OstreeSysroot     *self,
       goto out;
     }
 
-  /* We have inherited kernel arguments from the previous deployment;
-   * now, override/extend that with arguments provided by the command
-   * line.
-   * 
-   * After this, install_deployment_kernel() will set the other boot
+  /* After this, install_deployment_kernel() will set the other boot
    * options and write it out to disk.
    */
-  if (add_kernel_argv)
+  if (override_kernel_argv)
     {
-      char **strviter;
-      __attribute__((cleanup(_ostree_ordered_hash_cleanup))) OstreeOrderedHash *ohash = NULL;
+      __attribute__((cleanup(_ostree_kernel_args_cleanup))) OstreeKernelArgs *kargs = NULL;
       gs_free char *new_options = NULL;
 
-      ohash = _ostree_sysroot_parse_kernel_args (ostree_bootconfig_parser_get (bootconfig, "options"));
-
-      for (strviter = add_kernel_argv; *strviter; strviter++)
-        {
-          char *karg = g_strdup (*strviter);
-          const char *val = _ostree_sysroot_split_keyeq (karg);
-        
-          _ostree_ordered_hash_replace_key_take (ohash, karg, val);
-        }
-
-      new_options = _ostree_sysroot_kernel_arg_string_serialize (ohash);
+      kargs = _ostree_kernel_args_new ();
+      _ostree_kernel_args_append_argv (kargs, override_kernel_argv);
+      new_options = _ostree_kernel_args_to_string (kargs);
       ostree_bootconfig_parser_set (bootconfig, "options", new_options);
     }
 
diff --git a/src/libostree/ostree-sysroot-private.h b/src/libostree/ostree-sysroot-private.h
index ce79fb8..0857e4c 100644
--- a/src/libostree/ostree-sysroot-private.h
+++ b/src/libostree/ostree-sysroot-private.h
@@ -21,7 +21,7 @@
 #pragma once
 
 #include "ostree.h"
-#include "ostree-ordered-hash.h"
+#include "ostree-kernel-args.h"
 #include "ostree-bootloader.h"
 
 G_BEGIN_DECLS
@@ -75,12 +75,6 @@ _ostree_sysroot_get_devino (GFile         *path,
 
 char *_ostree_sysroot_join_lines (GPtrArray  *lines);
 
-char *_ostree_sysroot_split_keyeq (char *str);
-
-OstreeOrderedHash *_ostree_sysroot_parse_kernel_args (const char *options);
-
-char * _ostree_sysroot_kernel_arg_string_serialize (OstreeOrderedHash *ohash);
-
 OstreeBootloader *_ostree_sysroot_query_bootloader (OstreeSysroot         *sysroot);
 
 G_END_DECLS
diff --git a/src/libostree/ostree-sysroot.c b/src/libostree/ostree-sysroot.c
index f61324a..56811b8 100644
--- a/src/libostree/ostree-sysroot.c
+++ b/src/libostree/ostree-sysroot.c
@@ -884,9 +884,9 @@ _ostree_sysroot_join_lines (GPtrArray  *lines)
 }
 
 static gboolean
-parse_kernel_commandline (OstreeOrderedHash  **out_args,
-                          GCancellable    *cancellable,
-                          GError         **error)
+parse_kernel_commandline (OstreeKernelArgs  **out_args,
+                          GCancellable       *cancellable,
+                          GError            **error)
 {
   gboolean ret = FALSE;
   gs_unref_object GFile *proc_cmdline = g_file_new_for_path ("/proc/cmdline");
@@ -897,8 +897,10 @@ parse_kernel_commandline (OstreeOrderedHash  **out_args,
                              error))
     goto out;
 
+  g_strchomp (contents);
+
   ret = TRUE;
-  *out_args = _ostree_sysroot_parse_kernel_args (contents);;
+  *out_args = _ostree_kernel_args_from_string (contents);
  out:
   return ret;
 }
@@ -919,7 +921,7 @@ find_booted_deployment (OstreeSysroot       *self,
       gs_unref_object OstreeSysroot *active_deployment_root = ostree_sysroot_new_default ();
       guint i;
       const char *bootlink_arg;
-      __attribute__((cleanup(_ostree_ordered_hash_cleanup))) OstreeOrderedHash *kernel_args = NULL;
+      __attribute__((cleanup(_ostree_kernel_args_cleanup))) OstreeKernelArgs *kernel_args = NULL;
       guint32 root_device;
       guint64 root_inode;
       
@@ -930,7 +932,7 @@ find_booted_deployment (OstreeSysroot       *self,
       if (!parse_kernel_commandline (&kernel_args, cancellable, error))
         goto out;
       
-      bootlink_arg = g_hash_table_lookup (kernel_args->table, "ostree");
+      bootlink_arg = _ostree_kernel_args_get_last_value (kernel_args, "ostree");
       if (bootlink_arg)
         {
           for (i = 0; i < deployments->len; i++)
@@ -969,88 +971,6 @@ find_booted_deployment (OstreeSysroot       *self,
   return ret;
 }
 
-OstreeOrderedHash *
-_ostree_sysroot_parse_kernel_args (const char *options)
-{
-  OstreeOrderedHash *ret;
-  char **args;
-  char **iter;
-
-  ret = _ostree_ordered_hash_new ();
-
-  if (!options)
-    return ret;
-  
-  args = g_strsplit (options, " ", -1);
-  for (iter = args; *iter; iter++)
-    {
-      char *arg = *iter;
-      char *val;
-      
-      val = _ostree_sysroot_split_keyeq (arg);
-
-      g_ptr_array_add (ret->order, arg);
-      g_hash_table_insert (ret->table, arg, val);
-    }
-
-  return ret;
-}
-
-/*
- * Modify @arg which should be of the form key=value to make @arg just
- * contain key.  Return a pointer to the start of value.
- */
-char *
-_ostree_sysroot_split_keyeq (char *arg)
-{
-  char *eq;
-      
-  eq = strchr (arg, '=');
-  if (eq)
-    {
-      /* Note key/val are in one malloc block,
-       * so we don't free val...
-       */
-      *eq = '\0';
-      return eq+1;
-    }
-  else
-    {
-      /* ...and this allows us to insert a constant
-       * string.
-       */
-      return "";
-    }
-}
-
-char *
-_ostree_sysroot_kernel_arg_string_serialize (OstreeOrderedHash *ohash)
-{
-  guint i;
-  GString *buf = g_string_new ("");
-  gboolean first = TRUE;
-
-  for (i = 0; i < ohash->order->len; i++)
-    {
-      const char *key = ohash->order->pdata[i];
-      const char *val = g_hash_table_lookup (ohash->table, key);
-
-      g_assert (val != NULL);
-
-      if (first)
-        first = FALSE;
-      else
-        g_string_append_c (buf, ' ');
-
-      if (*val)
-        g_string_append_printf (buf, "%s=%s", key, val);
-      else
-        g_string_append (buf, key);
-    }
-
-  return g_string_free (buf, FALSE);
-}
-
 /**
  * ostree_sysroot_get_merge_deployment:
  * @self: Sysroot
diff --git a/src/libostree/ostree-sysroot.h b/src/libostree/ostree-sysroot.h
index 5bed119..fbf3dff 100644
--- a/src/libostree/ostree-sysroot.h
+++ b/src/libostree/ostree-sysroot.h
@@ -71,15 +71,15 @@ gboolean ostree_sysroot_write_deployments (OstreeSysroot     *self,
                                            GCancellable      *cancellable,
                                            GError           **error);
 
-gboolean ostree_sysroot_deploy_one_tree (OstreeSysroot     *self,
-                                         const char        *osname,
-                                         const char        *revision,
-                                         GKeyFile          *origin,
-                                         char             **add_kernel_argv,
-                                         OstreeDeployment  *provided_merge_deployment,
-                                         OstreeDeployment **out_new_deployment,
-                                         GCancellable      *cancellable,
-                                         GError           **error);
+gboolean ostree_sysroot_deploy_tree (OstreeSysroot     *self,
+                                     const char        *osname,
+                                     const char        *revision,
+                                     GKeyFile          *origin,
+                                     OstreeDeployment  *provided_merge_deployment,
+                                     char             **override_kernel_argv,
+                                     OstreeDeployment **out_new_deployment,
+                                     GCancellable      *cancellable,
+                                     GError           **error);
 
 OstreeDeployment *ostree_sysroot_get_merge_deployment (OstreeSysroot     *self,
                                                        const char        *osname);
diff --git a/src/ostree/ot-admin-builtin-deploy.c b/src/ostree/ot-admin-builtin-deploy.c
index 9d47924..6bcde91 100644
--- a/src/ostree/ot-admin-builtin-deploy.c
+++ b/src/ostree/ot-admin-builtin-deploy.c
@@ -27,11 +27,14 @@
 #include "ostree.h"
 #include "otutil.h"
 
+#include "../libostree/ostree-kernel-args.h"
+
 #include <glib/gi18n.h>
 
 static gboolean opt_no_bootloader;
 static gboolean opt_retain;
 static char **opt_kernel_argv;
+static char **opt_kernel_argv_append;
 static gboolean opt_kernel_proc_cmdline;
 static char *opt_osname;
 static char *opt_origin_path;
@@ -42,7 +45,8 @@ static GOptionEntry options[] = {
   { "no-bootloader", 0, 0, G_OPTION_ARG_NONE, &opt_no_bootloader, "Don't update bootloader", NULL },
   { "retain", 0, 0, G_OPTION_ARG_NONE, &opt_retain, "Do not delete previous deployment", NULL },
   { "karg-proc-cmdline", 0, 0, G_OPTION_ARG_NONE, &opt_kernel_proc_cmdline, "Import current /proc/cmdline", 
NULL },
-  { "karg", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_kernel_argv, "Set kernel argument, like 
--karg=root=/dev/sda1", NULL },
+  { "karg", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_kernel_argv, "Set kernel argument, like root=/dev/sda1; 
this overrides any earlier argument with the same name", "KEY=VALUE" },
+  { "karg-append", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_kernel_argv_append, "Append kernel argument; useful 
with e.g. console= that can be used multiple times", "KEY=VALUE" },
   { NULL }
 };
 
@@ -58,7 +62,7 @@ ot_admin_builtin_deploy (int argc, char **argv, OstreeSysroot *sysroot, GCancell
   gs_unref_object OstreeDeployment *new_deployment = NULL;
   gs_unref_object OstreeDeployment *merge_deployment = NULL;
   gs_free char *revision = NULL;
-  gs_unref_ptrarray GPtrArray *kargs = NULL;
+  __attribute__((cleanup(_ostree_kernel_args_cleanup))) OstreeKernelArgs *kargs = NULL;
 
   context = g_option_context_new ("REFSPEC - Checkout revision REFSPEC as the new default deployment");
 
@@ -121,51 +125,56 @@ ot_admin_builtin_deploy (int argc, char **argv, OstreeSysroot *sysroot, GCancell
       goto out;
     }
 
-  kargs = g_ptr_array_new_with_free_func (g_free);
+  kargs = _ostree_kernel_args_new ();
 
+  /* If they want the current kernel's args, they very likely don't
+   * want the ones from the merge.
+   */
   if (opt_kernel_proc_cmdline)
     {
       gs_unref_object GFile *proc_cmdline_path = g_file_new_for_path ("/proc/cmdline");
       gs_free char *proc_cmdline = NULL;
       gsize proc_cmdline_len = 0;
       gs_strfreev char **proc_cmdline_args = NULL;
-      char **strviter;
 
       if (!g_file_load_contents (proc_cmdline_path, cancellable,
                                  &proc_cmdline, &proc_cmdline_len,
                                  NULL, error))
         goto out;
 
+      g_strchomp (proc_cmdline);
+
       proc_cmdline_args = g_strsplit (proc_cmdline, " ", -1);
-      for (strviter = proc_cmdline_args; strviter && *strviter; strviter++)
-        {
-          char *arg = *strviter;
-          g_strchomp (arg);
-          g_ptr_array_add (kargs, arg);
-          *strviter = NULL; /* transfer ownership */
-        }
+      _ostree_kernel_args_replace_argv (kargs, proc_cmdline_args);
+    }
+  else if (merge_deployment)
+    {
+      OstreeBootconfigParser *bootconfig = ostree_deployment_get_bootconfig (merge_deployment);
+      gs_strfreev char **previous_args = g_strsplit (ostree_bootconfig_parser_get (bootconfig, "options"), " 
", -1);
+
+      _ostree_kernel_args_replace_argv (kargs, previous_args);
     }
 
   if (opt_kernel_argv)
     {
-      char **strviter;
-      for (strviter = opt_kernel_argv; strviter && *strviter; strviter++)
-        {
-          const char *arg = *strviter;
-          char *val = g_strdup (arg);
-          g_strchomp (val);
-          g_ptr_array_add (kargs, val);
-        }
+      _ostree_kernel_args_replace_argv (kargs, opt_kernel_argv);
     }
 
-  g_ptr_array_add (kargs, NULL);
+  if (opt_kernel_argv_append)
+    {
+      _ostree_kernel_args_append_argv (kargs, opt_kernel_argv_append);
+    }
 
-  if (!ostree_sysroot_deploy_one_tree (sysroot,
-                                       opt_osname, revision, origin,
-                                       (char**)kargs->pdata, merge_deployment,
-                                       &new_deployment,
-                                       cancellable, error))
-    goto out;
+  {
+    gs_strfreev char **kargs_strv = _ostree_kernel_args_to_strv (kargs);
+
+    if (!ostree_sysroot_deploy_tree (sysroot,
+                                     opt_osname, revision, origin,
+                                     merge_deployment, kargs_strv,
+                                     &new_deployment,
+                                     cancellable, error))
+      goto out;
+  }
 
   if (!ot_admin_complete_deploy_one (sysroot, opt_osname,
                                      new_deployment, merge_deployment, opt_retain,
diff --git a/src/ostree/ot-admin-builtin-upgrade.c b/src/ostree/ot-admin-builtin-upgrade.c
index 299c6a8..d222e9e 100644
--- a/src/ostree/ot-admin-builtin-upgrade.c
+++ b/src/ostree/ot-admin-builtin-upgrade.c
@@ -147,12 +147,12 @@ ot_admin_builtin_upgrade (int argc, char **argv, OstreeSysroot *sysroot, GCancel
           goto out;
         }
 
-      if (!ostree_sysroot_deploy_one_tree (sysroot,
-                                           opt_osname, new_revision, origin,
-                                           NULL,
-                                           merge_deployment,
-                                           &new_deployment,
-                                           cancellable, error))
+      if (!ostree_sysroot_deploy_tree (sysroot,
+                                       opt_osname, new_revision, origin,
+                                       merge_deployment,
+                                       NULL,
+                                       &new_deployment,
+                                       cancellable, error))
         goto out;
 
       if (!ot_admin_complete_deploy_one (sysroot, opt_osname,
diff --git a/tests/test-admin-deploy-karg.sh b/tests/test-admin-deploy-karg.sh
index 395e281..2a75081 100644
--- a/tests/test-admin-deploy-karg.sh
+++ b/tests/test-admin-deploy-karg.sh
@@ -52,3 +52,13 @@ ostree admin --sysroot=sysroot deploy --karg-proc-cmdline --os=testos testos:tes
 assert_file_has_content sysroot/boot/loader/entries/ostree-testos-0.conf 'options.*root=.'
 
 echo "ok deploy --karg-proc-cmdline"
+
+ostree admin --sysroot=sysroot status
+ostree admin --sysroot=sysroot undeploy 0
+
+ostree admin --sysroot=sysroot deploy  --os=testos --karg-append=APPENDARG=VALAPPEND 
--karg-append=APPENDARG=2NDAPPEND testos:testos/buildmaster/x86_64-runtime
+assert_file_has_content sysroot/boot/loader/entries/ostree-testos-0.conf 'options.*FOO=BAR'
+assert_file_has_content sysroot/boot/loader/entries/ostree-testos-0.conf 'options.*TESTARG=TESTVALUE'
+assert_file_has_content sysroot/boot/loader/entries/ostree-testos-0.conf 'options.*APPENDARG=VALAPPEND 
.*APPENDARG=2NDAPPEND'
+
+echo "ok deploy --karg-append"


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]