chiark / gitweb /
core: replace readdir_r with readdir
[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                 _cleanup_free_ char *f = NULL;
67                 int k;
68
69                 errno = 0;
70                 de = readdir(d);
71                 if (!de && errno != 0) {
72                         k = errno;
73                         log_error("Failed to read directory %s: %s", path, strerror(k));
74                         return -k;
75                 }
76
77                 if (!de)
78                         break;
79
80                 if (ignore_file(de->d_name))
81                         continue;
82
83                 f = strjoin(path, "/", de->d_name, NULL);
84                 if (!f)
85                         return log_oom();
86
87                 r = unit_add_dependency_by_name(u, dependency, de->d_name, f, true);
88                 if (r < 0)
89                         log_error("Cannot add dependency %s to %s, ignoring: %s", de->d_name, u->id, strerror(-r));
90         }
91
92         return 0;
93 }
94
95 static int process_dir(
96                 Unit *u,
97                 const char *unit_path,
98                 const char *name,
99                 const char *suffix,
100                 UnitDependency dependency,
101                 char ***strv) {
102
103         int r;
104         char *path;
105
106         assert(u);
107         assert(unit_path);
108         assert(name);
109         assert(suffix);
110
111         path = strjoin(unit_path, "/", name, suffix, NULL);
112         if (!path)
113                 return log_oom();
114
115         if (u->manager->unit_path_cache &&
116             !set_get(u->manager->unit_path_cache, path))
117                 r = 0;
118         else
119                 r = iterate_dir(u, path, dependency, strv);
120         free(path);
121
122         if (r < 0)
123                 return r;
124
125         if (u->instance) {
126                 char *template;
127                 /* Also try the template dir */
128
129                 template = unit_name_template(name);
130                 if (!template)
131                         return log_oom();
132
133                 path = strjoin(unit_path, "/", template, suffix, NULL);
134                 free(template);
135
136                 if (!path)
137                         return log_oom();
138
139                 if (u->manager->unit_path_cache &&
140                     !set_get(u->manager->unit_path_cache, path))
141                         r = 0;
142                 else
143                         r = iterate_dir(u, path, dependency, strv);
144                 free(path);
145
146                 if (r < 0)
147                         return r;
148         }
149
150         return 0;
151 }
152
153 char **unit_find_dropin_paths(Unit *u) {
154         _cleanup_strv_free_ char **strv = NULL;
155         char **configs = NULL;
156         Iterator i;
157         char *t;
158         int r;
159
160         assert(u);
161
162         SET_FOREACH(t, u->names, i) {
163                 char **p;
164
165                 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
166                         /* This loads the drop-in config snippets */
167                         r = process_dir(u, *p, t, ".d", _UNIT_DEPENDENCY_INVALID, &strv);
168                         if (r < 0)
169                                 return NULL;
170                 }
171         }
172
173         if (strv_isempty(strv))
174                 return NULL;
175
176         r = conf_files_list_strv(&configs, ".conf", NULL, (const char**) strv);
177         if (r < 0) {
178                 log_error("Failed to get list of configuration files: %s", strerror(-r));
179                 strv_free(configs);
180                 return NULL;
181         }
182
183         return configs;
184 }
185
186 int unit_load_dropin(Unit *u) {
187         Iterator i;
188         char *t, **f;
189         int r;
190
191         assert(u);
192
193         /* Load dependencies from supplementary drop-in directories */
194
195         SET_FOREACH(t, u->names, i) {
196                 char **p;
197
198                 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
199                         r = process_dir(u, *p, t, ".wants", UNIT_WANTS, NULL);
200                         if (r < 0)
201                                 return r;
202
203                         r = process_dir(u, *p, t, ".requires", UNIT_REQUIRES, NULL);
204                         if (r < 0)
205                                 return r;
206                 }
207         }
208
209         u->dropin_paths = unit_find_dropin_paths(u);
210         if (! u->dropin_paths)
211                 return 0;
212
213         STRV_FOREACH(f, u->dropin_paths) {
214                 r = config_parse(u->id, *f, NULL,
215                                  UNIT_VTABLE(u)->sections, config_item_perf_lookup,
216                                  (void*) load_fragment_gperf_lookup, false, false, u);
217                 if (r < 0)
218                         return r;
219         }
220
221         u->dropin_mtime = now(CLOCK_REALTIME);
222
223         return 0;
224 }