X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fshared%2Fdropin.c;h=d1baad61929517d68623e88a3974a3f0467d6c27;hb=374c22b351e43ce4ef70ef0ad1bd1e4e520f9a28;hp=7774236f71dacc05d28a3fbfa2fdf56d7114c299;hpb=2968644080fd103062f070e83edd620e0a58c44d;p=elogind.git diff --git a/src/shared/dropin.c b/src/shared/dropin.c index 7774236f7..d1baad619 100644 --- a/src/shared/dropin.c +++ b/src/shared/dropin.c @@ -21,32 +21,38 @@ #include "dropin.h" #include "util.h" +#include "strv.h" #include "mkdir.h" #include "fileio-label.h" +#include "conf-files.h" -int drop_in_file(const char *dir, const char *unit, +int drop_in_file(const char *dir, const char *unit, unsigned level, const char *name, char **_p, char **_q) { _cleanup_free_ char *b = NULL; char *p, *q; + char prefix[DECIMAL_STR_MAX(unsigned)]; + assert(unit); assert(name); assert(_p); assert(_q); + sprintf(prefix, "%u", level); + b = xescape(name, "/."); if (!b) return -ENOMEM; - if (!filename_is_safe(b)) + if (!filename_is_valid(b)) return -EINVAL; p = strjoin(dir, "/", unit, ".d", NULL); if (!p) return -ENOMEM; - q = strjoin(p, "/90-", b, ".conf", NULL); + q = strjoin(p, "/", prefix, "-", b, ".conf", NULL); if (!q) { free(p); return -ENOMEM; @@ -57,7 +63,7 @@ int drop_in_file(const char *dir, const char *unit, return 0; } -int write_drop_in(const char *dir, const char *unit, +int write_drop_in(const char *dir, const char *unit, unsigned level, const char *name, const char *data) { _cleanup_free_ char *p = NULL, *q = NULL; @@ -68,7 +74,7 @@ int write_drop_in(const char *dir, const char *unit, assert(name); assert(data); - r = drop_in_file(dir, unit, name, &p, &q); + r = drop_in_file(dir, unit, level, name, &p, &q); if (r < 0) return r; @@ -76,7 +82,7 @@ int write_drop_in(const char *dir, const char *unit, return write_string_file_atomic_label(q, data); } -int write_drop_in_format(const char *dir, const char *unit, +int write_drop_in_format(const char *dir, const char *unit, unsigned level, const char *name, const char *format, ...) { _cleanup_free_ char *p = NULL; va_list ap; @@ -94,5 +100,139 @@ int write_drop_in_format(const char *dir, const char *unit, if (r < 0) return -ENOMEM; - return write_drop_in(dir, unit, name, p); + return write_drop_in(dir, unit, level, name, p); +} + +static int iterate_dir( + const char *path, + UnitDependency dependency, + dependency_consumer_t consumer, + void *arg, + char ***strv) { + + _cleanup_closedir_ DIR *d = NULL; + int r; + + assert(path); + + /* The config directories are special, since the order of the + * drop-ins matters */ + if (dependency < 0) { + r = strv_extend(strv, path); + if (r < 0) + return log_oom(); + + return 0; + } + + assert(consumer); + + d = opendir(path); + if (!d) { + if (errno == ENOENT) + return 0; + + log_error_errno(errno, "Failed to open directory %s: %m", path); + return -errno; + } + + for (;;) { + struct dirent *de; + _cleanup_free_ char *f = NULL; + + errno = 0; + de = readdir(d); + if (!de && errno != 0) + return log_error_errno(errno, "Failed to read directory %s: %m", path); + + if (!de) + break; + + if (hidden_file(de->d_name)) + continue; + + f = strjoin(path, "/", de->d_name, NULL); + if (!f) + return log_oom(); + + r = consumer(dependency, de->d_name, f, arg); + if (r < 0) + return r; + } + + return 0; +} + +int unit_file_process_dir( + Set * unit_path_cache, + const char *unit_path, + const char *name, + const char *suffix, + UnitDependency dependency, + dependency_consumer_t consumer, + void *arg, + char ***strv) { + + _cleanup_free_ char *path = NULL; + + assert(unit_path); + assert(name); + assert(suffix); + + path = strjoin(unit_path, "/", name, suffix, NULL); + if (!path) + return log_oom(); + + if (!unit_path_cache || set_get(unit_path_cache, path)) + iterate_dir(path, dependency, consumer, arg, strv); + + if (unit_name_is_instance(name)) { + _cleanup_free_ char *template = NULL, *p = NULL; + /* Also try the template dir */ + + template = unit_name_template(name); + if (!template) + return log_oom(); + + p = strjoin(unit_path, "/", template, suffix, NULL); + if (!p) + return log_oom(); + + if (!unit_path_cache || set_get(unit_path_cache, p)) + iterate_dir(p, dependency, consumer, arg, strv); + } + + return 0; +} + +int unit_file_find_dropin_paths( + char **lookup_path, + Set *unit_path_cache, + Set *names, + char ***paths) { + + _cleanup_strv_free_ char **strv = NULL, **ans = NULL; + Iterator i; + char *t; + int r; + + assert(paths); + + SET_FOREACH(t, names, i) { + char **p; + + STRV_FOREACH(p, lookup_path) + unit_file_process_dir(unit_path_cache, *p, t, ".d", _UNIT_DEPENDENCY_INVALID, NULL, NULL, &strv); + } + + if (strv_isempty(strv)) + return 0; + + r = conf_files_list_strv(&ans, ".conf", NULL, (const char**) strv); + if (r < 0) + return log_warning_errno(r, "Failed to get list of configuration files: %m"); + + *paths = ans; + ans = NULL; + return 1; }