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