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