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