]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/dropin.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
8 #include "alloc-util.h"
9 #include "chase-symlinks.h"
10 #include "conf-files.h"
11 #include "dirent-util.h"
15 #include "fileio-label.h"
20 #include "path-util.h"
22 #include "string-util.h"
24 #include "unit-name.h"
26 int drop_in_file(const char *dir
, const char *unit
, unsigned level
,
27 const char *name
, char **ret_p
, char **ret_q
) {
29 char prefix
[DECIMAL_STR_MAX(unsigned)];
30 _cleanup_free_
char *b
= NULL
, *p
= NULL
, *q
= NULL
;
37 sprintf(prefix
, "%u", level
);
39 b
= xescape(name
, "/.");
43 if (!filename_is_valid(b
))
46 p
= strjoin(dir
, "/", unit
, ".d");
47 q
= strjoin(p
, "/", prefix
, "-", b
, ".conf");
56 int write_drop_in(const char *dir
, const char *unit
, unsigned level
,
57 const char *name
, const char *data
) {
59 _cleanup_free_
char *p
= NULL
, *q
= NULL
;
67 r
= drop_in_file(dir
, unit
, level
, name
, &p
, &q
);
71 (void) mkdir_p(p
, 0755);
72 return write_string_file_atomic_label(q
, data
);
75 int write_drop_in_format(const char *dir
, const char *unit
, unsigned level
,
76 const char *name
, const char *format
, ...) {
77 _cleanup_free_
char *p
= NULL
;
87 r
= vasprintf(&p
, format
, ap
);
93 return write_drop_in(dir
, unit
, level
, name
, p
);
96 static int unit_file_add_dir(
97 const char *original_root
,
101 _cleanup_free_
char *chased
= NULL
;
106 /* This adds [original_root]/path to dirs, if it exists. */
108 r
= chase_symlinks(path
, original_root
, 0, &chased
, NULL
);
109 if (r
== -ENOENT
) /* Ignore -ENOENT, after all most units won't have a drop-in dir. */
111 if (r
== -ENAMETOOLONG
) {
112 /* Also, ignore -ENAMETOOLONG but log about it. After all, users are not even able to create the
113 * drop-in dir in such case. This mostly happens for device units with an overly long /sys path. */
114 log_debug_errno(r
, "Path '%s' too long, couldn't canonicalize, ignoring.", path
);
118 return log_warning_errno(r
, "Failed to canonicalize path '%s': %m", path
);
120 if (strv_consume(dirs
, TAKE_PTR(chased
)) < 0)
126 static int unit_file_find_dirs(
127 const char *original_root
,
128 Set
*unit_path_cache
,
129 const char *unit_path
,
134 _cleanup_free_
char *prefix
= NULL
, *instance
= NULL
, *built
= NULL
;
135 bool is_instance
, chopped
;
146 path
= strjoina(unit_path
, "/", name
, suffix
);
147 if (!unit_path_cache
|| set_get(unit_path_cache
, path
)) {
148 r
= unit_file_add_dir(original_root
, path
, dirs
);
153 is_instance
= unit_name_is_valid(name
, UNIT_NAME_INSTANCE
);
154 if (is_instance
) { /* Also try the template dir */
155 _cleanup_free_
char *template = NULL
;
157 r
= unit_name_template(name
, &template);
159 return log_error_errno(r
, "Failed to generate template from unit name: %m");
161 r
= unit_file_find_dirs(original_root
, unit_path_cache
, unit_path
, template, suffix
, dirs
);
166 /* Return early for top level drop-ins. */
167 if (unit_type_from_string(name
) >= 0)
170 /* Let's see if there's a "-" prefix for this unit name. If so, let's invoke ourselves for it. This will then
171 * recursively do the same for all our prefixes. i.e. this means given "foo-bar-waldo.service" we'll also
172 * search "foo-bar-.service" and "foo-.service".
174 * Note the order in which we do it: we traverse up adding drop-ins on each step. This means the more specific
175 * drop-ins may override the more generic drop-ins, which is the intended behaviour. */
177 r
= unit_name_to_prefix(name
, &prefix
);
179 return log_error_errno(r
, "Failed to derive unit name prefix from unit name: %m");
183 dash
= strrchr(prefix
, '-');
184 if (!dash
) /* No dash? if so we are done */
187 n
= (size_t) (dash
- prefix
);
188 if (n
== 0) /* Leading dash? If so, we are done */
191 if (prefix
[n
+1] != 0 || chopped
) {
196 /* Trailing dash? If so, chop it off and try again, but not more than once. */
201 if (!unit_prefix_is_valid(prefix
))
204 type
= unit_name_to_type(name
);
206 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
207 "Failed to derive unit type from unit name: %s",
211 r
= unit_name_to_instance(name
, &instance
);
213 return log_error_errno(r
, "Failed to derive unit name instance from unit name: %m");
216 r
= unit_name_build_from_type(prefix
, instance
, type
, &built
);
218 return log_error_errno(r
, "Failed to build prefix unit name: %m");
220 return unit_file_find_dirs(original_root
, unit_path_cache
, unit_path
, built
, suffix
, dirs
);
223 int unit_file_find_dropin_paths(
224 const char *original_root
,
226 Set
*unit_path_cache
,
227 const char *dir_suffix
,
228 const char *file_suffix
,
233 _cleanup_strv_free_
char **dirs
= NULL
;
240 STRV_FOREACH(p
, lookup_path
)
241 (void) unit_file_find_dirs(original_root
, unit_path_cache
, *p
, name
, dir_suffix
, &dirs
);
243 SET_FOREACH(n
, aliases
)
244 STRV_FOREACH(p
, lookup_path
)
245 (void) unit_file_find_dirs(original_root
, unit_path_cache
, *p
, n
, dir_suffix
, &dirs
);
247 /* All the names in the unit are of the same type so just grab one. */
248 n
= name
?: (const char*) set_first(aliases
);
250 UnitType type
= _UNIT_TYPE_INVALID
;
252 type
= unit_name_to_type(n
);
254 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
255 "Failed to derive unit type from unit name: %s", n
);
257 /* Special top level drop in for "<unit type>.<suffix>". Add this last as it's the most generic
258 * and should be able to be overridden by more specific drop-ins. */
259 STRV_FOREACH(p
, lookup_path
)
260 (void) unit_file_find_dirs(original_root
,
263 unit_type_to_string(type
),
268 if (strv_isempty(dirs
)) {
273 r
= conf_files_list_strv(ret
, file_suffix
, NULL
, 0, (const char**) dirs
);
275 return log_warning_errno(r
, "Failed to create the list of configuration files: %m");