LCOV - code coverage report
Current view: top level - shared - install.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 1309 1727 75.8 %
Date: 2019-08-22 15:41:25 Functions: 77 80 96.2 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <dirent.h>
       4             : #include <errno.h>
       5             : #include <fcntl.h>
       6             : #include <fnmatch.h>
       7             : #include <limits.h>
       8             : #include <stddef.h>
       9             : #include <stdio.h>
      10             : #include <stdlib.h>
      11             : #include <string.h>
      12             : #include <sys/stat.h>
      13             : #include <unistd.h>
      14             : 
      15             : #include "alloc-util.h"
      16             : #include "conf-files.h"
      17             : #include "conf-parser.h"
      18             : #include "def.h"
      19             : #include "dirent-util.h"
      20             : #include "extract-word.h"
      21             : #include "fd-util.h"
      22             : #include "fileio.h"
      23             : #include "fs-util.h"
      24             : #include "hashmap.h"
      25             : #include "install-printf.h"
      26             : #include "install.h"
      27             : #include "locale-util.h"
      28             : #include "log.h"
      29             : #include "macro.h"
      30             : #include "mkdir.h"
      31             : #include "path-lookup.h"
      32             : #include "path-util.h"
      33             : #include "rm-rf.h"
      34             : #include "set.h"
      35             : #include "special.h"
      36             : #include "stat-util.h"
      37             : #include "string-table.h"
      38             : #include "string-util.h"
      39             : #include "strv.h"
      40             : #include "unit-file.h"
      41             : 
      42             : #define UNIT_FILE_FOLLOW_SYMLINK_MAX 64
      43             : 
      44             : typedef enum SearchFlags {
      45             :         SEARCH_LOAD                   = 1 << 0,
      46             :         SEARCH_FOLLOW_CONFIG_SYMLINKS = 1 << 1,
      47             :         SEARCH_DROPIN                 = 1 << 2,
      48             : } SearchFlags;
      49             : 
      50             : typedef struct {
      51             :         OrderedHashmap *will_process;
      52             :         OrderedHashmap *have_processed;
      53             : } InstallContext;
      54             : 
      55             : typedef enum {
      56             :         PRESET_UNKNOWN,
      57             :         PRESET_ENABLE,
      58             :         PRESET_DISABLE,
      59             : } PresetAction;
      60             : 
      61             : typedef struct {
      62             :         char *pattern;
      63             :         PresetAction action;
      64             :         char **instances;
      65             : } PresetRule;
      66             : 
      67             : typedef struct {
      68             :         PresetRule *rules;
      69             :         size_t n_rules;
      70             : } Presets;
      71             : 
      72         518 : static bool unit_file_install_info_has_rules(const UnitFileInstallInfo *i) {
      73         518 :         assert(i);
      74             : 
      75         518 :         return !strv_isempty(i->aliases) ||
      76         800 :                !strv_isempty(i->wanted_by) ||
      77         282 :                !strv_isempty(i->required_by);
      78             : }
      79             : 
      80         276 : static bool unit_file_install_info_has_also(const UnitFileInstallInfo *i) {
      81         276 :         assert(i);
      82             : 
      83         276 :         return !strv_isempty(i->also);
      84             : }
      85             : 
      86          14 : static void presets_freep(Presets *p) {
      87             :         size_t i;
      88             : 
      89          14 :         if (!p)
      90           0 :                 return;
      91             : 
      92          32 :         for (i = 0; i < p->n_rules; i++) {
      93          18 :                 free(p->rules[i].pattern);
      94          18 :                 strv_free(p->rules[i].instances);
      95             :         }
      96             : 
      97          14 :         free(p->rules);
      98          14 :         p->n_rules = 0;
      99             : }
     100             : 
     101             : static const char *const unit_file_type_table[_UNIT_FILE_TYPE_MAX] = {
     102             :         [UNIT_FILE_TYPE_REGULAR] = "regular",
     103             :         [UNIT_FILE_TYPE_SYMLINK] = "symlink",
     104             :         [UNIT_FILE_TYPE_MASKED] = "masked",
     105             : };
     106             : 
     107           2 : DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(unit_file_type, UnitFileType);
     108             : 
     109          31 : static int in_search_path(const LookupPaths *p, const char *path) {
     110          31 :         _cleanup_free_ char *parent = NULL;
     111             :         char **i;
     112             : 
     113          31 :         assert(path);
     114             : 
     115          31 :         parent = dirname_malloc(path);
     116          31 :         if (!parent)
     117           0 :                 return -ENOMEM;
     118             : 
     119         343 :         STRV_FOREACH(i, p->search_path)
     120         339 :                 if (path_equal(parent, *i))
     121          27 :                         return true;
     122             : 
     123           4 :         return false;
     124             : }
     125             : 
     126         292 : static const char* skip_root(const LookupPaths *p, const char *path) {
     127             :         char *e;
     128             : 
     129         292 :         assert(p);
     130         292 :         assert(path);
     131             : 
     132         292 :         if (!p->root_dir)
     133         169 :                 return path;
     134             : 
     135         123 :         e = path_startswith(path, p->root_dir);
     136         123 :         if (!e)
     137           2 :                 return NULL;
     138             : 
     139             :         /* Make sure the returned path starts with a slash */
     140         121 :         if (e[0] != '/') {
     141         121 :                 if (e == path || e[-1] != '/')
     142           0 :                         return NULL;
     143             : 
     144         121 :                 e--;
     145             :         }
     146             : 
     147         121 :         return e;
     148             : }
     149             : 
     150         694 : static int path_is_generator(const LookupPaths *p, const char *path) {
     151         694 :         _cleanup_free_ char *parent = NULL;
     152             : 
     153         694 :         assert(p);
     154         694 :         assert(path);
     155             : 
     156         694 :         parent = dirname_malloc(path);
     157         694 :         if (!parent)
     158           0 :                 return -ENOMEM;
     159             : 
     160        1381 :         return path_equal_ptr(parent, p->generator) ||
     161        1381 :                path_equal_ptr(parent, p->generator_early) ||
     162         687 :                path_equal_ptr(parent, p->generator_late);
     163             : }
     164             : 
     165         684 : static int path_is_transient(const LookupPaths *p, const char *path) {
     166         684 :         _cleanup_free_ char *parent = NULL;
     167             : 
     168         684 :         assert(p);
     169         684 :         assert(path);
     170             : 
     171         684 :         parent = dirname_malloc(path);
     172         684 :         if (!parent)
     173           0 :                 return -ENOMEM;
     174             : 
     175         684 :         return path_equal_ptr(parent, p->transient);
     176             : }
     177             : 
     178           0 : static int path_is_control(const LookupPaths *p, const char *path) {
     179           0 :         _cleanup_free_ char *parent = NULL;
     180             : 
     181           0 :         assert(p);
     182           0 :         assert(path);
     183             : 
     184           0 :         parent = dirname_malloc(path);
     185           0 :         if (!parent)
     186           0 :                 return -ENOMEM;
     187             : 
     188           0 :         return path_equal_ptr(parent, p->persistent_control) ||
     189           0 :                path_equal_ptr(parent, p->runtime_control);
     190             : }
     191             : 
     192          12 : static int path_is_config(const LookupPaths *p, const char *path, bool check_parent) {
     193          12 :         _cleanup_free_ char *parent = NULL;
     194             : 
     195          12 :         assert(p);
     196          12 :         assert(path);
     197             : 
     198             :         /* Note that we do *not* have generic checks for /etc or /run in place, since with
     199             :          * them we couldn't discern configuration from transient or generated units */
     200             : 
     201          12 :         if (check_parent) {
     202          12 :                 parent = dirname_malloc(path);
     203          12 :                 if (!parent)
     204           0 :                         return -ENOMEM;
     205             : 
     206          12 :                 path = parent;
     207             :         }
     208             : 
     209          22 :         return path_equal_ptr(path, p->persistent_config) ||
     210          10 :                path_equal_ptr(path, p->runtime_config);
     211             : }
     212             : 
     213         226 : static int path_is_runtime(const LookupPaths *p, const char *path, bool check_parent) {
     214         226 :         _cleanup_free_ char *parent = NULL;
     215             :         const char *rpath;
     216             : 
     217         226 :         assert(p);
     218         226 :         assert(path);
     219             : 
     220             :         /* Everything in /run is considered runtime. On top of that we also add
     221             :          * explicit checks for the various runtime directories, as safety net. */
     222             : 
     223         226 :         rpath = skip_root(p, path);
     224         226 :         if (rpath && path_startswith(rpath, "/run"))
     225           1 :                 return true;
     226             : 
     227         225 :         if (check_parent) {
     228           5 :                 parent = dirname_malloc(path);
     229           5 :                 if (!parent)
     230           0 :                         return -ENOMEM;
     231             : 
     232           5 :                 path = parent;
     233             :         }
     234             : 
     235         450 :         return path_equal_ptr(path, p->runtime_config) ||
     236         450 :                path_equal_ptr(path, p->generator) ||
     237         450 :                path_equal_ptr(path, p->generator_early) ||
     238         450 :                path_equal_ptr(path, p->generator_late) ||
     239         675 :                path_equal_ptr(path, p->transient) ||
     240         225 :                path_equal_ptr(path, p->runtime_control);
     241             : }
     242             : 
     243           4 : static int path_is_vendor(const LookupPaths *p, const char *path) {
     244             :         const char *rpath;
     245             : 
     246           4 :         assert(p);
     247           4 :         assert(path);
     248             : 
     249           4 :         rpath = skip_root(p, path);
     250           4 :         if (!rpath)
     251           0 :                 return 0;
     252             : 
     253           4 :         if (path_startswith(rpath, "/usr"))
     254           3 :                 return true;
     255             : 
     256             : #if HAVE_SPLIT_USR
     257             :         if (path_startswith(rpath, "/lib"))
     258             :                 return true;
     259             : #endif
     260             : 
     261           1 :         return path_equal(rpath, SYSTEM_DATA_UNIT_PATH);
     262             : }
     263             : 
     264         122 : int unit_file_changes_add(
     265             :                 UnitFileChange **changes,
     266             :                 size_t *n_changes,
     267             :                 UnitFileChangeType type,
     268             :                 const char *path,
     269             :                 const char *source) {
     270             : 
     271         122 :         _cleanup_free_ char *p = NULL, *s = NULL;
     272             :         UnitFileChange *c;
     273             : 
     274         122 :         assert(path);
     275         122 :         assert(!changes == !n_changes);
     276             : 
     277         122 :         if (!changes)
     278          59 :                 return 0;
     279             : 
     280          63 :         c = reallocarray(*changes, *n_changes + 1, sizeof(UnitFileChange));
     281          63 :         if (!c)
     282           0 :                 return -ENOMEM;
     283          63 :         *changes = c;
     284             : 
     285          63 :         p = strdup(path);
     286          63 :         if (source)
     287          37 :                 s = strdup(source);
     288             : 
     289          63 :         if (!p || (source && !s))
     290           0 :                 return -ENOMEM;
     291             : 
     292          63 :         path_simplify(p, false);
     293          63 :         if (s)
     294          37 :                 path_simplify(s, false);
     295             : 
     296          63 :         c[*n_changes] = (UnitFileChange) { type, p, s };
     297          63 :         p = s = NULL;
     298          63 :         (*n_changes) ++;
     299          63 :         return 0;
     300             : }
     301             : 
     302          44 : void unit_file_changes_free(UnitFileChange *changes, size_t n_changes) {
     303             :         size_t i;
     304             : 
     305          44 :         assert(changes || n_changes == 0);
     306             : 
     307         107 :         for (i = 0; i < n_changes; i++) {
     308          63 :                 free(changes[i].path);
     309          63 :                 free(changes[i].source);
     310             :         }
     311             : 
     312          44 :         free(changes);
     313          44 : }
     314             : 
     315           0 : void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *changes, size_t n_changes, bool quiet) {
     316             :         size_t i;
     317           0 :         bool logged = false;
     318             : 
     319           0 :         assert(changes || n_changes == 0);
     320             :         /* If verb is not specified, errors are not allowed! */
     321           0 :         assert(verb || r >= 0);
     322             : 
     323           0 :         for (i = 0; i < n_changes; i++) {
     324           0 :                 assert(verb || changes[i].type >= 0);
     325             : 
     326           0 :                 switch(changes[i].type) {
     327           0 :                 case UNIT_FILE_SYMLINK:
     328           0 :                         if (!quiet)
     329           0 :                                 log_info("Created symlink %s %s %s.",
     330             :                                          changes[i].path,
     331             :                                          special_glyph(SPECIAL_GLYPH_ARROW),
     332             :                                          changes[i].source);
     333           0 :                         break;
     334           0 :                 case UNIT_FILE_UNLINK:
     335           0 :                         if (!quiet)
     336           0 :                                 log_info("Removed %s.", changes[i].path);
     337           0 :                         break;
     338           0 :                 case UNIT_FILE_IS_MASKED:
     339           0 :                         if (!quiet)
     340           0 :                                 log_info("Unit %s is masked, ignoring.", changes[i].path);
     341           0 :                         break;
     342           0 :                 case UNIT_FILE_IS_DANGLING:
     343           0 :                         if (!quiet)
     344           0 :                                 log_info("Unit %s is an alias to a unit that is not present, ignoring.",
     345             :                                          changes[i].path);
     346           0 :                         break;
     347           0 :                 case -EEXIST:
     348           0 :                         if (changes[i].source)
     349           0 :                                 log_error_errno(changes[i].type,
     350             :                                                 "Failed to %s unit, file %s already exists and is a symlink to %s.",
     351             :                                                 verb, changes[i].path, changes[i].source);
     352             :                         else
     353           0 :                                 log_error_errno(changes[i].type,
     354             :                                                 "Failed to %s unit, file %s already exists.",
     355             :                                                 verb, changes[i].path);
     356           0 :                         logged = true;
     357           0 :                         break;
     358           0 :                 case -ERFKILL:
     359           0 :                         log_error_errno(changes[i].type, "Failed to %s unit, unit %s is masked.",
     360             :                                         verb, changes[i].path);
     361           0 :                         logged = true;
     362           0 :                         break;
     363           0 :                 case -EADDRNOTAVAIL:
     364           0 :                         log_error_errno(changes[i].type, "Failed to %s unit, unit %s is transient or generated.",
     365             :                                         verb, changes[i].path);
     366           0 :                         logged = true;
     367           0 :                         break;
     368           0 :                 case -ELOOP:
     369           0 :                         log_error_errno(changes[i].type, "Failed to %s unit, refusing to operate on linked unit file %s",
     370             :                                         verb, changes[i].path);
     371           0 :                         logged = true;
     372           0 :                         break;
     373             : 
     374           0 :                 case -ENOENT:
     375           0 :                         log_error_errno(changes[i].type, "Failed to %s unit, unit %s does not exist.", verb, changes[i].path);
     376           0 :                         logged = true;
     377           0 :                         break;
     378             : 
     379           0 :                 default:
     380           0 :                         assert(changes[i].type < 0);
     381           0 :                         log_error_errno(changes[i].type, "Failed to %s unit, file %s: %m.",
     382             :                                         verb, changes[i].path);
     383           0 :                         logged = true;
     384             :                 }
     385             :         }
     386             : 
     387           0 :         if (r < 0 && !logged)
     388           0 :                 log_error_errno(r, "Failed to %s: %m.", verb);
     389           0 : }
     390             : 
     391             : /**
     392             :  * Checks if two paths or symlinks from wd are the same, when root is the root of the filesystem.
     393             :  * wc should be the full path in the host file system.
     394             :  */
     395           2 : static bool chroot_symlinks_same(const char *root, const char *wd, const char *a, const char *b) {
     396           2 :         assert(path_is_absolute(wd));
     397             : 
     398             :         /* This will give incorrect results if the paths are relative and go outside
     399             :          * of the chroot. False negatives are possible. */
     400             : 
     401           2 :         if (!root)
     402           0 :                 root = "/";
     403             : 
     404          14 :         a = strjoina(path_is_absolute(a) ? root : wd, "/", a);
     405          14 :         b = strjoina(path_is_absolute(b) ? root : wd, "/", b);
     406           2 :         return path_equal_or_files_same(a, b, 0);
     407             : }
     408             : 
     409          39 : static int create_symlink(
     410             :                 const LookupPaths *paths,
     411             :                 const char *old_path,
     412             :                 const char *new_path,
     413             :                 bool force,
     414             :                 UnitFileChange **changes,
     415             :                 size_t *n_changes) {
     416             : 
     417          39 :         _cleanup_free_ char *dest = NULL, *dirname = NULL;
     418             :         const char *rp;
     419             :         int r;
     420             : 
     421          39 :         assert(old_path);
     422          39 :         assert(new_path);
     423             : 
     424          39 :         rp = skip_root(paths, old_path);
     425          39 :         if (rp)
     426          37 :                 old_path = rp;
     427             : 
     428             :         /* Actually create a symlink, and remember that we did. Is
     429             :          * smart enough to check if there's already a valid symlink in
     430             :          * place.
     431             :          *
     432             :          * Returns 1 if a symlink was created or already exists and points to
     433             :          * the right place, or negative on error.
     434             :          */
     435             : 
     436          39 :         mkdir_parents_label(new_path, 0755);
     437             : 
     438          39 :         if (symlink(old_path, new_path) >= 0) {
     439          37 :                 unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
     440          37 :                 return 1;
     441             :         }
     442             : 
     443           2 :         if (errno != EEXIST) {
     444           0 :                 unit_file_changes_add(changes, n_changes, -errno, new_path, NULL);
     445           0 :                 return -errno;
     446             :         }
     447             : 
     448           2 :         r = readlink_malloc(new_path, &dest);
     449           2 :         if (r < 0) {
     450             :                 /* translate EINVAL (non-symlink exists) to EEXIST */
     451           0 :                 if (r == -EINVAL)
     452           0 :                         r = -EEXIST;
     453             : 
     454           0 :                 unit_file_changes_add(changes, n_changes, r, new_path, NULL);
     455           0 :                 return r;
     456             :         }
     457             : 
     458           2 :         dirname = dirname_malloc(new_path);
     459           2 :         if (!dirname)
     460           0 :                 return -ENOMEM;
     461             : 
     462           2 :         if (chroot_symlinks_same(paths->root_dir, dirname, dest, old_path)) {
     463           2 :                 log_debug("Symlink %s → %s already exists", new_path, dest);
     464           2 :                 return 1;
     465             :         }
     466             : 
     467           0 :         if (!force) {
     468           0 :                 unit_file_changes_add(changes, n_changes, -EEXIST, new_path, dest);
     469           0 :                 return -EEXIST;
     470             :         }
     471             : 
     472           0 :         r = symlink_atomic(old_path, new_path);
     473           0 :         if (r < 0) {
     474           0 :                 unit_file_changes_add(changes, n_changes, r, new_path, NULL);
     475           0 :                 return r;
     476             :         }
     477             : 
     478           0 :         unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL);
     479           0 :         unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
     480             : 
     481           0 :         return 1;
     482             : }
     483             : 
     484          58 : static int mark_symlink_for_removal(
     485             :                 Set **remove_symlinks_to,
     486             :                 const char *p) {
     487             : 
     488             :         char *n;
     489             :         int r;
     490             : 
     491          58 :         assert(p);
     492             : 
     493          58 :         r = set_ensure_allocated(remove_symlinks_to, &path_hash_ops);
     494          58 :         if (r < 0)
     495           0 :                 return r;
     496             : 
     497          58 :         n = strdup(p);
     498          58 :         if (!n)
     499           0 :                 return -ENOMEM;
     500             : 
     501          58 :         path_simplify(n, false);
     502             : 
     503          58 :         r = set_consume(*remove_symlinks_to, n);
     504          58 :         if (r == -EEXIST)
     505           0 :                 return 0;
     506          58 :         if (r < 0)
     507           0 :                 return r;
     508             : 
     509          58 :         return 1;
     510             : }
     511             : 
     512          62 : static int remove_marked_symlinks_fd(
     513             :                 Set *remove_symlinks_to,
     514             :                 int fd,
     515             :                 const char *path,
     516             :                 const char *config_path,
     517             :                 const LookupPaths *lp,
     518             :                 bool dry_run,
     519             :                 bool *restart,
     520             :                 UnitFileChange **changes,
     521             :                 size_t *n_changes) {
     522             : 
     523          62 :         _cleanup_closedir_ DIR *d = NULL;
     524             :         struct dirent *de;
     525          62 :         int r = 0;
     526             : 
     527          62 :         assert(remove_symlinks_to);
     528          62 :         assert(fd >= 0);
     529          62 :         assert(path);
     530          62 :         assert(config_path);
     531          62 :         assert(lp);
     532          62 :         assert(restart);
     533             : 
     534          62 :         d = fdopendir(fd);
     535          62 :         if (!d) {
     536           0 :                 safe_close(fd);
     537           0 :                 return -errno;
     538             :         }
     539             : 
     540          62 :         rewinddir(d);
     541             : 
     542         326 :         FOREACH_DIRENT(de, d, return -errno) {
     543             : 
     544         140 :                 dirent_ensure_type(d, de);
     545             : 
     546         140 :                 if (de->d_type == DT_DIR) {
     547          32 :                         _cleanup_free_ char *p = NULL;
     548             :                         int nfd, q;
     549             : 
     550          32 :                         nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
     551          32 :                         if (nfd < 0) {
     552           0 :                                 if (errno == ENOENT)
     553           0 :                                         continue;
     554             : 
     555           0 :                                 if (r == 0)
     556           0 :                                         r = -errno;
     557           0 :                                 continue;
     558             :                         }
     559             : 
     560          32 :                         p = path_make_absolute(de->d_name, path);
     561          32 :                         if (!p) {
     562           0 :                                 safe_close(nfd);
     563           0 :                                 return -ENOMEM;
     564             :                         }
     565             : 
     566             :                         /* This will close nfd, regardless whether it succeeds or not */
     567          32 :                         q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, lp, dry_run, restart, changes, n_changes);
     568          32 :                         if (q < 0 && r == 0)
     569           0 :                                 r = q;
     570             : 
     571         108 :                 } else if (de->d_type == DT_LNK) {
     572         196 :                         _cleanup_free_ char *p = NULL, *dest = NULL;
     573             :                         const char *rp;
     574             :                         bool found;
     575             :                         int q;
     576             : 
     577         108 :                         if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
     578           0 :                                 continue;
     579             : 
     580         108 :                         p = path_make_absolute(de->d_name, path);
     581         108 :                         if (!p)
     582           0 :                                 return -ENOMEM;
     583         108 :                         path_simplify(p, false);
     584             : 
     585         108 :                         q = readlink_malloc(p, &dest);
     586         108 :                         if (q == -ENOENT)
     587           0 :                                 continue;
     588         108 :                         if (q < 0) {
     589           0 :                                 if (r == 0)
     590           0 :                                         r = q;
     591           0 :                                 continue;
     592             :                         }
     593             : 
     594             :                         /* We remove all links pointing to a file or path that is marked, as well as all files sharing
     595             :                          * the same name as a file that is marked. */
     596             : 
     597         216 :                         found = set_contains(remove_symlinks_to, dest) ||
     598         216 :                                 set_contains(remove_symlinks_to, basename(dest)) ||
     599          90 :                                 set_contains(remove_symlinks_to, de->d_name);
     600             : 
     601         108 :                         if (!found)
     602          88 :                                 continue;
     603             : 
     604          20 :                         if (!dry_run) {
     605          20 :                                 if (unlinkat(fd, de->d_name, 0) < 0 && errno != ENOENT) {
     606           0 :                                         if (r == 0)
     607           0 :                                                 r = -errno;
     608           0 :                                         unit_file_changes_add(changes, n_changes, -errno, p, NULL);
     609           0 :                                         continue;
     610             :                                 }
     611             : 
     612          20 :                                 (void) rmdir_parents(p, config_path);
     613             :                         }
     614             : 
     615          20 :                         unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, p, NULL);
     616             : 
     617             :                         /* Now, remember the full path (but with the root prefix removed) of
     618             :                          * the symlink we just removed, and remove any symlinks to it, too. */
     619             : 
     620          20 :                         rp = skip_root(lp, p);
     621          20 :                         q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: p);
     622          20 :                         if (q < 0)
     623           0 :                                 return q;
     624          20 :                         if (q > 0 && !dry_run)
     625          20 :                                 *restart = true;
     626             :                 }
     627             :         }
     628             : 
     629          62 :         return r;
     630             : }
     631             : 
     632          24 : static int remove_marked_symlinks(
     633             :                 Set *remove_symlinks_to,
     634             :                 const char *config_path,
     635             :                 const LookupPaths *lp,
     636             :                 bool dry_run,
     637             :                 UnitFileChange **changes,
     638             :                 size_t *n_changes) {
     639             : 
     640          24 :         _cleanup_close_ int fd = -1;
     641             :         bool restart;
     642          24 :         int r = 0;
     643             : 
     644          24 :         assert(config_path);
     645          24 :         assert(lp);
     646             : 
     647          24 :         if (set_size(remove_symlinks_to) <= 0)
     648           5 :                 return 0;
     649             : 
     650          19 :         fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC);
     651          19 :         if (fd < 0)
     652           0 :                 return errno == ENOENT ? 0 : -errno;
     653             : 
     654             :         do {
     655             :                 int q, cfd;
     656          30 :                 restart = false;
     657             : 
     658          30 :                 cfd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
     659          30 :                 if (cfd < 0)
     660           0 :                         return -errno;
     661             : 
     662             :                 /* This takes possession of cfd and closes it */
     663          30 :                 q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, lp, dry_run, &restart, changes, n_changes);
     664          30 :                 if (r == 0)
     665          30 :                         r = q;
     666          30 :         } while (restart);
     667             : 
     668          19 :         return r;
     669             : }
     670             : 
     671         312 : static int is_symlink_with_known_name(const UnitFileInstallInfo *i, const char *name) {
     672             :         int r;
     673             : 
     674         312 :         if (streq(name, i->name))
     675         170 :                 return true;
     676             : 
     677         142 :         if (strv_contains(i->aliases, name))
     678          22 :                 return true;
     679             : 
     680             :         /* Look for template symlink matching DefaultInstance */
     681         120 :         if (i->default_instance && unit_name_is_valid(i->name, UNIT_NAME_TEMPLATE)) {
     682          20 :                 _cleanup_free_ char *s = NULL;
     683             : 
     684          20 :                 r = unit_name_replace_instance(i->name, i->default_instance, &s);
     685          20 :                 if (r < 0) {
     686           0 :                         if (r != -EINVAL)
     687           0 :                                 return r;
     688             : 
     689          20 :                 } else if (streq(name, s))
     690           4 :                         return true;
     691             :         }
     692             : 
     693         116 :         return false;
     694             : }
     695             : 
     696       56948 : static int find_symlinks_fd(
     697             :                 const char *root_dir,
     698             :                 const UnitFileInstallInfo *i,
     699             :                 bool match_aliases,
     700             :                 bool ignore_same_name,
     701             :                 int fd,
     702             :                 const char *path,
     703             :                 const char *config_path,
     704             :                 bool *same_name_link) {
     705             : 
     706       56948 :         _cleanup_closedir_ DIR *d = NULL;
     707             :         struct dirent *de;
     708       56948 :         int r = 0;
     709             : 
     710       56948 :         assert(i);
     711       56948 :         assert(fd >= 0);
     712       56948 :         assert(path);
     713       56948 :         assert(config_path);
     714       56948 :         assert(same_name_link);
     715             : 
     716       56948 :         d = fdopendir(fd);
     717       56948 :         if (!d) {
     718           0 :                 safe_close(fd);
     719           0 :                 return -errno;
     720             :         }
     721             : 
     722      746806 :         FOREACH_DIRENT(de, d, return -errno) {
     723             : 
     724      576960 :                 dirent_ensure_type(d, de);
     725             : 
     726      576960 :                 if (de->d_type == DT_DIR) {
     727       51112 :                         _cleanup_free_ char *p = NULL;
     728             :                         int nfd, q;
     729             : 
     730       51112 :                         nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
     731       51112 :                         if (nfd < 0) {
     732           0 :                                 if (errno == ENOENT)
     733           0 :                                         continue;
     734             : 
     735           0 :                                 if (r == 0)
     736           0 :                                         r = -errno;
     737           0 :                                 continue;
     738             :                         }
     739             : 
     740       51112 :                         p = path_make_absolute(de->d_name, path);
     741       51112 :                         if (!p) {
     742           0 :                                 safe_close(nfd);
     743           0 :                                 return -ENOMEM;
     744             :                         }
     745             : 
     746             :                         /* This will close nfd, regardless whether it succeeds or not */
     747       51112 :                         q = find_symlinks_fd(root_dir, i, match_aliases, ignore_same_name, nfd,
     748             :                                              p, config_path, same_name_link);
     749       51112 :                         if (q > 0)
     750         243 :                                 return 1;
     751       50869 :                         if (r == 0)
     752       50869 :                                 r = q;
     753             : 
     754      525848 :                 } else if (de->d_type == DT_LNK) {
     755      158994 :                         _cleanup_free_ char *p = NULL, *dest = NULL;
     756      158648 :                         bool found_path = false, found_dest, b = false;
     757             :                         int q;
     758             : 
     759             :                         /* Acquire symlink name */
     760      158648 :                         p = path_make_absolute(de->d_name, path);
     761      158648 :                         if (!p)
     762           0 :                                 return -ENOMEM;
     763             : 
     764             :                         /* Acquire symlink destination */
     765      158648 :                         q = readlink_malloc(p, &dest);
     766      158648 :                         if (q == -ENOENT)
     767           0 :                                 continue;
     768      158648 :                         if (q < 0) {
     769           0 :                                 if (r == 0)
     770           0 :                                         r = q;
     771           0 :                                 continue;
     772             :                         }
     773             : 
     774             :                         /* Make absolute */
     775      158648 :                         if (!path_is_absolute(dest)) {
     776             :                                 char *x;
     777             : 
     778       85148 :                                 x = path_join(root_dir, dest);
     779       85148 :                                 if (!x)
     780           0 :                                         return -ENOMEM;
     781             : 
     782       85148 :                                 free_and_replace(dest, x);
     783             :                         }
     784             : 
     785      158648 :                         assert(unit_name_is_valid(i->name, UNIT_NAME_ANY));
     786      158648 :                         if (!ignore_same_name)
     787             :                                 /* Check if the symlink itself matches what we are looking for.
     788             :                                  *
     789             :                                  * If ignore_same_name is specified, we are in one of the directories which
     790             :                                  * have lower priority than the unit file, and even if a file or symlink with
     791             :                                  * this name was found, we should ignore it. */
     792      154339 :                                  found_path = streq(de->d_name, i->name);
     793             : 
     794             :                         /* Check if what the symlink points to matches what we are looking for */
     795      158648 :                         found_dest = streq(basename(dest), i->name);
     796             : 
     797      158648 :                         if (found_path && found_dest) {
     798         238 :                                 _cleanup_free_ char *t = NULL;
     799             : 
     800             :                                 /* Filter out same name links in the main
     801             :                                  * config path */
     802         238 :                                 t = path_make_absolute(i->name, config_path);
     803         238 :                                 if (!t)
     804           0 :                                         return -ENOMEM;
     805             : 
     806         238 :                                 b = path_equal(t, p);
     807             :                         }
     808             : 
     809      158648 :                         if (b)
     810          19 :                                 *same_name_link = true;
     811      158629 :                         else if (found_path || found_dest) {
     812         462 :                                 if (!match_aliases)
     813         150 :                                         return 1;
     814             : 
     815             :                                 /* Check if symlink name is in the set of names used by [Install] */
     816         312 :                                 q = is_symlink_with_known_name(i, de->d_name);
     817         312 :                                 if (q < 0)
     818           0 :                                         return q;
     819         312 :                                 if (q > 0)
     820         196 :                                         return 1;
     821             :                         }
     822             :                 }
     823             :         }
     824             : 
     825       56359 :         return r;
     826             : }
     827             : 
     828       13219 : static int find_symlinks(
     829             :                 const char *root_dir,
     830             :                 const UnitFileInstallInfo *i,
     831             :                 bool match_name,
     832             :                 bool ignore_same_name,
     833             :                 const char *config_path,
     834             :                 bool *same_name_link) {
     835             : 
     836             :         int fd;
     837             : 
     838       13219 :         assert(i);
     839       13219 :         assert(config_path);
     840       13219 :         assert(same_name_link);
     841             : 
     842       13219 :         fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC);
     843       13219 :         if (fd < 0) {
     844        7383 :                 if (IN_SET(errno, ENOENT, ENOTDIR, EACCES))
     845        7383 :                         return 0;
     846           0 :                 return -errno;
     847             :         }
     848             : 
     849             :         /* This takes possession of fd and closes it */
     850        5836 :         return find_symlinks_fd(root_dir, i, match_name, ignore_same_name, fd,
     851             :                                 config_path, config_path, same_name_link);
     852             : }
     853             : 
     854        1178 : static int find_symlinks_in_scope(
     855             :                 UnitFileScope scope,
     856             :                 const LookupPaths *paths,
     857             :                 const UnitFileInstallInfo *i,
     858             :                 bool match_name,
     859             :                 UnitFileState *state) {
     860             : 
     861        1178 :         bool same_name_link_runtime = false, same_name_link_config = false;
     862        1178 :         bool enabled_in_runtime = false, enabled_at_all = false;
     863        1178 :         bool ignore_same_name = false;
     864             :         char **p;
     865             :         int r;
     866             : 
     867        1178 :         assert(paths);
     868        1178 :         assert(i);
     869             : 
     870             :         /* As we iterate over the list of search paths in paths->search_path, we may encounter "same name"
     871             :          * symlinks. The ones which are "below" (i.e. have lower priority) than the unit file itself are
     872             :          * effectively masked, so we should ignore them. */
     873             : 
     874       14266 :         STRV_FOREACH(p, paths->search_path)  {
     875       13219 :                 bool same_name_link = false;
     876             : 
     877       13219 :                 r = find_symlinks(paths->root_dir, i, match_name, ignore_same_name, *p, &same_name_link);
     878       13219 :                 if (r < 0)
     879         131 :                         return r;
     880       13219 :                 if (r > 0) {
     881             :                         /* We found symlinks in this dir? Yay! Let's see where precisely it is enabled. */
     882             : 
     883         346 :                         if (path_equal_ptr(*p, paths->persistent_config)) {
     884             :                                 /* This is the best outcome, let's return it immediately. */
     885         131 :                                 *state = UNIT_FILE_ENABLED;
     886         131 :                                 return 1;
     887             :                         }
     888             : 
     889             :                         /* look for global enablement of user units */
     890         215 :                         if (scope == UNIT_FILE_USER && path_is_user_config_dir(*p)) {
     891           0 :                                 *state = UNIT_FILE_ENABLED;
     892           0 :                                 return 1;
     893             :                         }
     894             : 
     895         215 :                         r = path_is_runtime(paths, *p, false);
     896         215 :                         if (r < 0)
     897           0 :                                 return r;
     898         215 :                         if (r > 0)
     899           1 :                                 enabled_in_runtime = true;
     900             :                         else
     901         214 :                                 enabled_at_all = true;
     902             : 
     903       12873 :                 } else if (same_name_link) {
     904           8 :                         if (path_equal_ptr(*p, paths->persistent_config))
     905           2 :                                 same_name_link_config = true;
     906             :                         else {
     907           6 :                                 r = path_is_runtime(paths, *p, false);
     908           6 :                                 if (r < 0)
     909           0 :                                         return r;
     910           6 :                                 if (r > 0)
     911           0 :                                         same_name_link_runtime = true;
     912             :                         }
     913             :                 }
     914             : 
     915             :                 /* Check if next iteration will be "below" the unit file (either a regular file
     916             :                  * or a symlink), and hence should be ignored */
     917       13088 :                 if (!ignore_same_name && path_startswith(i->path, *p))
     918        1039 :                         ignore_same_name = true;
     919             :         }
     920             : 
     921        1047 :         if (enabled_in_runtime) {
     922           1 :                 *state = UNIT_FILE_ENABLED_RUNTIME;
     923           1 :                 return 1;
     924             :         }
     925             : 
     926             :         /* Here's a special rule: if the unit we are looking for is an instance, and it symlinked in the search path
     927             :          * outside of runtime and configuration directory, then we consider it statically enabled. Note we do that only
     928             :          * for instance, not for regular names, as those are merely aliases, while instances explicitly instantiate
     929             :          * something, and hence are a much stronger concept. */
     930        1046 :         if (enabled_at_all && unit_name_is_valid(i->name, UNIT_NAME_INSTANCE)) {
     931           1 :                 *state = UNIT_FILE_STATIC;
     932           1 :                 return 1;
     933             :         }
     934             : 
     935             :         /* Hmm, we didn't find it, but maybe we found the same name
     936             :          * link? */
     937        1045 :         if (same_name_link_config) {
     938           2 :                 *state = UNIT_FILE_LINKED;
     939           2 :                 return 1;
     940             :         }
     941        1043 :         if (same_name_link_runtime) {
     942           0 :                 *state = UNIT_FILE_LINKED_RUNTIME;
     943           0 :                 return 1;
     944             :         }
     945             : 
     946        1043 :         return 0;
     947             : }
     948             : 
     949        1025 : static void install_info_free(UnitFileInstallInfo *i) {
     950             : 
     951        1025 :         if (!i)
     952           0 :                 return;
     953             : 
     954        1025 :         free(i->name);
     955        1025 :         free(i->path);
     956        1025 :         strv_free(i->aliases);
     957        1025 :         strv_free(i->wanted_by);
     958        1025 :         strv_free(i->required_by);
     959        1025 :         strv_free(i->also);
     960        1025 :         free(i->default_instance);
     961        1025 :         free(i->symlink_target);
     962        1025 :         free(i);
     963             : }
     964             : 
     965         829 : static void install_context_done(InstallContext *c) {
     966         829 :         assert(c);
     967             : 
     968        1780 :         c->will_process = ordered_hashmap_free_with_destructor(c->will_process, install_info_free);
     969         903 :         c->have_processed = ordered_hashmap_free_with_destructor(c->have_processed, install_info_free);
     970         829 : }
     971             : 
     972        1128 : static UnitFileInstallInfo *install_info_find(InstallContext *c, const char *name) {
     973             :         UnitFileInstallInfo *i;
     974             : 
     975        1128 :         i = ordered_hashmap_get(c->have_processed, name);
     976        1128 :         if (i)
     977           0 :                 return i;
     978             : 
     979        1128 :         return ordered_hashmap_get(c->will_process, name);
     980             : }
     981             : 
     982          31 : static int install_info_may_process(
     983             :                 const UnitFileInstallInfo *i,
     984             :                 const LookupPaths *paths,
     985             :                 UnitFileChange **changes,
     986             :                 size_t *n_changes) {
     987          31 :         assert(i);
     988          31 :         assert(paths);
     989             : 
     990             :         /* Checks whether the loaded unit file is one we should process, or is masked,
     991             :          * transient or generated and thus not subject to enable/disable operations. */
     992             : 
     993          31 :         if (i->type == UNIT_FILE_TYPE_MASKED) {
     994           1 :                 unit_file_changes_add(changes, n_changes, -ERFKILL, i->path, NULL);
     995           1 :                 return -ERFKILL;
     996             :         }
     997          60 :         if (path_is_generator(paths, i->path) ||
     998          30 :             path_is_transient(paths, i->path)) {
     999           0 :                 unit_file_changes_add(changes, n_changes, -EADDRNOTAVAIL, i->path, NULL);
    1000           0 :                 return -EADDRNOTAVAIL;
    1001             :         }
    1002             : 
    1003          30 :         return 0;
    1004             : }
    1005             : 
    1006             : /**
    1007             :  * Adds a new UnitFileInstallInfo entry under name in the InstallContext.will_process
    1008             :  * hashmap, or retrieves the existing one if already present.
    1009             :  *
    1010             :  * Returns negative on error, 0 if the unit was already known, 1 otherwise.
    1011             :  */
    1012        1034 : static int install_info_add(
    1013             :                 InstallContext *c,
    1014             :                 const char *name,
    1015             :                 const char *path,
    1016             :                 bool auxiliary,
    1017             :                 UnitFileInstallInfo **ret) {
    1018             : 
    1019        1034 :         UnitFileInstallInfo *i = NULL;
    1020             :         int r;
    1021             : 
    1022        1034 :         assert(c);
    1023        1034 :         assert(name || path);
    1024             : 
    1025        1034 :         if (!name)
    1026           1 :                 name = basename(path);
    1027             : 
    1028        1034 :         if (!unit_name_is_valid(name, UNIT_NAME_ANY))
    1029           0 :                 return -EINVAL;
    1030             : 
    1031        1034 :         i = install_info_find(c, name);
    1032        1034 :         if (i) {
    1033           9 :                 i->auxiliary = i->auxiliary && auxiliary;
    1034             : 
    1035           9 :                 if (ret)
    1036           9 :                         *ret = i;
    1037           9 :                 return 0;
    1038             :         }
    1039             : 
    1040        1025 :         r = ordered_hashmap_ensure_allocated(&c->will_process, &string_hash_ops);
    1041        1025 :         if (r < 0)
    1042           0 :                 return r;
    1043             : 
    1044        1025 :         i = new(UnitFileInstallInfo, 1);
    1045        1025 :         if (!i)
    1046           0 :                 return -ENOMEM;
    1047             : 
    1048        1025 :         *i = (UnitFileInstallInfo) {
    1049             :                 .type = _UNIT_FILE_TYPE_INVALID,
    1050             :                 .auxiliary = auxiliary,
    1051             :         };
    1052             : 
    1053        1025 :         i->name = strdup(name);
    1054        1025 :         if (!i->name) {
    1055           0 :                 r = -ENOMEM;
    1056           0 :                 goto fail;
    1057             :         }
    1058             : 
    1059        1025 :         if (path) {
    1060           1 :                 i->path = strdup(path);
    1061           1 :                 if (!i->path) {
    1062           0 :                         r = -ENOMEM;
    1063           0 :                         goto fail;
    1064             :                 }
    1065             :         }
    1066             : 
    1067        1025 :         r = ordered_hashmap_put(c->will_process, i->name, i);
    1068        1025 :         if (r < 0)
    1069           0 :                 goto fail;
    1070             : 
    1071        1025 :         if (ret)
    1072        1015 :                 *ret = i;
    1073             : 
    1074        1025 :         return 1;
    1075             : 
    1076           0 : fail:
    1077           0 :         install_info_free(i);
    1078           0 :         return r;
    1079             : }
    1080             : 
    1081          36 : static int config_parse_alias(
    1082             :                 const char *unit,
    1083             :                 const char *filename,
    1084             :                 unsigned line,
    1085             :                 const char *section,
    1086             :                 unsigned section_line,
    1087             :                 const char *lvalue,
    1088             :                 int ltype,
    1089             :                 const char *rvalue,
    1090             :                 void *data,
    1091             :                 void *userdata) {
    1092             : 
    1093             :         UnitType type;
    1094             : 
    1095          36 :         assert(unit);
    1096          36 :         assert(filename);
    1097          36 :         assert(lvalue);
    1098          36 :         assert(rvalue);
    1099             : 
    1100          36 :         type = unit_name_to_type(unit);
    1101          36 :         if (!unit_type_may_alias(type))
    1102           0 :                 return log_syntax(unit, LOG_WARNING, filename, line, 0,
    1103             :                                   "Alias= is not allowed for %s units, ignoring.",
    1104             :                                   unit_type_to_string(type));
    1105             : 
    1106          36 :         return config_parse_strv(unit, filename, line, section, section_line,
    1107             :                                  lvalue, ltype, rvalue, data, userdata);
    1108             : }
    1109             : 
    1110          46 : static int config_parse_also(
    1111             :                 const char *unit,
    1112             :                 const char *filename,
    1113             :                 unsigned line,
    1114             :                 const char *section,
    1115             :                 unsigned section_line,
    1116             :                 const char *lvalue,
    1117             :                 int ltype,
    1118             :                 const char *rvalue,
    1119             :                 void *data,
    1120             :                 void *userdata) {
    1121             : 
    1122          46 :         UnitFileInstallInfo *info = userdata, *alsoinfo = NULL;
    1123          46 :         InstallContext *c = data;
    1124             :         int r;
    1125             : 
    1126          46 :         assert(unit);
    1127          46 :         assert(filename);
    1128          46 :         assert(lvalue);
    1129          46 :         assert(rvalue);
    1130             : 
    1131          50 :         for (;;) {
    1132         142 :                 _cleanup_free_ char *word = NULL, *printed = NULL;
    1133             : 
    1134          96 :                 r = extract_first_word(&rvalue, &word, NULL, 0);
    1135          96 :                 if (r < 0)
    1136           0 :                         return r;
    1137          96 :                 if (r == 0)
    1138          46 :                         break;
    1139             : 
    1140          50 :                 r = install_full_printf(info, word, &printed);
    1141          50 :                 if (r < 0)
    1142           0 :                         return r;
    1143             : 
    1144          50 :                 if (!unit_name_is_valid(printed, UNIT_NAME_ANY))
    1145           0 :                         return -EINVAL;
    1146             : 
    1147          50 :                 r = install_info_add(c, printed, NULL, true, &alsoinfo);
    1148          50 :                 if (r < 0)
    1149           0 :                         return r;
    1150             : 
    1151          50 :                 r = strv_push(&info->also, printed);
    1152          50 :                 if (r < 0)
    1153           0 :                         return r;
    1154             : 
    1155          50 :                 printed = NULL;
    1156             :         }
    1157             : 
    1158          46 :         return 0;
    1159             : }
    1160             : 
    1161          74 : static int config_parse_default_instance(
    1162             :                 const char *unit,
    1163             :                 const char *filename,
    1164             :                 unsigned line,
    1165             :                 const char *section,
    1166             :                 unsigned section_line,
    1167             :                 const char *lvalue,
    1168             :                 int ltype,
    1169             :                 const char *rvalue,
    1170             :                 void *data,
    1171             :                 void *userdata) {
    1172             : 
    1173          74 :         UnitFileInstallInfo *i = data;
    1174          74 :         _cleanup_free_ char *printed = NULL;
    1175             :         int r;
    1176             : 
    1177          74 :         assert(unit);
    1178          74 :         assert(filename);
    1179          74 :         assert(lvalue);
    1180          74 :         assert(rvalue);
    1181             : 
    1182          74 :         if (unit_name_is_valid(unit, UNIT_NAME_INSTANCE))
    1183             :                 /* When enabling an instance, we might be using a template unit file,
    1184             :                  * but we should ignore DefaultInstance silently. */
    1185          50 :                 return 0;
    1186          24 :         if (!unit_name_is_valid(unit, UNIT_NAME_TEMPLATE))
    1187           0 :                 return log_syntax(unit, LOG_WARNING, filename, line, 0,
    1188             :                                   "DefaultInstance= only makes sense for template units, ignoring.");
    1189             : 
    1190          24 :         r = install_full_printf(i, rvalue, &printed);
    1191          24 :         if (r < 0)
    1192           0 :                 return r;
    1193             : 
    1194          24 :         if (!unit_instance_is_valid(printed))
    1195           0 :                 return -EINVAL;
    1196             : 
    1197          24 :         return free_and_replace(i->default_instance, printed);
    1198             : }
    1199             : 
    1200       11294 : static int unit_file_load(
    1201             :                 InstallContext *c,
    1202             :                 UnitFileInstallInfo *info,
    1203             :                 const char *path,
    1204             :                 const char *root_dir,
    1205             :                 SearchFlags flags) {
    1206             : 
    1207       45176 :         const ConfigTableItem items[] = {
    1208       11294 :                 { "Install", "Alias",           config_parse_alias,            0, &info->aliases           },
    1209       11294 :                 { "Install", "WantedBy",        config_parse_strv,             0, &info->wanted_by         },
    1210       11294 :                 { "Install", "RequiredBy",      config_parse_strv,             0, &info->required_by       },
    1211             :                 { "Install", "DefaultInstance", config_parse_default_instance, 0, info                     },
    1212             :                 { "Install", "Also",            config_parse_also,             0, c                        },
    1213             :                 {}
    1214             :         };
    1215             : 
    1216             :         UnitType type;
    1217       11294 :         _cleanup_fclose_ FILE *f = NULL;
    1218       11294 :         _cleanup_close_ int fd = -1;
    1219             :         struct stat st;
    1220             :         int r;
    1221             : 
    1222       11294 :         assert(info);
    1223       11294 :         assert(path);
    1224             : 
    1225       11294 :         if (!(flags & SEARCH_DROPIN)) {
    1226             :                 /* Loading or checking for the main unit file… */
    1227             : 
    1228       11263 :                 type = unit_name_to_type(info->name);
    1229       11263 :                 if (type < 0)
    1230           0 :                         return -EINVAL;
    1231       11263 :                 if (unit_name_is_valid(info->name, UNIT_NAME_TEMPLATE|UNIT_NAME_INSTANCE) && !unit_type_may_template(type))
    1232           0 :                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
    1233             :                                                "Unit type %s cannot be templated.", unit_type_to_string(type));
    1234             : 
    1235       11263 :                 if (!(flags & SEARCH_LOAD)) {
    1236        1156 :                         r = lstat(path, &st);
    1237        1156 :                         if (r < 0)
    1238        1050 :                                 return -errno;
    1239             : 
    1240         106 :                         if (null_or_empty(&st))
    1241           0 :                                 info->type = UNIT_FILE_TYPE_MASKED;
    1242         106 :                         else if (S_ISREG(st.st_mode))
    1243          77 :                                 info->type = UNIT_FILE_TYPE_REGULAR;
    1244          29 :                         else if (S_ISLNK(st.st_mode))
    1245          29 :                                 return -ELOOP;
    1246           0 :                         else if (S_ISDIR(st.st_mode))
    1247           0 :                                 return -EISDIR;
    1248             :                         else
    1249           0 :                                 return -ENOTTY;
    1250             : 
    1251          77 :                         return 0;
    1252             :                 }
    1253             : 
    1254       10107 :                 fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
    1255       10107 :                 if (fd < 0)
    1256        9399 :                         return -errno;
    1257             :         } else {
    1258             :                 /* Operating on a drop-in file. If we aren't supposed to load the unit file drop-ins don't matter, let's hence shortcut this. */
    1259             : 
    1260          31 :                 if (!(flags & SEARCH_LOAD))
    1261           1 :                         return 0;
    1262             : 
    1263          30 :                 fd = chase_symlinks_and_open(path, root_dir, 0, O_RDONLY|O_CLOEXEC|O_NOCTTY, NULL);
    1264          30 :                 if (fd < 0)
    1265           0 :                         return fd;
    1266             :         }
    1267             : 
    1268         738 :         if (fstat(fd, &st) < 0)
    1269           0 :                 return -errno;
    1270             : 
    1271         738 :         if (null_or_empty(&st)) {
    1272           0 :                 if ((flags & SEARCH_DROPIN) == 0)
    1273           0 :                         info->type = UNIT_FILE_TYPE_MASKED;
    1274             : 
    1275           0 :                 return 0;
    1276             :         }
    1277             : 
    1278         738 :         r = stat_verify_regular(&st);
    1279         738 :         if (r < 0)
    1280           0 :                 return r;
    1281             : 
    1282         738 :         f = fdopen(fd, "r");
    1283         738 :         if (!f)
    1284           0 :                 return -errno;
    1285         738 :         fd = -1;
    1286             : 
    1287             :         /* c is only needed if we actually load the file (it's referenced from items[] btw, in case you wonder.) */
    1288         738 :         assert(c);
    1289             : 
    1290         738 :         r = config_parse(info->name, path, f,
    1291             :                          NULL,
    1292             :                          config_item_table_lookup, items,
    1293             :                          CONFIG_PARSE_RELAXED|CONFIG_PARSE_ALLOW_INCLUDE, info);
    1294         738 :         if (r < 0)
    1295           0 :                 return log_debug_errno(r, "Failed to parse %s: %m", info->name);
    1296             : 
    1297         738 :         if ((flags & SEARCH_DROPIN) == 0)
    1298         708 :                 info->type = UNIT_FILE_TYPE_REGULAR;
    1299             : 
    1300             :         return
    1301        1476 :                 (int) strv_length(info->aliases) +
    1302        1476 :                 (int) strv_length(info->wanted_by) +
    1303         738 :                 (int) strv_length(info->required_by);
    1304             : }
    1305             : 
    1306       11294 : static int unit_file_load_or_readlink(
    1307             :                 InstallContext *c,
    1308             :                 UnitFileInstallInfo *info,
    1309             :                 const char *path,
    1310             :                 const char *root_dir,
    1311             :                 SearchFlags flags) {
    1312             : 
    1313       11294 :         _cleanup_free_ char *target = NULL;
    1314             :         int r;
    1315             : 
    1316       11294 :         r = unit_file_load(c, info, path, root_dir, flags);
    1317       11294 :         if (r != -ELOOP || (flags & SEARCH_DROPIN))
    1318       11133 :                 return r;
    1319             : 
    1320             :         /* This is a symlink, let's read it. */
    1321             : 
    1322         161 :         r = readlink_malloc(path, &target);
    1323         161 :         if (r < 0)
    1324           0 :                 return r;
    1325             : 
    1326         161 :         if (path_equal(target, "/dev/null"))
    1327           6 :                 info->type = UNIT_FILE_TYPE_MASKED;
    1328             :         else {
    1329             :                 const char *bn;
    1330             :                 UnitType a, b;
    1331             : 
    1332         155 :                 bn = basename(target);
    1333             : 
    1334         155 :                 if (unit_name_is_valid(info->name, UNIT_NAME_PLAIN)) {
    1335             : 
    1336         128 :                         if (!unit_name_is_valid(bn, UNIT_NAME_PLAIN))
    1337           0 :                                 return -EINVAL;
    1338             : 
    1339          27 :                 } else if (unit_name_is_valid(info->name, UNIT_NAME_INSTANCE)) {
    1340             : 
    1341          17 :                         if (!unit_name_is_valid(bn, UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE))
    1342           0 :                                 return -EINVAL;
    1343             : 
    1344          10 :                 } else if (unit_name_is_valid(info->name, UNIT_NAME_TEMPLATE)) {
    1345             : 
    1346          10 :                         if (!unit_name_is_valid(bn, UNIT_NAME_TEMPLATE))
    1347           0 :                                 return -EINVAL;
    1348             :                 } else
    1349           0 :                         return -EINVAL;
    1350             : 
    1351             :                 /* Enforce that the symlink destination does not
    1352             :                  * change the unit file type. */
    1353             : 
    1354         155 :                 a = unit_name_to_type(info->name);
    1355         155 :                 b = unit_name_to_type(bn);
    1356         155 :                 if (a < 0 || b < 0 || a != b)
    1357           0 :                         return -EINVAL;
    1358             : 
    1359         155 :                 if (path_is_absolute(target))
    1360             :                         /* This is an absolute path, prefix the root so that we always deal with fully qualified paths */
    1361          52 :                         info->symlink_target = path_join(root_dir, target);
    1362             :                 else
    1363             :                         /* This is a relative path, take it relative to the dir the symlink is located in. */
    1364         103 :                         info->symlink_target = file_in_same_dir(path, target);
    1365         155 :                 if (!info->symlink_target)
    1366           0 :                         return -ENOMEM;
    1367             : 
    1368         155 :                 info->type = UNIT_FILE_TYPE_SYMLINK;
    1369             :         }
    1370             : 
    1371         161 :         return 0;
    1372             : }
    1373             : 
    1374        1050 : static int unit_file_search(
    1375             :                 InstallContext *c,
    1376             :                 UnitFileInstallInfo *info,
    1377             :                 const LookupPaths *paths,
    1378             :                 SearchFlags flags) {
    1379             : 
    1380        1050 :         const char *dropin_dir_name = NULL, *dropin_template_dir_name = NULL;
    1381        1050 :         _cleanup_strv_free_ char **dirs = NULL, **files = NULL;
    1382        1050 :         _cleanup_free_ char *template = NULL;
    1383        1050 :         bool found_unit = false;
    1384             :         int r, result;
    1385             :         char **p;
    1386             : 
    1387        1050 :         assert(info);
    1388        1050 :         assert(paths);
    1389             : 
    1390             :         /* Was this unit already loaded? */
    1391        1050 :         if (info->type != _UNIT_FILE_TYPE_INVALID)
    1392          69 :                 return 0;
    1393             : 
    1394         981 :         if (info->path)
    1395           1 :                 return unit_file_load_or_readlink(c, info, info->path, paths->root_dir, flags);
    1396             : 
    1397         980 :         assert(info->name);
    1398             : 
    1399         980 :         if (unit_name_is_valid(info->name, UNIT_NAME_INSTANCE)) {
    1400          80 :                 r = unit_name_template(info->name, &template);
    1401          80 :                 if (r < 0)
    1402           0 :                         return r;
    1403             :         }
    1404             : 
    1405       10509 :         STRV_FOREACH(p, paths->search_path) {
    1406       10375 :                 _cleanup_free_ char *path = NULL;
    1407             : 
    1408       10375 :                 path = path_join(*p, info->name);
    1409       10375 :                 if (!path)
    1410           0 :                         return -ENOMEM;
    1411             : 
    1412       10375 :                 r = unit_file_load_or_readlink(c, info, path, paths->root_dir, flags);
    1413       10375 :                 if (r >= 0) {
    1414         846 :                         info->path = TAKE_PTR(path);
    1415         846 :                         result = r;
    1416         846 :                         found_unit = true;
    1417         846 :                         break;
    1418        9529 :                 } else if (!IN_SET(r, -ENOENT, -ENOTDIR, -EACCES))
    1419           0 :                         return r;
    1420             :         }
    1421             : 
    1422         980 :         if (!found_unit && template) {
    1423             : 
    1424             :                 /* Unit file doesn't exist, however instance
    1425             :                  * enablement was requested.  We will check if it is
    1426             :                  * possible to load template unit file. */
    1427             : 
    1428         866 :                 STRV_FOREACH(p, paths->search_path) {
    1429         862 :                         _cleanup_free_ char *path = NULL;
    1430             : 
    1431         862 :                         path = path_join(*p, template);
    1432         862 :                         if (!path)
    1433           0 :                                 return -ENOMEM;
    1434             : 
    1435         862 :                         r = unit_file_load_or_readlink(c, info, path, paths->root_dir, flags);
    1436         862 :                         if (r >= 0) {
    1437          74 :                                 info->path = TAKE_PTR(path);
    1438          74 :                                 result = r;
    1439          74 :                                 found_unit = true;
    1440          74 :                                 break;
    1441         788 :                         } else if (!IN_SET(r, -ENOENT, -ENOTDIR, -EACCES))
    1442           0 :                                 return r;
    1443             :                 }
    1444             :         }
    1445             : 
    1446         980 :         if (!found_unit)
    1447          60 :                 return log_debug_errno(SYNTHETIC_ERRNO(ENOENT),
    1448             :                                        "Cannot find unit %s%s%s.",
    1449             :                                        info->name, template ? " or " : "", strempty(template));
    1450             : 
    1451         920 :         if (info->type == UNIT_FILE_TYPE_MASKED)
    1452           6 :                 return result;
    1453             : 
    1454             :         /* Search for drop-in directories */
    1455             : 
    1456        4570 :         dropin_dir_name = strjoina(info->name, ".d");
    1457       11871 :         STRV_FOREACH(p, paths->search_path) {
    1458             :                 char *path;
    1459             : 
    1460       10957 :                 path = path_join(*p, dropin_dir_name);
    1461       10957 :                 if (!path)
    1462           0 :                         return -ENOMEM;
    1463             : 
    1464       10957 :                 r = strv_consume(&dirs, path);
    1465       10957 :                 if (r < 0)
    1466           0 :                         return r;
    1467             :         }
    1468             : 
    1469         914 :         if (template) {
    1470         380 :                 dropin_template_dir_name = strjoina(template, ".d");
    1471         988 :                 STRV_FOREACH(p, paths->search_path) {
    1472             :                         char *path;
    1473             : 
    1474         912 :                         path = path_join(*p, dropin_template_dir_name);
    1475         912 :                         if (!path)
    1476           0 :                                 return -ENOMEM;
    1477             : 
    1478         912 :                         r = strv_consume(&dirs, path);
    1479         912 :                         if (r < 0)
    1480           0 :                                 return r;
    1481             :                 }
    1482             :         }
    1483             : 
    1484             :         /* Load drop-in conf files */
    1485             : 
    1486         914 :         r = conf_files_list_strv(&files, ".conf", NULL, 0, (const char**) dirs);
    1487         914 :         if (r < 0)
    1488           0 :                 return log_debug_errno(r, "Failed to get list of conf files: %m");
    1489             : 
    1490         945 :         STRV_FOREACH(p, files) {
    1491          31 :                 r = unit_file_load_or_readlink(c, info, *p, paths->root_dir, flags | SEARCH_DROPIN);
    1492          31 :                 if (r < 0)
    1493           0 :                         return log_debug_errno(r, "Failed to load conf file %s: %m", *p);
    1494             :         }
    1495             : 
    1496         914 :         return result;
    1497             : }
    1498             : 
    1499         164 : static int install_info_follow(
    1500             :                 InstallContext *c,
    1501             :                 UnitFileInstallInfo *i,
    1502             :                 const char *root_dir,
    1503             :                 SearchFlags flags,
    1504             :                 bool ignore_different_name) {
    1505             : 
    1506         164 :         assert(c);
    1507         164 :         assert(i);
    1508             : 
    1509         164 :         if (i->type != UNIT_FILE_TYPE_SYMLINK)
    1510           0 :                 return -EINVAL;
    1511         164 :         if (!i->symlink_target)
    1512           0 :                 return -EINVAL;
    1513             : 
    1514             :         /* If the basename doesn't match, the caller should add a
    1515             :          * complete new entry for this. */
    1516             : 
    1517         164 :         if (!ignore_different_name && !streq(basename(i->symlink_target), i->name))
    1518         139 :                 return -EXDEV;
    1519             : 
    1520          25 :         free_and_replace(i->path, i->symlink_target);
    1521          25 :         i->type = _UNIT_FILE_TYPE_INVALID;
    1522             : 
    1523          25 :         return unit_file_load_or_readlink(c, i, i->path, root_dir, flags);
    1524             : }
    1525             : 
    1526             : /**
    1527             :  * Search for the unit file. If the unit name is a symlink, follow the symlink to the
    1528             :  * target, maybe more than once. Propagate the instance name if present.
    1529             :  */
    1530         910 : static int install_info_traverse(
    1531             :                 UnitFileScope scope,
    1532             :                 InstallContext *c,
    1533             :                 const LookupPaths *paths,
    1534             :                 UnitFileInstallInfo *start,
    1535             :                 SearchFlags flags,
    1536             :                 UnitFileInstallInfo **ret) {
    1537             : 
    1538             :         UnitFileInstallInfo *i;
    1539         910 :         unsigned k = 0;
    1540             :         int r;
    1541             : 
    1542         910 :         assert(paths);
    1543         910 :         assert(start);
    1544         910 :         assert(c);
    1545             : 
    1546         910 :         r = unit_file_search(c, start, paths, flags);
    1547         910 :         if (r < 0)
    1548          60 :                 return r;
    1549             : 
    1550         850 :         i = start;
    1551        1013 :         while (i->type == UNIT_FILE_TYPE_SYMLINK) {
    1552             :                 /* Follow the symlink */
    1553             : 
    1554         163 :                 if (++k > UNIT_FILE_FOLLOW_SYMLINK_MAX)
    1555           0 :                         return -ELOOP;
    1556             : 
    1557         163 :                 if (!(flags & SEARCH_FOLLOW_CONFIG_SYMLINKS)) {
    1558           7 :                         r = path_is_config(paths, i->path, true);
    1559           7 :                         if (r < 0)
    1560           0 :                                 return r;
    1561           7 :                         if (r > 0)
    1562           0 :                                 return -ELOOP;
    1563             :                 }
    1564             : 
    1565         163 :                 r = install_info_follow(c, i, paths->root_dir, flags, false);
    1566         163 :                 if (r == -EXDEV) {
    1567         139 :                         _cleanup_free_ char *buffer = NULL;
    1568             :                         const char *bn;
    1569             : 
    1570             :                         /* Target has a different name, create a new
    1571             :                          * install info object for that, and continue
    1572             :                          * with that. */
    1573             : 
    1574         139 :                         bn = basename(i->symlink_target);
    1575             : 
    1576         139 :                         if (unit_name_is_valid(i->name, UNIT_NAME_INSTANCE) &&
    1577          18 :                             unit_name_is_valid(bn, UNIT_NAME_TEMPLATE)) {
    1578             : 
    1579          18 :                                 _cleanup_free_ char *instance = NULL;
    1580             : 
    1581          18 :                                 r = unit_name_to_instance(i->name, &instance);
    1582          18 :                                 if (r < 0)
    1583           0 :                                         return r;
    1584             : 
    1585          18 :                                 r = unit_name_replace_instance(bn, instance, &buffer);
    1586          18 :                                 if (r < 0)
    1587           0 :                                         return r;
    1588             : 
    1589          18 :                                 if (streq(buffer, i->name)) {
    1590             : 
    1591             :                                         /* We filled in the instance, and the target stayed the same? If so, then let's
    1592             :                                          * honour the link as it is. */
    1593             : 
    1594           1 :                                         r = install_info_follow(c, i, paths->root_dir, flags, true);
    1595           1 :                                         if (r < 0)
    1596           0 :                                                 return r;
    1597             : 
    1598           1 :                                         continue;
    1599             :                                 }
    1600             : 
    1601          17 :                                 bn = buffer;
    1602             :                         }
    1603             : 
    1604         138 :                         r = install_info_add(c, bn, NULL, false, &i);
    1605         138 :                         if (r < 0)
    1606           0 :                                 return r;
    1607             : 
    1608             :                         /* Try again, with the new target we found. */
    1609         138 :                         r = unit_file_search(c, i, paths, flags);
    1610         138 :                         if (r == -ENOENT)
    1611             :                                 /* Translate error code to highlight this specific case */
    1612           0 :                                 return -ENOLINK;
    1613             :                 }
    1614             : 
    1615         162 :                 if (r < 0)
    1616           0 :                         return r;
    1617             :         }
    1618             : 
    1619         850 :         if (ret)
    1620         775 :                 *ret = i;
    1621             : 
    1622         850 :         return 0;
    1623             : }
    1624             : 
    1625             : /**
    1626             :  * Call install_info_add() with name_or_path as the path (if name_or_path starts with "/")
    1627             :  * or the name (otherwise). root_dir is prepended to the path.
    1628             :  */
    1629         836 : static int install_info_add_auto(
    1630             :                 InstallContext *c,
    1631             :                 const LookupPaths *paths,
    1632             :                 const char *name_or_path,
    1633             :                 UnitFileInstallInfo **ret) {
    1634             : 
    1635         836 :         assert(c);
    1636         836 :         assert(name_or_path);
    1637             : 
    1638         836 :         if (path_is_absolute(name_or_path)) {
    1639             :                 const char *pp;
    1640             : 
    1641           1 :                 pp = prefix_roota(paths->root_dir, name_or_path);
    1642             : 
    1643           1 :                 return install_info_add(c, NULL, pp, false, ret);
    1644             :         } else
    1645         835 :                 return install_info_add(c, name_or_path, NULL, false, ret);
    1646             : }
    1647             : 
    1648         836 : static int install_info_discover(
    1649             :                 UnitFileScope scope,
    1650             :                 InstallContext *c,
    1651             :                 const LookupPaths *paths,
    1652             :                 const char *name,
    1653             :                 SearchFlags flags,
    1654             :                 UnitFileInstallInfo **ret,
    1655             :                 UnitFileChange **changes,
    1656             :                 size_t *n_changes) {
    1657             : 
    1658             :         UnitFileInstallInfo *i;
    1659             :         int r;
    1660             : 
    1661         836 :         assert(c);
    1662         836 :         assert(paths);
    1663         836 :         assert(name);
    1664             : 
    1665         836 :         r = install_info_add_auto(c, paths, name, &i);
    1666         836 :         if (r >= 0)
    1667         836 :                 r = install_info_traverse(scope, c, paths, i, flags, ret);
    1668             : 
    1669         836 :         if (r < 0)
    1670          60 :                 unit_file_changes_add(changes, n_changes, r, name, NULL);
    1671         836 :         return r;
    1672             : }
    1673             : 
    1674          31 : static int install_info_discover_and_check(
    1675             :                         UnitFileScope scope,
    1676             :                         InstallContext *c,
    1677             :                         const LookupPaths *paths,
    1678             :                         const char *name,
    1679             :                         SearchFlags flags,
    1680             :                         UnitFileInstallInfo **ret,
    1681             :                         UnitFileChange **changes,
    1682             :                         size_t *n_changes) {
    1683             : 
    1684             :         int r;
    1685             : 
    1686          31 :         r = install_info_discover(scope, c, paths, name, flags, ret, changes, n_changes);
    1687          31 :         if (r < 0)
    1688           1 :                 return r;
    1689             : 
    1690          30 :         return install_info_may_process(ret ? *ret : NULL, paths, changes, n_changes);
    1691             : }
    1692             : 
    1693          30 : static int install_info_symlink_alias(
    1694             :                 UnitFileInstallInfo *i,
    1695             :                 const LookupPaths *paths,
    1696             :                 const char *config_path,
    1697             :                 bool force,
    1698             :                 UnitFileChange **changes,
    1699             :                 size_t *n_changes) {
    1700             : 
    1701             :         char **s;
    1702          30 :         int r = 0, q;
    1703             : 
    1704          30 :         assert(i);
    1705          30 :         assert(paths);
    1706          30 :         assert(config_path);
    1707             : 
    1708          30 :         STRV_FOREACH(s, i->aliases) {
    1709           0 :                 _cleanup_free_ char *alias_path = NULL, *dst = NULL;
    1710             : 
    1711           0 :                 q = install_full_printf(i, *s, &dst);
    1712           0 :                 if (q < 0)
    1713           0 :                         return q;
    1714             : 
    1715           0 :                 alias_path = path_make_absolute(dst, config_path);
    1716           0 :                 if (!alias_path)
    1717           0 :                         return -ENOMEM;
    1718             : 
    1719           0 :                 q = create_symlink(paths, i->path, alias_path, force, changes, n_changes);
    1720           0 :                 if (r == 0)
    1721           0 :                         r = q;
    1722             :         }
    1723             : 
    1724          30 :         return r;
    1725             : }
    1726             : 
    1727          60 : static int install_info_symlink_wants(
    1728             :                 UnitFileInstallInfo *i,
    1729             :                 const LookupPaths *paths,
    1730             :                 const char *config_path,
    1731             :                 char **list,
    1732             :                 const char *suffix,
    1733             :                 UnitFileChange **changes,
    1734             :                 size_t *n_changes) {
    1735             : 
    1736          60 :         _cleanup_free_ char *buf = NULL;
    1737             :         const char *n;
    1738             :         char **s;
    1739          60 :         int r = 0, q;
    1740             : 
    1741          60 :         assert(i);
    1742          60 :         assert(paths);
    1743          60 :         assert(config_path);
    1744             : 
    1745          60 :         if (strv_isempty(list))
    1746          32 :                 return 0;
    1747             : 
    1748          28 :         if (unit_name_is_valid(i->name, UNIT_NAME_TEMPLATE)) {
    1749           2 :                 UnitFileInstallInfo instance = {
    1750             :                         .type = _UNIT_FILE_TYPE_INVALID,
    1751             :                 };
    1752           2 :                 _cleanup_free_ char *path = NULL;
    1753             : 
    1754             :                 /* If this is a template, and we have no instance, don't do anything */
    1755           2 :                 if (!i->default_instance)
    1756           0 :                         return 1;
    1757             : 
    1758           2 :                 r = unit_name_replace_instance(i->name, i->default_instance, &buf);
    1759           2 :                 if (r < 0)
    1760           0 :                         return r;
    1761             : 
    1762           2 :                 instance.name = buf;
    1763           2 :                 r = unit_file_search(NULL, &instance, paths, SEARCH_FOLLOW_CONFIG_SYMLINKS);
    1764           2 :                 if (r < 0)
    1765           0 :                         return r;
    1766             : 
    1767           2 :                 path = TAKE_PTR(instance.path);
    1768             : 
    1769           2 :                 if (instance.type == UNIT_FILE_TYPE_MASKED) {
    1770           0 :                         unit_file_changes_add(changes, n_changes, -ERFKILL, path, NULL);
    1771           0 :                         return -ERFKILL;
    1772             :                 }
    1773             : 
    1774           2 :                 n = buf;
    1775             :         } else
    1776          26 :                 n = i->name;
    1777             : 
    1778          61 :         STRV_FOREACH(s, list) {
    1779          33 :                 _cleanup_free_ char *path = NULL, *dst = NULL;
    1780             : 
    1781          33 :                 q = install_full_printf(i, *s, &dst);
    1782          33 :                 if (q < 0)
    1783           0 :                         return q;
    1784             : 
    1785          33 :                 if (!unit_name_is_valid(dst, UNIT_NAME_ANY)) {
    1786           0 :                         r = -EINVAL;
    1787           0 :                         continue;
    1788             :                 }
    1789             : 
    1790          33 :                 path = strjoin(config_path, "/", dst, suffix, n);
    1791          33 :                 if (!path)
    1792           0 :                         return -ENOMEM;
    1793             : 
    1794          33 :                 q = create_symlink(paths, i->path, path, true, changes, n_changes);
    1795          33 :                 if (r == 0)
    1796          28 :                         r = q;
    1797             :         }
    1798             : 
    1799          28 :         return r;
    1800             : }
    1801             : 
    1802          30 : static int install_info_symlink_link(
    1803             :                 UnitFileInstallInfo *i,
    1804             :                 const LookupPaths *paths,
    1805             :                 const char *config_path,
    1806             :                 bool force,
    1807             :                 UnitFileChange **changes,
    1808             :                 size_t *n_changes) {
    1809             : 
    1810          30 :         _cleanup_free_ char *path = NULL;
    1811             :         int r;
    1812             : 
    1813          30 :         assert(i);
    1814          30 :         assert(paths);
    1815          30 :         assert(config_path);
    1816          30 :         assert(i->path);
    1817             : 
    1818          30 :         r = in_search_path(paths, i->path);
    1819          30 :         if (r < 0)
    1820           0 :                 return r;
    1821          30 :         if (r > 0)
    1822          27 :                 return 0;
    1823             : 
    1824           3 :         path = path_join(config_path, i->name);
    1825           3 :         if (!path)
    1826           0 :                 return -ENOMEM;
    1827             : 
    1828           3 :         return create_symlink(paths, i->path, path, force, changes, n_changes);
    1829             : }
    1830             : 
    1831          30 : static int install_info_apply(
    1832             :                 UnitFileInstallInfo *i,
    1833             :                 const LookupPaths *paths,
    1834             :                 const char *config_path,
    1835             :                 bool force,
    1836             :                 UnitFileChange **changes,
    1837             :                 size_t *n_changes) {
    1838             : 
    1839             :         int r, q;
    1840             : 
    1841          30 :         assert(i);
    1842          30 :         assert(paths);
    1843          30 :         assert(config_path);
    1844             : 
    1845          30 :         if (i->type != UNIT_FILE_TYPE_REGULAR)
    1846           0 :                 return 0;
    1847             : 
    1848          30 :         r = install_info_symlink_alias(i, paths, config_path, force, changes, n_changes);
    1849             : 
    1850          30 :         q = install_info_symlink_wants(i, paths, config_path, i->wanted_by, ".wants/", changes, n_changes);
    1851          30 :         if (r == 0)
    1852          30 :                 r = q;
    1853             : 
    1854          30 :         q = install_info_symlink_wants(i, paths, config_path, i->required_by, ".requires/", changes, n_changes);
    1855          30 :         if (r == 0)
    1856           2 :                 r = q;
    1857             : 
    1858          30 :         q = install_info_symlink_link(i, paths, config_path, force, changes, n_changes);
    1859             :         /* Do not count links to the unit file towards the "carries_install_info" count */
    1860          30 :         if (r == 0 && q < 0)
    1861           0 :                 r = q;
    1862             : 
    1863          30 :         return r;
    1864             : }
    1865             : 
    1866          27 : static int install_context_apply(
    1867             :                 UnitFileScope scope,
    1868             :                 InstallContext *c,
    1869             :                 const LookupPaths *paths,
    1870             :                 const char *config_path,
    1871             :                 bool force,
    1872             :                 SearchFlags flags,
    1873             :                 UnitFileChange **changes,
    1874             :                 size_t *n_changes) {
    1875             : 
    1876             :         UnitFileInstallInfo *i;
    1877             :         int r;
    1878             : 
    1879          27 :         assert(c);
    1880          27 :         assert(paths);
    1881          27 :         assert(config_path);
    1882             : 
    1883          27 :         if (ordered_hashmap_isempty(c->will_process))
    1884           2 :                 return 0;
    1885             : 
    1886          25 :         r = ordered_hashmap_ensure_allocated(&c->have_processed, &string_hash_ops);
    1887          25 :         if (r < 0)
    1888           0 :                 return r;
    1889             : 
    1890          25 :         r = 0;
    1891          62 :         while ((i = ordered_hashmap_first(c->will_process))) {
    1892             :                 int q;
    1893             : 
    1894          37 :                 q = ordered_hashmap_move_one(c->have_processed, c->will_process, i->name);
    1895          37 :                 if (q < 0)
    1896           0 :                         return q;
    1897             : 
    1898          37 :                 q = install_info_traverse(scope, c, paths, i, flags, NULL);
    1899          37 :                 if (q < 0) {
    1900           0 :                         unit_file_changes_add(changes, n_changes, r, i->name, NULL);
    1901           0 :                         return q;
    1902             :                 }
    1903             : 
    1904             :                 /* We can attempt to process a masked unit when a different unit
    1905             :                  * that we were processing specifies it in Also=. */
    1906          37 :                 if (i->type == UNIT_FILE_TYPE_MASKED) {
    1907           0 :                         unit_file_changes_add(changes, n_changes, UNIT_FILE_IS_MASKED, i->path, NULL);
    1908           0 :                         if (r >= 0)
    1909             :                                 /* Assume that something *could* have been enabled here,
    1910             :                                  * avoid "empty [Install] section" warning. */
    1911           0 :                                 r += 1;
    1912           0 :                         continue;
    1913             :                 }
    1914             : 
    1915          37 :                 if (i->type != UNIT_FILE_TYPE_REGULAR)
    1916           7 :                         continue;
    1917             : 
    1918          30 :                 q = install_info_apply(i, paths, config_path, force, changes, n_changes);
    1919          30 :                 if (r >= 0) {
    1920          30 :                         if (q < 0)
    1921           0 :                                 r = q;
    1922             :                         else
    1923          30 :                                 r += q;
    1924             :                 }
    1925             :         }
    1926             : 
    1927          25 :         return r;
    1928             : }
    1929             : 
    1930          17 : static int install_context_mark_for_removal(
    1931             :                 UnitFileScope scope,
    1932             :                 InstallContext *c,
    1933             :                 const LookupPaths *paths,
    1934             :                 Set **remove_symlinks_to,
    1935             :                 const char *config_path,
    1936             :                 UnitFileChange **changes,
    1937             :                 size_t *n_changes) {
    1938             : 
    1939             :         UnitFileInstallInfo *i;
    1940             :         int r;
    1941             : 
    1942          17 :         assert(c);
    1943          17 :         assert(paths);
    1944          17 :         assert(config_path);
    1945             : 
    1946             :         /* Marks all items for removal */
    1947             : 
    1948          17 :         if (ordered_hashmap_isempty(c->will_process))
    1949           3 :                 return 0;
    1950             : 
    1951          14 :         r = ordered_hashmap_ensure_allocated(&c->have_processed, &string_hash_ops);
    1952          14 :         if (r < 0)
    1953           0 :                 return r;
    1954             : 
    1955          51 :         while ((i = ordered_hashmap_first(c->will_process))) {
    1956             : 
    1957          37 :                 r = ordered_hashmap_move_one(c->have_processed, c->will_process, i->name);
    1958          37 :                 if (r < 0)
    1959           0 :                         return r;
    1960             : 
    1961          37 :                 r = install_info_traverse(scope, c, paths, i, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, NULL);
    1962          37 :                 if (r == -ENOLINK) {
    1963           0 :                         log_debug_errno(r, "Name %s leads to a dangling symlink, removing name.", i->name);
    1964           0 :                         unit_file_changes_add(changes, n_changes, UNIT_FILE_IS_DANGLING, i->path ?: i->name, NULL);
    1965          37 :                 } else if (r == -ENOENT) {
    1966             : 
    1967           0 :                         if (i->auxiliary)  /* some unit specified in Also= or similar is missing */
    1968           0 :                                 log_debug_errno(r, "Auxiliary unit of %s not found, removing name.", i->name);
    1969             :                         else {
    1970           0 :                                 log_debug_errno(r, "Unit %s not found, removing name.", i->name);
    1971           0 :                                 unit_file_changes_add(changes, n_changes, r, i->path ?: i->name, NULL);
    1972             :                         }
    1973             : 
    1974          37 :                 } else if (r < 0) {
    1975           0 :                         log_debug_errno(r, "Failed to find unit %s, removing name: %m", i->name);
    1976           0 :                         unit_file_changes_add(changes, n_changes, r, i->path ?: i->name, NULL);
    1977          37 :                 } else if (i->type == UNIT_FILE_TYPE_MASKED) {
    1978           0 :                         log_debug("Unit file %s is masked, ignoring.", i->name);
    1979           0 :                         unit_file_changes_add(changes, n_changes, UNIT_FILE_IS_MASKED, i->path ?: i->name, NULL);
    1980           0 :                         continue;
    1981          37 :                 } else if (i->type != UNIT_FILE_TYPE_REGULAR) {
    1982           2 :                         log_debug("Unit %s has type %s, ignoring.", i->name, unit_file_type_to_string(i->type) ?: "invalid");
    1983           2 :                         continue;
    1984             :                 }
    1985             : 
    1986          35 :                 r = mark_symlink_for_removal(remove_symlinks_to, i->name);
    1987          35 :                 if (r < 0)
    1988           0 :                         return r;
    1989             :         }
    1990             : 
    1991          14 :         return 0;
    1992             : }
    1993             : 
    1994           1 : int unit_file_mask(
    1995             :                 UnitFileScope scope,
    1996             :                 UnitFileFlags flags,
    1997             :                 const char *root_dir,
    1998             :                 char **files,
    1999             :                 UnitFileChange **changes,
    2000             :                 size_t *n_changes) {
    2001             : 
    2002           1 :         _cleanup_(lookup_paths_free) LookupPaths paths = {};
    2003             :         const char *config_path;
    2004             :         char **i;
    2005             :         int r;
    2006             : 
    2007           1 :         assert(scope >= 0);
    2008           1 :         assert(scope < _UNIT_FILE_SCOPE_MAX);
    2009             : 
    2010           1 :         r = lookup_paths_init(&paths, scope, 0, root_dir);
    2011           1 :         if (r < 0)
    2012           0 :                 return r;
    2013             : 
    2014           1 :         config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
    2015           1 :         if (!config_path)
    2016           0 :                 return -ENXIO;
    2017             : 
    2018           2 :         STRV_FOREACH(i, files) {
    2019           1 :                 _cleanup_free_ char *path = NULL;
    2020             :                 int q;
    2021             : 
    2022           1 :                 if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) {
    2023           0 :                         if (r == 0)
    2024           0 :                                 r = -EINVAL;
    2025           0 :                         continue;
    2026             :                 }
    2027             : 
    2028           1 :                 path = path_make_absolute(*i, config_path);
    2029           1 :                 if (!path)
    2030           0 :                         return -ENOMEM;
    2031             : 
    2032           1 :                 q = create_symlink(&paths, "/dev/null", path, !!(flags & UNIT_FILE_FORCE), changes, n_changes);
    2033           1 :                 if (q < 0 && r >= 0)
    2034           0 :                         r = q;
    2035             :         }
    2036             : 
    2037           1 :         return r;
    2038             : }
    2039             : 
    2040           1 : int unit_file_unmask(
    2041             :                 UnitFileScope scope,
    2042             :                 UnitFileFlags flags,
    2043             :                 const char *root_dir,
    2044             :                 char **files,
    2045             :                 UnitFileChange **changes,
    2046             :                 size_t *n_changes) {
    2047             : 
    2048           1 :         _cleanup_(lookup_paths_free) LookupPaths paths = {};
    2049           1 :         _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
    2050           1 :         _cleanup_strv_free_ char **todo = NULL;
    2051           1 :         size_t n_todo = 0, n_allocated = 0;
    2052             :         const char *config_path;
    2053             :         char **i;
    2054             :         bool dry_run;
    2055             :         int r, q;
    2056             : 
    2057           1 :         assert(scope >= 0);
    2058           1 :         assert(scope < _UNIT_FILE_SCOPE_MAX);
    2059             : 
    2060           1 :         r = lookup_paths_init(&paths, scope, 0, root_dir);
    2061           1 :         if (r < 0)
    2062           0 :                 return r;
    2063             : 
    2064           1 :         config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
    2065           1 :         if (!config_path)
    2066           0 :                 return -ENXIO;
    2067             : 
    2068           1 :         dry_run = !!(flags & UNIT_FILE_DRY_RUN);
    2069             : 
    2070           2 :         STRV_FOREACH(i, files) {
    2071           1 :                 _cleanup_free_ char *path = NULL;
    2072             : 
    2073           1 :                 if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
    2074           0 :                         return -EINVAL;
    2075             : 
    2076           1 :                 path = path_make_absolute(*i, config_path);
    2077           1 :                 if (!path)
    2078           0 :                         return -ENOMEM;
    2079             : 
    2080           1 :                 r = null_or_empty_path(path);
    2081           1 :                 if (r == -ENOENT)
    2082           0 :                         continue;
    2083           1 :                 if (r < 0)
    2084           0 :                         return r;
    2085           1 :                 if (r == 0)
    2086           0 :                         continue;
    2087             : 
    2088           1 :                 if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
    2089           0 :                         return -ENOMEM;
    2090             : 
    2091           1 :                 todo[n_todo] = strdup(*i);
    2092           1 :                 if (!todo[n_todo])
    2093           0 :                         return -ENOMEM;
    2094             : 
    2095           1 :                 n_todo++;
    2096             :         }
    2097             : 
    2098           1 :         strv_uniq(todo);
    2099             : 
    2100           1 :         r = 0;
    2101           2 :         STRV_FOREACH(i, todo) {
    2102           1 :                 _cleanup_free_ char *path = NULL;
    2103             :                 const char *rp;
    2104             : 
    2105           1 :                 path = path_make_absolute(*i, config_path);
    2106           1 :                 if (!path)
    2107           0 :                         return -ENOMEM;
    2108             : 
    2109           1 :                 if (!dry_run && unlink(path) < 0) {
    2110           0 :                         if (errno != ENOENT) {
    2111           0 :                                 if (r >= 0)
    2112           0 :                                         r = -errno;
    2113           0 :                                 unit_file_changes_add(changes, n_changes, -errno, path, NULL);
    2114             :                         }
    2115             : 
    2116           0 :                         continue;
    2117             :                 }
    2118             : 
    2119           1 :                 unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
    2120             : 
    2121           1 :                 rp = skip_root(&paths, path);
    2122           1 :                 q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: path);
    2123           1 :                 if (q < 0)
    2124           0 :                         return q;
    2125             :         }
    2126             : 
    2127           1 :         q = remove_marked_symlinks(remove_symlinks_to, config_path, &paths, dry_run, changes, n_changes);
    2128           1 :         if (r >= 0)
    2129           1 :                 r = q;
    2130             : 
    2131           1 :         return r;
    2132             : }
    2133             : 
    2134           1 : int unit_file_link(
    2135             :                 UnitFileScope scope,
    2136             :                 UnitFileFlags flags,
    2137             :                 const char *root_dir,
    2138             :                 char **files,
    2139             :                 UnitFileChange **changes,
    2140             :                 size_t *n_changes) {
    2141             : 
    2142           1 :         _cleanup_(lookup_paths_free) LookupPaths paths = {};
    2143           1 :         _cleanup_strv_free_ char **todo = NULL;
    2144           1 :         size_t n_todo = 0, n_allocated = 0;
    2145             :         const char *config_path;
    2146             :         char **i;
    2147             :         int r, q;
    2148             : 
    2149           1 :         assert(scope >= 0);
    2150           1 :         assert(scope < _UNIT_FILE_SCOPE_MAX);
    2151             : 
    2152           1 :         r = lookup_paths_init(&paths, scope, 0, root_dir);
    2153           1 :         if (r < 0)
    2154           0 :                 return r;
    2155             : 
    2156           1 :         config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
    2157           1 :         if (!config_path)
    2158           0 :                 return -ENXIO;
    2159             : 
    2160           2 :         STRV_FOREACH(i, files) {
    2161           1 :                 _cleanup_free_ char *full = NULL;
    2162             :                 struct stat st;
    2163             :                 char *fn;
    2164             : 
    2165           1 :                 if (!path_is_absolute(*i))
    2166           0 :                         return -EINVAL;
    2167             : 
    2168           1 :                 fn = basename(*i);
    2169           1 :                 if (!unit_name_is_valid(fn, UNIT_NAME_ANY))
    2170           0 :                         return -EINVAL;
    2171             : 
    2172           1 :                 full = path_join(paths.root_dir, *i);
    2173           1 :                 if (!full)
    2174           0 :                         return -ENOMEM;
    2175             : 
    2176           1 :                 if (lstat(full, &st) < 0)
    2177           0 :                         return -errno;
    2178           1 :                 r = stat_verify_regular(&st);
    2179           1 :                 if (r < 0)
    2180           0 :                         return r;
    2181             : 
    2182           1 :                 q = in_search_path(&paths, *i);
    2183           1 :                 if (q < 0)
    2184           0 :                         return q;
    2185           1 :                 if (q > 0)
    2186           0 :                         continue;
    2187             : 
    2188           1 :                 if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
    2189           0 :                         return -ENOMEM;
    2190             : 
    2191           1 :                 todo[n_todo] = strdup(*i);
    2192           1 :                 if (!todo[n_todo])
    2193           0 :                         return -ENOMEM;
    2194             : 
    2195           1 :                 n_todo++;
    2196             :         }
    2197             : 
    2198           1 :         strv_uniq(todo);
    2199             : 
    2200           1 :         r = 0;
    2201           2 :         STRV_FOREACH(i, todo) {
    2202           1 :                 _cleanup_free_ char *new_path = NULL;
    2203             : 
    2204           1 :                 new_path = path_make_absolute(basename(*i), config_path);
    2205           1 :                 if (!new_path)
    2206           0 :                         return -ENOMEM;
    2207             : 
    2208           1 :                 q = create_symlink(&paths, *i, new_path, !!(flags & UNIT_FILE_FORCE), changes, n_changes);
    2209           1 :                 if (q < 0 && r >= 0)
    2210           0 :                         r = q;
    2211             :         }
    2212             : 
    2213           1 :         return r;
    2214             : }
    2215             : 
    2216           1 : static int path_shall_revert(const LookupPaths *paths, const char *path) {
    2217             :         int r;
    2218             : 
    2219           1 :         assert(paths);
    2220           1 :         assert(path);
    2221             : 
    2222             :         /* Checks whether the path is one where the drop-in directories shall be removed. */
    2223             : 
    2224           1 :         r = path_is_config(paths, path, true);
    2225           1 :         if (r != 0)
    2226           1 :                 return r;
    2227             : 
    2228           0 :         r = path_is_control(paths, path);
    2229           0 :         if (r != 0)
    2230           0 :                 return r;
    2231             : 
    2232           0 :         return path_is_transient(paths, path);
    2233             : }
    2234             : 
    2235           3 : int unit_file_revert(
    2236             :                 UnitFileScope scope,
    2237             :                 const char *root_dir,
    2238             :                 char **files,
    2239             :                 UnitFileChange **changes,
    2240             :                 size_t *n_changes) {
    2241             : 
    2242           3 :         _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
    2243           3 :         _cleanup_(lookup_paths_free) LookupPaths paths = {};
    2244           3 :         _cleanup_strv_free_ char **todo = NULL;
    2245           3 :         size_t n_todo = 0, n_allocated = 0;
    2246             :         char **i;
    2247             :         int r, q;
    2248             : 
    2249             :         /* Puts a unit file back into vendor state. This means:
    2250             :          *
    2251             :          * a) we remove all drop-in snippets added by the user ("config"), add to transient units ("transient"), and
    2252             :          *    added via "systemctl set-property" ("control"), but not if the drop-in is generated ("generated").
    2253             :          *
    2254             :          * c) if there's a vendor unit file (i.e. one in /usr) we remove any configured overriding unit files (i.e. in
    2255             :          *    "config", but not in "transient" or "control" or even "generated").
    2256             :          *
    2257             :          * We remove all that in both the runtime and the persistent directories, if that applies.
    2258             :          */
    2259             : 
    2260           3 :         r = lookup_paths_init(&paths, scope, 0, root_dir);
    2261           3 :         if (r < 0)
    2262           0 :                 return r;
    2263             : 
    2264           6 :         STRV_FOREACH(i, files) {
    2265           3 :                 bool has_vendor = false;
    2266             :                 char **p;
    2267             : 
    2268           3 :                 if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
    2269           0 :                         return -EINVAL;
    2270             : 
    2271          39 :                 STRV_FOREACH(p, paths.search_path) {
    2272          36 :                         _cleanup_free_ char *path = NULL, *dropin = NULL;
    2273             :                         struct stat st;
    2274             : 
    2275          36 :                         path = path_make_absolute(*i, *p);
    2276          36 :                         if (!path)
    2277           0 :                                 return -ENOMEM;
    2278             : 
    2279          36 :                         r = lstat(path, &st);
    2280          36 :                         if (r < 0) {
    2281          32 :                                 if (errno != ENOENT)
    2282           0 :                                         return -errno;
    2283           4 :                         } else if (S_ISREG(st.st_mode)) {
    2284             :                                 /* Check if there's a vendor version */
    2285           4 :                                 r = path_is_vendor(&paths, path);
    2286           4 :                                 if (r < 0)
    2287           0 :                                         return r;
    2288           4 :                                 if (r > 0)
    2289           3 :                                         has_vendor = true;
    2290             :                         }
    2291             : 
    2292          36 :                         dropin = strjoin(path, ".d");
    2293          36 :                         if (!dropin)
    2294           0 :                                 return -ENOMEM;
    2295             : 
    2296          36 :                         r = lstat(dropin, &st);
    2297          36 :                         if (r < 0) {
    2298          35 :                                 if (errno != ENOENT)
    2299           0 :                                         return -errno;
    2300           1 :                         } else if (S_ISDIR(st.st_mode)) {
    2301             :                                 /* Remove the drop-ins */
    2302           1 :                                 r = path_shall_revert(&paths, dropin);
    2303           1 :                                 if (r < 0)
    2304           0 :                                         return r;
    2305           1 :                                 if (r > 0) {
    2306           1 :                                         if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
    2307           0 :                                                 return -ENOMEM;
    2308             : 
    2309           1 :                                         todo[n_todo++] = TAKE_PTR(dropin);
    2310             :                                 }
    2311             :                         }
    2312             :                 }
    2313             : 
    2314           3 :                 if (!has_vendor)
    2315           0 :                         continue;
    2316             : 
    2317             :                 /* OK, there's a vendor version, hence drop all configuration versions */
    2318          39 :                 STRV_FOREACH(p, paths.search_path) {
    2319          36 :                         _cleanup_free_ char *path = NULL;
    2320             :                         struct stat st;
    2321             : 
    2322          36 :                         path = path_make_absolute(*i, *p);
    2323          36 :                         if (!path)
    2324           0 :                                 return -ENOMEM;
    2325             : 
    2326          36 :                         r = lstat(path, &st);
    2327          36 :                         if (r < 0) {
    2328          32 :                                 if (errno != ENOENT)
    2329           0 :                                         return -errno;
    2330           4 :                         } else if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
    2331           4 :                                 r = path_is_config(&paths, path, true);
    2332           4 :                                 if (r < 0)
    2333           0 :                                         return r;
    2334           4 :                                 if (r > 0) {
    2335           1 :                                         if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
    2336           0 :                                                 return -ENOMEM;
    2337             : 
    2338           1 :                                         todo[n_todo++] = TAKE_PTR(path);
    2339             :                                 }
    2340             :                         }
    2341             :                 }
    2342             :         }
    2343             : 
    2344           3 :         strv_uniq(todo);
    2345             : 
    2346           3 :         r = 0;
    2347           5 :         STRV_FOREACH(i, todo) {
    2348           2 :                 _cleanup_strv_free_ char **fs = NULL;
    2349             :                 const char *rp;
    2350             :                 char **j;
    2351             : 
    2352           2 :                 (void) get_files_in_directory(*i, &fs);
    2353             : 
    2354           2 :                 q = rm_rf(*i, REMOVE_ROOT|REMOVE_PHYSICAL);
    2355           2 :                 if (q < 0 && q != -ENOENT && r >= 0) {
    2356           0 :                         r = q;
    2357           0 :                         continue;
    2358             :                 }
    2359             : 
    2360           3 :                 STRV_FOREACH(j, fs) {
    2361           1 :                         _cleanup_free_ char *t = NULL;
    2362             : 
    2363           1 :                         t = path_join(*i, *j);
    2364           1 :                         if (!t)
    2365           0 :                                 return -ENOMEM;
    2366             : 
    2367           1 :                         unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, t, NULL);
    2368             :                 }
    2369             : 
    2370           2 :                 unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, *i, NULL);
    2371             : 
    2372           2 :                 rp = skip_root(&paths, *i);
    2373           2 :                 q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: *i);
    2374           2 :                 if (q < 0)
    2375           0 :                         return q;
    2376             :         }
    2377             : 
    2378           3 :         q = remove_marked_symlinks(remove_symlinks_to, paths.runtime_config, &paths, false, changes, n_changes);
    2379           3 :         if (r >= 0)
    2380           3 :                 r = q;
    2381             : 
    2382           3 :         q = remove_marked_symlinks(remove_symlinks_to, paths.persistent_config, &paths, false, changes, n_changes);
    2383           3 :         if (r >= 0)
    2384           3 :                 r = q;
    2385             : 
    2386           3 :         return r;
    2387             : }
    2388             : 
    2389           1 : int unit_file_add_dependency(
    2390             :                 UnitFileScope scope,
    2391             :                 UnitFileFlags flags,
    2392             :                 const char *root_dir,
    2393             :                 char **files,
    2394             :                 const char *target,
    2395             :                 UnitDependency dep,
    2396             :                 UnitFileChange **changes,
    2397             :                 size_t *n_changes) {
    2398             : 
    2399           1 :         _cleanup_(lookup_paths_free) LookupPaths paths = {};
    2400           1 :         _cleanup_(install_context_done) InstallContext c = {};
    2401             :         UnitFileInstallInfo *i, *target_info;
    2402             :         const char *config_path;
    2403             :         char **f;
    2404             :         int r;
    2405             : 
    2406           1 :         assert(scope >= 0);
    2407           1 :         assert(scope < _UNIT_FILE_SCOPE_MAX);
    2408           1 :         assert(target);
    2409             : 
    2410           1 :         if (!IN_SET(dep, UNIT_WANTS, UNIT_REQUIRES))
    2411           0 :                 return -EINVAL;
    2412             : 
    2413           1 :         if (!unit_name_is_valid(target, UNIT_NAME_ANY))
    2414           0 :                 return -EINVAL;
    2415             : 
    2416           1 :         r = lookup_paths_init(&paths, scope, 0, root_dir);
    2417           1 :         if (r < 0)
    2418           0 :                 return r;
    2419             : 
    2420           1 :         config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
    2421           1 :         if (!config_path)
    2422           0 :                 return -ENXIO;
    2423             : 
    2424           1 :         r = install_info_discover_and_check(scope, &c, &paths, target, SEARCH_FOLLOW_CONFIG_SYMLINKS,
    2425             :                                             &target_info, changes, n_changes);
    2426           1 :         if (r < 0)
    2427           0 :                 return r;
    2428             : 
    2429           1 :         assert(target_info->type == UNIT_FILE_TYPE_REGULAR);
    2430             : 
    2431           2 :         STRV_FOREACH(f, files) {
    2432             :                 char ***l;
    2433             : 
    2434           1 :                 r = install_info_discover_and_check(scope, &c, &paths, *f, SEARCH_FOLLOW_CONFIG_SYMLINKS,
    2435             :                                                     &i, changes, n_changes);
    2436           1 :                 if (r < 0)
    2437           0 :                         return r;
    2438             : 
    2439           1 :                 assert(i->type == UNIT_FILE_TYPE_REGULAR);
    2440             : 
    2441             :                 /* We didn't actually load anything from the unit
    2442             :                  * file, but instead just add in our new symlink to
    2443             :                  * create. */
    2444             : 
    2445           1 :                 if (dep == UNIT_WANTS)
    2446           1 :                         l = &i->wanted_by;
    2447             :                 else
    2448           0 :                         l = &i->required_by;
    2449             : 
    2450           1 :                 strv_free(*l);
    2451           1 :                 *l = strv_new(target_info->name);
    2452           1 :                 if (!*l)
    2453           0 :                         return -ENOMEM;
    2454             :         }
    2455             : 
    2456           1 :         return install_context_apply(scope, &c, &paths, config_path, !!(flags & UNIT_FILE_FORCE), SEARCH_FOLLOW_CONFIG_SYMLINKS, changes, n_changes);
    2457             : }
    2458             : 
    2459          20 : int unit_file_enable(
    2460             :                 UnitFileScope scope,
    2461             :                 UnitFileFlags flags,
    2462             :                 const char *root_dir,
    2463             :                 char **files,
    2464             :                 UnitFileChange **changes,
    2465             :                 size_t *n_changes) {
    2466             : 
    2467          20 :         _cleanup_(lookup_paths_free) LookupPaths paths = {};
    2468          20 :         _cleanup_(install_context_done) InstallContext c = {};
    2469             :         const char *config_path;
    2470             :         UnitFileInstallInfo *i;
    2471             :         char **f;
    2472             :         int r;
    2473             : 
    2474          20 :         assert(scope >= 0);
    2475          20 :         assert(scope < _UNIT_FILE_SCOPE_MAX);
    2476             : 
    2477          20 :         r = lookup_paths_init(&paths, scope, 0, root_dir);
    2478          20 :         if (r < 0)
    2479           0 :                 return r;
    2480             : 
    2481          20 :         config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
    2482          20 :         if (!config_path)
    2483           0 :                 return -ENXIO;
    2484             : 
    2485          39 :         STRV_FOREACH(f, files) {
    2486          20 :                 r = install_info_discover_and_check(scope, &c, &paths, *f, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS,
    2487             :                                                     &i, changes, n_changes);
    2488          20 :                 if (r < 0)
    2489           1 :                         return r;
    2490             : 
    2491          19 :                 assert(i->type == UNIT_FILE_TYPE_REGULAR);
    2492             :         }
    2493             : 
    2494             :         /* This will return the number of symlink rules that were
    2495             :            supposed to be created, not the ones actually created. This
    2496             :            is useful to determine whether the passed files had any
    2497             :            installation data at all. */
    2498             : 
    2499          19 :         return install_context_apply(scope, &c, &paths, config_path, !!(flags & UNIT_FILE_FORCE), SEARCH_LOAD, changes, n_changes);
    2500             : }
    2501             : 
    2502          10 : int unit_file_disable(
    2503             :                 UnitFileScope scope,
    2504             :                 UnitFileFlags flags,
    2505             :                 const char *root_dir,
    2506             :                 char **files,
    2507             :                 UnitFileChange **changes,
    2508             :                 size_t *n_changes) {
    2509             : 
    2510          10 :         _cleanup_(lookup_paths_free) LookupPaths paths = {};
    2511          10 :         _cleanup_(install_context_done) InstallContext c = {};
    2512          10 :         _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
    2513             :         const char *config_path;
    2514             :         char **i;
    2515             :         int r;
    2516             : 
    2517          10 :         assert(scope >= 0);
    2518          10 :         assert(scope < _UNIT_FILE_SCOPE_MAX);
    2519             : 
    2520          10 :         r = lookup_paths_init(&paths, scope, 0, root_dir);
    2521          10 :         if (r < 0)
    2522           0 :                 return r;
    2523             : 
    2524          10 :         config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
    2525          10 :         if (!config_path)
    2526           0 :                 return -ENXIO;
    2527             : 
    2528          20 :         STRV_FOREACH(i, files) {
    2529          10 :                 if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
    2530           0 :                         return -EINVAL;
    2531             : 
    2532          10 :                 r = install_info_add(&c, *i, NULL, false, NULL);
    2533          10 :                 if (r < 0)
    2534           0 :                         return r;
    2535             :         }
    2536             : 
    2537          10 :         r = install_context_mark_for_removal(scope, &c, &paths, &remove_symlinks_to, config_path, changes, n_changes);
    2538          10 :         if (r < 0)
    2539           0 :                 return r;
    2540             : 
    2541          10 :         return remove_marked_symlinks(remove_symlinks_to, config_path, &paths, !!(flags & UNIT_FILE_DRY_RUN), changes, n_changes);
    2542             : }
    2543             : 
    2544           1 : int unit_file_reenable(
    2545             :                 UnitFileScope scope,
    2546             :                 UnitFileFlags flags,
    2547             :                 const char *root_dir,
    2548             :                 char **files,
    2549             :                 UnitFileChange **changes,
    2550             :                 size_t *n_changes) {
    2551             : 
    2552             :         char **n;
    2553             :         int r;
    2554             :         size_t l, i;
    2555             : 
    2556             :         /* First, we invoke the disable command with only the basename... */
    2557           1 :         l = strv_length(files);
    2558           1 :         n = newa(char*, l+1);
    2559           2 :         for (i = 0; i < l; i++)
    2560           1 :                 n[i] = basename(files[i]);
    2561           1 :         n[i] = NULL;
    2562             : 
    2563           1 :         r = unit_file_disable(scope, flags, root_dir, n, changes, n_changes);
    2564           1 :         if (r < 0)
    2565           0 :                 return r;
    2566             : 
    2567             :         /* But the enable command with the full name */
    2568           1 :         return unit_file_enable(scope, flags, root_dir, files, changes, n_changes);
    2569             : }
    2570             : 
    2571           2 : int unit_file_set_default(
    2572             :                 UnitFileScope scope,
    2573             :                 UnitFileFlags flags,
    2574             :                 const char *root_dir,
    2575             :                 const char *name,
    2576             :                 UnitFileChange **changes,
    2577             :                 size_t *n_changes) {
    2578             : 
    2579           2 :         _cleanup_(lookup_paths_free) LookupPaths paths = {};
    2580           2 :         _cleanup_(install_context_done) InstallContext c = {};
    2581             :         UnitFileInstallInfo *i;
    2582             :         const char *new_path;
    2583             :         int r;
    2584             : 
    2585           2 :         assert(scope >= 0);
    2586           2 :         assert(scope < _UNIT_FILE_SCOPE_MAX);
    2587           2 :         assert(name);
    2588             : 
    2589           2 :         if (unit_name_to_type(name) != UNIT_TARGET) /* this also validates the name */
    2590           0 :                 return -EINVAL;
    2591           2 :         if (streq(name, SPECIAL_DEFAULT_TARGET))
    2592           0 :                 return -EINVAL;
    2593             : 
    2594           2 :         r = lookup_paths_init(&paths, scope, 0, root_dir);
    2595           2 :         if (r < 0)
    2596           0 :                 return r;
    2597             : 
    2598           2 :         r = install_info_discover_and_check(scope, &c, &paths, name, 0, &i, changes, n_changes);
    2599           2 :         if (r < 0)
    2600           1 :                 return r;
    2601             : 
    2602           5 :         new_path = strjoina(paths.persistent_config, "/" SPECIAL_DEFAULT_TARGET);
    2603           1 :         return create_symlink(&paths, i->path, new_path, !!(flags & UNIT_FILE_FORCE), changes, n_changes);
    2604             : }
    2605             : 
    2606           3 : int unit_file_get_default(
    2607             :                 UnitFileScope scope,
    2608             :                 const char *root_dir,
    2609             :                 char **name) {
    2610             : 
    2611           3 :         _cleanup_(lookup_paths_free) LookupPaths paths = {};
    2612           3 :         _cleanup_(install_context_done) InstallContext c = {};
    2613             :         UnitFileInstallInfo *i;
    2614             :         char *n;
    2615             :         int r;
    2616             : 
    2617           3 :         assert(scope >= 0);
    2618           3 :         assert(scope < _UNIT_FILE_SCOPE_MAX);
    2619           3 :         assert(name);
    2620             : 
    2621           3 :         r = lookup_paths_init(&paths, scope, 0, root_dir);
    2622           3 :         if (r < 0)
    2623           0 :                 return r;
    2624             : 
    2625           3 :         r = install_info_discover(scope, &c, &paths, SPECIAL_DEFAULT_TARGET, SEARCH_FOLLOW_CONFIG_SYMLINKS,
    2626             :                                   &i, NULL, NULL);
    2627           3 :         if (r < 0)
    2628           2 :                 return r;
    2629           1 :         r = install_info_may_process(i, &paths, NULL, 0);
    2630           1 :         if (r < 0)
    2631           0 :                 return r;
    2632             : 
    2633           1 :         n = strdup(i->name);
    2634           1 :         if (!n)
    2635           0 :                 return -ENOMEM;
    2636             : 
    2637           1 :         *name = n;
    2638           1 :         return 0;
    2639             : }
    2640             : 
    2641         707 : int unit_file_lookup_state(
    2642             :                 UnitFileScope scope,
    2643             :                 const LookupPaths *paths,
    2644             :                 const char *name,
    2645             :                 UnitFileState *ret) {
    2646             : 
    2647         707 :         _cleanup_(install_context_done) InstallContext c = {};
    2648             :         UnitFileInstallInfo *i;
    2649             :         UnitFileState state;
    2650             :         int r;
    2651             : 
    2652         707 :         assert(paths);
    2653         707 :         assert(name);
    2654             : 
    2655         707 :         if (!unit_name_is_valid(name, UNIT_NAME_ANY))
    2656           0 :                 return -EINVAL;
    2657             : 
    2658         707 :         r = install_info_discover(scope, &c, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS,
    2659             :                                   &i, NULL, NULL);
    2660         707 :         if (r < 0)
    2661          33 :                 return log_debug_errno(r, "Failed to discover unit %s: %m", name);
    2662             : 
    2663         674 :         assert(IN_SET(i->type, UNIT_FILE_TYPE_REGULAR, UNIT_FILE_TYPE_MASKED));
    2664         674 :         log_debug("Found unit %s at %s (%s)", name, strna(i->path),
    2665             :                   i->type == UNIT_FILE_TYPE_REGULAR ? "regular file" : "mask");
    2666             : 
    2667             :         /* Shortcut things, if the caller just wants to know if this unit exists. */
    2668         674 :         if (!ret)
    2669           5 :                 return 0;
    2670             : 
    2671         669 :         switch (i->type) {
    2672             : 
    2673           5 :         case UNIT_FILE_TYPE_MASKED:
    2674           5 :                 r = path_is_runtime(paths, i->path, true);
    2675           5 :                 if (r < 0)
    2676           0 :                         return r;
    2677             : 
    2678           5 :                 state = r > 0 ? UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
    2679           5 :                 break;
    2680             : 
    2681         664 :         case UNIT_FILE_TYPE_REGULAR:
    2682         664 :                 r = path_is_generator(paths, i->path);
    2683         664 :                 if (r < 0)
    2684           0 :                         return r;
    2685         664 :                 if (r > 0) {
    2686          10 :                         state = UNIT_FILE_GENERATED;
    2687          10 :                         break;
    2688             :                 }
    2689             : 
    2690         654 :                 r = path_is_transient(paths, i->path);
    2691         654 :                 if (r < 0)
    2692           0 :                         return r;
    2693         654 :                 if (r > 0) {
    2694           1 :                         state = UNIT_FILE_TRANSIENT;
    2695           1 :                         break;
    2696             :                 }
    2697             : 
    2698             :                 /* Check if any of the Alias= symlinks have been created.
    2699             :                  * We ignore other aliases, and only check those that would
    2700             :                  * be created by systemctl enable for this unit. */
    2701         653 :                 r = find_symlinks_in_scope(scope, paths, i, true, &state);
    2702         653 :                 if (r < 0)
    2703           0 :                         return r;
    2704         653 :                 if (r > 0)
    2705         128 :                         break;
    2706             : 
    2707             :                 /* Check if the file is known under other names. If it is,
    2708             :                  * it might be in use. Report that as UNIT_FILE_INDIRECT. */
    2709         525 :                 r = find_symlinks_in_scope(scope, paths, i, false, &state);
    2710         525 :                 if (r < 0)
    2711           0 :                         return r;
    2712         525 :                 if (r > 0)
    2713           7 :                         state = UNIT_FILE_INDIRECT;
    2714             :                 else {
    2715         518 :                         if (unit_file_install_info_has_rules(i))
    2716         242 :                                 state = UNIT_FILE_DISABLED;
    2717         276 :                         else if (unit_file_install_info_has_also(i))
    2718          17 :                                 state = UNIT_FILE_INDIRECT;
    2719             :                         else
    2720         259 :                                 state = UNIT_FILE_STATIC;
    2721             :                 }
    2722             : 
    2723         525 :                 break;
    2724             : 
    2725           0 :         default:
    2726           0 :                 assert_not_reached("Unexpected unit file type.");
    2727             :         }
    2728             : 
    2729         669 :         *ret = state;
    2730         669 :         return 0;
    2731             : }
    2732             : 
    2733         182 : int unit_file_get_state(
    2734             :                 UnitFileScope scope,
    2735             :                 const char *root_dir,
    2736             :                 const char *name,
    2737             :                 UnitFileState *ret) {
    2738             : 
    2739         182 :         _cleanup_(lookup_paths_free) LookupPaths paths = {};
    2740             :         int r;
    2741             : 
    2742         182 :         assert(scope >= 0);
    2743         182 :         assert(scope < _UNIT_FILE_SCOPE_MAX);
    2744         182 :         assert(name);
    2745             : 
    2746         182 :         r = lookup_paths_init(&paths, scope, 0, root_dir);
    2747         182 :         if (r < 0)
    2748           0 :                 return r;
    2749             : 
    2750         182 :         return unit_file_lookup_state(scope, &paths, name, ret);
    2751             : }
    2752             : 
    2753          25 : int unit_file_exists(UnitFileScope scope, const LookupPaths *paths, const char *name) {
    2754          25 :         _cleanup_(install_context_done) InstallContext c = {};
    2755             :         int r;
    2756             : 
    2757          25 :         assert(paths);
    2758          25 :         assert(name);
    2759             : 
    2760          25 :         if (!unit_name_is_valid(name, UNIT_NAME_ANY))
    2761           0 :                 return -EINVAL;
    2762             : 
    2763          25 :         r = install_info_discover(scope, &c, paths, name, 0, NULL, NULL, NULL);
    2764          25 :         if (r == -ENOENT)
    2765          24 :                 return 0;
    2766           1 :         if (r < 0)
    2767           0 :                 return r;
    2768             : 
    2769           1 :         return 1;
    2770             : }
    2771             : 
    2772          11 : static int split_pattern_into_name_and_instances(const char *pattern, char **out_unit_name, char ***out_instances) {
    2773          11 :         _cleanup_strv_free_ char **instances = NULL;
    2774          11 :         _cleanup_free_ char *unit_name = NULL;
    2775             :         int r;
    2776             : 
    2777          11 :         assert(pattern);
    2778          11 :         assert(out_instances);
    2779          11 :         assert(out_unit_name);
    2780             : 
    2781          11 :         r = extract_first_word(&pattern, &unit_name, NULL, EXTRACT_RETAIN_ESCAPE);
    2782          11 :         if (r < 0)
    2783           0 :                 return r;
    2784             : 
    2785             :         /* We handle the instances logic when unit name is extracted */
    2786          11 :         if (pattern) {
    2787             :                 /* We only create instances when a rule of templated unit
    2788             :                  * is seen. A rule like enable foo@.service a b c will
    2789             :                  * result in an array of (a, b, c) as instance names */
    2790           2 :                 if (!unit_name_is_valid(unit_name, UNIT_NAME_TEMPLATE))
    2791           0 :                         return -EINVAL;
    2792             : 
    2793           2 :                 instances = strv_split(pattern, WHITESPACE);
    2794           2 :                 if (!instances)
    2795           0 :                         return -ENOMEM;
    2796             : 
    2797           2 :                 *out_instances = TAKE_PTR(instances);
    2798             :         }
    2799             : 
    2800          11 :         *out_unit_name = TAKE_PTR(unit_name);
    2801             : 
    2802          11 :         return 0;
    2803             : }
    2804             : 
    2805           7 : static int presets_find_config(UnitFileScope scope, const char *root_dir, char ***files) {
    2806             :         static const char* const system_dirs[] = {CONF_PATHS("systemd/system-preset"), NULL};
    2807             :         static const char* const user_dirs[] = {CONF_PATHS_USR("systemd/user-preset"), NULL};
    2808             :         const char* const* dirs;
    2809             : 
    2810           7 :         assert(scope >= 0);
    2811           7 :         assert(scope < _UNIT_FILE_SCOPE_MAX);
    2812             : 
    2813           7 :         if (scope == UNIT_FILE_SYSTEM)
    2814           7 :                 dirs = system_dirs;
    2815           0 :         else if (IN_SET(scope, UNIT_FILE_GLOBAL, UNIT_FILE_USER))
    2816           0 :                 dirs = user_dirs;
    2817             :         else
    2818           0 :                 assert_not_reached("Invalid unit file scope");
    2819             : 
    2820           7 :         return conf_files_list_strv(files, ".preset", root_dir, 0, dirs);
    2821             : }
    2822             : 
    2823           7 : static int read_presets(UnitFileScope scope, const char *root_dir, Presets *presets) {
    2824           7 :         _cleanup_(presets_freep) Presets ps = {};
    2825           7 :         size_t n_allocated = 0;
    2826           7 :         _cleanup_strv_free_ char **files = NULL;
    2827             :         char **p;
    2828             :         int r;
    2829             : 
    2830           7 :         assert(scope >= 0);
    2831           7 :         assert(scope < _UNIT_FILE_SCOPE_MAX);
    2832           7 :         assert(presets);
    2833             : 
    2834           7 :         r = presets_find_config(scope, root_dir, &files);
    2835           7 :         if (r < 0)
    2836           0 :                 return r;
    2837             : 
    2838          14 :         STRV_FOREACH(p, files) {
    2839           7 :                 _cleanup_fclose_ FILE *f;
    2840           7 :                 int n = 0;
    2841             : 
    2842           7 :                 f = fopen(*p, "re");
    2843           7 :                 if (!f) {
    2844           0 :                         if (errno == ENOENT)
    2845           0 :                                 continue;
    2846             : 
    2847           0 :                         return -errno;
    2848             :                 }
    2849             : 
    2850          18 :                 for (;;) {
    2851          25 :                         _cleanup_free_ char *line = NULL;
    2852          25 :                         PresetRule rule = {};
    2853             :                         const char *parameter;
    2854             :                         char *l;
    2855             : 
    2856          25 :                         r = read_line(f, LONG_LINE_MAX, &line);
    2857          25 :                         if (r < 0)
    2858           0 :                                 return r;
    2859          25 :                         if (r == 0)
    2860           7 :                                 break;
    2861             : 
    2862          18 :                         l = strstrip(line);
    2863          18 :                         n++;
    2864             : 
    2865          18 :                         if (isempty(l))
    2866           0 :                                 continue;
    2867          18 :                         if (strchr(COMMENTS, *l))
    2868           0 :                                 continue;
    2869             : 
    2870          18 :                         parameter = first_word(l, "enable");
    2871          18 :                         if (parameter) {
    2872             :                                 char *unit_name;
    2873          11 :                                 char **instances = NULL;
    2874             : 
    2875             :                                 /* Unit_name will remain the same as parameter when no instances are specified */
    2876          11 :                                 r = split_pattern_into_name_and_instances(parameter, &unit_name, &instances);
    2877          11 :                                 if (r < 0) {
    2878           0 :                                         log_syntax(NULL, LOG_WARNING, *p, n, r, "Couldn't parse line '%s'. Ignoring.", line);
    2879           0 :                                         continue;
    2880             :                                 }
    2881             : 
    2882          11 :                                 rule = (PresetRule) {
    2883             :                                         .pattern = unit_name,
    2884             :                                         .action = PRESET_ENABLE,
    2885             :                                         .instances = instances,
    2886             :                                 };
    2887             :                         }
    2888             : 
    2889          18 :                         parameter = first_word(l, "disable");
    2890          18 :                         if (parameter) {
    2891             :                                 char *pattern;
    2892             : 
    2893           7 :                                 pattern = strdup(parameter);
    2894           7 :                                 if (!pattern)
    2895           0 :                                         return -ENOMEM;
    2896             : 
    2897           7 :                                 rule = (PresetRule) {
    2898             :                                         .pattern = pattern,
    2899             :                                         .action = PRESET_DISABLE,
    2900             :                                 };
    2901             :                         }
    2902             : 
    2903          18 :                         if (rule.action) {
    2904          18 :                                 if (!GREEDY_REALLOC(ps.rules, n_allocated, ps.n_rules + 1))
    2905           0 :                                         return -ENOMEM;
    2906             : 
    2907          18 :                                 ps.rules[ps.n_rules++] = rule;
    2908          18 :                                 continue;
    2909             :                         }
    2910             : 
    2911           0 :                         log_syntax(NULL, LOG_WARNING, *p, n, 0, "Couldn't parse line '%s'. Ignoring.", line);
    2912             :                 }
    2913             :         }
    2914             : 
    2915           7 :         *presets = ps;
    2916           7 :         ps = (Presets){};
    2917             : 
    2918           7 :         return 0;
    2919             : }
    2920             : 
    2921          65 : static int pattern_match_multiple_instances(
    2922             :                         const PresetRule rule,
    2923             :                         const char *unit_name,
    2924             :                         char ***ret) {
    2925             : 
    2926          65 :         _cleanup_free_ char *templated_name = NULL;
    2927             :         int r;
    2928             : 
    2929             :         /* If no ret is needed or the rule itself does not have instances
    2930             :          * initialized, we return not matching */
    2931          65 :         if (!ret || !rule.instances)
    2932          51 :                 return 0;
    2933             : 
    2934          14 :         r = unit_name_template(unit_name, &templated_name);
    2935          14 :         if (r < 0)
    2936          11 :                 return r;
    2937           3 :         if (!streq(rule.pattern, templated_name))
    2938           1 :                 return 0;
    2939             : 
    2940             :         /* Compose a list of specified instances when unit name is a template  */
    2941           2 :         if (unit_name_is_valid(unit_name, UNIT_NAME_TEMPLATE)) {
    2942           1 :                 _cleanup_free_ char *prefix = NULL;
    2943           1 :                 _cleanup_strv_free_ char **out_strv = NULL;
    2944             :                 char **iter;
    2945             : 
    2946           1 :                 r = unit_name_to_prefix(unit_name, &prefix);
    2947           1 :                 if (r < 0)
    2948           0 :                         return r;
    2949             : 
    2950           4 :                 STRV_FOREACH(iter, rule.instances) {
    2951           3 :                         _cleanup_free_ char *name = NULL;
    2952           3 :                         r = unit_name_build(prefix, *iter, ".service", &name);
    2953           3 :                         if (r < 0)
    2954           0 :                                 return r;
    2955           3 :                         r = strv_extend(&out_strv, name);
    2956           3 :                         if (r < 0)
    2957           0 :                                 return r;
    2958             :                 }
    2959             : 
    2960           1 :                 *ret = TAKE_PTR(out_strv);
    2961           1 :                 return 1;
    2962             :         } else {
    2963             :                 /* We now know the input unit name is an instance name */
    2964           1 :                 _cleanup_free_ char *instance_name = NULL;
    2965             : 
    2966           1 :                 r = unit_name_to_instance(unit_name, &instance_name);
    2967           1 :                 if (r < 0)
    2968           0 :                         return r;
    2969             : 
    2970           1 :                 if (strv_find(rule.instances, instance_name))
    2971           1 :                         return 1;
    2972             :         }
    2973           0 :         return 0;
    2974             : }
    2975             : 
    2976          29 : static int query_presets(const char *name, const Presets presets, char ***instance_name_list) {
    2977          29 :         PresetAction action = PRESET_UNKNOWN;
    2978             :         size_t i;
    2979             :         char **s;
    2980          29 :         if (!unit_name_is_valid(name, UNIT_NAME_ANY))
    2981           0 :                 return -EINVAL;
    2982             : 
    2983          65 :         for (i = 0; i < presets.n_rules; i++)
    2984         128 :                 if (pattern_match_multiple_instances(presets.rules[i], name, instance_name_list) > 0 ||
    2985          63 :                     fnmatch(presets.rules[i].pattern, name, FNM_NOESCAPE) == 0) {
    2986          29 :                         action = presets.rules[i].action;
    2987          29 :                         break;
    2988             :                 }
    2989             : 
    2990          29 :         switch (action) {
    2991           0 :         case PRESET_UNKNOWN:
    2992           0 :                 log_debug("Preset files don't specify rule for %s. Enabling.", name);
    2993           0 :                 return 1;
    2994           5 :         case PRESET_ENABLE:
    2995           6 :                 if (instance_name_list && *instance_name_list)
    2996           4 :                         STRV_FOREACH(s, *instance_name_list)
    2997           3 :                                 log_debug("Preset files say enable %s.", *s);
    2998             :                 else
    2999           4 :                         log_debug("Preset files say enable %s.", name);
    3000           5 :                 return 1;
    3001          24 :         case PRESET_DISABLE:
    3002          24 :                 log_debug("Preset files say disable %s.", name);
    3003          24 :                 return 0;
    3004           0 :         default:
    3005           0 :                 assert_not_reached("invalid preset action");
    3006             :         }
    3007             : }
    3008             : 
    3009           0 : int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name) {
    3010           0 :         _cleanup_(presets_freep) Presets presets = {};
    3011             :         int r;
    3012             : 
    3013           0 :         r = read_presets(scope, root_dir, &presets);
    3014           0 :         if (r < 0)
    3015           0 :                 return r;
    3016             : 
    3017           0 :         return query_presets(name, presets, NULL);
    3018             : }
    3019             : 
    3020           7 : static int execute_preset(
    3021             :                 UnitFileScope scope,
    3022             :                 InstallContext *plus,
    3023             :                 InstallContext *minus,
    3024             :                 const LookupPaths *paths,
    3025             :                 const char *config_path,
    3026             :                 char **files,
    3027             :                 UnitFilePresetMode mode,
    3028             :                 bool force,
    3029             :                 UnitFileChange **changes,
    3030             :                 size_t *n_changes) {
    3031             : 
    3032             :         int r;
    3033             : 
    3034           7 :         assert(plus);
    3035           7 :         assert(minus);
    3036           7 :         assert(paths);
    3037           7 :         assert(config_path);
    3038             : 
    3039           7 :         if (mode != UNIT_FILE_PRESET_ENABLE_ONLY) {
    3040           7 :                 _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
    3041             : 
    3042           7 :                 r = install_context_mark_for_removal(scope, minus, paths, &remove_symlinks_to, config_path, changes, n_changes);
    3043           7 :                 if (r < 0)
    3044           0 :                         return r;
    3045             : 
    3046           7 :                 r = remove_marked_symlinks(remove_symlinks_to, config_path, paths, false, changes, n_changes);
    3047             :         } else
    3048           0 :                 r = 0;
    3049             : 
    3050           7 :         if (mode != UNIT_FILE_PRESET_DISABLE_ONLY) {
    3051             :                 int q;
    3052             : 
    3053             :                 /* Returns number of symlinks that where supposed to be installed. */
    3054           7 :                 q = install_context_apply(scope, plus, paths, config_path, force, SEARCH_LOAD, changes, n_changes);
    3055           7 :                 if (r >= 0) {
    3056           7 :                         if (q < 0)
    3057           0 :                                 r = q;
    3058             :                         else
    3059           7 :                                 r += q;
    3060             :                 }
    3061             :         }
    3062             : 
    3063           7 :         return r;
    3064             : }
    3065             : 
    3066          47 : static int preset_prepare_one(
    3067             :                 UnitFileScope scope,
    3068             :                 InstallContext *plus,
    3069             :                 InstallContext *minus,
    3070             :                 LookupPaths *paths,
    3071             :                 const char *name,
    3072             :                 Presets presets,
    3073             :                 UnitFileChange **changes,
    3074             :                 size_t *n_changes) {
    3075             : 
    3076          47 :         _cleanup_(install_context_done) InstallContext tmp = {};
    3077          47 :         _cleanup_strv_free_ char **instance_name_list = NULL;
    3078             :         UnitFileInstallInfo *i;
    3079             :         int r;
    3080             : 
    3081          47 :         if (install_info_find(plus, name) || install_info_find(minus, name))
    3082           1 :                 return 0;
    3083             : 
    3084          46 :         r = install_info_discover(scope, &tmp, paths, name, SEARCH_FOLLOW_CONFIG_SYMLINKS,
    3085             :                                   &i, changes, n_changes);
    3086          46 :         if (r < 0)
    3087           0 :                 return r;
    3088          46 :         if (!streq(name, i->name)) {
    3089          17 :                 log_debug("Skipping %s because it is an alias for %s.", name, i->name);
    3090          17 :                 return 0;
    3091             :         }
    3092             : 
    3093          29 :         r = query_presets(name, presets, &instance_name_list);
    3094          29 :         if (r < 0)
    3095           0 :                 return r;
    3096             : 
    3097          29 :         if (r > 0) {
    3098           5 :                 if (instance_name_list) {
    3099             :                         char **s;
    3100           4 :                         STRV_FOREACH(s, instance_name_list) {
    3101           3 :                                 r = install_info_discover_and_check(scope, plus, paths, *s, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS,
    3102             :                                                                     &i, changes, n_changes);
    3103           3 :                                 if (r < 0)
    3104           0 :                                         return r;
    3105             :                         }
    3106             :                 } else {
    3107           4 :                         r = install_info_discover_and_check(scope, plus, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS,
    3108             :                                                             &i, changes, n_changes);
    3109           4 :                         if (r < 0)
    3110           0 :                                 return r;
    3111             :                 }
    3112             : 
    3113             :         } else
    3114          24 :                 r = install_info_discover(scope, minus, paths, name, SEARCH_FOLLOW_CONFIG_SYMLINKS,
    3115             :                                           &i, changes, n_changes);
    3116             : 
    3117          29 :         return r;
    3118             : }
    3119             : 
    3120           5 : int unit_file_preset(
    3121             :                 UnitFileScope scope,
    3122             :                 UnitFileFlags flags,
    3123             :                 const char *root_dir,
    3124             :                 char **files,
    3125             :                 UnitFilePresetMode mode,
    3126             :                 UnitFileChange **changes,
    3127             :                 size_t *n_changes) {
    3128             : 
    3129           5 :         _cleanup_(install_context_done) InstallContext plus = {}, minus = {};
    3130           5 :         _cleanup_(lookup_paths_free) LookupPaths paths = {};
    3131           5 :         _cleanup_(presets_freep) Presets presets = {};
    3132             :         const char *config_path;
    3133             :         char **i;
    3134             :         int r;
    3135             : 
    3136           5 :         assert(scope >= 0);
    3137           5 :         assert(scope < _UNIT_FILE_SCOPE_MAX);
    3138           5 :         assert(mode < _UNIT_FILE_PRESET_MAX);
    3139             : 
    3140           5 :         r = lookup_paths_init(&paths, scope, 0, root_dir);
    3141           5 :         if (r < 0)
    3142           0 :                 return r;
    3143             : 
    3144           5 :         config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
    3145           5 :         if (!config_path)
    3146           0 :                 return -ENXIO;
    3147             : 
    3148           5 :         r = read_presets(scope, root_dir, &presets);
    3149           5 :         if (r < 0)
    3150           0 :                 return r;
    3151             : 
    3152          10 :         STRV_FOREACH(i, files) {
    3153           5 :                 r = preset_prepare_one(scope, &plus, &minus, &paths, *i, presets, changes, n_changes);
    3154           5 :                 if (r < 0)
    3155           0 :                         return r;
    3156             :         }
    3157             : 
    3158           5 :         return execute_preset(scope, &plus, &minus, &paths, config_path, files, mode, !!(flags & UNIT_FILE_FORCE), changes, n_changes);
    3159             : }
    3160             : 
    3161           2 : int unit_file_preset_all(
    3162             :                 UnitFileScope scope,
    3163             :                 UnitFileFlags flags,
    3164             :                 const char *root_dir,
    3165             :                 UnitFilePresetMode mode,
    3166             :                 UnitFileChange **changes,
    3167             :                 size_t *n_changes) {
    3168             : 
    3169           2 :         _cleanup_(install_context_done) InstallContext plus = {}, minus = {};
    3170           2 :         _cleanup_(lookup_paths_free) LookupPaths paths = {};
    3171           2 :         _cleanup_(presets_freep) Presets presets = {};
    3172           2 :         const char *config_path = NULL;
    3173             :         char **i;
    3174             :         int r;
    3175             : 
    3176           2 :         assert(scope >= 0);
    3177           2 :         assert(scope < _UNIT_FILE_SCOPE_MAX);
    3178           2 :         assert(mode < _UNIT_FILE_PRESET_MAX);
    3179             : 
    3180           2 :         r = lookup_paths_init(&paths, scope, 0, root_dir);
    3181           2 :         if (r < 0)
    3182           0 :                 return r;
    3183             : 
    3184           2 :         config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
    3185           2 :         if (!config_path)
    3186           0 :                 return -ENXIO;
    3187             : 
    3188           2 :         r = read_presets(scope, root_dir, &presets);
    3189           2 :         if (r < 0)
    3190           0 :                 return r;
    3191             : 
    3192          26 :         STRV_FOREACH(i, paths.search_path) {
    3193          24 :                 _cleanup_closedir_ DIR *d = NULL;
    3194             :                 struct dirent *de;
    3195             : 
    3196          24 :                 d = opendir(*i);
    3197          24 :                 if (!d) {
    3198          18 :                         if (errno == ENOENT)
    3199          18 :                                 continue;
    3200             : 
    3201           0 :                         return -errno;
    3202             :                 }
    3203             : 
    3204          63 :                 FOREACH_DIRENT(de, d, return -errno) {
    3205             : 
    3206          45 :                         if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
    3207           3 :                                 continue;
    3208             : 
    3209          42 :                         dirent_ensure_type(d, de);
    3210             : 
    3211          42 :                         if (!IN_SET(de->d_type, DT_LNK, DT_REG))
    3212           0 :                                 continue;
    3213             : 
    3214             :                         /* we don't pass changes[] in, because we want to handle errors on our own */
    3215          42 :                         r = preset_prepare_one(scope, &plus, &minus, &paths, de->d_name, presets, NULL, 0);
    3216          42 :                         if (r == -ERFKILL)
    3217           0 :                                 r = unit_file_changes_add(changes, n_changes,
    3218           0 :                                                           UNIT_FILE_IS_MASKED, de->d_name, NULL);
    3219          42 :                         else if (r == -ENOLINK)
    3220           0 :                                 r = unit_file_changes_add(changes, n_changes,
    3221           0 :                                                           UNIT_FILE_IS_DANGLING, de->d_name, NULL);
    3222          42 :                         else if (r == -EADDRNOTAVAIL) /* Ignore generated/transient units when applying preset */
    3223           0 :                                 continue;
    3224          42 :                         if (r < 0)
    3225           0 :                                 return r;
    3226             :                 }
    3227             :         }
    3228             : 
    3229           2 :         return execute_preset(scope, &plus, &minus, &paths, config_path, NULL, mode, !!(flags & UNIT_FILE_FORCE), changes, n_changes);
    3230             : }
    3231             : 
    3232         525 : static void unit_file_list_free_one(UnitFileList *f) {
    3233         525 :         if (!f)
    3234           0 :                 return;
    3235             : 
    3236         525 :         free(f->path);
    3237         525 :         free(f);
    3238             : }
    3239             : 
    3240           2 : Hashmap* unit_file_list_free(Hashmap *h) {
    3241         527 :         return hashmap_free_with_destructor(h, unit_file_list_free_one);
    3242             : }
    3243             : 
    3244         594 : DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList*, unit_file_list_free_one);
    3245             : 
    3246           2 : int unit_file_get_list(
    3247             :                 UnitFileScope scope,
    3248             :                 const char *root_dir,
    3249             :                 Hashmap *h,
    3250             :                 char **states,
    3251             :                 char **patterns) {
    3252             : 
    3253           2 :         _cleanup_(lookup_paths_free) LookupPaths paths = {};
    3254             :         char **i;
    3255             :         int r;
    3256             : 
    3257           2 :         assert(scope >= 0);
    3258           2 :         assert(scope < _UNIT_FILE_SCOPE_MAX);
    3259           2 :         assert(h);
    3260             : 
    3261           2 :         r = lookup_paths_init(&paths, scope, 0, root_dir);
    3262           2 :         if (r < 0)
    3263           0 :                 return r;
    3264             : 
    3265          26 :         STRV_FOREACH(i, paths.search_path) {
    3266          24 :                 _cleanup_closedir_ DIR *d = NULL;
    3267             :                 struct dirent *de;
    3268             : 
    3269          24 :                 d = opendir(*i);
    3270          24 :                 if (!d) {
    3271          15 :                         if (errno == ENOENT)
    3272          15 :                                 continue;
    3273           0 :                         if (IN_SET(errno, ENOTDIR, EACCES)) {
    3274           0 :                                 log_debug_errno(errno, "Failed to open \"%s\": %m", *i);
    3275           0 :                                 continue;
    3276             :                         }
    3277             : 
    3278           0 :                         return -errno;
    3279             :                 }
    3280             : 
    3281         621 :                 FOREACH_DIRENT(de, d, return -errno) {
    3282         594 :                         _cleanup_(unit_file_list_free_onep) UnitFileList *f = NULL;
    3283             : 
    3284         594 :                         if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
    3285          64 :                                 continue;
    3286             : 
    3287         530 :                         if (!strv_fnmatch_or_empty(patterns, de->d_name, FNM_NOESCAPE))
    3288           0 :                                 continue;
    3289             : 
    3290         530 :                         if (hashmap_get(h, de->d_name))
    3291           5 :                                 continue;
    3292             : 
    3293         525 :                         dirent_ensure_type(d, de);
    3294             : 
    3295         525 :                         if (!IN_SET(de->d_type, DT_LNK, DT_REG))
    3296           0 :                                 continue;
    3297             : 
    3298         525 :                         f = new0(UnitFileList, 1);
    3299         525 :                         if (!f)
    3300           0 :                                 return -ENOMEM;
    3301             : 
    3302         525 :                         f->path = path_make_absolute(de->d_name, *i);
    3303         525 :                         if (!f->path)
    3304           0 :                                 return -ENOMEM;
    3305             : 
    3306         525 :                         r = unit_file_lookup_state(scope, &paths, de->d_name, &f->state);
    3307         525 :                         if (r < 0)
    3308           0 :                                 f->state = UNIT_FILE_BAD;
    3309             : 
    3310         525 :                         if (!strv_isempty(states) &&
    3311           0 :                             !strv_contains(states, unit_file_state_to_string(f->state)))
    3312           0 :                                 continue;
    3313             : 
    3314         525 :                         r = hashmap_put(h, basename(f->path), f);
    3315         525 :                         if (r < 0)
    3316           0 :                                 return r;
    3317             : 
    3318         525 :                         f = NULL; /* prevent cleanup */
    3319             :                 }
    3320             :         }
    3321             : 
    3322           2 :         return 0;
    3323             : }
    3324             : 
    3325             : static const char* const unit_file_state_table[_UNIT_FILE_STATE_MAX] = {
    3326             :         [UNIT_FILE_ENABLED] = "enabled",
    3327             :         [UNIT_FILE_ENABLED_RUNTIME] = "enabled-runtime",
    3328             :         [UNIT_FILE_LINKED] = "linked",
    3329             :         [UNIT_FILE_LINKED_RUNTIME] = "linked-runtime",
    3330             :         [UNIT_FILE_MASKED] = "masked",
    3331             :         [UNIT_FILE_MASKED_RUNTIME] = "masked-runtime",
    3332             :         [UNIT_FILE_STATIC] = "static",
    3333             :         [UNIT_FILE_DISABLED] = "disabled",
    3334             :         [UNIT_FILE_INDIRECT] = "indirect",
    3335             :         [UNIT_FILE_GENERATED] = "generated",
    3336             :         [UNIT_FILE_TRANSIENT] = "transient",
    3337             :         [UNIT_FILE_BAD] = "bad",
    3338             : };
    3339             : 
    3340         535 : DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState);
    3341             : 
    3342             : static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX] = {
    3343             :         [UNIT_FILE_SYMLINK] = "symlink",
    3344             :         [UNIT_FILE_UNLINK] = "unlink",
    3345             :         [UNIT_FILE_IS_MASKED] = "masked",
    3346             :         [UNIT_FILE_IS_DANGLING] = "dangling",
    3347             : };
    3348             : 
    3349          12 : DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType);
    3350             : 
    3351             : static const char* const unit_file_preset_mode_table[_UNIT_FILE_PRESET_MAX] = {
    3352             :         [UNIT_FILE_PRESET_FULL] = "full",
    3353             :         [UNIT_FILE_PRESET_ENABLE_ONLY] = "enable-only",
    3354             :         [UNIT_FILE_PRESET_DISABLE_ONLY] = "disable-only",
    3355             : };
    3356             : 
    3357          10 : DEFINE_STRING_TABLE_LOOKUP(unit_file_preset_mode, UnitFilePresetMode);

Generated by: LCOV version 1.14