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