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