LCOV - code coverage report
Current view: top level - shared - path-lookup.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 137 194 70.6 %
Date: 2015-07-29 18:47:03 Functions: 8 8 100.0 %

          Line data    Source code
       1             : /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
       2             : 
       3             : /***
       4             :   This file is part of systemd.
       5             : 
       6             :   Copyright 2010 Lennart Poettering
       7             : 
       8             :   systemd is free software; you can redistribute it and/or modify it
       9             :   under the terms of the GNU Lesser General Public License as published by
      10             :   the Free Software Foundation; either version 2.1 of the License, or
      11             :   (at your option) any later version.
      12             : 
      13             :   systemd is distributed in the hope that it will be useful, but
      14             :   WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
      16             :   Lesser General Public License for more details.
      17             : 
      18             :   You should have received a copy of the GNU Lesser General Public License
      19             :   along with systemd; If not, see <http://www.gnu.org/licenses/>.
      20             : ***/
      21             : 
      22             : #include <stdlib.h>
      23             : #include <stdio.h>
      24             : #include <string.h>
      25             : #include <errno.h>
      26             : 
      27             : #include "util.h"
      28             : #include "strv.h"
      29             : #include "path-util.h"
      30             : #include "path-lookup.h"
      31             : #include "install.h"
      32             : 
      33           1 : int user_config_home(char **config_home) {
      34             :         const char *e;
      35             :         char *r;
      36             : 
      37           1 :         e = getenv("XDG_CONFIG_HOME");
      38           1 :         if (e) {
      39           0 :                 r = strappend(e, "/systemd/user");
      40           0 :                 if (!r)
      41           0 :                         return -ENOMEM;
      42             : 
      43           0 :                 *config_home = r;
      44           0 :                 return 1;
      45             :         } else {
      46             :                 const char *home;
      47             : 
      48           1 :                 home = getenv("HOME");
      49           1 :                 if (home) {
      50           1 :                         r = strappend(home, "/.config/systemd/user");
      51           1 :                         if (!r)
      52           0 :                                 return -ENOMEM;
      53             : 
      54           1 :                         *config_home = r;
      55           1 :                         return 1;
      56             :                 }
      57             :         }
      58             : 
      59           0 :         return 0;
      60             : }
      61             : 
      62           1 : int user_runtime_dir(char **runtime_dir) {
      63             :         const char *e;
      64             :         char *r;
      65             : 
      66           1 :         e = getenv("XDG_RUNTIME_DIR");
      67           1 :         if (e) {
      68           1 :                 r = strappend(e, "/systemd/user");
      69           1 :                 if (!r)
      70           0 :                         return -ENOMEM;
      71             : 
      72           1 :                 *runtime_dir = r;
      73           1 :                 return 1;
      74             :         }
      75             : 
      76           0 :         return 0;
      77             : }
      78             : 
      79           1 : static int user_data_home_dir(char **dir, const char *suffix) {
      80             :         const char *e;
      81             :         char *res;
      82             : 
      83             :         /* We don't treat /etc/xdg/systemd here as the spec
      84             :          * suggests because we assume that that is a link to
      85             :          * /etc/systemd/ anyway. */
      86             : 
      87           1 :         e = getenv("XDG_DATA_HOME");
      88           1 :         if (e)
      89           0 :                 res = strappend(e, suffix);
      90             :         else {
      91             :                 const char *home;
      92             : 
      93           1 :                 home = getenv("HOME");
      94           1 :                 if (home)
      95           1 :                         res = strjoin(home, "/.local/share", suffix, NULL);
      96             :                 else
      97           0 :                         return 0;
      98             :         }
      99           1 :         if (!res)
     100           0 :                 return -ENOMEM;
     101             : 
     102           1 :         *dir = res;
     103           1 :         return 0;
     104             : }
     105             : 
     106           1 : static char** user_dirs(
     107             :                 const char *generator,
     108             :                 const char *generator_early,
     109             :                 const char *generator_late) {
     110             : 
     111           1 :         const char * const config_unit_paths[] = {
     112             :                 USER_CONFIG_UNIT_PATH,
     113             :                 "/etc/systemd/user",
     114             :                 NULL
     115             :         };
     116             : 
     117           1 :         const char * const runtime_unit_path = "/run/systemd/user";
     118             : 
     119           1 :         const char * const data_unit_paths[] = {
     120             :                 "/usr/local/lib/systemd/user",
     121             :                 "/usr/local/share/systemd/user",
     122             :                 USER_DATA_UNIT_PATH,
     123             :                 "/usr/lib/systemd/user",
     124             :                 "/usr/share/systemd/user",
     125             :                 NULL
     126             :         };
     127             : 
     128             :         const char *e;
     129           2 :         _cleanup_free_ char *config_home = NULL, *runtime_dir = NULL, *data_home = NULL;
     130           2 :         _cleanup_strv_free_ char **config_dirs = NULL, **data_dirs = NULL;
     131           2 :         _cleanup_free_ char **res = NULL;
     132             :         char **tmp;
     133             :         int r;
     134             : 
     135             :         /* Implement the mechanisms defined in
     136             :          *
     137             :          * http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
     138             :          *
     139             :          * We look in both the config and the data dirs because we
     140             :          * want to encourage that distributors ship their unit files
     141             :          * as data, and allow overriding as configuration.
     142             :          */
     143             : 
     144           1 :         if (user_config_home(&config_home) < 0)
     145           0 :                 return NULL;
     146             : 
     147           1 :         if (user_runtime_dir(&runtime_dir) < 0)
     148           0 :                 return NULL;
     149             : 
     150           1 :         e = getenv("XDG_CONFIG_DIRS");
     151           1 :         if (e) {
     152           0 :                 config_dirs = strv_split(e, ":");
     153           0 :                 if (!config_dirs)
     154           0 :                         return NULL;
     155             :         }
     156             : 
     157           1 :         r = user_data_home_dir(&data_home, "/systemd/user");
     158           1 :         if (r < 0)
     159           0 :                 return NULL;
     160             : 
     161           1 :         e = getenv("XDG_DATA_DIRS");
     162           1 :         if (e)
     163           0 :                 data_dirs = strv_split(e, ":");
     164             :         else
     165           1 :                 data_dirs = strv_new("/usr/local/share",
     166             :                                      "/usr/share",
     167             :                                      NULL);
     168           1 :         if (!data_dirs)
     169           0 :                 return NULL;
     170             : 
     171             :         /* Now merge everything we found. */
     172           1 :         if (generator_early)
     173           1 :                 if (strv_extend(&res, generator_early) < 0)
     174           0 :                         return NULL;
     175             : 
     176           1 :         if (config_home)
     177           1 :                 if (strv_extend(&res, config_home) < 0)
     178           0 :                         return NULL;
     179             : 
     180           1 :         if (!strv_isempty(config_dirs))
     181           0 :                 if (strv_extend_strv_concat(&res, config_dirs, "/systemd/user") < 0)
     182           0 :                         return NULL;
     183             : 
     184           1 :         if (strv_extend_strv(&res, (char**) config_unit_paths) < 0)
     185           0 :                 return NULL;
     186             : 
     187           1 :         if (runtime_dir)
     188           1 :                 if (strv_extend(&res, runtime_dir) < 0)
     189           0 :                         return NULL;
     190             : 
     191           1 :         if (strv_extend(&res, runtime_unit_path) < 0)
     192           0 :                 return NULL;
     193             : 
     194           1 :         if (generator)
     195           1 :                 if (strv_extend(&res, generator) < 0)
     196           0 :                         return NULL;
     197             : 
     198           1 :         if (data_home)
     199           1 :                 if (strv_extend(&res, data_home) < 0)
     200           0 :                         return NULL;
     201             : 
     202           1 :         if (!strv_isempty(data_dirs))
     203           1 :                 if (strv_extend_strv_concat(&res, data_dirs, "/systemd/user") < 0)
     204           0 :                         return NULL;
     205             : 
     206           1 :         if (strv_extend_strv(&res, (char**) data_unit_paths) < 0)
     207           0 :                 return NULL;
     208             : 
     209           1 :         if (generator_late)
     210           1 :                 if (strv_extend(&res, generator_late) < 0)
     211           0 :                         return NULL;
     212             : 
     213           1 :         if (!path_strv_make_absolute_cwd(res))
     214           0 :                 return NULL;
     215             : 
     216           1 :         tmp = res;
     217           1 :         res = NULL;
     218           1 :         return tmp;
     219             : }
     220             : 
     221           2 : char **generator_paths(ManagerRunningAs running_as) {
     222           2 :         if (running_as == MANAGER_USER)
     223           1 :                 return strv_new("/run/systemd/user-generators",
     224             :                                 "/etc/systemd/user-generators",
     225             :                                 "/usr/local/lib/systemd/user-generators",
     226             :                                 USER_GENERATOR_PATH,
     227             :                                 NULL);
     228             :         else
     229           1 :                 return strv_new("/run/systemd/system-generators",
     230             :                                 "/etc/systemd/system-generators",
     231             :                                 "/usr/local/lib/systemd/system-generators",
     232             :                                 SYSTEM_GENERATOR_PATH,
     233             :                                 NULL);
     234             : }
     235             : 
     236          34 : int lookup_paths_init(
     237             :                 LookupPaths *p,
     238             :                 ManagerRunningAs running_as,
     239             :                 bool personal,
     240             :                 const char *root_dir,
     241             :                 const char *generator,
     242             :                 const char *generator_early,
     243             :                 const char *generator_late) {
     244             : 
     245             :         const char *e;
     246          34 :         bool append = false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */
     247             : 
     248          34 :         assert(p);
     249             : 
     250             :         /* First priority is whatever has been passed to us via env
     251             :          * vars */
     252          34 :         e = getenv("SYSTEMD_UNIT_PATH");
     253          34 :         if (e) {
     254          29 :                 if (endswith(e, ":")) {
     255           0 :                         e = strndupa(e, strlen(e) - 1);
     256           0 :                         append = true;
     257             :                 }
     258             : 
     259             :                 /* FIXME: empty components in other places should be
     260             :                  * rejected. */
     261             : 
     262          29 :                 p->unit_path = path_split_and_make_absolute(e);
     263          29 :                 if (!p->unit_path)
     264           0 :                         return -ENOMEM;
     265             :         } else
     266           5 :                 p->unit_path = NULL;
     267             : 
     268          34 :         if (!p->unit_path || append) {
     269             :                 /* Let's figure something out. */
     270             : 
     271           5 :                 _cleanup_strv_free_ char **unit_path;
     272             :                 int r;
     273             : 
     274             :                 /* For the user units we include share/ in the search
     275             :                  * path in order to comply with the XDG basedir spec.
     276             :                  * For the system stuff we avoid such nonsense. OTOH
     277             :                  * we include /lib in the search path for the system
     278             :                  * stuff but avoid it for user stuff. */
     279             : 
     280           5 :                 if (running_as == MANAGER_USER) {
     281           2 :                         if (personal)
     282           1 :                                 unit_path = user_dirs(generator, generator_early, generator_late);
     283             :                         else
     284           1 :                                 unit_path = strv_new(
     285             :                                         /* If you modify this you also want to modify
     286             :                                          * systemduserunitpath= in systemd.pc.in, and
     287             :                                          * the arrays in user_dirs() above! */
     288             :                                         STRV_IFNOTNULL(generator_early),
     289             :                                         USER_CONFIG_UNIT_PATH,
     290             :                                         "/etc/systemd/user",
     291             :                                         "/run/systemd/user",
     292             :                                         STRV_IFNOTNULL(generator),
     293             :                                         "/usr/local/lib/systemd/user",
     294             :                                         "/usr/local/share/systemd/user",
     295             :                                         USER_DATA_UNIT_PATH,
     296             :                                         "/usr/lib/systemd/user",
     297             :                                         "/usr/share/systemd/user",
     298             :                                         STRV_IFNOTNULL(generator_late),
     299             :                                         NULL);
     300             :                 } else
     301           3 :                         unit_path = strv_new(
     302             :                                 /* If you modify this you also want to modify
     303             :                                  * systemdsystemunitpath= in systemd.pc.in! */
     304             :                                 STRV_IFNOTNULL(generator_early),
     305             :                                 SYSTEM_CONFIG_UNIT_PATH,
     306             :                                 "/etc/systemd/system",
     307             :                                 "/run/systemd/system",
     308             :                                 STRV_IFNOTNULL(generator),
     309             :                                 "/usr/local/lib/systemd/system",
     310             :                                 SYSTEM_DATA_UNIT_PATH,
     311             :                                 "/usr/lib/systemd/system",
     312             : #ifdef HAVE_SPLIT_USR
     313             :                                 "/lib/systemd/system",
     314             : #endif
     315             :                                 STRV_IFNOTNULL(generator_late),
     316             :                                 NULL);
     317             : 
     318           5 :                 if (!unit_path)
     319           0 :                         return -ENOMEM;
     320             : 
     321           5 :                 r = strv_extend_strv(&p->unit_path, unit_path);
     322           5 :                 if (r < 0)
     323           0 :                         return r;
     324             :         }
     325             : 
     326          34 :         if (!path_strv_resolve_uniq(p->unit_path, root_dir))
     327           0 :                 return -ENOMEM;
     328             : 
     329          34 :         if (!strv_isempty(p->unit_path)) {
     330          68 :                 _cleanup_free_ char *t = strv_join(p->unit_path, "\n\t");
     331          34 :                 if (!t)
     332           0 :                         return -ENOMEM;
     333          34 :                 log_debug("Looking for unit files in (higher priority first):\n\t%s", t);
     334             :         } else {
     335           0 :                 log_debug("Ignoring unit files.");
     336           0 :                 strv_free(p->unit_path);
     337           0 :                 p->unit_path = NULL;
     338             :         }
     339             : 
     340          34 :         if (running_as == MANAGER_SYSTEM) {
     341             : #ifdef HAVE_SYSV_COMPAT
     342             :                 /* /etc/init.d/ compatibility does not matter to users */
     343             : 
     344          22 :                 e = getenv("SYSTEMD_SYSVINIT_PATH");
     345          22 :                 if (e) {
     346          19 :                         p->sysvinit_path = path_split_and_make_absolute(e);
     347          19 :                         if (!p->sysvinit_path)
     348           0 :                                 return -ENOMEM;
     349             :                 } else
     350           3 :                         p->sysvinit_path = NULL;
     351             : 
     352          22 :                 if (strv_isempty(p->sysvinit_path)) {
     353           3 :                         strv_free(p->sysvinit_path);
     354             : 
     355           3 :                         p->sysvinit_path = strv_new(
     356             :                                         SYSTEM_SYSVINIT_PATH,     /* /etc/init.d/ */
     357             :                                         NULL);
     358           3 :                         if (!p->sysvinit_path)
     359           0 :                                 return -ENOMEM;
     360             :                 }
     361             : 
     362          22 :                 e = getenv("SYSTEMD_SYSVRCND_PATH");
     363          22 :                 if (e) {
     364          19 :                         p->sysvrcnd_path = path_split_and_make_absolute(e);
     365          19 :                         if (!p->sysvrcnd_path)
     366           0 :                                 return -ENOMEM;
     367             :                 } else
     368           3 :                         p->sysvrcnd_path = NULL;
     369             : 
     370          22 :                 if (strv_isempty(p->sysvrcnd_path)) {
     371           3 :                         strv_free(p->sysvrcnd_path);
     372             : 
     373           3 :                         p->sysvrcnd_path = strv_new(
     374             :                                         SYSTEM_SYSVRCND_PATH,     /* /etc/rcN.d/ */
     375             :                                         NULL);
     376           3 :                         if (!p->sysvrcnd_path)
     377           0 :                                 return -ENOMEM;
     378             :                 }
     379             : 
     380          22 :                 if (!path_strv_resolve_uniq(p->sysvinit_path, root_dir))
     381           0 :                         return -ENOMEM;
     382             : 
     383          22 :                 if (!path_strv_resolve_uniq(p->sysvrcnd_path, root_dir))
     384           0 :                         return -ENOMEM;
     385             : 
     386          22 :                 if (!strv_isempty(p->sysvinit_path)) {
     387          44 :                         _cleanup_free_ char *t = strv_join(p->sysvinit_path, "\n\t");
     388          22 :                         if (!t)
     389           0 :                                 return -ENOMEM;
     390          22 :                         log_debug("Looking for SysV init scripts in:\n\t%s", t);
     391             :                 } else {
     392           0 :                         log_debug("Ignoring SysV init scripts.");
     393           0 :                         strv_free(p->sysvinit_path);
     394           0 :                         p->sysvinit_path = NULL;
     395             :                 }
     396             : 
     397          22 :                 if (!strv_isempty(p->sysvrcnd_path)) {
     398          44 :                         _cleanup_free_ char *t =
     399          22 :                                 strv_join(p->sysvrcnd_path, "\n\t");
     400          22 :                         if (!t)
     401           0 :                                 return -ENOMEM;
     402             : 
     403          22 :                         log_debug("Looking for SysV rcN.d links in:\n\t%s", t);
     404             :                 } else {
     405           0 :                         log_debug("Ignoring SysV rcN.d links.");
     406           0 :                         strv_free(p->sysvrcnd_path);
     407           0 :                         p->sysvrcnd_path = NULL;
     408             :                 }
     409             : #else
     410             :                 log_debug("SysV init scripts and rcN.d links support disabled");
     411             : #endif
     412             :         }
     413             : 
     414          34 :         return 0;
     415             : }
     416             : 
     417          35 : void lookup_paths_free(LookupPaths *p) {
     418          35 :         assert(p);
     419             : 
     420          35 :         strv_free(p->unit_path);
     421          35 :         p->unit_path = NULL;
     422             : 
     423             : #ifdef HAVE_SYSV_COMPAT
     424          35 :         strv_free(p->sysvinit_path);
     425          35 :         strv_free(p->sysvrcnd_path);
     426          35 :         p->sysvinit_path = p->sysvrcnd_path = NULL;
     427             : #endif
     428          35 : }
     429             : 
     430           1 : int lookup_paths_init_from_scope(LookupPaths *paths,
     431             :                                  UnitFileScope scope,
     432             :                                  const char *root_dir) {
     433           1 :         assert(paths);
     434           1 :         assert(scope >= 0);
     435           1 :         assert(scope < _UNIT_FILE_SCOPE_MAX);
     436             : 
     437           1 :         zero(*paths);
     438             : 
     439           1 :         return lookup_paths_init(paths,
     440             :                                  scope == UNIT_FILE_SYSTEM ? MANAGER_SYSTEM : MANAGER_USER,
     441             :                                  scope == UNIT_FILE_USER,
     442             :                                  root_dir,
     443             :                                  NULL, NULL, NULL);
     444             : }

Generated by: LCOV version 1.11