chiark / gitweb /
core/busname: add lookup string for BUSNAME_FAILURE_SERVICE_FAILED_PERMANENT
[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         _cleanup_free_ char *path = NULL;
104         int r;
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 || set_get(u->manager->unit_path_cache, path)) {
116                 r = iterate_dir(u, path, dependency, strv);
117                 if (r < 0)
118                         return r;
119         }
120
121         if (u->instance) {
122                 _cleanup_free_ char *template = NULL, *p = NULL;
123                 /* Also try the template dir */
124
125                 template = unit_name_template(name);
126                 if (!template)
127                         return log_oom();
128
129                 p = strjoin(unit_path, "/", template, suffix, NULL);
130                 if (!p)
131                         return log_oom();
132
133                 if (!u->manager->unit_path_cache || set_get(u->manager->unit_path_cache, p)) {
134                         r = iterate_dir(u, p, dependency, strv);
135                         if (r < 0)
136                                 return r;
137                 }
138         }
139
140         return 0;
141 }
142
143 char **unit_find_dropin_paths(Unit *u) {
144         _cleanup_strv_free_ char **strv = NULL;
145         char **configs = NULL;
146         Iterator i;
147         char *t;
148         int r;
149
150         assert(u);
151
152         SET_FOREACH(t, u->names, i) {
153                 char **p;
154
155                 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
156                         /* This loads the drop-in config snippets */
157                         r = process_dir(u, *p, t, ".d", _UNIT_DEPENDENCY_INVALID, &strv);
158                         if (r < 0)
159                                 return NULL;
160                 }
161         }
162
163         if (strv_isempty(strv))
164                 return NULL;
165
166         r = conf_files_list_strv(&configs, ".conf", NULL, (const char**) strv);
167         if (r < 0) {
168                 log_error("Failed to get list of configuration files: %s", strerror(-r));
169                 strv_free(configs);
170                 return NULL;
171         }
172
173         return configs;
174 }
175
176 int unit_load_dropin(Unit *u) {
177         Iterator i;
178         char *t, **f;
179         int r;
180
181         assert(u);
182
183         /* Load dependencies from supplementary drop-in directories */
184
185         SET_FOREACH(t, u->names, i) {
186                 char **p;
187
188                 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
189                         r = process_dir(u, *p, t, ".wants", UNIT_WANTS, NULL);
190                         if (r < 0)
191                                 return r;
192
193                         r = process_dir(u, *p, t, ".requires", UNIT_REQUIRES, NULL);
194                         if (r < 0)
195                                 return r;
196                 }
197         }
198
199         u->dropin_paths = unit_find_dropin_paths(u);
200         if (! u->dropin_paths)
201                 return 0;
202
203         STRV_FOREACH(f, u->dropin_paths) {
204                 r = config_parse(u->id, *f, NULL,
205                                  UNIT_VTABLE(u)->sections, config_item_perf_lookup,
206                                  (void*) load_fragment_gperf_lookup, false, false, u);
207                 if (r < 0)
208                         return r;
209         }
210
211         u->dropin_mtime = now(CLOCK_REALTIME);
212
213         return 0;
214 }