chiark / gitweb /
Prep v220: Use new cgroups functions
[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 (hidden_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         int r;
178
179         assert(unit_path);
180         assert(name);
181         assert(suffix);
182
183         path = strjoin(unit_path, "/", name, suffix, NULL);
184         if (!path)
185                 return log_oom();
186
187         if (!unit_path_cache || set_get(unit_path_cache, path))
188                 (void) iterate_dir(path, dependency, consumer, arg, strv);
189
190         if (unit_name_is_valid(name, UNIT_NAME_INSTANCE)) {
191                 _cleanup_free_ char *template = NULL, *p = NULL;
192                 /* Also try the template dir */
193
194                 r = unit_name_template(name, &template);
195                 if (r < 0)
196                         return log_error_errno(r, "Failed to generate template from unit name: %m");
197
198                 p = strjoin(unit_path, "/", template, suffix, NULL);
199                 if (!p)
200                         return log_oom();
201
202                 if (!unit_path_cache || set_get(unit_path_cache, p))
203                         (void) iterate_dir(p, dependency, consumer, arg, strv);
204         }
205
206         return 0;
207 }
208
209 int unit_file_find_dropin_paths(
210                 char **lookup_path,
211                 Set *unit_path_cache,
212                 Set *names,
213                 char ***paths) {
214
215         _cleanup_strv_free_ char **strv = NULL, **ans = NULL;
216         Iterator i;
217         char *t;
218         int r;
219
220         assert(paths);
221
222         SET_FOREACH(t, names, i) {
223                 char **p;
224
225                 STRV_FOREACH(p, lookup_path)
226                         unit_file_process_dir(unit_path_cache, *p, t, ".d", _UNIT_DEPENDENCY_INVALID, NULL, NULL, &strv);
227         }
228
229         if (strv_isempty(strv))
230                 return 0;
231
232         r = conf_files_list_strv(&ans, ".conf", NULL, (const char**) strv);
233         if (r < 0)
234                 return log_warning_errno(r, "Failed to get list of configuration files: %m");
235
236         *paths = ans;
237         ans = NULL;
238         return 1;
239 }