Coverage Report

Created: 2025-08-28 06:46

/src/systemd/src/core/varlink-cgroup.c
Line
Count
Source (jump to first uncovered line)
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3
#include "sd-json.h"
4
5
#include "bpf-program.h"
6
#include "cgroup.h"
7
#include "cpu-set-util.h"
8
#include "json-util.h"
9
#include "in-addr-prefix-util.h"
10
#include "ip-protocol-list.h"
11
#include "path-util.h"
12
#include "set.h"
13
#include "unit.h"
14
#include "varlink-cgroup.h"
15
16
#define JSON_BUILD_PAIR_CONDITION_UNSIGNED(condition, name, value) \
17
        SD_JSON_BUILD_PAIR_CONDITION(condition, name, SD_JSON_BUILD_UNSIGNED(value))
18
19
0
static int cpu_set_build_json(sd_json_variant **ret, const char *name, void *userdata) {
20
0
        _cleanup_free_ uint8_t *array = NULL;
21
0
        CPUSet *cpuset = ASSERT_PTR(userdata);
22
0
        size_t allocated;
23
0
        int r;
24
25
0
        assert(ret);
26
0
        assert(name);
27
28
0
        if (!cpuset->set)
29
0
                goto empty;
30
31
0
        r = cpu_set_to_dbus(cpuset, &array, &allocated);
32
0
        if (r < 0)
33
0
                return log_debug_errno(r, "Failed to call cpu_set_to_dbus(): %m");
34
35
0
        if (allocated == 0)
36
0
                goto empty;
37
38
0
        return sd_json_variant_new_array_bytes(ret, array, allocated);
39
40
0
empty:
41
0
        *ret = NULL;
42
0
        return 0;
43
0
}
44
45
0
static int tasks_max_build_json(sd_json_variant **ret, const char *name, void *userdata) {
46
0
        CGroupTasksMax *tasks_max = ASSERT_PTR(userdata);
47
48
0
        assert(ret);
49
0
        assert(name);
50
51
0
        if (!cgroup_tasks_max_isset(tasks_max)) {
52
0
                *ret = NULL;
53
0
                return 0;
54
0
        }
55
56
0
        return sd_json_buildo(
57
0
                        ret,
58
0
                        SD_JSON_BUILD_PAIR_UNSIGNED("value", tasks_max->value),
59
0
                        SD_JSON_BUILD_PAIR_UNSIGNED("scale", tasks_max->scale));
60
0
}
61
62
0
static int io_device_weights_build_json(sd_json_variant **ret, const char *name, void *userdata) {
63
0
        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
64
0
        CGroupIODeviceWeight *weights = userdata;
65
0
        int r;
66
67
0
        assert(ret);
68
0
        assert(name);
69
70
0
        LIST_FOREACH(device_weights, w, weights) {
71
0
                r = sd_json_variant_append_arraybo(
72
0
                                &v,
73
0
                                SD_JSON_BUILD_PAIR_STRING("path", w->path),
74
0
                                SD_JSON_BUILD_PAIR_UNSIGNED("weight", w->weight));
75
0
                if (r < 0)
76
0
                        return r;
77
0
        }
78
79
0
        *ret = TAKE_PTR(v);
80
0
        return 0;
81
0
}
82
83
0
static int io_device_limits_build_json(sd_json_variant **ret, const char *name, void *userdata) {
84
0
        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
85
0
        CGroupIODeviceLimit *limits = userdata;
86
0
        int r;
87
88
0
        assert(ret);
89
0
        assert(name);
90
91
0
        CGroupIOLimitType type = cgroup_io_limit_type_from_string(name);
92
0
        assert(type >= 0);
93
94
0
        LIST_FOREACH(device_limits, l, limits) {
95
0
                if (l->limits[type] == cgroup_io_limit_defaults[type])
96
0
                        continue;
97
98
0
                r = sd_json_variant_append_arraybo(
99
0
                                &v,
100
0
                                SD_JSON_BUILD_PAIR_STRING("path", l->path),
101
0
                                SD_JSON_BUILD_PAIR_UNSIGNED("limit", l->limits[type]));
102
0
                if (r < 0)
103
0
                        return r;
104
0
        }
105
106
0
        *ret = TAKE_PTR(v);
107
0
        return 0;
108
0
}
109
110
0
static int io_device_latencies_build_json(sd_json_variant **ret, const char *name, void *userdata) {
111
0
        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
112
0
        CGroupIODeviceLatency *latencies = userdata;
113
0
        int r;
114
115
0
        assert(ret);
116
0
        assert(name);
117
118
0
        LIST_FOREACH(device_latencies, l, latencies) {
119
0
                r = sd_json_variant_append_arraybo(
120
0
                                &v,
121
0
                                SD_JSON_BUILD_PAIR_STRING("path", l->path),
122
0
                                JSON_BUILD_PAIR_FINITE_USEC("targetUSec", l->target_usec));
123
0
                if (r < 0)
124
0
                        return r;
125
0
        }
126
127
0
        *ret = TAKE_PTR(v);
128
0
        return 0;
129
0
}
130
131
0
static int ip_address_access_build_json(sd_json_variant **ret, const char *name, void *userdata) {
132
0
        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
133
0
        Set *prefixes = userdata;
134
0
        int r;
135
136
0
        assert(ret);
137
0
        assert(name);
138
139
0
        struct in_addr_prefix *i;
140
0
        SET_FOREACH(i, prefixes) {
141
0
                r = sd_json_variant_append_arraybo(
142
0
                                &v,
143
0
                                SD_JSON_BUILD_PAIR_INTEGER("family", i->family),
144
0
                                JSON_BUILD_PAIR_IN_ADDR("address", &i->address, i->family),
145
0
                                SD_JSON_BUILD_PAIR_UNSIGNED("prefixLength", i->prefixlen));
146
0
                if (r < 0)
147
0
                        return r;
148
0
        }
149
150
0
        *ret = TAKE_PTR(v);
151
0
        return 0;
152
0
}
153
154
0
static int socket_bind_build_json(sd_json_variant **ret, const char *name, void *userdata) {
155
0
        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
156
0
        CGroupSocketBindItem *items = userdata;
157
0
        int r;
158
159
0
        assert(ret);
160
0
        assert(name);
161
162
0
        LIST_FOREACH(socket_bind_items, i, items) {
163
0
                r = sd_json_variant_append_arraybo(
164
0
                                &v,
165
0
                                SD_JSON_BUILD_PAIR_INTEGER("family", i->address_family),
166
0
                                SD_JSON_BUILD_PAIR_STRING("protocol", ip_protocol_to_name(i->ip_protocol)),
167
0
                                SD_JSON_BUILD_PAIR_UNSIGNED("numberOfPorts", i->nr_ports),
168
0
                                SD_JSON_BUILD_PAIR_UNSIGNED("minimumPort", i->port_min));
169
0
                if (r < 0)
170
0
                        return r;
171
0
        }
172
173
0
        *ret = TAKE_PTR(v);
174
0
        return 0;
175
0
}
176
177
0
static int nft_set_build_json(sd_json_variant **ret, const char *name, void *userdata) {
178
0
        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
179
0
        NFTSetContext *c = ASSERT_PTR(userdata);
180
0
        int r;
181
182
0
        assert(ret);
183
0
        assert(name);
184
185
0
        FOREACH_ARRAY(nft_set, c->sets, c->n_sets) {
186
0
                r = sd_json_variant_append_arraybo(
187
0
                                &v,
188
0
                                SD_JSON_BUILD_PAIR_STRING("source", nft_set_source_to_string(nft_set->source)),
189
0
                                SD_JSON_BUILD_PAIR_STRING("protocol", nfproto_to_string(nft_set->nfproto)),
190
0
                                SD_JSON_BUILD_PAIR_STRING("table", nft_set->table),
191
0
                                SD_JSON_BUILD_PAIR_STRING("set", nft_set->set));
192
0
                if (r < 0)
193
0
                        return r;
194
0
        }
195
196
0
        *ret = TAKE_PTR(v);
197
0
        return 0;
198
0
}
199
200
0
static int bpf_program_build_json(sd_json_variant **ret, const char *name, void *userdata) {
201
0
        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
202
0
        CGroupBPFForeignProgram *programs = userdata;
203
0
        int r;
204
205
0
        assert(ret);
206
0
        assert(name);
207
208
0
        LIST_FOREACH(programs, p, programs) {
209
0
                r = sd_json_variant_append_arraybo(
210
0
                                &v,
211
0
                                SD_JSON_BUILD_PAIR_STRING("attachType", bpf_cgroup_attach_type_to_string(p->attach_type)),
212
0
                                SD_JSON_BUILD_PAIR_STRING("path", p->bpffs_path));
213
0
                if (r < 0)
214
0
                        return r;
215
0
        }
216
217
0
        *ret = TAKE_PTR(v);
218
0
        return 0;
219
0
}
220
221
0
static int device_allow_build_json(sd_json_variant **ret, const char *name, void *userdata) {
222
0
        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
223
0
        CGroupDeviceAllow *allow = userdata;
224
0
        int r;
225
226
0
        LIST_FOREACH(device_allow, a, allow) {
227
0
                r = sd_json_variant_append_arraybo(
228
0
                                &v,
229
0
                                SD_JSON_BUILD_PAIR_STRING("path", a->path),
230
0
                                SD_JSON_BUILD_PAIR_STRING("permissions", cgroup_device_permissions_to_string(a->permissions)));
231
0
                if (r < 0)
232
0
                        return r;
233
0
        }
234
235
0
        *ret = TAKE_PTR(v);
236
0
        return 0;
237
0
}
238
239
0
static int controllers_build_json(sd_json_variant **ret, const char *name, void *userdata) {
240
0
        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
241
0
        CGroupMask *mask = ASSERT_PTR(userdata);
242
0
        int r;
243
244
0
        assert(ret);
245
0
        assert(name);
246
247
0
        for (CGroupController ctrl = 0; ctrl < _CGROUP_CONTROLLER_MAX; ctrl++) {
248
0
                if (!FLAGS_SET(*mask, CGROUP_CONTROLLER_TO_MASK(ctrl)))
249
0
                        continue;
250
251
0
                r = sd_json_variant_append_arrayb(&v, SD_JSON_BUILD_STRING(cgroup_controller_to_string(ctrl)));
252
0
                if (r < 0)
253
0
                        return r;
254
0
        }
255
256
0
        *ret = TAKE_PTR(v);
257
0
        return 0;
258
0
}
259
260
0
int unit_cgroup_context_build_json(sd_json_variant **ret, const char *name, void *userdata) {
261
0
        Unit *u = ASSERT_PTR(userdata);
262
263
0
        assert(ret);
264
0
        assert(name);
265
266
0
        CGroupContext *c = unit_get_cgroup_context(u);
267
0
        if (!c) {
268
0
                *ret = NULL;
269
0
                return 0;
270
0
        }
271
272
        /* The main principle behind context/runtime split is the following:
273
         * If it make sense to place a property into a config/unit file it belongs to Context.
274
         * Otherwise it's a 'Runtime'. */
275
276
0
        return sd_json_buildo(
277
0
                        ret,
278
279
0
                        JSON_BUILD_PAIR_STRING_NON_EMPTY("Slice", unit_slice_name(u)),
280
281
                        /* CPU Control */
282
0
                        JSON_BUILD_PAIR_UNSIGNED_NOT_EQUAL("CPUWeight", c->cpu_weight, CGROUP_WEIGHT_INVALID),
283
0
                        JSON_BUILD_PAIR_UNSIGNED_NOT_EQUAL("StartupCPUWeight", c->startup_cpu_weight, CGROUP_WEIGHT_INVALID),
284
0
                        JSON_BUILD_PAIR_FINITE_USEC("CPUQuotaPerSecUSec", c->cpu_quota_per_sec_usec),
285
0
                        JSON_BUILD_PAIR_FINITE_USEC("CPUQuotaPeriodUSec", c->cpu_quota_period_usec),
286
0
                        JSON_BUILD_PAIR_CALLBACK_NON_NULL("AllowedCPUs", cpu_set_build_json, &c->cpuset_cpus),
287
0
                        JSON_BUILD_PAIR_CALLBACK_NON_NULL("StartupAllowedCPUs", cpu_set_build_json, &c->startup_cpuset_cpus),
288
289
                        /* Memory Accounting and Control */
290
0
                        SD_JSON_BUILD_PAIR_BOOLEAN("MemoryAccounting", c->memory_accounting),
291
0
                        JSON_BUILD_PAIR_CONDITION_UNSIGNED(c->memory_min_set, "MemoryMin", c->memory_min),
292
0
                        JSON_BUILD_PAIR_CONDITION_UNSIGNED(c->default_memory_min_set, "DefaultMemoryMin", c->default_memory_min),
293
0
                        JSON_BUILD_PAIR_CONDITION_UNSIGNED(c->memory_low_set, "MemoryLow", c->memory_low),
294
0
                        JSON_BUILD_PAIR_CONDITION_UNSIGNED(c->default_memory_low_set, "DefaultMemoryLow", c->default_memory_low),
295
0
                        JSON_BUILD_PAIR_CONDITION_UNSIGNED(c->startup_memory_low_set, "StartupMemoryLow", c->startup_memory_low),
296
0
                        JSON_BUILD_PAIR_CONDITION_UNSIGNED(c->default_startup_memory_low_set, "DefaultStartupMemoryLow", c->default_startup_memory_low),
297
0
                        JSON_BUILD_PAIR_UNSIGNED_NOT_EQUAL("MemoryHigh", c->memory_high, CGROUP_LIMIT_MAX),
298
0
                        JSON_BUILD_PAIR_CONDITION_UNSIGNED(c->startup_memory_high_set, "StartupMemoryHigh", c->startup_memory_high),
299
0
                        JSON_BUILD_PAIR_UNSIGNED_NOT_EQUAL("MemoryMax", c->memory_max, CGROUP_LIMIT_MAX),
300
0
                        JSON_BUILD_PAIR_CONDITION_UNSIGNED(c->startup_memory_max_set, "StartupMemoryMax", c->startup_memory_max),
301
0
                        JSON_BUILD_PAIR_UNSIGNED_NOT_EQUAL("MemorySwapMax", c->memory_swap_max, CGROUP_LIMIT_MAX),
302
0
                        JSON_BUILD_PAIR_CONDITION_UNSIGNED(c->startup_memory_swap_max_set, "StartupMemorySwapMax", c->startup_memory_swap_max),
303
0
                        JSON_BUILD_PAIR_UNSIGNED_NOT_EQUAL("MemoryZSwapMax", c->memory_zswap_max, CGROUP_LIMIT_MAX),
304
0
                        JSON_BUILD_PAIR_CONDITION_UNSIGNED(c->startup_memory_zswap_max_set, "StartupMemoryZSwapMax", c->startup_memory_zswap_max),
305
0
                        SD_JSON_BUILD_PAIR_BOOLEAN("MemoryZSwapWriteback", c->memory_zswap_writeback),
306
0
                        JSON_BUILD_PAIR_CALLBACK_NON_NULL("AllowedMemoryNodes", cpu_set_build_json, &c->cpuset_mems),
307
0
                        JSON_BUILD_PAIR_CALLBACK_NON_NULL("StartupAllowedMemoryNodes", cpu_set_build_json, &c->startup_cpuset_mems),
308
309
                        /* Process Accounting and Control */
310
0
                        SD_JSON_BUILD_PAIR_BOOLEAN("TasksAccounting", c->tasks_accounting),
311
0
                        JSON_BUILD_PAIR_CALLBACK_NON_NULL("TasksMax", tasks_max_build_json, &c->tasks_max),
312
313
                        /* IO Accounting and Control */
314
0
                        SD_JSON_BUILD_PAIR_BOOLEAN("IOAccounting", c->io_accounting),
315
0
                        JSON_BUILD_PAIR_UNSIGNED_NOT_EQUAL("IOWeight", c->io_weight, CGROUP_WEIGHT_INVALID),
316
0
                        JSON_BUILD_PAIR_UNSIGNED_NOT_EQUAL("StartupIOWeight", c->startup_io_weight, CGROUP_WEIGHT_INVALID),
317
0
                        JSON_BUILD_PAIR_CALLBACK_NON_NULL("IODeviceWeight", io_device_weights_build_json, c->io_device_weights),
318
0
                        JSON_BUILD_PAIR_CALLBACK_NON_NULL("IOReadBandwidthMax", io_device_limits_build_json, c->io_device_limits),
319
0
                        JSON_BUILD_PAIR_CALLBACK_NON_NULL("IOWriteBandwidthMax", io_device_limits_build_json, c->io_device_limits),
320
0
                        JSON_BUILD_PAIR_CALLBACK_NON_NULL("IOReadIOPSMax", io_device_limits_build_json, c->io_device_limits),
321
0
                        JSON_BUILD_PAIR_CALLBACK_NON_NULL("IOWriteIOPSMax", io_device_limits_build_json, c->io_device_limits),
322
0
                        JSON_BUILD_PAIR_CALLBACK_NON_NULL("IODeviceLatencyTargetUSec", io_device_latencies_build_json, c->io_device_latencies),
323
324
                        /* Network Accounting and Control */
325
0
                        SD_JSON_BUILD_PAIR_BOOLEAN("IPAccounting", c->ip_accounting),
326
0
                        JSON_BUILD_PAIR_CALLBACK_NON_NULL("IPAddressAllow", ip_address_access_build_json, c->ip_address_allow),
327
0
                        JSON_BUILD_PAIR_CALLBACK_NON_NULL("IPAddressDeny", ip_address_access_build_json, c->ip_address_deny),
328
0
                        JSON_BUILD_PAIR_CALLBACK_NON_NULL("SocketBindAllow", socket_bind_build_json, c->socket_bind_allow),
329
0
                        JSON_BUILD_PAIR_CALLBACK_NON_NULL("SocketBindDeny", socket_bind_build_json, c->socket_bind_deny),
330
0
                        SD_JSON_BUILD_PAIR_CONDITION(!set_isempty(c->restrict_network_interfaces), "RestrictNetworkInterfaces",
331
0
                                        SD_JSON_BUILD_OBJECT(
332
0
                                                SD_JSON_BUILD_PAIR_BOOLEAN("isAllowList", c->restrict_network_interfaces_is_allow_list),
333
0
                                                JSON_BUILD_PAIR_STRING_SET("interfaces", c->restrict_network_interfaces))),
334
0
                        JSON_BUILD_PAIR_CALLBACK_NON_NULL("NFTSet", nft_set_build_json, &c->nft_set_context),
335
336
                        /* BPF programs */
337
0
                        JSON_BUILD_PAIR_STRV_NON_EMPTY("IPIngressFilterPath", c->ip_filters_ingress),
338
0
                        JSON_BUILD_PAIR_STRV_NON_EMPTY("IPEgressFilterPath", c->ip_filters_egress),
339
0
                        JSON_BUILD_PAIR_CALLBACK_NON_NULL("BPFProgram", bpf_program_build_json, c->bpf_foreign_programs),
340
341
                        /* Device Access */
342
0
                        JSON_BUILD_PAIR_CALLBACK_NON_NULL("DeviceAllow", device_allow_build_json, c->device_allow),
343
0
                        SD_JSON_BUILD_PAIR_STRING("DevicePolicy", cgroup_device_policy_to_string(c->device_policy)),
344
345
                        /* Control Group Management */
346
0
                        SD_JSON_BUILD_PAIR_BOOLEAN("Delegate", c->delegate),
347
0
                        JSON_BUILD_PAIR_STRING_NON_EMPTY("DelegateSubgroup", c->delegate_subgroup),
348
0
                        JSON_BUILD_PAIR_CALLBACK_NON_NULL("DelegateControllers", controllers_build_json, &c->delegate_controllers),
349
0
                        JSON_BUILD_PAIR_CALLBACK_NON_NULL("DisableControllers", controllers_build_json, &c->disable_controllers),
350
351
                        /* Memory Pressure Control */
352
0
                        SD_JSON_BUILD_PAIR_STRING("ManagedOOMSwap", managed_oom_mode_to_string(c->moom_swap)),
353
0
                        SD_JSON_BUILD_PAIR_STRING("ManagedOOMMemoryPressure", managed_oom_mode_to_string(c->moom_mem_pressure)),
354
0
                        JSON_BUILD_PAIR_UNSIGNED_NON_ZERO("ManagedOOMMemoryPressureLimit", c->moom_mem_pressure_limit),
355
0
                        JSON_BUILD_PAIR_FINITE_USEC("ManagedOOMMemoryPressureDurationUSec", c->moom_mem_pressure_duration_usec),
356
0
                        SD_JSON_BUILD_PAIR_STRING("ManagedOOMPreference", managed_oom_preference_to_string(c->moom_preference)),
357
0
                        SD_JSON_BUILD_PAIR_STRING("MemoryPressureWatch", cgroup_pressure_watch_to_string(c->memory_pressure_watch)),
358
0
                        JSON_BUILD_PAIR_FINITE_USEC("MemoryPressureThresholdUSec", c->memory_pressure_threshold_usec),
359
360
                        /* Others */
361
0
                        SD_JSON_BUILD_PAIR_BOOLEAN("CoredumpReceive", c->coredump_receive));
362
0
}
363
364
0
static int memory_accounting_metric_build_json(sd_json_variant **ret, const char *name, void *userdata) {
365
0
        Unit *u = ASSERT_PTR(userdata);
366
0
        CGroupMemoryAccountingMetric metric;
367
0
        uint64_t value;
368
0
        int r;
369
370
0
        assert(ret);
371
0
        assert(name);
372
373
0
        metric = cgroup_memory_accounting_metric_from_string(name);
374
0
        assert(metric >= 0);
375
376
0
        r = unit_get_memory_accounting(u, metric, &value);
377
0
        if (r == -ENODATA)
378
0
                goto empty;
379
0
        if (r < 0)
380
0
                return log_debug_errno(r, "Failed to get value for '%s': %m", name);
381
382
0
        if (value == UINT64_MAX)
383
0
                goto empty;
384
385
0
        return sd_json_variant_new_unsigned(ret, value);
386
387
0
empty:
388
0
        *ret = NULL;
389
0
        return 0;
390
0
}
391
392
0
static int memory_available_build_json(sd_json_variant **ret, const char *name, void *userdata) {
393
0
        Unit *u = ASSERT_PTR(userdata);
394
0
        uint64_t value;
395
0
        int r;
396
397
0
        assert(ret);
398
0
        assert(name);
399
400
0
        r = unit_get_memory_available(u, &value);
401
0
        if (r == -ENODATA)
402
0
                goto empty;
403
0
        if (r < 0)
404
0
                return log_debug_errno(r, "Failed to get value of available memory: %m");
405
406
0
        if (value == UINT64_MAX)
407
0
                goto empty;
408
409
0
        return sd_json_variant_new_unsigned(ret, value);
410
411
0
empty:
412
0
        *ret = NULL;
413
0
        return 0;
414
0
}
415
416
0
static int effective_limit_build_json(sd_json_variant **ret, const char *name, void *userdata) {
417
0
        Unit *u = ASSERT_PTR(userdata);
418
0
        CGroupLimitType type;
419
0
        uint64_t value;
420
0
        int r;
421
422
0
        assert(ret);
423
0
        assert(name);
424
425
0
        type = cgroup_effective_limit_type_from_string(name);
426
0
        assert(type >= 0);
427
428
0
        r = unit_get_effective_limit(u, type, &value);
429
0
        if (r < 0)
430
0
                return log_debug_errno(r, "Failed to get value for '%s': %m", name);
431
432
0
        if (value == UINT64_MAX) {
433
0
                *ret = NULL;
434
0
                return 0;
435
0
        }
436
437
0
        return sd_json_variant_new_unsigned(ret, value);
438
0
}
439
440
0
static int cpu_usage_build_json(sd_json_variant **ret, const char *name, void *userdata) {
441
0
        Unit *u = ASSERT_PTR(userdata);
442
0
        nsec_t ns;
443
0
        int r;
444
445
0
        assert(ret);
446
0
        assert(name);
447
448
0
        r = unit_get_cpu_usage(u, &ns);
449
0
        if (r == -ENODATA)
450
0
                goto empty;
451
0
        if (r < 0)
452
0
                return log_debug_errno(r, "Failed to get cpu usage: %m");
453
454
0
        if (ns == NSEC_INFINITY)
455
0
                goto empty;
456
457
0
        return sd_json_variant_new_unsigned(ret, ns);
458
459
0
empty:
460
0
        *ret = NULL;
461
0
        return 0;
462
0
}
463
464
0
static int effective_cpuset_build_json(sd_json_variant **ret, const char *name, void *userdata, const char *cpuset_name) {
465
0
        Unit *u = ASSERT_PTR(userdata);
466
0
        _cleanup_(cpu_set_done) CPUSet cpus = {};
467
0
        int r;
468
469
0
        assert(ret);
470
0
        assert(name);
471
0
        assert(cpuset_name);
472
473
0
        r = unit_get_cpuset(u, &cpus, cpuset_name);
474
0
        if (r == -ENODATA) {
475
0
                *ret = NULL;
476
0
                return 0;
477
0
        }
478
0
        if (r < 0)
479
0
                return log_debug_errno(r, "Failed to get cpu set '%s': %m", cpuset_name);
480
481
0
        return cpu_set_build_json(ret, name, &cpus);
482
0
}
483
484
0
static inline int effective_cpus_build_json(sd_json_variant **ret, const char *name, void *userdata) {
485
0
        return effective_cpuset_build_json(ret, name, userdata, "cpuset.cpus.effective");
486
0
}
487
488
0
static inline int effective_mems_build_json(sd_json_variant **ret, const char *name, void *userdata) {
489
0
        return effective_cpuset_build_json(ret, name, userdata, "cpuset.mems.effective");
490
0
}
491
492
0
static int tasks_current_build_json(sd_json_variant **ret, const char *name, void *userdata) {
493
0
        Unit *u = ASSERT_PTR(userdata);
494
0
        uint64_t cn;
495
0
        int r;
496
497
0
        assert(ret);
498
0
        assert(name);
499
500
0
        r = unit_get_tasks_current(u, &cn);
501
0
        if (r == -ENODATA)
502
0
                goto empty;
503
0
        if (r < 0)
504
0
                return log_debug_errno(r, "Failed to get count of current tasks: %m");
505
506
0
        if (cn == UINT64_MAX)
507
0
                goto empty;
508
509
0
        return sd_json_variant_new_unsigned(ret, cn);
510
511
0
empty:
512
0
        *ret = NULL;
513
0
        return 0;
514
0
}
515
516
0
static int get_ip_counter_build_json(sd_json_variant **ret, const char *name, void *userdata) {
517
0
        Unit *u = ASSERT_PTR(userdata);
518
0
        CGroupIPAccountingMetric metric;
519
0
        uint64_t value;
520
0
        int r;
521
522
0
        assert(ret);
523
0
        assert(name);
524
525
0
        metric = cgroup_ip_accounting_metric_from_string(name);
526
0
        assert(metric >= 0);
527
528
0
        r = unit_get_ip_accounting(u, metric, &value);
529
0
        if (r == -ENODATA)
530
0
                goto empty;
531
0
        if (r < 0)
532
0
                return log_debug_errno(r, "Failed to get value for '%s': %m", name);
533
534
0
        if (value == UINT64_MAX)
535
0
                goto empty;
536
537
0
        return sd_json_variant_new_unsigned(ret, value);
538
539
0
empty:
540
0
        *ret = NULL;
541
0
        return 0;
542
0
}
543
544
0
static int get_io_counter_build_json(sd_json_variant **ret, const char *name, void *userdata) {
545
0
        Unit *u = ASSERT_PTR(userdata);
546
0
        CGroupIOAccountingMetric metric;
547
0
        uint64_t value;
548
0
        int r;
549
550
0
        assert(ret);
551
0
        assert(name);
552
553
0
        metric = cgroup_io_accounting_metric_from_string(name);
554
0
        assert(metric >= 0);
555
556
0
        r = unit_get_io_accounting(u, metric, &value);
557
0
        if (r == -ENODATA)
558
0
                goto empty;
559
0
        if (r < 0)
560
0
                return log_debug_errno(r, "Failed to get value for '%s': %m", name);
561
562
0
        if (value == UINT64_MAX)
563
0
                goto empty;
564
565
0
        return sd_json_variant_new_unsigned(ret, value);
566
567
0
empty:
568
0
        *ret = NULL;
569
0
        return 0;
570
0
}
571
572
0
int unit_cgroup_runtime_build_json(sd_json_variant **ret, const char *name, void *userdata) {
573
0
        Unit *u = ASSERT_PTR(userdata);
574
575
0
        assert(ret);
576
0
        assert(name);
577
578
0
        CGroupRuntime *crt = unit_get_cgroup_runtime(u);
579
0
        if (!crt) {
580
0
                *ret = NULL;
581
0
                return 0;
582
0
        }
583
584
0
        return sd_json_buildo(
585
0
                        ret,
586
587
                        /* ID */
588
0
                        JSON_BUILD_PAIR_UNSIGNED_NON_ZERO("ID", crt->cgroup_id),
589
0
                        JSON_BUILD_PAIR_STRING_NON_EMPTY("Path", crt->cgroup_path ? empty_to_root(crt->cgroup_path) : NULL),
590
591
                        /* Memory */
592
0
                        JSON_BUILD_PAIR_CALLBACK_NON_NULL("MemoryCurrent", memory_accounting_metric_build_json, u),
593
0
                        JSON_BUILD_PAIR_CALLBACK_NON_NULL("MemoryPeak", memory_accounting_metric_build_json, u),
594
0
                        JSON_BUILD_PAIR_CALLBACK_NON_NULL("MemorySwapCurrent", memory_accounting_metric_build_json, u),
595
0
                        JSON_BUILD_PAIR_CALLBACK_NON_NULL("MemorySwapPeak", memory_accounting_metric_build_json, u),
596
0
                        JSON_BUILD_PAIR_CALLBACK_NON_NULL("MemoryZSwapCurrent", memory_accounting_metric_build_json, u),
597
0
                        JSON_BUILD_PAIR_CALLBACK_NON_NULL("MemoryAvailable", memory_available_build_json, u),
598
0
                        JSON_BUILD_PAIR_CALLBACK_NON_NULL("EffectiveMemoryMax", effective_limit_build_json, u),
599
0
                        JSON_BUILD_PAIR_CALLBACK_NON_NULL("EffectiveMemoryHigh", effective_limit_build_json, u),
600
0
                        JSON_BUILD_PAIR_CALLBACK_NON_NULL("EffectiveMemoryNodes", effective_mems_build_json, u),
601
602
                        /* CPU */
603
0
                        JSON_BUILD_PAIR_CALLBACK_NON_NULL("CPUUsageNSec", cpu_usage_build_json, u),
604
0
                        JSON_BUILD_PAIR_CALLBACK_NON_NULL("EffectiveCPUs", effective_cpus_build_json, u),
605
0
                        JSON_BUILD_PAIR_CALLBACK_NON_NULL("TasksCurrent", tasks_current_build_json, u),
606
0
                        JSON_BUILD_PAIR_CALLBACK_NON_NULL("EffectiveTasksMax", effective_limit_build_json, u),
607
608
                        /* IP */
609
0
                        JSON_BUILD_PAIR_CALLBACK_NON_NULL("IPIngressBytes", get_ip_counter_build_json, u),
610
0
                        JSON_BUILD_PAIR_CALLBACK_NON_NULL("IPIngressPackets", get_ip_counter_build_json, u),
611
0
                        JSON_BUILD_PAIR_CALLBACK_NON_NULL("IPEgressBytes", get_ip_counter_build_json, u),
612
0
                        JSON_BUILD_PAIR_CALLBACK_NON_NULL("IPEgressPackets", get_ip_counter_build_json, u),
613
614
                        /* IO */
615
0
                        JSON_BUILD_PAIR_CALLBACK_NON_NULL("IOReadBytes", get_io_counter_build_json, u),
616
0
                        JSON_BUILD_PAIR_CALLBACK_NON_NULL("IOReadOperations", get_io_counter_build_json, u),
617
0
                        JSON_BUILD_PAIR_CALLBACK_NON_NULL("IOWriteBytes", get_io_counter_build_json, u),
618
0
                        JSON_BUILD_PAIR_CALLBACK_NON_NULL("IOWriteOperations", get_io_counter_build_json, u));
619
0
}