chiark / gitweb /
a77dfc77e4a096dd698c564d5d18fd63d3dbb091
[elogind.git] / src / shared / install.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2011 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty <of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <unistd.h>
25 #include <string.h>
26 #include <fnmatch.h>
27
28 #include "util.h"
29 #include "mkdir.h"
30 #include "hashmap.h"
31 #include "set.h"
32 #include "path-lookup.h"
33 #include "strv.h"
34 #include "unit-name.h"
35 #include "install.h"
36 #include "conf-parser.h"
37 #include "conf-files.h"
38
39 typedef struct {
40         char *name;
41         char *path;
42
43         char **aliases;
44         char **wanted_by;
45 } InstallInfo;
46
47 typedef struct {
48         Hashmap *will_install;
49         Hashmap *have_installed;
50 } InstallContext;
51
52 static int lookup_paths_init_from_scope(LookupPaths *paths, UnitFileScope scope) {
53         assert(paths);
54         assert(scope >= 0);
55         assert(scope < _UNIT_FILE_SCOPE_MAX);
56
57         zero(*paths);
58
59         return lookup_paths_init(paths,
60                                  scope == UNIT_FILE_SYSTEM ? MANAGER_SYSTEM : MANAGER_USER,
61                                  scope == UNIT_FILE_USER);
62 }
63
64 static int get_config_path(UnitFileScope scope, bool runtime, const char *root_dir, char **ret) {
65         char *p = NULL;
66         int r;
67
68         assert(scope >= 0);
69         assert(scope < _UNIT_FILE_SCOPE_MAX);
70         assert(ret);
71
72         switch (scope) {
73
74         case UNIT_FILE_SYSTEM:
75
76                 if (root_dir && runtime)
77                         asprintf(&p, "%s/run/systemd/system", root_dir);
78                 else if (runtime)
79                         p = strdup("/run/systemd/system");
80                 else if (root_dir)
81                         asprintf(&p, "%s/%s", root_dir, SYSTEM_CONFIG_UNIT_PATH);
82                 else
83                         p = strdup(SYSTEM_CONFIG_UNIT_PATH);
84
85                 break;
86
87         case UNIT_FILE_GLOBAL:
88
89                 if (root_dir)
90                         return -EINVAL;
91
92                 if (runtime)
93                         p = strdup("/run/systemd/user");
94                 else
95                         p = strdup(USER_CONFIG_UNIT_PATH);
96                 break;
97
98         case UNIT_FILE_USER:
99
100                 if (root_dir || runtime)
101                         return -EINVAL;
102
103                 r = user_config_home(&p);
104                 if (r <= 0)
105                         return r < 0 ? r : -ENOENT;
106
107                 break;
108
109         default:
110                 assert_not_reached("Bad scope");
111         }
112
113         if (!p)
114                 return -ENOMEM;
115
116         *ret = p;
117         return 0;
118 }
119
120 static int add_file_change(
121                 UnitFileChange **changes,
122                 unsigned *n_changes,
123                 UnitFileChangeType type,
124                 const char *path,
125                 const char *source) {
126
127         UnitFileChange *c;
128         unsigned i;
129
130         assert(path);
131         assert(!changes == !n_changes);
132
133         if (!changes)
134                 return 0;
135
136         c = realloc(*changes, (*n_changes + 1) * sizeof(UnitFileChange));
137         if (!c)
138                 return -ENOMEM;
139
140         *changes = c;
141         i = *n_changes;
142
143         c[i].type = type;
144         c[i].path = strdup(path);
145         if (!c[i].path)
146                 return -ENOMEM;
147
148         if (source) {
149                 c[i].source = strdup(source);
150                 if (!c[i].source) {
151                         free(c[i].path);
152                         return -ENOMEM;
153                 }
154         } else
155                 c[i].source = NULL;
156
157         *n_changes = i+1;
158         return 0;
159 }
160
161 static int mark_symlink_for_removal(
162                 Set **remove_symlinks_to,
163                 const char *p) {
164
165         char *n;
166         int r;
167
168         assert(p);
169
170         r = set_ensure_allocated(remove_symlinks_to, string_hash_func, string_compare_func);
171         if (r < 0)
172                 return r;
173
174         n = strdup(p);
175         if (!n)
176                 return -ENOMEM;
177
178         path_kill_slashes(n);
179
180         r = set_put(*remove_symlinks_to, n);
181         if (r < 0) {
182                 free(n);
183                 return r == -EEXIST ? 0 : r;
184         }
185
186         return 0;
187 }
188
189 static int remove_marked_symlinks_fd(
190                 Set *remove_symlinks_to,
191                 int fd,
192                 const char *path,
193                 const char *config_path,
194                 bool *deleted,
195                 UnitFileChange **changes,
196                 unsigned *n_changes) {
197
198         int r = 0;
199         DIR *d;
200         struct dirent buffer, *de;
201
202         assert(remove_symlinks_to);
203         assert(fd >= 0);
204         assert(path);
205         assert(config_path);
206         assert(deleted);
207
208         d = fdopendir(fd);
209         if (!d) {
210                 close_nointr_nofail(fd);
211                 return -errno;
212         }
213
214         rewinddir(d);
215
216         for (;;) {
217                 int k;
218
219                 k = readdir_r(d, &buffer, &de);
220                 if (k != 0) {
221                         r = -errno;
222                         break;
223                 }
224
225                 if (!de)
226                         break;
227
228                 if (ignore_file(de->d_name))
229                         continue;
230
231                 dirent_ensure_type(d, de);
232
233                 if (de->d_type == DT_DIR) {
234                         int nfd, q;
235                         char *p;
236
237                         nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
238                         if (nfd < 0) {
239                                 if (errno == ENOENT)
240                                         continue;
241
242                                 if (r == 0)
243                                         r = -errno;
244                                 continue;
245                         }
246
247                         p = path_make_absolute(de->d_name, path);
248                         if (!p) {
249                                 close_nointr_nofail(nfd);
250                                 r = -ENOMEM;
251                                 break;
252                         }
253
254                         /* This will close nfd, regardless whether it succeeds or not */
255                         q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, deleted, changes, n_changes);
256                         free(p);
257
258                         if (r == 0)
259                                 r = q;
260
261                 } else if (de->d_type == DT_LNK) {
262                         char *p, *dest;
263                         int q;
264                         bool found;
265
266                         p = path_make_absolute(de->d_name, path);
267                         if (!p) {
268                                 r = -ENOMEM;
269                                 break;
270                         }
271
272                         q = readlink_and_canonicalize(p, &dest);
273                         if (q < 0) {
274                                 free(p);
275
276                                 if (q == -ENOENT)
277                                         continue;
278
279                                 if (r == 0)
280                                         r = q;
281                                 continue;
282                         }
283
284                         found =
285                                 set_get(remove_symlinks_to, dest) ||
286                                 set_get(remove_symlinks_to, file_name_from_path(dest));
287
288                         if (found) {
289
290                                 if (unlink(p) < 0 && errno != ENOENT) {
291
292                                         if (r == 0)
293                                                 r = -errno;
294                                 } else {
295                                         rmdir_parents(p, config_path);
296                                         path_kill_slashes(p);
297
298                                         add_file_change(changes, n_changes, UNIT_FILE_UNLINK, p, NULL);
299
300                                         if (!set_get(remove_symlinks_to, p)) {
301
302                                                 q = mark_symlink_for_removal(&remove_symlinks_to, p);
303                                                 if (q < 0) {
304                                                         if (r == 0)
305                                                                 r = q;
306                                                 } else
307                                                         *deleted = true;
308                                         }
309                                 }
310                         }
311
312                         free(p);
313                         free(dest);
314                 }
315         }
316
317         closedir(d);
318
319         return r;
320 }
321
322 static int remove_marked_symlinks(
323                 Set *remove_symlinks_to,
324                 const char *config_path,
325                 UnitFileChange **changes,
326                 unsigned *n_changes) {
327
328         int fd, r = 0;
329         bool deleted;
330
331         assert(config_path);
332
333         if (set_size(remove_symlinks_to) <= 0)
334                 return 0;
335
336         fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
337         if (fd < 0)
338                 return -errno;
339
340         do {
341                 int q, cfd;
342                 deleted = false;
343
344                 cfd = dup(fd);
345                 if (cfd < 0) {
346                         r = -errno;
347                         break;
348                 }
349
350                 /* This takes possession of cfd and closes it */
351                 q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, &deleted, changes, n_changes);
352                 if (r == 0)
353                         r = q;
354         } while (deleted);
355
356         close_nointr_nofail(fd);
357
358         return r;
359 }
360
361 static int find_symlinks_fd(
362                 const char *name,
363                 int fd,
364                 const char *path,
365                 const char *config_path,
366                 bool *same_name_link) {
367
368         int r = 0;
369         DIR *d;
370         struct dirent buffer, *de;
371
372         assert(name);
373         assert(fd >= 0);
374         assert(path);
375         assert(config_path);
376         assert(same_name_link);
377
378         d = fdopendir(fd);
379         if (!d) {
380                 close_nointr_nofail(fd);
381                 return -errno;
382         }
383
384         for (;;) {
385                 int k;
386
387                 k = readdir_r(d, &buffer, &de);
388                 if (k != 0) {
389                         r = -errno;
390                         break;
391                 }
392
393                 if (!de)
394                         break;
395
396                 if (ignore_file(de->d_name))
397                         continue;
398
399                 dirent_ensure_type(d, de);
400
401                 if (de->d_type == DT_DIR) {
402                         int nfd, q;
403                         char *p;
404
405                         nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
406                         if (nfd < 0) {
407                                 if (errno == ENOENT)
408                                         continue;
409
410                                 if (r == 0)
411                                         r = -errno;
412                                 continue;
413                         }
414
415                         p = path_make_absolute(de->d_name, path);
416                         if (!p) {
417                                 close_nointr_nofail(nfd);
418                                 r = -ENOMEM;
419                                 break;
420                         }
421
422                         /* This will close nfd, regardless whether it succeeds or not */
423                         q = find_symlinks_fd(name, nfd, p, config_path, same_name_link);
424                         free(p);
425
426                         if (q > 0) {
427                                 r = 1;
428                                 break;
429                         }
430
431                         if (r == 0)
432                                 r = q;
433
434                 } else if (de->d_type == DT_LNK) {
435                         char *p, *dest;
436                         bool found_path, found_dest, b = false;
437                         int q;
438
439                         /* Acquire symlink name */
440                         p = path_make_absolute(de->d_name, path);
441                         if (!p) {
442                                 r = -ENOMEM;
443                                 break;
444                         }
445
446                         /* Acquire symlink destination */
447                         q = readlink_and_canonicalize(p, &dest);
448                         if (q < 0) {
449                                 free(p);
450
451                                 if (q == -ENOENT)
452                                         continue;
453
454                                 if (r == 0)
455                                         r = q;
456                                 continue;
457                         }
458
459                         /* Check if the symlink itself matches what we
460                          * are looking for */
461                         if (path_is_absolute(name))
462                                 found_path = path_equal(p, name);
463                         else
464                                 found_path = streq(de->d_name, name);
465
466                         /* Check if what the symlink points to
467                          * matches what we are looking for */
468                         if (path_is_absolute(name))
469                                 found_dest = path_equal(dest, name);
470                         else
471                                 found_dest = streq(file_name_from_path(dest), name);
472
473                         free(dest);
474
475                         if (found_path && found_dest) {
476                                 char *t;
477
478                                 /* Filter out same name links in the main
479                                  * config path */
480                                 t = path_make_absolute(name, config_path);
481                                 if (!t) {
482                                         free(p);
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                         r = -errno;
1577                         if (errno == ENOENT)
1578                                 continue;
1579
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 (r == -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 {
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-runtime",
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);