• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

drakenclimber / libcgroup / 14937352646

09 May 2025 08:40PM UTC coverage: 54.044% (-2.1%) from 56.161%
14937352646

push

github

drakenclimber
wip - have it working

sudo ./src/tools/cgset -p -r AllowedCPUs=1-3,6-13,15 foo.scope

Signed-off-by: Tom Hromatka <tom.hromatka@oracle.com>

8 of 222 new or added lines in 2 files covered. (3.6%)

170 existing lines in 13 files now uncovered.

5573 of 10312 relevant lines covered (54.04%)

325.78 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

40.37
/src/systemd.c
1
/* SPDX-License-Identifier: LGPL-2.1-only */
2
/**
3
 * Copyright (c) 2022-2025 Oracle and/or its affiliates.
4
 * Author: Tom Hromatka <tom.hromatka@oracle.com>
5
 * Author: Silvia Chapa <silvia.chapa@oracle.com>
6
 */
7

8
#include "libcgroup-internal.h"
9

10
#ifdef WITH_SYSTEMD
11
#include <systemd/sd-bus.h>
12
#include <libcgroup.h>
13
#include <unistd.h>
14
#include <assert.h>
15
#include <stdlib.h>
16
#include <libgen.h>
17
#include <errno.h>
18

19
#define USEC_PER_SEC 1000000
20

21
static const char * const modes[] = {
22
        "fail",                        /* CGROUP_SYSTEMD_MODE_FAIL */
23
        "replace",                /* CGROUP_SYSTEMD_MODE_REPLACE */
24
        "isolate",                /* CGROUP_SYSTEMD_MODE_ISOLATE */
25
        "ignore-dependencies",        /* CGROUP_SYSTEMD_MODE_IGNORE_DEPS */
26
        "ignore-requirements",        /* CGROUP_SYSTEMD_MODE_IGNORE_REQS */
27
};
28
static_assert(ARRAY_SIZE(modes) == CGROUP_SYSTEMD_MODE_CNT,
29
              "modes[] array must be same length as CGROUP_SYSTEMD_MODE_CNT");
30

31
/*
32
 * controller_name table borrowed from:
33
 * https://github.com/systemd/systemd/blob/main/src/basic/cgroup-util.c#L2260
34
 */
35
static const char * const controller_name[] = {
36
        /* subset of controllers (cgroup v1/v2), systemd supports */
37
        "cpu",
38
        "cpuacct",
39
        "cpuset",
40
        "io",
41
        "blkio",
42
        "memory",
43
        "devices",
44
        "pids",
45

46
        /* systemd pseudo BPF based controllers (cgroup v2 ) */
47
        "bpf-firewall",
48
        "bpf-devices",
49
        "bpf-foreign",
50
        "bpf-socket-bind",
51
        "bpf-restrict-network-interfaces",
52
};
53

54
static const char * const sender = "org.freedesktop.systemd1";
55
static const char * const path = "/org/freedesktop/systemd1";
56
static const char * const interface = "org.freedesktop.systemd1.Manager";
57

58
const struct systemd_property_and_type systemd_property_table[] = {
59
        { "AllowedCPUs", SD_BUS_TYPE_ARRAY, SD_BUS_TYPE_BYTE },
60
        { "CPUAccounting", SD_BUS_TYPE_BOOLEAN, _SD_BUS_TYPE_INVALID },
61
        { "CPUQuotaPeriodUSec", SD_BUS_TYPE_UINT64, _SD_BUS_TYPE_INVALID },
62
        { "CPUQuotaPerSecUSec", SD_BUS_TYPE_UINT64, _SD_BUS_TYPE_INVALID },
63
        { "CPUWeight", SD_BUS_TYPE_UINT64, _SD_BUS_TYPE_INVALID },
64
        { "DefaultMemoryLow", SD_BUS_TYPE_UINT64, _SD_BUS_TYPE_INVALID },
65
        { "DefaultMemoryLowScale", SD_BUS_TYPE_UINT64, _SD_BUS_TYPE_INVALID },
66
        { "DefaultMemoryMin", SD_BUS_TYPE_UINT64, _SD_BUS_TYPE_INVALID },
67
        { "DefaultMemoryMinScale", SD_BUS_TYPE_UINT64, _SD_BUS_TYPE_INVALID },
68
        { "DefaultStartupMemoryLow", SD_BUS_TYPE_UINT64, _SD_BUS_TYPE_INVALID },
69
        { "IOAccounting", SD_BUS_TYPE_BOOLEAN, _SD_BUS_TYPE_INVALID },
70
        { "IOWeight", SD_BUS_TYPE_UINT64, _SD_BUS_TYPE_INVALID },
71
        { "MemoryAccounting", SD_BUS_TYPE_BOOLEAN, _SD_BUS_TYPE_INVALID },
72
        { "MemoryHigh", SD_BUS_TYPE_UINT64, _SD_BUS_TYPE_INVALID },
73
        { "MemoryHighScale", SD_BUS_TYPE_UINT64, _SD_BUS_TYPE_INVALID },
74
        { "MemoryLow", SD_BUS_TYPE_UINT64, _SD_BUS_TYPE_INVALID },
75
        { "MemoryLowScale", SD_BUS_TYPE_UINT64, _SD_BUS_TYPE_INVALID },
76
        { "MemoryMax", SD_BUS_TYPE_UINT64, _SD_BUS_TYPE_INVALID },
77
        { "MemoryMaxScale", SD_BUS_TYPE_UINT64, _SD_BUS_TYPE_INVALID },
78
        { "MemoryMin", SD_BUS_TYPE_UINT64, _SD_BUS_TYPE_INVALID },
79
        { "MemoryMinScale", SD_BUS_TYPE_UINT64, _SD_BUS_TYPE_INVALID },
80
        { "MemorySwapMax", SD_BUS_TYPE_UINT64, _SD_BUS_TYPE_INVALID },
81
        { "MemorySwapMaxScale", SD_BUS_TYPE_UINT64, _SD_BUS_TYPE_INVALID },
82
        { "MemoryZSwapMax", SD_BUS_TYPE_UINT64, _SD_BUS_TYPE_INVALID },
83
        { "MemoryZSwapMaxScale", SD_BUS_TYPE_UINT64, _SD_BUS_TYPE_INVALID },
84
        { "MemoryZSwapWriteback", SD_BUS_TYPE_BOOLEAN, _SD_BUS_TYPE_INVALID },
85
        { "StartupAllowedCPUs", SD_BUS_TYPE_ARRAY, SD_BUS_TYPE_BYTE },
86
        { "StartupIOWeight", SD_BUS_TYPE_UINT64, _SD_BUS_TYPE_INVALID },
87
        { "StartupMemoryLow", SD_BUS_TYPE_UINT64, _SD_BUS_TYPE_INVALID },
88
        { "StartupMemoryHigh", SD_BUS_TYPE_UINT64, _SD_BUS_TYPE_INVALID },
89
        { "StartupMemoryMax", SD_BUS_TYPE_UINT64, _SD_BUS_TYPE_INVALID },
90
        { "StartupMemorySwapMax", SD_BUS_TYPE_UINT64, _SD_BUS_TYPE_INVALID },
91
        { "StartupMemoryZSwapMax", SD_BUS_TYPE_UINT64, _SD_BUS_TYPE_INVALID },
92
        { "TasksAccounting", SD_BUS_TYPE_BOOLEAN, _SD_BUS_TYPE_INVALID },
93
        { "TasksMax", SD_BUS_TYPE_UINT64, _SD_BUS_TYPE_INVALID },
94
        { "TasksMaxScale", SD_BUS_TYPE_UINT64, _SD_BUS_TYPE_INVALID },
95
};
96
const int systemd_property_table_sz = ARRAY_SIZE(systemd_property_table);
97

98
int cgroup_set_default_scope_opts(struct cgroup_systemd_scope_opts * const opts)
37✔
99
{
100
        if (!opts)
37✔
UNCOV
101
                return ECGINVAL;
×
102

103
        opts->delegated = 1;
37✔
104
        opts->mode = CGROUP_SYSTEMD_MODE_FAIL;
37✔
105
        opts->pid = -1;
37✔
106

107
        return 0;
37✔
108
}
109

110
/*
111
 * Returns time elapsed in usec
112
 *
113
 * Inspired-by: https://github.com/cockpit-project/cockpit/blob/main/src/tls/socket-io.c#L39
114
 */
115
static int64_t elapsed_time(const struct timespec * const start, const struct timespec * const end)
1,984✔
116
{
117
        int64_t elapsed = (end->tv_sec - start->tv_sec) * 1000000 +
1,984✔
118
                          (end->tv_nsec - start->tv_nsec) / 1000;
1,984✔
119

120
        assert(elapsed >= 0);
1,984✔
121

122
        return elapsed;
1,984✔
123
}
124

125
static int job_removed_callback(sd_bus_message *message, void *user_data, sd_bus_error *error)
19✔
126
{
127
        const char *result, *msg_path, *scope_name;
128
        const char **job_path = user_data;
19✔
129
        int ret;
130

131
        ret = sd_bus_message_read(message, "uoss", NULL, &msg_path, &scope_name, &result);
19✔
132
        if (ret < 0) {
19✔
UNCOV
133
                cgroup_err("callback message read failed: %d\n", errno);
×
UNCOV
134
                return 0;
×
135
        }
136

137
        if (*job_path == NULL || strcmp(msg_path, *job_path) != 0) {
19✔
138
                cgroup_dbg("Received a systemd signal, but it was not our message\n");
2✔
139
                return 0;
2✔
140
        }
141

142
        cgroup_dbg("Received JobRemoved signal for scope %s.  Result: %s\n", scope_name, result);
17✔
143

144
        /*
145
         * Use the job_path pointer as a way to inform the original thread that the job has
146
         * completed.
147
         */
148
        *job_path = NULL;
17✔
149
        return 0;
17✔
150
}
151

152
static int validate_scope_slice_name(const char * const scope_name, const char * const slice_name)
29✔
153
{
154
        char *_scope_name = NULL;
29✔
155
        int i, len, ret = 0;
29✔
156

157
        /* get the scope name without the suffix, min length is <n>.scope */
158
        len = strlen(scope_name) - 6;
29✔
159
        if (len < 1)
29✔
160
                cgroup_warn("Invalid scope name %s\n", scope_name);
2✔
161
        else if (strcmp(&scope_name[len], ".scope") != 0)
27✔
162
                cgroup_warn("scope doesn't have expected suffix\n");
2✔
163

164
        /* get the slice name without the suffix, min length is <n>.slice */
165
        len = strlen(slice_name) - 6;
29✔
166
        if (len < 1)
29✔
167
                cgroup_warn("Invalid slice name %s\n", slice_name);
2✔
168
        else if (strcmp(&slice_name[len], ".slice") != 0)
27✔
169
                cgroup_warn("slice doesn't have expected suffix\n");
2✔
170

171
        /*
172
         * systemd will silently prefix a '_' to the scope name and
173
         * create, and delegate it under the slice. If it matches with any
174
         * of the controller in the controller_name[]. i.e.,
175
         * oracle.slice/cpuset.scope, will be created as
176
         * oracle.slice/_cpuset.scope
177
         *
178
         * Disallow such scope names, that will cause confusion to the
179
         * users, where they might try to operate scope cgroup, but
180
         * the delegated scope is _scope cgroup.
181
         */
182
        _scope_name = strdup(scope_name);
29✔
183
        if (_scope_name == NULL) {
29✔
UNCOV
184
                cgroup_err("Failed to allocate memory for _scope_name\n");
×
UNCOV
185
                last_errno = errno;
×
UNCOV
186
                ret = 1;
×
UNCOV
187
                goto out;
×
188
        }
189

190
        len = strlen(_scope_name) - 6;        /* strlen(".scope") + '\0' */
29✔
191
        _scope_name[len] = '\0';
29✔
192

193
        for (i = 0; i < ARRAY_SIZE(controller_name); i++) {
380✔
194
                if (strcmp(_scope_name, controller_name[i]))
353✔
195
                        continue;
351✔
196

197
                cgroup_err("Invalid scope name, using controller name %s\n", controller_name[i]);
2✔
198
                ret = 1;
2✔
199
                break;
2✔
200
        }
201

202
        free(_scope_name);
29✔
203
out:
29✔
204
        return ret;
29✔
205
}
206

207
int cgroup_create_scope(const char * const scope_name, const char * const slice_name,
29✔
208
                        const struct cgroup_systemd_scope_opts * const opts)
209
{
210
        sd_bus_message *msg = NULL, *reply = NULL;
29✔
211
        int ret = 0, sdret = 0, cgret = ECGFAIL;
29✔
212
        sd_bus_error error = SD_BUS_ERROR_NULL;
29✔
213
        const char *job_path = NULL;
29✔
214
        struct timespec start, now;
215
        sd_bus *bus = NULL;
29✔
216
        pid_t child_pid;
217

218
        if (!scope_name || !slice_name || !opts)
29✔
UNCOV
219
                return ECGINVAL;
×
220

221
        if (validate_scope_slice_name(scope_name, slice_name))
29✔
222
                return ECGINVAL;
2✔
223

224
        if (opts->mode >= CGROUP_SYSTEMD_MODE_CNT) {
27✔
UNCOV
225
                cgroup_err("invalid systemd mode: %d\n", opts->mode);
×
UNCOV
226
                return ECGINVAL;
×
227
        }
228

229
        if (opts->mode == CGROUP_SYSTEMD_MODE_ISOLATE ||
27✔
230
            opts->mode == CGROUP_SYSTEMD_MODE_IGNORE_DEPS ||
27✔
231
            opts->mode == CGROUP_SYSTEMD_MODE_IGNORE_REQS) {
27✔
UNCOV
232
                cgroup_err("unsupported systemd mode: %d\n", opts->mode);
×
UNCOV
233
                return ECGINVAL;
×
234
        }
235

236
        if (opts->pid < 0) {
27✔
237
                child_pid = fork();
14✔
238
                if (child_pid < 0) {
28✔
UNCOV
239
                        last_errno = errno;
×
UNCOV
240
                        cgroup_err("fork failed: %d\n", errno);
×
UNCOV
241
                        return ECGOTHER;
×
242
                }
243

244
                if (child_pid == 0) {
28✔
245
                        static char * const args[] = {"libcgroup_systemd_idle_thread", NULL};
246

247
                        /*
248
                         * Have the child sleep forever.  Systemd will delete the scope if
249
                         * there isn't a running process in it.
250
                         */
251
                        execvp("libcgroup_systemd_idle_thread", args);
14✔
252

253
                        /* The child process should never get here */
254
                        last_errno = errno;
14✔
255
                        cgroup_err("failed to create system idle thread.\n");
14✔
UNCOV
256
                        return ECGOTHER;
×
257
                }
258

259
                cgroup_dbg("created libcgroup_system_idle thread pid %d\n", child_pid);
14✔
260
        } else {
261
                child_pid = opts->pid;
13✔
262
        }
263
        cgroup_dbg("pid %d will be placed in scope %s\n", child_pid, scope_name);
27✔
264

265
        sdret = sd_bus_default_system(&bus);
27✔
266
        if (sdret < 0) {
27✔
UNCOV
267
                cgroup_err("failed to open the system bus: %d\n", errno);
×
UNCOV
268
                goto out;
×
269
        }
270

271
        sdret = sd_bus_match_signal(bus, NULL, sender, path, interface,
27✔
272
                                    "JobRemoved", job_removed_callback, &job_path);
273
        if (sdret < 0) {
27✔
UNCOV
274
                cgroup_err("failed to install match callback: %d\n", errno);
×
UNCOV
275
                goto out;
×
276
        }
277

278
        sdret = sd_bus_message_new_method_call(bus, &msg, sender, path, interface,
27✔
279
                                               "StartTransientUnit");
280
        if (sdret < 0) {
27✔
UNCOV
281
                cgroup_err("failed to create the systemd msg: %d\n", errno);
×
UNCOV
282
                goto out;
×
283
        }
284

285
        sdret = sd_bus_message_append(msg, "ss", scope_name, modes[opts->mode]);
27✔
286
        if (sdret < 0) {
27✔
UNCOV
287
                cgroup_err("failed to append the scope name: %d\n", errno);
×
UNCOV
288
                goto out;
×
289
        }
290

291
        sdret = sd_bus_message_open_container(msg, 'a', "(sv)");
27✔
292
        if (sdret < 0) {
27✔
UNCOV
293
                cgroup_err("failed to open container: %d\n", errno);
×
UNCOV
294
                goto out;
×
295
        }
296

297
        sdret = sd_bus_message_append(msg, "(sv)", "Description", "s",
27✔
298
                                      "scope created by libcgroup");
299
        if (sdret < 0) {
27✔
UNCOV
300
                cgroup_err("failed to append the description: %d\n", errno);
×
UNCOV
301
                goto out;
×
302
        }
303

304
        sdret = sd_bus_message_append(msg, "(sv)", "PIDs", "au", 1, child_pid);
27✔
305
        if (sdret < 0) {
27✔
UNCOV
306
                cgroup_err("failed to append the PID: %d\n", errno);
×
UNCOV
307
                goto out;
×
308
        }
309

310
        sdret = sd_bus_message_append(msg, "(sv)", "Slice", "s", slice_name);
27✔
311
        if (sdret < 0) {
27✔
UNCOV
312
                cgroup_err("failed to append the slice: %d\n", errno);
×
UNCOV
313
                goto out;
×
314
        }
315

316
        if (opts->delegated == 1) {
27✔
317
                sdret = sd_bus_message_append(msg, "(sv)", "Delegate", "b", 1);
27✔
318
                if (sdret < 0) {
27✔
UNCOV
319
                        cgroup_err("failed to append delegate: %d\n", errno);
×
UNCOV
320
                        goto out;
×
321
                }
322
        }
323

324
        sdret = sd_bus_message_close_container(msg);
27✔
325
        if (sdret < 0) {
27✔
UNCOV
326
                cgroup_err("failed to close the container: %d\n", errno);
×
UNCOV
327
                goto out;
×
328
        }
329

330
        sdret = sd_bus_message_append(msg, "a(sa(sv))", 0);
27✔
331
        if (sdret < 0) {
27✔
UNCOV
332
                cgroup_err("failed to append aux structure: %d\n", errno);
×
UNCOV
333
                goto out;
×
334
        }
335

336
        sdret = sd_bus_call(bus, msg, 0, &error, &reply);
27✔
337
        if (sdret < 0) {
27✔
338
                cgroup_err("sd_bus_call() failed: %d\n",
10✔
339
                           sd_bus_message_get_errno(msg));
340
                cgroup_err("error message: %s\n", error.message);
10✔
341
                goto out;
10✔
342
        }
343

344
        /* Receive the job_path from systemd */
345
        sdret = sd_bus_message_read(reply, "o", &job_path);
17✔
346
        if (sdret < 0) {
17✔
UNCOV
347
                cgroup_err("failed to read reply: %d\n", errno);
×
UNCOV
348
                goto out;
×
349
        }
350

351
        cgroup_dbg("job_path = %s\n", job_path);
17✔
352

353
        ret = clock_gettime(CLOCK_MONOTONIC, &start);
17✔
354
        if (ret < 0) {
17✔
UNCOV
355
                last_errno = errno;
×
UNCOV
356
                cgroup_err("Failed to get time: %d\n", errno);
×
UNCOV
357
                cgret = ECGOTHER;
×
UNCOV
358
                goto out;
×
359
        }
360

361
        /* The callback will null out the job_path pointer on completion */
362
        while (job_path) {
2,001✔
363
                sdret = sd_bus_process(bus, NULL);
1,984✔
364
                if (sdret < 0) {
1,984✔
UNCOV
365
                        cgroup_err("failed to process the sd bus: %d\n", errno);
×
UNCOV
366
                        goto out;
×
367
                }
368

369
                if (sdret == 0) {
1,984✔
370
                        /*
371
                         * Per the sd_bus_wait() man page, call this function after sd_bus_process
372
                         * returns zero. The wait time (usec) was somewhat arbitrarily chosen
373
                         */
374
                        sdret = sd_bus_wait(bus, 10);
1,948✔
375
                        if (sdret < 0) {
1,948✔
UNCOV
376
                                cgroup_err("failed to wait for sd bus: %d\n", errno);
×
UNCOV
377
                                goto out;
×
378
                        }
379
                }
380

381
                ret = clock_gettime(CLOCK_MONOTONIC, &now);
1,984✔
382
                if (ret < 0) {
1,984✔
UNCOV
383
                        last_errno = errno;
×
UNCOV
384
                        cgroup_err("Failed to get time: %d\n", errno);
×
UNCOV
385
                        cgret = ECGOTHER;
×
UNCOV
386
                        goto out;
×
387
                }
388

389
                if (elapsed_time(&start, &now) > USEC_PER_SEC) {
1,984✔
UNCOV
390
                        cgroup_err("The create scope command timed out\n");
×
UNCOV
391
                        goto out;
×
392
                }
393
        }
394

395
        cgret = 0;
17✔
396

397
out:
27✔
398
        if (cgret && opts->pid < 0)
27✔
399
                kill(child_pid, SIGTERM);
8✔
400

401
        sd_bus_error_free(&error);
27✔
402
        sd_bus_message_unref(msg);
27✔
403
        sd_bus_message_unref(reply);
27✔
404
        sd_bus_unref(bus);
27✔
405

406
        return cgret;
27✔
407
}
408

409
int cgroup_create_scope2(struct cgroup *cgroup, int ignore_ownership,
21✔
410
                         const struct cgroup_systemd_scope_opts * const opts)
411
{
412
        char *copy1 = NULL, *copy2 = NULL, *slash, *slice_name, *scope_name;
21✔
413
        int ret = 0;
21✔
414

415
        if (!cgroup)
21✔
UNCOV
416
                return ECGROUPNOTALLOWED;
×
417

418
        slash = strstr(cgroup->name, "/");
21✔
419
        if (!slash) {
21✔
420
                cgroup_err("cgroup name does not contain a slash: %s\n", cgroup->name);
1✔
421
                return ECGINVAL;
1✔
422
        }
423

424
        slash = strstr(slash + 1, "/");
20✔
425
        if (slash) {
20✔
426
                cgroup_err("cgroup name contains more than one slash: %s\n", cgroup->name);
1✔
427
                return ECGINVAL;
1✔
428
        }
429

430
        copy1 = strdup(cgroup->name);
19✔
431
        if (!copy1) {
19✔
UNCOV
432
                last_errno = errno;
×
UNCOV
433
                ret = ECGOTHER;
×
UNCOV
434
                goto err;
×
435
        }
436

437
        scope_name = basename(copy1);
19✔
438

439
        copy2 = strdup(cgroup->name);
19✔
440
        if (!copy2) {
19✔
UNCOV
441
                last_errno = errno;
×
UNCOV
442
                ret = ECGOTHER;
×
UNCOV
443
                goto err;
×
444
        }
445

446
        slice_name = dirname(copy2);
19✔
447

448
        ret = cgroup_create_scope(scope_name, slice_name, opts);
19✔
449
        if (ret)
19✔
450
                goto err;
11✔
451

452
        /*
453
         * Utilize cgroup_create_cgroup() to assign the requested owner/group and permissions.
454
         * cgroup_create_cgroup() can gracefully handle EEXIST if the cgroup already exists, so
455
         * we can reuse its ownership logic without penalty.
456
         */
457
        ret = cgroup_create_cgroup(cgroup, ignore_ownership);
8✔
458

459
err:
19✔
460
        if (copy1)
19✔
461
                free(copy1);
19✔
462
        if (copy2)
19✔
463
                free(copy2);
19✔
464

465
        return ret;
19✔
466
}
467

468
bool cgroup_is_systemd_enabled(void)
17✔
469
{
470
        return true;
17✔
471
}
472

NEW
473
static int append_byte_array(sd_bus_message * const msg, const char * const setting,
×
474
                             const struct cgroup_systemd_value * const value)
475
{
476
        int sdret;
477

NEW
478
        sdret = sd_bus_message_open_container(msg, SD_BUS_TYPE_STRUCT, "sv");
×
NEW
479
        if (sdret < 0) {
×
NEW
480
                cgroup_err("failed to open sv container: %d\n", errno);
×
NEW
481
                goto out;
×
482
        }
483

NEW
484
        sdret = sd_bus_message_append(msg, "s", setting);
×
NEW
485
        if (sdret < 0) {
×
NEW
486
                cgroup_err("failed to append the setting, %s: %d\n", setting, errno);
×
NEW
487
                goto out;
×
488
        }
489

NEW
490
        sdret = sd_bus_message_open_container(msg, 'v', "ay");
×
NEW
491
        if (sdret < 0) {
×
NEW
492
                cgroup_err("failed to open byte array container: %d\n", errno);
×
NEW
493
                goto out;
×
494
        }
495

NEW
496
        sdret = sd_bus_message_append_array(msg, 'y', value->byte_array, value->array_len);
×
NEW
497
        if (sdret < 0) {
×
NEW
498
                cgroup_err("failed to append byte array: %d\n", errno);
×
NEW
499
                goto out;
×
500
        }
501

NEW
502
        sdret = sd_bus_message_close_container(msg);
×
NEW
503
        if (sdret < 0) {
×
NEW
504
                cgroup_err("failed to close the byte array container: %d\n", errno);
×
NEW
505
                goto out;
×
506
        }
507

NEW
508
        sdret = sd_bus_message_close_container(msg);
×
NEW
509
        if (sdret < 0) {
×
NEW
510
                cgroup_err("failed to close the sv container: %d\n", errno);
×
NEW
511
                goto out;
×
512
        }
513

NEW
514
out:
×
NEW
515
        return sdret;
×
516
}
517

NEW
518
int cgroup_set_property(const char * const cgrp, const char * const setting,
×
519
                        const struct cgroup_systemd_value * const value,
520
                        const struct cgroup_systemd_property_opts * const opts)
521
{
NEW
522
        sd_bus_message *msg = NULL, *reply = NULL;
×
NEW
523
        sd_bus_error error = SD_BUS_ERROR_NULL;
×
NEW
524
        int sdret = 0, cgret = ECGFAIL;
×
NEW
525
        sd_bus *bus = NULL;
×
526
        char t[2];
527

NEW
528
        if (!cgrp || !setting || !value || !opts)
×
NEW
529
                return ECGINVAL;
×
530

NEW
531
        sdret = sd_bus_default_system(&bus);
×
NEW
532
        if (sdret < 0) {
×
NEW
533
                cgroup_err("failed to open the system bus: %d\n", errno);
×
NEW
534
                goto out;
×
535
        }
536

NEW
537
        sdret = sd_bus_message_new_method_call(bus, &msg, sender, path, interface,
×
538
                                               "SetUnitProperties");
NEW
539
        if (sdret < 0) {
×
NEW
540
                cgroup_err("failed to create the systemd msg: %d\n", errno);
×
NEW
541
                goto out;
×
542
        }
543

NEW
544
        sdret = sd_bus_message_append(msg, "s", cgrp);
×
NEW
545
        if (sdret < 0) {
×
NEW
546
                cgroup_err("failed to append the cgroup name: %d\n", errno);
×
NEW
547
                goto out;
×
548
        }
549

NEW
550
        sdret = sd_bus_message_append(msg, "b", opts->runtime);
×
NEW
551
        if (sdret < 0) {
×
NEW
552
                cgroup_err("failed to append the runtime value: %d\n", errno);
×
NEW
553
                goto out;
×
554
        }
555

NEW
556
        sdret = sd_bus_message_open_container(msg, 'a', "(sv)");
×
NEW
557
        if (sdret < 0) {
×
NEW
558
                cgroup_err("failed to open container: %d\n", errno);
×
NEW
559
                goto out;
×
560
        }
561

NEW
562
        t[0] = value->type;
×
NEW
563
        t[1] = '\0';
×
564

NEW
565
        switch (value->type) {
×
NEW
566
        case SD_BUS_TYPE_BYTE:
×
NEW
567
                sdret = sd_bus_message_append(msg, "(sv)", setting, t, value->byte_value);
×
NEW
568
                break;
×
NEW
569
        case SD_BUS_TYPE_ARRAY:
×
NEW
570
                switch (value->array_type) {
×
NEW
571
                        case SD_BUS_TYPE_BYTE:
×
NEW
572
                                sdret = append_byte_array(msg, setting, value);
×
NEW
573
                                break;
×
NEW
574
                        default:
×
NEW
575
                                cgroup_err("unsupported d-bus array type: %d\n",
×
576
                                           value->array_type);
NEW
577
                                break;
×
578
                }
NEW
579
                break;
×
NEW
580
        case SD_BUS_TYPE_BOOLEAN:
×
NEW
581
                sdret = sd_bus_message_append(msg, "(sv)", setting, t, value->bool_value);
×
NEW
582
                break;
×
NEW
583
        case SD_BUS_TYPE_STRING:
×
NEW
584
                sdret = sd_bus_message_append(msg, "(sv)", setting, t, value->str_value);
×
NEW
585
                break;
×
NEW
586
        case SD_BUS_TYPE_INT32:
×
NEW
587
                sdret = sd_bus_message_append(msg, "(sv)", setting, t, value->int_value);
×
NEW
588
                break;
×
NEW
589
        case SD_BUS_TYPE_UINT32:
×
NEW
590
                sdret = sd_bus_message_append(msg, "(sv)", setting, t, value->uint_value);
×
NEW
591
                break;
×
NEW
592
        case SD_BUS_TYPE_INT64:
×
NEW
593
                sdret = sd_bus_message_append(msg, "(sv)", setting, t, value->ll_value);
×
NEW
594
                break;
×
NEW
595
        case SD_BUS_TYPE_UINT64:
×
NEW
596
                sdret = sd_bus_message_append(msg, "(sv)", setting, t, value->ull_value);
×
NEW
597
                break;
×
NEW
598
        case _SD_BUS_TYPE_INVALID:
×
NEW
599
                cgroup_err("Invalid systemd type\n");
×
NEW
600
                sdret = -1;
×
NEW
601
                break;
×
602
        }
NEW
603
        if (sdret < 0) {
×
NEW
604
                cgroup_err("failed to append the description: %d\n", errno);
×
NEW
605
                goto out;
×
606
        }
607

NEW
608
        sdret = sd_bus_message_close_container(msg);
×
NEW
609
        if (sdret < 0) {
×
NEW
610
                cgroup_err("failed to close the container: %d\n", errno);
×
NEW
611
                goto out;
×
612
        }
613

NEW
614
        sdret = sd_bus_call(bus, msg, 0, &error, &reply);
×
NEW
615
        if (sdret < 0) {
×
NEW
616
                cgroup_err("sd_bus_call() failed: %d\n",
×
617
                           sd_bus_message_get_errno(msg));
NEW
618
                cgroup_err("error message: %s\n", error.message);
×
NEW
619
                goto out;
×
620
        }
621

NEW
622
        cgret = 0;
×
623

NEW
624
out:
×
NEW
625
        sd_bus_error_free(&error);
×
NEW
626
        sd_bus_message_unref(msg);
×
NEW
627
        sd_bus_message_unref(reply);
×
NEW
628
        sd_bus_unref(bus);
×
629

NEW
630
        return cgret;
×
631
}
632

NEW
633
static int insert_cpu_into_byte_array(unsigned int cpu, unsigned char **array,
×
634
                                      int * const array_len)
635
{
636
        unsigned int byte_num;
637
        void *tmp;
638
        int i;
639

NEW
640
        byte_num = cpu / 8;
×
641

NEW
642
        if (byte_num >= (*array_len)) {
×
NEW
643
                tmp = realloc((*array), sizeof(unsigned char) * (byte_num + 1));
×
NEW
644
                if (tmp == NULL)
×
NEW
645
                        return ECGOTHER;
×
646

NEW
647
                *array = tmp;
×
648

NEW
649
                for (i = (*array_len); i < byte_num + 1; i++) {
×
650
                        /* zero out the newly added memory */
NEW
651
                        (*array)[i] = 0;
×
652
                }
653

NEW
654
                *array_len = byte_num + 1;
×
655
        }
656

NEW
657
        (*array)[byte_num] |= 1u << (cpu % 8);
×
658

NEW
659
        return 0;
×
660
}
661

NEW
662
int cgroup_systemd_cpuset_str_to_byte_array(char * const in_str, unsigned char **byte_array,
×
663
                                            int * const array_len)
664
{
NEW
665
        char *comma_saveptr = NULL, *hyphen_saveptr = NULL;
×
NEW
666
        char *comma_token = NULL, *hyphen_token = NULL;
×
667
        unsigned char *tmp_array;
668
        unsigned int cpu;
669
        int start, end;
670
        int ret, i;
671

NEW
672
        if (!in_str || !byte_array || !array_len)
×
NEW
673
                return ECGINVAL;
×
674

NEW
675
        *array_len = 0;
×
NEW
676
        tmp_array = NULL;
×
677

NEW
678
        comma_token = strtok_r(in_str, ",", &comma_saveptr);
×
679

680
        do {
NEW
681
                if (strstr(comma_token, "-") != NULL) {
×
NEW
682
                        hyphen_token = strtok_r(comma_token, "-", &hyphen_saveptr);
×
NEW
683
                        start = atoi(hyphen_token);
×
684

NEW
685
                        hyphen_token = strtok_r(NULL, "-", &hyphen_saveptr);
×
NEW
686
                        end = atoi(hyphen_token);
×
687

NEW
688
                        for (i = start; i <= end; i++) {
×
NEW
689
                                ret = insert_cpu_into_byte_array(i, &tmp_array, array_len);
×
NEW
690
                                if (ret)
×
NEW
691
                                        return ret;
×
692
                        }
693
                } else {
694
                        /* a single cpu was provided */
NEW
695
                        cpu = atoi(comma_token);
×
696

NEW
697
                        ret = insert_cpu_into_byte_array(cpu, &tmp_array, array_len);
×
NEW
698
                        if (ret)
×
NEW
699
                                return ret;
×
700
                }
NEW
701
        } while ((comma_token = strtok_r(NULL, ",", &comma_saveptr)));
×
702

NEW
703
        *byte_array = tmp_array;
×
704

NEW
705
        return 0;
×
706
}
707
#else
708
int cgroup_set_default_scope_opts(struct cgroup_systemd_scope_opts * const opts)
×
709
{
710
        cgroup_err("Systemd support not compiled\n");
×
711
        return 1;
×
712
}
713

714
int cgroup_create_scope(const char * const scope_name, const char * const slice_name,
×
715
                        const struct cgroup_systemd_scope_opts * const opts)
716
{
717
        cgroup_err("Systemd support not compiled\n");
×
718
        return 1;
×
719
}
720

721
int cgroup_create_scope2(struct cgroup *cgroup, int ignore_ownership,
×
722
                         const struct cgroup_systemd_scope_opts * const opts)
723
{
724
        cgroup_err("Systemd support not compiled\n");
×
725
        return 1;
×
726
}
727

728
bool cgroup_is_systemd_enabled(void)
×
729
{
730
        return false;
×
731
}
732

NEW
733
int cgroup_set_property(const char * const cgrp, const char * const setting,
×
734
                        const struct cgroup_systemd_value * const value,
735
                        const struct cgroup_systemd_property_opts * const opts)
736
{
NEW
737
        cgroup_err("Systemd support not compiled\n");
×
NEW
738
        return 1;
×
739
}
740

NEW
741
int cgroup_systemd_cpuset_str_to_byte_array(char * const in_str, unsigned char **byte_array,
×
742
                                            int * const array_len)
743
{
NEW
744
        return ECGROUPUNSUPP;
×
745
}
746
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc