chiark / gitweb /
Move dropin listing to shared
[elogind.git] / src / shared / 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 2014 Zbigniew JÄ™drzejewski-Szmek
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 "dropin.h"
23 #include "util.h"
24 #include "strv.h"
25 #include "mkdir.h"
26 #include "fileio-label.h"
27 #include "conf-files.h"
28
29 int drop_in_file(const char *dir, const char *unit, unsigned level,
30                  const char *name, char **_p, char **_q) {
31
32         _cleanup_free_ char *b = NULL;
33         char *p, *q;
34
35         char prefix[DECIMAL_STR_MAX(unsigned)];
36
37         assert(unit);
38         assert(name);
39         assert(_p);
40         assert(_q);
41
42         sprintf(prefix, "%u", level);
43
44         b = xescape(name, "/.");
45         if (!b)
46                 return -ENOMEM;
47
48         if (!filename_is_valid(b))
49                 return -EINVAL;
50
51         p = strjoin(dir, "/", unit, ".d", NULL);
52         if (!p)
53                 return -ENOMEM;
54
55         q = strjoin(p, "/", prefix, "-", b, ".conf", NULL);
56         if (!q) {
57                 free(p);
58                 return -ENOMEM;
59         }
60
61         *_p = p;
62         *_q = q;
63         return 0;
64 }
65
66 int write_drop_in(const char *dir, const char *unit, unsigned level,
67                   const char *name, const char *data) {
68
69         _cleanup_free_ char *p = NULL, *q = NULL;
70         int r;
71
72         assert(dir);
73         assert(unit);
74         assert(name);
75         assert(data);
76
77         r = drop_in_file(dir, unit, level, name, &p, &q);
78         if (r < 0)
79                 return r;
80
81         mkdir_p(p, 0755);
82         return write_string_file_atomic_label(q, data);
83 }
84
85 int write_drop_in_format(const char *dir, const char *unit, unsigned level,
86                          const char *name, const char *format, ...) {
87         _cleanup_free_ char *p = NULL;
88         va_list ap;
89         int r;
90
91         assert(dir);
92         assert(unit);
93         assert(name);
94         assert(format);
95
96         va_start(ap, format);
97         r = vasprintf(&p, format, ap);
98         va_end(ap);
99
100         if (r < 0)
101                 return -ENOMEM;
102
103         return write_drop_in(dir, unit, level, name, p);
104 }
105
106 static int iterate_dir(
107                 const char *path,
108                 UnitDependency dependency,
109                 dependency_consumer_t consumer,
110                 void *arg,
111                 char ***strv) {
112
113         _cleanup_closedir_ DIR *d = NULL;
114         int r;
115
116         assert(path);
117
118         /* The config directories are special, since the order of the
119          * drop-ins matters */
120         if (dependency < 0)  {
121                 r = strv_extend(strv, path);
122                 if (r < 0)
123                         return log_oom();
124
125                 return 0;
126         }
127
128         assert(consumer);
129
130         d = opendir(path);
131         if (!d) {
132                 if (errno == ENOENT)
133                         return 0;
134
135                 log_error_errno(errno, "Failed to open directory %s: %m", path);
136                 return -errno;
137         }
138
139         for (;;) {
140                 struct dirent *de;
141                 _cleanup_free_ char *f = NULL;
142
143                 errno = 0;
144                 de = readdir(d);
145                 if (!de && errno != 0)
146                         return log_error_errno(errno, "Failed to read directory %s: %m", path);
147
148                 if (!de)
149                         break;
150
151                 if (ignore_file(de->d_name))
152                         continue;
153
154                 f = strjoin(path, "/", de->d_name, NULL);
155                 if (!f)
156                         return log_oom();
157
158                 r = consumer(dependency, de->d_name, f, arg);
159                 if (r < 0)
160                         return r;
161         }
162
163         return 0;
164 }
165
166 int unit_file_process_dir(
167                 Set * unit_path_cache,
168                 const char *unit_path,
169                 const char *name,
170                 const char *suffix,
171                 UnitDependency dependency,
172                 dependency_consumer_t consumer,
173                 void *arg,
174                 char ***strv) {
175
176         _cleanup_free_ char *path = NULL;
177
178         assert(unit_path);
179         assert(name);
180         assert(suffix);
181
182         path = strjoin(unit_path, "/", name, suffix, NULL);
183         if (!path)
184                 return log_oom();
185
186         if (!unit_path_cache || set_get(unit_path_cache, path))
187                 iterate_dir(path, dependency, consumer, arg, strv);
188
189         if (unit_name_is_instance(name)) {
190                 _cleanup_free_ char *template = NULL, *p = NULL;
191                 /* Also try the template dir */
192
193                 template = unit_name_template(name);
194                 if (!template)
195                         return log_oom();
196
197                 p = strjoin(unit_path, "/", template, suffix, NULL);
198                 if (!p)
199                         return log_oom();
200
201                 if (!unit_path_cache || set_get(unit_path_cache, p))
202                         iterate_dir(p, dependency, consumer, arg, strv);
203         }
204
205         return 0;
206 }
207
208 int unit_file_find_dropin_paths(
209                 char **lookup_path,
210                 Set *unit_path_cache,
211                 Set *names,
212                 char ***paths) {
213
214         _cleanup_strv_free_ char **strv = NULL, **ans = NULL;
215         Iterator i;
216         char *t;
217         int r;
218
219         assert(paths);
220
221         SET_FOREACH(t, names, i) {
222                 char **p;
223
224                 STRV_FOREACH(p, lookup_path)
225                         unit_file_process_dir(unit_path_cache, *p, t, ".d", _UNIT_DEPENDENCY_INVALID, NULL, NULL, &strv);
226         }
227
228         if (strv_isempty(strv))
229                 return 0;
230
231         r = conf_files_list_strv(&ans, ".conf", NULL, (const char**) strv);
232         if (r < 0)
233                 return log_warning_errno(r, "Failed to get list of configuration files: %m");
234
235         *paths = ans;
236         ans = NULL;
237         return 1;
238 }