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