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