LCOV - code coverage report
Current view: top level - shared - install.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 311 1196 26.0 %
Date: 2015-07-29 18:47:03 Functions: 24 52 46.2 %

          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 2011 Lennart Poettering
       7             : 
       8             :   systemd is free software; you can redistribute it and/or modify it
       9             :   under the terms of the GNU Lesser General Public License as published by
      10             :   the Free Software Foundation; either version 2.1 of the License, or
      11             :   (at your option) any later version.
      12             : 
      13             :   systemd is distributed in the hope that it will be useful, but
      14             :   WITHOUT ANY WARRANTY; without even the implied warranty <of
      15             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
      16             :   Lesser General Public License for more details.
      17             : 
      18             :   You should have received a copy of the GNU Lesser General Public License
      19             :   along with systemd; If not, see <http://www.gnu.org/licenses/>.
      20             : ***/
      21             : 
      22             : #include <errno.h>
      23             : #include <fcntl.h>
      24             : #include <unistd.h>
      25             : #include <string.h>
      26             : #include <fnmatch.h>
      27             : 
      28             : #include "util.h"
      29             : #include "mkdir.h"
      30             : #include "hashmap.h"
      31             : #include "set.h"
      32             : #include "path-util.h"
      33             : #include "path-lookup.h"
      34             : #include "strv.h"
      35             : #include "unit-name.h"
      36             : #include "install.h"
      37             : #include "conf-parser.h"
      38             : #include "conf-files.h"
      39             : #include "install-printf.h"
      40             : #include "special.h"
      41             : 
      42             : typedef struct {
      43             :         OrderedHashmap *will_install;
      44             :         OrderedHashmap *have_installed;
      45             : } InstallContext;
      46             : 
      47           0 : static int in_search_path(const char *path, char **search) {
      48           0 :         _cleanup_free_ char *parent = NULL;
      49             :         int r;
      50             : 
      51           0 :         assert(path);
      52             : 
      53           0 :         r = path_get_parent(path, &parent);
      54           0 :         if (r < 0)
      55           0 :                 return r;
      56             : 
      57           0 :         return strv_contains(search, parent);
      58             : }
      59             : 
      60         574 : static int get_config_path(UnitFileScope scope, bool runtime, const char *root_dir, char **ret) {
      61         574 :         char *p = NULL;
      62             :         int r;
      63             : 
      64         574 :         assert(scope >= 0);
      65         574 :         assert(scope < _UNIT_FILE_SCOPE_MAX);
      66         574 :         assert(ret);
      67             : 
      68         574 :         switch (scope) {
      69             : 
      70             :         case UNIT_FILE_SYSTEM:
      71             : 
      72         574 :                 if (runtime)
      73         287 :                         p = path_join(root_dir, "/run/systemd/system", NULL);
      74             :                 else
      75         287 :                         p = path_join(root_dir, SYSTEM_CONFIG_UNIT_PATH, NULL);
      76         574 :                 break;
      77             : 
      78             :         case UNIT_FILE_GLOBAL:
      79             : 
      80           0 :                 if (root_dir)
      81           0 :                         return -EINVAL;
      82             : 
      83           0 :                 if (runtime)
      84           0 :                         p = strdup("/run/systemd/user");
      85             :                 else
      86           0 :                         p = strdup(USER_CONFIG_UNIT_PATH);
      87           0 :                 break;
      88             : 
      89             :         case UNIT_FILE_USER:
      90             : 
      91           0 :                 if (root_dir)
      92           0 :                         return -EINVAL;
      93             : 
      94           0 :                 if (runtime)
      95           0 :                         r = user_runtime_dir(&p);
      96             :                 else
      97           0 :                         r = user_config_home(&p);
      98             : 
      99           0 :                 if (r <= 0)
     100           0 :                         return r < 0 ? r : -ENOENT;
     101             : 
     102           0 :                 break;
     103             : 
     104             :         default:
     105           0 :                 assert_not_reached("Bad scope");
     106             :         }
     107             : 
     108         574 :         if (!p)
     109           0 :                 return -ENOMEM;
     110             : 
     111         574 :         *ret = p;
     112         574 :         return 0;
     113             : }
     114             : 
     115           0 : static int mark_symlink_for_removal(
     116             :                 Set **remove_symlinks_to,
     117             :                 const char *p) {
     118             : 
     119             :         char *n;
     120             :         int r;
     121             : 
     122           0 :         assert(p);
     123             : 
     124           0 :         r = set_ensure_allocated(remove_symlinks_to, &string_hash_ops);
     125           0 :         if (r < 0)
     126           0 :                 return r;
     127             : 
     128           0 :         n = strdup(p);
     129           0 :         if (!n)
     130           0 :                 return -ENOMEM;
     131             : 
     132           0 :         path_kill_slashes(n);
     133             : 
     134           0 :         r = set_consume(*remove_symlinks_to, n);
     135           0 :         if (r < 0)
     136           0 :                 return r == -EEXIST ? 0 : r;
     137             : 
     138           0 :         return 0;
     139             : }
     140             : 
     141           0 : static int remove_marked_symlinks_fd(
     142             :                 Set *remove_symlinks_to,
     143             :                 int fd,
     144             :                 const char *path,
     145             :                 const char *config_path,
     146             :                 bool *deleted,
     147             :                 UnitFileChange **changes,
     148             :                 unsigned *n_changes,
     149             :                 char** instance_whitelist) {
     150             : 
     151           0 :         _cleanup_closedir_ DIR *d = NULL;
     152           0 :         int r = 0;
     153             : 
     154           0 :         assert(remove_symlinks_to);
     155           0 :         assert(fd >= 0);
     156           0 :         assert(path);
     157           0 :         assert(config_path);
     158           0 :         assert(deleted);
     159             : 
     160           0 :         d = fdopendir(fd);
     161           0 :         if (!d) {
     162           0 :                 safe_close(fd);
     163           0 :                 return -errno;
     164             :         }
     165             : 
     166           0 :         rewinddir(d);
     167             : 
     168             :         for (;;) {
     169             :                 struct dirent *de;
     170             : 
     171           0 :                 errno = 0;
     172           0 :                 de = readdir(d);
     173           0 :                 if (!de && errno != 0) {
     174           0 :                         r = -errno;
     175           0 :                         break;
     176             :                 }
     177             : 
     178           0 :                 if (!de)
     179           0 :                         break;
     180             : 
     181           0 :                 if (hidden_file(de->d_name))
     182           0 :                         continue;
     183             : 
     184           0 :                 dirent_ensure_type(d, de);
     185             : 
     186           0 :                 if (de->d_type == DT_DIR) {
     187             :                         int nfd, q;
     188           0 :                         _cleanup_free_ char *p = NULL;
     189             : 
     190           0 :                         nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
     191           0 :                         if (nfd < 0) {
     192           0 :                                 if (errno == ENOENT)
     193           0 :                                         continue;
     194             : 
     195           0 :                                 if (r == 0)
     196           0 :                                         r = -errno;
     197           0 :                                 continue;
     198             :                         }
     199             : 
     200           0 :                         p = path_make_absolute(de->d_name, path);
     201           0 :                         if (!p) {
     202           0 :                                 safe_close(nfd);
     203           0 :                                 return -ENOMEM;
     204             :                         }
     205             : 
     206             :                         /* This will close nfd, regardless whether it succeeds or not */
     207           0 :                         q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, deleted, changes, n_changes, instance_whitelist);
     208           0 :                         if (q < 0 && r == 0)
     209           0 :                                 r = q;
     210             : 
     211           0 :                 } else if (de->d_type == DT_LNK) {
     212           0 :                         _cleanup_free_ char *p = NULL, *dest = NULL;
     213             :                         int q;
     214             :                         bool found;
     215             : 
     216           0 :                         if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
     217           0 :                                 continue;
     218             : 
     219           0 :                         if (unit_name_is_valid(de->d_name, UNIT_NAME_INSTANCE) &&
     220           0 :                             instance_whitelist &&
     221           0 :                             !strv_contains(instance_whitelist, de->d_name)) {
     222             : 
     223           0 :                                 _cleanup_free_ char *w = NULL;
     224             : 
     225             :                                 /* OK, the file is not listed directly
     226             :                                  * in the whitelist, so let's check if
     227             :                                  * the template of it might be
     228             :                                  * listed. */
     229             : 
     230           0 :                                 r = unit_name_template(de->d_name, &w);
     231           0 :                                 if (r < 0)
     232           0 :                                         return r;
     233             : 
     234           0 :                                 if (!strv_contains(instance_whitelist, w))
     235           0 :                                         continue;
     236             :                         }
     237             : 
     238           0 :                         p = path_make_absolute(de->d_name, path);
     239           0 :                         if (!p)
     240           0 :                                 return -ENOMEM;
     241             : 
     242           0 :                         q = readlink_and_canonicalize(p, &dest);
     243           0 :                         if (q < 0) {
     244           0 :                                 if (q == -ENOENT)
     245           0 :                                         continue;
     246             : 
     247           0 :                                 if (r == 0)
     248           0 :                                         r = q;
     249           0 :                                 continue;
     250             :                         }
     251             : 
     252           0 :                         found =
     253           0 :                                 set_get(remove_symlinks_to, dest) ||
     254           0 :                                 set_get(remove_symlinks_to, basename(dest));
     255             : 
     256           0 :                         if (!found)
     257           0 :                                 continue;
     258             : 
     259           0 :                         if (unlink(p) < 0 && errno != ENOENT) {
     260           0 :                                 if (r == 0)
     261           0 :                                         r = -errno;
     262           0 :                                 continue;
     263             :                         }
     264             : 
     265           0 :                         path_kill_slashes(p);
     266           0 :                         rmdir_parents(p, config_path);
     267           0 :                         unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, p, NULL);
     268             : 
     269           0 :                         if (!set_get(remove_symlinks_to, p)) {
     270             : 
     271           0 :                                 q = mark_symlink_for_removal(&remove_symlinks_to, p);
     272           0 :                                 if (q < 0) {
     273           0 :                                         if (r == 0)
     274           0 :                                                 r = q;
     275             :                                 } else
     276           0 :                                         *deleted = true;
     277             :                         }
     278             :                 }
     279           0 :         }
     280             : 
     281           0 :         return r;
     282             : }
     283             : 
     284           0 : static int remove_marked_symlinks(
     285             :                 Set *remove_symlinks_to,
     286             :                 const char *config_path,
     287             :                 UnitFileChange **changes,
     288             :                 unsigned *n_changes,
     289             :                 char** instance_whitelist) {
     290             : 
     291           0 :         _cleanup_close_ int fd = -1;
     292           0 :         int r = 0;
     293             :         bool deleted;
     294             : 
     295           0 :         assert(config_path);
     296             : 
     297           0 :         if (set_size(remove_symlinks_to) <= 0)
     298           0 :                 return 0;
     299             : 
     300           0 :         fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
     301           0 :         if (fd < 0)
     302           0 :                 return -errno;
     303             : 
     304             :         do {
     305             :                 int q, cfd;
     306           0 :                 deleted = false;
     307             : 
     308           0 :                 cfd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
     309           0 :                 if (cfd < 0) {
     310           0 :                         r = -errno;
     311           0 :                         break;
     312             :                 }
     313             : 
     314             :                 /* This takes possession of cfd and closes it */
     315           0 :                 q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, &deleted, changes, n_changes, instance_whitelist);
     316           0 :                 if (r == 0)
     317           0 :                         r = q;
     318           0 :         } while (deleted);
     319             : 
     320           0 :         return r;
     321             : }
     322             : 
     323        2278 : static int find_symlinks_fd(
     324             :                 const char *name,
     325             :                 int fd,
     326             :                 const char *path,
     327             :                 const char *config_path,
     328             :                 bool *same_name_link) {
     329             : 
     330        2278 :         int r = 0;
     331        4556 :         _cleanup_closedir_ DIR *d = NULL;
     332             : 
     333        2278 :         assert(name);
     334        2278 :         assert(fd >= 0);
     335        2278 :         assert(path);
     336        2278 :         assert(config_path);
     337        2278 :         assert(same_name_link);
     338             : 
     339        2278 :         d = fdopendir(fd);
     340        2278 :         if (!d) {
     341           0 :                 safe_close(fd);
     342           0 :                 return -errno;
     343             :         }
     344             : 
     345             :         for (;;) {
     346             :                 struct dirent *de;
     347             : 
     348       13624 :                 errno = 0;
     349       13624 :                 de = readdir(d);
     350       13624 :                 if (!de && errno != 0)
     351           0 :                         return -errno;
     352             : 
     353       13624 :                 if (!de)
     354        2261 :                         return r;
     355             : 
     356       11363 :                 if (hidden_file(de->d_name))
     357        4556 :                         continue;
     358             : 
     359        6807 :                 dirent_ensure_type(d, de);
     360             : 
     361        6807 :                 if (de->d_type == DT_DIR) {
     362             :                         int nfd, q;
     363        3408 :                         _cleanup_free_ char *p = NULL;
     364             : 
     365        1704 :                         nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
     366        1704 :                         if (nfd < 0) {
     367           0 :                                 if (errno == ENOENT)
     368           0 :                                         continue;
     369             : 
     370           0 :                                 if (r == 0)
     371           0 :                                         r = -errno;
     372           0 :                                 continue;
     373             :                         }
     374             : 
     375        1704 :                         p = path_make_absolute(de->d_name, path);
     376        1704 :                         if (!p) {
     377           0 :                                 safe_close(nfd);
     378           0 :                                 return -ENOMEM;
     379             :                         }
     380             : 
     381             :                         /* This will close nfd, regardless whether it succeeds or not */
     382        1704 :                         q = find_symlinks_fd(name, nfd, p, config_path, same_name_link);
     383        1704 :                         if (q > 0)
     384           5 :                                 return 1;
     385        1699 :                         if (r == 0)
     386        1699 :                                 r = q;
     387             : 
     388        5103 :                 } else if (de->d_type == DT_LNK) {
     389        5642 :                         _cleanup_free_ char *p = NULL, *dest = NULL;
     390        2821 :                         bool found_path, found_dest, b = false;
     391             :                         int q;
     392             : 
     393             :                         /* Acquire symlink name */
     394        2821 :                         p = path_make_absolute(de->d_name, path);
     395        2821 :                         if (!p)
     396           0 :                                 return -ENOMEM;
     397             : 
     398             :                         /* Acquire symlink destination */
     399        2821 :                         q = readlink_and_canonicalize(p, &dest);
     400        2821 :                         if (q < 0) {
     401           0 :                                 if (q == -ENOENT)
     402           0 :                                         continue;
     403             : 
     404           0 :                                 if (r == 0)
     405           0 :                                         r = q;
     406           0 :                                 continue;
     407             :                         }
     408             : 
     409             :                         /* Check if the symlink itself matches what we
     410             :                          * are looking for */
     411        2821 :                         if (path_is_absolute(name))
     412           0 :                                 found_path = path_equal(p, name);
     413             :                         else
     414        2821 :                                 found_path = streq(de->d_name, name);
     415             : 
     416             :                         /* Check if what the symlink points to
     417             :                          * matches what we are looking for */
     418        2821 :                         if (path_is_absolute(name))
     419           0 :                                 found_dest = path_equal(dest, name);
     420             :                         else
     421        2821 :                                 found_dest = streq(basename(dest), name);
     422             : 
     423        2821 :                         if (found_path && found_dest) {
     424           8 :                                 _cleanup_free_ char *t = NULL;
     425             : 
     426             :                                 /* Filter out same name links in the main
     427             :                                  * config path */
     428           4 :                                 t = path_make_absolute(name, config_path);
     429           4 :                                 if (!t)
     430           0 :                                         return -ENOMEM;
     431             : 
     432           4 :                                 b = path_equal(t, p);
     433             :                         }
     434             : 
     435        2821 :                         if (b)
     436           0 :                                 *same_name_link = true;
     437        2821 :                         else if (found_path || found_dest)
     438          12 :                                 return 1;
     439             :                 }
     440       11346 :         }
     441             : }
     442             : 
     443         574 : static int find_symlinks(
     444             :                 const char *name,
     445             :                 const char *config_path,
     446             :                 bool *same_name_link) {
     447             : 
     448             :         int fd;
     449             : 
     450         574 :         assert(name);
     451         574 :         assert(config_path);
     452         574 :         assert(same_name_link);
     453             : 
     454         574 :         fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
     455         574 :         if (fd < 0) {
     456           0 :                 if (errno == ENOENT)
     457           0 :                         return 0;
     458           0 :                 return -errno;
     459             :         }
     460             : 
     461             :         /* This takes possession of fd and closes it */
     462         574 :         return find_symlinks_fd(name, fd, config_path, config_path, same_name_link);
     463             : }
     464             : 
     465         287 : static int find_symlinks_in_scope(
     466             :                 UnitFileScope scope,
     467             :                 const char *root_dir,
     468             :                 const char *name,
     469             :                 UnitFileState *state) {
     470             : 
     471             :         int r;
     472         574 :         _cleanup_free_ char *normal_path = NULL, *runtime_path = NULL;
     473         287 :         bool same_name_link_runtime = false, same_name_link = false;
     474             : 
     475         287 :         assert(scope >= 0);
     476         287 :         assert(scope < _UNIT_FILE_SCOPE_MAX);
     477         287 :         assert(name);
     478             : 
     479             :         /* First look in runtime config path */
     480         287 :         r = get_config_path(scope, true, root_dir, &normal_path);
     481         287 :         if (r < 0)
     482           0 :                 return r;
     483             : 
     484         287 :         r = find_symlinks(name, normal_path, &same_name_link_runtime);
     485         287 :         if (r < 0)
     486           0 :                 return r;
     487         287 :         else if (r > 0) {
     488           0 :                 *state = UNIT_FILE_ENABLED_RUNTIME;
     489           0 :                 return r;
     490             :         }
     491             : 
     492             :         /* Then look in the normal config path */
     493         287 :         r = get_config_path(scope, false, root_dir, &runtime_path);
     494         287 :         if (r < 0)
     495           0 :                 return r;
     496             : 
     497         287 :         r = find_symlinks(name, runtime_path, &same_name_link);
     498         287 :         if (r < 0)
     499           0 :                 return r;
     500         287 :         else if (r > 0) {
     501          12 :                 *state = UNIT_FILE_ENABLED;
     502          12 :                 return r;
     503             :         }
     504             : 
     505             :         /* Hmm, we didn't find it, but maybe we found the same name
     506             :          * link? */
     507         275 :         if (same_name_link_runtime) {
     508           0 :                 *state = UNIT_FILE_LINKED_RUNTIME;
     509           0 :                 return 1;
     510         275 :         } else if (same_name_link) {
     511           0 :                 *state = UNIT_FILE_LINKED;
     512           0 :                 return 1;
     513             :         }
     514             : 
     515         275 :         return 0;
     516             : }
     517             : 
     518           0 : int unit_file_mask(
     519             :                 UnitFileScope scope,
     520             :                 bool runtime,
     521             :                 const char *root_dir,
     522             :                 char **files,
     523             :                 bool force,
     524             :                 UnitFileChange **changes,
     525             :                 unsigned *n_changes) {
     526             : 
     527             :         char **i;
     528           0 :         _cleanup_free_ char *prefix = NULL;
     529             :         int r;
     530             : 
     531           0 :         assert(scope >= 0);
     532           0 :         assert(scope < _UNIT_FILE_SCOPE_MAX);
     533             : 
     534           0 :         r = get_config_path(scope, runtime, root_dir, &prefix);
     535           0 :         if (r < 0)
     536           0 :                 return r;
     537             : 
     538           0 :         STRV_FOREACH(i, files) {
     539           0 :                 _cleanup_free_ char *path = NULL;
     540             : 
     541           0 :                 if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) {
     542           0 :                         if (r == 0)
     543           0 :                                 r = -EINVAL;
     544           0 :                         continue;
     545             :                 }
     546             : 
     547           0 :                 path = path_make_absolute(*i, prefix);
     548           0 :                 if (!path) {
     549           0 :                         r = -ENOMEM;
     550           0 :                         break;
     551             :                 }
     552             : 
     553           0 :                 if (symlink("/dev/null", path) >= 0) {
     554           0 :                         unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
     555           0 :                         continue;
     556             :                 }
     557             : 
     558           0 :                 if (errno == EEXIST) {
     559             : 
     560           0 :                         if (null_or_empty_path(path) > 0)
     561           0 :                                 continue;
     562             : 
     563           0 :                         if (force) {
     564           0 :                                 if (symlink_atomic("/dev/null", path) >= 0) {
     565           0 :                                         unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
     566           0 :                                         unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
     567           0 :                                         continue;
     568             :                                 }
     569             :                         }
     570             : 
     571           0 :                         if (r == 0)
     572           0 :                                 r = -EEXIST;
     573             :                 } else {
     574           0 :                         if (r == 0)
     575           0 :                                 r = -errno;
     576             :                 }
     577             :         }
     578             : 
     579           0 :         return r;
     580             : }
     581             : 
     582           0 : int unit_file_unmask(
     583             :                 UnitFileScope scope,
     584             :                 bool runtime,
     585             :                 const char *root_dir,
     586             :                 char **files,
     587             :                 UnitFileChange **changes,
     588             :                 unsigned *n_changes) {
     589             : 
     590           0 :         char **i, *config_path = NULL;
     591             :         int r, q;
     592           0 :         Set *remove_symlinks_to = NULL;
     593             : 
     594           0 :         assert(scope >= 0);
     595           0 :         assert(scope < _UNIT_FILE_SCOPE_MAX);
     596             : 
     597           0 :         r = get_config_path(scope, runtime, root_dir, &config_path);
     598           0 :         if (r < 0)
     599           0 :                 goto finish;
     600             : 
     601           0 :         STRV_FOREACH(i, files) {
     602           0 :                 _cleanup_free_ char *path = NULL;
     603             : 
     604           0 :                 if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) {
     605           0 :                         if (r == 0)
     606           0 :                                 r = -EINVAL;
     607           0 :                         continue;
     608             :                 }
     609             : 
     610           0 :                 path = path_make_absolute(*i, config_path);
     611           0 :                 if (!path) {
     612           0 :                         r = -ENOMEM;
     613           0 :                         break;
     614             :                 }
     615             : 
     616           0 :                 q = null_or_empty_path(path);
     617           0 :                 if (q > 0) {
     618           0 :                         if (unlink(path) < 0)
     619           0 :                                 q = -errno;
     620             :                         else {
     621           0 :                                 q = mark_symlink_for_removal(&remove_symlinks_to, path);
     622           0 :                                 unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
     623             :                         }
     624             :                 }
     625             : 
     626           0 :                 if (q != -ENOENT && r == 0)
     627           0 :                         r = q;
     628             :         }
     629             : 
     630             : 
     631             : finish:
     632           0 :         q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
     633           0 :         if (r == 0)
     634           0 :                 r = q;
     635             : 
     636           0 :         set_free_free(remove_symlinks_to);
     637           0 :         free(config_path);
     638             : 
     639           0 :         return r;
     640             : }
     641             : 
     642           0 : int unit_file_link(
     643             :                 UnitFileScope scope,
     644             :                 bool runtime,
     645             :                 const char *root_dir,
     646             :                 char **files,
     647             :                 bool force,
     648             :                 UnitFileChange **changes,
     649             :                 unsigned *n_changes) {
     650             : 
     651           0 :         _cleanup_lookup_paths_free_ LookupPaths paths = {};
     652             :         char **i;
     653           0 :         _cleanup_free_ char *config_path = NULL;
     654             :         int r, q;
     655             : 
     656           0 :         assert(scope >= 0);
     657           0 :         assert(scope < _UNIT_FILE_SCOPE_MAX);
     658             : 
     659           0 :         r = lookup_paths_init_from_scope(&paths, scope, root_dir);
     660           0 :         if (r < 0)
     661           0 :                 return r;
     662             : 
     663           0 :         r = get_config_path(scope, runtime, root_dir, &config_path);
     664           0 :         if (r < 0)
     665           0 :                 return r;
     666             : 
     667           0 :         STRV_FOREACH(i, files) {
     668           0 :                 _cleanup_free_ char *path = NULL;
     669             :                 char *fn;
     670             :                 struct stat st;
     671             : 
     672           0 :                 fn = basename(*i);
     673             : 
     674           0 :                 if (!path_is_absolute(*i) ||
     675           0 :                     !unit_name_is_valid(fn, UNIT_NAME_ANY)) {
     676           0 :                         if (r == 0)
     677           0 :                                 r = -EINVAL;
     678           0 :                         continue;
     679             :                 }
     680             : 
     681           0 :                 if (lstat(*i, &st) < 0) {
     682           0 :                         if (r == 0)
     683           0 :                                 r = -errno;
     684           0 :                         continue;
     685             :                 }
     686             : 
     687           0 :                 if (!S_ISREG(st.st_mode)) {
     688           0 :                         r = -ENOENT;
     689           0 :                         continue;
     690             :                 }
     691             : 
     692           0 :                 q = in_search_path(*i, paths.unit_path);
     693           0 :                 if (q < 0)
     694           0 :                         return q;
     695             : 
     696           0 :                 if (q > 0)
     697           0 :                         continue;
     698             : 
     699           0 :                 path = path_make_absolute(fn, config_path);
     700           0 :                 if (!path)
     701           0 :                         return -ENOMEM;
     702             : 
     703           0 :                 if (symlink(*i, path) >= 0) {
     704           0 :                         unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
     705           0 :                         continue;
     706             :                 }
     707             : 
     708           0 :                 if (errno == EEXIST) {
     709           0 :                         _cleanup_free_ char *dest = NULL;
     710             : 
     711           0 :                         q = readlink_and_make_absolute(path, &dest);
     712           0 :                         if (q < 0 && errno != ENOENT) {
     713           0 :                                 if (r == 0)
     714           0 :                                         r = q;
     715           0 :                                 continue;
     716             :                         }
     717             : 
     718           0 :                         if (q >= 0 && path_equal(dest, *i))
     719           0 :                                 continue;
     720             : 
     721           0 :                         if (force) {
     722           0 :                                 if (symlink_atomic(*i, path) >= 0) {
     723           0 :                                         unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
     724           0 :                                         unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
     725           0 :                                         continue;
     726             :                                 }
     727             :                         }
     728             : 
     729           0 :                         if (r == 0)
     730           0 :                                 r = -EEXIST;
     731             :                 } else {
     732           0 :                         if (r == 0)
     733           0 :                                 r = -errno;
     734             :                 }
     735             :         }
     736             : 
     737           0 :         return r;
     738             : }
     739             : 
     740           1 : void unit_file_list_free(Hashmap *h) {
     741             :         UnitFileList *i;
     742             : 
     743         288 :         while ((i = hashmap_steal_first(h))) {
     744         286 :                 free(i->path);
     745         286 :                 free(i);
     746             :         }
     747             : 
     748           1 :         hashmap_free(h);
     749           1 : }
     750             : 
     751           0 : int unit_file_changes_add(
     752             :                 UnitFileChange **changes,
     753             :                 unsigned *n_changes,
     754             :                 UnitFileChangeType type,
     755             :                 const char *path,
     756             :                 const char *source) {
     757             : 
     758             :         UnitFileChange *c;
     759             :         unsigned i;
     760             : 
     761           0 :         assert(path);
     762           0 :         assert(!changes == !n_changes);
     763             : 
     764           0 :         if (!changes)
     765           0 :                 return 0;
     766             : 
     767           0 :         c = realloc(*changes, (*n_changes + 1) * sizeof(UnitFileChange));
     768           0 :         if (!c)
     769           0 :                 return -ENOMEM;
     770             : 
     771           0 :         *changes = c;
     772           0 :         i = *n_changes;
     773             : 
     774           0 :         c[i].type = type;
     775           0 :         c[i].path = strdup(path);
     776           0 :         if (!c[i].path)
     777           0 :                 return -ENOMEM;
     778             : 
     779           0 :         path_kill_slashes(c[i].path);
     780             : 
     781           0 :         if (source) {
     782           0 :                 c[i].source = strdup(source);
     783           0 :                 if (!c[i].source) {
     784           0 :                         free(c[i].path);
     785           0 :                         return -ENOMEM;
     786             :                 }
     787             : 
     788           0 :                 path_kill_slashes(c[i].path);
     789             :         } else
     790           0 :                 c[i].source = NULL;
     791             : 
     792           0 :         *n_changes = i+1;
     793           0 :         return 0;
     794             : }
     795             : 
     796           0 : void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes) {
     797             :         unsigned i;
     798             : 
     799           0 :         assert(changes || n_changes == 0);
     800             : 
     801           0 :         if (!changes)
     802           0 :                 return;
     803             : 
     804           0 :         for (i = 0; i < n_changes; i++) {
     805           0 :                 free(changes[i].path);
     806           0 :                 free(changes[i].source);
     807             :         }
     808             : 
     809           0 :         free(changes);
     810             : }
     811             : 
     812         291 : static void install_info_free(UnitFileInstallInfo *i) {
     813         291 :         assert(i);
     814             : 
     815         291 :         free(i->name);
     816         291 :         free(i->path);
     817         291 :         strv_free(i->aliases);
     818         291 :         strv_free(i->wanted_by);
     819         291 :         strv_free(i->required_by);
     820         291 :         strv_free(i->also);
     821         291 :         free(i->default_instance);
     822         291 :         free(i);
     823         291 : }
     824             : 
     825         550 : static void install_info_hashmap_free(OrderedHashmap *m) {
     826             :         UnitFileInstallInfo *i;
     827             : 
     828         550 :         if (!m)
     829         275 :                 return;
     830             : 
     831         841 :         while ((i = ordered_hashmap_steal_first(m)))
     832         291 :                 install_info_free(i);
     833             : 
     834         275 :         ordered_hashmap_free(m);
     835             : }
     836             : 
     837         275 : static void install_context_done(InstallContext *c) {
     838         275 :         assert(c);
     839             : 
     840         275 :         install_info_hashmap_free(c->will_install);
     841         275 :         install_info_hashmap_free(c->have_installed);
     842             : 
     843         275 :         c->will_install = c->have_installed = NULL;
     844         275 : }
     845             : 
     846         292 : static int install_info_add(
     847             :                 InstallContext *c,
     848             :                 const char *name,
     849             :                 const char *path) {
     850         292 :         UnitFileInstallInfo *i = NULL;
     851             :         int r;
     852             : 
     853         292 :         assert(c);
     854         292 :         assert(name || path);
     855             : 
     856         292 :         if (!name)
     857         275 :                 name = basename(path);
     858             : 
     859         292 :         if (!unit_name_is_valid(name, UNIT_NAME_ANY))
     860           0 :                 return -EINVAL;
     861             : 
     862         584 :         if (ordered_hashmap_get(c->have_installed, name) ||
     863         292 :             ordered_hashmap_get(c->will_install, name))
     864           1 :                 return 0;
     865             : 
     866         291 :         r = ordered_hashmap_ensure_allocated(&c->will_install, &string_hash_ops);
     867         291 :         if (r < 0)
     868           0 :                 return r;
     869             : 
     870         291 :         i = new0(UnitFileInstallInfo, 1);
     871         291 :         if (!i)
     872           0 :                 return -ENOMEM;
     873             : 
     874         291 :         i->name = strdup(name);
     875         291 :         if (!i->name) {
     876           0 :                 r = -ENOMEM;
     877           0 :                 goto fail;
     878             :         }
     879             : 
     880         291 :         if (path) {
     881         275 :                 i->path = strdup(path);
     882         275 :                 if (!i->path) {
     883           0 :                         r = -ENOMEM;
     884           0 :                         goto fail;
     885             :                 }
     886             :         }
     887             : 
     888         291 :         r = ordered_hashmap_put(c->will_install, i->name, i);
     889         291 :         if (r < 0)
     890           0 :                 goto fail;
     891             : 
     892         291 :         return 0;
     893             : 
     894             : fail:
     895           0 :         if (i)
     896           0 :                 install_info_free(i);
     897             : 
     898           0 :         return r;
     899             : }
     900             : 
     901         275 : static int install_info_add_auto(
     902             :                 InstallContext *c,
     903             :                 const char *name_or_path) {
     904             : 
     905         275 :         assert(c);
     906         275 :         assert(name_or_path);
     907             : 
     908         275 :         if (path_is_absolute(name_or_path))
     909         275 :                 return install_info_add(c, NULL, name_or_path);
     910             :         else
     911           0 :                 return install_info_add(c, name_or_path, NULL);
     912             : }
     913             : 
     914          14 : static int config_parse_also(
     915             :                 const char *unit,
     916             :                 const char *filename,
     917             :                 unsigned line,
     918             :                 const char *section,
     919             :                 unsigned section_line,
     920             :                 const char *lvalue,
     921             :                 int ltype,
     922             :                 const char *rvalue,
     923             :                 void *data,
     924             :                 void *userdata) {
     925             : 
     926             :         size_t l;
     927             :         const char *word, *state;
     928          14 :         InstallContext *c = data;
     929          14 :         UnitFileInstallInfo *i = userdata;
     930             : 
     931          14 :         assert(filename);
     932          14 :         assert(lvalue);
     933          14 :         assert(rvalue);
     934             : 
     935          31 :         FOREACH_WORD_QUOTED(word, l, rvalue, state) {
     936          17 :                 _cleanup_free_ char *n;
     937             :                 int r;
     938             : 
     939          17 :                 n = strndup(word, l);
     940          17 :                 if (!n)
     941           0 :                         return -ENOMEM;
     942             : 
     943          17 :                 r = install_info_add(c, n, NULL);
     944          17 :                 if (r < 0)
     945           0 :                         return r;
     946             : 
     947          17 :                 r = strv_extend(&i->also, n);
     948          17 :                 if (r < 0)
     949           0 :                         return r;
     950             :         }
     951          14 :         if (!isempty(state))
     952           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
     953             :                            "Trailing garbage, ignoring.");
     954             : 
     955          14 :         return 0;
     956             : }
     957             : 
     958           0 : static int config_parse_user(
     959             :                 const char *unit,
     960             :                 const char *filename,
     961             :                 unsigned line,
     962             :                 const char *section,
     963             :                 unsigned section_line,
     964             :                 const char *lvalue,
     965             :                 int ltype,
     966             :                 const char *rvalue,
     967             :                 void *data,
     968             :                 void *userdata) {
     969             : 
     970           0 :         UnitFileInstallInfo *i = data;
     971             :         char *printed;
     972             :         int r;
     973             : 
     974           0 :         assert(filename);
     975           0 :         assert(lvalue);
     976           0 :         assert(rvalue);
     977             : 
     978           0 :         r = install_full_printf(i, rvalue, &printed);
     979           0 :         if (r < 0)
     980           0 :                 return r;
     981             : 
     982           0 :         free(i->user);
     983           0 :         i->user = printed;
     984             : 
     985           0 :         return 0;
     986             : }
     987             : 
     988           3 : static int config_parse_default_instance(
     989             :                 const char *unit,
     990             :                 const char *filename,
     991             :                 unsigned line,
     992             :                 const char *section,
     993             :                 unsigned section_line,
     994             :                 const char *lvalue,
     995             :                 int ltype,
     996             :                 const char *rvalue,
     997             :                 void *data,
     998             :                 void *userdata) {
     999             : 
    1000           3 :         UnitFileInstallInfo *i = data;
    1001             :         char *printed;
    1002             :         int r;
    1003             : 
    1004           3 :         assert(filename);
    1005           3 :         assert(lvalue);
    1006           3 :         assert(rvalue);
    1007             : 
    1008           3 :         r = install_full_printf(i, rvalue, &printed);
    1009           3 :         if (r < 0)
    1010           0 :                 return r;
    1011             : 
    1012           3 :         if (!unit_instance_is_valid(printed)) {
    1013           0 :                 free(printed);
    1014           0 :                 return -EINVAL;
    1015             :         }
    1016             : 
    1017           3 :         free(i->default_instance);
    1018           3 :         i->default_instance = printed;
    1019             : 
    1020           3 :         return 0;
    1021             : }
    1022             : 
    1023         275 : static int unit_file_load(
    1024             :                 InstallContext *c,
    1025             :                 UnitFileInstallInfo *info,
    1026             :                 const char *path,
    1027             :                 const char *root_dir,
    1028             :                 bool allow_symlink,
    1029             :                 bool load,
    1030             :                 bool *also) {
    1031             : 
    1032        1100 :         const ConfigTableItem items[] = {
    1033         275 :                 { "Install", "Alias",           config_parse_strv,             0, &info->aliases           },
    1034         275 :                 { "Install", "WantedBy",        config_parse_strv,             0, &info->wanted_by         },
    1035         275 :                 { "Install", "RequiredBy",      config_parse_strv,             0, &info->required_by       },
    1036             :                 { "Install", "DefaultInstance", config_parse_default_instance, 0, info                     },
    1037             :                 { "Install", "Also",            config_parse_also,             0, c                        },
    1038             :                 { "Exec",    "User",            config_parse_user,             0, info                     },
    1039             :                 {}
    1040             :         };
    1041             : 
    1042         550 :         _cleanup_fclose_ FILE *f = NULL;
    1043             :         int fd, r;
    1044             : 
    1045         275 :         assert(c);
    1046         275 :         assert(info);
    1047         275 :         assert(path);
    1048             : 
    1049         275 :         if (!isempty(root_dir))
    1050           0 :                 path = strjoina(root_dir, "/", path);
    1051             : 
    1052         275 :         if (!load) {
    1053           0 :                 r = access(path, F_OK) ? -errno : 0;
    1054           0 :                 return r;
    1055             :         }
    1056             : 
    1057         275 :         fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|(allow_symlink ? 0 : O_NOFOLLOW));
    1058         275 :         if (fd < 0)
    1059           0 :                 return -errno;
    1060             : 
    1061         275 :         f = fdopen(fd, "re");
    1062         275 :         if (!f) {
    1063           0 :                 safe_close(fd);
    1064           0 :                 return -ENOMEM;
    1065             :         }
    1066             : 
    1067         275 :         r = config_parse(NULL, path, f,
    1068             :                          NULL,
    1069             :                          config_item_table_lookup, items,
    1070             :                          true, true, false, info);
    1071         275 :         if (r < 0)
    1072           0 :                 return r;
    1073             : 
    1074         275 :         if (also)
    1075         275 :                 *also = !strv_isempty(info->also);
    1076             : 
    1077             :         return
    1078         825 :                 (int) strv_length(info->aliases) +
    1079         275 :                 (int) strv_length(info->wanted_by) +
    1080         275 :                 (int) strv_length(info->required_by);
    1081             : }
    1082             : 
    1083         275 : static int unit_file_search(
    1084             :                 InstallContext *c,
    1085             :                 UnitFileInstallInfo *info,
    1086             :                 const LookupPaths *paths,
    1087             :                 const char *root_dir,
    1088             :                 bool allow_symlink,
    1089             :                 bool load,
    1090             :                 bool *also) {
    1091             : 
    1092             :         char **p;
    1093             :         int r;
    1094             : 
    1095         275 :         assert(c);
    1096         275 :         assert(info);
    1097         275 :         assert(paths);
    1098             : 
    1099         275 :         if (info->path)
    1100         275 :                 return unit_file_load(c, info, info->path, root_dir, allow_symlink, load, also);
    1101             : 
    1102           0 :         assert(info->name);
    1103             : 
    1104           0 :         STRV_FOREACH(p, paths->unit_path) {
    1105           0 :                 _cleanup_free_ char *path = NULL;
    1106             : 
    1107           0 :                 path = strjoin(*p, "/", info->name, NULL);
    1108           0 :                 if (!path)
    1109           0 :                         return -ENOMEM;
    1110             : 
    1111           0 :                 r = unit_file_load(c, info, path, root_dir, allow_symlink, load, also);
    1112           0 :                 if (r >= 0) {
    1113           0 :                         info->path = path;
    1114           0 :                         path = NULL;
    1115           0 :                         return r;
    1116             :                 }
    1117           0 :                 if (r != -ENOENT && r != -ELOOP)
    1118           0 :                         return r;
    1119             :         }
    1120             : 
    1121           0 :         if (unit_name_is_valid(info->name, UNIT_NAME_INSTANCE)) {
    1122             : 
    1123             :                 /* Unit file doesn't exist, however instance
    1124             :                  * enablement was requested.  We will check if it is
    1125             :                  * possible to load template unit file. */
    1126             : 
    1127           0 :                 _cleanup_free_ char *template = NULL;
    1128             : 
    1129           0 :                 r = unit_name_template(info->name, &template);
    1130           0 :                 if (r < 0)
    1131           0 :                         return r;
    1132             : 
    1133           0 :                 STRV_FOREACH(p, paths->unit_path) {
    1134           0 :                         _cleanup_free_ char *path = NULL;
    1135             : 
    1136           0 :                         path = strjoin(*p, "/", template, NULL);
    1137           0 :                         if (!path)
    1138           0 :                                 return -ENOMEM;
    1139             : 
    1140           0 :                         r = unit_file_load(c, info, path, root_dir, allow_symlink, load, also);
    1141           0 :                         if (r >= 0) {
    1142           0 :                                 info->path = path;
    1143           0 :                                 path = NULL;
    1144           0 :                                 return r;
    1145             :                         }
    1146           0 :                         if (r != -ENOENT && r != -ELOOP)
    1147           0 :                                 return r;
    1148             :                 }
    1149             :         }
    1150             : 
    1151           0 :         return -ENOENT;
    1152             : }
    1153             : 
    1154         275 : static int unit_file_can_install(
    1155             :                 const LookupPaths *paths,
    1156             :                 const char *root_dir,
    1157             :                 const char *name,
    1158             :                 bool allow_symlink,
    1159             :                 bool *also) {
    1160             : 
    1161         550 :         _cleanup_(install_context_done) InstallContext c = {};
    1162             :         UnitFileInstallInfo *i;
    1163             :         int r;
    1164             : 
    1165         275 :         assert(paths);
    1166         275 :         assert(name);
    1167             : 
    1168         275 :         r = install_info_add_auto(&c, name);
    1169         275 :         if (r < 0)
    1170           0 :                 return r;
    1171             : 
    1172         275 :         assert_se(i = ordered_hashmap_first(c.will_install));
    1173             : 
    1174         275 :         r = unit_file_search(&c, i, paths, root_dir, allow_symlink, true, also);
    1175             : 
    1176         275 :         if (r >= 0)
    1177         275 :                 r =
    1178         550 :                         (int) strv_length(i->aliases) +
    1179         275 :                         (int) strv_length(i->wanted_by) +
    1180         275 :                         (int) strv_length(i->required_by);
    1181             : 
    1182         275 :         return r;
    1183             : }
    1184             : 
    1185           0 : static int create_symlink(
    1186             :                 const char *old_path,
    1187             :                 const char *new_path,
    1188             :                 bool force,
    1189             :                 UnitFileChange **changes,
    1190             :                 unsigned *n_changes) {
    1191             : 
    1192           0 :         _cleanup_free_ char *dest = NULL;
    1193             :         int r;
    1194             : 
    1195           0 :         assert(old_path);
    1196           0 :         assert(new_path);
    1197             : 
    1198           0 :         mkdir_parents_label(new_path, 0755);
    1199             : 
    1200           0 :         if (symlink(old_path, new_path) >= 0) {
    1201           0 :                 unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
    1202           0 :                 return 0;
    1203             :         }
    1204             : 
    1205           0 :         if (errno != EEXIST)
    1206           0 :                 return -errno;
    1207             : 
    1208           0 :         r = readlink_and_make_absolute(new_path, &dest);
    1209           0 :         if (r < 0)
    1210           0 :                 return r;
    1211             : 
    1212           0 :         if (path_equal(dest, old_path))
    1213           0 :                 return 0;
    1214             : 
    1215           0 :         if (!force)
    1216           0 :                 return -EEXIST;
    1217             : 
    1218           0 :         r = symlink_atomic(old_path, new_path);
    1219           0 :         if (r < 0)
    1220           0 :                 return r;
    1221             : 
    1222           0 :         unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL);
    1223           0 :         unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
    1224             : 
    1225           0 :         return 0;
    1226             : }
    1227             : 
    1228           0 : static int install_info_symlink_alias(
    1229             :                 UnitFileInstallInfo *i,
    1230             :                 const char *config_path,
    1231             :                 bool force,
    1232             :                 UnitFileChange **changes,
    1233             :                 unsigned *n_changes) {
    1234             : 
    1235             :         char **s;
    1236           0 :         int r = 0, q;
    1237             : 
    1238           0 :         assert(i);
    1239           0 :         assert(config_path);
    1240             : 
    1241           0 :         STRV_FOREACH(s, i->aliases) {
    1242           0 :                 _cleanup_free_ char *alias_path = NULL, *dst = NULL;
    1243             : 
    1244           0 :                 q = install_full_printf(i, *s, &dst);
    1245           0 :                 if (q < 0)
    1246           0 :                         return q;
    1247             : 
    1248           0 :                 alias_path = path_make_absolute(dst, config_path);
    1249           0 :                 if (!alias_path)
    1250           0 :                         return -ENOMEM;
    1251             : 
    1252           0 :                 q = create_symlink(i->path, alias_path, force, changes, n_changes);
    1253           0 :                 if (r == 0)
    1254           0 :                         r = q;
    1255             :         }
    1256             : 
    1257           0 :         return r;
    1258             : }
    1259             : 
    1260           0 : static int install_info_symlink_wants(
    1261             :                 UnitFileInstallInfo *i,
    1262             :                 const char *config_path,
    1263             :                 char **list,
    1264             :                 const char *suffix,
    1265             :                 bool force,
    1266             :                 UnitFileChange **changes,
    1267             :                 unsigned *n_changes) {
    1268             : 
    1269           0 :         _cleanup_free_ char *buf = NULL;
    1270             :         const char *n;
    1271             :         char **s;
    1272           0 :         int r = 0, q;
    1273             : 
    1274           0 :         assert(i);
    1275           0 :         assert(config_path);
    1276             : 
    1277           0 :         if (unit_name_is_valid(i->name, UNIT_NAME_TEMPLATE)) {
    1278             : 
    1279             :                 /* Don't install any symlink if there's no default
    1280             :                  * instance configured */
    1281             : 
    1282           0 :                 if (!i->default_instance)
    1283           0 :                         return 0;
    1284             : 
    1285           0 :                 r = unit_name_replace_instance(i->name, i->default_instance, &buf);
    1286           0 :                 if (r < 0)
    1287           0 :                         return r;
    1288             : 
    1289           0 :                 n = buf;
    1290             :         } else
    1291           0 :                 n = i->name;
    1292             : 
    1293           0 :         STRV_FOREACH(s, list) {
    1294           0 :                 _cleanup_free_ char *path = NULL, *dst = NULL;
    1295             : 
    1296           0 :                 q = install_full_printf(i, *s, &dst);
    1297           0 :                 if (q < 0)
    1298           0 :                         return q;
    1299             : 
    1300           0 :                 if (!unit_name_is_valid(dst, UNIT_NAME_ANY)) {
    1301           0 :                         r = -EINVAL;
    1302           0 :                         continue;
    1303             :                 }
    1304             : 
    1305           0 :                 path = strjoin(config_path, "/", dst, suffix, n, NULL);
    1306           0 :                 if (!path)
    1307           0 :                         return -ENOMEM;
    1308             : 
    1309           0 :                 q = create_symlink(i->path, path, force, changes, n_changes);
    1310           0 :                 if (r == 0)
    1311           0 :                         r = q;
    1312             :         }
    1313             : 
    1314           0 :         return r;
    1315             : }
    1316             : 
    1317           0 : static int install_info_symlink_link(
    1318             :                 UnitFileInstallInfo *i,
    1319             :                 const LookupPaths *paths,
    1320             :                 const char *config_path,
    1321             :                 const char *root_dir,
    1322             :                 bool force,
    1323             :                 UnitFileChange **changes,
    1324             :                 unsigned *n_changes) {
    1325             : 
    1326           0 :         _cleanup_free_ char *path = NULL;
    1327             :         int r;
    1328             : 
    1329           0 :         assert(i);
    1330           0 :         assert(paths);
    1331           0 :         assert(config_path);
    1332           0 :         assert(i->path);
    1333             : 
    1334           0 :         r = in_search_path(i->path, paths->unit_path);
    1335           0 :         if (r != 0)
    1336           0 :                 return r;
    1337             : 
    1338           0 :         path = strjoin(config_path, "/", i->name, NULL);
    1339           0 :         if (!path)
    1340           0 :                 return -ENOMEM;
    1341             : 
    1342           0 :         return create_symlink(i->path, path, force, changes, n_changes);
    1343             : }
    1344             : 
    1345           0 : static int install_info_apply(
    1346             :                 UnitFileInstallInfo *i,
    1347             :                 const LookupPaths *paths,
    1348             :                 const char *config_path,
    1349             :                 const char *root_dir,
    1350             :                 bool force,
    1351             :                 UnitFileChange **changes,
    1352             :                 unsigned *n_changes) {
    1353             : 
    1354             :         int r, q;
    1355             : 
    1356           0 :         assert(i);
    1357           0 :         assert(paths);
    1358           0 :         assert(config_path);
    1359             : 
    1360           0 :         r = install_info_symlink_alias(i, config_path, force, changes, n_changes);
    1361             : 
    1362           0 :         q = install_info_symlink_wants(i, config_path, i->wanted_by, ".wants/", force, changes, n_changes);
    1363           0 :         if (r == 0)
    1364           0 :                 r = q;
    1365             : 
    1366           0 :         q = install_info_symlink_wants(i, config_path, i->required_by, ".requires/", force, changes, n_changes);
    1367           0 :         if (r == 0)
    1368           0 :                 r = q;
    1369             : 
    1370           0 :         q = install_info_symlink_link(i, paths, config_path, root_dir, force, changes, n_changes);
    1371           0 :         if (r == 0)
    1372           0 :                 r = q;
    1373             : 
    1374           0 :         return r;
    1375             : }
    1376             : 
    1377           0 : static int install_context_apply(
    1378             :                 InstallContext *c,
    1379             :                 const LookupPaths *paths,
    1380             :                 const char *config_path,
    1381             :                 const char *root_dir,
    1382             :                 bool force,
    1383             :                 UnitFileChange **changes,
    1384             :                 unsigned *n_changes) {
    1385             : 
    1386             :         UnitFileInstallInfo *i;
    1387             :         int r, q;
    1388             : 
    1389           0 :         assert(c);
    1390           0 :         assert(paths);
    1391           0 :         assert(config_path);
    1392             : 
    1393           0 :         if (!ordered_hashmap_isempty(c->will_install)) {
    1394           0 :                 r = ordered_hashmap_ensure_allocated(&c->have_installed, &string_hash_ops);
    1395           0 :                 if (r < 0)
    1396           0 :                         return r;
    1397             : 
    1398           0 :                 r = ordered_hashmap_reserve(c->have_installed, ordered_hashmap_size(c->will_install));
    1399           0 :                 if (r < 0)
    1400           0 :                         return r;
    1401             :         }
    1402             : 
    1403           0 :         r = 0;
    1404           0 :         while ((i = ordered_hashmap_first(c->will_install))) {
    1405           0 :                 assert_se(ordered_hashmap_move_one(c->have_installed, c->will_install, i->name) == 0);
    1406             : 
    1407           0 :                 q = unit_file_search(c, i, paths, root_dir, false, true, NULL);
    1408           0 :                 if (q < 0) {
    1409           0 :                         if (r >= 0)
    1410           0 :                                 r = q;
    1411             : 
    1412           0 :                         return r;
    1413           0 :                 } else if (r >= 0)
    1414           0 :                         r += q;
    1415             : 
    1416           0 :                 q = install_info_apply(i, paths, config_path, root_dir, force, changes, n_changes);
    1417           0 :                 if (r >= 0 && q < 0)
    1418           0 :                         r = q;
    1419             :         }
    1420             : 
    1421           0 :         return r;
    1422             : }
    1423             : 
    1424           0 : static int install_context_mark_for_removal(
    1425             :                 InstallContext *c,
    1426             :                 const LookupPaths *paths,
    1427             :                 Set **remove_symlinks_to,
    1428             :                 const char *config_path,
    1429             :                 const char *root_dir) {
    1430             : 
    1431             :         UnitFileInstallInfo *i;
    1432             :         int r, q;
    1433             : 
    1434           0 :         assert(c);
    1435           0 :         assert(paths);
    1436           0 :         assert(config_path);
    1437             : 
    1438             :         /* Marks all items for removal */
    1439             : 
    1440           0 :         if (!ordered_hashmap_isempty(c->will_install)) {
    1441           0 :                 r = ordered_hashmap_ensure_allocated(&c->have_installed, &string_hash_ops);
    1442           0 :                 if (r < 0)
    1443           0 :                         return r;
    1444             : 
    1445           0 :                 r = ordered_hashmap_reserve(c->have_installed, ordered_hashmap_size(c->will_install));
    1446           0 :                 if (r < 0)
    1447           0 :                         return r;
    1448             :         }
    1449             : 
    1450           0 :         r = 0;
    1451           0 :         while ((i = ordered_hashmap_first(c->will_install))) {
    1452           0 :                 assert_se(ordered_hashmap_move_one(c->have_installed, c->will_install, i->name) == 0);
    1453             : 
    1454           0 :                 q = unit_file_search(c, i, paths, root_dir, false, true, NULL);
    1455           0 :                 if (q == -ENOENT) {
    1456             :                         /* do nothing */
    1457           0 :                 } else if (q < 0) {
    1458           0 :                         if (r >= 0)
    1459           0 :                                 r = q;
    1460             : 
    1461           0 :                         return r;
    1462           0 :                 } else if (r >= 0)
    1463           0 :                         r += q;
    1464             : 
    1465           0 :                 if (unit_name_is_valid(i->name, UNIT_NAME_INSTANCE)) {
    1466             :                         char *unit_file;
    1467             : 
    1468           0 :                         if (i->path) {
    1469           0 :                                 unit_file = basename(i->path);
    1470             : 
    1471           0 :                                 if (unit_name_is_valid(unit_file, UNIT_NAME_INSTANCE))
    1472             :                                         /* unit file named as instance exists, thus all symlinks
    1473             :                                          * pointing to it will be removed */
    1474           0 :                                         q = mark_symlink_for_removal(remove_symlinks_to, i->name);
    1475             :                                 else
    1476             :                                         /* does not exist, thus we will mark for removal symlinks
    1477             :                                          * to template unit file */
    1478           0 :                                         q = mark_symlink_for_removal(remove_symlinks_to, unit_file);
    1479             :                         } else {
    1480             :                                 /* If i->path is not set, it means that we didn't actually find
    1481             :                                  * the unit file. But we can still remove symlinks to the
    1482             :                                  * nonexistent template. */
    1483           0 :                                 r = unit_name_template(i->name, &unit_file);
    1484           0 :                                 if (r < 0)
    1485           0 :                                         return r;
    1486             : 
    1487           0 :                                 q = mark_symlink_for_removal(remove_symlinks_to, unit_file);
    1488           0 :                                 free(unit_file);
    1489             :                         }
    1490             :                 } else
    1491           0 :                         q = mark_symlink_for_removal(remove_symlinks_to, i->name);
    1492             : 
    1493           0 :                 if (r >= 0 && q < 0)
    1494           0 :                         r = q;
    1495             :         }
    1496             : 
    1497           0 :         return r;
    1498             : }
    1499             : 
    1500           0 : int unit_file_add_dependency(
    1501             :                 UnitFileScope scope,
    1502             :                 bool runtime,
    1503             :                 const char *root_dir,
    1504             :                 char **files,
    1505             :                 char *target,
    1506             :                 UnitDependency dep,
    1507             :                 bool force,
    1508             :                 UnitFileChange **changes,
    1509             :                 unsigned *n_changes) {
    1510             : 
    1511           0 :         _cleanup_lookup_paths_free_ LookupPaths paths = {};
    1512           0 :         _cleanup_(install_context_done) InstallContext c = {};
    1513           0 :         _cleanup_free_ char *config_path = NULL;
    1514             :         char **i;
    1515             :         int r;
    1516             :         UnitFileInstallInfo *info;
    1517             : 
    1518           0 :         assert(scope >= 0);
    1519           0 :         assert(scope < _UNIT_FILE_SCOPE_MAX);
    1520             : 
    1521           0 :         r = lookup_paths_init_from_scope(&paths, scope, root_dir);
    1522           0 :         if (r < 0)
    1523           0 :                 return r;
    1524             : 
    1525           0 :         r = get_config_path(scope, runtime, root_dir, &config_path);
    1526           0 :         if (r < 0)
    1527           0 :                 return r;
    1528             : 
    1529           0 :         STRV_FOREACH(i, files) {
    1530             :                 UnitFileState state;
    1531             : 
    1532           0 :                 state = unit_file_get_state(scope, root_dir, *i);
    1533           0 :                 if (state < 0)
    1534           0 :                         return log_error_errno(state, "Failed to get unit file state for %s: %m", *i);
    1535             : 
    1536           0 :                 if (state == UNIT_FILE_MASKED || state == UNIT_FILE_MASKED_RUNTIME) {
    1537           0 :                         log_error("Failed to enable unit: Unit %s is masked", *i);
    1538           0 :                         return -EOPNOTSUPP;
    1539             :                 }
    1540             : 
    1541           0 :                 r = install_info_add_auto(&c, *i);
    1542           0 :                 if (r < 0)
    1543           0 :                         return r;
    1544             :         }
    1545             : 
    1546           0 :         if (!ordered_hashmap_isempty(c.will_install)) {
    1547           0 :                 r = ordered_hashmap_ensure_allocated(&c.have_installed, &string_hash_ops);
    1548           0 :                 if (r < 0)
    1549           0 :                         return r;
    1550             : 
    1551           0 :                 r = ordered_hashmap_reserve(c.have_installed, ordered_hashmap_size(c.will_install));
    1552           0 :                 if (r < 0)
    1553           0 :                         return r;
    1554             :         }
    1555             : 
    1556           0 :         while ((info = ordered_hashmap_first(c.will_install))) {
    1557           0 :                 assert_se(ordered_hashmap_move_one(c.have_installed, c.will_install, info->name) == 0);
    1558             : 
    1559           0 :                 r = unit_file_search(&c, info, &paths, root_dir, false, false, NULL);
    1560           0 :                 if (r < 0)
    1561           0 :                         return r;
    1562             : 
    1563           0 :                 if (dep == UNIT_WANTS)
    1564           0 :                         r = strv_extend(&info->wanted_by, target);
    1565           0 :                 else if (dep == UNIT_REQUIRES)
    1566           0 :                         r = strv_extend(&info->required_by, target);
    1567             :                 else
    1568           0 :                         r = -EINVAL;
    1569             : 
    1570           0 :                 if (r < 0)
    1571           0 :                         return r;
    1572             : 
    1573           0 :                 r = install_info_apply(info, &paths, config_path, root_dir, force, changes, n_changes);
    1574           0 :                 if (r < 0)
    1575           0 :                         return r;
    1576             :         }
    1577             : 
    1578           0 :         return 0;
    1579             : }
    1580             : 
    1581           0 : int unit_file_enable(
    1582             :                 UnitFileScope scope,
    1583             :                 bool runtime,
    1584             :                 const char *root_dir,
    1585             :                 char **files,
    1586             :                 bool force,
    1587             :                 UnitFileChange **changes,
    1588             :                 unsigned *n_changes) {
    1589             : 
    1590           0 :         _cleanup_lookup_paths_free_ LookupPaths paths = {};
    1591           0 :         _cleanup_(install_context_done) InstallContext c = {};
    1592             :         char **i;
    1593           0 :         _cleanup_free_ char *config_path = NULL;
    1594             :         int r;
    1595             : 
    1596           0 :         assert(scope >= 0);
    1597           0 :         assert(scope < _UNIT_FILE_SCOPE_MAX);
    1598             : 
    1599           0 :         r = lookup_paths_init_from_scope(&paths, scope, root_dir);
    1600           0 :         if (r < 0)
    1601           0 :                 return r;
    1602             : 
    1603           0 :         r = get_config_path(scope, runtime, root_dir, &config_path);
    1604           0 :         if (r < 0)
    1605           0 :                 return r;
    1606             : 
    1607           0 :         STRV_FOREACH(i, files) {
    1608             :                 UnitFileState state;
    1609             : 
    1610             :                 /* We only want to know if this unit is masked, so we ignore
    1611             :                  * errors from unit_file_get_state, deferring other checks.
    1612             :                  * This allows templated units to be enabled on the fly. */
    1613           0 :                 state = unit_file_get_state(scope, root_dir, *i);
    1614           0 :                 if (state == UNIT_FILE_MASKED || state == UNIT_FILE_MASKED_RUNTIME) {
    1615           0 :                         log_error("Failed to enable unit: Unit %s is masked", *i);
    1616           0 :                         return -EOPNOTSUPP;
    1617             :                 }
    1618             : 
    1619           0 :                 r = install_info_add_auto(&c, *i);
    1620           0 :                 if (r < 0)
    1621           0 :                         return r;
    1622             :         }
    1623             : 
    1624             :         /* This will return the number of symlink rules that were
    1625             :         supposed to be created, not the ones actually created. This is
    1626             :         useful to determine whether the passed files had any
    1627             :         installation data at all. */
    1628             : 
    1629           0 :         return install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes);
    1630             : }
    1631             : 
    1632           0 : int unit_file_disable(
    1633             :                 UnitFileScope scope,
    1634             :                 bool runtime,
    1635             :                 const char *root_dir,
    1636             :                 char **files,
    1637             :                 UnitFileChange **changes,
    1638             :                 unsigned *n_changes) {
    1639             : 
    1640           0 :         _cleanup_lookup_paths_free_ LookupPaths paths = {};
    1641           0 :         _cleanup_(install_context_done) InstallContext c = {};
    1642             :         char **i;
    1643           0 :         _cleanup_free_ char *config_path = NULL;
    1644           0 :         _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
    1645             :         int r, q;
    1646             : 
    1647           0 :         assert(scope >= 0);
    1648           0 :         assert(scope < _UNIT_FILE_SCOPE_MAX);
    1649             : 
    1650           0 :         r = lookup_paths_init_from_scope(&paths, scope, root_dir);
    1651           0 :         if (r < 0)
    1652           0 :                 return r;
    1653             : 
    1654           0 :         r = get_config_path(scope, runtime, root_dir, &config_path);
    1655           0 :         if (r < 0)
    1656           0 :                 return r;
    1657             : 
    1658           0 :         STRV_FOREACH(i, files) {
    1659           0 :                 r = install_info_add_auto(&c, *i);
    1660           0 :                 if (r < 0)
    1661           0 :                         return r;
    1662             :         }
    1663             : 
    1664           0 :         r = install_context_mark_for_removal(&c, &paths, &remove_symlinks_to, config_path, root_dir);
    1665             : 
    1666           0 :         q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
    1667           0 :         if (r >= 0)
    1668           0 :                 r = q;
    1669             : 
    1670           0 :         return r;
    1671             : }
    1672             : 
    1673           0 : int unit_file_reenable(
    1674             :                 UnitFileScope scope,
    1675             :                 bool runtime,
    1676             :                 const char *root_dir,
    1677             :                 char **files,
    1678             :                 bool force,
    1679             :                 UnitFileChange **changes,
    1680             :                 unsigned *n_changes) {
    1681             :         int r;
    1682             : 
    1683           0 :         r = unit_file_disable(scope, runtime, root_dir, files,
    1684             :                               changes, n_changes);
    1685           0 :         if (r < 0)
    1686           0 :                 return r;
    1687             : 
    1688           0 :         return unit_file_enable(scope, runtime, root_dir, files, force,
    1689             :                                 changes, n_changes);
    1690             : }
    1691             : 
    1692           0 : int unit_file_set_default(
    1693             :                 UnitFileScope scope,
    1694             :                 const char *root_dir,
    1695             :                 const char *file,
    1696             :                 bool force,
    1697             :                 UnitFileChange **changes,
    1698             :                 unsigned *n_changes) {
    1699             : 
    1700           0 :         _cleanup_lookup_paths_free_ LookupPaths paths = {};
    1701           0 :         _cleanup_(install_context_done) InstallContext c = {};
    1702           0 :         _cleanup_free_ char *config_path = NULL;
    1703             :         char *path;
    1704             :         int r;
    1705           0 :         UnitFileInstallInfo *i = NULL;
    1706             : 
    1707           0 :         assert(scope >= 0);
    1708           0 :         assert(scope < _UNIT_FILE_SCOPE_MAX);
    1709           0 :         assert(file);
    1710             : 
    1711           0 :         if (unit_name_to_type(file) != UNIT_TARGET)
    1712           0 :                 return -EINVAL;
    1713             : 
    1714           0 :         r = lookup_paths_init_from_scope(&paths, scope, root_dir);
    1715           0 :         if (r < 0)
    1716           0 :                 return r;
    1717             : 
    1718           0 :         r = get_config_path(scope, false, root_dir, &config_path);
    1719           0 :         if (r < 0)
    1720           0 :                 return r;
    1721             : 
    1722           0 :         r = install_info_add_auto(&c, file);
    1723           0 :         if (r < 0)
    1724           0 :                 return r;
    1725             : 
    1726           0 :         assert_se(i = ordered_hashmap_first(c.will_install));
    1727             : 
    1728           0 :         r = unit_file_search(&c, i, &paths, root_dir, false, true, NULL);
    1729           0 :         if (r < 0)
    1730           0 :                 return r;
    1731             : 
    1732           0 :         path = strjoina(config_path, "/" SPECIAL_DEFAULT_TARGET);
    1733             : 
    1734           0 :         r = create_symlink(i->path, path, force, changes, n_changes);
    1735           0 :         if (r < 0)
    1736           0 :                 return r;
    1737             : 
    1738           0 :         return 0;
    1739             : }
    1740             : 
    1741           0 : int unit_file_get_default(
    1742             :                 UnitFileScope scope,
    1743             :                 const char *root_dir,
    1744             :                 char **name) {
    1745             : 
    1746           0 :         _cleanup_lookup_paths_free_ LookupPaths paths = {};
    1747             :         char **p;
    1748             :         int r;
    1749             : 
    1750           0 :         assert(scope >= 0);
    1751           0 :         assert(scope < _UNIT_FILE_SCOPE_MAX);
    1752           0 :         assert(name);
    1753             : 
    1754           0 :         r = lookup_paths_init_from_scope(&paths, scope, root_dir);
    1755           0 :         if (r < 0)
    1756           0 :                 return r;
    1757             : 
    1758           0 :         STRV_FOREACH(p, paths.unit_path) {
    1759           0 :                 _cleanup_free_ char *path = NULL, *tmp = NULL;
    1760             :                 char *n;
    1761             : 
    1762           0 :                 path = path_join(root_dir, *p, SPECIAL_DEFAULT_TARGET);
    1763           0 :                 if (!path)
    1764           0 :                         return -ENOMEM;
    1765             : 
    1766           0 :                 r = readlink_malloc(path, &tmp);
    1767           0 :                 if (r == -ENOENT)
    1768           0 :                         continue;
    1769           0 :                 else if (r == -EINVAL)
    1770             :                         /* not a symlink */
    1771           0 :                         n = strdup(SPECIAL_DEFAULT_TARGET);
    1772           0 :                 else if (r < 0)
    1773           0 :                         return r;
    1774             :                 else
    1775           0 :                         n = strdup(basename(tmp));
    1776             : 
    1777           0 :                 if (!n)
    1778           0 :                         return -ENOMEM;
    1779             : 
    1780           0 :                 *name = n;
    1781           0 :                 return 0;
    1782             :         }
    1783             : 
    1784           0 :         return -ENOENT;
    1785             : }
    1786             : 
    1787          26 : UnitFileState unit_file_lookup_state(
    1788             :                 UnitFileScope scope,
    1789             :                 const char *root_dir,
    1790             :                 const LookupPaths *paths,
    1791             :                 const char *name) {
    1792             : 
    1793          26 :         UnitFileState state = _UNIT_FILE_STATE_INVALID;
    1794             :         char **i;
    1795          52 :         _cleanup_free_ char *path = NULL;
    1796          26 :         int r = 0;
    1797             : 
    1798          26 :         assert(paths);
    1799             : 
    1800          26 :         if (!unit_name_is_valid(name, UNIT_NAME_ANY))
    1801           0 :                 return -EINVAL;
    1802             : 
    1803          51 :         STRV_FOREACH(i, paths->unit_path) {
    1804             :                 struct stat st;
    1805             :                 char *partial;
    1806          26 :                 bool also = false;
    1807             : 
    1808          26 :                 free(path);
    1809          26 :                 path = path_join(root_dir, *i, name);
    1810          26 :                 if (!path)
    1811           1 :                         return -ENOMEM;
    1812             : 
    1813          26 :                 if (root_dir)
    1814           0 :                         partial = path + strlen(root_dir);
    1815             :                 else
    1816          26 :                         partial = path;
    1817             : 
    1818             :                 /*
    1819             :                  * Search for a unit file in our default paths, to
    1820             :                  * be sure, that there are no broken symlinks.
    1821             :                  */
    1822          26 :                 if (lstat(path, &st) < 0) {
    1823          25 :                         r = -errno;
    1824          25 :                         if (errno != ENOENT)
    1825           0 :                                 return r;
    1826             : 
    1827          25 :                         if (!unit_name_is_valid(name, UNIT_NAME_INSTANCE))
    1828          25 :                                 continue;
    1829             :                 } else {
    1830           1 :                         if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode))
    1831           0 :                                 return -ENOENT;
    1832             : 
    1833           1 :                         r = null_or_empty_path(path);
    1834           1 :                         if (r < 0 && r != -ENOENT)
    1835           0 :                                 return r;
    1836           1 :                         else if (r > 0) {
    1837           0 :                                 state = path_startswith(*i, "/run") ? UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
    1838           0 :                                 return state;
    1839             :                         }
    1840             :                 }
    1841             : 
    1842           1 :                 r = find_symlinks_in_scope(scope, root_dir, name, &state);
    1843           1 :                 if (r < 0)
    1844           0 :                         return r;
    1845           1 :                 else if (r > 0)
    1846           0 :                         return state;
    1847             : 
    1848           1 :                 r = unit_file_can_install(paths, root_dir, partial, true, &also);
    1849           1 :                 if (r < 0 && errno != ENOENT)
    1850           0 :                         return r;
    1851           1 :                 else if (r > 0)
    1852           0 :                         return UNIT_FILE_DISABLED;
    1853           1 :                 else if (r == 0) {
    1854           1 :                         if (also)
    1855           0 :                                 return UNIT_FILE_INDIRECT;
    1856           1 :                         return UNIT_FILE_STATIC;
    1857             :                 }
    1858             :         }
    1859             : 
    1860          25 :         return r < 0 ? r : state;
    1861             : }
    1862             : 
    1863           0 : UnitFileState unit_file_get_state(
    1864             :                 UnitFileScope scope,
    1865             :                 const char *root_dir,
    1866             :                 const char *name) {
    1867             : 
    1868           0 :         _cleanup_lookup_paths_free_ LookupPaths paths = {};
    1869             :         int r;
    1870             : 
    1871           0 :         assert(scope >= 0);
    1872           0 :         assert(scope < _UNIT_FILE_SCOPE_MAX);
    1873           0 :         assert(name);
    1874             : 
    1875           0 :         if (root_dir && scope != UNIT_FILE_SYSTEM)
    1876           0 :                 return -EINVAL;
    1877             : 
    1878           0 :         r = lookup_paths_init_from_scope(&paths, scope, root_dir);
    1879           0 :         if (r < 0)
    1880           0 :                 return r;
    1881             : 
    1882           0 :         return unit_file_lookup_state(scope, root_dir, &paths, name);
    1883             : }
    1884             : 
    1885           0 : int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name) {
    1886           0 :         _cleanup_strv_free_ char **files = NULL;
    1887             :         char **p;
    1888             :         int r;
    1889             : 
    1890           0 :         assert(scope >= 0);
    1891           0 :         assert(scope < _UNIT_FILE_SCOPE_MAX);
    1892           0 :         assert(name);
    1893             : 
    1894           0 :         if (scope == UNIT_FILE_SYSTEM)
    1895           0 :                 r = conf_files_list(&files, ".preset", root_dir,
    1896             :                                     "/etc/systemd/system-preset",
    1897             :                                     "/usr/local/lib/systemd/system-preset",
    1898             :                                     "/usr/lib/systemd/system-preset",
    1899             : #ifdef HAVE_SPLIT_USR
    1900             :                                     "/lib/systemd/system-preset",
    1901             : #endif
    1902             :                                     NULL);
    1903           0 :         else if (scope == UNIT_FILE_GLOBAL)
    1904           0 :                 r = conf_files_list(&files, ".preset", root_dir,
    1905             :                                     "/etc/systemd/user-preset",
    1906             :                                     "/usr/local/lib/systemd/user-preset",
    1907             :                                     "/usr/lib/systemd/user-preset",
    1908             :                                     NULL);
    1909             :         else
    1910           0 :                 return 1;
    1911             : 
    1912           0 :         if (r < 0)
    1913           0 :                 return r;
    1914             : 
    1915           0 :         STRV_FOREACH(p, files) {
    1916           0 :                 _cleanup_fclose_ FILE *f;
    1917             : 
    1918           0 :                 f = fopen(*p, "re");
    1919           0 :                 if (!f) {
    1920           0 :                         if (errno == ENOENT)
    1921           0 :                                 continue;
    1922             : 
    1923           0 :                         return -errno;
    1924             :                 }
    1925             : 
    1926             :                 for (;;) {
    1927             :                         char line[LINE_MAX], *l;
    1928             : 
    1929           0 :                         if (!fgets(line, sizeof(line), f))
    1930           0 :                                 break;
    1931             : 
    1932           0 :                         l = strstrip(line);
    1933           0 :                         if (!*l)
    1934           0 :                                 continue;
    1935             : 
    1936           0 :                         if (strchr(COMMENTS "\n", *l))
    1937           0 :                                 continue;
    1938             : 
    1939           0 :                         if (first_word(l, "enable")) {
    1940           0 :                                 l += 6;
    1941           0 :                                 l += strspn(l, WHITESPACE);
    1942             : 
    1943           0 :                                 if (fnmatch(l, name, FNM_NOESCAPE) == 0) {
    1944           0 :                                         log_debug("Preset file says enable %s.", name);
    1945           0 :                                         return 1;
    1946             :                                 }
    1947             : 
    1948           0 :                         } else if (first_word(l, "disable")) {
    1949           0 :                                 l += 7;
    1950           0 :                                 l += strspn(l, WHITESPACE);
    1951             : 
    1952           0 :                                 if (fnmatch(l, name, FNM_NOESCAPE) == 0) {
    1953           0 :                                         log_debug("Preset file says disable %s.", name);
    1954           0 :                                         return 0;
    1955             :                                 }
    1956             : 
    1957             :                         } else
    1958           0 :                                 log_debug("Couldn't parse line '%s'", l);
    1959           0 :                 }
    1960             :         }
    1961             : 
    1962             :         /* Default is "enable" */
    1963           0 :         log_debug("Preset file doesn't say anything about %s, enabling.", name);
    1964           0 :         return 1;
    1965             : }
    1966             : 
    1967           0 : int unit_file_preset(
    1968             :                 UnitFileScope scope,
    1969             :                 bool runtime,
    1970             :                 const char *root_dir,
    1971             :                 char **files,
    1972             :                 UnitFilePresetMode mode,
    1973             :                 bool force,
    1974             :                 UnitFileChange **changes,
    1975             :                 unsigned *n_changes) {
    1976             : 
    1977           0 :         _cleanup_(install_context_done) InstallContext plus = {}, minus = {};
    1978           0 :         _cleanup_lookup_paths_free_ LookupPaths paths = {};
    1979           0 :         _cleanup_free_ char *config_path = NULL;
    1980             :         char **i;
    1981             :         int r, q;
    1982             : 
    1983           0 :         assert(scope >= 0);
    1984           0 :         assert(scope < _UNIT_FILE_SCOPE_MAX);
    1985           0 :         assert(mode < _UNIT_FILE_PRESET_MAX);
    1986             : 
    1987           0 :         r = lookup_paths_init_from_scope(&paths, scope, root_dir);
    1988           0 :         if (r < 0)
    1989           0 :                 return r;
    1990             : 
    1991           0 :         r = get_config_path(scope, runtime, root_dir, &config_path);
    1992           0 :         if (r < 0)
    1993           0 :                 return r;
    1994             : 
    1995           0 :         STRV_FOREACH(i, files) {
    1996             : 
    1997           0 :                 if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
    1998           0 :                         return -EINVAL;
    1999             : 
    2000           0 :                 r = unit_file_query_preset(scope, root_dir, *i);
    2001           0 :                 if (r < 0)
    2002           0 :                         return r;
    2003             : 
    2004           0 :                 if (r && mode != UNIT_FILE_PRESET_DISABLE_ONLY)
    2005           0 :                         r = install_info_add_auto(&plus, *i);
    2006           0 :                 else if (!r && mode != UNIT_FILE_PRESET_ENABLE_ONLY)
    2007           0 :                         r = install_info_add_auto(&minus, *i);
    2008             :                 else
    2009           0 :                         r = 0;
    2010           0 :                 if (r < 0)
    2011           0 :                         return r;
    2012             :         }
    2013             : 
    2014           0 :         r = 0;
    2015             : 
    2016           0 :         if (mode != UNIT_FILE_PRESET_ENABLE_ONLY) {
    2017           0 :                 _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
    2018             : 
    2019           0 :                 r = install_context_mark_for_removal(&minus, &paths, &remove_symlinks_to, config_path, root_dir);
    2020             : 
    2021           0 :                 q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
    2022           0 :                 if (r == 0)
    2023           0 :                         r = q;
    2024             :         }
    2025             : 
    2026           0 :         if (mode != UNIT_FILE_PRESET_DISABLE_ONLY) {
    2027             :                 /* Returns number of symlinks that where supposed to be installed. */
    2028           0 :                 q = install_context_apply(&plus, &paths, config_path, root_dir, force, changes, n_changes);
    2029           0 :                 if (r == 0)
    2030           0 :                         r = q;
    2031             :         }
    2032             : 
    2033           0 :         return r;
    2034             : }
    2035             : 
    2036           0 : int unit_file_preset_all(
    2037             :                 UnitFileScope scope,
    2038             :                 bool runtime,
    2039             :                 const char *root_dir,
    2040             :                 UnitFilePresetMode mode,
    2041             :                 bool force,
    2042             :                 UnitFileChange **changes,
    2043             :                 unsigned *n_changes) {
    2044             : 
    2045           0 :         _cleanup_(install_context_done) InstallContext plus = {}, minus = {};
    2046           0 :         _cleanup_lookup_paths_free_ LookupPaths paths = {};
    2047           0 :         _cleanup_free_ char *config_path = NULL;
    2048             :         char **i;
    2049             :         int r, q;
    2050             : 
    2051           0 :         assert(scope >= 0);
    2052           0 :         assert(scope < _UNIT_FILE_SCOPE_MAX);
    2053           0 :         assert(mode < _UNIT_FILE_PRESET_MAX);
    2054             : 
    2055           0 :         r = lookup_paths_init_from_scope(&paths, scope, root_dir);
    2056           0 :         if (r < 0)
    2057           0 :                 return r;
    2058             : 
    2059           0 :         r = get_config_path(scope, runtime, root_dir, &config_path);
    2060           0 :         if (r < 0)
    2061           0 :                 return r;
    2062             : 
    2063           0 :         STRV_FOREACH(i, paths.unit_path) {
    2064           0 :                 _cleanup_closedir_ DIR *d = NULL;
    2065           0 :                 _cleanup_free_ char *units_dir;
    2066             : 
    2067           0 :                 units_dir = path_join(root_dir, *i, NULL);
    2068           0 :                 if (!units_dir)
    2069           0 :                         return -ENOMEM;
    2070             : 
    2071           0 :                 d = opendir(units_dir);
    2072           0 :                 if (!d) {
    2073           0 :                         if (errno == ENOENT)
    2074           0 :                                 continue;
    2075             : 
    2076           0 :                         return -errno;
    2077             :                 }
    2078             : 
    2079             :                 for (;;) {
    2080             :                         struct dirent *de;
    2081             : 
    2082           0 :                         errno = 0;
    2083           0 :                         de = readdir(d);
    2084           0 :                         if (!de && errno != 0)
    2085           0 :                                 return -errno;
    2086             : 
    2087           0 :                         if (!de)
    2088           0 :                                 break;
    2089             : 
    2090           0 :                         if (hidden_file(de->d_name))
    2091           0 :                                 continue;
    2092             : 
    2093           0 :                         if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
    2094           0 :                                 continue;
    2095             : 
    2096           0 :                         dirent_ensure_type(d, de);
    2097             : 
    2098           0 :                         if (de->d_type != DT_REG)
    2099           0 :                                 continue;
    2100             : 
    2101           0 :                         r = unit_file_query_preset(scope, root_dir, de->d_name);
    2102           0 :                         if (r < 0)
    2103           0 :                                 return r;
    2104             : 
    2105           0 :                         if (r && mode != UNIT_FILE_PRESET_DISABLE_ONLY)
    2106           0 :                                 r = install_info_add_auto(&plus, de->d_name);
    2107           0 :                         else if (!r && mode != UNIT_FILE_PRESET_ENABLE_ONLY)
    2108           0 :                                 r = install_info_add_auto(&minus, de->d_name);
    2109             :                         else
    2110           0 :                                 r = 0;
    2111           0 :                         if (r < 0)
    2112           0 :                                 return r;
    2113           0 :                 }
    2114             :         }
    2115             : 
    2116           0 :         r = 0;
    2117             : 
    2118           0 :         if (mode != UNIT_FILE_PRESET_ENABLE_ONLY) {
    2119           0 :                 _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
    2120             : 
    2121           0 :                 r = install_context_mark_for_removal(&minus, &paths, &remove_symlinks_to, config_path, root_dir);
    2122             : 
    2123           0 :                 q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, NULL);
    2124           0 :                 if (r == 0)
    2125           0 :                         r = q;
    2126             :         }
    2127             : 
    2128           0 :         if (mode != UNIT_FILE_PRESET_DISABLE_ONLY) {
    2129           0 :                 q = install_context_apply(&plus, &paths, config_path, root_dir, force, changes, n_changes);
    2130           0 :                 if (r == 0)
    2131           0 :                         r = q;
    2132             :         }
    2133             : 
    2134           0 :         return r;
    2135             : }
    2136             : 
    2137           0 : static void unit_file_list_free_one(UnitFileList *f) {
    2138           0 :         if (!f)
    2139           0 :                 return;
    2140             : 
    2141           0 :         free(f->path);
    2142           0 :         free(f);
    2143             : }
    2144             : 
    2145         310 : DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList*, unit_file_list_free_one);
    2146             : 
    2147           1 : int unit_file_get_list(
    2148             :                 UnitFileScope scope,
    2149             :                 const char *root_dir,
    2150             :                 Hashmap *h) {
    2151             : 
    2152           2 :         _cleanup_lookup_paths_free_ LookupPaths paths = {};
    2153             :         char **i;
    2154             :         int r;
    2155             : 
    2156           1 :         assert(scope >= 0);
    2157           1 :         assert(scope < _UNIT_FILE_SCOPE_MAX);
    2158           1 :         assert(h);
    2159             : 
    2160           1 :         if (root_dir && scope != UNIT_FILE_SYSTEM)
    2161           0 :                 return -EINVAL;
    2162             : 
    2163           1 :         if (root_dir) {
    2164           0 :                 r = access(root_dir, F_OK);
    2165           0 :                 if (r < 0)
    2166           0 :                         return -errno;
    2167             :         }
    2168             : 
    2169           1 :         r = lookup_paths_init_from_scope(&paths, scope, root_dir);
    2170           1 :         if (r < 0)
    2171           0 :                 return r;
    2172             : 
    2173           5 :         STRV_FOREACH(i, paths.unit_path) {
    2174           8 :                 _cleanup_closedir_ DIR *d = NULL;
    2175           4 :                 _cleanup_free_ char *units_dir;
    2176             : 
    2177           4 :                 units_dir = path_join(root_dir, *i, NULL);
    2178           4 :                 if (!units_dir)
    2179           0 :                         return -ENOMEM;
    2180             : 
    2181           4 :                 d = opendir(units_dir);
    2182           4 :                 if (!d) {
    2183           1 :                         if (errno == ENOENT)
    2184           1 :                                 continue;
    2185             : 
    2186           0 :                         return -errno;
    2187             :                 }
    2188             : 
    2189             :                 for (;;) {
    2190         620 :                         _cleanup_(unit_file_list_free_onep) UnitFileList *f = NULL;
    2191             :                         struct dirent *de;
    2192         620 :                         _cleanup_free_ char *path = NULL;
    2193         310 :                         bool also = false;
    2194             : 
    2195         310 :                         errno = 0;
    2196         310 :                         de = readdir(d);
    2197         310 :                         if (!de && errno != 0)
    2198           0 :                                 return -errno;
    2199             : 
    2200         310 :                         if (!de)
    2201           3 :                                 break;
    2202             : 
    2203         307 :                         if (hidden_file(de->d_name))
    2204           6 :                                 continue;
    2205             : 
    2206         301 :                         if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
    2207          15 :                                 continue;
    2208             : 
    2209         286 :                         if (hashmap_get(h, de->d_name))
    2210           0 :                                 continue;
    2211             : 
    2212         286 :                         dirent_ensure_type(d, de);
    2213             : 
    2214         286 :                         if (!IN_SET(de->d_type, DT_LNK, DT_REG))
    2215           0 :                                 continue;
    2216             : 
    2217         286 :                         f = new0(UnitFileList, 1);
    2218         286 :                         if (!f)
    2219           0 :                                 return -ENOMEM;
    2220             : 
    2221         286 :                         f->path = path_make_absolute(de->d_name, units_dir);
    2222         286 :                         if (!f->path)
    2223           0 :                                 return -ENOMEM;
    2224             : 
    2225         286 :                         r = null_or_empty_path(f->path);
    2226         286 :                         if (r < 0 && r != -ENOENT)
    2227           0 :                                 return r;
    2228         286 :                         else if (r > 0) {
    2229           0 :                                 f->state =
    2230           0 :                                         path_startswith(*i, "/run") ?
    2231             :                                         UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
    2232           0 :                                 goto found;
    2233             :                         }
    2234             : 
    2235         286 :                         r = find_symlinks_in_scope(scope, root_dir, de->d_name, &f->state);
    2236         286 :                         if (r < 0)
    2237           0 :                                 return r;
    2238         286 :                         else if (r > 0) {
    2239          12 :                                 f->state = UNIT_FILE_ENABLED;
    2240          12 :                                 goto found;
    2241             :                         }
    2242             : 
    2243         274 :                         path = path_make_absolute(de->d_name, *i);
    2244         274 :                         if (!path)
    2245           0 :                                 return -ENOMEM;
    2246             : 
    2247         274 :                         r = unit_file_can_install(&paths, root_dir, path, true, &also);
    2248         274 :                         if (r == -EINVAL ||  /* Invalid setting? */
    2249         274 :                             r == -EBADMSG || /* Invalid format? */
    2250             :                             r == -ENOENT     /* Included file not found? */)
    2251           0 :                                 f->state = UNIT_FILE_INVALID;
    2252         274 :                         else if (r < 0)
    2253           0 :                                 return r;
    2254         274 :                         else if (r > 0)
    2255          95 :                                 f->state = UNIT_FILE_DISABLED;
    2256             :                         else
    2257         179 :                                 f->state = also ? UNIT_FILE_INDIRECT : UNIT_FILE_STATIC;
    2258             : 
    2259             :                 found:
    2260         286 :                         r = hashmap_put(h, basename(f->path), f);
    2261         286 :                         if (r < 0)
    2262           0 :                                 return r;
    2263         286 :                         f = NULL; /* prevent cleanup */
    2264         307 :                 }
    2265             :         }
    2266             : 
    2267           1 :         return 0;
    2268             : }
    2269             : 
    2270             : static const char* const unit_file_state_table[_UNIT_FILE_STATE_MAX] = {
    2271             :         [UNIT_FILE_ENABLED] = "enabled",
    2272             :         [UNIT_FILE_ENABLED_RUNTIME] = "enabled-runtime",
    2273             :         [UNIT_FILE_LINKED] = "linked",
    2274             :         [UNIT_FILE_LINKED_RUNTIME] = "linked-runtime",
    2275             :         [UNIT_FILE_MASKED] = "masked",
    2276             :         [UNIT_FILE_MASKED_RUNTIME] = "masked-runtime",
    2277             :         [UNIT_FILE_STATIC] = "static",
    2278             :         [UNIT_FILE_DISABLED] = "disabled",
    2279             :         [UNIT_FILE_INDIRECT] = "indirect",
    2280             :         [UNIT_FILE_INVALID] = "invalid",
    2281             : };
    2282             : 
    2283         310 : DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState);
    2284             : 
    2285             : static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX] = {
    2286             :         [UNIT_FILE_SYMLINK] = "symlink",
    2287             :         [UNIT_FILE_UNLINK] = "unlink",
    2288             : };
    2289             : 
    2290           8 : DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType);
    2291             : 
    2292             : static const char* const unit_file_preset_mode_table[_UNIT_FILE_PRESET_MAX] = {
    2293             :         [UNIT_FILE_PRESET_FULL] = "full",
    2294             :         [UNIT_FILE_PRESET_ENABLE_ONLY] = "enable-only",
    2295             :         [UNIT_FILE_PRESET_DISABLE_ONLY] = "disable-only",
    2296             : };
    2297             : 
    2298          10 : DEFINE_STRING_TABLE_LOOKUP(unit_file_preset_mode, UnitFilePresetMode);

Generated by: LCOV version 1.11