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