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