LCOV - code coverage report
Current view: top level - shared - path-lookup.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 349 471 74.1 %
Date: 2019-08-23 13:36:53 Functions: 17 21 81.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 202 369 54.7 %

           Branch data     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                 :        300 : int xdg_user_runtime_dir(char **ret, const char *suffix) {
      25                 :            :         const char *e;
      26                 :            :         char *j;
      27                 :            : 
      28         [ -  + ]:        300 :         assert(ret);
      29         [ -  + ]:        300 :         assert(suffix);
      30                 :            : 
      31                 :        300 :         e = getenv("XDG_RUNTIME_DIR");
      32         [ +  + ]:        300 :         if (!e)
      33                 :          4 :                 return -ENXIO;
      34                 :            : 
      35                 :        296 :         j = strjoin(e, suffix);
      36         [ -  + ]:        296 :         if (!j)
      37                 :          0 :                 return -ENOMEM;
      38                 :            : 
      39                 :        296 :         *ret = j;
      40                 :        296 :         return 0;
      41                 :            : }
      42                 :            : 
      43                 :        288 : int xdg_user_config_dir(char **ret, const char *suffix) {
      44                 :            :         const char *e;
      45                 :            :         char *j;
      46                 :            :         int r;
      47                 :            : 
      48         [ -  + ]:        288 :         assert(ret);
      49                 :            : 
      50                 :        288 :         e = getenv("XDG_CONFIG_HOME");
      51         [ -  + ]:        288 :         if (e)
      52                 :          0 :                 j = strjoin(e, suffix);
      53                 :            :         else {
      54         [ +  - ]:        288 :                 _cleanup_free_ char *home = NULL;
      55                 :            : 
      56                 :        288 :                 r = get_home_dir(&home);
      57         [ -  + ]:        288 :                 if (r < 0)
      58                 :          0 :                         return r;
      59                 :            : 
      60                 :        288 :                 j = strjoin(home, "/.config", suffix);
      61                 :            :         }
      62                 :            : 
      63         [ -  + ]:        288 :         if (!j)
      64                 :          0 :                 return -ENOMEM;
      65                 :            : 
      66                 :        288 :         *ret = j;
      67                 :        288 :         return 0;
      68                 :            : }
      69                 :            : 
      70                 :        176 : int xdg_user_data_dir(char **ret, const char *suffix) {
      71                 :            :         const char *e;
      72                 :            :         char *j;
      73                 :            :         int r;
      74                 :            : 
      75         [ -  + ]:        176 :         assert(ret);
      76         [ -  + ]:        176 :         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                 :        176 :         e = getenv("XDG_DATA_HOME");
      83         [ -  + ]:        176 :         if (e)
      84                 :          0 :                 j = strjoin(e, suffix);
      85                 :            :         else {
      86         [ +  - ]:        176 :                 _cleanup_free_ char *home = NULL;
      87                 :            : 
      88                 :        176 :                 r = get_home_dir(&home);
      89         [ -  + ]:        176 :                 if (r < 0)
      90                 :          0 :                         return r;
      91                 :            : 
      92                 :        176 :                 j = strjoin(home, "/.local/share", suffix);
      93                 :            :         }
      94         [ -  + ]:        176 :         if (!j)
      95                 :          0 :                 return -ENOMEM;
      96                 :            : 
      97                 :        176 :         *ret = j;
      98                 :        176 :         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                 :        176 : 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                 :        176 :         _cleanup_strv_free_ char **config_dirs = NULL, **data_dirs = NULL;
     127                 :            : 
     128                 :        176 :         e = getenv("XDG_CONFIG_DIRS");
     129         [ -  + ]:        176 :         if (e) {
     130                 :          0 :                 config_dirs = strv_split(e, ":");
     131         [ #  # ]:          0 :                 if (!config_dirs)
     132                 :          0 :                         return -ENOMEM;
     133                 :            :         }
     134                 :            : 
     135                 :        176 :         e = getenv("XDG_DATA_DIRS");
     136         [ +  + ]:        176 :         if (e)
     137                 :        168 :                 data_dirs = strv_split(e, ":");
     138                 :            :         else
     139                 :          8 :                 data_dirs = strv_new("/usr/local/share",
     140                 :            :                                      "/usr/share");
     141         [ -  + ]:        176 :         if (!data_dirs)
     142                 :          0 :                 return -ENOMEM;
     143                 :            : 
     144                 :        176 :         *ret_config_dirs = TAKE_PTR(config_dirs);
     145                 :        176 :         *ret_data_dirs = TAKE_PTR(data_dirs);
     146                 :            : 
     147                 :        176 :         return 0;
     148                 :            : }
     149                 :            : 
     150                 :         16 : 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                 :         16 :         _cleanup_strv_free_ char **config_dirs = NULL, **data_dirs = NULL;
     163                 :         16 :         _cleanup_free_ char *data_home = NULL;
     164                 :         16 :         _cleanup_strv_free_ char **res = NULL;
     165                 :            :         int r;
     166                 :            : 
     167                 :         16 :         r = xdg_user_dirs(&config_dirs, &data_dirs);
     168         [ -  + ]:         16 :         if (r < 0)
     169                 :          0 :                 return NULL;
     170                 :            : 
     171                 :         16 :         r = xdg_user_data_dir(&data_home, "/systemd/user");
     172   [ -  +  #  # ]:         16 :         if (r < 0 && r != -ENXIO)
     173                 :          0 :                 return NULL;
     174                 :            : 
     175                 :            :         /* Now merge everything we found. */
     176         [ -  + ]:         16 :         if (strv_extend(&res, persistent_control) < 0)
     177                 :          0 :                 return NULL;
     178                 :            : 
     179         [ -  + ]:         16 :         if (strv_extend(&res, runtime_control) < 0)
     180                 :          0 :                 return NULL;
     181                 :            : 
     182         [ -  + ]:         16 :         if (strv_extend(&res, transient) < 0)
     183                 :          0 :                 return NULL;
     184                 :            : 
     185         [ -  + ]:         16 :         if (strv_extend(&res, generator_early) < 0)
     186                 :          0 :                 return NULL;
     187                 :            : 
     188         [ -  + ]:         16 :         if (strv_extend_strv_concat(&res, config_dirs, "/systemd/user") < 0)
     189                 :          0 :                 return NULL;
     190                 :            : 
     191         [ -  + ]:         16 :         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         [ -  + ]:         16 :         if (strv_extend(&res, global_persistent_config) < 0)
     196                 :          0 :                 return NULL;
     197                 :            : 
     198         [ -  + ]:         16 :         if (strv_extend_strv(&res, (char**) user_config_unit_paths, false) < 0)
     199                 :          0 :                 return NULL;
     200                 :            : 
     201         [ -  + ]:         16 :         if (strv_extend(&res, runtime_config) < 0)
     202                 :          0 :                 return NULL;
     203                 :            : 
     204         [ -  + ]:         16 :         if (strv_extend(&res, global_runtime_config) < 0)
     205                 :          0 :                 return NULL;
     206                 :            : 
     207         [ -  + ]:         16 :         if (strv_extend(&res, generator) < 0)
     208                 :          0 :                 return NULL;
     209                 :            : 
     210         [ -  + ]:         16 :         if (strv_extend(&res, data_home) < 0)
     211                 :          0 :                 return NULL;
     212                 :            : 
     213         [ -  + ]:         16 :         if (strv_extend_strv_concat(&res, data_dirs, "/systemd/user") < 0)
     214                 :          0 :                 return NULL;
     215                 :            : 
     216         [ -  + ]:         16 :         if (strv_extend_strv(&res, (char**) user_data_unit_paths, false) < 0)
     217                 :          0 :                 return NULL;
     218                 :            : 
     219         [ -  + ]:         16 :         if (strv_extend(&res, generator_late) < 0)
     220                 :          0 :                 return NULL;
     221                 :            : 
     222         [ -  + ]:         16 :         if (path_strv_make_absolute_cwd(res) < 0)
     223                 :          0 :                 return NULL;
     224                 :            : 
     225                 :         16 :         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                 :       1020 : 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                 :       1020 :         _cleanup_free_ char *x = NULL, *y = NULL, *z = NULL;
     248                 :            :         const char *prefix;
     249                 :            : 
     250         [ -  + ]:       1020 :         assert(generator);
     251         [ -  + ]:       1020 :         assert(generator_early);
     252         [ -  + ]:       1020 :         assert(generator_late);
     253   [ +  -  -  + ]:       1020 :         assert(IN_SET(scope, UNIT_FILE_SYSTEM, UNIT_FILE_USER, UNIT_FILE_GLOBAL));
     254                 :            : 
     255         [ +  + ]:       1020 :         if (scope == UNIT_FILE_GLOBAL)
     256                 :         12 :                 return -EOPNOTSUPP;
     257                 :            : 
     258         [ +  + ]:       1008 :         if (tempdir)
     259                 :         52 :                 prefix = tempdir;
     260         [ +  + ]:        956 :         else if (scope == UNIT_FILE_SYSTEM)
     261                 :        944 :                 prefix = "/run/systemd";
     262                 :            :         else {
     263                 :            :                 /* UNIT_FILE_USER */
     264                 :            :                 const char *e;
     265                 :            : 
     266                 :         12 :                 e = getenv("XDG_RUNTIME_DIR");
     267         [ -  + ]:         12 :                 if (!e)
     268                 :          0 :                         return -ENXIO;
     269                 :            : 
     270   [ +  +  +  -  :         60 :                 prefix = strjoina(e, "/systemd");
          -  +  -  +  +  
                +  +  - ]
     271                 :            :         }
     272                 :            : 
     273                 :       1008 :         x = path_join(prefix, "generator");
     274         [ -  + ]:       1008 :         if (!x)
     275                 :          0 :                 return -ENOMEM;
     276                 :            : 
     277                 :       1008 :         y = path_join(prefix, "generator.early");
     278         [ -  + ]:       1008 :         if (!y)
     279                 :          0 :                 return -ENOMEM;
     280                 :            : 
     281                 :       1008 :         z = path_join(prefix, "generator.late");
     282         [ -  + ]:       1008 :         if (!z)
     283                 :          0 :                 return -ENOMEM;
     284                 :            : 
     285                 :       1008 :         *generator = TAKE_PTR(x);
     286                 :       1008 :         *generator_early = TAKE_PTR(y);
     287                 :       1008 :         *generator_late = TAKE_PTR(z);
     288                 :            : 
     289                 :       1008 :         return 0;
     290                 :            : }
     291                 :            : 
     292                 :       1096 : static int acquire_transient_dir(
     293                 :            :                 UnitFileScope scope,
     294                 :            :                 const char *tempdir,
     295                 :            :                 char **ret) {
     296                 :            : 
     297                 :            :         char *transient;
     298                 :            : 
     299         [ -  + ]:       1096 :         assert(ret);
     300   [ +  -  -  + ]:       1096 :         assert(IN_SET(scope, UNIT_FILE_SYSTEM, UNIT_FILE_USER, UNIT_FILE_GLOBAL));
     301                 :            : 
     302         [ +  + ]:       1096 :         if (scope == UNIT_FILE_GLOBAL)
     303                 :         12 :                 return -EOPNOTSUPP;
     304                 :            : 
     305         [ +  + ]:       1084 :         if (tempdir)
     306                 :         52 :                 transient = path_join(tempdir, "transient");
     307         [ +  + ]:       1032 :         else if (scope == UNIT_FILE_SYSTEM)
     308                 :       1020 :                 transient = strdup("/run/systemd/transient");
     309                 :            :         else
     310                 :         12 :                 return xdg_user_runtime_dir(ret, "/systemd/transient");
     311                 :            : 
     312         [ -  + ]:       1072 :         if (!transient)
     313                 :          0 :                 return -ENOMEM;
     314                 :       1072 :         *ret = transient;
     315                 :       1072 :         return 0;
     316                 :            : }
     317                 :            : 
     318                 :       1160 : static int acquire_config_dirs(UnitFileScope scope, char **persistent, char **runtime) {
     319                 :       1160 :         _cleanup_free_ char *a = NULL, *b = NULL;
     320                 :            :         int r;
     321                 :            : 
     322         [ -  + ]:       1160 :         assert(persistent);
     323         [ -  + ]:       1160 :         assert(runtime);
     324                 :            : 
     325   [ +  +  +  - ]:       1160 :         switch (scope) {
     326                 :            : 
     327                 :       1020 :         case UNIT_FILE_SYSTEM:
     328                 :       1020 :                 a = strdup(SYSTEM_CONFIG_UNIT_PATH);
     329                 :       1020 :                 b = strdup("/run/systemd/system");
     330                 :       1020 :                 break;
     331                 :            : 
     332                 :         76 :         case UNIT_FILE_GLOBAL:
     333                 :         76 :                 a = strdup(USER_CONFIG_UNIT_PATH);
     334                 :         76 :                 b = strdup("/run/systemd/user");
     335                 :         76 :                 break;
     336                 :            : 
     337                 :         64 :         case UNIT_FILE_USER:
     338                 :         64 :                 r = xdg_user_config_dir(&a, "/systemd/user");
     339   [ -  +  #  # ]:         64 :                 if (r < 0 && r != -ENXIO)
     340                 :          0 :                         return r;
     341                 :            : 
     342                 :         64 :                 r = xdg_user_runtime_dir(runtime, "/systemd/user");
     343         [ -  + ]:         64 :                 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                 :         64 :                 *persistent = TAKE_PTR(a);
     353                 :            : 
     354                 :         64 :                 return 0;
     355                 :            : 
     356                 :          0 :         default:
     357                 :          0 :                 assert_not_reached("Hmm, unexpected scope value.");
     358                 :            :         }
     359                 :            : 
     360   [ +  -  -  + ]:       1096 :         if (!a || !b)
     361                 :          0 :                 return -ENOMEM;
     362                 :            : 
     363                 :       1096 :         *persistent = TAKE_PTR(a);
     364                 :       1096 :         *runtime = TAKE_PTR(b);
     365                 :            : 
     366                 :       1096 :         return 0;
     367                 :            : }
     368                 :            : 
     369                 :       1096 : static int acquire_control_dirs(UnitFileScope scope, char **persistent, char **runtime) {
     370                 :       1096 :         _cleanup_free_ char *a = NULL;
     371                 :            :         int r;
     372                 :            : 
     373         [ -  + ]:       1096 :         assert(persistent);
     374         [ -  + ]:       1096 :         assert(runtime);
     375                 :            : 
     376   [ +  +  +  - ]:       1096 :         switch (scope) {
     377                 :            : 
     378                 :       1020 :         case UNIT_FILE_SYSTEM:  {
     379         [ -  + ]:       1020 :                 _cleanup_free_ char *b = NULL;
     380                 :            : 
     381                 :       1020 :                 a = strdup("/etc/systemd/system.control");
     382         [ -  + ]:       1020 :                 if (!a)
     383                 :          0 :                         return -ENOMEM;
     384                 :            : 
     385                 :       1020 :                 b = strdup("/run/systemd/system.control");
     386         [ -  + ]:       1020 :                 if (!b)
     387                 :          0 :                         return -ENOMEM;
     388                 :            : 
     389                 :       1020 :                 *runtime = TAKE_PTR(b);
     390                 :            : 
     391                 :       1020 :                 break;
     392                 :            :         }
     393                 :            : 
     394                 :         64 :         case UNIT_FILE_USER:
     395                 :         64 :                 r = xdg_user_config_dir(&a, "/systemd/user.control");
     396   [ -  +  #  # ]:         64 :                 if (r < 0 && r != -ENXIO)
     397                 :          0 :                         return r;
     398                 :            : 
     399                 :         64 :                 r = xdg_user_runtime_dir(runtime, "/systemd/user.control");
     400         [ -  + ]:         64 :                 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                 :         64 :                 break;
     410                 :            : 
     411                 :         12 :         case UNIT_FILE_GLOBAL:
     412                 :         12 :                 return -EOPNOTSUPP;
     413                 :            : 
     414                 :          0 :         default:
     415                 :          0 :                 assert_not_reached("Hmm, unexpected scope value.");
     416                 :            :         }
     417                 :            : 
     418                 :       1084 :         *persistent = TAKE_PTR(a);
     419                 :            : 
     420                 :       1084 :         return 0;
     421                 :            : }
     422                 :            : 
     423                 :       1096 : static int acquire_attached_dirs(
     424                 :            :                 UnitFileScope scope,
     425                 :            :                 char **ret_persistent,
     426                 :            :                 char **ret_runtime) {
     427                 :            : 
     428                 :       1096 :         _cleanup_free_ char *a = NULL, *b = NULL;
     429                 :            : 
     430         [ -  + ]:       1096 :         assert(ret_persistent);
     431         [ -  + ]:       1096 :         assert(ret_runtime);
     432                 :            : 
     433                 :            :         /* Portable services are not available to regular users for now. */
     434         [ +  + ]:       1096 :         if (scope != UNIT_FILE_SYSTEM)
     435                 :         76 :                 return -EOPNOTSUPP;
     436                 :            : 
     437                 :       1020 :         a = strdup("/etc/systemd/system.attached");
     438         [ -  + ]:       1020 :         if (!a)
     439                 :          0 :                 return -ENOMEM;
     440                 :            : 
     441                 :       1020 :         b = strdup("/run/systemd/system.attached");
     442         [ -  + ]:       1020 :         if (!b)
     443                 :          0 :                 return -ENOMEM;
     444                 :            : 
     445                 :       1020 :         *ret_persistent = TAKE_PTR(a);
     446                 :       1020 :         *ret_runtime = TAKE_PTR(b);
     447                 :            : 
     448                 :       1020 :         return 0;
     449                 :            : }
     450                 :            : 
     451                 :      25808 : static int patch_root_prefix(char **p, const char *root_dir) {
     452                 :            :         char *c;
     453                 :            : 
     454         [ -  + ]:      25808 :         assert(p);
     455                 :            : 
     456         [ +  + ]:      25808 :         if (!*p)
     457                 :        452 :                 return 0;
     458                 :            : 
     459                 :      25356 :         c = path_join(root_dir, *p);
     460         [ -  + ]:      25356 :         if (!c)
     461                 :          0 :                 return -ENOMEM;
     462                 :            : 
     463                 :      25356 :         free_and_replace(*p, c);
     464                 :      25356 :         return 0;
     465                 :            : }
     466                 :            : 
     467                 :       1096 : static int patch_root_prefix_strv(char **l, const char *root_dir) {
     468                 :            :         char **i;
     469                 :            :         int r;
     470                 :            : 
     471         [ +  + ]:       1096 :         if (!root_dir)
     472                 :        168 :                 return 0;
     473                 :            : 
     474   [ +  -  +  + ]:      15776 :         STRV_FOREACH(i, l) {
     475                 :      14848 :                 r = patch_root_prefix(i, root_dir);
     476         [ -  + ]:      14848 :                 if (r < 0)
     477                 :          0 :                         return r;
     478                 :            :         }
     479                 :            : 
     480                 :        928 :         return 0;
     481                 :            : }
     482                 :            : 
     483                 :       1096 : int lookup_paths_init(
     484                 :            :                 LookupPaths *p,
     485                 :            :                 UnitFileScope scope,
     486                 :            :                 LookupPathsFlags flags,
     487                 :            :                 const char *root_dir) {
     488                 :            : 
     489                 :       1096 :         _cleanup_(rmdir_and_freep) char *tempdir = NULL;
     490                 :            :         _cleanup_free_ char
     491                 :       1096 :                 *root = NULL,
     492                 :       1096 :                 *persistent_config = NULL, *runtime_config = NULL,
     493                 :       1096 :                 *global_persistent_config = NULL, *global_runtime_config = NULL,
     494                 :       1096 :                 *generator = NULL, *generator_early = NULL, *generator_late = NULL,
     495                 :       1096 :                 *transient = NULL,
     496                 :       1096 :                 *persistent_control = NULL, *runtime_control = NULL,
     497                 :       1096 :                 *persistent_attached = NULL, *runtime_attached = NULL;
     498                 :       1096 :         bool append = false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */
     499                 :       1096 :         _cleanup_strv_free_ char **paths = NULL;
     500                 :            :         const char *e;
     501                 :            :         int r;
     502                 :            : 
     503         [ -  + ]:       1096 :         assert(p);
     504         [ -  + ]:       1096 :         assert(scope >= 0);
     505         [ -  + ]:       1096 :         assert(scope < _UNIT_FILE_SCOPE_MAX);
     506                 :            : 
     507                 :            : #if HAVE_SPLIT_USR
     508                 :            :         flags |= LOOKUP_PATHS_SPLIT_USR;
     509                 :            : #endif
     510                 :            : 
     511         [ +  + ]:       1096 :         if (!empty_or_root(root_dir)) {
     512         [ -  + ]:        928 :                 if (scope == UNIT_FILE_USER)
     513                 :          0 :                         return -EINVAL;
     514                 :            : 
     515                 :        928 :                 r = is_dir(root_dir, true);
     516         [ -  + ]:        928 :                 if (r < 0)
     517                 :          0 :                         return r;
     518         [ -  + ]:        928 :                 if (r == 0)
     519                 :          0 :                         return -ENOTDIR;
     520                 :            : 
     521                 :        928 :                 root = strdup(root_dir);
     522         [ -  + ]:        928 :                 if (!root)
     523                 :          0 :                         return -ENOMEM;
     524                 :            :         }
     525                 :            : 
     526         [ +  + ]:       1096 :         if (flags & LOOKUP_PATHS_TEMPORARY_GENERATED) {
     527                 :         52 :                 r = mkdtemp_malloc("/tmp/systemd-temporary-XXXXXX", &tempdir);
     528         [ -  + ]:         52 :                 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                 :       1096 :         r = acquire_config_dirs(scope, &persistent_config, &runtime_config);
     534         [ -  + ]:       1096 :         if (r < 0)
     535                 :          0 :                 return r;
     536                 :            : 
     537         [ +  + ]:       1096 :         if (scope == UNIT_FILE_USER) {
     538                 :         64 :                 r = acquire_config_dirs(UNIT_FILE_GLOBAL, &global_persistent_config, &global_runtime_config);
     539         [ -  + ]:         64 :                 if (r < 0)
     540                 :          0 :                         return r;
     541                 :            :         }
     542                 :            : 
     543         [ +  + ]:       1096 :         if ((flags & LOOKUP_PATHS_EXCLUDE_GENERATED) == 0) {
     544                 :            :                 /* Note: if XDG_RUNTIME_DIR is not set, this will fail completely with ENXIO */
     545                 :       1020 :                 r = acquire_generator_dirs(scope, tempdir,
     546                 :            :                                            &generator, &generator_early, &generator_late);
     547   [ +  +  +  -  :       1020 :                 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                 :       1096 :         r = acquire_transient_dir(scope, tempdir, &transient);
     553   [ +  +  +  -  :       1096 :         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                 :       1096 :         r = acquire_control_dirs(scope, &persistent_control, &runtime_control);
     558   [ +  +  -  + ]:       1096 :         if (r < 0 && r != -EOPNOTSUPP)
     559                 :          0 :                 return r;
     560                 :            : 
     561                 :       1096 :         r = acquire_attached_dirs(scope, &persistent_attached, &runtime_attached);
     562   [ +  +  -  + ]:       1096 :         if (r < 0 && r != -EOPNOTSUPP)
     563                 :          0 :                 return r;
     564                 :            : 
     565                 :            :         /* First priority is whatever has been passed to us via env vars */
     566                 :       1096 :         e = getenv("SYSTEMD_UNIT_PATH");
     567         [ +  + ]:       1096 :         if (e) {
     568                 :            :                 const char *k;
     569                 :            : 
     570                 :        132 :                 k = endswith(e, ":");
     571         [ -  + ]:        132 :                 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                 :        132 :                 r = path_split_and_make_absolute(e, &paths);
     579         [ -  + ]:        132 :                 if (r < 0)
     580                 :          0 :                         return r;
     581                 :            :         }
     582                 :            : 
     583   [ +  +  -  + ]:       1096 :         if (!paths || append) {
     584                 :            :                 /* Let's figure something out. */
     585                 :            : 
     586         [ +  - ]:        964 :                 _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   [ +  +  +  - ]:        964 :                 switch (scope) {
     595                 :            : 
     596                 :        940 :                 case UNIT_FILE_SYSTEM:
     597         [ -  + ]:        940 :                         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                 :        940 :                         break;
     618                 :            : 
     619                 :          8 :                 case UNIT_FILE_GLOBAL:
     620                 :          8 :                         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                 :          8 :                         break;
     641                 :            : 
     642                 :         16 :                 case UNIT_FILE_USER:
     643                 :         16 :                         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                 :         16 :                         break;
     649                 :            : 
     650                 :          0 :                 default:
     651                 :          0 :                         assert_not_reached("Hmm, unexpected scope?");
     652                 :            :                 }
     653                 :            : 
     654         [ -  + ]:        964 :                 if (!add)
     655                 :          0 :                         return -ENOMEM;
     656                 :            : 
     657         [ -  + ]:        964 :                 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                 :        964 :                         paths = TAKE_PTR(add);
     665                 :            :         }
     666                 :            : 
     667                 :       1096 :         r = patch_root_prefix(&persistent_config, root);
     668         [ -  + ]:       1096 :         if (r < 0)
     669                 :          0 :                 return r;
     670                 :       1096 :         r = patch_root_prefix(&runtime_config, root);
     671         [ -  + ]:       1096 :         if (r < 0)
     672                 :          0 :                 return r;
     673                 :            : 
     674                 :       1096 :         r = patch_root_prefix(&generator, root);
     675         [ -  + ]:       1096 :         if (r < 0)
     676                 :          0 :                 return r;
     677                 :       1096 :         r = patch_root_prefix(&generator_early, root);
     678         [ -  + ]:       1096 :         if (r < 0)
     679                 :          0 :                 return r;
     680                 :       1096 :         r = patch_root_prefix(&generator_late, root);
     681         [ -  + ]:       1096 :         if (r < 0)
     682                 :          0 :                 return r;
     683                 :            : 
     684                 :       1096 :         r = patch_root_prefix(&transient, root);
     685         [ -  + ]:       1096 :         if (r < 0)
     686                 :          0 :                 return r;
     687                 :            : 
     688                 :       1096 :         r = patch_root_prefix(&persistent_control, root);
     689         [ -  + ]:       1096 :         if (r < 0)
     690                 :          0 :                 return r;
     691                 :       1096 :         r = patch_root_prefix(&runtime_control, root);
     692         [ -  + ]:       1096 :         if (r < 0)
     693                 :          0 :                 return r;
     694                 :            : 
     695                 :       1096 :         r = patch_root_prefix(&persistent_attached, root);
     696         [ -  + ]:       1096 :         if (r < 0)
     697                 :          0 :                 return r;
     698                 :       1096 :         r = patch_root_prefix(&runtime_attached, root);
     699         [ -  + ]:       1096 :         if (r < 0)
     700                 :          0 :                 return r;
     701                 :            : 
     702                 :       1096 :         r = patch_root_prefix_strv(paths, root);
     703         [ -  + ]:       1096 :         if (r < 0)
     704                 :          0 :                 return -ENOMEM;
     705                 :            : 
     706                 :       1096 :         *p = (LookupPaths) {
     707                 :       1096 :                 .search_path = strv_uniq(paths),
     708                 :            : 
     709                 :       1096 :                 .persistent_config = TAKE_PTR(persistent_config),
     710                 :       1096 :                 .runtime_config = TAKE_PTR(runtime_config),
     711                 :            : 
     712                 :       1096 :                 .generator = TAKE_PTR(generator),
     713                 :       1096 :                 .generator_early = TAKE_PTR(generator_early),
     714                 :       1096 :                 .generator_late = TAKE_PTR(generator_late),
     715                 :            : 
     716                 :       1096 :                 .transient = TAKE_PTR(transient),
     717                 :            : 
     718                 :       1096 :                 .persistent_control = TAKE_PTR(persistent_control),
     719                 :       1096 :                 .runtime_control = TAKE_PTR(runtime_control),
     720                 :            : 
     721                 :       1096 :                 .persistent_attached = TAKE_PTR(persistent_attached),
     722                 :       1096 :                 .runtime_attached = TAKE_PTR(runtime_attached),
     723                 :            : 
     724                 :       1096 :                 .root_dir = TAKE_PTR(root),
     725                 :       1096 :                 .temporary_dir = TAKE_PTR(tempdir),
     726                 :            :         };
     727                 :            : 
     728                 :       1096 :         paths = NULL;
     729                 :       1096 :         return 0;
     730                 :            : }
     731                 :            : 
     732                 :       1100 : void lookup_paths_free(LookupPaths *p) {
     733         [ -  + ]:       1100 :         if (!p)
     734                 :          0 :                 return;
     735                 :            : 
     736                 :       1100 :         p->search_path = strv_free(p->search_path);
     737                 :            : 
     738                 :       1100 :         p->persistent_config = mfree(p->persistent_config);
     739                 :       1100 :         p->runtime_config = mfree(p->runtime_config);
     740                 :            : 
     741                 :       1100 :         p->persistent_attached = mfree(p->persistent_attached);
     742                 :       1100 :         p->runtime_attached = mfree(p->runtime_attached);
     743                 :            : 
     744                 :       1100 :         p->generator = mfree(p->generator);
     745                 :       1100 :         p->generator_early = mfree(p->generator_early);
     746                 :       1100 :         p->generator_late = mfree(p->generator_late);
     747                 :            : 
     748                 :       1100 :         p->transient = mfree(p->transient);
     749                 :            : 
     750                 :       1100 :         p->persistent_control = mfree(p->persistent_control);
     751                 :       1100 :         p->runtime_control = mfree(p->runtime_control);
     752                 :            : 
     753                 :       1100 :         p->root_dir = mfree(p->root_dir);
     754                 :       1100 :         p->temporary_dir = mfree(p->temporary_dir);
     755                 :            : }
     756                 :            : 
     757                 :         76 : int lookup_paths_reduce(LookupPaths *p) {
     758                 :         76 :         _cleanup_free_ struct stat *stats = NULL;
     759                 :         76 :         size_t n_stats = 0, allocated = 0;
     760                 :         76 :         size_t c = 0;
     761                 :            :         int r;
     762                 :            : 
     763         [ -  + ]:         76 :         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         [ -  + ]:         76 :         if (!p->search_path)
     769                 :          0 :                 return 0;
     770                 :            : 
     771         [ +  + ]:        408 :         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   [ +  +  +  + ]:        648 :                 if (path_equal_ptr(p->search_path[c], p->transient) ||
     777         [ +  + ]:        616 :                     path_equal_ptr(p->search_path[c], p->persistent_control) ||
     778                 :        300 :                     path_equal_ptr(p->search_path[c], p->runtime_control)) {
     779                 :         48 :                         c++;
     780                 :        144 :                         continue;
     781                 :            :                 }
     782                 :            : 
     783                 :        284 :                 r = chase_symlinks_and_stat(p->search_path[c], p->root_dir, 0, NULL, &st);
     784         [ +  + ]:        284 :                 if (r == -ENOENT)
     785                 :        188 :                         goto remove_item;
     786         [ -  + ]:         96 :                 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         [ +  + ]:        152 :                 for (k = 0; k < n_stats; k++)
     794         [ +  + ]:         56 :                         if (stats[k].st_dev == st.st_dev &&
     795         [ -  + ]:         32 :                             stats[k].st_ino == st.st_ino)
     796                 :          0 :                                 break;
     797                 :            : 
     798         [ -  + ]:         96 :                 if (k < n_stats) /* Is there already an entry with the same device/inode? */
     799                 :          0 :                         goto remove_item;
     800                 :            : 
     801         [ -  + ]:         96 :                 if (!GREEDY_REALLOC(stats, allocated, n_stats+1))
     802                 :          0 :                         return -ENOMEM;
     803                 :            : 
     804                 :         96 :                 stats[n_stats++] = st;
     805                 :         96 :                 c++;
     806                 :         96 :                 continue;
     807                 :            : 
     808                 :        188 :         remove_item:
     809                 :        188 :                 free(p->search_path[c]);
     810                 :        564 :                 memmove(p->search_path + c,
     811                 :        376 :                         p->search_path + c + 1,
     812                 :        188 :                         (strv_length(p->search_path + c + 1) + 1) * sizeof(char*));
     813                 :            :         }
     814                 :            : 
     815         [ +  + ]:         76 :         if (strv_isempty(p->search_path)) {
     816         [ +  - ]:         12 :                 log_debug("Ignoring unit files.");
     817                 :         12 :                 p->search_path = strv_free(p->search_path);
     818                 :            :         } else {
     819         [ +  - ]:         64 :                 _cleanup_free_ char *t;
     820                 :            : 
     821                 :         64 :                 t = strv_join(p->search_path, "\n\t");
     822         [ -  + ]:         64 :                 if (!t)
     823                 :          0 :                         return -ENOMEM;
     824                 :            : 
     825         [ +  + ]:         64 :                 log_debug("Looking for unit files in (higher priority first):\n\t%s", t);
     826                 :            :         }
     827                 :            : 
     828                 :         76 :         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                 :         56 : void lookup_paths_flush_generator(LookupPaths *p) {
     866         [ -  + ]:         56 :         assert(p);
     867                 :            : 
     868                 :            :         /* Flush the generated unit files in full */
     869                 :            : 
     870         [ +  + ]:         56 :         if (p->generator)
     871                 :         52 :                 (void) rm_rf(p->generator, REMOVE_ROOT|REMOVE_PHYSICAL);
     872         [ +  + ]:         56 :         if (p->generator_early)
     873                 :         52 :                 (void) rm_rf(p->generator_early, REMOVE_ROOT|REMOVE_PHYSICAL);
     874         [ +  + ]:         56 :         if (p->generator_late)
     875                 :         52 :                 (void) rm_rf(p->generator_late, REMOVE_ROOT|REMOVE_PHYSICAL);
     876                 :            : 
     877         [ +  + ]:         56 :         if (p->temporary_dir)
     878                 :         52 :                 (void) rm_rf(p->temporary_dir, REMOVE_ROOT|REMOVE_PHYSICAL);
     879                 :         56 : }
     880                 :            : 
     881                 :          8 : char **generator_binary_paths(UnitFileScope scope) {
     882                 :            : 
     883      [ +  +  - ]:          8 :         switch (scope) {
     884                 :            : 
     885                 :          4 :         case UNIT_FILE_SYSTEM:
     886                 :          4 :                 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                 :          4 :         case UNIT_FILE_GLOBAL:
     892                 :            :         case UNIT_FILE_USER:
     893                 :          4 :                 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