LCOV - code coverage report
Current view: top level - basic - cgroup-util.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 422 1024 41.2 %
Date: 2015-07-29 18:47:03 Functions: 38 67 56.7 %

          Line data    Source code
       1             : /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
       2             : 
       3             : /***
       4             :   This file is part of systemd.
       5             : 
       6             :   Copyright 2010 Lennart Poettering
       7             : 
       8             :   systemd is free software; you can redistribute it and/or modify it
       9             :   under the terms of the GNU Lesser General Public License as published by
      10             :   the Free Software Foundation; either version 2.1 of the License, or
      11             :   (at your option) any later version.
      12             : 
      13             :   systemd is distributed in the hope that it will be useful, but
      14             :   WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
      16             :   Lesser General Public License for more details.
      17             : 
      18             :   You should have received a copy of the GNU Lesser General Public License
      19             :   along with systemd; If not, see <http://www.gnu.org/licenses/>.
      20             : ***/
      21             : 
      22             : #include <errno.h>
      23             : #include <unistd.h>
      24             : #include <signal.h>
      25             : #include <string.h>
      26             : #include <stdlib.h>
      27             : #include <dirent.h>
      28             : #include <sys/stat.h>
      29             : #include <sys/types.h>
      30             : #include <ftw.h>
      31             : 
      32             : #include "cgroup-util.h"
      33             : #include "set.h"
      34             : #include "macro.h"
      35             : #include "util.h"
      36             : #include "formats-util.h"
      37             : #include "process-util.h"
      38             : #include "path-util.h"
      39             : #include "unit-name.h"
      40             : #include "fileio.h"
      41             : #include "special.h"
      42             : #include "mkdir.h"
      43             : #include "login-util.h"
      44             : 
      45           0 : int cg_enumerate_processes(const char *controller, const char *path, FILE **_f) {
      46           0 :         _cleanup_free_ char *fs = NULL;
      47             :         FILE *f;
      48             :         int r;
      49             : 
      50           0 :         assert(_f);
      51             : 
      52           0 :         r = cg_get_path(controller, path, "cgroup.procs", &fs);
      53           0 :         if (r < 0)
      54           0 :                 return r;
      55             : 
      56           0 :         f = fopen(fs, "re");
      57           0 :         if (!f)
      58           0 :                 return -errno;
      59             : 
      60           0 :         *_f = f;
      61           0 :         return 0;
      62             : }
      63             : 
      64           0 : int cg_read_pid(FILE *f, pid_t *_pid) {
      65             :         unsigned long ul;
      66             : 
      67             :         /* Note that the cgroup.procs might contain duplicates! See
      68             :          * cgroups.txt for details. */
      69             : 
      70           0 :         assert(f);
      71           0 :         assert(_pid);
      72             : 
      73           0 :         errno = 0;
      74           0 :         if (fscanf(f, "%lu", &ul) != 1) {
      75             : 
      76           0 :                 if (feof(f))
      77           0 :                         return 0;
      78             : 
      79           0 :                 return errno ? -errno : -EIO;
      80             :         }
      81             : 
      82           0 :         if (ul <= 0)
      83           0 :                 return -EIO;
      84             : 
      85           0 :         *_pid = (pid_t) ul;
      86           0 :         return 1;
      87             : }
      88             : 
      89           0 : int cg_enumerate_subgroups(const char *controller, const char *path, DIR **_d) {
      90           0 :         _cleanup_free_ char *fs = NULL;
      91             :         int r;
      92             :         DIR *d;
      93             : 
      94           0 :         assert(_d);
      95             : 
      96             :         /* This is not recursive! */
      97             : 
      98           0 :         r = cg_get_path(controller, path, NULL, &fs);
      99           0 :         if (r < 0)
     100           0 :                 return r;
     101             : 
     102           0 :         d = opendir(fs);
     103           0 :         if (!d)
     104           0 :                 return -errno;
     105             : 
     106           0 :         *_d = d;
     107           0 :         return 0;
     108             : }
     109             : 
     110           0 : int cg_read_subgroup(DIR *d, char **fn) {
     111             :         struct dirent *de;
     112             : 
     113           0 :         assert(d);
     114           0 :         assert(fn);
     115             : 
     116           0 :         FOREACH_DIRENT(de, d, return -errno) {
     117             :                 char *b;
     118             : 
     119           0 :                 if (de->d_type != DT_DIR)
     120           0 :                         continue;
     121             : 
     122           0 :                 if (streq(de->d_name, ".") ||
     123           0 :                     streq(de->d_name, ".."))
     124           0 :                         continue;
     125             : 
     126           0 :                 b = strdup(de->d_name);
     127           0 :                 if (!b)
     128           0 :                         return -ENOMEM;
     129             : 
     130           0 :                 *fn = b;
     131           0 :                 return 1;
     132           0 :         }
     133             : 
     134           0 :         return 0;
     135             : }
     136             : 
     137           0 : int cg_rmdir(const char *controller, const char *path) {
     138           0 :         _cleanup_free_ char *p = NULL;
     139             :         int r;
     140             : 
     141           0 :         r = cg_get_path(controller, path, NULL, &p);
     142           0 :         if (r < 0)
     143           0 :                 return r;
     144             : 
     145           0 :         r = rmdir(p);
     146           0 :         if (r < 0 && errno != ENOENT)
     147           0 :                 return -errno;
     148             : 
     149           0 :         return 0;
     150             : }
     151             : 
     152           0 : int cg_kill(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, Set *s) {
     153           0 :         _cleanup_set_free_ Set *allocated_set = NULL;
     154           0 :         bool done = false;
     155           0 :         int r, ret = 0;
     156             :         pid_t my_pid;
     157             : 
     158           0 :         assert(sig >= 0);
     159             : 
     160             :         /* This goes through the tasks list and kills them all. This
     161             :          * is repeated until no further processes are added to the
     162             :          * tasks list, to properly handle forking processes */
     163             : 
     164           0 :         if (!s) {
     165           0 :                 s = allocated_set = set_new(NULL);
     166           0 :                 if (!s)
     167           0 :                         return -ENOMEM;
     168             :         }
     169             : 
     170           0 :         my_pid = getpid();
     171             : 
     172             :         do {
     173           0 :                 _cleanup_fclose_ FILE *f = NULL;
     174           0 :                 pid_t pid = 0;
     175           0 :                 done = true;
     176             : 
     177           0 :                 r = cg_enumerate_processes(controller, path, &f);
     178           0 :                 if (r < 0) {
     179           0 :                         if (ret >= 0 && r != -ENOENT)
     180           0 :                                 return r;
     181             : 
     182           0 :                         return ret;
     183             :                 }
     184             : 
     185           0 :                 while ((r = cg_read_pid(f, &pid)) > 0) {
     186             : 
     187           0 :                         if (ignore_self && pid == my_pid)
     188           0 :                                 continue;
     189             : 
     190           0 :                         if (set_get(s, LONG_TO_PTR(pid)) == LONG_TO_PTR(pid))
     191           0 :                                 continue;
     192             : 
     193             :                         /* If we haven't killed this process yet, kill
     194             :                          * it */
     195           0 :                         if (kill(pid, sig) < 0) {
     196           0 :                                 if (ret >= 0 && errno != ESRCH)
     197           0 :                                         ret = -errno;
     198             :                         } else {
     199           0 :                                 if (sigcont && sig != SIGKILL)
     200           0 :                                         kill(pid, SIGCONT);
     201             : 
     202           0 :                                 if (ret == 0)
     203           0 :                                         ret = 1;
     204             :                         }
     205             : 
     206           0 :                         done = false;
     207             : 
     208           0 :                         r = set_put(s, LONG_TO_PTR(pid));
     209           0 :                         if (r < 0) {
     210           0 :                                 if (ret >= 0)
     211           0 :                                         return r;
     212             : 
     213           0 :                                 return ret;
     214             :                         }
     215             :                 }
     216             : 
     217           0 :                 if (r < 0) {
     218           0 :                         if (ret >= 0)
     219           0 :                                 return r;
     220             : 
     221           0 :                         return ret;
     222             :                 }
     223             : 
     224             :                 /* To avoid racing against processes which fork
     225             :                  * quicker than we can kill them we repeat this until
     226             :                  * no new pids need to be killed. */
     227             : 
     228           0 :         } while (!done);
     229             : 
     230           0 :         return ret;
     231             : }
     232             : 
     233           0 : int cg_kill_recursive(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, bool rem, Set *s) {
     234           0 :         _cleanup_set_free_ Set *allocated_set = NULL;
     235           0 :         _cleanup_closedir_ DIR *d = NULL;
     236           0 :         int r, ret = 0;
     237             :         char *fn;
     238             : 
     239           0 :         assert(path);
     240           0 :         assert(sig >= 0);
     241             : 
     242           0 :         if (!s) {
     243           0 :                 s = allocated_set = set_new(NULL);
     244           0 :                 if (!s)
     245           0 :                         return -ENOMEM;
     246             :         }
     247             : 
     248           0 :         ret = cg_kill(controller, path, sig, sigcont, ignore_self, s);
     249             : 
     250           0 :         r = cg_enumerate_subgroups(controller, path, &d);
     251           0 :         if (r < 0) {
     252           0 :                 if (ret >= 0 && r != -ENOENT)
     253           0 :                         return r;
     254             : 
     255           0 :                 return ret;
     256             :         }
     257             : 
     258           0 :         while ((r = cg_read_subgroup(d, &fn)) > 0) {
     259           0 :                 _cleanup_free_ char *p = NULL;
     260             : 
     261           0 :                 p = strjoin(path, "/", fn, NULL);
     262           0 :                 free(fn);
     263           0 :                 if (!p)
     264           0 :                         return -ENOMEM;
     265             : 
     266           0 :                 r = cg_kill_recursive(controller, p, sig, sigcont, ignore_self, rem, s);
     267           0 :                 if (ret >= 0 && r != 0)
     268           0 :                         ret = r;
     269             :         }
     270             : 
     271           0 :         if (ret >= 0 && r < 0)
     272           0 :                 ret = r;
     273             : 
     274           0 :         if (rem) {
     275           0 :                 r = cg_rmdir(controller, path);
     276           0 :                 if (r < 0 && ret >= 0 && r != -ENOENT && r != -EBUSY)
     277           0 :                         return r;
     278             :         }
     279             : 
     280           0 :         return ret;
     281             : }
     282             : 
     283           0 : int cg_migrate(const char *cfrom, const char *pfrom, const char *cto, const char *pto, bool ignore_self) {
     284           0 :         bool done = false;
     285           0 :         _cleanup_set_free_ Set *s = NULL;
     286           0 :         int r, ret = 0;
     287             :         pid_t my_pid;
     288             : 
     289           0 :         assert(cfrom);
     290           0 :         assert(pfrom);
     291           0 :         assert(cto);
     292           0 :         assert(pto);
     293             : 
     294           0 :         s = set_new(NULL);
     295           0 :         if (!s)
     296           0 :                 return -ENOMEM;
     297             : 
     298           0 :         my_pid = getpid();
     299             : 
     300             :         do {
     301           0 :                 _cleanup_fclose_ FILE *f = NULL;
     302           0 :                 pid_t pid = 0;
     303           0 :                 done = true;
     304             : 
     305           0 :                 r = cg_enumerate_processes(cfrom, pfrom, &f);
     306           0 :                 if (r < 0) {
     307           0 :                         if (ret >= 0 && r != -ENOENT)
     308           0 :                                 return r;
     309             : 
     310           0 :                         return ret;
     311             :                 }
     312             : 
     313           0 :                 while ((r = cg_read_pid(f, &pid)) > 0) {
     314             : 
     315             :                         /* This might do weird stuff if we aren't a
     316             :                          * single-threaded program. However, we
     317             :                          * luckily know we are not */
     318           0 :                         if (ignore_self && pid == my_pid)
     319           0 :                                 continue;
     320             : 
     321           0 :                         if (set_get(s, LONG_TO_PTR(pid)) == LONG_TO_PTR(pid))
     322           0 :                                 continue;
     323             : 
     324           0 :                         r = cg_attach(cto, pto, pid);
     325           0 :                         if (r < 0) {
     326           0 :                                 if (ret >= 0 && r != -ESRCH)
     327           0 :                                         ret = r;
     328           0 :                         } else if (ret == 0)
     329           0 :                                 ret = 1;
     330             : 
     331           0 :                         done = false;
     332             : 
     333           0 :                         r = set_put(s, LONG_TO_PTR(pid));
     334           0 :                         if (r < 0) {
     335           0 :                                 if (ret >= 0)
     336           0 :                                         return r;
     337             : 
     338           0 :                                 return ret;
     339             :                         }
     340             :                 }
     341             : 
     342           0 :                 if (r < 0) {
     343           0 :                         if (ret >= 0)
     344           0 :                                 return r;
     345             : 
     346           0 :                         return ret;
     347             :                 }
     348           0 :         } while (!done);
     349             : 
     350           0 :         return ret;
     351             : }
     352             : 
     353           0 : int cg_migrate_recursive(
     354             :                 const char *cfrom,
     355             :                 const char *pfrom,
     356             :                 const char *cto,
     357             :                 const char *pto,
     358             :                 bool ignore_self,
     359             :                 bool rem) {
     360             : 
     361           0 :         _cleanup_closedir_ DIR *d = NULL;
     362           0 :         int r, ret = 0;
     363             :         char *fn;
     364             : 
     365           0 :         assert(cfrom);
     366           0 :         assert(pfrom);
     367           0 :         assert(cto);
     368           0 :         assert(pto);
     369             : 
     370           0 :         ret = cg_migrate(cfrom, pfrom, cto, pto, ignore_self);
     371             : 
     372           0 :         r = cg_enumerate_subgroups(cfrom, pfrom, &d);
     373           0 :         if (r < 0) {
     374           0 :                 if (ret >= 0 && r != -ENOENT)
     375           0 :                         return r;
     376             : 
     377           0 :                 return ret;
     378             :         }
     379             : 
     380           0 :         while ((r = cg_read_subgroup(d, &fn)) > 0) {
     381           0 :                 _cleanup_free_ char *p = NULL;
     382             : 
     383           0 :                 p = strjoin(pfrom, "/", fn, NULL);
     384           0 :                 free(fn);
     385           0 :                 if (!p) {
     386           0 :                         if (ret >= 0)
     387           0 :                                 return -ENOMEM;
     388             : 
     389           0 :                         return ret;
     390             :                 }
     391             : 
     392           0 :                 r = cg_migrate_recursive(cfrom, p, cto, pto, ignore_self, rem);
     393           0 :                 if (r != 0 && ret >= 0)
     394           0 :                         ret = r;
     395             :         }
     396             : 
     397           0 :         if (r < 0 && ret >= 0)
     398           0 :                 ret = r;
     399             : 
     400           0 :         if (rem) {
     401           0 :                 r = cg_rmdir(cfrom, pfrom);
     402           0 :                 if (r < 0 && ret >= 0 && r != -ENOENT && r != -EBUSY)
     403           0 :                         return r;
     404             :         }
     405             : 
     406           0 :         return ret;
     407             : }
     408             : 
     409           0 : int cg_migrate_recursive_fallback(
     410             :                 const char *cfrom,
     411             :                 const char *pfrom,
     412             :                 const char *cto,
     413             :                 const char *pto,
     414             :                 bool ignore_self,
     415             :                 bool rem) {
     416             : 
     417             :         int r;
     418             : 
     419           0 :         assert(cfrom);
     420           0 :         assert(pfrom);
     421           0 :         assert(cto);
     422           0 :         assert(pto);
     423             : 
     424           0 :         r = cg_migrate_recursive(cfrom, pfrom, cto, pto, ignore_self, rem);
     425           0 :         if (r < 0) {
     426           0 :                 char prefix[strlen(pto) + 1];
     427             : 
     428             :                 /* This didn't work? Then let's try all prefixes of the destination */
     429             : 
     430           0 :                 PATH_FOREACH_PREFIX(prefix, pto) {
     431           0 :                         r = cg_migrate_recursive(cfrom, pfrom, cto, prefix, ignore_self, rem);
     432           0 :                         if (r >= 0)
     433           0 :                                 break;
     434             :                 }
     435             :         }
     436             : 
     437           0 :         return 0;
     438             : }
     439             : 
     440        1586 : static const char *normalize_controller(const char *controller) {
     441             : 
     442        1586 :         assert(controller);
     443             : 
     444        1586 :         if (startswith(controller, "name="))
     445           0 :                 return controller + 5;
     446             :         else
     447        1586 :                 return controller;
     448             : }
     449             : 
     450          70 : static int join_path(const char *controller, const char *path, const char *suffix, char **fs) {
     451          70 :         char *t = NULL;
     452             : 
     453          70 :         if (!isempty(controller)) {
     454          70 :                 if (!isempty(path) && !isempty(suffix))
     455           6 :                         t = strjoin("/sys/fs/cgroup/", controller, "/", path, "/", suffix, NULL);
     456          64 :                 else if (!isempty(path))
     457          64 :                         t = strjoin("/sys/fs/cgroup/", controller, "/", path, NULL);
     458           0 :                 else if (!isempty(suffix))
     459           0 :                         t = strjoin("/sys/fs/cgroup/", controller, "/", suffix, NULL);
     460             :                 else
     461           0 :                         t = strappend("/sys/fs/cgroup/", controller);
     462             :         } else {
     463           0 :                 if (!isempty(path) && !isempty(suffix))
     464           0 :                         t = strjoin(path, "/", suffix, NULL);
     465           0 :                 else if (!isempty(path))
     466           0 :                         t = strdup(path);
     467             :                 else
     468           0 :                         return -EINVAL;
     469             :         }
     470             : 
     471          70 :         if (!t)
     472           0 :                 return -ENOMEM;
     473             : 
     474          70 :         *fs = path_kill_slashes(t);
     475          70 :         return 0;
     476             : }
     477             : 
     478          52 : int cg_get_path(const char *controller, const char *path, const char *suffix, char **fs) {
     479             :         const char *p;
     480             :         static thread_local bool good = false;
     481             : 
     482          52 :         assert(fs);
     483             : 
     484          52 :         if (controller && !cg_controller_is_valid(controller))
     485           0 :                 return -EINVAL;
     486             : 
     487          52 :         if (_unlikely_(!good)) {
     488             :                 int r;
     489             : 
     490           5 :                 r = path_is_mount_point("/sys/fs/cgroup", 0);
     491           5 :                 if (r < 0)
     492           0 :                         return r;
     493           5 :                 if (r == 0)
     494           0 :                         return -ENOENT;
     495             : 
     496             :                 /* Cache this to save a few stat()s */
     497           5 :                 good = true;
     498             :         }
     499             : 
     500          52 :         p = controller ? normalize_controller(controller) : NULL;
     501             : 
     502          52 :         return join_path(p, path, suffix, fs);
     503             : }
     504             : 
     505          91 : static int check_hierarchy(const char *p) {
     506             :         const char *cc;
     507             : 
     508          91 :         assert(p);
     509             : 
     510          91 :         if (!filename_is_valid(p))
     511           0 :                 return 0;
     512             : 
     513             :         /* Check if this controller actually really exists */
     514          91 :         cc = strjoina("/sys/fs/cgroup/", p);
     515          91 :         if (laccess(cc, F_OK) < 0)
     516          17 :                 return -errno;
     517             : 
     518          74 :         return 0;
     519             : }
     520             : 
     521          18 : int cg_get_path_and_check(const char *controller, const char *path, const char *suffix, char **fs) {
     522             :         const char *p;
     523             :         int r;
     524             : 
     525          18 :         assert(fs);
     526             : 
     527          18 :         if (!cg_controller_is_valid(controller))
     528           0 :                 return -EINVAL;
     529             : 
     530             :         /* Normalize the controller syntax */
     531          18 :         p = normalize_controller(controller);
     532             : 
     533             :         /* Check if this controller actually really exists */
     534          18 :         r = check_hierarchy(p);
     535          18 :         if (r < 0)
     536           0 :                 return r;
     537             : 
     538          18 :         return join_path(p, path, suffix, fs);
     539             : }
     540             : 
     541          55 : static int trim_cb(const char *path, const struct stat *sb, int typeflag, struct FTW *ftwbuf) {
     542          55 :         assert(path);
     543          55 :         assert(sb);
     544          55 :         assert(ftwbuf);
     545             : 
     546          55 :         if (typeflag != FTW_DP)
     547          44 :                 return 0;
     548             : 
     549          11 :         if (ftwbuf->level < 1)
     550          11 :                 return 0;
     551             : 
     552           0 :         rmdir(path);
     553           0 :         return 0;
     554             : }
     555             : 
     556          41 : int cg_trim(const char *controller, const char *path, bool delete_root) {
     557          82 :         _cleanup_free_ char *fs = NULL;
     558          41 :         int r = 0;
     559             : 
     560          41 :         assert(path);
     561             : 
     562          41 :         r = cg_get_path(controller, path, NULL, &fs);
     563          41 :         if (r < 0)
     564           0 :                 return r;
     565             : 
     566          41 :         errno = 0;
     567          41 :         if (nftw(fs, trim_cb, 64, FTW_DEPTH|FTW_MOUNT|FTW_PHYS) != 0)
     568          30 :                 r = errno ? -errno : -EIO;
     569             : 
     570          41 :         if (delete_root) {
     571          30 :                 if (rmdir(fs) < 0 && errno != ENOENT)
     572           0 :                         return -errno;
     573             :         }
     574             : 
     575          41 :         return r;
     576             : }
     577             : 
     578           0 : int cg_delete(const char *controller, const char *path) {
     579           0 :         _cleanup_free_ char *parent = NULL;
     580             :         int r;
     581             : 
     582           0 :         assert(path);
     583             : 
     584           0 :         r = path_get_parent(path, &parent);
     585           0 :         if (r < 0)
     586           0 :                 return r;
     587             : 
     588           0 :         r = cg_migrate_recursive(controller, path, controller, parent, false, true);
     589           0 :         return r == -ENOENT ? 0 : r;
     590             : }
     591             : 
     592          12 : int cg_create(const char *controller, const char *path) {
     593          24 :         _cleanup_free_ char *fs = NULL;
     594             :         int r;
     595             : 
     596          12 :         r = cg_get_path_and_check(controller, path, NULL, &fs);
     597          12 :         if (r < 0)
     598           0 :                 return r;
     599             : 
     600          12 :         r = mkdir_parents(fs, 0755);
     601          12 :         if (r < 0)
     602           0 :                 return r;
     603             : 
     604          12 :         if (mkdir(fs, 0755) < 0) {
     605             : 
     606          12 :                 if (errno == EEXIST)
     607           6 :                         return 0;
     608             : 
     609           6 :                 return -errno;
     610             :         }
     611             : 
     612           0 :         return 1;
     613             : }
     614             : 
     615           0 : int cg_create_and_attach(const char *controller, const char *path, pid_t pid) {
     616             :         int r, q;
     617             : 
     618           0 :         assert(pid >= 0);
     619             : 
     620           0 :         r = cg_create(controller, path);
     621           0 :         if (r < 0)
     622           0 :                 return r;
     623             : 
     624           0 :         q = cg_attach(controller, path, pid);
     625           0 :         if (q < 0)
     626           0 :                 return q;
     627             : 
     628             :         /* This does not remove the cgroup on failure */
     629           0 :         return r;
     630             : }
     631             : 
     632           6 : int cg_attach(const char *controller, const char *path, pid_t pid) {
     633          12 :         _cleanup_free_ char *fs = NULL;
     634             :         char c[DECIMAL_STR_MAX(pid_t) + 2];
     635             :         int r;
     636             : 
     637           6 :         assert(path);
     638           6 :         assert(pid >= 0);
     639             : 
     640           6 :         r = cg_get_path_and_check(controller, path, "cgroup.procs", &fs);
     641           6 :         if (r < 0)
     642           0 :                 return r;
     643             : 
     644           6 :         if (pid == 0)
     645           0 :                 pid = getpid();
     646             : 
     647           6 :         snprintf(c, sizeof(c), PID_FMT"\n", pid);
     648             : 
     649           6 :         return write_string_file(fs, c, 0);
     650             : }
     651             : 
     652           0 : int cg_attach_fallback(const char *controller, const char *path, pid_t pid) {
     653             :         int r;
     654             : 
     655           0 :         assert(controller);
     656           0 :         assert(path);
     657           0 :         assert(pid >= 0);
     658             : 
     659           0 :         r = cg_attach(controller, path, pid);
     660           0 :         if (r < 0) {
     661           0 :                 char prefix[strlen(path) + 1];
     662             : 
     663             :                 /* This didn't work? Then let's try all prefixes of
     664             :                  * the destination */
     665             : 
     666           0 :                 PATH_FOREACH_PREFIX(prefix, path) {
     667           0 :                         r = cg_attach(controller, prefix, pid);
     668           0 :                         if (r >= 0)
     669           0 :                                 break;
     670             :                 }
     671             :         }
     672             : 
     673           0 :         return 0;
     674             : }
     675             : 
     676           0 : int cg_set_group_access(
     677             :                 const char *controller,
     678             :                 const char *path,
     679             :                 mode_t mode,
     680             :                 uid_t uid,
     681             :                 gid_t gid) {
     682             : 
     683           0 :         _cleanup_free_ char *fs = NULL;
     684             :         int r;
     685             : 
     686           0 :         assert(path);
     687             : 
     688           0 :         if (mode != MODE_INVALID)
     689           0 :                 mode &= 0777;
     690             : 
     691           0 :         r = cg_get_path(controller, path, NULL, &fs);
     692           0 :         if (r < 0)
     693           0 :                 return r;
     694             : 
     695           0 :         return chmod_and_chown(fs, mode, uid, gid);
     696             : }
     697             : 
     698           0 : int cg_set_task_access(
     699             :                 const char *controller,
     700             :                 const char *path,
     701             :                 mode_t mode,
     702             :                 uid_t uid,
     703             :                 gid_t gid) {
     704             : 
     705           0 :         _cleanup_free_ char *fs = NULL, *procs = NULL;
     706             :         int r;
     707             : 
     708           0 :         assert(path);
     709             : 
     710           0 :         if (mode == MODE_INVALID && uid == UID_INVALID && gid == GID_INVALID)
     711           0 :                 return 0;
     712             : 
     713           0 :         if (mode != MODE_INVALID)
     714           0 :                 mode &= 0666;
     715             : 
     716           0 :         r = cg_get_path(controller, path, "cgroup.procs", &fs);
     717           0 :         if (r < 0)
     718           0 :                 return r;
     719             : 
     720           0 :         r = chmod_and_chown(fs, mode, uid, gid);
     721           0 :         if (r < 0)
     722           0 :                 return r;
     723             : 
     724             :         /* Compatibility, Always keep values for "tasks" in sync with
     725             :          * "cgroup.procs" */
     726           0 :         r = cg_get_path(controller, path, "tasks", &procs);
     727           0 :         if (r < 0)
     728           0 :                 return r;
     729             : 
     730           0 :         return chmod_and_chown(procs, mode, uid, gid);
     731             : }
     732             : 
     733        1518 : int cg_pid_get_path(const char *controller, pid_t pid, char **path) {
     734        3036 :         _cleanup_fclose_ FILE *f = NULL;
     735             :         char line[LINE_MAX];
     736             :         const char *fs;
     737             :         size_t cs;
     738             : 
     739        1518 :         assert(path);
     740        1518 :         assert(pid >= 0);
     741             : 
     742        1518 :         if (controller) {
     743        1516 :                 if (!cg_controller_is_valid(controller))
     744           0 :                         return -EINVAL;
     745             : 
     746        1516 :                 controller = normalize_controller(controller);
     747             :         } else
     748           2 :                 controller = SYSTEMD_CGROUP_CONTROLLER;
     749             : 
     750        1518 :         fs = procfs_file_alloca(pid, "cgroup");
     751             : 
     752        1518 :         f = fopen(fs, "re");
     753        1518 :         if (!f)
     754           0 :                 return errno == ENOENT ? -ESRCH : -errno;
     755             : 
     756        1518 :         cs = strlen(controller);
     757             : 
     758       12144 :         FOREACH_LINE(line, f, return -errno) {
     759             :                 char *l, *p, *e;
     760             :                 size_t k;
     761             :                 const char *word, *state;
     762       12144 :                 bool found = false;
     763             : 
     764       12144 :                 truncate_nl(line);
     765             : 
     766       12144 :                 l = strchr(line, ':');
     767       12144 :                 if (!l)
     768       10626 :                         continue;
     769             : 
     770       12144 :                 l++;
     771       12144 :                 e = strchr(l, ':');
     772       12144 :                 if (!e)
     773           0 :                         continue;
     774             : 
     775       12144 :                 *e = 0;
     776             : 
     777       24288 :                 FOREACH_WORD_SEPARATOR(word, k, l, ",", state) {
     778             : 
     779       13662 :                         if (k == cs && memcmp(word, controller, cs) == 0) {
     780           0 :                                 found = true;
     781           0 :                                 break;
     782             :                         }
     783             : 
     784       15180 :                         if (k == 5 + cs &&
     785        3036 :                             memcmp(word, "name=", 5) == 0 &&
     786        1518 :                             memcmp(word+5, controller, cs) == 0) {
     787        1518 :                                 found = true;
     788        1518 :                                 break;
     789             :                         }
     790             :                 }
     791             : 
     792       12144 :                 if (!found)
     793       10626 :                         continue;
     794             : 
     795        1518 :                 p = strdup(e + 1);
     796        1518 :                 if (!p)
     797        1518 :                         return -ENOMEM;
     798             : 
     799        1518 :                 *path = p;
     800        1518 :                 return 0;
     801       10626 :         }
     802             : 
     803           0 :         return -ENOENT;
     804             : }
     805             : 
     806           0 : int cg_install_release_agent(const char *controller, const char *agent) {
     807           0 :         _cleanup_free_ char *fs = NULL, *contents = NULL;
     808             :         char *sc;
     809             :         int r;
     810             : 
     811           0 :         assert(agent);
     812             : 
     813           0 :         r = cg_get_path(controller, NULL, "release_agent", &fs);
     814           0 :         if (r < 0)
     815           0 :                 return r;
     816             : 
     817           0 :         r = read_one_line_file(fs, &contents);
     818           0 :         if (r < 0)
     819           0 :                 return r;
     820             : 
     821           0 :         sc = strstrip(contents);
     822           0 :         if (sc[0] == 0) {
     823           0 :                 r = write_string_file(fs, agent, 0);
     824           0 :                 if (r < 0)
     825           0 :                         return r;
     826           0 :         } else if (!streq(sc, agent))
     827           0 :                 return -EEXIST;
     828             : 
     829           0 :         free(fs);
     830           0 :         fs = NULL;
     831           0 :         r = cg_get_path(controller, NULL, "notify_on_release", &fs);
     832           0 :         if (r < 0)
     833           0 :                 return r;
     834             : 
     835           0 :         free(contents);
     836           0 :         contents = NULL;
     837           0 :         r = read_one_line_file(fs, &contents);
     838           0 :         if (r < 0)
     839           0 :                 return r;
     840             : 
     841           0 :         sc = strstrip(contents);
     842           0 :         if (streq(sc, "0")) {
     843           0 :                 r = write_string_file(fs, "1", 0);
     844           0 :                 if (r < 0)
     845           0 :                         return r;
     846             : 
     847           0 :                 return 1;
     848             :         }
     849             : 
     850           0 :         if (!streq(sc, "1"))
     851           0 :                 return -EIO;
     852             : 
     853           0 :         return 0;
     854             : }
     855             : 
     856           0 : int cg_uninstall_release_agent(const char *controller) {
     857           0 :         _cleanup_free_ char *fs = NULL;
     858             :         int r;
     859             : 
     860           0 :         r = cg_get_path(controller, NULL, "notify_on_release", &fs);
     861           0 :         if (r < 0)
     862           0 :                 return r;
     863             : 
     864           0 :         r = write_string_file(fs, "0", 0);
     865           0 :         if (r < 0)
     866           0 :                 return r;
     867             : 
     868           0 :         free(fs);
     869           0 :         fs = NULL;
     870             : 
     871           0 :         r = cg_get_path(controller, NULL, "release_agent", &fs);
     872           0 :         if (r < 0)
     873           0 :                 return r;
     874             : 
     875           0 :         r = write_string_file(fs, "", 0);
     876           0 :         if (r < 0)
     877           0 :                 return r;
     878             : 
     879           0 :         return 0;
     880             : }
     881             : 
     882           0 : int cg_is_empty(const char *controller, const char *path, bool ignore_self) {
     883           0 :         _cleanup_fclose_ FILE *f = NULL;
     884           0 :         pid_t pid = 0, self_pid;
     885           0 :         bool found = false;
     886             :         int r;
     887             : 
     888           0 :         assert(path);
     889             : 
     890           0 :         r = cg_enumerate_processes(controller, path, &f);
     891           0 :         if (r < 0)
     892           0 :                 return r == -ENOENT ? 1 : r;
     893             : 
     894           0 :         self_pid = getpid();
     895             : 
     896           0 :         while ((r = cg_read_pid(f, &pid)) > 0) {
     897             : 
     898           0 :                 if (ignore_self && pid == self_pid)
     899           0 :                         continue;
     900             : 
     901           0 :                 found = true;
     902           0 :                 break;
     903             :         }
     904             : 
     905           0 :         if (r < 0)
     906           0 :                 return r;
     907             : 
     908           0 :         return !found;
     909             : }
     910             : 
     911           0 : int cg_is_empty_recursive(const char *controller, const char *path, bool ignore_self) {
     912           0 :         _cleanup_closedir_ DIR *d = NULL;
     913             :         char *fn;
     914             :         int r;
     915             : 
     916           0 :         assert(path);
     917             : 
     918           0 :         r = cg_is_empty(controller, path, ignore_self);
     919           0 :         if (r <= 0)
     920           0 :                 return r;
     921             : 
     922           0 :         r = cg_enumerate_subgroups(controller, path, &d);
     923           0 :         if (r < 0)
     924           0 :                 return r == -ENOENT ? 1 : r;
     925             : 
     926           0 :         while ((r = cg_read_subgroup(d, &fn)) > 0) {
     927           0 :                 _cleanup_free_ char *p = NULL;
     928             : 
     929           0 :                 p = strjoin(path, "/", fn, NULL);
     930           0 :                 free(fn);
     931           0 :                 if (!p)
     932           0 :                         return -ENOMEM;
     933             : 
     934           0 :                 r = cg_is_empty_recursive(controller, p, ignore_self);
     935           0 :                 if (r <= 0)
     936           0 :                         return r;
     937             :         }
     938             : 
     939           0 :         if (r < 0)
     940           0 :                 return r;
     941             : 
     942           0 :         return 1;
     943             : }
     944             : 
     945           0 : int cg_split_spec(const char *spec, char **controller, char **path) {
     946             :         const char *e;
     947           0 :         char *t = NULL, *u = NULL;
     948           0 :         _cleanup_free_ char *v = NULL;
     949             : 
     950           0 :         assert(spec);
     951             : 
     952           0 :         if (*spec == '/') {
     953           0 :                 if (!path_is_safe(spec))
     954           0 :                         return -EINVAL;
     955             : 
     956           0 :                 if (path) {
     957           0 :                         t = strdup(spec);
     958           0 :                         if (!t)
     959           0 :                                 return -ENOMEM;
     960             : 
     961           0 :                         *path = path_kill_slashes(t);
     962             :                 }
     963             : 
     964           0 :                 if (controller)
     965           0 :                         *controller = NULL;
     966             : 
     967           0 :                 return 0;
     968             :         }
     969             : 
     970           0 :         e = strchr(spec, ':');
     971           0 :         if (!e) {
     972           0 :                 if (!cg_controller_is_valid(spec))
     973           0 :                         return -EINVAL;
     974             : 
     975           0 :                 if (controller) {
     976           0 :                         t = strdup(normalize_controller(spec));
     977           0 :                         if (!t)
     978           0 :                                 return -ENOMEM;
     979             : 
     980           0 :                         *controller = t;
     981             :                 }
     982             : 
     983           0 :                 if (path)
     984           0 :                         *path = NULL;
     985             : 
     986           0 :                 return 0;
     987             :         }
     988             : 
     989           0 :         v = strndup(spec, e-spec);
     990           0 :         if (!v)
     991           0 :                 return -ENOMEM;
     992           0 :         t = strdup(normalize_controller(v));
     993           0 :         if (!t)
     994           0 :                 return -ENOMEM;
     995           0 :         if (!cg_controller_is_valid(t)) {
     996           0 :                 free(t);
     997           0 :                 return -EINVAL;
     998             :         }
     999             : 
    1000           0 :         if (streq(e+1, "")) {
    1001           0 :                 u = strdup("/");
    1002           0 :                 if (!u) {
    1003           0 :                         free(t);
    1004           0 :                         return -ENOMEM;
    1005             :                 }
    1006             :         } else {
    1007           0 :                 u = strdup(e+1);
    1008           0 :                 if (!u) {
    1009           0 :                         free(t);
    1010           0 :                         return -ENOMEM;
    1011             :                 }
    1012             : 
    1013           0 :                 if (!path_is_safe(u) ||
    1014           0 :                     !path_is_absolute(u)) {
    1015           0 :                         free(t);
    1016           0 :                         free(u);
    1017           0 :                         return -EINVAL;
    1018             :                 }
    1019             : 
    1020           0 :                 path_kill_slashes(u);
    1021             :         }
    1022             : 
    1023           0 :         if (controller)
    1024           0 :                 *controller = t;
    1025             :         else
    1026           0 :                 free(t);
    1027             : 
    1028           0 :         if (path)
    1029           0 :                 *path = u;
    1030             :         else
    1031           0 :                 free(u);
    1032             : 
    1033           0 :         return 0;
    1034             : }
    1035             : 
    1036           0 : int cg_mangle_path(const char *path, char **result) {
    1037           0 :         _cleanup_free_ char *c = NULL, *p = NULL;
    1038             :         char *t;
    1039             :         int r;
    1040             : 
    1041           0 :         assert(path);
    1042           0 :         assert(result);
    1043             : 
    1044             :         /* First, check if it already is a filesystem path */
    1045           0 :         if (path_startswith(path, "/sys/fs/cgroup")) {
    1046             : 
    1047           0 :                 t = strdup(path);
    1048           0 :                 if (!t)
    1049           0 :                         return -ENOMEM;
    1050             : 
    1051           0 :                 *result = path_kill_slashes(t);
    1052           0 :                 return 0;
    1053             :         }
    1054             : 
    1055             :         /* Otherwise, treat it as cg spec */
    1056           0 :         r = cg_split_spec(path, &c, &p);
    1057           0 :         if (r < 0)
    1058           0 :                 return r;
    1059             : 
    1060           0 :         return cg_get_path(c ? c : SYSTEMD_CGROUP_CONTROLLER, p ? p : "/", NULL, result);
    1061             : }
    1062             : 
    1063         705 : int cg_get_root_path(char **path) {
    1064             :         char *p, *e;
    1065             :         int r;
    1066             : 
    1067         705 :         assert(path);
    1068             : 
    1069         705 :         r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 1, &p);
    1070         705 :         if (r < 0)
    1071           0 :                 return r;
    1072             : 
    1073         705 :         e = endswith(p, "/" SPECIAL_SYSTEM_SLICE);
    1074         705 :         if (e)
    1075           0 :                 *e = 0;
    1076             : 
    1077         705 :         *path = p;
    1078         705 :         return 0;
    1079             : }
    1080             : 
    1081         726 : int cg_shift_path(const char *cgroup, const char *root, const char **shifted) {
    1082        1452 :         _cleanup_free_ char *rt = NULL;
    1083             :         char *p;
    1084             :         int r;
    1085             : 
    1086         726 :         assert(cgroup);
    1087         726 :         assert(shifted);
    1088             : 
    1089         726 :         if (!root) {
    1090             :                 /* If the root was specified let's use that, otherwise
    1091             :                  * let's determine it from PID 1 */
    1092             : 
    1093         700 :                 r = cg_get_root_path(&rt);
    1094         700 :                 if (r < 0)
    1095           0 :                         return r;
    1096             : 
    1097         700 :                 root = rt;
    1098             :         }
    1099             : 
    1100         726 :         p = path_startswith(cgroup, root);
    1101         726 :         if (p)
    1102         724 :                 *shifted = p - 1;
    1103             :         else
    1104           2 :                 *shifted = cgroup;
    1105             : 
    1106         726 :         return 0;
    1107             : }
    1108             : 
    1109         700 : int cg_pid_get_path_shifted(pid_t pid, const char *root, char **cgroup) {
    1110        1400 :         _cleanup_free_ char *raw = NULL;
    1111             :         const char *c;
    1112             :         int r;
    1113             : 
    1114         700 :         assert(pid >= 0);
    1115         700 :         assert(cgroup);
    1116             : 
    1117         700 :         r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &raw);
    1118         700 :         if (r < 0)
    1119           0 :                 return r;
    1120             : 
    1121         700 :         r = cg_shift_path(raw, root, &c);
    1122         700 :         if (r < 0)
    1123           0 :                 return r;
    1124             : 
    1125         700 :         if (c == raw) {
    1126         700 :                 *cgroup = raw;
    1127         700 :                 raw = NULL;
    1128             :         } else {
    1129             :                 char *n;
    1130             : 
    1131           0 :                 n = strdup(c);
    1132           0 :                 if (!n)
    1133           0 :                         return -ENOMEM;
    1134             : 
    1135           0 :                 *cgroup = n;
    1136             :         }
    1137             : 
    1138         700 :         return 0;
    1139             : }
    1140             : 
    1141         643 : int cg_path_decode_unit(const char *cgroup, char **unit){
    1142             :         char *c, *s;
    1143             :         size_t n;
    1144             : 
    1145         643 :         assert(cgroup);
    1146         643 :         assert(unit);
    1147             : 
    1148         643 :         n = strcspn(cgroup, "/");
    1149         643 :         if (n < 3)
    1150          91 :                 return -ENXIO;
    1151             : 
    1152         552 :         c = strndupa(cgroup, n);
    1153         552 :         c = cg_unescape(c);
    1154             : 
    1155         552 :         if (!unit_name_is_valid(c, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE))
    1156           8 :                 return -ENXIO;
    1157             : 
    1158         544 :         s = strdup(c);
    1159         544 :         if (!s)
    1160           0 :                 return -ENOMEM;
    1161             : 
    1162         544 :         *unit = s;
    1163         544 :         return 0;
    1164             : }
    1165             : 
    1166        1990 : static bool valid_slice_name(const char *p, size_t n) {
    1167             : 
    1168        1990 :         if (!p)
    1169           0 :                 return false;
    1170             : 
    1171        1990 :         if (n < strlen("x.slice"))
    1172         117 :                 return false;
    1173             : 
    1174        1873 :         if (memcmp(p + n - 6, ".slice", 6) == 0) {
    1175        1211 :                 char buf[n+1], *c;
    1176             : 
    1177        1211 :                 memcpy(buf, p, n);
    1178        1211 :                 buf[n] = 0;
    1179             : 
    1180        1211 :                 c = cg_unescape(buf);
    1181             : 
    1182        1211 :                 return unit_name_is_valid(c, UNIT_NAME_PLAIN);
    1183             :         }
    1184             : 
    1185         662 :         return false;
    1186             : }
    1187             : 
    1188         554 : static const char *skip_slices(const char *p) {
    1189         554 :         assert(p);
    1190             : 
    1191             :         /* Skips over all slice assignments */
    1192             : 
    1193             :         for (;;) {
    1194             :                 size_t n;
    1195             : 
    1196        1370 :                 p += strspn(p, "/");
    1197             : 
    1198        1370 :                 n = strcspn(p, "/");
    1199        1370 :                 if (!valid_slice_name(p, n))
    1200        1108 :                         return p;
    1201             : 
    1202         816 :                 p += n;
    1203         816 :         }
    1204             : }
    1205             : 
    1206         422 : int cg_path_get_unit(const char *path, char **ret) {
    1207             :         const char *e;
    1208             :         char *unit;
    1209             :         int r;
    1210             : 
    1211         422 :         assert(path);
    1212         422 :         assert(ret);
    1213             : 
    1214         422 :         e = skip_slices(path);
    1215             : 
    1216         422 :         r = cg_path_decode_unit(e, &unit);
    1217         422 :         if (r < 0)
    1218          95 :                 return r;
    1219             : 
    1220             :         /* We skipped over the slices, don't accept any now */
    1221         327 :         if (endswith(unit, ".slice")) {
    1222           0 :                 free(unit);
    1223           0 :                 return -ENXIO;
    1224             :         }
    1225             : 
    1226         327 :         *ret = unit;
    1227         327 :         return 0;
    1228             : }
    1229             : 
    1230         100 : int cg_pid_get_unit(pid_t pid, char **unit) {
    1231         200 :         _cleanup_free_ char *cgroup = NULL;
    1232             :         int r;
    1233             : 
    1234         100 :         assert(unit);
    1235             : 
    1236         100 :         r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
    1237         100 :         if (r < 0)
    1238           0 :                 return r;
    1239             : 
    1240         100 :         return cg_path_get_unit(cgroup, unit);
    1241             : }
    1242             : 
    1243             : /**
    1244             :  * Skip session-*.scope, but require it to be there.
    1245             :  */
    1246         119 : static const char *skip_session(const char *p) {
    1247             :         size_t n;
    1248             : 
    1249         119 :         if (isempty(p))
    1250           7 :                 return NULL;
    1251             : 
    1252         112 :         p += strspn(p, "/");
    1253             : 
    1254         112 :         n = strcspn(p, "/");
    1255         112 :         if (n < strlen("session-x.scope"))
    1256           7 :                 return NULL;
    1257             : 
    1258         105 :         if (memcmp(p, "session-", 8) == 0 && memcmp(p + n - 6, ".scope", 6) == 0) {
    1259          93 :                 char buf[n - 8 - 6 + 1];
    1260             : 
    1261          93 :                 memcpy(buf, p + 8, n - 8 - 6);
    1262          93 :                 buf[n - 8 - 6] = 0;
    1263             : 
    1264             :                 /* Note that session scopes never need unescaping,
    1265             :                  * since they cannot conflict with the kernel's own
    1266             :                  * names, hence we don't need to call cg_unescape()
    1267             :                  * here. */
    1268             : 
    1269          93 :                 if (!session_id_valid(buf))
    1270           0 :                         return false;
    1271             : 
    1272          93 :                 p += n;
    1273          93 :                 p += strspn(p, "/");
    1274          93 :                 return p;
    1275             :         }
    1276             : 
    1277          12 :         return NULL;
    1278             : }
    1279             : 
    1280             : /**
    1281             :  * Skip user@*.service, but require it to be there.
    1282             :  */
    1283         132 : static const char *skip_user_manager(const char *p) {
    1284             :         size_t n;
    1285             : 
    1286         132 :         if (isempty(p))
    1287           7 :                 return NULL;
    1288             : 
    1289         125 :         p += strspn(p, "/");
    1290             : 
    1291         125 :         n = strcspn(p, "/");
    1292         125 :         if (n < strlen("user@x.service"))
    1293           6 :                 return NULL;
    1294             : 
    1295         119 :         if (memcmp(p, "user@", 5) == 0 && memcmp(p + n - 8, ".service", 8) == 0) {
    1296          13 :                 char buf[n - 5 - 8 + 1];
    1297             : 
    1298          13 :                 memcpy(buf, p + 5, n - 5 - 8);
    1299          13 :                 buf[n - 5 - 8] = 0;
    1300             : 
    1301             :                 /* Note that user manager services never need unescaping,
    1302             :                  * since they cannot conflict with the kernel's own
    1303             :                  * names, hence we don't need to call cg_unescape()
    1304             :                  * here. */
    1305             : 
    1306          13 :                 if (parse_uid(buf, NULL) < 0)
    1307           0 :                         return NULL;
    1308             : 
    1309          13 :                 p += n;
    1310          13 :                 p += strspn(p, "/");
    1311             : 
    1312          13 :                 return p;
    1313             :         }
    1314             : 
    1315         106 :         return NULL;
    1316             : }
    1317             : 
    1318         132 : static const char *skip_user_prefix(const char *path) {
    1319             :         const char *e, *t;
    1320             : 
    1321         132 :         assert(path);
    1322             : 
    1323             :         /* Skip slices, if there are any */
    1324         132 :         e = skip_slices(path);
    1325             : 
    1326             :         /* Skip the user manager, if it's in the path now... */
    1327         132 :         t = skip_user_manager(e);
    1328         132 :         if (t)
    1329          13 :                 return t;
    1330             : 
    1331             :         /* Alternatively skip the user session if it is in the path... */
    1332         119 :         return skip_session(e);
    1333             : }
    1334             : 
    1335         117 : int cg_path_get_user_unit(const char *path, char **ret) {
    1336             :         const char *t;
    1337             : 
    1338         117 :         assert(path);
    1339         117 :         assert(ret);
    1340             : 
    1341         117 :         t = skip_user_prefix(path);
    1342         117 :         if (!t)
    1343          18 :                 return -ENXIO;
    1344             : 
    1345             :         /* And from here on it looks pretty much the same as for a
    1346             :          * system unit, hence let's use the same parser from here
    1347             :          * on. */
    1348          99 :         return cg_path_get_unit(t, ret);
    1349             : }
    1350             : 
    1351         100 : int cg_pid_get_user_unit(pid_t pid, char **unit) {
    1352         200 :         _cleanup_free_ char *cgroup = NULL;
    1353             :         int r;
    1354             : 
    1355         100 :         assert(unit);
    1356             : 
    1357         100 :         r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
    1358         100 :         if (r < 0)
    1359           0 :                 return r;
    1360             : 
    1361         100 :         return cg_path_get_user_unit(cgroup, unit);
    1362             : }
    1363             : 
    1364         100 : int cg_path_get_machine_name(const char *path, char **machine) {
    1365         200 :         _cleanup_free_ char *u = NULL, *sl = NULL;
    1366             :         int r;
    1367             : 
    1368         100 :         r = cg_path_get_unit(path, &u);
    1369         100 :         if (r < 0)
    1370           1 :                 return r;
    1371             : 
    1372          99 :         sl = strjoin("/run/systemd/machines/unit:", u, NULL);
    1373          99 :         if (!sl)
    1374           0 :                 return -ENOMEM;
    1375             : 
    1376          99 :         return readlink_malloc(sl, machine);
    1377             : }
    1378             : 
    1379         100 : int cg_pid_get_machine_name(pid_t pid, char **machine) {
    1380         200 :         _cleanup_free_ char *cgroup = NULL;
    1381             :         int r;
    1382             : 
    1383         100 :         assert(machine);
    1384             : 
    1385         100 :         r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
    1386         100 :         if (r < 0)
    1387           0 :                 return r;
    1388             : 
    1389         100 :         return cg_path_get_machine_name(cgroup, machine);
    1390             : }
    1391             : 
    1392         108 : int cg_path_get_session(const char *path, char **session) {
    1393         216 :         _cleanup_free_ char *unit = NULL;
    1394             :         char *start, *end;
    1395             :         int r;
    1396             : 
    1397         108 :         assert(path);
    1398             : 
    1399         108 :         r = cg_path_get_unit(path, &unit);
    1400         108 :         if (r < 0)
    1401           3 :                 return r;
    1402             : 
    1403         105 :         start = startswith(unit, "session-");
    1404         105 :         if (!start)
    1405          19 :                 return -ENXIO;
    1406          86 :         end = endswith(start, ".scope");
    1407          86 :         if (!end)
    1408           0 :                 return -ENXIO;
    1409             : 
    1410          86 :         *end = 0;
    1411          86 :         if (!session_id_valid(start))
    1412           1 :                 return -ENXIO;
    1413             : 
    1414          85 :         if (session) {
    1415             :                 char *rr;
    1416             : 
    1417          85 :                 rr = strdup(start);
    1418          85 :                 if (!rr)
    1419           0 :                         return -ENOMEM;
    1420             : 
    1421          85 :                 *session = rr;
    1422             :         }
    1423             : 
    1424          85 :         return 0;
    1425             : }
    1426             : 
    1427         100 : int cg_pid_get_session(pid_t pid, char **session) {
    1428         200 :         _cleanup_free_ char *cgroup = NULL;
    1429             :         int r;
    1430             : 
    1431         100 :         r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
    1432         100 :         if (r < 0)
    1433           0 :                 return r;
    1434             : 
    1435         100 :         return cg_path_get_session(cgroup, session);
    1436             : }
    1437             : 
    1438         107 : int cg_path_get_owner_uid(const char *path, uid_t *uid) {
    1439         214 :         _cleanup_free_ char *slice = NULL;
    1440             :         char *start, *end;
    1441             :         int r;
    1442             : 
    1443         107 :         assert(path);
    1444             : 
    1445         107 :         r = cg_path_get_slice(path, &slice);
    1446         107 :         if (r < 0)
    1447           0 :                 return r;
    1448             : 
    1449         107 :         start = startswith(slice, "user-");
    1450         107 :         if (!start)
    1451          17 :                 return -ENXIO;
    1452          90 :         end = endswith(start, ".slice");
    1453          90 :         if (!end)
    1454           0 :                 return -ENXIO;
    1455             : 
    1456          90 :         *end = 0;
    1457          90 :         if (parse_uid(start, uid) < 0)
    1458           0 :                 return -ENXIO;
    1459             : 
    1460          90 :         return 0;
    1461             : }
    1462             : 
    1463         100 : int cg_pid_get_owner_uid(pid_t pid, uid_t *uid) {
    1464         200 :         _cleanup_free_ char *cgroup = NULL;
    1465             :         int r;
    1466             : 
    1467         100 :         r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
    1468         100 :         if (r < 0)
    1469           0 :                 return r;
    1470             : 
    1471         100 :         return cg_path_get_owner_uid(cgroup, uid);
    1472             : }
    1473             : 
    1474         225 : int cg_path_get_slice(const char *p, char **slice) {
    1475         225 :         const char *e = NULL;
    1476             : 
    1477         225 :         assert(p);
    1478         225 :         assert(slice);
    1479             : 
    1480             :         /* Finds the right-most slice unit from the beginning, but
    1481             :          * stops before we come to the first non-slice unit. */
    1482             : 
    1483             :         for (;;) {
    1484             :                 size_t n;
    1485             : 
    1486         620 :                 p += strspn(p, "/");
    1487             : 
    1488         620 :                 n = strcspn(p, "/");
    1489         620 :                 if (!valid_slice_name(p, n)) {
    1490             : 
    1491         225 :                         if (!e) {
    1492             :                                 char *s;
    1493             : 
    1494          13 :                                 s = strdup("-.slice");
    1495          13 :                                 if (!s)
    1496           0 :                                         return -ENOMEM;
    1497             : 
    1498          13 :                                 *slice = s;
    1499          13 :                                 return 0;
    1500             :                         }
    1501             : 
    1502         212 :                         return cg_path_decode_unit(e, slice);
    1503             :                 }
    1504             : 
    1505         395 :                 e = p;
    1506         395 :                 p += n;
    1507         395 :         }
    1508             : }
    1509             : 
    1510         100 : int cg_pid_get_slice(pid_t pid, char **slice) {
    1511         200 :         _cleanup_free_ char *cgroup = NULL;
    1512             :         int r;
    1513             : 
    1514         100 :         assert(slice);
    1515             : 
    1516         100 :         r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
    1517         100 :         if (r < 0)
    1518           0 :                 return r;
    1519             : 
    1520         100 :         return cg_path_get_slice(cgroup, slice);
    1521             : }
    1522             : 
    1523          15 : int cg_path_get_user_slice(const char *p, char **slice) {
    1524             :         const char *t;
    1525          15 :         assert(p);
    1526          15 :         assert(slice);
    1527             : 
    1528          15 :         t = skip_user_prefix(p);
    1529          15 :         if (!t)
    1530           8 :                 return -ENXIO;
    1531             : 
    1532             :         /* And now it looks pretty much the same as for a system
    1533             :          * slice, so let's just use the same parser from here on. */
    1534           7 :         return cg_path_get_slice(t, slice);
    1535             : }
    1536             : 
    1537           0 : int cg_pid_get_user_slice(pid_t pid, char **slice) {
    1538           0 :         _cleanup_free_ char *cgroup = NULL;
    1539             :         int r;
    1540             : 
    1541           0 :         assert(slice);
    1542             : 
    1543           0 :         r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
    1544           0 :         if (r < 0)
    1545           0 :                 return r;
    1546             : 
    1547           0 :         return cg_path_get_user_slice(cgroup, slice);
    1548             : }
    1549             : 
    1550          26 : char *cg_escape(const char *p) {
    1551          26 :         bool need_prefix = false;
    1552             : 
    1553             :         /* This implements very minimal escaping for names to be used
    1554             :          * as file names in the cgroup tree: any name which might
    1555             :          * conflict with a kernel name or is prefixed with '_' is
    1556             :          * prefixed with a '_'. That way, when reading cgroup names it
    1557             :          * is sufficient to remove a single prefixing underscore if
    1558             :          * there is one. */
    1559             : 
    1560             :         /* The return value of this function (unlike cg_unescape())
    1561             :          * needs free()! */
    1562             : 
    1563          51 :         if (p[0] == 0 ||
    1564          48 :             p[0] == '_' ||
    1565          44 :             p[0] == '.' ||
    1566          42 :             streq(p, "notify_on_release") ||
    1567          42 :             streq(p, "release_agent") ||
    1568          21 :             streq(p, "tasks"))
    1569           6 :                 need_prefix = true;
    1570             :         else {
    1571             :                 const char *dot;
    1572             : 
    1573          20 :                 dot = strrchr(p, '.');
    1574          20 :                 if (dot) {
    1575             : 
    1576          19 :                         if (dot - p == 6 && memcmp(p, "cgroup", 6) == 0)
    1577           1 :                                 need_prefix = true;
    1578             :                         else {
    1579             :                                 char *n;
    1580             : 
    1581          18 :                                 n = strndupa(p, dot - p);
    1582             : 
    1583          18 :                                 if (check_hierarchy(n) >= 0)
    1584           1 :                                         need_prefix = true;
    1585             :                         }
    1586             :                 }
    1587             :         }
    1588             : 
    1589          26 :         if (need_prefix)
    1590           8 :                 return strappend("_", p);
    1591             :         else
    1592          18 :                 return strdup(p);
    1593             : }
    1594             : 
    1595        1773 : char *cg_unescape(const char *p) {
    1596        1773 :         assert(p);
    1597             : 
    1598             :         /* The return value of this function (unlike cg_escape())
    1599             :          * doesn't need free()! */
    1600             : 
    1601        1773 :         if (p[0] == '_')
    1602          11 :                 return (char*) p+1;
    1603             : 
    1604        1762 :         return (char*) p;
    1605             : }
    1606             : 
    1607             : #define CONTROLLER_VALID                        \
    1608             :         DIGITS LETTERS                          \
    1609             :         "_"
    1610             : 
    1611        1596 : bool cg_controller_is_valid(const char *p) {
    1612             :         const char *t, *s;
    1613             : 
    1614        1596 :         if (!p)
    1615           0 :                 return false;
    1616             : 
    1617        1596 :         s = startswith(p, "name=");
    1618        1596 :         if (s)
    1619           2 :                 p = s;
    1620             : 
    1621        1596 :         if (*p == 0 || *p == '_')
    1622           4 :                 return false;
    1623             : 
    1624       12674 :         for (t = p; *t; t++)
    1625       11085 :                 if (!strchr(CONTROLLER_VALID, *t))
    1626           3 :                         return false;
    1627             : 
    1628        1589 :         if (t - p > FILENAME_MAX)
    1629           0 :                 return false;
    1630             : 
    1631        1589 :         return true;
    1632             : }
    1633             : 
    1634          13 : int cg_slice_to_path(const char *unit, char **ret) {
    1635          26 :         _cleanup_free_ char *p = NULL, *s = NULL, *e = NULL;
    1636             :         const char *dash;
    1637             :         int r;
    1638             : 
    1639          13 :         assert(unit);
    1640          13 :         assert(ret);
    1641             : 
    1642          13 :         if (streq(unit, "-.slice")) {
    1643             :                 char *x;
    1644             : 
    1645           1 :                 x = strdup("");
    1646           1 :                 if (!x)
    1647           0 :                         return -ENOMEM;
    1648           1 :                 *ret = x;
    1649           1 :                 return 0;
    1650             :         }
    1651             : 
    1652          12 :         if (!unit_name_is_valid(unit, UNIT_NAME_PLAIN))
    1653           2 :                 return -EINVAL;
    1654             : 
    1655          10 :         if (!endswith(unit, ".slice"))
    1656           1 :                 return -EINVAL;
    1657             : 
    1658           9 :         r = unit_name_to_prefix(unit, &p);
    1659           9 :         if (r < 0)
    1660           0 :                 return r;
    1661             : 
    1662           9 :         dash = strchr(p, '-');
    1663             : 
    1664             :         /* Don't allow initial dashes */
    1665           9 :         if (dash == p)
    1666           3 :                 return -EINVAL;
    1667             : 
    1668          18 :         while (dash) {
    1669          16 :                 _cleanup_free_ char *escaped = NULL;
    1670           8 :                 char n[dash - p + sizeof(".slice")];
    1671             : 
    1672             :                 /* Don't allow trailing or double dashes */
    1673           8 :                 if (dash[1] == 0 || dash[1] == '-')
    1674           2 :                         return -EINVAL;
    1675             : 
    1676           6 :                 strcpy(stpncpy(n, p, dash - p), ".slice");
    1677           6 :                 if (!unit_name_is_valid(n, UNIT_NAME_PLAIN))
    1678           0 :                         return -EINVAL;
    1679             : 
    1680           6 :                 escaped = cg_escape(n);
    1681           6 :                 if (!escaped)
    1682           0 :                         return -ENOMEM;
    1683             : 
    1684           6 :                 if (!strextend(&s, escaped, "/", NULL))
    1685           0 :                         return -ENOMEM;
    1686             : 
    1687           6 :                 dash = strchr(dash+1, '-');
    1688             :         }
    1689             : 
    1690           4 :         e = cg_escape(unit);
    1691           4 :         if (!e)
    1692           0 :                 return -ENOMEM;
    1693             : 
    1694           4 :         if (!strextend(&s, e, NULL))
    1695           0 :                 return -ENOMEM;
    1696             : 
    1697           4 :         *ret = s;
    1698           4 :         s = NULL;
    1699             : 
    1700           4 :         return 0;
    1701             : }
    1702             : 
    1703           0 : int cg_set_attribute(const char *controller, const char *path, const char *attribute, const char *value) {
    1704           0 :         _cleanup_free_ char *p = NULL;
    1705             :         int r;
    1706             : 
    1707           0 :         r = cg_get_path(controller, path, attribute, &p);
    1708           0 :         if (r < 0)
    1709           0 :                 return r;
    1710             : 
    1711           0 :         return write_string_file(p, value, 0);
    1712             : }
    1713             : 
    1714           0 : int cg_get_attribute(const char *controller, const char *path, const char *attribute, char **ret) {
    1715           0 :         _cleanup_free_ char *p = NULL;
    1716             :         int r;
    1717             : 
    1718           0 :         r = cg_get_path(controller, path, attribute, &p);
    1719           0 :         if (r < 0)
    1720           0 :                 return r;
    1721             : 
    1722           0 :         return read_one_line_file(p, ret);
    1723             : }
    1724             : 
    1725             : static const char mask_names[] =
    1726             :         "cpu\0"
    1727             :         "cpuacct\0"
    1728             :         "blkio\0"
    1729             :         "memory\0"
    1730             :         "devices\0";
    1731             : 
    1732          12 : int cg_create_everywhere(CGroupControllerMask supported, CGroupControllerMask mask, const char *path) {
    1733          12 :         CGroupControllerMask bit = 1;
    1734             :         const char *n;
    1735             :         int r;
    1736             : 
    1737             :         /* This one will create a cgroup in our private tree, but also
    1738             :          * duplicate it in the trees specified in mask, and remove it
    1739             :          * in all others */
    1740             : 
    1741             :         /* First create the cgroup in our own hierarchy. */
    1742          12 :         r = cg_create(SYSTEMD_CGROUP_CONTROLLER, path);
    1743          12 :         if (r < 0)
    1744           6 :                 return r;
    1745             : 
    1746             :         /* Then, do the same in the other hierarchies */
    1747          36 :         NULSTR_FOREACH(n, mask_names) {
    1748          30 :                 if (mask & bit)
    1749           0 :                         cg_create(n, path);
    1750          30 :                 else if (supported & bit)
    1751          30 :                         cg_trim(n, path, true);
    1752             : 
    1753          30 :                 bit <<= 1;
    1754             :         }
    1755             : 
    1756           6 :         return 0;
    1757             : }
    1758             : 
    1759           0 : int cg_attach_everywhere(CGroupControllerMask supported, const char *path, pid_t pid, cg_migrate_callback_t path_callback, void *userdata) {
    1760           0 :         CGroupControllerMask bit = 1;
    1761             :         const char *n;
    1762             :         int r;
    1763             : 
    1764           0 :         r = cg_attach(SYSTEMD_CGROUP_CONTROLLER, path, pid);
    1765           0 :         if (r < 0)
    1766           0 :                 return r;
    1767             : 
    1768           0 :         NULSTR_FOREACH(n, mask_names) {
    1769             : 
    1770           0 :                 if (supported & bit) {
    1771           0 :                         const char *p = NULL;
    1772             : 
    1773           0 :                         if (path_callback)
    1774           0 :                                 p = path_callback(bit, userdata);
    1775             : 
    1776           0 :                         if (!p)
    1777           0 :                                 p = path;
    1778             : 
    1779           0 :                         cg_attach_fallback(n, p, pid);
    1780             :                 }
    1781             : 
    1782           0 :                 bit <<= 1;
    1783             :         }
    1784             : 
    1785           0 :         return 0;
    1786             : }
    1787             : 
    1788           0 : int cg_attach_many_everywhere(CGroupControllerMask supported, const char *path, Set* pids, cg_migrate_callback_t path_callback, void *userdata) {
    1789             :         Iterator i;
    1790             :         void *pidp;
    1791           0 :         int r = 0;
    1792             : 
    1793           0 :         SET_FOREACH(pidp, pids, i) {
    1794           0 :                 pid_t pid = PTR_TO_LONG(pidp);
    1795             :                 int q;
    1796             : 
    1797           0 :                 q = cg_attach_everywhere(supported, path, pid, path_callback, userdata);
    1798           0 :                 if (q < 0)
    1799           0 :                         r = q;
    1800             :         }
    1801             : 
    1802           0 :         return r;
    1803             : }
    1804             : 
    1805           0 : int cg_migrate_everywhere(CGroupControllerMask supported, const char *from, const char *to, cg_migrate_callback_t to_callback, void *userdata) {
    1806           0 :         CGroupControllerMask bit = 1;
    1807             :         const char *n;
    1808             :         int r;
    1809             : 
    1810           0 :         if (!path_equal(from, to))  {
    1811           0 :                 r = cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, from, SYSTEMD_CGROUP_CONTROLLER, to, false, true);
    1812           0 :                 if (r < 0)
    1813           0 :                         return r;
    1814             :         }
    1815             : 
    1816           0 :         NULSTR_FOREACH(n, mask_names) {
    1817           0 :                 if (supported & bit) {
    1818           0 :                         const char *p = NULL;
    1819             : 
    1820           0 :                         if (to_callback)
    1821           0 :                                 p = to_callback(bit, userdata);
    1822             : 
    1823           0 :                         if (!p)
    1824           0 :                                 p = to;
    1825             : 
    1826           0 :                         cg_migrate_recursive_fallback(SYSTEMD_CGROUP_CONTROLLER, to, n, p, false, false);
    1827             :                 }
    1828             : 
    1829           0 :                 bit <<= 1;
    1830             :         }
    1831             : 
    1832           0 :         return 0;
    1833             : }
    1834             : 
    1835           0 : int cg_trim_everywhere(CGroupControllerMask supported, const char *path, bool delete_root) {
    1836           0 :         CGroupControllerMask bit = 1;
    1837             :         const char *n;
    1838             :         int r;
    1839             : 
    1840           0 :         r = cg_trim(SYSTEMD_CGROUP_CONTROLLER, path, delete_root);
    1841           0 :         if (r < 0)
    1842           0 :                 return r;
    1843             : 
    1844           0 :         NULSTR_FOREACH(n, mask_names) {
    1845           0 :                 if (supported & bit)
    1846           0 :                         cg_trim(n, path, delete_root);
    1847             : 
    1848           0 :                 bit <<= 1;
    1849             :         }
    1850             : 
    1851           0 :         return 0;
    1852             : }
    1853             : 
    1854          11 : CGroupControllerMask cg_mask_supported(void) {
    1855          11 :         CGroupControllerMask bit = 1, mask = 0;
    1856             :         const char *n;
    1857             : 
    1858          66 :         NULSTR_FOREACH(n, mask_names) {
    1859          55 :                 if (check_hierarchy(n) >= 0)
    1860          55 :                         mask |= bit;
    1861             : 
    1862          55 :                 bit <<= 1;
    1863             :         }
    1864             : 
    1865          11 :         return mask;
    1866             : }
    1867             : 
    1868           0 : int cg_kernel_controllers(Set *controllers) {
    1869           0 :         _cleanup_fclose_ FILE *f = NULL;
    1870             :         char buf[LINE_MAX];
    1871             :         int r;
    1872             : 
    1873           0 :         assert(controllers);
    1874             : 
    1875           0 :         f = fopen("/proc/cgroups", "re");
    1876           0 :         if (!f) {
    1877           0 :                 if (errno == ENOENT)
    1878           0 :                         return 0;
    1879           0 :                 return -errno;
    1880             :         }
    1881             : 
    1882             :         /* Ignore the header line */
    1883           0 :         (void) fgets(buf, sizeof(buf), f);
    1884             : 
    1885             :         for (;;) {
    1886             :                 char *controller;
    1887           0 :                 int enabled = 0;
    1888             : 
    1889           0 :                 errno = 0;
    1890           0 :                 if (fscanf(f, "%ms %*i %*i %i", &controller, &enabled) != 2) {
    1891             : 
    1892           0 :                         if (feof(f))
    1893           0 :                                 break;
    1894             : 
    1895           0 :                         if (ferror(f) && errno)
    1896           0 :                                 return -errno;
    1897             : 
    1898           0 :                         return -EBADMSG;
    1899             :                 }
    1900             : 
    1901           0 :                 if (!enabled) {
    1902           0 :                         free(controller);
    1903           0 :                         continue;
    1904             :                 }
    1905             : 
    1906           0 :                 if (!filename_is_valid(controller)) {
    1907           0 :                         free(controller);
    1908           0 :                         return -EBADMSG;
    1909             :                 }
    1910             : 
    1911           0 :                 r = set_consume(controllers, controller);
    1912           0 :                 if (r < 0)
    1913           0 :                         return r;
    1914           0 :         }
    1915             : 
    1916           0 :         return 0;
    1917             : }

Generated by: LCOV version 1.11