]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core: implement SwapContext/Runtime for io.systemd.Unit.List + tests
authorIvan Kruglov <mail@ikruglov.com>
Thu, 7 May 2026 12:05:24 +0000 (05:05 -0700)
committerIvan Kruglov <mail@ikruglov.com>
Mon, 11 May 2026 11:32:14 +0000 (04:32 -0700)
Add varlink context and runtime builders for .swap units:

SwapContext: What, Priority, Options, TimeoutUSec, ExecActivate, ExecDeactivate
SwapRuntime: ControlPID, Result, CleanResult, UID, GID (SwapResult enum)

SwapResult is exposed as a proper varlink enum type. Runtime follows the same pattern as MountRuntime (ControlPID, Result, CleanResult, ref UID/GID).

The integration test is conditional since swap units may not be present on all systems.

Co-developed-by: Claude Opus 4.6 <noreply@anthropic.com>
src/core/meson.build
src/core/varlink-swap.c [new file with mode: 0644]
src/core/varlink-swap.h [new file with mode: 0644]
src/core/varlink-unit.c
src/shared/varlink-io.systemd.Unit.c
src/shared/varlink-io.systemd.Unit.h
src/test/test-varlink-idl-unit.c
test/units/TEST-74-AUX-UTILS.varlinkctl.sh

index 796669814bf351ff9e2152e667d2d9abef7eec87..e59a683c9a50b421c660404e2a7a1ba89180911a 100644 (file)
@@ -75,6 +75,7 @@ libcore_sources = files(
         'varlink-mount.c',
         'varlink-path.c',
         'varlink-scope.c',
+        'varlink-swap.c',
         'varlink-unit.c',
 )
 
diff --git a/src/core/varlink-swap.c b/src/core/varlink-swap.c
new file mode 100644 (file)
index 0000000..055e73a
--- /dev/null
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "sd-json.h"
+
+#include "json-util.h"
+#include "swap.h"
+#include "user-util.h"
+#include "varlink-common.h"
+#include "varlink-swap.h"
+
+int swap_context_build_json(sd_json_variant **ret, const char *name, void *userdata) {
+        Swap *s = ASSERT_PTR(SWAP(userdata));
+
+        return sd_json_buildo(
+                        ASSERT_PTR(ret),
+                        SD_JSON_BUILD_PAIR_STRING("What", s->what),
+                        JSON_BUILD_PAIR_INTEGER_NON_NEGATIVE("Priority", swap_get_priority(s)),
+                        JSON_BUILD_PAIR_STRING_NON_EMPTY("Options", swap_get_options(s)),
+                        JSON_BUILD_PAIR_FINITE_USEC("TimeoutUSec", s->timeout_usec),
+                        JSON_BUILD_PAIR_CALLBACK_NON_NULL("ExecActivate", exec_command_build_json, &s->exec_command[SWAP_EXEC_ACTIVATE]),
+                        JSON_BUILD_PAIR_CALLBACK_NON_NULL("ExecDeactivate", exec_command_build_json, &s->exec_command[SWAP_EXEC_DEACTIVATE]));
+}
+
+int swap_runtime_build_json(sd_json_variant **ret, const char *name, void *userdata) {
+        Unit *u = ASSERT_PTR(userdata);
+        Swap *s = ASSERT_PTR(SWAP(u));
+
+        return sd_json_buildo(
+                        ASSERT_PTR(ret),
+                        SD_JSON_BUILD_PAIR_CONDITION(pidref_is_set(&s->control_pid), "ControlPID", JSON_BUILD_PIDREF(&s->control_pid)),
+                        JSON_BUILD_PAIR_ENUM("Result", swap_result_to_string(s->result)),
+                        JSON_BUILD_PAIR_ENUM("CleanResult", swap_result_to_string(s->clean_result)),
+                        SD_JSON_BUILD_PAIR_CONDITION(uid_is_valid(u->ref_uid), "UID", SD_JSON_BUILD_UNSIGNED(u->ref_uid)),
+                        SD_JSON_BUILD_PAIR_CONDITION(gid_is_valid(u->ref_gid), "GID", SD_JSON_BUILD_UNSIGNED(u->ref_gid)));
+}
diff --git a/src/core/varlink-swap.h b/src/core/varlink-swap.h
new file mode 100644 (file)
index 0000000..f76aa63
--- /dev/null
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include "core-forward.h"
+
+int swap_context_build_json(sd_json_variant **ret, const char *name, void *userdata);
+int swap_runtime_build_json(sd_json_variant **ret, const char *name, void *userdata);
index 30b912ddf103697f17e7e2caab786e5108df9ac9..fa017e955157f4b3a34dcd636c963a684ad7062b 100644 (file)
@@ -31,6 +31,7 @@
 #include "varlink-mount.h"
 #include "varlink-path.h"
 #include "varlink-scope.h"
+#include "varlink-swap.h"
 #include "varlink-unit.h"
 #include "varlink-util.h"
 
@@ -167,6 +168,7 @@ static int unit_context_build_json(sd_json_variant **ret, const char *name, void
                 [UNIT_PATH]      = path_context_build_json,
                 [UNIT_SCOPE]     = scope_context_build_json,
                 [UNIT_SERVICE]   = service_context_build_json,
+                [UNIT_SWAP]      = swap_context_build_json,
         };
 
         return sd_json_buildo(
@@ -334,6 +336,7 @@ static int unit_runtime_build_json(sd_json_variant **ret, const char *name, void
                 [UNIT_MOUNT]     = mount_runtime_build_json,
                 [UNIT_PATH]      = path_runtime_build_json,
                 [UNIT_SCOPE]     = scope_runtime_build_json,
+                [UNIT_SWAP]      = swap_runtime_build_json,
         };
 
         return sd_json_buildo(
index 83a728e2cc68027dfe9ae334ca1bd10ef11cebbc..4d77e64a740dbbdecdc8e4fbb48dfa0bd5d785e9 100644 (file)
@@ -1041,6 +1041,46 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE(
                 SD_VARLINK_FIELD_COMMENT("Result of scope operation"),
                 SD_VARLINK_DEFINE_FIELD_BY_TYPE(Result, ScopeResult, 0));
 
+/* SwapContext
+ * https://www.freedesktop.org/software/systemd/man/latest/systemd.swap.html */
+static SD_VARLINK_DEFINE_STRUCT_TYPE(
+                SwapContext,
+                SD_VARLINK_FIELD_COMMENT("https://www.freedesktop.org/software/systemd/man/"PROJECT_VERSION_STR"/systemd.swap.html#What="),
+                SD_VARLINK_DEFINE_FIELD(What, SD_VARLINK_STRING, 0),
+                SD_VARLINK_FIELD_COMMENT("https://www.freedesktop.org/software/systemd/man/"PROJECT_VERSION_STR"/systemd.swap.html#Priority="),
+                SD_VARLINK_DEFINE_FIELD(Priority, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
+                SD_VARLINK_FIELD_COMMENT("https://www.freedesktop.org/software/systemd/man/"PROJECT_VERSION_STR"/systemd.swap.html#Options="),
+                SD_VARLINK_DEFINE_FIELD(Options, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
+                SD_VARLINK_FIELD_COMMENT("https://www.freedesktop.org/software/systemd/man/"PROJECT_VERSION_STR"/systemd.swap.html#TimeoutSec="),
+                SD_VARLINK_DEFINE_FIELD(TimeoutUSec, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
+                SD_VARLINK_FIELD_COMMENT("Activate command"),
+                SD_VARLINK_DEFINE_FIELD_BY_TYPE(ExecActivate, ExecCommand, SD_VARLINK_NULLABLE),
+                SD_VARLINK_FIELD_COMMENT("Deactivate command"),
+                SD_VARLINK_DEFINE_FIELD_BY_TYPE(ExecDeactivate, ExecCommand, SD_VARLINK_NULLABLE));
+
+SD_VARLINK_DEFINE_ENUM_TYPE(
+                SwapResult,
+                SD_VARLINK_DEFINE_ENUM_VALUE(success),
+                SD_VARLINK_DEFINE_ENUM_VALUE(resources),
+                SD_VARLINK_DEFINE_ENUM_VALUE(timeout),
+                SD_VARLINK_DEFINE_ENUM_VALUE(exit_code),
+                SD_VARLINK_DEFINE_ENUM_VALUE(signal),
+                SD_VARLINK_DEFINE_ENUM_VALUE(core_dump),
+                SD_VARLINK_DEFINE_ENUM_VALUE(start_limit_hit));
+
+static SD_VARLINK_DEFINE_STRUCT_TYPE(
+                SwapRuntime,
+                SD_VARLINK_FIELD_COMMENT("PID of the current swap control process"),
+                SD_VARLINK_DEFINE_FIELD_BY_TYPE(ControlPID, ProcessId, SD_VARLINK_NULLABLE),
+                SD_VARLINK_FIELD_COMMENT("Result of swap operation"),
+                SD_VARLINK_DEFINE_FIELD_BY_TYPE(Result, SwapResult, 0),
+                SD_VARLINK_FIELD_COMMENT("Result of cleaning operation"),
+                SD_VARLINK_DEFINE_FIELD_BY_TYPE(CleanResult, SwapResult, 0),
+                SD_VARLINK_FIELD_COMMENT("Reference UID"),
+                SD_VARLINK_DEFINE_FIELD(UID, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
+                SD_VARLINK_FIELD_COMMENT("Reference GID"),
+                SD_VARLINK_DEFINE_FIELD(GID, SD_VARLINK_INT, SD_VARLINK_NULLABLE));
+
 /* Service-specific types */
 
 /* Keep in sync with service_type_table[] in src/core/service.c */
@@ -1237,7 +1277,9 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE(
                 SD_VARLINK_FIELD_COMMENT("The path context of the unit"),
                 SD_VARLINK_DEFINE_FIELD_BY_TYPE(Path, PathContext, SD_VARLINK_NULLABLE),
                 SD_VARLINK_FIELD_COMMENT("The scope context of the unit"),
-                SD_VARLINK_DEFINE_FIELD_BY_TYPE(Scope, ScopeContext, SD_VARLINK_NULLABLE));
+                SD_VARLINK_DEFINE_FIELD_BY_TYPE(Scope, ScopeContext, SD_VARLINK_NULLABLE),
+                SD_VARLINK_FIELD_COMMENT("The swap context of the unit"),
+                SD_VARLINK_DEFINE_FIELD_BY_TYPE(Swap, SwapContext, SD_VARLINK_NULLABLE));
 
 static SD_VARLINK_DEFINE_STRUCT_TYPE(
                 ActivationDetails,
@@ -1415,7 +1457,9 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE(
                 SD_VARLINK_FIELD_COMMENT("The path runtime of the unit"),
                 SD_VARLINK_DEFINE_FIELD_BY_TYPE(Path, PathRuntime, SD_VARLINK_NULLABLE),
                 SD_VARLINK_FIELD_COMMENT("The scope runtime of the unit"),
-                SD_VARLINK_DEFINE_FIELD_BY_TYPE(Scope, ScopeRuntime, SD_VARLINK_NULLABLE));
+                SD_VARLINK_DEFINE_FIELD_BY_TYPE(Scope, ScopeRuntime, SD_VARLINK_NULLABLE),
+                SD_VARLINK_FIELD_COMMENT("The swap runtime of the unit"),
+                SD_VARLINK_DEFINE_FIELD_BY_TYPE(Swap, SwapRuntime, SD_VARLINK_NULLABLE));
 
 static SD_VARLINK_DEFINE_METHOD_FULL(
                 List,
@@ -1586,6 +1630,9 @@ SD_VARLINK_DEFINE_INTERFACE(
                 &vl_type_ScopeContext,
                 &vl_type_ScopeResult,
                 &vl_type_ScopeRuntime,
+                &vl_type_SwapContext,
+                &vl_type_SwapResult,
+                &vl_type_SwapRuntime,
 
                 /* UnitContext enums */
                 &vl_type_CollectMode,
index 54d2dad1c13391d5b4c60f04c95aba7873b5f802..230fc5c43eeab1b64ec9ab0f03d966c37282baeb 100644 (file)
@@ -33,6 +33,7 @@ extern const sd_varlink_symbol vl_type_MountResult;
 extern const sd_varlink_symbol vl_type_PathType;
 extern const sd_varlink_symbol vl_type_PathResult;
 extern const sd_varlink_symbol vl_type_ScopeResult;
+extern const sd_varlink_symbol vl_type_SwapResult;
 extern const sd_varlink_symbol vl_type_CollectMode;
 extern const sd_varlink_symbol vl_type_JobMode;
 extern const sd_varlink_symbol vl_type_ServiceType;
index 5e9ce4ce0612270db88904a148fe14855be2e3c9..eba3a7d96a520d805dfff8a071bf99fe01ddab69 100644 (file)
@@ -75,6 +75,9 @@ TEST(unit_enums_idl) {
         /* ScopeRuntime enums */
         TEST_IDL_ENUM(ScopeResult, scope_result, vl_type_ScopeResult);
 
+        /* SwapRuntime enums */
+        TEST_IDL_ENUM(SwapResult, swap_result, vl_type_SwapResult);
+
         /* UnitContext enums */
         TEST_IDL_ENUM(CollectMode, collect_mode, vl_type_CollectMode);
         TEST_IDL_ENUM(EmergencyAction, emergency_action, vl_type_EmergencyAction);
index 900eda1138c25d8bcc61b1ed77454c5311c0a5ac..4d9649f2d702df96fc99b7bb5c27dbb694e4371e 100755 (executable)
@@ -258,6 +258,13 @@ test -n "$scope_id"
 scope_params=$(jq -cn --arg name "$scope_id" '{name: $name}')
 varlinkctl call /run/systemd/io.systemd.Manager io.systemd.Unit.List "$scope_params" | jq -e '.context.Scope'
 varlinkctl call /run/systemd/io.systemd.Manager io.systemd.Unit.List "$scope_params" | jq -e '.runtime.Scope'
+# test for SwapContext/Runtime (swap units may not be present on all systems)
+swap_id=$(varlinkctl call --collect /run/systemd/io.systemd.Manager io.systemd.Unit.List '{}' | jq -r '.[] | select(.context.Type == "swap" and .runtime.LoadState == "loaded") .context.ID // empty' | tail -n 1)
+if test -n "$swap_id"; then
+    swap_params=$(jq -cn --arg name "$swap_id" '{name: $name}')
+    varlinkctl call /run/systemd/io.systemd.Manager io.systemd.Unit.List "$swap_params" | jq -e '.context.Swap'
+    varlinkctl call /run/systemd/io.systemd.Manager io.systemd.Unit.List "$swap_params" | jq -e '.runtime.Swap'
+fi
 
 # test io.systemd.Metrics
 varlinkctl info /run/systemd/report/io.systemd.Manager