]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core: Unit Runtime in io.systemd.Unit.List method
authorIvan Kruglov <mail@ikruglov.com>
Tue, 13 May 2025 18:40:49 +0000 (11:40 -0700)
committerIvan Kruglov <mail@ikruglov.com>
Tue, 27 May 2025 08:16:42 +0000 (01:16 -0700)
src/core/varlink-unit.c
src/shared/varlink-io.systemd.Unit.c

index 8967cc6bd434bc127b22752e0e3565e92800c071..f2ab708b237d954283b9bb8df12ddd341a959a39 100644 (file)
@@ -2,6 +2,10 @@
 
 #include "sd-json.h"
 
+#include "bitfield.h"
+#include "condition.h"
+#include "execute.h"
+#include "install.h"
 #include "json-util.h"
 #include "manager.h"
 #include "set.h"
@@ -183,6 +187,115 @@ static int unit_context_build_json(sd_json_variant **ret, const char *name, void
         // Socket context
 }
 
+static int can_clean_build_json(sd_json_variant **ret, const char *name, void *userdata) {
+        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
+        Unit *u = ASSERT_PTR(userdata);
+        ExecCleanMask mask;
+        int r;
+
+        assert(ret);
+
+        r = unit_can_clean(u, &mask);
+        if (r < 0)
+                return log_debug_errno(r, "Failed to check if unit can be cleaned: %m");
+
+        for (ExecDirectoryType t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++) {
+                if (!BIT_SET(mask, t))
+                        continue;
+
+                r = sd_json_variant_append_arrayb(&v, SD_JSON_BUILD_STRING(exec_resource_type_to_string(t)));
+                if (r < 0)
+                        return r;
+        }
+
+        if (FLAGS_SET(mask, EXEC_CLEAN_FDSTORE)) {
+                r = sd_json_variant_append_arrayb(&v, SD_JSON_BUILD_STRING("fdstore"));
+                if (r < 0)
+                        return r;
+        }
+
+        *ret = TAKE_PTR(v);
+        return 0;
+}
+
+static int markers_build_json(sd_json_variant **ret, const char *name, void *userdata) {
+        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
+        unsigned *markers = ASSERT_PTR(userdata);
+        int r;
+
+        assert(ret);
+
+        BIT_FOREACH(m, *markers) {
+                r = sd_json_variant_append_arrayb(&v, SD_JSON_BUILD_STRING(unit_marker_to_string(m)));
+                if (r < 0)
+                        return r;
+        }
+
+        *ret = TAKE_PTR(v);
+        return 0;
+}
+
+static int activation_details_build_json(sd_json_variant **ret, const char *name, void *userdata) {
+        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
+        const ActivationDetails *activation_details = userdata;
+        _cleanup_strv_free_ char **pairs = NULL;
+        int r;
+
+        assert(ret);
+
+        /* activation_details_append_pair() gracefully takes activation_details==NULL */
+        r = activation_details_append_pair(activation_details, &pairs);
+        if (r < 0)
+                return log_debug_errno(r, "Failed to get activation details: %m");
+
+        STRV_FOREACH_PAIR(key, value, pairs) {
+                r = sd_json_variant_append_arraybo(&v,
+                                SD_JSON_BUILD_PAIR_STRING("type", *key),
+                                SD_JSON_BUILD_PAIR_STRING("name", *value));
+                if (r < 0)
+                        return r;
+        }
+
+        *ret = TAKE_PTR(v);
+        return 0;
+}
+
+static int unit_runtime_build_json(sd_json_variant **ret, const char *name, void *userdata) {
+        Unit *u = ASSERT_PTR(userdata);
+        Unit *f = unit_following(u);
+
+        return sd_json_buildo(
+                        ASSERT_PTR(ret),
+                        JSON_BUILD_PAIR_STRING_NON_EMPTY("Following", f ? f->id : NULL),
+                        SD_JSON_BUILD_PAIR_STRING("LoadState", unit_load_state_to_string(u->load_state)),
+                        SD_JSON_BUILD_PAIR_STRING("ActiveState", unit_active_state_to_string(unit_active_state(u))),
+                        SD_JSON_BUILD_PAIR_STRING("FreezerState", freezer_state_to_string(u->freezer_state)),
+                        SD_JSON_BUILD_PAIR_STRING("SubState", unit_sub_state_to_string(u)),
+                        JSON_BUILD_PAIR_STRING_NON_EMPTY("UnitFileState", unit_file_state_to_string(unit_get_unit_file_state(u))),
+                        JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL("StateChangeTimestamp", &u->state_change_timestamp),
+                        JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL("ActiveEnterTimestamp", &u->active_enter_timestamp),
+                        JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL("ActiveExitTimestamp", &u->active_exit_timestamp),
+                        JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL("InactiveEnterTimestamp", &u->inactive_enter_timestamp),
+                        JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL("InactiveExitTimestamp", &u->inactive_exit_timestamp),
+                        SD_JSON_BUILD_PAIR_BOOLEAN("CanStart", unit_can_start_refuse_manual(u)),
+                        SD_JSON_BUILD_PAIR_BOOLEAN("CanStop", unit_can_stop_refuse_manual(u)),
+                        SD_JSON_BUILD_PAIR_BOOLEAN("CanReload", unit_can_reload(u)),
+                        SD_JSON_BUILD_PAIR_BOOLEAN("CanIsolate", unit_can_isolate_refuse_manual(u)),
+                        JSON_BUILD_PAIR_CALLBACK_NON_NULL("CanClean", can_clean_build_json, u),
+                        SD_JSON_BUILD_PAIR_BOOLEAN("CanFreeze", unit_can_freeze(u)),
+                        SD_JSON_BUILD_PAIR_BOOLEAN("CanLiveMount", unit_can_live_mount(u, /* error= */ NULL) >= 0),
+                        JSON_BUILD_PAIR_UNSIGNED_NON_ZERO("JobId", u->job ? u->job->id : 0),
+                        SD_JSON_BUILD_PAIR_BOOLEAN("NeedDaemonReload", unit_need_daemon_reload(u)),
+                        SD_JSON_BUILD_PAIR_BOOLEAN("ConditionResult", u->condition_result),
+                        SD_JSON_BUILD_PAIR_BOOLEAN("AssertResult", u->assert_result),
+                        JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL("ConditionTimestamp", &u->condition_timestamp),
+                        JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL("AssertTimestamp", &u->assert_timestamp),
+                        SD_JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(u->invocation_id), "InvocationID", SD_JSON_BUILD_UUID(u->invocation_id)),
+                        JSON_BUILD_PAIR_CALLBACK_NON_NULL("Markers", markers_build_json, &u->markers),
+                        JSON_BUILD_PAIR_CALLBACK_NON_NULL("ActivationDetails", activation_details_build_json, u->activation_details),
+                        SD_JSON_BUILD_PAIR_BOOLEAN("DebugInvocation", u->debug_invocation));
+}
+
 static int list_unit_one(sd_varlink *link, Unit *unit, bool more) {
         _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
         int r;
@@ -190,7 +303,10 @@ static int list_unit_one(sd_varlink *link, Unit *unit, bool more) {
         assert(link);
         assert(unit);
 
-        r = sd_json_buildo(&v, SD_JSON_BUILD_PAIR_CALLBACK("context", unit_context_build_json, unit));
+        r = sd_json_buildo(
+                &v,
+                SD_JSON_BUILD_PAIR_CALLBACK("context", unit_context_build_json, unit),
+                SD_JSON_BUILD_PAIR_CALLBACK("runtime", unit_runtime_build_json, unit));
         if (r < 0)
                 return r;
 
index bd8e6cc1c934607d4938db5e89b54765a77248eb..5c134ecd5dc14193d2bc99d867e77f91554fc3cf 100644 (file)
@@ -154,13 +154,81 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE(
                 SD_VARLINK_FIELD_COMMENT("Whether this unit is perpetual"),
                 SD_VARLINK_DEFINE_FIELD(Perpetual, SD_VARLINK_BOOL, 0));
 
+static SD_VARLINK_DEFINE_STRUCT_TYPE(
+                ActivationDetails,
+                SD_VARLINK_FIELD_COMMENT("Trigger unit type"),
+                SD_VARLINK_DEFINE_FIELD(type, SD_VARLINK_STRING, 0),
+                SD_VARLINK_FIELD_COMMENT("Trigger unit name"),
+                SD_VARLINK_DEFINE_FIELD(name, SD_VARLINK_STRING, 0));
+
+static SD_VARLINK_DEFINE_STRUCT_TYPE(
+                UnitRuntime,
+                SD_VARLINK_FIELD_COMMENT("If not empty, the field contains the name of another unit that this unit follows in state"),
+                SD_VARLINK_DEFINE_FIELD(Following, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
+                SD_VARLINK_FIELD_COMMENT("Reflects whether the configuration file of this unit has been loaded"),
+                SD_VARLINK_DEFINE_FIELD(LoadState, SD_VARLINK_STRING, 0),
+                SD_VARLINK_FIELD_COMMENT("Reflects whether the unit is currently active or not"),
+                SD_VARLINK_DEFINE_FIELD(ActiveState, SD_VARLINK_STRING, 0),
+                SD_VARLINK_FIELD_COMMENT("Reflects whether the unit is currently frozen or not"),
+                SD_VARLINK_DEFINE_FIELD(FreezerState, SD_VARLINK_STRING, 0),
+                SD_VARLINK_FIELD_COMMENT("Reflect more fine-grained state that is unit-type-specific"),
+                SD_VARLINK_DEFINE_FIELD(SubState, SD_VARLINK_STRING, 0),
+                SD_VARLINK_FIELD_COMMENT("Reflects the install state of the unit file"),
+                SD_VARLINK_DEFINE_FIELD(UnitFileState, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
+                SD_VARLINK_FIELD_COMMENT("Timestamp when the firmware first began execution"),
+                SD_VARLINK_DEFINE_FIELD_BY_TYPE(StateChangeTimestamp, Timestamp, SD_VARLINK_NULLABLE),
+                SD_VARLINK_FIELD_COMMENT("Timestamp when the unit entered active state"),
+                SD_VARLINK_DEFINE_FIELD_BY_TYPE(ActiveEnterTimestamp, Timestamp, SD_VARLINK_NULLABLE),
+                SD_VARLINK_FIELD_COMMENT("Timestamp when the unit exited active state"),
+                SD_VARLINK_DEFINE_FIELD_BY_TYPE(ActiveExitTimestamp, Timestamp, SD_VARLINK_NULLABLE),
+                SD_VARLINK_FIELD_COMMENT("Timestamp when the unit entered inactive state"),
+                SD_VARLINK_DEFINE_FIELD_BY_TYPE(InactiveEnterTimestamp, Timestamp, SD_VARLINK_NULLABLE),
+                SD_VARLINK_FIELD_COMMENT("Timestamp when the unit exited inactive state"),
+                SD_VARLINK_DEFINE_FIELD_BY_TYPE(InactiveExitTimestamp, Timestamp, SD_VARLINK_NULLABLE),
+                SD_VARLINK_FIELD_COMMENT("Reflects whether the unit can be started or not"),
+                SD_VARLINK_DEFINE_FIELD(CanStart, SD_VARLINK_BOOL, 0),
+                SD_VARLINK_FIELD_COMMENT("Reflects whether the unit can be stopped or not"),
+                SD_VARLINK_DEFINE_FIELD(CanStop, SD_VARLINK_BOOL, 0),
+                SD_VARLINK_FIELD_COMMENT("Reflects whether the unit can be reloaded or not"),
+                SD_VARLINK_DEFINE_FIELD(CanReload, SD_VARLINK_BOOL, 0),
+                SD_VARLINK_FIELD_COMMENT("Reflects whether the unit may be started in isolation mode"),
+                SD_VARLINK_DEFINE_FIELD(CanIsolate, SD_VARLINK_BOOL, 0),
+                SD_VARLINK_FIELD_COMMENT("Returns which unit resources can be cleaned up"),
+                SD_VARLINK_DEFINE_FIELD(CanClean, SD_VARLINK_STRING, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
+                SD_VARLINK_FIELD_COMMENT("Whether the unit supports the freeze operation"),
+                SD_VARLINK_DEFINE_FIELD(CanFreeze, SD_VARLINK_BOOL, 0),
+                SD_VARLINK_FIELD_COMMENT("Whether the unit supports live mounting"),
+                SD_VARLINK_DEFINE_FIELD(CanLiveMount, SD_VARLINK_BOOL, 0),
+                SD_VARLINK_FIELD_COMMENT("The job ID of the job currently scheduled or being executed for this unit, if there is any."),
+                SD_VARLINK_DEFINE_FIELD(JobId, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
+                SD_VARLINK_FIELD_COMMENT("Whether the configuration file this unit is loaded from (i.e. FragmentPath or SourcePath) has changed since the configuration was read and hence whether a configuration reload is recommended"),
+                SD_VARLINK_DEFINE_FIELD(NeedDaemonReload, SD_VARLINK_BOOL, 0),
+                SD_VARLINK_FIELD_COMMENT("Condition result of the last time the configured conditions of this unit were checked"),
+                SD_VARLINK_DEFINE_FIELD(ConditionResult, SD_VARLINK_BOOL, 0),
+                SD_VARLINK_FIELD_COMMENT("Assert result of the last time the configured asserts of this unit were checked"),
+                SD_VARLINK_DEFINE_FIELD(AssertResult, SD_VARLINK_BOOL, 0),
+                SD_VARLINK_FIELD_COMMENT("The last time the configured conditions of the unit have been checked"),
+                SD_VARLINK_DEFINE_FIELD_BY_TYPE(ConditionTimestamp, Timestamp, SD_VARLINK_NULLABLE),
+                SD_VARLINK_FIELD_COMMENT("The last time the configured asserts of the unit have been checked"),
+                SD_VARLINK_DEFINE_FIELD_BY_TYPE(AssertTimestamp, Timestamp, SD_VARLINK_NULLABLE),
+                SD_VARLINK_FIELD_COMMENT("Current invocation ID"),
+                SD_VARLINK_DEFINE_FIELD(InvocationID, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
+                SD_VARLINK_FIELD_COMMENT("Reflects whether the unit has been marked for reload, restart, etc."),
+                SD_VARLINK_DEFINE_FIELD(Markers, SD_VARLINK_STRING, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
+                SD_VARLINK_FIELD_COMMENT("Provides details about why a unit was activated"),
+                SD_VARLINK_DEFINE_FIELD_BY_TYPE(ActivationDetails, ActivationDetails, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
+                SD_VARLINK_FIELD_COMMENT("When true, logs about this unit will be at debug level regardless of other log level settings"),
+                SD_VARLINK_DEFINE_FIELD(DebugInvocation, SD_VARLINK_BOOL, 0));
+
 static SD_VARLINK_DEFINE_ERROR(NoSuchUnit);
 
 static SD_VARLINK_DEFINE_METHOD_FULL(
                 List,
                 SD_VARLINK_SUPPORTS_MORE,
                 SD_VARLINK_FIELD_COMMENT("Configuration of the unit"),
-                SD_VARLINK_DEFINE_OUTPUT_BY_TYPE(context, UnitContext, 0));
+                SD_VARLINK_DEFINE_OUTPUT_BY_TYPE(context, UnitContext, 0),
+                SD_VARLINK_FIELD_COMMENT("Runtime information of the unit"),
+                SD_VARLINK_DEFINE_OUTPUT_BY_TYPE(runtime, UnitRuntime, 0));
 
 SD_VARLINK_DEFINE_INTERFACE(
                 io_systemd_Unit,
@@ -172,5 +240,11 @@ SD_VARLINK_DEFINE_INTERFACE(
                 &vl_type_Condition,
                 SD_VARLINK_SYMBOL_COMMENT("An object to represent a unit's context"),
                 &vl_type_UnitContext,
+                SD_VARLINK_SYMBOL_COMMENT("An object to represent a unit's runtime information"),
+                &vl_type_UnitRuntime,
+                SD_VARLINK_SYMBOL_COMMENT("A timestamp object consisting of both CLOCK_REALTIME and CLOCK_MONOTONIC timestamps"),
+                &vl_type_Timestamp,
+                SD_VARLINK_SYMBOL_COMMENT("An object to represent a unit's activation details"),
+                &vl_type_ActivationDetails,
                 SD_VARLINK_SYMBOL_COMMENT("No matching unit found"),
                 &vl_error_NoSuchUnit);