chiark / gitweb /
bus: introduce "trusted" bus concept and encode access control in object vtables
[elogind.git] / src / core / load-dropin.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2010 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 <dirent.h>
23 #include <errno.h>
24
25 #include "unit.h"
26 #include "load-dropin.h"
27 #include "log.h"
28 #include "strv.h"
29 #include "unit-name.h"
30 #include "conf-parser.h"
31 #include "load-fragment.h"
32 #include "conf-files.h"
33
34 static int iterate_dir(
35                 Unit *u,
36                 const char *path,
37                 UnitDependency dependency,
38                 char ***strv) {
39
40         _cleanup_closedir_ DIR *d = NULL;
41         int r;
42
43         assert(u);
44         assert(path);
45
46         /* The config directories are special, since the order of the
47          * drop-ins matters */
48         if (dependency < 0)  {
49                 r = strv_extend(strv, path);
50                 if (r < 0)
51                         return log_oom();
52
53                 return 0;
54         }
55
56         d = opendir(path);
57         if (!d) {
58                 if (errno == ENOENT)
59                         return 0;
60
61                 return -errno;
62         }
63
64         for (;;) {
65                 struct dirent *de;
66                 union dirent_storage buf;
67                 _cleanup_free_ char *f = NULL;
68                 int k;
69
70                 k = readdir_r(d, &buf.de, &de);
71                 if (k != 0) {
72                         log_error("Failed to read directory %s: %s", path, strerror(k));
73                         return -k;
74                 }
75
76                 if (!de)
77                         break;
78
79                 if (ignore_file(de->d_name))
80                         continue;
81
82                 f = strjoin(path, "/", de->d_name, NULL);
83                 if (!f)
84                         return log_oom();
85
86                 r = unit_add_dependency_by_name(u, dependency, de->d_name, f, true);
87                 if (r < 0)
88                         log_error("Cannot add dependency %s to %s, ignoring: %s", de->d_name, u->id, strerror(-r));
89         }
90
91         return 0;
92 }
93
94 static int process_dir(
95                 Unit *u,
96                 const char *unit_path,
97                 const char *name,
98                 const char *suffix,
99                 UnitDependency dependency,
100                 char ***strv) {
101
102         int r;
103         char *path;
104
105         assert(u);
106         assert(unit_path);
107         assert(name);
108         assert(suffix);
109
110         path = strjoin(unit_path, "/", name, suffix, NULL);
111         if (!path)
112                 return log_oom();
113
114         if (u->manager->unit_path_cache &&
115             !set_get(u->manager->unit_path_cache, path))
116                 r = 0;
117         else
118                 r = iterate_dir(u, path, dependency, strv);
119         free(path);
120
121         if (r < 0)
122                 return r;
123
124         if (u->instance) {
125                 char *template;
126                 /* Also try the template dir */
127
128                 template = unit_name_template(name);
129                 if (!template)
130                         return log_oom();
131
132                 path = strjoin(unit_path, "/", template, suffix, NULL);
133                 free(template);
134
135                 if (!path)
136                         return log_oom();
137
138                 if (u->manager->unit_path_cache &&
139                     !set_get(u->manager->unit_path_cache, path))
140                         r = 0;
141                 else
142                         r = iterate_dir(u, path, dependency, strv);
143                 free(path);
144
145                 if (r < 0)
146                         return r;
147         }
148
149         return 0;
150 }
151
152 char **unit_find_dropin_paths(Unit *u) {
153         _cleanup_strv_free_ char **strv = NULL;
154         char **configs = NULL;
155         Iterator i;
156         char *t;
157         int r;
158
159         assert(u);
160
161         SET_FOREACH(t, u->names, i) {
162                 char **p;
163
164                 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
165                         /* This loads the drop-in config snippets */
166                         r = process_dir(u, *p, t, ".d", _UNIT_DEPENDENCY_INVALID, &strv);
167                         if (r < 0)
168                                 return NULL;
169                 }
170         }
171
172         if (strv_isempty(strv))
173                 return NULL;
174
175         r = conf_files_list_strv(&configs, ".conf", NULL, (const char**) strv);
176         if (r < 0) {
177                 log_error("Failed to get list of configuration files: %s", strerror(-r));
178                 strv_free(configs);
179                 return NULL;
180         }
181
182         return configs;
183 }
184
185 int unit_load_dropin(Unit *u) {
186         Iterator i;
187         char *t, **f;
188         int r;
189
190         assert(u);
191
192         /* Load dependencies from supplementary drop-in directories */
193
194         SET_FOREACH(t, u->names, i) {
195                 char **p;
196
197                 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
198                         r = process_dir(u, *p, t, ".wants", UNIT_WANTS, NULL);
199                         if (r < 0)
200                                 return r;
201
202                         r = process_dir(u, *p, t, ".requires", UNIT_REQUIRES, NULL);
203                         if (r < 0)
204                                 return r;
205                 }
206         }
207
208         u->dropin_paths = unit_find_dropin_paths(u);
209         if (! u->dropin_paths)
210                 return 0;
211
212         STRV_FOREACH(f, u->dropin_paths) {
213                 r = config_parse(u->id, *f, NULL,
214                                  UNIT_VTABLE(u)->sections, config_item_perf_lookup,
215                                  (void*) load_fragment_gperf_lookup, false, false, u);
216                 if (r < 0)
217                         return r;
218         }
219
220         u->dropin_mtime = now(CLOCK_REALTIME);
221
222         return 0;
223 }