chiark / gitweb /
move _cleanup_ attribute in front of the type
[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         _cleanup_closedir_ DIR *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                         _cleanup_free_ char *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                         _cleanup_free_ char *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         _cleanup_closedir_ DIR *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                         _cleanup_free_ char *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                         _cleanup_free_ char *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                                 _cleanup_free_ char *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         _cleanup_free_ char *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         _cleanup_free_ char *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                 _cleanup_free_ char *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         _cleanup_lookup_paths_free_ LookupPaths paths = {};
704         char **i;
705         _cleanup_free_ char *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                 _cleanup_free_ char *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                         _cleanup_free_ char *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(const char *unit,
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                 _cleanup_free_ char *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 config_parse_user(const char *unit,
960                              const char *filename,
961                              unsigned line,
962                              const char *section,
963                              const char *lvalue,
964                              int ltype,
965                              const char *rvalue,
966                              void *data,
967                              void *userdata) {
968
969         InstallInfo *i = data;
970         char* printed;
971
972         assert(filename);
973         assert(lvalue);
974         assert(rvalue);
975
976         printed = install_full_printf(i, rvalue);
977         if (!printed)
978                 return -ENOMEM;
979
980         free(i->user);
981         i->user = printed;
982
983         return 0;
984 }
985
986 static int unit_file_load(
987                 InstallContext *c,
988                 InstallInfo *info,
989                 const char *path,
990                 bool allow_symlink) {
991
992         const ConfigTableItem items[] = {
993                 { "Install", "Alias",      config_parse_strv, 0, &info->aliases     },
994                 { "Install", "WantedBy",   config_parse_strv, 0, &info->wanted_by   },
995                 { "Install", "RequiredBy", config_parse_strv, 0, &info->required_by },
996                 { "Install", "Also",       config_parse_also, 0, c                  },
997                 { "Exec",    "User",       config_parse_user, 0, info               },
998                 { NULL, NULL, NULL, 0, NULL }
999         };
1000
1001         int fd;
1002         _cleanup_fclose_ FILE *f = NULL;
1003         int r;
1004
1005         assert(c);
1006         assert(info);
1007         assert(path);
1008
1009         fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|(allow_symlink ? 0 : O_NOFOLLOW));
1010         if (fd < 0)
1011                 return -errno;
1012
1013         f = fdopen(fd, "re");
1014         if (!f) {
1015                 close_nointr_nofail(fd);
1016                 return -ENOMEM;
1017         }
1018
1019         r = config_parse(NULL, path, f, NULL,
1020                          config_item_table_lookup, (void*) items, true, info);
1021         if (r < 0)
1022                 return r;
1023
1024         return
1025                 strv_length(info->aliases) +
1026                 strv_length(info->wanted_by) +
1027                 strv_length(info->required_by);
1028 }
1029
1030 static int unit_file_search(
1031                 InstallContext *c,
1032                 InstallInfo *info,
1033                 LookupPaths *paths,
1034                 const char *root_dir,
1035                 bool allow_symlink) {
1036
1037         char **p;
1038         int r;
1039
1040         assert(c);
1041         assert(info);
1042         assert(paths);
1043
1044         if (info->path)
1045                 return unit_file_load(c, info, info->path, allow_symlink);
1046
1047         assert(info->name);
1048
1049         STRV_FOREACH(p, paths->unit_path) {
1050                 char *path = NULL;
1051
1052                 if (isempty(root_dir))
1053                         asprintf(&path, "%s/%s", *p, info->name);
1054                 else
1055                         asprintf(&path, "%s/%s/%s", root_dir, *p, info->name);
1056
1057                 if (!path)
1058                         return -ENOMEM;
1059
1060                 r = unit_file_load(c, info, path, allow_symlink);
1061
1062                 if (r >= 0)
1063                         info->path = path;
1064                 else {
1065                         if (r == -ENOENT && unit_name_is_instance(info->name)) {
1066                                 /* unit file doesn't exist, however instance enablement was request */
1067                                 /* we will check if it is possible to load template unit file */
1068                                 char *template = NULL,
1069                                      *template_path = NULL,
1070                                      *template_dir = NULL;
1071
1072                                 template = unit_name_template(info->name);
1073                                 if (!template) {
1074                                         free(path);
1075                                         return -ENOMEM;
1076                                 }
1077
1078                                 /* we will reuse path variable since we don't need it anymore */
1079                                 template_dir = path;
1080                                 *(strrchr(path, '/') + 1) = '\0';
1081
1082                                 template_path = strjoin(template_dir, template, NULL);
1083                                 if (!template_path) {
1084                                         free(path);
1085                                         free(template);
1086                                         return -ENOMEM;
1087                                 }
1088
1089                                 /* let's try to load template unit */
1090                                 r = unit_file_load(c, info, template_path, allow_symlink);
1091                                 if (r >= 0) {
1092                                         info->path = strdup(template_path);
1093                                         if (!info->path) {
1094                                                 free(path);
1095                                                 free(template);
1096                                                 free(template_path);
1097                                                 return -ENOMEM;
1098                                         }
1099                                 }
1100
1101                                 free(template);
1102                                 free(template_path);
1103                         }
1104                         free(path);
1105                 }
1106
1107                 if (r != -ENOENT && r != -ELOOP)
1108                         return r;
1109         }
1110
1111         return -ENOENT;
1112 }
1113
1114 static int unit_file_can_install(
1115                 LookupPaths *paths,
1116                 const char *root_dir,
1117                 const char *name,
1118                 bool allow_symlink) {
1119
1120         _cleanup_install_context_done_ InstallContext c = {};
1121         InstallInfo *i;
1122         int r;
1123
1124         assert(paths);
1125         assert(name);
1126
1127         r = install_info_add_auto(&c, name);
1128         if (r < 0)
1129                 return r;
1130
1131         assert_se(i = hashmap_first(c.will_install));
1132
1133         r = unit_file_search(&c, i, paths, root_dir, allow_symlink);
1134
1135         if (r >= 0)
1136                 r =
1137                         strv_length(i->aliases) +
1138                         strv_length(i->wanted_by) +
1139                         strv_length(i->required_by);
1140
1141         return r;
1142 }
1143
1144 static int create_symlink(
1145                 const char *old_path,
1146                 const char *new_path,
1147                 bool force,
1148                 UnitFileChange **changes,
1149                 unsigned *n_changes) {
1150
1151         _cleanup_free_ char *dest = NULL;
1152         int r;
1153
1154         assert(old_path);
1155         assert(new_path);
1156
1157         mkdir_parents_label(new_path, 0755);
1158
1159         if (symlink(old_path, new_path) >= 0) {
1160                 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
1161                 return 0;
1162         }
1163
1164         if (errno != EEXIST)
1165                 return -errno;
1166
1167         r = readlink_and_make_absolute(new_path, &dest);
1168         if (r < 0)
1169                 return r;
1170
1171         if (path_equal(dest, old_path))
1172                 return 0;
1173
1174         if (!force)
1175                 return -EEXIST;
1176
1177         unlink(new_path);
1178
1179         if (symlink(old_path, new_path) >= 0) {
1180                 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL);
1181                 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
1182                 return 0;
1183         }
1184
1185         return -errno;
1186 }
1187
1188 static int install_info_symlink_alias(
1189                 InstallInfo *i,
1190                 const char *config_path,
1191                 bool force,
1192                 UnitFileChange **changes,
1193                 unsigned *n_changes) {
1194
1195         char **s;
1196         int r = 0, q;
1197
1198         assert(i);
1199         assert(config_path);
1200
1201         STRV_FOREACH(s, i->aliases) {
1202                 _cleanup_free_ char *alias_path = NULL, *dst = NULL;
1203
1204                 dst = install_full_printf(i, *s);
1205                 if (!dst)
1206                         return -ENOMEM;
1207
1208                 alias_path = path_make_absolute(dst, config_path);
1209                 if (!alias_path)
1210                         return -ENOMEM;
1211
1212                 q = create_symlink(i->path, alias_path, force, changes, n_changes);
1213                 if (r == 0)
1214                         r = q;
1215         }
1216
1217         return r;
1218 }
1219
1220 static int install_info_symlink_wants(
1221                 InstallInfo *i,
1222                 const char *config_path,
1223                 bool force,
1224                 UnitFileChange **changes,
1225                 unsigned *n_changes) {
1226
1227         char **s;
1228         int r = 0, q;
1229
1230         assert(i);
1231         assert(config_path);
1232
1233         STRV_FOREACH(s, i->wanted_by) {
1234                 _cleanup_free_ char *path = NULL, *dst = NULL;
1235
1236                 dst = install_full_printf(i, *s);
1237                 if (!dst)
1238                         return -ENOMEM;
1239
1240                 if (!unit_name_is_valid(dst, true)) {
1241                         r = -EINVAL;
1242                         continue;
1243                 }
1244
1245                 if (asprintf(&path, "%s/%s.wants/%s", config_path, dst, i->name) < 0)
1246                         return -ENOMEM;
1247
1248                 q = create_symlink(i->path, path, force, changes, n_changes);
1249
1250                 if (r == 0)
1251                         r = q;
1252         }
1253
1254         return r;
1255 }
1256
1257 static int install_info_symlink_requires(
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->required_by) {
1271                 _cleanup_free_ char *path = NULL, *dst = NULL;
1272
1273                 dst = install_full_printf(i, *s);
1274                 if (!dst)
1275                         return -ENOMEM;
1276
1277                 if (!unit_name_is_valid(dst, true)) {
1278                         r = -EINVAL;
1279                         continue;
1280                 }
1281
1282                 if (asprintf(&path, "%s/%s.requires/%s", config_path, dst, i->name) < 0)
1283                         return -ENOMEM;
1284
1285                 q = create_symlink(i->path, path, force, changes, n_changes);
1286
1287                 if (r == 0)
1288                         r = q;
1289         }
1290
1291         return r;
1292 }
1293
1294 static int install_info_symlink_link(
1295                 InstallInfo *i,
1296                 LookupPaths *paths,
1297                 const char *config_path,
1298                 bool force,
1299                 UnitFileChange **changes,
1300                 unsigned *n_changes) {
1301
1302         int r;
1303         _cleanup_free_ char *path = NULL;
1304
1305         assert(i);
1306         assert(paths);
1307         assert(config_path);
1308         assert(i->path);
1309
1310         r = in_search_path(i->path, paths->unit_path);
1311         if (r != 0)
1312                 return r;
1313
1314         if (asprintf(&path, "%s/%s", config_path, i->name) < 0)
1315                 return -ENOMEM;
1316
1317         r = create_symlink(i->path, path, force, changes, n_changes);
1318         return r;
1319 }
1320
1321 static int install_info_apply(
1322                 InstallInfo *i,
1323                 LookupPaths *paths,
1324                 const char *config_path,
1325                 bool force,
1326                 UnitFileChange **changes,
1327                 unsigned *n_changes) {
1328
1329         int r, q;
1330
1331         assert(i);
1332         assert(paths);
1333         assert(config_path);
1334
1335         r = install_info_symlink_alias(i, config_path, force, changes, n_changes);
1336
1337         q = install_info_symlink_wants(i, config_path, force, changes, n_changes);
1338         if (r == 0)
1339                 r = q;
1340
1341         q = install_info_symlink_requires(i, config_path, force, changes, n_changes);
1342         if (r == 0)
1343                 r = q;
1344
1345         q = install_info_symlink_link(i, paths, config_path, force, changes, n_changes);
1346         if (r == 0)
1347                 r = q;
1348
1349         return r;
1350 }
1351
1352 static int install_context_apply(
1353                 InstallContext *c,
1354                 LookupPaths *paths,
1355                 const char *config_path,
1356                 const char *root_dir,
1357                 bool force,
1358                 UnitFileChange **changes,
1359                 unsigned *n_changes) {
1360
1361         InstallInfo *i;
1362         int r = 0, q;
1363
1364         assert(c);
1365         assert(paths);
1366         assert(config_path);
1367
1368         while ((i = hashmap_first(c->will_install))) {
1369
1370                 q = hashmap_ensure_allocated(&c->have_installed, string_hash_func, string_compare_func);
1371                 if (q < 0)
1372                         return q;
1373
1374                 assert_se(hashmap_move_one(c->have_installed, c->will_install, i->name) == 0);
1375
1376                 q = unit_file_search(c, i, paths, root_dir, false);
1377                 if (q < 0) {
1378                         if (r >= 0)
1379                                 r = q;
1380
1381                         return r;
1382                 } else if (r >= 0)
1383                         r += q;
1384
1385                 q = install_info_apply(i, paths, config_path, force, changes, n_changes);
1386                 if (r >= 0 && q < 0)
1387                         r = q;
1388         }
1389
1390         return r;
1391 }
1392
1393 static int install_context_mark_for_removal(
1394                 InstallContext *c,
1395                 LookupPaths *paths,
1396                 Set **remove_symlinks_to,
1397                 const char *config_path,
1398                 const char *root_dir) {
1399
1400         InstallInfo *i;
1401         int r = 0, q;
1402
1403         assert(c);
1404         assert(paths);
1405         assert(config_path);
1406
1407         /* Marks all items for removal */
1408
1409         while ((i = hashmap_first(c->will_install))) {
1410
1411                 q = hashmap_ensure_allocated(&c->have_installed, string_hash_func, string_compare_func);
1412                 if (q < 0)
1413                         return q;
1414
1415                 assert_se(hashmap_move_one(c->have_installed, c->will_install, i->name) == 0);
1416
1417                 q = unit_file_search(c, i, paths, root_dir, false);
1418                 if (q < 0) {
1419                         if (r >= 0)
1420                                 r = q;
1421
1422                         return r;
1423                 } else if (r >= 0)
1424                         r += q;
1425
1426                 if (unit_name_is_instance(i->name)) {
1427                         char *unit_file = NULL;
1428
1429                         unit_file = path_get_file_name(i->path);
1430
1431                         if (unit_name_is_instance(unit_file))
1432                                 /* unit file named as instance exists, thus all symlinks pointing to it, will be removed */
1433                                 q = mark_symlink_for_removal(remove_symlinks_to, i->name);
1434                         else
1435                                 /* does not exist, thus we will mark for removal symlinks to template unit file */
1436                                 q = mark_symlink_for_removal(remove_symlinks_to, unit_file);
1437                 } else
1438                         q = mark_symlink_for_removal(remove_symlinks_to, i->name);
1439
1440                 if (r >= 0 && q < 0)
1441                         r = q;
1442         }
1443
1444         return r;
1445 }
1446
1447 int unit_file_enable(
1448                 UnitFileScope scope,
1449                 bool runtime,
1450                 const char *root_dir,
1451                 char *files[],
1452                 bool force,
1453                 UnitFileChange **changes,
1454                 unsigned *n_changes) {
1455
1456         _cleanup_lookup_paths_free_ LookupPaths paths = {};
1457         _cleanup_install_context_done_ InstallContext c = {};
1458         char **i;
1459         _cleanup_free_ char *config_path = NULL;
1460         int r;
1461
1462         assert(scope >= 0);
1463         assert(scope < _UNIT_FILE_SCOPE_MAX);
1464
1465         r = lookup_paths_init_from_scope(&paths, scope);
1466         if (r < 0)
1467                 return r;
1468
1469         r = get_config_path(scope, runtime, root_dir, &config_path);
1470         if (r < 0)
1471                 return r;
1472
1473         STRV_FOREACH(i, files) {
1474                 r = install_info_add_auto(&c, *i);
1475                 if (r < 0)
1476                         return r;
1477         }
1478
1479         /* This will return the number of symlink rules that were
1480         supposed to be created, not the ones actually created. This is
1481         useful to determine whether the passed files had any
1482         installation data at all. */
1483         r = install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes);
1484         return r;
1485 }
1486
1487 int unit_file_disable(
1488                 UnitFileScope scope,
1489                 bool runtime,
1490                 const char *root_dir,
1491                 char *files[],
1492                 UnitFileChange **changes,
1493                 unsigned *n_changes) {
1494
1495         _cleanup_lookup_paths_free_ LookupPaths paths = {};
1496         _cleanup_install_context_done_ InstallContext c = {};
1497         char **i;
1498         _cleanup_free_ char *config_path = NULL;
1499         _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
1500         int r, q;
1501
1502         assert(scope >= 0);
1503         assert(scope < _UNIT_FILE_SCOPE_MAX);
1504
1505         r = lookup_paths_init_from_scope(&paths, scope);
1506         if (r < 0)
1507                 return r;
1508
1509         r = get_config_path(scope, runtime, root_dir, &config_path);
1510         if (r < 0)
1511                 return r;
1512
1513         STRV_FOREACH(i, files) {
1514                 r = install_info_add_auto(&c, *i);
1515                 if (r < 0)
1516                         return r;
1517         }
1518
1519         r = install_context_mark_for_removal(&c, &paths, &remove_symlinks_to, config_path, root_dir);
1520
1521         q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
1522         if (r == 0)
1523                 r = q;
1524
1525         return r;
1526 }
1527
1528 int unit_file_reenable(
1529                 UnitFileScope scope,
1530                 bool runtime,
1531                 const char *root_dir,
1532                 char *files[],
1533                 bool force,
1534                 UnitFileChange **changes,
1535                 unsigned *n_changes) {
1536
1537         _cleanup_lookup_paths_free_ LookupPaths paths = {};
1538         _cleanup_install_context_done_ InstallContext c = {};
1539         char **i;
1540         _cleanup_free_ char *config_path = NULL;
1541         _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
1542         int r, q;
1543
1544         assert(scope >= 0);
1545         assert(scope < _UNIT_FILE_SCOPE_MAX);
1546
1547         r = lookup_paths_init_from_scope(&paths, scope);
1548         if (r < 0)
1549                 return r;
1550
1551         r = get_config_path(scope, runtime, root_dir, &config_path);
1552         if (r < 0)
1553                 return r;
1554
1555         STRV_FOREACH(i, files) {
1556                 r = mark_symlink_for_removal(&remove_symlinks_to, *i);
1557                 if (r < 0)
1558                         return r;
1559
1560                 r = install_info_add_auto(&c, *i);
1561                 if (r < 0)
1562                         return r;
1563         }
1564
1565         r = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
1566
1567         /* Returns number of symlinks that where supposed to be installed. */
1568         q = install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes);
1569         if (r == 0)
1570                 r = q;
1571
1572         return r;
1573 }
1574
1575 UnitFileState unit_file_get_state(
1576                 UnitFileScope scope,
1577                 const char *root_dir,
1578                 const char *name) {
1579
1580         _cleanup_lookup_paths_free_ LookupPaths paths = {};
1581         UnitFileState state = _UNIT_FILE_STATE_INVALID;
1582         char **i;
1583         _cleanup_free_ char *path = NULL;
1584         int r;
1585
1586         assert(scope >= 0);
1587         assert(scope < _UNIT_FILE_SCOPE_MAX);
1588         assert(name);
1589
1590         if (root_dir && scope != UNIT_FILE_SYSTEM)
1591                 return -EINVAL;
1592
1593         if (!unit_name_is_valid(name, true))
1594                 return -EINVAL;
1595
1596         r = lookup_paths_init_from_scope(&paths, scope);
1597         if (r < 0)
1598                 return r;
1599
1600         STRV_FOREACH(i, paths.unit_path) {
1601                 struct stat st;
1602
1603                 free(path);
1604                 path = NULL;
1605
1606                 if (root_dir)
1607                         asprintf(&path, "%s/%s/%s", root_dir, *i, name);
1608                 else
1609                         asprintf(&path, "%s/%s", *i, name);
1610
1611                 if (!path)
1612                         return -ENOMEM;
1613
1614                 if (lstat(path, &st) < 0) {
1615                         r = -errno;
1616                         if (errno == ENOENT)
1617                                 continue;
1618
1619                         return -errno;
1620                 }
1621
1622                 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode))
1623                         return -ENOENT;
1624
1625                 r = null_or_empty_path(path);
1626                 if (r < 0 && r != -ENOENT)
1627                         return r;
1628                 else if (r > 0) {
1629                         state = path_startswith(*i, "/run") ?
1630                                 UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
1631                         return state;
1632                 }
1633
1634                 r = find_symlinks_in_scope(scope, root_dir, name, &state);
1635                 if (r < 0)
1636                         return r;
1637                 else if (r > 0)
1638                         return state;
1639
1640                 r = unit_file_can_install(&paths, root_dir, path, true);
1641                 if (r < 0 && errno != ENOENT)
1642                         return r;
1643                 else if (r > 0)
1644                         return UNIT_FILE_DISABLED;
1645                 else if (r == 0)
1646                         return UNIT_FILE_STATIC;
1647         }
1648
1649         return r < 0 ? r : state;
1650 }
1651
1652 int unit_file_query_preset(UnitFileScope scope, const char *name) {
1653         _cleanup_strv_free_ char **files = NULL;
1654         char **i;
1655         int r;
1656
1657         assert(scope >= 0);
1658         assert(scope < _UNIT_FILE_SCOPE_MAX);
1659         assert(name);
1660
1661         if (scope == UNIT_FILE_SYSTEM)
1662                 r = conf_files_list(&files, ".preset", NULL,
1663                                     "/etc/systemd/system-preset",
1664                                     "/usr/local/lib/systemd/system-preset",
1665                                     "/usr/lib/systemd/system-preset",
1666 #ifdef HAVE_SPLIT_USR
1667                                     "/lib/systemd/system-preset",
1668 #endif
1669                                     NULL);
1670         else if (scope == UNIT_FILE_GLOBAL)
1671                 r = conf_files_list(&files, ".preset", NULL,
1672                                     "/etc/systemd/user-preset",
1673                                     "/usr/local/lib/systemd/user-preset",
1674                                     "/usr/lib/systemd/user-preset",
1675                                     NULL);
1676         else
1677                 return 1;
1678
1679         if (r < 0)
1680                 return r;
1681
1682         STRV_FOREACH(i, files) {
1683                 _cleanup_fclose_ FILE *f;
1684
1685                 f = fopen(*i, "re");
1686                 if (!f) {
1687                         if (errno == ENOENT)
1688                                 continue;
1689
1690                         return -errno;
1691                 }
1692
1693                 for (;;) {
1694                         char line[LINE_MAX], *l;
1695
1696                         if (!fgets(line, sizeof(line), f))
1697                                 break;
1698
1699                         l = strstrip(line);
1700                         if (!*l)
1701                                 continue;
1702
1703                         if (strchr(COMMENTS "\n", *l))
1704                                 continue;
1705
1706                         if (first_word(l, "enable")) {
1707                                 l += 6;
1708                                 l += strspn(l, WHITESPACE);
1709
1710                                 if (fnmatch(l, name, FNM_NOESCAPE) == 0)
1711                                         return 1;
1712
1713                         } else if (first_word(l, "disable")) {
1714                                 l += 7;
1715                                 l += strspn(l, WHITESPACE);
1716
1717                                 if (fnmatch(l, name, FNM_NOESCAPE) == 0)
1718                                         return 0;
1719
1720                         } else
1721                                 log_debug("Couldn't parse line '%s'", l);
1722                 }
1723         }
1724
1725         /* Default is "enable" */
1726         return 1;
1727 }
1728
1729 int unit_file_preset(
1730                 UnitFileScope scope,
1731                 bool runtime,
1732                 const char *root_dir,
1733                 char *files[],
1734                 bool force,
1735                 UnitFileChange **changes,
1736                 unsigned *n_changes) {
1737
1738         _cleanup_lookup_paths_free_ LookupPaths paths = {};
1739         _cleanup_install_context_done_ InstallContext plus = {}, minus = {};
1740         char **i;
1741         _cleanup_free_ char *config_path = NULL;
1742         _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
1743         int r, q;
1744
1745         assert(scope >= 0);
1746         assert(scope < _UNIT_FILE_SCOPE_MAX);
1747
1748         r = lookup_paths_init_from_scope(&paths, scope);
1749         if (r < 0)
1750                 return r;
1751
1752         r = get_config_path(scope, runtime, root_dir, &config_path);
1753         if (r < 0)
1754                 return r;
1755
1756         STRV_FOREACH(i, files) {
1757
1758                 if (!unit_name_is_valid(*i, true))
1759                         return -EINVAL;
1760
1761                 r = unit_file_query_preset(scope, *i);
1762                 if (r < 0)
1763                         return r;
1764
1765                 if (r)
1766                         r = install_info_add_auto(&plus, *i);
1767                 else
1768                         r = install_info_add_auto(&minus, *i);
1769
1770                 if (r < 0)
1771                         return r;
1772         }
1773
1774         r = install_context_mark_for_removal(&minus, &paths, &remove_symlinks_to,
1775                                              config_path, root_dir);
1776
1777         q = remove_marked_symlinks(remove_symlinks_to, config_path,
1778                                    changes, n_changes, files);
1779         if (r == 0)
1780                 r = q;
1781
1782         /* Returns number of symlinks that where supposed to be installed. */
1783         q = install_context_apply(&plus, &paths, config_path, root_dir, force,
1784                                   changes, n_changes);
1785         if (r == 0)
1786                 r = q;
1787
1788         return r;
1789 }
1790
1791 static void unitfilelist_free(UnitFileList **f) {
1792         if (!*f)
1793                 return;
1794
1795         free((*f)->path);
1796         free(*f);
1797 }
1798
1799 int unit_file_get_list(
1800                 UnitFileScope scope,
1801                 const char *root_dir,
1802                 Hashmap *h) {
1803
1804         _cleanup_lookup_paths_free_ LookupPaths paths = {};
1805         char **i;
1806         _cleanup_free_ char *buf = NULL;
1807         _cleanup_closedir_ DIR *d = NULL;
1808         int r;
1809
1810         assert(scope >= 0);
1811         assert(scope < _UNIT_FILE_SCOPE_MAX);
1812         assert(h);
1813
1814         if (root_dir && scope != UNIT_FILE_SYSTEM)
1815                 return -EINVAL;
1816
1817         r = lookup_paths_init_from_scope(&paths, scope);
1818         if (r < 0)
1819                 return r;
1820
1821         STRV_FOREACH(i, paths.unit_path) {
1822                 const char *units_dir;
1823
1824                 free(buf);
1825                 buf = NULL;
1826
1827                 if (root_dir) {
1828                         if (asprintf(&buf, "%s/%s", root_dir, *i) < 0)
1829                                 return -ENOMEM;
1830
1831                         units_dir = buf;
1832                 } else
1833                         units_dir = *i;
1834
1835                 if (d)
1836                         closedir(d);
1837
1838                 d = opendir(units_dir);
1839                 if (!d) {
1840                         if (errno == ENOENT)
1841                                 continue;
1842
1843                         return -errno;
1844                 }
1845
1846                 for (;;) {
1847                         struct dirent *de;
1848                         union dirent_storage buffer;
1849                         UnitFileList __attribute__((cleanup(unitfilelist_free)))
1850                                 *f = NULL;
1851
1852                         r = readdir_r(d, &buffer.de, &de);
1853                         if (r != 0)
1854                                 return -r;
1855
1856                         if (!de)
1857                                 break;
1858
1859                         if (ignore_file(de->d_name))
1860                                 continue;
1861
1862                         if (!unit_name_is_valid(de->d_name, true))
1863                                 continue;
1864
1865                         if (hashmap_get(h, de->d_name))
1866                                 continue;
1867
1868                         r = dirent_ensure_type(d, de);
1869                         if (r < 0) {
1870                                 if (r == -ENOENT)
1871                                         continue;
1872
1873                                 return r;
1874                         }
1875
1876                         if (de->d_type != DT_LNK && de->d_type != DT_REG)
1877                                 continue;
1878
1879                         f = new0(UnitFileList, 1);
1880                         if (!f)
1881                                 return -ENOMEM;
1882
1883                         f->path = path_make_absolute(de->d_name, units_dir);
1884                         if (!f->path)
1885                                 return -ENOMEM;
1886
1887                         r = null_or_empty_path(f->path);
1888                         if (r < 0 && r != -ENOENT)
1889                                 return r;
1890                         else if (r > 0) {
1891                                 f->state =
1892                                         path_startswith(*i, "/run") ?
1893                                         UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
1894                                 goto found;
1895                         }
1896
1897                         r = find_symlinks_in_scope(scope, root_dir, de->d_name, &f->state);
1898                         if (r < 0)
1899                                 return r;
1900                         else if (r > 0) {
1901                                 f->state = UNIT_FILE_ENABLED;
1902                                 goto found;
1903                         }
1904
1905                         r = unit_file_can_install(&paths, root_dir, f->path, true);
1906                         if (r == -EINVAL ||  /* Invalid setting? */
1907                             r == -EBADMSG || /* Invalid format? */
1908                             r == -ENOENT     /* Included file not found? */)
1909                                 f->state = UNIT_FILE_INVALID;
1910                         else if (r < 0)
1911                                 return r;
1912                         else if (r > 0)
1913                                 f->state = UNIT_FILE_DISABLED;
1914                         else
1915                                 f->state = UNIT_FILE_STATIC;
1916
1917                 found:
1918                         r = hashmap_put(h, path_get_file_name(f->path), f);
1919                         if (r < 0)
1920                                 return r;
1921                         f = NULL; /* prevent cleanup */
1922                 }
1923         }
1924
1925         return r;
1926 }
1927
1928 static const char* const unit_file_state_table[_UNIT_FILE_STATE_MAX] = {
1929         [UNIT_FILE_ENABLED] = "enabled",
1930         [UNIT_FILE_ENABLED_RUNTIME] = "enabled-runtime",
1931         [UNIT_FILE_LINKED] = "linked",
1932         [UNIT_FILE_LINKED_RUNTIME] = "linked-runtime",
1933         [UNIT_FILE_MASKED] = "masked",
1934         [UNIT_FILE_MASKED_RUNTIME] = "masked-runtime",
1935         [UNIT_FILE_STATIC] = "static",
1936         [UNIT_FILE_DISABLED] = "disabled",
1937         [UNIT_FILE_INVALID] = "invalid",
1938 };
1939
1940 DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState);
1941
1942 static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX] = {
1943         [UNIT_FILE_SYMLINK] = "symlink",
1944         [UNIT_FILE_UNLINK] = "unlink",
1945 };
1946
1947 DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType);