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