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