• 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

43.55
/src/tools/cgclassify.c
1
// SPDX-License-Identifier: LGPL-2.1-only
2
/**
3
 * Copyright RedHat Inc. 2008
4
 *
5
 * Authors:        Vivek Goyal <vgoyal@redhat.com>
6
 *
7
 * Replace systemd idle_thread enhancements by Kamalesh Babulal
8
 * Copyright (c) 2023 Oracle and/or its affiliates.
9
 * Author: Kamalesh Babulal <kamalesh.babulal@oracle.com>
10
 */
11

12
#include "tools-common.h"
13

14
#include <libcgroup.h>
15
#include <libcgroup-internal.h>
16

17
#include <stdlib.h>
18
#include <string.h>
19
#include <limits.h>
20
#include <unistd.h>
21
#include <getopt.h>
22
#include <signal.h>
23
#include <errno.h>
24
#include <stdio.h>
25
#include <pwd.h>
26

27
#include <sys/mount.h>
28
#include <sys/types.h>
29
#include <sys/stat.h>
30

31

32
#define TEMP_BUF        81
33

34
#define SYSTEMD_IDLE_THREAD        "libcgroup_systemd_idle_thread"
35

36
static pid_t find_scope_pid(pid_t pid, int capture);
37
static int write_systemd_unified(const char * const cgrp_name, pid_t pid);
38
static int is_scope_parsed(const char * const path);
39
static int rollback_pid_cgroups(pid_t pid);
40

41
struct cgroup_info {
42
        char ctrl_name[CONTROL_NAMELEN_MAX];
43
        char cgrp_path[FILENAME_MAX];
44
} info[MAX_MNT_ELEMENTS + 1];
45

46
static void usage(int status, const char *program_name)
×
47
{
48
        if (status != 0) {
×
49
                err("Wrong input parameters, try %s '-h' for more information.\n", program_name);
×
50
                return;
×
51
        }
52

53
        info("Usage: %s [[-g] <controllers>:<path>] ", program_name);
×
54
        info("[--sticky | --cancel-sticky] <list of pids>\n");
×
55
        info("Move running task(s) to given cgroups\n");
×
56
        info("  -h, --help                        Display this help\n");
×
57
        info("  -g <controllers>:<path>        Control group to be used as target\n");
×
58
        info("  --cancel-sticky                cgred daemon change pidlist and children tasks\n");
×
59
        info("  --sticky                        cgred daemon does not change ");
×
60
        info("pidlist and children tasks\n");
×
61
#ifdef WITH_SYSTEMD
UNCOV
62
        info("  -b                                Ignore default systemd delegate hierarchy\n");
×
UNCOV
63
        info("  -r                                Replace the default idle_thread spawned ");
×
UNCOV
64
        info("for the systemd scope\n");
×
65
#endif
66
}
67

68
/*
69
 * Change process group as specified on command line.
70
 */
71
static int change_group_path(pid_t pid, struct cgroup_group_spec *cgrp_list[])
38✔
72
{
73
        int ret = 0;
38✔
74
        int i;
75

76
        for (i = 0; i < CG_HIER_MAX; i++) {
72✔
77
                if (!cgrp_list[i])
72✔
78
                        break;
34✔
79

80
                ret = cgroup_change_cgroup_path(cgrp_list[i]->path, pid,
38✔
81
                                                (const char *const*) cgrp_list[i]->controllers);
38✔
82
                if (ret) {
38✔
83
                        err("Error changing group of pid %d: %s\n", pid, cgroup_strerror(ret));
4✔
84
                        return -1;
4✔
85
                }
86
        }
87

88
        return 0;
34✔
89
}
90

91
/*
92
 * Change process group as specified in cgrules.conf.
93
 */
94
static int change_group_based_on_rule(pid_t pid)
×
95
{
96
        char *procname = NULL;
×
97
        int ret = -1;
×
98
        uid_t euid;
99
        gid_t egid;
100

101
        /* Put pid into right cgroup as per rules in /etc/cgrules.conf */
102
        if (cgroup_get_uid_gid_from_procfs(pid, &euid, &egid)) {
×
103
                err("Error in determining euid/egid of pid %d\n", pid);
×
104
                goto out;
×
105
        }
106

107
        ret = cgroup_get_procname_from_procfs(pid, &procname);
×
108
        if (ret) {
×
109
                err("Error in determining process name of pid %d\n", pid);
×
110
                goto out;
×
111
        }
112

113
        /* Change the cgroup by determining the rules */
114
        ret = cgroup_change_cgroup_flags(euid, egid, procname, pid, 0);
×
115
        if (ret) {
×
116
                err("Error: change of cgroup failed for pid %d: %s\n", pid, cgroup_strerror(ret));
×
117
                goto out;
×
118
        }
119
        ret = 0;
×
120

121
out:
×
122
        if (procname)
×
123
                free(procname);
×
124

125
        return ret;
×
126
}
127

128
static struct option longopts[] = {
129
        {"sticky",                no_argument, NULL, 's'},
130
        {"cancel-sticky",        no_argument, NULL, 'u'},
131
        {"help",                no_argument, NULL, 'h'},
132
        {0, 0, 0, 0}
133
};
134

135
int main(int argc, char *argv[])
19✔
136
{
137
        struct cgroup_group_spec *cgrp_list[CG_HIER_MAX];
138
#ifdef WITH_SYSTEMD
139
        int ignore_default_systemd_delegate_slice = 0;
19✔
140
#endif
141
        int ret = 0, i, exit_code = 0;
19✔
142
        int skip_replace_idle = 0;
19✔
143
        int cgrp_specified = 0;
19✔
144
        pid_t scope_pid = -1;
19✔
145
        int replace_idle = 0;
19✔
146
        int flag = 0;
19✔
147
        char *endptr;
148
        pid_t pid;
149
        int c;
150

151
        if (argc < 2) {
19✔
152
                usage(1, argv[0]);
×
153
                exit(EXIT_BADARGS);
×
154
        }
155

156
        memset(cgrp_list, 0, sizeof(cgrp_list));
19✔
157
#ifdef WITH_SYSTEMD
158
        while ((c = getopt_long(argc, argv, "+g:shbr", longopts, NULL)) > 0) {
48✔
159
                switch (c) {
29✔
160
                case 'b':
6✔
161
                        ignore_default_systemd_delegate_slice = 1;
6✔
162
                        break;
6✔
163
                case 'r':
4✔
164
                        replace_idle = 1;
4✔
165
                        break;
4✔
166
#else
167
        while ((c = getopt_long(argc, argv, "+g:sh", longopts, NULL)) > 0) {
168
                switch (c) {
169
#endif
170
                case 'h':
×
171
                        usage(0, argv[0]);
×
172
                        exit(0);
×
173
                        break;
174
                case 'g':
19✔
175
                        ret = parse_cgroup_spec(cgrp_list, optarg, CG_HIER_MAX);
19✔
176
                        if (ret) {
19✔
177
                                err("cgroup controller and path parsing failed\n");
×
178
                                exit(EXIT_BADARGS);
×
179
                        }
180
                        cgrp_specified = 1;
19✔
181
                        break;
19✔
182
                case 's':
×
183
                        flag |= CGROUP_DAEMON_UNCHANGE_CHILDREN;
×
184
                        break;
×
185
                case 'u':
×
186
                        flag |= CGROUP_DAEMON_CANCEL_UNCHANGE_PROCESS;
×
187
                        break;
×
188
                default:
×
189
                        usage(1, argv[0]);
×
190
                        exit(EXIT_BADARGS);
×
191
                        break;
192
                }
193
        }
194

195
        /* Initialize libcg */
196
        ret = cgroup_init();
19✔
197
        if (ret) {
19✔
198
                err("%s: libcgroup initialization failed: %s\n", argv[0], cgroup_strerror(ret));
×
199
                return ret;
×
200
        }
201

202
#ifdef WITH_SYSTEMD
203
        if (!ignore_default_systemd_delegate_slice)
19✔
204
                cgroup_set_default_systemd_cgroup();
13✔
205
#endif
206

207
        for (i = optind; i < argc; i++) {
54✔
208
                pid = (pid_t) strtol(argv[i], &endptr, 10);
38✔
209
                if (endptr[0] != '\0') {
38✔
210
                        /* the input argument was not a number */
211
                        err("Error: %s is not valid pid.\n", argv[i]);
×
212
                        exit_code = 2;
×
213
                        continue;
×
214
                }
215

216
                if (flag)
38✔
217
                        ret = cgroup_register_unchanged_process(pid, flag);
×
218
                if (ret)
38✔
219
                        exit_code = 1;
×
220

221
                if (replace_idle && !skip_replace_idle) {
38✔
222
                        ret = find_scope_pid(pid, 1);
4✔
223
                        if (ret) {
4✔
224
                                err("Failed to read /proc/%u/cgroups\n", pid);
×
225
                                return 1;
×
226
                        }
227
                }
228

229
                if (cgrp_specified)
38✔
230
                        ret = change_group_path(pid, cgrp_list);
38✔
231
                else
232
                        ret = change_group_based_on_rule(pid);
×
233

234
                /* if any group change fails */
235
                if (ret)
38✔
236
                        exit_code = 1;
4✔
237

238
                /* skip replacing of idle_thread in systemd slice */
239
                if (!replace_idle)
38✔
240
                        continue;
34✔
241

242
                /* systemd idle_thread is already replaced */
243
                if (skip_replace_idle)
4✔
244
                        continue;
×
245

246
                scope_pid = find_scope_pid(pid, 0);
4✔
247
                if (scope_pid == -1)
4✔
248
                        goto err;
3✔
249

250
                skip_replace_idle = 1;
1✔
251

252
                ret = kill(scope_pid, SIGTERM);
1✔
253
                if (ret) {
1✔
254
                        err("Failed to kill pid %u:%s\n", scope_pid, strerror(errno));
×
255
                        goto err;
×
256
                }
257
        }
258

259
        return exit_code;
16✔
260

261
err:
3✔
262
        exit_code = rollback_pid_cgroups(pid);
3✔
263
        return exit_code;
3✔
264
}
265

266
static pid_t search_systemd_idle_thread_task(pid_t pids[], size_t size)
2✔
267
{
268
        char task_cmd[FILENAME_MAX];
269
        char buffer[FILENAME_MAX];
270
        FILE *pid_cmd_fp = NULL;
2✔
271
        int scope_pid = -1;
2✔
272
        int i;
273

274
        for (i = 0; i < size; i++) {
4✔
275
                snprintf(buffer, FILENAME_MAX, "/proc/%u/cmdline", pids[i]);
3✔
276
                pid_cmd_fp = fopen(buffer, "re");
3✔
277
                /* task might have exited */
278
                if (!pid_cmd_fp)
3✔
279
                        continue;
×
280

281
                /* task might have exited, so consider only successful reads. */
282
                if (fgets(task_cmd, FILENAME_MAX, pid_cmd_fp)) {
3✔
283
                        if (!strcmp(task_cmd, SYSTEMD_IDLE_THREAD)) {
3✔
284
                                scope_pid = pids[i];
1✔
285
                                fclose(pid_cmd_fp);
1✔
286
                                break;
1✔
287
                        }
288
                }
289
                fclose(pid_cmd_fp);
2✔
290
        }
291

292
        return scope_pid;
2✔
293
}
294

295
static pid_t find_scope_pid(pid_t pid, int capture)
8✔
296
{
297
        pid_t _scope_pid = -1, scope_pid = -1;
8✔
298
        char ctrl_name[CONTROL_NAMELEN_MAX];
299
        char scope_name[FILENAME_MAX];
300
        char cgrp_name[FILENAME_MAX];
301
        int found_systemd_cgrp = 0;
8✔
302
        int found_unified_cgrp = 0;
8✔
303
        char buffer[FILENAME_MAX];
304
        FILE *pid_proc_fp = NULL;
8✔
305
        char *_ctrl_name = NULL;
8✔
306
        int idx, ret, size = 0;
8✔
307
        pid_t *pids;
308
        int i = 0;
8✔
309

310
        /*
311
         * Let's parse the cgroup of the pid, to check if its in one or
312
         * more .scopes.
313
         */
314
        snprintf(buffer, FILENAME_MAX, "/proc/%u/cgroup", pid);
8✔
315
        pid_proc_fp = fopen(buffer, "re");
8✔
316
        if (!pid_proc_fp) {
8✔
317
                err("Failed to open: %s\n", buffer);
×
318
                return -1;
×
319
        }
320

321
        while (fgets(buffer, FILENAME_MAX, pid_proc_fp)) {
16✔
322
                memset(ctrl_name, '\0', sizeof(ctrl_name));
8✔
323

324
                /* check for overflow of controllers */
325
                if (i >= MAX_MNT_ELEMENTS) {
8✔
326
                        err("Found more than MAX_MNT_ELEMENTS controllers\n");
×
327
                        scope_pid = -1;
×
328
                        goto out;
×
329
                }
330

331
                /* read according to the cgroup mode */
332
                if (strstr(buffer, "::")) {
8✔
333
                        snprintf(ctrl_name, CONTROL_NAMELEN_MAX, "unified");
8✔
334
                        ret = sscanf(buffer, "%d::%4096s\n", &idx, cgrp_name);
8✔
335
                } else {
336
                        ret = sscanf(buffer, "%d:%[^:]:%4096s\n", &idx, ctrl_name, cgrp_name);
×
337
                }
338

339
                if (ret != 2 && ret != 3) {
8✔
340
                        err("Unrecognized cgroup file format: %s\n", buffer);
×
341
                        scope_pid = -1;
×
342
                        goto out;
×
343
                }
344

345
                /* cgroup v1 might have shared mount points cpu,cpuacct */
346
                _ctrl_name = strchr(ctrl_name, ',');
8✔
347
                if (_ctrl_name) {
8✔
348
                        size = strlen(ctrl_name) - strlen(_ctrl_name);
×
349
                        ctrl_name[size] = '\0';
×
350
                }
351

352
                /*
353
                 * capture is true, while the pid's controller and cgroups
354
                 * are populated for rollback case.
355
                 */
356
                if (capture) {
8✔
357
                        snprintf(info[i].ctrl_name, CONTROL_NAMELEN_MAX, "%s", ctrl_name);
4✔
358
                        snprintf(info[i].cgrp_path, FILENAME_MAX, "%s", cgrp_name);
4✔
359
                }
360

361
                if (!is_cgroup_mode_unified()) {
8✔
362
                        if (ret == 3 && !strncmp(ctrl_name, "name=", 5)) {
×
363
                                if (!strcmp(ctrl_name, "name=systemd")) {
×
364
                                        i++;
×
365
                                        found_systemd_cgrp = 1;
×
366
                                }
367
                                continue;
×
368
                        } else if (ret == 2) {
×
369
                                i++;
×
370
                                found_unified_cgrp = 1;
×
371
                                continue;
×
372
                        }
373
                }
374
                i++;
8✔
375

376
                /* we are not interested in other functionality */
377
                if (capture)
8✔
378
                        continue;
4✔
379

380
                /* skip if the cgroup path doesn't have systemd scope format */
381
                if (strstr(cgrp_name, ".scope") == NULL ||
4✔
382
                    strstr(cgrp_name, ".slice") == NULL)
3✔
383
                        continue;
2✔
384

385
                /* skip if we have already searched cgroup for idle_thread */
386
                if (is_scope_parsed(cgrp_name))
2✔
387
                        continue;
×
388

389

390
                if (ret == 2)
2✔
391
                        ret = cgroup_get_procs(cgrp_name, NULL, &pids, &size);
2✔
392
                else
393
                        ret = cgroup_get_procs(cgrp_name, ctrl_name, &pids, &size);
×
394
                if (ret) {
2✔
395
                        err("Failed to read cgroup.procs of cgroup: %s\n", cgrp_name + 1);
×
396
                        scope_pid = -1;
×
397
                        goto out;
×
398
                }
399

400
                /*
401
                 * .scope created by the non-libcgroup process, will not
402
                 * have libcgroup_systemd_idle_thread
403
                 */
404
                _scope_pid = search_systemd_idle_thread_task(pids, size);
2✔
405
                free(pids);
2✔
406

407
                if (_scope_pid == -1)
2✔
408
                        continue;
1✔
409

410
                if (scope_pid == -1) {
1✔
411
                        /*
412
                         * cgexec pid needs to written into:
413
                         * ../systemd/<slice>/<scope>/cgroup.procs (legacy/hybrid)
414
                         * ../unified/<slice>/<scope>/cgroup.procs (hybrid)
415
                         */
416
                        snprintf(scope_name, FILENAME_MAX, "%s", cgrp_name);
1✔
417
                        scope_pid = _scope_pid;
1✔
418
                        continue;
1✔
419
                }
420

421
                if (_scope_pid != scope_pid) {
×
422
                        err("Failed to replace scope idle_thread, found two idle_thread %u %u\n",
×
423
                            scope_pid, _scope_pid);
424
                        scope_pid = -1;
×
425
                        goto out;
×
426
                }
427
        }
428

429
        if (capture) {
8✔
430
                scope_pid = 0;
4✔
431
                goto out;
4✔
432
        }
433

434
        if (scope_pid == -1) {
4✔
435
                err("Failed to find idle_thread task\n");
3✔
436
                goto out;
3✔
437
        }
438

439
        if (is_cgroup_mode_legacy() && (found_systemd_cgrp == 0 || found_unified_cgrp == 1)) {
1✔
440
                err("cgroup legacy setup incorrect\n");
×
441
                scope_pid = -1;
×
442
                goto out;
×
443
        }
444

445
        if (is_cgroup_mode_hybrid() && (found_systemd_cgrp == 0 || found_unified_cgrp == 0)) {
1✔
446
                err("cgroup hybrid setup incorrect\n");
×
447
                scope_pid = -1;
×
448
                goto out;
×
449
        }
450

451
        /* This is true for cgroup v1 (legacy/hybrid) */
452
        if (found_systemd_cgrp) {
1✔
453
                ret = write_systemd_unified(scope_name, pid);
×
454
                if (ret)
×
455
                        scope_pid = -1;
×
456
        }
457

458
        info[i].ctrl_name[0] = '\0';
1✔
459
out:
8✔
460
        if (pid_proc_fp)
8✔
461
                fclose(pid_proc_fp);
8✔
462

463
        return scope_pid;
8✔
464
}
465

466
/*
467
 * Parse the /proc/mounts file and look for the controller string
468
 * in each line. If found copies the mount point into mnt_point,
469
 * else return NULL mnt_point.
470
 */
471
static void find_mnt_point(const char * const controller, char **mnt_point)
×
472
{
473
        char proc_mount[] = "/proc/mounts";
×
474
        char cgrp_path[FILENAME_MAX];
475
        char buffer[FILENAME_MAX * 2];
476
        FILE *proc_mount_f = NULL;
×
477
        int ret;
478

479
        *mnt_point = NULL;
×
480

481
        proc_mount_f = fopen(proc_mount, "re");
×
482
        if (proc_mount_f == NULL) {
×
483
                err("Failed to read %s:%s\n", proc_mount, strerror(errno));
×
484
                goto out;
×
485
        }
486

487
        while (fgets(buffer, (FILENAME_MAX * 2), proc_mount_f) != NULL) {
×
488
                /* skip line that doesn't have controller */
489
                if (!strstr(buffer, controller))
×
490
                        continue;
×
491

492
                if (strcmp(controller, "name=systemd") == 0) {
×
493
                        if (!strstr(buffer, "name=systemd ") && !strstr(buffer, "name=systemd,"))
×
494
                                continue;
×
495
                }
496

497
                ret = sscanf(buffer, "%*s %4096s\n", cgrp_path);
×
498
                if (ret != 1) {
×
499
                        err("Failed during read of %s:%s\n", proc_mount, strerror(errno));
×
500
                        goto out;
×
501
                }
502

503
                *mnt_point = strdup(cgrp_path);
×
504
                if (!*mnt_point)
×
505
                        err("strdup of %s failed\n", cgrp_path);
×
506
                break;
×
507
        }
508

509
out:
×
510
        if (proc_mount_f)
×
511
                fclose(proc_mount_f);
×
512
}
×
513

514
static int write_systemd_unified(const char * const scope_name, pid_t pid)
×
515
{
516
        char cgrp_procs_path[FILENAME_MAX + 14];
517
        FILE *cgrp_systemd_path_f = NULL;
×
518
        FILE *cgrp_unified_path_f = NULL;
×
519
        char *cgrp_name = NULL;
×
520

521
        /* construct the systemd cgroup path, by parsing /proc/mounts */
522
        find_mnt_point("name=systemd", &cgrp_name);
×
523
        if (!cgrp_name) {
×
524
                err("Unable find name=systemd cgroup path\n");
×
525
                return -1;
×
526
        }
527

528
        snprintf(cgrp_procs_path, sizeof(cgrp_procs_path), "%s/%s/cgroup.procs",
×
529
                 cgrp_name, scope_name);
530
        free(cgrp_name);
×
531

532
        cgrp_systemd_path_f = fopen(cgrp_procs_path, "we");
×
533
        if (!cgrp_systemd_path_f) {
×
534
                err("Failed to open %s\n", cgrp_procs_path);
×
535
                return -1;
×
536
        }
537

538
        if (is_cgroup_mode_hybrid()) {
×
539
                /*
540
                 * construct the unified cgroup path, by parsing
541
                 * /proc/mounts
542
                 */
543
                find_mnt_point("unified", &cgrp_name);
×
544
                if (!cgrp_name) {
×
545
                        err("Unable find unified cgroup path\n");
×
546
                        fclose(cgrp_systemd_path_f);
×
547
                        return -1;
×
548
                }
549

550
                snprintf(cgrp_procs_path, sizeof(cgrp_procs_path), "%s/%s/cgroup.procs",
×
551
                         cgrp_name, scope_name);
552
                free(cgrp_name);
×
553

554
                cgrp_unified_path_f = fopen(cgrp_procs_path, "we");
×
555
                if (!cgrp_unified_path_f) {
×
556
                        err("Failed to open %s\n", cgrp_procs_path);
×
557
                        fclose(cgrp_systemd_path_f);
×
558
                        return -1;
×
559
                }
560
        }
561

562
        fprintf(cgrp_systemd_path_f, "%d", pid);
×
563
        fflush(cgrp_systemd_path_f);
×
564
        fclose(cgrp_systemd_path_f);
×
565

566
        if (!is_cgroup_mode_hybrid())
×
567
                return 0;
×
568

569
        fprintf(cgrp_unified_path_f, "%d", pid);
×
570
        fflush(cgrp_unified_path_f);
×
571
        fclose(cgrp_unified_path_f);
×
572

573
        return 0;
×
574
}
575

576
static int is_scope_parsed(const char * const path)
2✔
577
{
578
        /*
579
         * As per, <kernel sources>/kernel/cgroup/cgroup.c::cgroup_init()
580
         * At the max there can be only 16 controllers and we are
581
         * not accounting for named hierarchies, which can be more
582
         * than 16 themselves.
583
         */
584
        static char parsed_scope_path[MAX_MNT_ELEMENTS][FILENAME_MAX];
585
        int i;
586

587
        for (i = 0; i < MAX_MNT_ELEMENTS; i++) {
2✔
588
                if (!strcmp(parsed_scope_path[i], path))
2✔
589
                        return 1;
×
590
                if (parsed_scope_path[i][0] == '\0') {
2✔
591
                        snprintf(parsed_scope_path[i], FILENAME_MAX, "%s", path);
2✔
592
                        break;
2✔
593
                }
594
        }
595

596
        return 0;
2✔
597
}
598

599
/* Borrowed from src/api.c::__attach_task_pid */
600
static int attach_task_pid(char *path, pid_t tid)
3✔
601
{
602
        FILE *tasks = NULL;
3✔
603
        int ret = 0;
3✔
604

605
        tasks = fopen(path, "we");
3✔
606
        if (!tasks) {
3✔
607
                switch (errno) {
×
608
                case EPERM:
×
609
                        ret = ECGROUPNOTOWNER;
×
610
                        break;
×
611
                case ENOENT:
×
612
                        ret = ECGROUPNOTEXIST;
×
613
                        break;
×
614
                default:
×
615
                        ret = ECGROUPNOTALLOWED;
×
616
                }
617
                goto err;
×
618
        }
619
        ret = fprintf(tasks, "%d", tid);
3✔
620
        if (ret < 0) {
3✔
621
                ret = ECGOTHER;
×
622
                goto err;
×
623
        }
624
        ret = fflush(tasks);
3✔
625
        if (ret) {
3✔
626
                ret = ECGOTHER;
×
627
                goto err;
×
628
        }
629
        fclose(tasks);
3✔
630
        return 0;
3✔
631
err:
×
632
        err("cannot write tid %d to %s:%s\n", tid, path, strerror(errno));
×
633
        if (tasks)
×
634
                fclose(tasks);
×
635
        return ret;
×
636
}
637

638
static int rollback_pid_cgroups(pid_t pid)
3✔
639
{
640
        char cgrp_proc_path[FILENAME_MAX + 14];
641
        char cgrp_path[FILENAME_MAX];
642
        char *_cgrp_proc_path = NULL;
3✔
643
        int err = 0, idx = 0;
3✔
644
        int ret = 0;
3✔
645

646
        /*
647
         * unified cgroup rollback is simple, we need to write into
648
         * single cgroup hierarchy.
649
         */
650
        if (is_cgroup_mode_unified()) {
3✔
651
                pthread_rwlock_rdlock(&cg_mount_table_lock);
3✔
652
                cg_build_path_locked(info[idx].cgrp_path, cgrp_path, NULL);
3✔
653
                pthread_rwlock_unlock(&cg_mount_table_lock);
3✔
654

655
                snprintf(cgrp_proc_path, FILENAME_MAX + 14, "%s/cgroup.procs", cgrp_path);
3✔
656
                ret = attach_task_pid(cgrp_proc_path, pid);
3✔
657
                return ret;
3✔
658
        }
659

660
        for (idx = 0; info[idx].ctrl_name[0] != '\0'; idx++) {
×
661
                /* find the systemd cgroup path */
662
                if (!strcmp(info[idx].ctrl_name, "name=systemd")) {
×
663
                        find_mnt_point("name=systemd", &_cgrp_proc_path);
×
664
                        if (!_cgrp_proc_path) {
×
665
                                err("Unable find name=systemd cgroup path\n");
×
666
                                return -1;
×
667
                        }
668

669
                        snprintf(cgrp_proc_path, FILENAME_MAX + 14, "%s/%s/cgroup.procs",
×
670
                                 _cgrp_proc_path, info[idx].cgrp_path);
×
671
                        free(_cgrp_proc_path);
×
672

673
                /* find the unified cgroup path */
674
                } else if (is_cgroup_mode_hybrid() &&
×
675
                           !strcmp(info[idx].ctrl_name, "unified")) {
×
676
                        find_mnt_point("unified cgroup2", &_cgrp_proc_path);
×
677
                        if (!_cgrp_proc_path) {
×
678
                                err("Unable find unified cgroup path\n");
×
679
                                return -1;
×
680
                        }
681

682
                        snprintf(cgrp_proc_path, FILENAME_MAX + 14, "%s/%s/cgroup.procs",
×
683
                                _cgrp_proc_path, info[idx].cgrp_path);
×
684
                        free(_cgrp_proc_path);
×
685

686
                /* find other controller hierarchy path */
687
                } else {
688
                        pthread_rwlock_rdlock(&cg_mount_table_lock);
×
689
                        cg_build_path_locked(info[idx].cgrp_path, cgrp_path, info[idx].ctrl_name);
×
690
                        pthread_rwlock_unlock(&cg_mount_table_lock);
×
691

692
                        snprintf(cgrp_proc_path, FILENAME_MAX + 14, "%s/cgroup.procs", cgrp_path);
×
693
                }
694

695
                /* record the error and continue */
696
                ret = attach_task_pid(cgrp_proc_path, pid);
×
697
                if (ret)
×
698
                        err = -1;
×
699
        }
700

701
        return err;
×
702
}
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