From e8e274c8da28c75fc1b07dfb17673f0703c2c100 Mon Sep 17 00:00:00 2001 From: Andres Beltran Date: Tue, 1 Jul 2025 17:41:31 +0000 Subject: [PATCH] Add quota support for systemctl --- src/systemctl/systemctl-show.c | 75 ++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/src/systemctl/systemctl-show.c b/src/systemctl/systemctl-show.c index e906c08772e..e75e7ac1c17 100644 --- a/src/systemctl/systemctl-show.c +++ b/src/systemctl/systemctl-show.c @@ -15,8 +15,10 @@ #include "cgroup-show.h" #include "cpu-set-util.h" #include "errno-util.h" +#include "exec-directory-util.h" #include "exec-util.h" #include "exit-status.h" +#include "extract-word.h" #include "format-util.h" #include "hexdecoct.h" #include "hostname-setup.h" @@ -33,6 +35,7 @@ #include "pager.h" #include "parse-util.h" #include "path-util.h" +#include "percent-util.h" #include "pretty-print.h" #include "process-util.h" #include "set.h" @@ -161,6 +164,13 @@ typedef struct UnitCondition { LIST_FIELDS(struct UnitCondition, conditions); } UnitCondition; +typedef struct QuotaInfo { + bool quota_enforce; + bool quota_accounting; + uint64_t quota_usage; + uint64_t quota_limit; +} QuotaInfo; + static UnitCondition* unit_condition_free(UnitCondition *c) { if (!c) return NULL; @@ -299,6 +309,9 @@ typedef struct UnitStatusInfo { uint64_t default_memory_low; uint64_t default_startup_memory_low; + /* Exec Quotas */ + QuotaInfo exec_directories_quota[_EXEC_DIRECTORY_TYPE_MAX]; + LIST_HEAD(ExecStatusInfo, exec_status_info_list); } UnitStatusInfo; @@ -338,6 +351,22 @@ static void format_enable_state(const char *enable_state, const char **enable_on *enable_on = *enable_off = ""; } +static void print_exec_directory_quota(UnitStatusInfo *i, ExecDirectoryType dt) { + assert(i); + + if (!IN_SET(dt, EXEC_DIRECTORY_STATE, EXEC_DIRECTORY_CACHE, EXEC_DIRECTORY_LOGS)) + return; + + if (i->exec_directories_quota[dt].quota_accounting) { + printf(" %s: %s", exec_directory_type_to_string(dt), FORMAT_BYTES(i->exec_directories_quota[dt].quota_usage)); + + if (i->exec_directories_quota[dt].quota_enforce) + printf(" (max: %s)", FORMAT_BYTES(i->exec_directories_quota[dt].quota_limit)); + + printf("\n"); + } +} + static void print_status_info( sd_bus *bus, UnitStatusInfo *i, @@ -877,6 +906,9 @@ static void print_status_info( if (i->cpu_usage_nsec != UINT64_MAX) printf(" CPU: %s\n", FORMAT_TIMESPAN(i->cpu_usage_nsec / NSEC_PER_USEC, USEC_PER_MSEC)); + for (ExecDirectoryType dt = 0; dt < _EXEC_DIRECTORY_TYPE_MAX; dt++) + print_exec_directory_quota(i, dt); + if (i->control_group) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; static const char prefix[] = " "; @@ -1122,6 +1154,25 @@ static int map_exec(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_e return 0; } +static int map_quota(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) { + int r; + QuotaInfo *qi = ASSERT_PTR(userdata); + uint64_t quota_usage, quota_limit; + + r = sd_bus_message_read(m, "(tt)", "a_usage, "a_limit); + if (r < 0) + return r; + + *qi = (QuotaInfo) { + .quota_enforce = quota_limit != UINT64_MAX, + .quota_accounting = quota_usage != UINT64_MAX, + .quota_usage = quota_usage, + .quota_limit = quota_limit + }; + + return 0; +} + static int print_property(const char *name, const char *expected_value, sd_bus_message *m, BusPrintPropertyFlags flags) { char bus_type; const char *contents; @@ -1338,6 +1389,27 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m fputc('\n', stdout); } return 1; + } else if (STR_IN_SET(name, "StateDirectoryQuota", "CacheDirectoryQuota", "LogsDirectoryQuota")) { + uint64_t quota_absolute; + uint32_t quota_scale; + const char *quota_enforce; + + r = sd_bus_message_read(m, "(tus)", "a_absolute, "a_scale, "a_enforce); + if (r < 0) + return r; + + r = parse_boolean(quota_enforce); + if (r < 0) + return r; + + if (!r) + bus_print_property_value(name, expected_value, flags, "[not set]"); + else if (quota_absolute != UINT64_MAX) + bus_print_property_valuef(name, expected_value, flags, "%" PRIu64, quota_absolute); + else + bus_print_property_valuef(name, expected_value, flags, "%d%%", UINT32_SCALE_TO_PERCENT(quota_scale)); + + return 1; } break; @@ -2201,6 +2273,9 @@ static int show_one( { "IPEgressBytes", "t", NULL, offsetof(UnitStatusInfo, ip_egress_bytes) }, { "IOReadBytes", "t", NULL, offsetof(UnitStatusInfo, io_read_bytes) }, { "IOWriteBytes", "t", NULL, offsetof(UnitStatusInfo, io_write_bytes) }, + { "StateDirectoryQuotaUsage", "(tt)", map_quota, offsetof(UnitStatusInfo, exec_directories_quota[EXEC_DIRECTORY_STATE]) }, + { "CacheDirectoryQuotaUsage", "(tt)", map_quota, offsetof(UnitStatusInfo, exec_directories_quota[EXEC_DIRECTORY_CACHE]) }, + { "LogsDirectoryQuotaUsage", "(tt)", map_quota, offsetof(UnitStatusInfo, exec_directories_quota[EXEC_DIRECTORY_LOGS]) }, { "ExecCondition", "a(sasbttttuii)", map_exec, 0 }, { "ExecConditionEx", "a(sasasttttuii)", map_exec, 0 }, { "ExecStartPre", "a(sasbttttuii)", map_exec, 0 }, -- 2.47.3