]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Add quota support for systemctl
authorAndres Beltran <abeltran@microsoft.com>
Tue, 1 Jul 2025 17:41:31 +0000 (17:41 +0000)
committerAndres Beltran <abeltran@microsoft.com>
Mon, 7 Jul 2025 17:31:05 +0000 (17:31 +0000)
src/systemctl/systemctl-show.c

index e906c08772e578d846808759d08e96c7bdb04e89..e75e7ac1c176cb328ad8537048dc4fe59f346e6d 100644 (file)
 #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)", &quota_usage, &quota_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)", &quota_absolute, &quota_scale, &quota_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                                                           },