LCOV - code coverage report
Current view: top level - shared - path-lookup.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 349 471 74.1 %
Date: 2019-08-22 15:41:25 Functions: 17 21 81.0 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <errno.h>
       4             : #include <stdio.h>
       5             : #include <stdlib.h>
       6             : #include <string.h>
       7             : 
       8             : #include "alloc-util.h"
       9             : #include "fs-util.h"
      10             : #include "install.h"
      11             : #include "log.h"
      12             : #include "macro.h"
      13             : #include "mkdir.h"
      14             : #include "path-lookup.h"
      15             : #include "path-util.h"
      16             : #include "rm-rf.h"
      17             : #include "stat-util.h"
      18             : #include "string-util.h"
      19             : #include "strv.h"
      20             : #include "tmpfile-util.h"
      21             : #include "user-util.h"
      22             : #include "util.h"
      23             : 
      24          75 : int xdg_user_runtime_dir(char **ret, const char *suffix) {
      25             :         const char *e;
      26             :         char *j;
      27             : 
      28          75 :         assert(ret);
      29          75 :         assert(suffix);
      30             : 
      31          75 :         e = getenv("XDG_RUNTIME_DIR");
      32          75 :         if (!e)
      33           1 :                 return -ENXIO;
      34             : 
      35          74 :         j = strjoin(e, suffix);
      36          74 :         if (!j)
      37           0 :                 return -ENOMEM;
      38             : 
      39          74 :         *ret = j;
      40          74 :         return 0;
      41             : }
      42             : 
      43          72 : int xdg_user_config_dir(char **ret, const char *suffix) {
      44             :         const char *e;
      45             :         char *j;
      46             :         int r;
      47             : 
      48          72 :         assert(ret);
      49             : 
      50          72 :         e = getenv("XDG_CONFIG_HOME");
      51          72 :         if (e)
      52           0 :                 j = strjoin(e, suffix);
      53             :         else {
      54          72 :                 _cleanup_free_ char *home = NULL;
      55             : 
      56          72 :                 r = get_home_dir(&home);
      57          72 :                 if (r < 0)
      58           0 :                         return r;
      59             : 
      60          72 :                 j = strjoin(home, "/.config", suffix);
      61             :         }
      62             : 
      63          72 :         if (!j)
      64           0 :                 return -ENOMEM;
      65             : 
      66          72 :         *ret = j;
      67          72 :         return 0;
      68             : }
      69             : 
      70          44 : int xdg_user_data_dir(char **ret, const char *suffix) {
      71             :         const char *e;
      72             :         char *j;
      73             :         int r;
      74             : 
      75          44 :         assert(ret);
      76          44 :         assert(suffix);
      77             : 
      78             :         /* We don't treat /etc/xdg/systemd here as the spec
      79             :          * suggests because we assume that is a link to
      80             :          * /etc/systemd/ anyway. */
      81             : 
      82          44 :         e = getenv("XDG_DATA_HOME");
      83          44 :         if (e)
      84           0 :                 j = strjoin(e, suffix);
      85             :         else {
      86          44 :                 _cleanup_free_ char *home = NULL;
      87             : 
      88          44 :                 r = get_home_dir(&home);
      89          44 :                 if (r < 0)
      90           0 :                         return r;
      91             : 
      92          44 :                 j = strjoin(home, "/.local/share", suffix);
      93             :         }
      94          44 :         if (!j)
      95           0 :                 return -ENOMEM;
      96             : 
      97          44 :         *ret = j;
      98          44 :         return 1;
      99             : }
     100             : 
     101             : static const char* const user_data_unit_paths[] = {
     102             :         "/usr/local/lib/systemd/user",
     103             :         "/usr/local/share/systemd/user",
     104             :         USER_DATA_UNIT_PATH,
     105             :         "/usr/lib/systemd/user",
     106             :         "/usr/share/systemd/user",
     107             :         NULL
     108             : };
     109             : 
     110             : static const char* const user_config_unit_paths[] = {
     111             :         USER_CONFIG_UNIT_PATH,
     112             :         "/etc/systemd/user",
     113             :         NULL
     114             : };
     115             : 
     116          44 : int xdg_user_dirs(char ***ret_config_dirs, char ***ret_data_dirs) {
     117             :         /* Implement the mechanisms defined in
     118             :          *
     119             :          * http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
     120             :          *
     121             :          * We look in both the config and the data dirs because we
     122             :          * want to encourage that distributors ship their unit files
     123             :          * as data, and allow overriding as configuration.
     124             :          */
     125             :         const char *e;
     126          44 :         _cleanup_strv_free_ char **config_dirs = NULL, **data_dirs = NULL;
     127             : 
     128          44 :         e = getenv("XDG_CONFIG_DIRS");
     129          44 :         if (e) {
     130           0 :                 config_dirs = strv_split(e, ":");
     131           0 :                 if (!config_dirs)
     132           0 :                         return -ENOMEM;
     133             :         }
     134             : 
     135          44 :         e = getenv("XDG_DATA_DIRS");
     136          44 :         if (e)
     137          42 :                 data_dirs = strv_split(e, ":");
     138             :         else
     139           2 :                 data_dirs = strv_new("/usr/local/share",
     140             :                                      "/usr/share");
     141          44 :         if (!data_dirs)
     142           0 :                 return -ENOMEM;
     143             : 
     144          44 :         *ret_config_dirs = TAKE_PTR(config_dirs);
     145          44 :         *ret_data_dirs = TAKE_PTR(data_dirs);
     146             : 
     147          44 :         return 0;
     148             : }
     149             : 
     150           4 : static char** user_dirs(
     151             :                 const char *persistent_config,
     152             :                 const char *runtime_config,
     153             :                 const char *global_persistent_config,
     154             :                 const char *global_runtime_config,
     155             :                 const char *generator,
     156             :                 const char *generator_early,
     157             :                 const char *generator_late,
     158             :                 const char *transient,
     159             :                 const char *persistent_control,
     160             :                 const char *runtime_control) {
     161             : 
     162           4 :         _cleanup_strv_free_ char **config_dirs = NULL, **data_dirs = NULL;
     163           4 :         _cleanup_free_ char *data_home = NULL;
     164           4 :         _cleanup_strv_free_ char **res = NULL;
     165             :         int r;
     166             : 
     167           4 :         r = xdg_user_dirs(&config_dirs, &data_dirs);
     168           4 :         if (r < 0)
     169           0 :                 return NULL;
     170             : 
     171           4 :         r = xdg_user_data_dir(&data_home, "/systemd/user");
     172           4 :         if (r < 0 && r != -ENXIO)
     173           0 :                 return NULL;
     174             : 
     175             :         /* Now merge everything we found. */
     176           4 :         if (strv_extend(&res, persistent_control) < 0)
     177           0 :                 return NULL;
     178             : 
     179           4 :         if (strv_extend(&res, runtime_control) < 0)
     180           0 :                 return NULL;
     181             : 
     182           4 :         if (strv_extend(&res, transient) < 0)
     183           0 :                 return NULL;
     184             : 
     185           4 :         if (strv_extend(&res, generator_early) < 0)
     186           0 :                 return NULL;
     187             : 
     188           4 :         if (strv_extend_strv_concat(&res, config_dirs, "/systemd/user") < 0)
     189           0 :                 return NULL;
     190             : 
     191           4 :         if (strv_extend(&res, persistent_config) < 0)
     192           0 :                 return NULL;
     193             : 
     194             :         /* global config has lower priority than the user config of the same type */
     195           4 :         if (strv_extend(&res, global_persistent_config) < 0)
     196           0 :                 return NULL;
     197             : 
     198           4 :         if (strv_extend_strv(&res, (char**) user_config_unit_paths, false) < 0)
     199           0 :                 return NULL;
     200             : 
     201           4 :         if (strv_extend(&res, runtime_config) < 0)
     202           0 :                 return NULL;
     203             : 
     204           4 :         if (strv_extend(&res, global_runtime_config) < 0)
     205           0 :                 return NULL;
     206             : 
     207           4 :         if (strv_extend(&res, generator) < 0)
     208           0 :                 return NULL;
     209             : 
     210           4 :         if (strv_extend(&res, data_home) < 0)
     211           0 :                 return NULL;
     212             : 
     213           4 :         if (strv_extend_strv_concat(&res, data_dirs, "/systemd/user") < 0)
     214           0 :                 return NULL;
     215             : 
     216           4 :         if (strv_extend_strv(&res, (char**) user_data_unit_paths, false) < 0)
     217           0 :                 return NULL;
     218             : 
     219           4 :         if (strv_extend(&res, generator_late) < 0)
     220           0 :                 return NULL;
     221             : 
     222           4 :         if (path_strv_make_absolute_cwd(res) < 0)
     223           0 :                 return NULL;
     224             : 
     225           4 :         return TAKE_PTR(res);
     226             : }
     227             : 
     228           0 : bool path_is_user_data_dir(const char *path) {
     229           0 :         assert(path);
     230             : 
     231           0 :         return strv_contains((char**) user_data_unit_paths, path);
     232             : }
     233             : 
     234           0 : bool path_is_user_config_dir(const char *path) {
     235           0 :         assert(path);
     236             : 
     237           0 :         return strv_contains((char**) user_config_unit_paths, path);
     238             : }
     239             : 
     240         255 : static int acquire_generator_dirs(
     241             :                 UnitFileScope scope,
     242             :                 const char *tempdir,
     243             :                 char **generator,
     244             :                 char **generator_early,
     245             :                 char **generator_late) {
     246             : 
     247         255 :         _cleanup_free_ char *x = NULL, *y = NULL, *z = NULL;
     248             :         const char *prefix;
     249             : 
     250         255 :         assert(generator);
     251         255 :         assert(generator_early);
     252         255 :         assert(generator_late);
     253         255 :         assert(IN_SET(scope, UNIT_FILE_SYSTEM, UNIT_FILE_USER, UNIT_FILE_GLOBAL));
     254             : 
     255         255 :         if (scope == UNIT_FILE_GLOBAL)
     256           3 :                 return -EOPNOTSUPP;
     257             : 
     258         252 :         if (tempdir)
     259          13 :                 prefix = tempdir;
     260         239 :         else if (scope == UNIT_FILE_SYSTEM)
     261         236 :                 prefix = "/run/systemd";
     262             :         else {
     263             :                 /* UNIT_FILE_USER */
     264             :                 const char *e;
     265             : 
     266           3 :                 e = getenv("XDG_RUNTIME_DIR");
     267           3 :                 if (!e)
     268           0 :                         return -ENXIO;
     269             : 
     270          15 :                 prefix = strjoina(e, "/systemd");
     271             :         }
     272             : 
     273         252 :         x = path_join(prefix, "generator");
     274         252 :         if (!x)
     275           0 :                 return -ENOMEM;
     276             : 
     277         252 :         y = path_join(prefix, "generator.early");
     278         252 :         if (!y)
     279           0 :                 return -ENOMEM;
     280             : 
     281         252 :         z = path_join(prefix, "generator.late");
     282         252 :         if (!z)
     283           0 :                 return -ENOMEM;
     284             : 
     285         252 :         *generator = TAKE_PTR(x);
     286         252 :         *generator_early = TAKE_PTR(y);
     287         252 :         *generator_late = TAKE_PTR(z);
     288             : 
     289         252 :         return 0;
     290             : }
     291             : 
     292         274 : static int acquire_transient_dir(
     293             :                 UnitFileScope scope,
     294             :                 const char *tempdir,
     295             :                 char **ret) {
     296             : 
     297             :         char *transient;
     298             : 
     299         274 :         assert(ret);
     300         274 :         assert(IN_SET(scope, UNIT_FILE_SYSTEM, UNIT_FILE_USER, UNIT_FILE_GLOBAL));
     301             : 
     302         274 :         if (scope == UNIT_FILE_GLOBAL)
     303           3 :                 return -EOPNOTSUPP;
     304             : 
     305         271 :         if (tempdir)
     306          13 :                 transient = path_join(tempdir, "transient");
     307         258 :         else if (scope == UNIT_FILE_SYSTEM)
     308         255 :                 transient = strdup("/run/systemd/transient");
     309             :         else
     310           3 :                 return xdg_user_runtime_dir(ret, "/systemd/transient");
     311             : 
     312         268 :         if (!transient)
     313           0 :                 return -ENOMEM;
     314         268 :         *ret = transient;
     315         268 :         return 0;
     316             : }
     317             : 
     318         290 : static int acquire_config_dirs(UnitFileScope scope, char **persistent, char **runtime) {
     319         290 :         _cleanup_free_ char *a = NULL, *b = NULL;
     320             :         int r;
     321             : 
     322         290 :         assert(persistent);
     323         290 :         assert(runtime);
     324             : 
     325         290 :         switch (scope) {
     326             : 
     327         255 :         case UNIT_FILE_SYSTEM:
     328         255 :                 a = strdup(SYSTEM_CONFIG_UNIT_PATH);
     329         255 :                 b = strdup("/run/systemd/system");
     330         255 :                 break;
     331             : 
     332          19 :         case UNIT_FILE_GLOBAL:
     333          19 :                 a = strdup(USER_CONFIG_UNIT_PATH);
     334          19 :                 b = strdup("/run/systemd/user");
     335          19 :                 break;
     336             : 
     337          16 :         case UNIT_FILE_USER:
     338          16 :                 r = xdg_user_config_dir(&a, "/systemd/user");
     339          16 :                 if (r < 0 && r != -ENXIO)
     340           0 :                         return r;
     341             : 
     342          16 :                 r = xdg_user_runtime_dir(runtime, "/systemd/user");
     343          16 :                 if (r < 0) {
     344           0 :                         if (r != -ENXIO)
     345           0 :                                 return r;
     346             : 
     347             :                         /* If XDG_RUNTIME_DIR is not set, don't consider that fatal, simply initialize the runtime
     348             :                          * directory to NULL */
     349           0 :                         *runtime = NULL;
     350             :                 }
     351             : 
     352          16 :                 *persistent = TAKE_PTR(a);
     353             : 
     354          16 :                 return 0;
     355             : 
     356           0 :         default:
     357           0 :                 assert_not_reached("Hmm, unexpected scope value.");
     358             :         }
     359             : 
     360         274 :         if (!a || !b)
     361           0 :                 return -ENOMEM;
     362             : 
     363         274 :         *persistent = TAKE_PTR(a);
     364         274 :         *runtime = TAKE_PTR(b);
     365             : 
     366         274 :         return 0;
     367             : }
     368             : 
     369         274 : static int acquire_control_dirs(UnitFileScope scope, char **persistent, char **runtime) {
     370         274 :         _cleanup_free_ char *a = NULL;
     371             :         int r;
     372             : 
     373         274 :         assert(persistent);
     374         274 :         assert(runtime);
     375             : 
     376         274 :         switch (scope) {
     377             : 
     378         255 :         case UNIT_FILE_SYSTEM:  {
     379         255 :                 _cleanup_free_ char *b = NULL;
     380             : 
     381         255 :                 a = strdup("/etc/systemd/system.control");
     382         255 :                 if (!a)
     383           0 :                         return -ENOMEM;
     384             : 
     385         255 :                 b = strdup("/run/systemd/system.control");
     386         255 :                 if (!b)
     387           0 :                         return -ENOMEM;
     388             : 
     389         255 :                 *runtime = TAKE_PTR(b);
     390             : 
     391         255 :                 break;
     392             :         }
     393             : 
     394          16 :         case UNIT_FILE_USER:
     395          16 :                 r = xdg_user_config_dir(&a, "/systemd/user.control");
     396          16 :                 if (r < 0 && r != -ENXIO)
     397           0 :                         return r;
     398             : 
     399          16 :                 r = xdg_user_runtime_dir(runtime, "/systemd/user.control");
     400          16 :                 if (r < 0) {
     401           0 :                         if (r != -ENXIO)
     402           0 :                                 return r;
     403             : 
     404             :                         /* If XDG_RUNTIME_DIR is not set, don't consider this fatal, simply initialize the directory to
     405             :                          * NULL */
     406           0 :                         *runtime = NULL;
     407             :                 }
     408             : 
     409          16 :                 break;
     410             : 
     411           3 :         case UNIT_FILE_GLOBAL:
     412           3 :                 return -EOPNOTSUPP;
     413             : 
     414           0 :         default:
     415           0 :                 assert_not_reached("Hmm, unexpected scope value.");
     416             :         }
     417             : 
     418         271 :         *persistent = TAKE_PTR(a);
     419             : 
     420         271 :         return 0;
     421             : }
     422             : 
     423         274 : static int acquire_attached_dirs(
     424             :                 UnitFileScope scope,
     425             :                 char **ret_persistent,
     426             :                 char **ret_runtime) {
     427             : 
     428         274 :         _cleanup_free_ char *a = NULL, *b = NULL;
     429             : 
     430         274 :         assert(ret_persistent);
     431         274 :         assert(ret_runtime);
     432             : 
     433             :         /* Portable services are not available to regular users for now. */
     434         274 :         if (scope != UNIT_FILE_SYSTEM)
     435          19 :                 return -EOPNOTSUPP;
     436             : 
     437         255 :         a = strdup("/etc/systemd/system.attached");
     438         255 :         if (!a)
     439           0 :                 return -ENOMEM;
     440             : 
     441         255 :         b = strdup("/run/systemd/system.attached");
     442         255 :         if (!b)
     443           0 :                 return -ENOMEM;
     444             : 
     445         255 :         *ret_persistent = TAKE_PTR(a);
     446         255 :         *ret_runtime = TAKE_PTR(b);
     447             : 
     448         255 :         return 0;
     449             : }
     450             : 
     451        6452 : static int patch_root_prefix(char **p, const char *root_dir) {
     452             :         char *c;
     453             : 
     454        6452 :         assert(p);
     455             : 
     456        6452 :         if (!*p)
     457         113 :                 return 0;
     458             : 
     459        6339 :         c = path_join(root_dir, *p);
     460        6339 :         if (!c)
     461           0 :                 return -ENOMEM;
     462             : 
     463        6339 :         free_and_replace(*p, c);
     464        6339 :         return 0;
     465             : }
     466             : 
     467         274 : static int patch_root_prefix_strv(char **l, const char *root_dir) {
     468             :         char **i;
     469             :         int r;
     470             : 
     471         274 :         if (!root_dir)
     472          42 :                 return 0;
     473             : 
     474        3944 :         STRV_FOREACH(i, l) {
     475        3712 :                 r = patch_root_prefix(i, root_dir);
     476        3712 :                 if (r < 0)
     477           0 :                         return r;
     478             :         }
     479             : 
     480         232 :         return 0;
     481             : }
     482             : 
     483         274 : int lookup_paths_init(
     484             :                 LookupPaths *p,
     485             :                 UnitFileScope scope,
     486             :                 LookupPathsFlags flags,
     487             :                 const char *root_dir) {
     488             : 
     489         274 :         _cleanup_(rmdir_and_freep) char *tempdir = NULL;
     490             :         _cleanup_free_ char
     491         274 :                 *root = NULL,
     492         274 :                 *persistent_config = NULL, *runtime_config = NULL,
     493         274 :                 *global_persistent_config = NULL, *global_runtime_config = NULL,
     494         274 :                 *generator = NULL, *generator_early = NULL, *generator_late = NULL,
     495         274 :                 *transient = NULL,
     496         274 :                 *persistent_control = NULL, *runtime_control = NULL,
     497         274 :                 *persistent_attached = NULL, *runtime_attached = NULL;
     498         274 :         bool append = false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */
     499         274 :         _cleanup_strv_free_ char **paths = NULL;
     500             :         const char *e;
     501             :         int r;
     502             : 
     503         274 :         assert(p);
     504         274 :         assert(scope >= 0);
     505         274 :         assert(scope < _UNIT_FILE_SCOPE_MAX);
     506             : 
     507             : #if HAVE_SPLIT_USR
     508             :         flags |= LOOKUP_PATHS_SPLIT_USR;
     509             : #endif
     510             : 
     511         274 :         if (!empty_or_root(root_dir)) {
     512         232 :                 if (scope == UNIT_FILE_USER)
     513           0 :                         return -EINVAL;
     514             : 
     515         232 :                 r = is_dir(root_dir, true);
     516         232 :                 if (r < 0)
     517           0 :                         return r;
     518         232 :                 if (r == 0)
     519           0 :                         return -ENOTDIR;
     520             : 
     521         232 :                 root = strdup(root_dir);
     522         232 :                 if (!root)
     523           0 :                         return -ENOMEM;
     524             :         }
     525             : 
     526         274 :         if (flags & LOOKUP_PATHS_TEMPORARY_GENERATED) {
     527          13 :                 r = mkdtemp_malloc("/tmp/systemd-temporary-XXXXXX", &tempdir);
     528          13 :                 if (r < 0)
     529           0 :                         return log_debug_errno(r, "Failed to create temporary directory: %m");
     530             :         }
     531             : 
     532             :         /* Note: when XDG_RUNTIME_DIR is not set this will not return -ENXIO, but simply set runtime_config to NULL */
     533         274 :         r = acquire_config_dirs(scope, &persistent_config, &runtime_config);
     534         274 :         if (r < 0)
     535           0 :                 return r;
     536             : 
     537         274 :         if (scope == UNIT_FILE_USER) {
     538          16 :                 r = acquire_config_dirs(UNIT_FILE_GLOBAL, &global_persistent_config, &global_runtime_config);
     539          16 :                 if (r < 0)
     540           0 :                         return r;
     541             :         }
     542             : 
     543         274 :         if ((flags & LOOKUP_PATHS_EXCLUDE_GENERATED) == 0) {
     544             :                 /* Note: if XDG_RUNTIME_DIR is not set, this will fail completely with ENXIO */
     545         255 :                 r = acquire_generator_dirs(scope, tempdir,
     546             :                                            &generator, &generator_early, &generator_late);
     547         255 :                 if (r < 0 && !IN_SET(r, -EOPNOTSUPP, -ENXIO))
     548           0 :                         return r;
     549             :         }
     550             : 
     551             :         /* Note: if XDG_RUNTIME_DIR is not set, this will fail completely with ENXIO */
     552         274 :         r = acquire_transient_dir(scope, tempdir, &transient);
     553         274 :         if (r < 0 && !IN_SET(r, -EOPNOTSUPP, -ENXIO))
     554           0 :                 return r;
     555             : 
     556             :         /* Note: when XDG_RUNTIME_DIR is not set this will not return -ENXIO, but simply set runtime_control to NULL */
     557         274 :         r = acquire_control_dirs(scope, &persistent_control, &runtime_control);
     558         274 :         if (r < 0 && r != -EOPNOTSUPP)
     559           0 :                 return r;
     560             : 
     561         274 :         r = acquire_attached_dirs(scope, &persistent_attached, &runtime_attached);
     562         274 :         if (r < 0 && r != -EOPNOTSUPP)
     563           0 :                 return r;
     564             : 
     565             :         /* First priority is whatever has been passed to us via env vars */
     566         274 :         e = getenv("SYSTEMD_UNIT_PATH");
     567         274 :         if (e) {
     568             :                 const char *k;
     569             : 
     570          33 :                 k = endswith(e, ":");
     571          33 :                 if (k) {
     572           0 :                         e = strndupa(e, k - e);
     573           0 :                         append = true;
     574             :                 }
     575             : 
     576             :                 /* FIXME: empty components in other places should be rejected. */
     577             : 
     578          33 :                 r = path_split_and_make_absolute(e, &paths);
     579          33 :                 if (r < 0)
     580           0 :                         return r;
     581             :         }
     582             : 
     583         274 :         if (!paths || append) {
     584             :                 /* Let's figure something out. */
     585             : 
     586         241 :                 _cleanup_strv_free_ char **add = NULL;
     587             : 
     588             :                 /* For the user units we include share/ in the search
     589             :                  * path in order to comply with the XDG basedir spec.
     590             :                  * For the system stuff we avoid such nonsense. OTOH
     591             :                  * we include /lib in the search path for the system
     592             :                  * stuff but avoid it for user stuff. */
     593             : 
     594         241 :                 switch (scope) {
     595             : 
     596         235 :                 case UNIT_FILE_SYSTEM:
     597         235 :                         add = strv_new(
     598             :                                         /* If you modify this you also want to modify
     599             :                                          * systemdsystemunitpath= in systemd.pc.in! */
     600             :                                         STRV_IFNOTNULL(persistent_control),
     601             :                                         STRV_IFNOTNULL(runtime_control),
     602             :                                         STRV_IFNOTNULL(transient),
     603             :                                         STRV_IFNOTNULL(generator_early),
     604             :                                         persistent_config,
     605             :                                         SYSTEM_CONFIG_UNIT_PATH,
     606             :                                         "/etc/systemd/system",
     607             :                                         STRV_IFNOTNULL(persistent_attached),
     608             :                                         runtime_config,
     609             :                                         "/run/systemd/system",
     610             :                                         STRV_IFNOTNULL(runtime_attached),
     611             :                                         STRV_IFNOTNULL(generator),
     612             :                                         "/usr/local/lib/systemd/system",
     613             :                                         SYSTEM_DATA_UNIT_PATH,
     614             :                                         "/usr/lib/systemd/system",
     615             :                                         STRV_IFNOTNULL(flags & LOOKUP_PATHS_SPLIT_USR ? "/lib/systemd/system" : NULL),
     616             :                                         STRV_IFNOTNULL(generator_late));
     617         235 :                         break;
     618             : 
     619           2 :                 case UNIT_FILE_GLOBAL:
     620           2 :                         add = strv_new(
     621             :                                         /* If you modify this you also want to modify
     622             :                                          * systemduserunitpath= in systemd.pc.in, and
     623             :                                          * the arrays in user_dirs() above! */
     624             :                                         STRV_IFNOTNULL(persistent_control),
     625             :                                         STRV_IFNOTNULL(runtime_control),
     626             :                                         STRV_IFNOTNULL(transient),
     627             :                                         STRV_IFNOTNULL(generator_early),
     628             :                                         persistent_config,
     629             :                                         USER_CONFIG_UNIT_PATH,
     630             :                                         "/etc/systemd/user",
     631             :                                         runtime_config,
     632             :                                         "/run/systemd/user",
     633             :                                         STRV_IFNOTNULL(generator),
     634             :                                         "/usr/local/share/systemd/user",
     635             :                                         "/usr/share/systemd/user",
     636             :                                         "/usr/local/lib/systemd/user",
     637             :                                         USER_DATA_UNIT_PATH,
     638             :                                         "/usr/lib/systemd/user",
     639             :                                         STRV_IFNOTNULL(generator_late));
     640           2 :                         break;
     641             : 
     642           4 :                 case UNIT_FILE_USER:
     643           4 :                         add = user_dirs(persistent_config, runtime_config,
     644             :                                         global_persistent_config, global_runtime_config,
     645             :                                         generator, generator_early, generator_late,
     646             :                                         transient,
     647             :                                         persistent_control, runtime_control);
     648           4 :                         break;
     649             : 
     650           0 :                 default:
     651           0 :                         assert_not_reached("Hmm, unexpected scope?");
     652             :                 }
     653             : 
     654         241 :                 if (!add)
     655           0 :                         return -ENOMEM;
     656             : 
     657         241 :                 if (paths) {
     658           0 :                         r = strv_extend_strv(&paths, add, true);
     659           0 :                         if (r < 0)
     660           0 :                                 return r;
     661             :                 } else
     662             :                         /* Small optimization: if paths is NULL (and it usually is), we can simply assign 'add' to it,
     663             :                          * and don't have to copy anything */
     664         241 :                         paths = TAKE_PTR(add);
     665             :         }
     666             : 
     667         274 :         r = patch_root_prefix(&persistent_config, root);
     668         274 :         if (r < 0)
     669           0 :                 return r;
     670         274 :         r = patch_root_prefix(&runtime_config, root);
     671         274 :         if (r < 0)
     672           0 :                 return r;
     673             : 
     674         274 :         r = patch_root_prefix(&generator, root);
     675         274 :         if (r < 0)
     676           0 :                 return r;
     677         274 :         r = patch_root_prefix(&generator_early, root);
     678         274 :         if (r < 0)
     679           0 :                 return r;
     680         274 :         r = patch_root_prefix(&generator_late, root);
     681         274 :         if (r < 0)
     682           0 :                 return r;
     683             : 
     684         274 :         r = patch_root_prefix(&transient, root);
     685         274 :         if (r < 0)
     686           0 :                 return r;
     687             : 
     688         274 :         r = patch_root_prefix(&persistent_control, root);
     689         274 :         if (r < 0)
     690           0 :                 return r;
     691         274 :         r = patch_root_prefix(&runtime_control, root);
     692         274 :         if (r < 0)
     693           0 :                 return r;
     694             : 
     695         274 :         r = patch_root_prefix(&persistent_attached, root);
     696         274 :         if (r < 0)
     697           0 :                 return r;
     698         274 :         r = patch_root_prefix(&runtime_attached, root);
     699         274 :         if (r < 0)
     700           0 :                 return r;
     701             : 
     702         274 :         r = patch_root_prefix_strv(paths, root);
     703         274 :         if (r < 0)
     704           0 :                 return -ENOMEM;
     705             : 
     706         274 :         *p = (LookupPaths) {
     707         274 :                 .search_path = strv_uniq(paths),
     708             : 
     709         274 :                 .persistent_config = TAKE_PTR(persistent_config),
     710         274 :                 .runtime_config = TAKE_PTR(runtime_config),
     711             : 
     712         274 :                 .generator = TAKE_PTR(generator),
     713         274 :                 .generator_early = TAKE_PTR(generator_early),
     714         274 :                 .generator_late = TAKE_PTR(generator_late),
     715             : 
     716         274 :                 .transient = TAKE_PTR(transient),
     717             : 
     718         274 :                 .persistent_control = TAKE_PTR(persistent_control),
     719         274 :                 .runtime_control = TAKE_PTR(runtime_control),
     720             : 
     721         274 :                 .persistent_attached = TAKE_PTR(persistent_attached),
     722         274 :                 .runtime_attached = TAKE_PTR(runtime_attached),
     723             : 
     724         274 :                 .root_dir = TAKE_PTR(root),
     725         274 :                 .temporary_dir = TAKE_PTR(tempdir),
     726             :         };
     727             : 
     728         274 :         paths = NULL;
     729         274 :         return 0;
     730             : }
     731             : 
     732         275 : void lookup_paths_free(LookupPaths *p) {
     733         275 :         if (!p)
     734           0 :                 return;
     735             : 
     736         275 :         p->search_path = strv_free(p->search_path);
     737             : 
     738         275 :         p->persistent_config = mfree(p->persistent_config);
     739         275 :         p->runtime_config = mfree(p->runtime_config);
     740             : 
     741         275 :         p->persistent_attached = mfree(p->persistent_attached);
     742         275 :         p->runtime_attached = mfree(p->runtime_attached);
     743             : 
     744         275 :         p->generator = mfree(p->generator);
     745         275 :         p->generator_early = mfree(p->generator_early);
     746         275 :         p->generator_late = mfree(p->generator_late);
     747             : 
     748         275 :         p->transient = mfree(p->transient);
     749             : 
     750         275 :         p->persistent_control = mfree(p->persistent_control);
     751         275 :         p->runtime_control = mfree(p->runtime_control);
     752             : 
     753         275 :         p->root_dir = mfree(p->root_dir);
     754         275 :         p->temporary_dir = mfree(p->temporary_dir);
     755             : }
     756             : 
     757          19 : int lookup_paths_reduce(LookupPaths *p) {
     758          19 :         _cleanup_free_ struct stat *stats = NULL;
     759          19 :         size_t n_stats = 0, allocated = 0;
     760          19 :         size_t c = 0;
     761             :         int r;
     762             : 
     763          19 :         assert(p);
     764             : 
     765             :         /* Drop duplicates and non-existing directories from the search path. We figure out whether two directories are
     766             :          * the same by comparing their device and inode numbers. */
     767             : 
     768          19 :         if (!p->search_path)
     769           0 :                 return 0;
     770             : 
     771         102 :         while (p->search_path[c]) {
     772             :                 struct stat st;
     773             :                 size_t k;
     774             : 
     775             :                 /* Never strip the transient and control directories from the path */
     776         162 :                 if (path_equal_ptr(p->search_path[c], p->transient) ||
     777         154 :                     path_equal_ptr(p->search_path[c], p->persistent_control) ||
     778          75 :                     path_equal_ptr(p->search_path[c], p->runtime_control)) {
     779          12 :                         c++;
     780          36 :                         continue;
     781             :                 }
     782             : 
     783          71 :                 r = chase_symlinks_and_stat(p->search_path[c], p->root_dir, 0, NULL, &st);
     784          71 :                 if (r == -ENOENT)
     785          47 :                         goto remove_item;
     786          24 :                 if (r < 0) {
     787             :                         /* If something we don't grok happened, let's better leave it in. */
     788           0 :                         log_debug_errno(r, "Failed to chase and stat %s: %m", p->search_path[c]);
     789           0 :                         c++;
     790           0 :                         continue;
     791             :                 }
     792             : 
     793          38 :                 for (k = 0; k < n_stats; k++)
     794          14 :                         if (stats[k].st_dev == st.st_dev &&
     795           8 :                             stats[k].st_ino == st.st_ino)
     796           0 :                                 break;
     797             : 
     798          24 :                 if (k < n_stats) /* Is there already an entry with the same device/inode? */
     799           0 :                         goto remove_item;
     800             : 
     801          24 :                 if (!GREEDY_REALLOC(stats, allocated, n_stats+1))
     802           0 :                         return -ENOMEM;
     803             : 
     804          24 :                 stats[n_stats++] = st;
     805          24 :                 c++;
     806          24 :                 continue;
     807             : 
     808          47 :         remove_item:
     809          47 :                 free(p->search_path[c]);
     810         141 :                 memmove(p->search_path + c,
     811          94 :                         p->search_path + c + 1,
     812          47 :                         (strv_length(p->search_path + c + 1) + 1) * sizeof(char*));
     813             :         }
     814             : 
     815          19 :         if (strv_isempty(p->search_path)) {
     816           3 :                 log_debug("Ignoring unit files.");
     817           3 :                 p->search_path = strv_free(p->search_path);
     818             :         } else {
     819          16 :                 _cleanup_free_ char *t;
     820             : 
     821          16 :                 t = strv_join(p->search_path, "\n\t");
     822          16 :                 if (!t)
     823           0 :                         return -ENOMEM;
     824             : 
     825          16 :                 log_debug("Looking for unit files in (higher priority first):\n\t%s", t);
     826             :         }
     827             : 
     828          19 :         return 0;
     829             : }
     830             : 
     831           0 : int lookup_paths_mkdir_generator(LookupPaths *p) {
     832             :         int r, q;
     833             : 
     834           0 :         assert(p);
     835             : 
     836           0 :         if (!p->generator || !p->generator_early || !p->generator_late)
     837           0 :                 return -EINVAL;
     838             : 
     839           0 :         r = mkdir_p_label(p->generator, 0755);
     840             : 
     841           0 :         q = mkdir_p_label(p->generator_early, 0755);
     842           0 :         if (q < 0 && r >= 0)
     843           0 :                 r = q;
     844             : 
     845           0 :         q = mkdir_p_label(p->generator_late, 0755);
     846           0 :         if (q < 0 && r >= 0)
     847           0 :                 r = q;
     848             : 
     849           0 :         return r;
     850             : }
     851             : 
     852           0 : void lookup_paths_trim_generator(LookupPaths *p) {
     853           0 :         assert(p);
     854             : 
     855             :         /* Trim empty dirs */
     856             : 
     857           0 :         if (p->generator)
     858           0 :                 (void) rmdir(p->generator);
     859           0 :         if (p->generator_early)
     860           0 :                 (void) rmdir(p->generator_early);
     861           0 :         if (p->generator_late)
     862           0 :                 (void) rmdir(p->generator_late);
     863           0 : }
     864             : 
     865          14 : void lookup_paths_flush_generator(LookupPaths *p) {
     866          14 :         assert(p);
     867             : 
     868             :         /* Flush the generated unit files in full */
     869             : 
     870          14 :         if (p->generator)
     871          13 :                 (void) rm_rf(p->generator, REMOVE_ROOT|REMOVE_PHYSICAL);
     872          14 :         if (p->generator_early)
     873          13 :                 (void) rm_rf(p->generator_early, REMOVE_ROOT|REMOVE_PHYSICAL);
     874          14 :         if (p->generator_late)
     875          13 :                 (void) rm_rf(p->generator_late, REMOVE_ROOT|REMOVE_PHYSICAL);
     876             : 
     877          14 :         if (p->temporary_dir)
     878          13 :                 (void) rm_rf(p->temporary_dir, REMOVE_ROOT|REMOVE_PHYSICAL);
     879          14 : }
     880             : 
     881           2 : char **generator_binary_paths(UnitFileScope scope) {
     882             : 
     883           2 :         switch (scope) {
     884             : 
     885           1 :         case UNIT_FILE_SYSTEM:
     886           1 :                 return strv_new("/run/systemd/system-generators",
     887             :                                 "/etc/systemd/system-generators",
     888             :                                 "/usr/local/lib/systemd/system-generators",
     889             :                                 SYSTEM_GENERATOR_PATH);
     890             : 
     891           1 :         case UNIT_FILE_GLOBAL:
     892             :         case UNIT_FILE_USER:
     893           1 :                 return strv_new("/run/systemd/user-generators",
     894             :                                 "/etc/systemd/user-generators",
     895             :                                 "/usr/local/lib/systemd/user-generators",
     896             :                                 USER_GENERATOR_PATH);
     897             : 
     898           0 :         default:
     899           0 :                 assert_not_reached("Hmm, unexpected scope.");
     900             :         }
     901             : }

Generated by: LCOV version 1.14