RFE: Add a hidden option to `ostree admin kargs edit-in-place` to
authorHuijing Hei <hhei@redhat.com>
Thu, 2 Jun 2022 07:30:20 +0000 (15:30 +0800)
committerHuijing Hei <hhei@redhat.com>
Thu, 23 Jun 2022 14:31:39 +0000 (22:31 +0800)
update all existing deployments in place

Example:
$ sudo ostree admin kargs edit-in-place --append-if-missing=rw
See https://github.com/ostreedev/ostree/issues/2617

This will not add duplicate key, if there is `TESTARG=VAL1` in the
kernel arguments, `--append-if-missing=TESTARG=VAL2` will be ignored.

13 files changed:
Makefile-libostree.am
Makefile-ostree.am
Makefile-tests.am
apidoc/ostree-sections.txt
src/libostree/libostree-devel.sym
src/libostree/ostree-kernel-args.c
src/libostree/ostree-kernel-args.h
src/ostree/ot-admin-builtin-kargs.c [new file with mode: 0644]
src/ostree/ot-admin-builtins.h
src/ostree/ot-admin-kargs-builtin-edit-in-place.c [new file with mode: 0644]
src/ostree/ot-admin-kargs-builtins.h [new file with mode: 0644]
src/ostree/ot-builtin-admin.c
tests/test-admin-kargs.sh [new file with mode: 0755]

index f93f712aa1c542f1abcc832af6b7be512dc5afbb..dd7ed8df7e66b9873bbcc48b487ae9291db85d2b 100644 (file)
@@ -174,6 +174,9 @@ symbol_files = $(top_srcdir)/src/libostree/libostree-released.sym
 #if BUILDOPT_IS_DEVEL_BUILD
 #symbol_files += $(top_srcdir)/src/libostree/libostree-devel.sym
 #endif
+if BUILDOPT_IS_DEVEL_BUILD
+symbol_files += $(top_srcdir)/src/libostree/libostree-devel.sym
+endif
 
 # http://blog.jgc.org/2007/06/escaping-comma-and-space-in-gnu-make.html
 wl_versionscript_arg = -Wl,--version-script=
index 0fe2c5f86c65c4516e808d9c6f19b8729c8a1cbc..fb377075ebc3b57af17af8fa2e6e3d12da2f537d 100644 (file)
@@ -73,6 +73,7 @@ ostree_SOURCES += \
        src/ostree/ot-admin-builtin-boot-complete.c \
        src/ostree/ot-admin-builtin-undeploy.c \
        src/ostree/ot-admin-builtin-instutil.c \
+       src/ostree/ot-admin-builtin-kargs.c \
        src/ostree/ot-admin-builtin-cleanup.c \
        src/ostree/ot-admin-builtin-os-init.c \
        src/ostree/ot-admin-builtin-set-origin.c \
@@ -88,6 +89,8 @@ ostree_SOURCES += \
        src/ostree/ot-admin-instutil-builtins.h \
        src/ostree/ot-admin-functions.h \
        src/ostree/ot-admin-functions.c \
+       src/ostree/ot-admin-kargs-builtins.h \
+       src/ostree/ot-admin-kargs-builtin-edit-in-place.c \
        $(NULL)
 
 # Remote subcommand
index 29de6c7aac3d8f5b76edfcd1f68c1bd94fe6bf44..c87893ee28bce444d268b009cc3e7584838a494f 100644 (file)
@@ -114,6 +114,7 @@ _installed_or_uninstalled_test_scripts = \
        tests/test-admin-pull-deploy-split.sh \
        tests/test-admin-locking.sh \
        tests/test-admin-deploy-clean.sh \
+       tests/test-admin-kargs.sh \
        tests/test-reset-nonlinear.sh \
        tests/test-oldstyle-partial.sh \
        tests/test-delta.sh \
index adf52557bbe2377ba2302021cde16b57e8d5d5b3..5af8e687739e00eaff8955f7916cf646bab2b1bf 100644 (file)
@@ -727,6 +727,7 @@ ostree_kernel_args_replace_argv
 ostree_kernel_args_append
 ostree_kernel_args_append_argv
 ostree_kernel_args_append_argv_filtered
+ostree_kernel_args_append_if_missing
 ostree_kernel_args_new_replace
 ostree_kernel_args_delete
 ostree_kernel_args_delete_key_entry
index eef5cba0b79ce805d9e9e4810ff7dc6f649c9ab9..54945ecaf684beb18a22bd42eb91bad2822b2b8f 100644 (file)
    - uncomment the include in Makefile-libostree.am
 */
 
+LIBOSTREE_2022.5 {
+global:
+  ostree_kernel_args_append_if_missing;
+} LIBOSTREE_2022.4;
 
 /* Stub section for the stable release *after* this development one; don't
  * edit this other than to update the year.  This is just a copy/paste
index 40f11e997756912a48e5c412c73dae260fe74a22..08dcf992f11eae991278009baf52f5c9d5ff3037 100644 (file)
@@ -804,3 +804,28 @@ ostree_kernel_args_get_last_value (OstreeKernelArgs *kargs, const char *key)
   const OstreeKernelArgsEntry *e = entries->pdata[entries->len-1];
   return _ostree_kernel_args_entry_get_value (e);
 }
+
+/**
+ * ostree_kernel_args_append_if_missing:
+ * @kargs: a OstreeKernelArgs instance
+ * @arg: key or key/value pair to be added
+ *
+ * Appends @arg which is in the form of key=value pair to the hash table kargs->table
+ * (appends to the value list if key is not in the hash table)
+ * and appends key to kargs->order if it is not in the hash table.
+ *
+ * Since: 2022.5
+ **/
+void
+ostree_kernel_args_append_if_missing (OstreeKernelArgs  *kargs,
+                                      const char *arg)
+{
+  g_autofree char *key = g_strdup (arg);
+  split_keyeq (key);
+  // Don't insert a duplicate key.
+  if (g_hash_table_contains (kargs->table, key))
+    return;
+  ostree_kernel_args_append (kargs, arg);
+}
index dde0312fc204a843b002dc574649354d18b6c9b3..2e1b249a957b34d8ff8b622598629d5369cb20f4 100644 (file)
@@ -130,4 +130,8 @@ char **ostree_kernel_args_to_strv (OstreeKernelArgs *kargs);
 _OSTREE_PUBLIC
 char *ostree_kernel_args_to_string (OstreeKernelArgs *kargs);
 
+_OSTREE_PUBLIC
+void ostree_kernel_args_append_if_missing (OstreeKernelArgs *kargs, 
+                                           const char *arg);
+
 G_END_DECLS
diff --git a/src/ostree/ot-admin-builtin-kargs.c b/src/ostree/ot-admin-builtin-kargs.c
new file mode 100644 (file)
index 0000000..4afef29
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2015 Colin Walters <walters@verbum.org>
+ * Copyright (C) 2022 Huijing Hei <hhei@redhat.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.0+
+ *
+ * This library 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 License, 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, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "ot-main.h"
+#include "ot-admin-builtins.h"
+#include "ot-admin-functions.h"
+#include "ot-admin-kargs-builtins.h"
+#include "otutil.h"
+
+#include <glib/gi18n.h>
+
+static OstreeCommand admin_kargs_subcommands[] = {
+  { "edit-in-place", OSTREE_BUILTIN_FLAG_NO_REPO | OSTREE_BUILTIN_FLAG_HIDDEN,
+    ot_admin_kargs_builtin_edit_in_place,
+    "Set new kernel command line arguments in place (applies to all deployments by default)"  },
+  { NULL, 0, NULL, NULL }
+};
+
+static GOptionContext *
+ostree_admin_kargs_option_context_new_with_commands (void)
+{
+  OstreeCommand *command = admin_kargs_subcommands;
+  GOptionContext *context = g_option_context_new ("COMMAND");
+
+  g_autoptr(GString) summary = g_string_new ("Builtin \"admin kargs\" Commands:");
+
+  while (command->name != NULL)
+    {
+      if ((command->flags & OSTREE_BUILTIN_FLAG_HIDDEN) == 0)
+        {
+          g_string_append_printf (summary, "\n  %-24s", command->name);
+          if (command->description != NULL)
+            g_string_append_printf (summary, "%s", command->description);
+        }
+
+      command++;
+    }
+
+  g_option_context_set_summary (context, summary->str);
+
+  return context;
+}
+
+gboolean
+ot_admin_builtin_kargs (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error)
+{
+  const char *subcommand_name = NULL;
+  int in, out;
+  for (in = 1, out = 1; in < argc; in++, out++)
+    {
+      /* The non-option is the command, take it out of the arguments */
+      if (argv[in][0] != '-')
+        {
+          if (subcommand_name == NULL)
+            {
+              subcommand_name = argv[in];
+              out--;
+              continue;
+            }
+        }
+
+      else if (g_str_equal (argv[in], "--"))
+        {
+          break;
+        }
+
+      argv[out] = argv[in];
+    }
+
+  argc = out;
+
+  OstreeCommand *subcommand = admin_kargs_subcommands;
+  while (subcommand->name)
+    {
+      if (g_strcmp0 (subcommand_name, subcommand->name) == 0)
+        break;
+      subcommand++;
+    }
+
+  if (!subcommand->name)
+    {
+      g_autoptr(GOptionContext) context =
+        ostree_admin_kargs_option_context_new_with_commands ();
+
+      /* This will not return for some options (e.g. --version). */
+      if (ostree_admin_option_context_parse (context, NULL, &argc, &argv,
+                                             OSTREE_ADMIN_BUILTIN_FLAG_NO_SYSROOT,
+                                             invocation, NULL, cancellable, error))
+        {
+          if (subcommand_name == NULL)
+            {
+              g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                                   "No \"admin kargs\" subcommand specified");
+            }
+          else
+            {
+              g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+                           "Unknown \"admin kargs\" subcommand '%s'", subcommand_name);
+            }
+        }
+
+      g_autofree char *help = g_option_context_get_help (context, FALSE, NULL);
+      g_printerr ("%s", help);
+      return FALSE;
+    }
+
+  g_autofree char *prgname = g_strdup_printf ("%s %s", g_get_prgname (), subcommand_name);
+  g_set_prgname (prgname);
+
+  OstreeCommandInvocation sub_invocation = { .command = subcommand };
+  if (!subcommand->fn (argc, argv, &sub_invocation, cancellable, error))
+    return FALSE;
+
+  return TRUE;
+}
index 8d9451bec6f86825d2290cdf6a340484f88a2ff1..8bac1c5625113651e735d093fb12aca9d430ace3 100644 (file)
@@ -46,6 +46,7 @@ BUILTINPROTO(set_origin);
 BUILTINPROTO(diff);
 BUILTINPROTO(switch);
 BUILTINPROTO(upgrade);
+BUILTINPROTO(kargs);
 
 #undef BUILTINPROTO
 
diff --git a/src/ostree/ot-admin-kargs-builtin-edit-in-place.c b/src/ostree/ot-admin-kargs-builtin-edit-in-place.c
new file mode 100644 (file)
index 0000000..40ada02
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2014 Colin Walters <walters@verbum.org>
+ * Copyright (C) 2022 Huijing Hei <hhei@redhat.com>
+ *
+ * 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, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "ot-main.h"
+#include "ot-admin-kargs-builtins.h"
+
+#include "ostree.h"
+#include "otutil.h"
+
+static char **opt_kargs_edit_in_place_append;
+
+static GOptionEntry options[] = {
+  { "append-if-missing", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_kargs_edit_in_place_append, "Append kernel arguments if they do not exist", "NAME=VALUE" },
+  { NULL }
+};
+
+gboolean
+ot_admin_kargs_builtin_edit_in_place (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error)
+{
+  g_autoptr(OstreeSysroot) sysroot = NULL;
+
+  g_autoptr(GOptionContext) context = g_option_context_new ("ARGS");
+
+  if (!ostree_admin_option_context_parse (context, options, &argc, &argv,
+                                          OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER,
+                                          invocation, &sysroot, cancellable, error))
+    return FALSE;
+
+  g_autoptr(GPtrArray) deployments = ostree_sysroot_get_deployments (sysroot);
+  if (deployments->len == 0)
+    {
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                   "Unable to find a deployment in sysroot");
+      return FALSE;
+    }
+
+  // set kargs for each deployment
+  for (guint i = 0; i < deployments->len; i++)
+    {
+      OstreeDeployment *deployment = deployments->pdata[i];
+      OstreeBootconfigParser *bootconfig = ostree_deployment_get_bootconfig (deployment);
+      g_autoptr(OstreeKernelArgs) kargs = ostree_kernel_args_from_string (ostree_bootconfig_parser_get (bootconfig, "options"));
+
+      if (opt_kargs_edit_in_place_append)
+        {
+          for (char **strviter = opt_kargs_edit_in_place_append; strviter && *strviter; strviter++)
+            {
+              const char *arg = *strviter;
+              ostree_kernel_args_append_if_missing (kargs, arg);
+            }
+        }
+      
+      g_auto(GStrv) kargs_strv = ostree_kernel_args_to_strv (kargs);
+      
+      if (!ostree_sysroot_deployment_set_kargs (sysroot, deployment,
+                                              kargs_strv,
+                                              cancellable, error))
+        return FALSE;
+      
+    }
+
+  return TRUE;
+}
diff --git a/src/ostree/ot-admin-kargs-builtins.h b/src/ostree/ot-admin-kargs-builtins.h
new file mode 100644 (file)
index 0000000..f3837c3
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2014 Colin Walters <walters@verbum.org>
+ * Copyright (C) 2022 Huijing Hei <hhei@redhat.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.0+
+ *
+ * This library 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 License, 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, see <https://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <ostree.h>
+
+G_BEGIN_DECLS
+
+#define BUILTINPROTO(name) gboolean ot_admin_kargs_builtin_ ## name (int argc, char **argv, \
+                                                                OstreeCommandInvocation *invocation, \
+                                                                GCancellable *cancellable, GError **error)
+
+BUILTINPROTO(edit_in_place);
+
+#undef BUILTINPROTO
+
+G_END_DECLS
index af09a6141679ae3997a62f434903d847eb1da702..503fb9a7bef3475a8a14a7ce015a906e4aab1bc0 100644 (file)
@@ -76,6 +76,9 @@ static OstreeCommand admin_subcommands[] = {
   { "upgrade", OSTREE_BUILTIN_FLAG_NO_REPO,
     ot_admin_builtin_upgrade,
     "Construct new tree from current origin and deploy it, if it changed" },
+  { "kargs", OSTREE_BUILTIN_FLAG_NO_REPO,
+    ot_admin_builtin_kargs,
+    "Change kernel arguments" },
   { NULL, 0, NULL, NULL }
 };
 
diff --git a/tests/test-admin-kargs.sh b/tests/test-admin-kargs.sh
new file mode 100755 (executable)
index 0000000..afcfc05
--- /dev/null
@@ -0,0 +1,44 @@
+#!/bin/bash
+#
+# Copyright (C) 2011 Colin Walters <walters@verbum.org>
+# Copyright (C) 2022 Huijing Hei <hhei@redhat.com>
+#
+# SPDX-License-Identifier: LGPL-2.0+
+#
+# This library 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 License, 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, see <https://www.gnu.org/licenses/>.
+
+set -euo pipefail
+
+. $(dirname $0)/libtest.sh
+
+# Exports OSTREE_SYSROOT so --sysroot not needed.
+setup_os_repository "archive" "syslinux"
+
+echo "1..2"
+
+${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull-local --remote=testos testos-repo testos/buildmain/x86_64-runtime
+${CMD_PREFIX} ostree admin deploy --karg=root=LABEL=MOO --karg=quiet --os=testos testos:testos/buildmain/x86_64-runtime
+${CMD_PREFIX} ostree admin kargs edit-in-place --append-if-missing=TESTARG=TESTVALUE --append-if-missing=ARGWITHOUTKEY testos:testos/buildmain/x86_64-runtime
+
+assert_file_has_content sysroot/boot/loader/entries/ostree-1-testos.conf 'options.*TESTARG=TESTVALUE .*ARGWITHOUTKEY'
+
+echo "ok kargs edit-in-place (basic)"
+
+${CMD_PREFIX} ostree admin kargs edit-in-place --append-if-missing=quiet testos:testos/buildmain/x86_64-runtime
+assert_not_file_has_content sysroot/boot/loader/entries/ostree-1-testos.conf 'quiet$'
+
+${CMD_PREFIX} ostree admin kargs edit-in-place --append-if-missing=TESTARG=TESTVALUE testos:testos/buildmain/x86_64-runtime
+assert_not_file_has_content sysroot/boot/loader/entries/ostree-1-testos.conf 'TESTARG=TESTVALUE$'
+
+echo "ok kargs edit-in-place (duplicate)"