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