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