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