]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/dropin.c
Merge pull request #6853 from sourcejedi/GetAll
[thirdparty/systemd.git] / src / shared / dropin.c
1 /***
2 This file is part of systemd.
3
4 Copyright 2014 Zbigniew Jędrzejewski-Szmek
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <errno.h>
21 #include <stdarg.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24
25 #include "alloc-util.h"
26 #include "conf-files.h"
27 #include "dirent-util.h"
28 #include "dropin.h"
29 #include "escape.h"
30 #include "fd-util.h"
31 #include "fileio-label.h"
32 #include "fs-util.h"
33 #include "hashmap.h"
34 #include "log.h"
35 #include "macro.h"
36 #include "mkdir.h"
37 #include "path-util.h"
38 #include "set.h"
39 #include "string-util.h"
40 #include "strv.h"
41 #include "unit-name.h"
42
43 int drop_in_file(const char *dir, const char *unit, unsigned level,
44 const char *name, char **_p, char **_q) {
45
46 char prefix[DECIMAL_STR_MAX(unsigned)];
47 _cleanup_free_ char *b = NULL;
48 char *p, *q;
49
50 assert(unit);
51 assert(name);
52 assert(_p);
53 assert(_q);
54
55 sprintf(prefix, "%u", level);
56
57 b = xescape(name, "/.");
58 if (!b)
59 return -ENOMEM;
60
61 if (!filename_is_valid(b))
62 return -EINVAL;
63
64 p = strjoin(dir, "/", unit, ".d");
65 if (!p)
66 return -ENOMEM;
67
68 q = strjoin(p, "/", prefix, "-", b, ".conf");
69 if (!q) {
70 free(p);
71 return -ENOMEM;
72 }
73
74 *_p = p;
75 *_q = q;
76 return 0;
77 }
78
79 int write_drop_in(const char *dir, const char *unit, unsigned level,
80 const char *name, const char *data) {
81
82 _cleanup_free_ char *p = NULL, *q = NULL;
83 int r;
84
85 assert(dir);
86 assert(unit);
87 assert(name);
88 assert(data);
89
90 r = drop_in_file(dir, unit, level, name, &p, &q);
91 if (r < 0)
92 return r;
93
94 (void) mkdir_p(p, 0755);
95 return write_string_file_atomic_label(q, data);
96 }
97
98 int write_drop_in_format(const char *dir, const char *unit, unsigned level,
99 const char *name, const char *format, ...) {
100 _cleanup_free_ char *p = NULL;
101 va_list ap;
102 int r;
103
104 assert(dir);
105 assert(unit);
106 assert(name);
107 assert(format);
108
109 va_start(ap, format);
110 r = vasprintf(&p, format, ap);
111 va_end(ap);
112
113 if (r < 0)
114 return -ENOMEM;
115
116 return write_drop_in(dir, unit, level, name, p);
117 }
118
119 static int unit_file_find_dir(
120 const char *original_root,
121 const char *path,
122 char ***dirs) {
123
124 _cleanup_free_ char *chased = NULL;
125 int r;
126
127 assert(path);
128
129 r = chase_symlinks(path, original_root, 0, &chased);
130 if (r == -ENOENT) /* Ignore -ENOENT, after all most units won't have a drop-in dir */
131 return 0;
132 if (r < 0)
133 return log_full_errno(LOG_WARNING, r, "Failed to canonicalize path %s: %m", path);
134
135 r = strv_push(dirs, chased);
136 if (r < 0)
137 return log_oom();
138
139 chased = NULL;
140 return 0;
141 }
142
143 static int unit_file_find_dirs(
144 const char *original_root,
145 Set *unit_path_cache,
146 const char *unit_path,
147 const char *name,
148 const char *suffix,
149 char ***dirs) {
150
151 char *path;
152 int r;
153
154 assert(unit_path);
155 assert(name);
156 assert(suffix);
157
158 path = strjoina(unit_path, "/", name, suffix);
159
160 if (!unit_path_cache || set_get(unit_path_cache, path)) {
161 r = unit_file_find_dir(original_root, path, dirs);
162 if (r < 0)
163 return r;
164 }
165
166 if (unit_name_is_valid(name, UNIT_NAME_INSTANCE)) {
167 /* Also try the template dir */
168
169 _cleanup_free_ char *template = NULL;
170
171 r = unit_name_template(name, &template);
172 if (r < 0)
173 return log_error_errno(r, "Failed to generate template from unit name: %m");
174
175 return unit_file_find_dirs(original_root, unit_path_cache, unit_path, template, suffix, dirs);
176 }
177
178 return 0;
179 }
180
181 int unit_file_find_dropin_paths(
182 const char *original_root,
183 char **lookup_path,
184 Set *unit_path_cache,
185 const char *dir_suffix,
186 const char *file_suffix,
187 Set *names,
188 char ***ret) {
189
190 _cleanup_strv_free_ char **dirs = NULL;
191 Iterator i;
192 char *t, **p;
193 int r;
194
195 assert(ret);
196
197 SET_FOREACH(t, names, i)
198 STRV_FOREACH(p, lookup_path)
199 unit_file_find_dirs(original_root, unit_path_cache, *p, t, dir_suffix, &dirs);
200
201 if (strv_isempty(dirs)) {
202 *ret = NULL;
203 return 0;
204 }
205
206 r = conf_files_list_strv(ret, file_suffix, NULL, 0, (const char**) dirs);
207 if (r < 0)
208 return log_warning_errno(r, "Failed to create the list of configuration files: %m");
209
210 return 1;
211 }