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