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