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