cgroup-util.c 27.3 KB
Newer Older
1
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

/***
  This file is part of systemd.

  Copyright 2010 Lennart Poettering

  systemd is free software; you can redistribute it and/or modify it
  under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  systemd is distributed in the hope that it will be useful, but
  WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/

#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <stdlib.h>
27
#include <dirent.h>
28
29
#include <sys/stat.h>
#include <sys/types.h>
30
#include <ftw.h>
31
32
33
34
35
36
37

#include "cgroup-util.h"
#include "log.h"
#include "set.h"
#include "macro.h"
#include "util.h"

38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
int cg_enumerate_processes(const char *controller, const char *path, FILE **_f) {
        char *fs;
        int r;
        FILE *f;

        assert(controller);
        assert(path);
        assert(_f);

        if ((r = cg_get_path(controller, path, "cgroup.procs", &fs)) < 0)
                return r;

        f = fopen(fs, "re");
        free(fs);

        if (!f)
                return -errno;

        *_f = f;
        return 0;
}

int cg_enumerate_tasks(const char *controller, const char *path, FILE **_f) {
        char *fs;
        int r;
        FILE *f;

        assert(controller);
        assert(path);
        assert(_f);

        if ((r = cg_get_path(controller, path, "tasks", &fs)) < 0)
                return r;

        f = fopen(fs, "re");
        free(fs);

        if (!f)
                return -errno;

        *_f = f;
        return 0;
}

int cg_read_pid(FILE *f, pid_t *_pid) {
        unsigned long ul;

        /* Note that the cgroup.procs might contain duplicates! See
         * cgroups.txt for details. */

        errno = 0;
        if (fscanf(f, "%lu", &ul) != 1) {

                if (feof(f))
                        return 0;

                return errno ? -errno : -EIO;
        }

        if (ul <= 0)
                return -EIO;

        *_pid = (pid_t) ul;
        return 1;
}

104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
int cg_enumerate_subgroups(const char *controller, const char *path, DIR **_d) {
        char *fs;
        int r;
        DIR *d;

        assert(controller);
        assert(path);
        assert(_d);

        /* This is not recursive! */

        if ((r = cg_get_path(controller, path, NULL, &fs)) < 0)
                return r;

        d = opendir(fs);
        free(fs);

        if (!d)
                return -errno;

        *_d = d;
        return 0;
}

int cg_read_subgroup(DIR *d, char **fn) {
        struct dirent *de;

        assert(d);

        errno = 0;
        while ((de = readdir(d))) {
                char *b;

                if (de->d_type != DT_DIR)
                        continue;

                if (streq(de->d_name, ".") ||
                    streq(de->d_name, ".."))
                        continue;

                if (!(b = strdup(de->d_name)))
                        return -ENOMEM;

                *fn = b;
                return 1;
        }

        if (errno)
                return -errno;

        return 0;
}

157
int cg_rmdir(const char *controller, const char *path, bool honour_sticky) {
158
159
160
        char *p;
        int r;

161
162
        r = cg_get_path(controller, path, NULL, &p);
        if (r < 0)
163
164
                return r;

165
166
167
168
169
170
171
172
173
174
175
        if (honour_sticky) {
                char *tasks;

                /* If the sticky bit is set don't remove the directory */

                tasks = strappend(p, "/tasks");
                if (!tasks) {
                        free(p);
                        return -ENOMEM;
                }

176
                r = file_is_priv_sticky(tasks);
177
178
179
180
181
182
183
184
                free(tasks);

                if (r > 0) {
                        free(p);
                        return 0;
                }
        }

185
186
187
        r = rmdir(p);
        free(p);

188
        return (r < 0 && errno != ENOENT) ? -errno : 0;
189
190
}

191
int cg_kill(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, Set *s) {
192
        bool done = false;
193
        int r, ret = 0;
194
        pid_t my_pid;
195
        FILE *f = NULL;
196
        Set *allocated_set = NULL;
197
198
199
200
201
202
203
204
205

        assert(controller);
        assert(path);
        assert(sig >= 0);

        /* This goes through the tasks list and kills them all. This
         * is repeated until no further processes are added to the
         * tasks list, to properly handle forking processes */

206
207
208
        if (!s)
                if (!(s = allocated_set = set_new(trivial_hash_func, trivial_compare_func)))
                        return -ENOMEM;
209
210
211
212

        my_pid = getpid();

        do {
Lennart Poettering's avatar
Lennart Poettering committed
213
                pid_t pid = 0;
214
215
                done = true;

216
                if ((r = cg_enumerate_processes(controller, path, &f)) < 0) {
217
                        if (ret >= 0 && r != -ENOENT)
218
219
                                ret = r;

220
                        goto finish;
221
                }
222
223

                while ((r = cg_read_pid(f, &pid)) > 0) {
224
225

                        if (pid == my_pid && ignore_self)
226
                                continue;
227

228
229
                        if (set_get(s, LONG_TO_PTR(pid)) == LONG_TO_PTR(pid))
                                continue;
230
231
232

                        /* If we haven't killed this process yet, kill
                         * it */
233
234
                        if (kill(pid, sig) < 0) {
                                if (ret >= 0 && errno != ESRCH)
235
                                        ret = -errno;
236
237
238
239
240
                        } else if (ret == 0) {

                                if (sigcont)
                                        kill(pid, SIGCONT);

241
                                ret = 1;
242
                        }
243
244
245

                        done = false;

246
247
248
249
250
251
252
253
254
255
256
257
258
                        if ((r = set_put(s, LONG_TO_PTR(pid))) < 0) {
                                if (ret >= 0)
                                        ret = r;

                                goto finish;
                        }
                }

                if (r < 0) {
                        if (ret >= 0)
                                ret = r;

                        goto finish;
259
260
                }

261
262
                fclose(f);
                f = NULL;
263
264
265
266
267

                /* To avoid racing against processes which fork
                 * quicker than we can kill them we repeat this until
                 * no new pids need to be killed. */

268
        } while (!done);
269

270
finish:
271
272
        if (allocated_set)
                set_free(allocated_set);
273

274
275
        if (f)
                fclose(f);
276

277
        return ret;
278
279
}

280
int cg_kill_recursive(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, bool rem, Set *s) {
281
282
283
        int r, ret = 0;
        DIR *d = NULL;
        char *fn;
284
        Set *allocated_set = NULL;
285
286
287
288
289

        assert(path);
        assert(controller);
        assert(sig >= 0);

290
291
292
293
        if (!s)
                if (!(s = allocated_set = set_new(trivial_hash_func, trivial_compare_func)))
                        return -ENOMEM;

294
        ret = cg_kill(controller, path, sig, sigcont, ignore_self, s);
295

296
        if ((r = cg_enumerate_subgroups(controller, path, &d)) < 0) {
297
                if (ret >= 0 && r != -ENOENT)
298
                        ret = r;
299

300
301
                goto finish;
        }
302

303
304
        while ((r = cg_read_subgroup(d, &fn)) > 0) {
                char *p = NULL;
305

306
307
308
309
310
311
                r = asprintf(&p, "%s/%s", path, fn);
                free(fn);

                if (r < 0) {
                        if (ret >= 0)
                                ret = -ENOMEM;
312

313
314
                        goto finish;
                }
315

316
                r = cg_kill_recursive(controller, p, sig, sigcont, ignore_self, rem, s);
317
                free(p);
318

319
320
                if (r != 0 && ret >= 0)
                        ret = r;
321
322
        }

323
324
325
326
        if (r < 0 && ret >= 0)
                ret = r;

        if (rem)
327
                if ((r = cg_rmdir(controller, path, true)) < 0) {
328
329
330
                        if (ret >= 0 &&
                            r != -ENOENT &&
                            r != -EBUSY)
331
332
                                ret = r;
                }
333

334
335
336
finish:
        if (d)
                closedir(d);
337

338
339
340
        if (allocated_set)
                set_free(allocated_set);

341
342
343
        return ret;
}

344
int cg_kill_recursive_and_wait(const char *controller, const char *path, bool rem) {
345
346
347
348
349
350
        unsigned i;

        assert(path);
        assert(controller);

        /* This safely kills all processes; first it sends a SIGTERM,
351
352
353
354
         * then checks 8 times after 200ms whether the group is now
         * empty, then kills everything that is left with SIGKILL and
         * finally checks 5 times after 200ms each whether the group
         * is finally empty. */
355

356
        for (i = 0; i < 15; i++) {
Lennart Poettering's avatar
Lennart Poettering committed
357
                int sig, r;
358
359
360

                if (i <= 0)
                        sig = SIGTERM;
361
                else if (i == 9)
362
363
364
365
                        sig = SIGKILL;
                else
                        sig = 0;

366
                if ((r = cg_kill_recursive(controller, path, sig, true, true, rem, NULL)) <= 0)
367
368
                        return r;

369
                usleep(200 * USEC_PER_MSEC);
370
371
372
373
374
375
        }

        return 0;
}

int cg_migrate(const char *controller, const char *from, const char *to, bool ignore_self) {
376
377
        bool done = false;
        Set *s;
378
379
        int r, ret = 0;
        pid_t my_pid;
380
        FILE *f = NULL;
381
382
383
384
385

        assert(controller);
        assert(from);
        assert(to);

386
387
388
        if (!(s = set_new(trivial_hash_func, trivial_compare_func)))
                return -ENOMEM;

389
390
391
        my_pid = getpid();

        do {
Lennart Poettering's avatar
Lennart Poettering committed
392
                pid_t pid = 0;
393
394
                done = true;

395
                if ((r = cg_enumerate_tasks(controller, from, &f)) < 0) {
396
                        if (ret >= 0 && r != -ENOENT)
397
398
                                ret = r;

399
                        goto finish;
400
                }
401
402

                while ((r = cg_read_pid(f, &pid)) > 0) {
403

404
405
406
                        /* This might do weird stuff if we aren't a
                         * single-threaded program. However, we
                         * luckily know we are not */
407
                        if (pid == my_pid && ignore_self)
408
                                continue;
409

410
411
412
                        if (set_get(s, LONG_TO_PTR(pid)) == LONG_TO_PTR(pid))
                                continue;

413
                        if ((r = cg_attach(controller, to, pid)) < 0) {
414
                                if (ret >= 0 && r != -ESRCH)
415
416
417
                                        ret = r;
                        } else if (ret == 0)
                                ret = 1;
418
419

                        done = false;
420
421
422
423
424
425
426
427
428
429
430
431
432
433

                        if ((r = set_put(s, LONG_TO_PTR(pid))) < 0) {
                                if (ret >= 0)
                                        ret = r;

                                goto finish;
                        }
                }

                if (r < 0) {
                        if (ret >= 0)
                                ret = r;

                        goto finish;
434
435
                }

436
437
                fclose(f);
                f = NULL;
438

439
        } while (!done);
440

441
finish:
442
        set_free(s);
443

444
445
        if (f)
                fclose(f);
446

447
        return ret;
448
449
}

450
451
452
453
int cg_migrate_recursive(const char *controller, const char *from, const char *to, bool ignore_self, bool rem) {
        int r, ret = 0;
        DIR *d = NULL;
        char *fn;
454
455
456
457
458

        assert(controller);
        assert(from);
        assert(to);

459
        ret = cg_migrate(controller, from, to, ignore_self);
460

461
        if ((r = cg_enumerate_subgroups(controller, from, &d)) < 0) {
462
                if (ret >= 0 && r != -ENOENT)
463
464
465
466
467
468
                        ret = r;
                goto finish;
        }

        while ((r = cg_read_subgroup(d, &fn)) > 0) {
                char *p = NULL;
469

470
471
                r = asprintf(&p, "%s/%s", from, fn);
                free(fn);
472

473
474
475
476
477
                if (r < 0) {
                        if (ret >= 0)
                                ret = -ENOMEM;

                        goto finish;
478
479
                }

480
                r = cg_migrate_recursive(controller, p, to, ignore_self, rem);
481
482
                free(p);

483
484
                if (r != 0 && ret >= 0)
                        ret = r;
485
486
        }

487
488
489
490
        if (r < 0 && ret >= 0)
                ret = r;

        if (rem)
491
                if ((r = cg_rmdir(controller, from, true)) < 0) {
492
493
494
                        if (ret >= 0 &&
                            r != -ENOENT &&
                            r != -EBUSY)
495
496
                                ret = r;
                }
497

498
499
500
finish:
        if (d)
                closedir(d);
501
502
503
504
505

        return ret;
}

int cg_get_path(const char *controller, const char *path, const char *suffix, char **fs) {
506
        const char *p;
507
        char *t;
508
        static __thread bool good = false;
509
510

        assert(controller);
511
512
        assert(fs);

513
        if (_unlikely_(!good)) {
514
515
                int r;

516
                r = path_is_mount_point("/sys/fs/cgroup", false);
517
518
519
520
521
522
523
524
525
526
                if (r <= 0)
                        return r < 0 ? r : -ENOENT;

                /* Cache this to save a few stat()s */
                good = true;
        }

        if (isempty(controller))
                return -EINVAL;

527
528
529
530
531
532
533
534
535
536
537
538
539
        /* This is a very minimal lookup from controller names to
         * paths. Since we have mounted most hierarchies ourselves
         * should be kinda safe, but eventually we might want to
         * extend this to have a fallback to actually check
         * /proc/mounts. Might need caching then. */

        if (streq(controller, SYSTEMD_CGROUP_CONTROLLER))
                p = "systemd";
        else if (startswith(controller, "name="))
                p = controller + 5;
        else
                p = controller;

540
        if (path && suffix)
541
                t = join("/sys/fs/cgroup/", p, "/", path, "/", suffix, NULL);
542
        else if (path)
543
                t = join("/sys/fs/cgroup/", p, "/", path, NULL);
544
        else if (suffix)
545
546
547
548
549
550
551
552
                t = join("/sys/fs/cgroup/", p, "/", suffix, NULL);
        else
                t = join("/sys/fs/cgroup/", p, NULL);

        if (!t)
                return -ENOMEM;

        path_kill_slashes(t);
553

554
555
        *fs = t;
        return 0;
556
557
}

558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
static int trim_cb(const char *path, const struct stat *sb, int typeflag, struct FTW *ftwbuf) {
        char *p;
        bool is_sticky;

        if (typeflag != FTW_DP)
                return 0;

        if (ftwbuf->level < 1)
                return 0;

        p = strappend(path, "/tasks");
        if (!p) {
                errno = ENOMEM;
                return 1;
        }

574
        is_sticky = file_is_priv_sticky(p) > 0;
575
576
577
578
579
580
581
582
583
        free(p);

        if (is_sticky)
                return 0;

        rmdir(path);
        return 0;
}

584
585
int cg_trim(const char *controller, const char *path, bool delete_root) {
        char *fs;
586
        int r = 0;
587
588
589
590

        assert(controller);
        assert(path);

591
592
        r = cg_get_path(controller, path, NULL, &fs);
        if (r < 0)
593
594
                return r;

595
596
597
598
599
600
601
602
603
604
605
606
607
608
        errno = 0;
        if (nftw(fs, trim_cb, 64, FTW_DEPTH|FTW_MOUNT|FTW_PHYS) < 0)
                r = errno ? -errno : -EIO;

        if (delete_root) {
                bool is_sticky;
                char *p;

                p = strappend(fs, "/tasks");
                if (!p) {
                        free(fs);
                        return -ENOMEM;
                }

609
                is_sticky = file_is_priv_sticky(p) > 0;
610
611
612
613
614
615
616
617
618
                free(p);

                if (!is_sticky)
                        if (rmdir(fs) < 0 && errno != ENOENT) {
                                if (r == 0)
                                        r = -errno;
                        }
        }

619
620
        free(fs);

621
        return r;
622
623
624
}

int cg_delete(const char *controller, const char *path) {
625
        char *parent;
626
627
628
629
630
        int r;

        assert(controller);
        assert(path);

631
632
        if ((r = parent_of_path(path, &parent)) < 0)
                return r;
633

634
635
        r = cg_migrate_recursive(controller, path, parent, false, true);
        free(parent);
636

637
        return r == -ENOENT ? 0 : r;
638
639
640
}

int cg_create(const char *controller, const char *path) {
641
        char *fs;
642
643
644
645
646
        int r;

        assert(controller);
        assert(path);

647
648
        if ((r = cg_get_path(controller, path, NULL, &fs)) < 0)
                return r;
649

650
651
652
653
654
655
656
657
658
659
660
        r = mkdir_parents(fs, 0755);

        if (r >= 0) {
                if (mkdir(fs, 0755) >= 0)
                        r = 1;
                else if (errno == EEXIST)
                        r = 0;
                else
                        r = -errno;
        }

661
        free(fs);
662
663
664
665
666

        return r;
}

int cg_attach(const char *controller, const char *path, pid_t pid) {
667
        char *fs;
668
        int r;
669
        char c[32];
670
671
672
673
674

        assert(controller);
        assert(path);
        assert(pid >= 0);

675
676
        if ((r = cg_get_path(controller, path, "tasks", &fs)) < 0)
                return r;
677
678
679
680

        if (pid == 0)
                pid = getpid();

681
682
        snprintf(c, sizeof(c), "%lu\n", (unsigned long) pid);
        char_array_0(c);
683

684
685
        r = write_one_line_file(fs, c);
        free(fs);
686
687
688
689
690

        return r;
}

int cg_create_and_attach(const char *controller, const char *path, pid_t pid) {
691
        int r, q;
692
693
694
695
696

        assert(controller);
        assert(path);
        assert(pid >= 0);

697
698
        if ((r = cg_create(controller, path)) < 0)
                return r;
699

700
701
        if ((q = cg_attach(controller, path, pid)) < 0)
                return q;
702

703
        /* This does not remove the cgroup on failure */
704
705
706
707
708
709
710
711
712
713
714

        return r;
}

int cg_set_group_access(const char *controller, const char *path, mode_t mode, uid_t uid, gid_t gid) {
        char *fs;
        int r;

        assert(controller);
        assert(path);

715
716
717
718
719
        if (mode != (mode_t) -1)
                mode &= 0777;

        r = cg_get_path(controller, path, NULL, &fs);
        if (r < 0)
720
721
722
723
724
725
726
727
                return r;

        r = chmod_and_chown(fs, mode, uid, gid);
        free(fs);

        return r;
}

728
int cg_set_task_access(const char *controller, const char *path, mode_t mode, uid_t uid, gid_t gid, int sticky) {
729
730
731
732
733
734
        char *fs;
        int r;

        assert(controller);
        assert(path);

735
736
737
738
739
740
741
742
        if (mode == (mode_t) -1 && uid == (uid_t) -1 && gid == (gid_t) -1 && sticky < 0)
                return 0;

        if (mode != (mode_t) -1)
                mode &= 0666;

        r = cg_get_path(controller, path, "tasks", &fs);
        if (r < 0)
743
744
                return r;

745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
        if (sticky >= 0 && mode != (mode_t) -1)
                /* Both mode and sticky param are passed */
                mode |= (sticky ? S_ISVTX : 0);
        else if ((sticky >= 0 && mode == (mode_t) -1) ||
                 (mode != (mode_t) -1 && sticky < 0)) {
                struct stat st;

                /* Only one param is passed, hence read the current
                 * mode from the file itself */

                r = lstat(fs, &st);
                if (r < 0) {
                        free(fs);
                        return -errno;
                }

                if (mode == (mode_t) -1)
                        /* No mode set, we just shall set the sticky bit */
                        mode = (st.st_mode & ~S_ISVTX) | (sticky ? S_ISVTX : 0);
                else
                        /* Only mode set, leave sticky bit untouched */
                        mode = (st.st_mode & ~0777) | mode;
        }

769
770
771
772
773
774
775
776
777
        r = chmod_and_chown(fs, mode, uid, gid);
        free(fs);

        return r;
}

int cg_get_by_pid(const char *controller, pid_t pid, char **path) {
        int r;
        char *p = NULL;
778
779
780
        FILE *f;
        char *fs;
        size_t cs;
781
782
783

        assert(controller);
        assert(path);
784
        assert(pid >= 0);
785

786
787
        if (pid == 0)
                pid = getpid();
788

789
790
        if (asprintf(&fs, "/proc/%lu/cgroup", (unsigned long) pid) < 0)
                return -ENOMEM;
791

792
793
794
        f = fopen(fs, "re");
        free(fs);

795
796
797
        if (!f)
                return errno == ENOENT ? -ESRCH : -errno;

798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
        cs = strlen(controller);

        while (!feof(f)) {
                char line[LINE_MAX];
                char *l;

                errno = 0;
                if (!(fgets(line, sizeof(line), f))) {
                        if (feof(f))
                                break;

                        r = errno ? -errno : -EIO;
                        goto finish;
                }

                truncate_nl(line);

                if (!(l = strchr(line, ':')))
                        continue;

                l++;
                if (strncmp(l, controller, cs) != 0)
                        continue;

                if (l[cs] != ':')
                        continue;

                if (!(p = strdup(l + cs + 1))) {
                        r = -ENOMEM;
                        goto finish;
                }

                *path = p;
                r = 0;
                goto finish;
        }

        r = -ENOENT;

finish:
        fclose(f);

        return r;
841
842
843
}

int cg_install_release_agent(const char *controller, const char *agent) {
844
        char *fs = NULL, *contents = NULL, *line = NULL, *sc;
845
846
847
848
849
        int r;

        assert(controller);
        assert(agent);

850
851
        if ((r = cg_get_path(controller, NULL, "release_agent", &fs)) < 0)
                return r;
852

853
        if ((r = read_one_line_file(fs, &contents)) < 0)
854
855
856
857
858
859
860
861
862
863
                goto finish;

        sc = strstrip(contents);
        if (sc[0] == 0) {

                if (asprintf(&line, "%s\n", agent) < 0) {
                        r = -ENOMEM;
                        goto finish;
                }

864
                if ((r = write_one_line_file(fs, line)) < 0)
865
866
867
868
869
870
871
                        goto finish;

        } else if (!streq(sc, agent)) {
                r = -EEXIST;
                goto finish;
        }

872
873
        free(fs);
        fs = NULL;
874
        if ((r = cg_get_path(controller, NULL, "notify_on_release", &fs)) < 0)
875
876
877
878
                goto finish;

        free(contents);
        contents = NULL;
879
        if ((r = read_one_line_file(fs, &contents)) < 0)
880
881
882
883
884
                goto finish;

        sc = strstrip(contents);

        if (streq(sc, "0")) {
885
                if ((r = write_one_line_file(fs, "1\n")) < 0)
886
                        goto finish;
887
888

                r = 1;
889
890
891
        } else if (!streq(sc, "1")) {
                r = -EIO;
                goto finish;
892
893
        } else
                r = 0;
894
895

finish:
896
        free(fs);
897
898
899
900
901
902
903
        free(contents);
        free(line);

        return r;
}

int cg_is_empty(const char *controller, const char *path, bool ignore_self) {
Lennart Poettering's avatar
Lennart Poettering committed
904
        pid_t pid = 0;
905
        int r;
Lennart Poettering's avatar
Lennart Poettering committed
906
        FILE *f = NULL;
907
        bool found = false;
908
909
910
911

        assert(controller);
        assert(path);

912
        if ((r = cg_enumerate_tasks(controller, path, &f)) < 0)
913
                return r == -ENOENT ? 1 : r;
914

915
        while ((r = cg_read_pid(f, &pid)) > 0) {
916

917
918
                if (ignore_self && pid == getpid())
                        continue;
919

920
921
                found = true;
                break;
922
923
        }

924
        fclose(f);
925

926
927
        if (r < 0)
                return r;
928

929
        return !found;
930
931
932
}

int cg_is_empty_recursive(const char *controller, const char *path, bool ignore_self) {
933
934
935
        int r;
        DIR *d = NULL;
        char *fn;
936
937
938
939

        assert(controller);
        assert(path);

940
941
942
943
        if ((r = cg_is_empty(controller, path, ignore_self)) <= 0)
                return r;

        if ((r = cg_enumerate_subgroups(controller, path, &d)) < 0)
944
                return r == -ENOENT ? 1 : r;
945

946
947
        while ((r = cg_read_subgroup(d, &fn)) > 0) {
                char *p = NULL;
948

949
950
                r = asprintf(&p, "%s/%s", path, fn);
                free(fn);
951

952
953
954
                if (r < 0) {
                        r = -ENOMEM;
                        goto finish;
955
956
                }

957
                r = cg_is_empty_recursive(controller, p, ignore_self);
958
959
                free(p);

960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
                if (r <= 0)
                        goto finish;
        }

        if (r >= 0)
                r = 1;

finish:

        if (d)
                closedir(d);

        return r;
}

int cg_split_spec(const char *spec, char **controller, char **path) {
        const char *e;
        char *t = NULL, *u = NULL;

        assert(spec);
        assert(controller || path);

        if (*spec == '/') {

                if (path) {
                        if (!(t = strdup(spec)))
                                return -ENOMEM;

                        *path = t;
989
990
                }

991
992
993
994
                if (controller)
                        *controller = NULL;

                return 0;
995
996
        }

997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
        if (!(e = strchr(spec, ':'))) {

                if (strchr(spec, '/') || spec[0] == 0)
                        return -EINVAL;

                if (controller) {
                        if (!(t = strdup(spec)))
                                return -ENOMEM;

                        *controller = t;
                }

                if (path)
                        *path = NULL;

                return 0;
1013
1014
        }

1015
1016
1017
1018
        if (e[1] != '/' ||
            e == spec ||
            memchr(spec, '/', e-spec))
                return -EINVAL;
1019

1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
        if (controller)
                if (!(t = strndup(spec, e-spec)))
                        return -ENOMEM;

        if (path)
                if (!(u = strdup(e+1))) {
                        free(t);
                        return -ENOMEM;
                }

        if (controller)
                *controller = t;

        if (path)
                *path = u;

        return 0;
1037
}
1038

1039
1040
1041
int cg_join_spec(const char *controller, const char *path, char **spec) {
        assert(controller);
        assert(path);
1042

1043
1044
1045
1046
1047
1048
1049
1050
        if (!path_is_absolute(path) ||
            controller[0] == 0 ||
            strchr(controller, ':') ||
            strchr(controller, '/'))
                return -EINVAL;

        if (asprintf(spec, "%s:%s", controller, path) < 0)
                return -ENOMEM;
1051
1052
1053

        return 0;
}
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063

int cg_fix_path(const char *path, char **result) {
        char *t, *c, *p;
        int r;

        assert(path);
        assert(result);

        /* First check if it already is a filesystem path */
        if (path_is_absolute(path) &&
1064
            path_startswith(path, "/sys/fs/cgroup") &&
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
            access(path, F_OK) >= 0) {

                if (!(t = strdup(path)))
                        return -ENOMEM;

                *result = t;
                return 0;
        }

        /* Otherwise treat it as cg spec */
        if ((r = cg_split_spec(path, &c, &p)) < 0)
                return r;

        r = cg_get_path(c ? c : SYSTEMD_CGROUP_CONTROLLER, p ? p : "/", NULL, result);
        free(c);
        free(p);

        return r;
}
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111

int cg_get_user_path(char **path) {
        char *root, *p;

        assert(path);

        /* Figure out the place to put user cgroups below. We use the
         * same as PID 1 has but with the "/system" suffix replaced by
         * "/user" */

        if (cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 1, &root) < 0)
                p = strdup("/user");
        else {
                if (endswith(root, "/system"))
                        root[strlen(root) - 7] = 0;
                else if (streq(root, "/"))
                        root[0] = 0;

                p = strappend(root, "/user");
                free(root);
        }

        if (!p)
                return -ENOMEM;

        *path = p;
        return 0;
}