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