/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 | } |