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