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