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

drakenclimber / libcgroup / 16178979042

16 Jun 2025 02:39PM UTC coverage: 54.02% (-2.2%) from 56.219%
16178979042

push

github

drakenclimber
api.c: prevent array out-of-bounds access in cgroup_parse_rules_file

In the function src/api.c/cgroup_parse_rules_file, the condition of loop:

for (i = 0; lst->tail->controllers[i]; i++)
        cgroup_dbg(" %s", lst->tail->controllers[i]);

allows accessing lst->tail->controllers[MAX_MNT_ELEMENTS] if
lst->tail->controllers is full and lacks a terminating NULL.

Add explicit bounds checking (i < MAX_MNT_ELEMENTS) while maintaining
the NULL check. This ensures that there will never be reading past the
array boundaries regardless of its content.

Found by Linux Verification Center (linuxtesting.org) with SVACE.

Signed-off-by: Mikhail Dmitrichenko <m.dmitrichenko222@gmail.com>
Acked-by: Kamalesh Babulal <kamalesh.babulal@oracle.com>
Signed-off-by: Tom Hromatka <tom.hromatka@oracle.com>

1 of 1 new or added line in 1 file covered. (100.0%)

272 existing lines in 14 files now uncovered.

5435 of 10061 relevant lines covered (54.02%)

170.44 hits per line

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

74.94
/src/wrapper.c
1
// SPDX-License-Identifier: LGPL-2.1-only
2
/**
3
 * Copyright IBM Corporation. 2008
4
 *
5
 * Author:        Dhaval Giani <dhaval@linux.vnet.ibm.com>
6
 *
7
 * Code initiated and designed by Dhaval Giani. All faults are most likely
8
 * his mistake.
9
 */
10

11
#define _GNU_SOURCE
12

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

16
#include <inttypes.h>
17
#include <stdlib.h>
18
#include <string.h>
19
#include <unistd.h>
20
#include <stdio.h>
21
#include <errno.h>
22

23
static void init_cgroup(struct cgroup *cgroup)
3,783✔
24
{
25
        cgroup->task_fperm = NO_PERMS;
3,783✔
26
        cgroup->control_fperm = NO_PERMS;
3,783✔
27
        cgroup->control_dperm = NO_PERMS;
3,783✔
28

29
        cgroup->control_gid = NO_UID_GID;
3,783✔
30
        cgroup->control_uid = NO_UID_GID;
3,783✔
31
        cgroup->tasks_gid = NO_UID_GID;
3,783✔
32
        cgroup->tasks_uid = NO_UID_GID;
3,783✔
33
}
3,783✔
34

35
void init_cgroup_table(struct cgroup *cgroups, size_t count)
69✔
36
{
37
        size_t i;
38

39
        for (i = 0; i < count; ++i)
3,036✔
40
                init_cgroup(&cgroups[i]);
2,967✔
41
}
69✔
42

43
struct cgroup *cgroup_new_cgroup(const char *name)
817✔
44
{
45
        struct cgroup *cgroup;
46

47
        if (!name)
817✔
48
                return NULL;
1✔
49

50
        cgroup = calloc(1, sizeof(struct cgroup));
816✔
51
        if (!cgroup)
816✔
52
                return NULL;
×
53

54
        init_cgroup(cgroup);
816✔
55
        strncpy(cgroup->name, name, FILENAME_MAX - 1);
816✔
56
        cgroup->name[FILENAME_MAX - 1] = '\0';
816✔
57

58
        return cgroup;
816✔
59
}
60

61
struct cgroup_controller *cgroup_add_controller(struct cgroup *cgroup, const char *name)
717✔
62
{
63
        struct cgroup_controller *controller;
64
        int i, ret;
65

66
        if (!cgroup || !name)
717✔
67
                return NULL;
3✔
68

69
        /* Still not sure how to handle the failure here. */
70
        if (cgroup->index >= CG_CONTROLLER_MAX)
714✔
71
                return NULL;
×
72

73
        /* Still not sure how to handle the failure here. */
74
        for (i = 0; i < cgroup->index; i++) {
859✔
75
                if (strncmp(name, cgroup->controller[i]->name, CONTROL_NAMELEN_MAX) == 0)
145✔
76
                        return NULL;
×
77
        }
78

79
        controller = calloc(1, sizeof(struct cgroup_controller));
714✔
80
        if (!controller)
714✔
81
                return NULL;
×
82

83
        strncpy(controller->name, name, CONTROL_NAMELEN_MAX - 1);
714✔
84
        controller->name[CONTROL_NAMELEN_MAX - 1] = '\0';
714✔
85

86
        controller->cgroup = cgroup;
714✔
87
        controller->index = 0;
714✔
88

89
        if (strcmp(controller->name, CGRP_FILE_PREFIX) == 0) {
714✔
90
                /*
91
                 * Operating on the "cgroup" controller is only allowed
92
                 * on cgroup v2 systems
93
                 */
94
                controller->version = CGROUP_V2;
45✔
95
        } else {
96
                ret = cgroup_get_controller_version(controller->name, &controller->version);
669✔
97
                if (ret) {
669✔
UNCOV
98
                        cgroup_dbg("failed to get cgroup version for controller %s\n",
×
99
                                   controller->name);
UNCOV
100
                        free(controller);
×
UNCOV
101
                        return NULL;
×
102
                }
103
        }
104

105
        cgroup->controller[cgroup->index] = controller;
714✔
106
        cgroup->index++;
714✔
107

108
        return controller;
714✔
109
}
110

111
int cgroup_add_all_controllers(struct cgroup *cgroup)
7✔
112
{
113
        struct cgroup_controller *cgc;
114
        struct controller_data info;
115
        enum cg_setup_mode_t mode;
116
        void *handle;
117
        int ret = 0;
7✔
118

119
        if (!cgroup)
7✔
120
                return ECGINVAL;
×
121

122
        mode = cgroup_setup_mode();
7✔
123

124
        /*
125
         * Per kernel documentation, cgroup-v2.rst, /proc/cgroups is "meaningless" for cgroup v2.
126
         * Use the cgroup's cgroup.controllers file instead
127
         */
128
        if (mode == CGROUP_MODE_UNIFIED) {
7✔
129
                char *ret_c, *controller, *stok_buff = NULL, line[CGV2_CONTROLLERS_LL_MAX];
7✔
130
                /*
131
                 * cg_cgroup_v2_mount_path (FILENAME_MAX) + cgroup->name (FILENAME_MAX) +
132
                 * strlen("cgroup.controllers") (18) + 2 forward slashes + 1 NULL terminator
133
                 */
134
                char cgroup_controllers_path[FILENAME_MAX * 2 + 18 + 2 + 1];
135
                FILE *fp;
136

137
                pthread_rwlock_rdlock(&cg_mount_table_lock);
7✔
138
                if (strlen(cg_cgroup_v2_mount_path) == 0) {
7✔
139
                        pthread_rwlock_unlock(&cg_mount_table_lock);
×
140
                        ret = ECGOTHER;
×
141
                        goto out;
×
142
                }
143

144
                snprintf(cgroup_controllers_path, sizeof(cgroup_controllers_path), "%s/%s/%s",
7✔
145
                         cg_cgroup_v2_mount_path, cgroup->name, CGV2_CONTROLLERS_FILE);
7✔
146
                pthread_rwlock_unlock(&cg_mount_table_lock);
7✔
147

148
                fp = fopen(cgroup_controllers_path, "re");
7✔
149
                if (!fp) {
7✔
150
                        ret = ECGOTHER;
×
151
                        goto out;
×
152
                }
153

154
                ret_c = fgets(line, CGV2_CONTROLLERS_LL_MAX, fp);
7✔
155
                fclose(fp);
7✔
156
                if (ret_c == NULL) {
7✔
157
                        /* no controllers are enabled */
158
                        goto out;
×
159
                }
160

161
                /* Remove the trailing newline */
162
                ret_c[strlen(ret_c) - 1] = '\0';
7✔
163

164
                /*
165
                 * cgroup.controllers returns a list of available controllers in
166
                 * the following format:
167
                 *        cpuset cpu io memory pids rdma
168
                 */
169
                controller = strtok_r(ret_c, " ", &stok_buff);
7✔
170
                do {
171
                        cgc = cgroup_add_controller(cgroup, controller);
27✔
172
                        if (!cgc) {
27✔
173
                                ret = ECGINVAL;
×
174
                                fprintf(stderr, "controller %s can't be added\n", controller);
×
175
                                goto end;
×
176
                        }
177
                } while ((controller = strtok_r(NULL, " ", &stok_buff)));
27✔
178
        } else {
179
                /* go through the controller list */
180
                ret = cgroup_get_all_controller_begin(&handle, &info);
×
181
                if ((ret != 0) && (ret != ECGEOF)) {
×
182
                        fprintf(stderr, "cannot read controller data: %s\n", cgroup_strerror(ret));
×
183
                        return ret;
×
184
                }
185

186
                while (ret == 0) {
×
187
                        if (info.hierarchy == 0) {
×
188
                                /*
189
                                 * the controller is not attached to any
190
                                 * hierarchy skip it.
191
                                 */
192
                                goto next;
×
193
                        }
194

195
                        /* add mounted controller to cgroup structure */
196
                        cgc = cgroup_add_controller(cgroup, info.name);
×
197
                        if (!cgc) {
×
198
                                ret = ECGINVAL;
×
199
                                fprintf(stderr, "controller %s can't be added\n", info.name);
×
200
                                goto end;
×
201
                        }
202

203
next:
×
204
                        ret = cgroup_get_all_controller_next(&handle, &info);
×
205
                        if (ret && ret != ECGEOF)
×
206
                                goto end;
×
207
                }
208

209
end:
×
210
                cgroup_get_all_controller_end(&handle);
×
211
                if (ret == ECGEOF)
×
212
                        ret = 0;
×
213
                if (ret)
×
214
                        fprintf(stderr,        "cgroup_get_controller_begin/next failed (%s)\n",
×
215
                                cgroup_strerror(ret));
216
        }
217

218
out:
×
219
        return ret;
7✔
220
}
221

222
static void cgroup_free_value(struct control_value *value)
818✔
223
{
224
        if (value->multiline_value)
818✔
225
                free(value->multiline_value);
4✔
226
        if (value->prev_name)
818✔
227
                free(value->prev_name);
27✔
228

229
        free(value);
818✔
230
}
818✔
231

232
void cgroup_free_controller(struct cgroup_controller *ctrl)
861✔
233
{
234
        int i;
235

236
        for (i = 0; i < ctrl->index; i++)
1,677✔
237
                cgroup_free_value(ctrl->values[i]);
816✔
238
        ctrl->index = 0;
861✔
239

240
        free(ctrl);
861✔
241
}
861✔
242

243
void cgroup_free_controllers(struct cgroup *cgroup)
1,050✔
244
{
245
        int i;
246

247
        if (!cgroup)
1,050✔
248
                return;
×
249

250
        for (i = 0; i < cgroup->index; i++)
1,910✔
251
                cgroup_free_controller(cgroup->controller[i]);
860✔
252

253
        cgroup->index = 0;
1,050✔
254
}
255

256
void cgroup_free(struct cgroup **cgroup)
942✔
257
{
258
        struct cgroup *cg = *cgroup;
942✔
259

260
        /* Passing NULL pointers is OK. We just return. */
261
        if (!cg)
942✔
262
                return;
142✔
263

264
        cgroup_free_controllers(cg);
800✔
265
        free(cg);
800✔
266
        *cgroup = NULL;
800✔
267
}
268

269
int cgroup_add_value_string(struct cgroup_controller *controller, const char *name,
598✔
270
                            const char *value)
271
{
272
        int i;
273
        struct control_value *cntl_value;
274

275
        if (!controller || !name)
598✔
276
                return ECGINVAL;
3✔
277

278
        if (controller->index >= CG_NV_MAX)
595✔
279
                return ECGMAXVALUESEXCEEDED;
×
280

281
        for (i = 0; i < controller->index && i < CG_NV_MAX; i++) {
2,316✔
282
                if (!strcmp(controller->values[i]->name, name))
1,721✔
283
                        return ECGVALUEEXISTS;
×
284
        }
285

286
        cntl_value = calloc(1, sizeof(struct control_value));
595✔
287
        if (!cntl_value)
595✔
288
                return ECGCONTROLLERCREATEFAILED;
×
289

290
        strncpy(cntl_value->name, name, sizeof(cntl_value->name));
595✔
291
        cntl_value->name[sizeof(cntl_value->name)-1] = '\0';
595✔
292

293
        if (value) {
595✔
294
                if (strlen(value) >= sizeof(cntl_value->value)) {
532✔
295
                        fprintf(stderr, "value exceeds the maximum of %ld characters\n",
×
296
                                sizeof(cntl_value->value) - 1);
297
                        free(cntl_value);
×
298
                        return ECGCONFIGPARSEFAIL;
×
299
                }
300

301
                strncpy(cntl_value->value, value, sizeof(cntl_value->value));
532✔
302
                cntl_value->value[sizeof(cntl_value->value)-1] = '\0';
532✔
303
                cntl_value->dirty = true;
532✔
304
        }
305

306
        controller->values[controller->index] = cntl_value;
595✔
307
        controller->index++;
595✔
308

309
        return 0;
595✔
310
}
311

312
int cgroup_add_value_int64(struct cgroup_controller *controller, const char *name, int64_t value)
2✔
313
{
314
        char *val;
315
        int ret;
316

317
        ret = asprintf(&val, "%"PRId64, value);
2✔
318
        if (ret < 0) {
2✔
319
                last_errno = errno;
×
320
                return ECGOTHER;
×
321
        }
322

323
        ret = cgroup_add_value_string(controller, name, val);
2✔
324
        free(val);
2✔
325

326
        return ret;
2✔
327
}
328

329
int cgroup_add_value_uint64(struct cgroup_controller *controller, const char *name,
2✔
330
                            u_int64_t value)
331
{
332
        char *val;
333
        int ret;
334

335
        ret = asprintf(&val, "%" PRIu64, value);
2✔
336
        if (ret < 0) {
2✔
337
                last_errno = errno;
×
338
                return ECGOTHER;
×
339
        }
340

341
        ret = cgroup_add_value_string(controller, name, val);
2✔
342
        free(val);
2✔
343

344
        return ret;
2✔
345
}
346

347
int cgroup_add_value_bool(struct cgroup_controller *controller, const char *name, bool value)
2✔
348
{
349
        char *val;
350
        int ret;
351

352
        if (value)
2✔
353
                val = strdup("1");
×
354
        else
355
                val = strdup("0");
2✔
356
        if (!val) {
2✔
357
                last_errno = errno;
×
358
                return ECGOTHER;
×
359
        }
360

361
        ret = cgroup_add_value_string(controller, name, val);
2✔
362
        free(val);
2✔
363

364
        return ret;
2✔
365
}
366

367
int cgroup_remove_value(struct cgroup_controller * const controller, const char * const name)
2✔
368
{
369
        int i;
370

371
        for (i = 0; i < controller->index; i++) {
3✔
372
                if (strcmp(controller->values[i]->name, name) == 0) {
3✔
373
                        cgroup_free_value(controller->values[i]);
2✔
374

375
                        if (i == (controller->index - 1)) {
2✔
376
                                /* This is the last entry in the table. There's nothing to move */
377
                                controller->index--;
×
378
                        } else {
379
                                memmove(&controller->values[i],        &controller->values[i + 1],
2✔
380
                                sizeof(struct control_value *) * (controller->index - i - 1));
2✔
381
                                controller->index--;
2✔
382
                        }
383
                        return 0;
2✔
384
                }
385
        }
386

387
        return ECGROUPNOTEXIST;
×
388
}
389

390
int cgroup_compare_controllers(struct cgroup_controller *cgca, struct cgroup_controller *cgcb)
30✔
391
{
392
        int i;
393

394
        if (!cgca || !cgcb)
30✔
395
                return ECGINVAL;
×
396

397
        if (strcmp(cgca->name, cgcb->name))
30✔
398
                return ECGCONTROLLERNOTEQUAL;
18✔
399

400
        if (cgca->index != cgcb->index)
12✔
401
                return ECGCONTROLLERNOTEQUAL;
×
402

403
        for (i = 0; i < cgca->index; i++) {
52✔
404
                struct control_value *cva = cgca->values[i];
40✔
405
                struct control_value *cvb = cgcb->values[i];
40✔
406

407
                if (strcmp(cva->name, cvb->name))
40✔
408
                        return ECGCONTROLLERNOTEQUAL;
×
409

410
                if (strcmp(cva->value, cvb->value))
40✔
411
                        return ECGCONTROLLERNOTEQUAL;
×
412
        }
413

414
        return 0;
12✔
415
}
416

417
int cgroup_compare_cgroup(struct cgroup *cgroup_a, struct cgroup *cgroup_b)
8✔
418
{
419
        int i, j;
420

421
        if (!cgroup_a || !cgroup_b)
8✔
422
                return ECGINVAL;
×
423

424
        if (strcmp(cgroup_a->name, cgroup_b->name))
8✔
425
                return ECGROUPNOTEQUAL;
×
426

427
        if (cgroup_a->tasks_uid != cgroup_b->tasks_uid)
8✔
428
                return ECGROUPNOTEQUAL;
1✔
429

430
        if (cgroup_a->tasks_gid != cgroup_b->tasks_gid)
7✔
431
                return ECGROUPNOTEQUAL;
1✔
432

433
        if (cgroup_a->control_uid != cgroup_b->control_uid)
6✔
434
                return ECGROUPNOTEQUAL;
1✔
435

436
        if (cgroup_a->control_gid != cgroup_b->control_gid)
5✔
437
                return ECGROUPNOTEQUAL;
1✔
438

439
        if (cgroup_a->index != cgroup_b->index)
4✔
440
                return ECGROUPNOTEQUAL;
×
441

442
        for (i = 0; i < cgroup_a->index; i++) {
16✔
443
                struct cgroup_controller *cgca = cgroup_a->controller[i];
12✔
444
                bool found_match = false;
12✔
445

446
                /*
447
                 * Don't penalize the user if the controllers are in different order
448
                 * from cgroup_a to cgroup_b
449
                 */
450
                for (j = 0; j < cgroup_b->index; j++) {
30✔
451
                        struct cgroup_controller *cgcb = cgroup_b->controller[j];
30✔
452

453
                        if (cgroup_compare_controllers(cgca, cgcb) == 0) {
30✔
454
                                found_match = true;
12✔
455
                                break;
12✔
456
                        }
457
                }
458

459
                if (!found_match)
12✔
460
                        return ECGCONTROLLERNOTEQUAL;
×
461
        }
462

463
        return 0;
4✔
464
}
465

466
int cgroup_set_uid_gid(struct cgroup *cgroup, uid_t tasks_uid, gid_t tasks_gid, uid_t control_uid,
120✔
467
                       gid_t control_gid)
468
{
469
        if (!cgroup)
120✔
470
                return ECGINVAL;
×
471

472
        cgroup->tasks_uid = tasks_uid;
120✔
473
        cgroup->tasks_gid = tasks_gid;
120✔
474
        cgroup->control_uid = control_uid;
120✔
475
        cgroup->control_gid = control_gid;
120✔
476

477
        return 0;
120✔
478
}
479

480
int cgroup_get_uid_gid(struct cgroup *cgroup, uid_t *tasks_uid, gid_t *tasks_gid,
6✔
481
                       uid_t *control_uid, gid_t *control_gid)
482
{
483
        if (!cgroup || !tasks_uid || !tasks_gid || !control_uid || !control_gid)
6✔
484
                return ECGINVAL;
5✔
485

486
        *tasks_uid = cgroup->tasks_uid;
1✔
487
        *tasks_gid = cgroup->tasks_gid;
1✔
488
        *control_uid = cgroup->control_uid;
1✔
489
        *control_gid = cgroup->control_gid;
1✔
490

491
        return 0;
1✔
492
}
493

494
struct cgroup_controller *cgroup_get_controller(struct cgroup *cgroup, const char *name)
265✔
495
{
496
        int i;
497
        struct cgroup_controller *cgc;
498

499
        if (!cgroup)
265✔
500
                return NULL;
×
501

502
        for (i = 0; i < cgroup->index; i++) {
343✔
503
                cgc = cgroup->controller[i];
149✔
504

505
                if (!strcmp(cgc->name, name))
149✔
506
                        return cgc;
71✔
507
        }
508

509
        return NULL;
194✔
510
}
511

512
int cgroup_get_value_string(struct cgroup_controller *controller, const char *name, char **value)
249✔
513
{
514
        int i;
515

516
        if (!controller || !name || !value)
249✔
517
                return ECGINVAL;
4✔
518

519
        for (i = 0; i < controller->index; i++) {
1,845✔
520
                struct control_value *val = controller->values[i];
1,845✔
521

522
                if (!strcmp(val->name, name)) {
1,845✔
523
                        *value = strdup(val->value);
245✔
524

525
                        if (!*value)
245✔
526
                                return ECGOTHER;
×
527

528
                        return 0;
245✔
529
                }
530
        }
531

532
        return ECGROUPVALUENOTEXIST;
×
533

534
}
535

536
int cgroup_set_value_string(struct cgroup_controller *controller, const char *name,
8✔
537
                            const char *value)
538
{
539
        int i;
540

541
        if (!controller || !name || !value)
8✔
542
                return ECGINVAL;
4✔
543

544
        for (i = 0; i < controller->index; i++) {
4✔
545
                struct control_value *val = controller->values[i];
4✔
546

547
                if (!strcmp(val->name, name)) {
4✔
548
                        strncpy(val->value, value, CG_CONTROL_VALUE_MAX);
4✔
549
                        val->value[sizeof(val->value)-1] = '\0';
4✔
550
                        val->dirty = true;
4✔
551
                        return 0;
4✔
552
                }
553
        }
554

555
        return cgroup_add_value_string(controller, name, value);
×
556
}
557

558
int cgroup_get_value_int64(struct cgroup_controller *controller, const char *name, int64_t *value)
5✔
559
{
560
        int i;
561

562
        if (!controller || !name || !value)
5✔
563
                return ECGINVAL;
4✔
564

565
        for (i = 0; i < controller->index; i++) {
1✔
566
                struct control_value *val = controller->values[i];
1✔
567

568
                if (!strcmp(val->name, name)) {
1✔
569
                        if (sscanf(val->value, "%" SCNd64, value) != 1)
1✔
570
                                return ECGINVAL;
×
571

572
                        return 0;
1✔
573
                }
574
        }
575

576
        return ECGROUPVALUENOTEXIST;
×
577
}
578

579
int cgroup_set_value_int64(struct cgroup_controller *controller, const char *name, int64_t value)
5✔
580
{
581
        int ret;
582
        int i;
583

584
        if (!controller || !name)
5✔
585
                return ECGINVAL;
2✔
586

587
        for (i = 0; i < controller->index; i++) {
3✔
588
                struct control_value *val = controller->values[i];
1✔
589

590
                if (!strcmp(val->name, name)) {
1✔
591
                        ret = snprintf(val->value, sizeof(val->value), "%" PRId64, value);
1✔
592
                        if (ret >= sizeof(val->value))
1✔
593
                                return ECGINVAL;
×
594

595
                        val->dirty = true;
1✔
596
                        return 0;
1✔
597
                }
598
        }
599

600
        return cgroup_add_value_int64(controller, name, value);
2✔
601
}
602

603
int cgroup_get_value_uint64(struct cgroup_controller *controller, const char *name,
5✔
604
                            u_int64_t *value)
605
{
606
        int i;
607

608
        if (!controller || !name || !value)
5✔
609
                return ECGINVAL;
4✔
610

611
        for (i = 0; i < controller->index; i++) {
1✔
612
                struct control_value *val = controller->values[i];
1✔
613

614
                if (!strcmp(val->name, name)) {
1✔
615
                        if (sscanf(val->value, "%" SCNu64, value) != 1)
1✔
616
                                return ECGINVAL;
×
617

618
                        return 0;
1✔
619
                }
620
        }
621

622
        return ECGROUPVALUENOTEXIST;
×
623
}
624

625
int cgroup_set_value_uint64(struct cgroup_controller *controller, const char *name,
5✔
626
                            u_int64_t value)
627
{
628
        int ret;
629
        int i;
630

631
        if (!controller || !name)
5✔
632
                return ECGINVAL;
2✔
633

634
        for (i = 0; i < controller->index; i++) {
3✔
635
                struct control_value *val = controller->values[i];
1✔
636

637
                if (!strcmp(val->name, name)) {
1✔
638
                        ret = snprintf(val->value, sizeof(val->value), "%" PRIu64, value);
1✔
639
                        if (ret >= sizeof(val->value))
1✔
640
                                return ECGINVAL;
×
641

642
                        val->dirty = true;
1✔
643
                        return 0;
1✔
644
                }
645
        }
646

647
        return cgroup_add_value_uint64(controller, name, value);
2✔
648
}
649

650
int cgroup_get_value_bool(struct cgroup_controller *controller, const char *name, bool *value)
5✔
651
{
652
        int i;
653

654
        if (!controller || !name || !value)
5✔
655
                return ECGINVAL;
4✔
656

657
        for (i = 0; i < controller->index; i++) {
1✔
658
                struct control_value *val = controller->values[i];
1✔
659

660
                if (!strcmp(val->name, name)) {
1✔
661
                        int cgc_val;
662

663
                        if (sscanf(val->value, "%d", &cgc_val) != 1)
1✔
664
                                return ECGINVAL;
×
665

666
                        if (cgc_val)
1✔
667
                                *value = true;
1✔
668
                        else
669
                                *value = false;
×
670

671
                        return 0;
1✔
672
                }
673
        }
674

675
        return ECGROUPVALUENOTEXIST;
×
676
}
677

678
int cgroup_set_value_bool(struct cgroup_controller *controller, const char *name, bool value)
5✔
679
{
680
        int ret;
681
        int i;
682

683
        if (!controller || !name)
5✔
684
                return ECGINVAL;
2✔
685

686
        for (i = 0; i < controller->index; i++) {
3✔
687
                struct control_value *val = controller->values[i];
1✔
688

689
                if (!strcmp(val->name, name)) {
1✔
690
                        if (value)
1✔
691
                                ret = snprintf(val->value, sizeof(val->value), "1");
1✔
692
                        else
693
                                ret = snprintf(val->value, sizeof(val->value), "0");
×
694

695
                        if (ret >= sizeof(val->value))
1✔
696
                                return ECGINVAL;
×
697

698
                        val->dirty = true;
1✔
699
                        return 0;
1✔
700

701
                }
702
        }
703

704
        return cgroup_add_value_bool(controller, name, value);
2✔
705
}
706

707
struct cgroup *create_cgroup_from_name_value_pairs(const char *name,
167✔
708
                                                   struct control_value *name_value, int nv_number)
709
{
710
        struct cgroup_controller *cgc;
711
        struct cgroup *src_cgroup;
712
        char con[FILENAME_MAX];
713

714
        int ret;
715
        int i;
716

717
        /* create source cgroup */
718
        src_cgroup = cgroup_new_cgroup(name);
167✔
719
        if (!src_cgroup) {
167✔
720
                fprintf(stderr, "can't create cgroup: %s\n", cgroup_strerror(ECGFAIL));
×
721
                goto scgroup_err;
×
722
        }
723

724
        /* Add pairs name-value to relevant controllers of this cgroup. */
725
        for (i = 0; i < nv_number; i++) {
314✔
726

727
                if ((strchr(name_value[i].name, '.')) == NULL) {
147✔
728
                        fprintf(stderr, "wrong -r  parameter (%s=%s)\n", name_value[i].name,
×
729
                                name_value[i].value);
×
730
                        goto scgroup_err;
×
731
                }
732

733
                strncpy(con, name_value[i].name, FILENAME_MAX - 1);
147✔
734
                con[FILENAME_MAX - 1] = '\0';
147✔
735

736
                strtok(con, ".");
147✔
737

738
                /*
739
                 * find out whether we have to add the controller or
740
                 * cgroup already contains it.
741
                 */
742
                cgc = cgroup_get_controller(src_cgroup, con);
147✔
743
                if (!cgc) {
147✔
744
                        /* add relevant controller */
745
                        cgc = cgroup_add_controller(src_cgroup, con);
147✔
746
                        if (!cgc) {
147✔
747
                                fprintf(stderr, "controller %s can't be add\n",        con);
×
748
                                goto scgroup_err;
×
749
                        }
750
                }
751

752
                /* add name-value pair to this controller */
753
                ret = cgroup_add_value_string(cgc, name_value[i].name, name_value[i].value);
147✔
754
                if (ret) {
147✔
755
                        fprintf(stderr, "name-value pair %s=%s can't be set\n",        name_value[i].name,
×
756
                                name_value[i].value);
×
757
                        goto scgroup_err;
×
758
                }
759
        }
760

761
        return src_cgroup;
167✔
762

763
scgroup_err:
×
764
        cgroup_free(&src_cgroup);
×
765

766
        return NULL;
×
767
}
768

769
int cgroup_get_value_name_count(struct cgroup_controller *controller)
54✔
770
{
771
        if (!controller)
54✔
772
                return -1;
×
773

774
        return controller->index;
54✔
775
}
776

777

778
char *cgroup_get_value_name(struct cgroup_controller *controller, int index)
245✔
779
{
780

781
        if (!controller)
245✔
782
                return NULL;
×
783

784
        if (index < controller->index)
245✔
785
                return (controller->values[index])->name;
245✔
786
        else
787
                return NULL;
×
788
}
789

790
char *cgroup_get_cgroup_name(struct cgroup *cgroup)
×
791
{
792
        if (!cgroup)
×
793
                return NULL;
×
794

795
        return cgroup->name;
×
796
}
797

798

799
/*
800
 * Return true if cgroup setup mode is cgroup v1 (legacy), else
801
 * returns false.
802
 */
803
bool is_cgroup_mode_legacy(void)
2✔
804
{
805
        enum cg_setup_mode_t setup_mode;
806

807
        setup_mode = cgroup_setup_mode();
2✔
808
        return (setup_mode == CGROUP_MODE_LEGACY);
2✔
809
}
810

811
/*
812
 * Return true if cgroup setup mode is cgroup v1/v2 (hybrid), else
813
 * returns false.
814
 */
815
bool is_cgroup_mode_hybrid(void)
2✔
816
{
817
        enum cg_setup_mode_t setup_mode;
818

819
        setup_mode = cgroup_setup_mode();
2✔
820
        return (setup_mode == CGROUP_MODE_HYBRID);
2✔
821
}
822

823
/*
824
 * Return true if cgroup setup mode is cgroup v2 (unified), else
825
 * returns false.
826
 */
827
bool is_cgroup_mode_unified(void)
82✔
828
{
829
        enum cg_setup_mode_t setup_mode;
830

831
        setup_mode = cgroup_setup_mode();
82✔
832
        return (setup_mode == CGROUP_MODE_UNIFIED);
82✔
833
}
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