1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
5 #include "alloc-util.h"
7 #include "conf-files.h"
12 #include "path-util.h"
14 #include "stdio-util.h"
15 #include "string-util.h"
18 #include "unit-name.h"
28 _cleanup_free_
char *n
= NULL
, *unit_dir
= NULL
;
34 n
= xescape(name
, "/.");
37 if (!filename_is_valid(n
))
40 if (ret_unit_dir
|| ret_path
) {
41 unit_dir
= path_join(dir
, strjoina(unit
, ".d"));
47 char prefix
[DECIMAL_STR_MAX(unsigned) + 1] = {};
49 if (level
!= UINT_MAX
)
50 xsprintf(prefix
, "%u-", level
);
52 _cleanup_free_
char *path
= strjoin(unit_dir
, "/", prefix
, n
, ".conf");
56 *ret_path
= TAKE_PTR(path
);
60 *ret_unit_dir
= TAKE_PTR(unit_dir
);
72 _cleanup_free_
char *p
= NULL
;
80 r
= drop_in_file(dir
, unit
, level
, name
, /* ret_unit_dir= */ NULL
, &p
);
84 return write_string_file(p
, data
, WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_ATOMIC
|WRITE_STRING_FILE_MKDIR_0755
|WRITE_STRING_FILE_LABEL
);
87 int write_drop_in_format(
92 const char *format
, ...) {
94 _cleanup_free_
char *content
= NULL
;
103 va_start(ap
, format
);
104 r
= vasprintf(&content
, format
, ap
);
110 return write_drop_in(dir
, unit
, level
, name
, content
);
113 static int unit_file_add_dir(
114 const char *original_root
,
118 _cleanup_free_
char *chased
= NULL
;
123 /* This adds [original_root]/path to dirs, if it exists. */
125 r
= chase(path
, original_root
, 0, &chased
, NULL
);
126 if (r
== -ENOENT
) /* Ignore -ENOENT, after all most units won't have a drop-in dir. */
128 if (r
== -ENAMETOOLONG
) {
129 /* Also, ignore -ENAMETOOLONG but log about it. After all, users are not even able to create the
130 * drop-in dir in such case. This mostly happens for device units with an overly long /sys path. */
131 log_debug_errno(r
, "Path '%s' too long, couldn't canonicalize, ignoring.", path
);
135 return log_warning_errno(r
, "Failed to canonicalize path '%s': %m", path
);
137 if (strv_consume(dirs
, TAKE_PTR(chased
)) < 0)
143 static int unit_file_find_dirs(
144 const char *original_root
,
145 Set
*unit_path_cache
,
146 const char *unit_path
,
151 _cleanup_free_
char *prefix
= NULL
, *instance
= NULL
, *built
= NULL
;
152 bool is_instance
, chopped
;
163 path
= strjoina(unit_path
, "/", name
, suffix
);
164 if (!unit_path_cache
|| set_get(unit_path_cache
, path
)) {
165 r
= unit_file_add_dir(original_root
, path
, dirs
);
170 is_instance
= unit_name_is_valid(name
, UNIT_NAME_INSTANCE
);
171 if (is_instance
) { /* Also try the template dir */
172 _cleanup_free_
char *template = NULL
;
174 r
= unit_name_template(name
, &template);
176 return log_error_errno(r
, "Failed to generate template from unit name: %m");
178 r
= unit_file_find_dirs(original_root
, unit_path_cache
, unit_path
, template, suffix
, dirs
);
183 /* Return early for top level drop-ins. */
184 if (unit_type_from_string(name
) >= 0)
187 /* Let's see if there's a "-" prefix for this unit name. If so, let's invoke ourselves for it. This will then
188 * recursively do the same for all our prefixes. i.e. this means given "foo-bar-waldo.service" we'll also
189 * search "foo-bar-.service" and "foo-.service".
191 * Note the order in which we do it: we traverse up adding drop-ins on each step. This means the more specific
192 * drop-ins may override the more generic drop-ins, which is the intended behaviour. */
194 r
= unit_name_to_prefix(name
, &prefix
);
196 return log_error_errno(r
, "Failed to derive unit name prefix from unit name: %m");
200 dash
= strrchr(prefix
, '-');
201 if (!dash
) /* No dash? if so we are done */
204 n
= (size_t) (dash
- prefix
);
205 if (n
== 0) /* Leading dash? If so, we are done */
208 if (prefix
[n
+1] != 0 || chopped
) {
213 /* Trailing dash? If so, chop it off and try again, but not more than once. */
218 if (!unit_prefix_is_valid(prefix
))
221 type
= unit_name_to_type(name
);
223 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
224 "Failed to derive unit type from unit name: %s",
228 r
= unit_name_to_instance(name
, &instance
);
230 return log_error_errno(r
, "Failed to derive unit name instance from unit name: %m");
233 r
= unit_name_build_from_type(prefix
, instance
, type
, &built
);
235 return log_error_errno(r
, "Failed to build prefix unit name: %m");
237 return unit_file_find_dirs(original_root
, unit_path_cache
, unit_path
, built
, suffix
, dirs
);
240 int unit_file_find_dropin_paths(
241 const char *original_root
,
243 Set
*unit_path_cache
,
244 const char *dir_suffix
,
245 const char *file_suffix
,
250 _cleanup_strv_free_
char **dirs
= NULL
;
257 STRV_FOREACH(p
, lookup_path
)
258 (void) unit_file_find_dirs(original_root
, unit_path_cache
, *p
, name
, dir_suffix
, &dirs
);
260 SET_FOREACH(n
, aliases
)
261 STRV_FOREACH(p
, lookup_path
)
262 (void) unit_file_find_dirs(original_root
, unit_path_cache
, *p
, n
, dir_suffix
, &dirs
);
264 /* All the names in the unit are of the same type so just grab one. */
265 n
= name
?: (const char*) set_first(aliases
);
267 UnitType type
= _UNIT_TYPE_INVALID
;
269 type
= unit_name_to_type(n
);
271 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
272 "Failed to derive unit type from unit name: %s", n
);
274 /* Special top level drop in for "<unit type>.<suffix>". Add this last as it's the most generic
275 * and should be able to be overridden by more specific drop-ins. */
276 STRV_FOREACH(p
, lookup_path
)
277 (void) unit_file_find_dirs(original_root
,
280 unit_type_to_string(type
),
285 if (strv_isempty(dirs
)) {
290 r
= conf_files_list_strv(ret
, file_suffix
, NULL
, 0, (const char**) dirs
);
292 return log_warning_errno(r
, "Failed to create the list of configuration files: %m");