]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/dropin.c
Merge pull request #1412 from zonque/strempty
[thirdparty/systemd.git] / src / shared / dropin.c
CommitLineData
29686440
ZJS
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"
1a7f1b38 24#include "strv.h"
29686440
ZJS
25#include "mkdir.h"
26#include "fileio-label.h"
1a7f1b38 27#include "conf-files.h"
29686440 28
8eea8687 29int drop_in_file(const char *dir, const char *unit, unsigned level,
29686440
ZJS
30 const char *name, char **_p, char **_q) {
31
32 _cleanup_free_ char *b = NULL;
33 char *p, *q;
34
8eea8687
ZJS
35 char prefix[DECIMAL_STR_MAX(unsigned)];
36
29686440
ZJS
37 assert(unit);
38 assert(name);
39 assert(_p);
40 assert(_q);
41
8eea8687
ZJS
42 sprintf(prefix, "%u", level);
43
29686440
ZJS
44 b = xescape(name, "/.");
45 if (!b)
46 return -ENOMEM;
47
ae6c3cc0 48 if (!filename_is_valid(b))
29686440
ZJS
49 return -EINVAL;
50
51 p = strjoin(dir, "/", unit, ".d", NULL);
52 if (!p)
53 return -ENOMEM;
54
8eea8687 55 q = strjoin(p, "/", prefix, "-", b, ".conf", NULL);
29686440
ZJS
56 if (!q) {
57 free(p);
58 return -ENOMEM;
59 }
60
61 *_p = p;
62 *_q = q;
63 return 0;
64}
65
8eea8687 66int write_drop_in(const char *dir, const char *unit, unsigned level,
29686440
ZJS
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
8eea8687 77 r = drop_in_file(dir, unit, level, name, &p, &q);
29686440
ZJS
78 if (r < 0)
79 return r;
80
81 mkdir_p(p, 0755);
82 return write_string_file_atomic_label(q, data);
83}
84
8eea8687 85int write_drop_in_format(const char *dir, const char *unit, unsigned level,
29686440
ZJS
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
8eea8687 103 return write_drop_in(dir, unit, level, name, p);
29686440 104}
1a7f1b38
ZJS
105
106static 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
a34bf9db 151 if (hidden_file(de->d_name))
1a7f1b38
ZJS
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
166int unit_file_process_dir(
7410616c 167 Set *unit_path_cache,
1a7f1b38
ZJS
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;
7410616c 177 int r;
1a7f1b38
ZJS
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))
7410616c 188 (void) iterate_dir(path, dependency, consumer, arg, strv);
1a7f1b38 189
7410616c 190 if (unit_name_is_valid(name, UNIT_NAME_INSTANCE)) {
1a7f1b38
ZJS
191 _cleanup_free_ char *template = NULL, *p = NULL;
192 /* Also try the template dir */
193
7410616c
LP
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");
1a7f1b38
ZJS
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))
7410616c 203 (void) iterate_dir(p, dependency, consumer, arg, strv);
1a7f1b38
ZJS
204 }
205
206 return 0;
207}
208
209int 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}