2017-11-18 17:09:20 +01:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1+ */
|
2010-02-03 13:03:47 +01:00
|
|
|
|
2015-11-16 22:09:36 +01:00
|
|
|
#include "conf-parser.h"
|
2017-02-05 04:36:17 +01:00
|
|
|
#include "fs-util.h"
|
2010-01-23 01:52:57 +01:00
|
|
|
#include "load-dropin.h"
|
2015-11-16 22:09:36 +01:00
|
|
|
#include "load-fragment.h"
|
2010-01-27 04:55:19 +01:00
|
|
|
#include "log.h"
|
2017-02-05 02:50:44 +01:00
|
|
|
#include "stat-util.h"
|
2017-02-05 04:36:17 +01:00
|
|
|
#include "string-util.h"
|
2010-02-13 01:07:02 +01:00
|
|
|
#include "strv.h"
|
2010-04-15 03:11:11 +02:00
|
|
|
#include "unit-name.h"
|
2015-11-16 22:09:36 +01:00
|
|
|
#include "unit.h"
|
2013-01-11 00:21:06 +01:00
|
|
|
|
2017-05-22 15:18:00 +02:00
|
|
|
static int unit_name_compatible(const char *a, const char *b) {
|
2018-02-23 12:20:14 +01:00
|
|
|
_cleanup_free_ char *template = NULL;
|
2017-02-05 04:36:17 +01:00
|
|
|
int r;
|
|
|
|
|
2018-02-23 12:20:14 +01:00
|
|
|
/* The straightforward case: the symlink name matches the target */
|
2017-02-05 04:36:17 +01:00
|
|
|
if (streq(a, b))
|
2017-05-22 15:18:00 +02:00
|
|
|
return 1;
|
2017-02-05 04:36:17 +01:00
|
|
|
|
2018-02-23 12:20:14 +01:00
|
|
|
r = unit_name_template(a, &template);
|
2017-05-21 01:34:50 +02:00
|
|
|
if (r == -EINVAL)
|
2018-02-23 12:20:14 +01:00
|
|
|
return 0; /* Not a template */
|
2017-05-21 01:34:50 +02:00
|
|
|
if (r < 0)
|
2018-02-23 12:20:14 +01:00
|
|
|
return r; /* OOM, or some other failure. Just skip the warning. */
|
2017-02-05 04:36:17 +01:00
|
|
|
|
2018-02-23 12:20:14 +01:00
|
|
|
/* An instance name points to a target that is just the template name */
|
|
|
|
return streq(template, b);
|
2017-02-05 04:36:17 +01:00
|
|
|
}
|
|
|
|
|
2017-02-05 02:50:44 +01:00
|
|
|
static int process_deps(Unit *u, UnitDependency dependency, const char *dir_suffix) {
|
|
|
|
_cleanup_strv_free_ char **paths = NULL;
|
|
|
|
char **p;
|
2010-04-15 03:11:11 +02:00
|
|
|
int r;
|
|
|
|
|
2017-02-05 02:50:44 +01:00
|
|
|
r = unit_file_find_dropin_paths(NULL,
|
|
|
|
u->manager->lookup_paths.search_path,
|
|
|
|
u->manager->unit_path_cache,
|
|
|
|
dir_suffix,
|
|
|
|
NULL,
|
|
|
|
u->names,
|
|
|
|
&paths);
|
2014-12-15 05:12:40 +01:00
|
|
|
if (r < 0)
|
2017-02-05 02:50:44 +01:00
|
|
|
return r;
|
|
|
|
|
|
|
|
STRV_FOREACH(p, paths) {
|
2017-02-05 04:36:17 +01:00
|
|
|
_cleanup_free_ char *target = NULL;
|
2018-02-23 12:30:14 +01:00
|
|
|
const char *entry;
|
2017-02-05 02:50:44 +01:00
|
|
|
|
|
|
|
entry = basename(*p);
|
|
|
|
|
2017-02-05 02:50:44 +01:00
|
|
|
if (null_or_empty_path(*p) > 0) {
|
|
|
|
/* an error usually means an invalid symlink, which is not a mask */
|
|
|
|
log_unit_debug(u, "%s dependency on %s is masked by %s, ignoring.",
|
|
|
|
unit_dependency_to_string(dependency), entry, *p);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-02-05 02:50:44 +01:00
|
|
|
r = is_symlink(*p);
|
|
|
|
if (r < 0) {
|
|
|
|
log_unit_warning_errno(u, r, "%s dropin %s unreadable, ignoring: %m",
|
|
|
|
unit_dependency_to_string(dependency), *p);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (r == 0) {
|
|
|
|
log_unit_warning(u, "%s dependency dropin %s is not a symlink, ignoring.",
|
|
|
|
unit_dependency_to_string(dependency), *p);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-02-05 04:36:17 +01:00
|
|
|
if (!unit_name_is_valid(entry, UNIT_NAME_ANY)) {
|
|
|
|
log_unit_warning(u, "%s dependency dropin %s is not a valid unit name, ignoring.",
|
|
|
|
unit_dependency_to_string(dependency), *p);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = readlink_malloc(*p, &target);
|
|
|
|
if (r < 0) {
|
|
|
|
log_unit_warning_errno(u, r, "readlink(\"%s\") failed, ignoring: %m", *p);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We don't treat this as an error, especially because we didn't check this for a
|
|
|
|
* long time. Nevertheless, we warn, because such mismatch can be mighty confusing. */
|
2017-05-22 15:18:00 +02:00
|
|
|
r = unit_name_compatible(entry, basename(target));
|
|
|
|
if (r < 0) {
|
|
|
|
log_unit_warning_errno(u, r, "Can't check if names %s and %s are compatible, ignoring: %m", entry, basename(target));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (r == 0)
|
2017-02-05 04:36:17 +01:00
|
|
|
log_unit_warning(u, "%s dependency dropin %s target %s has different name",
|
|
|
|
unit_dependency_to_string(dependency), *p, target);
|
2017-02-05 02:50:44 +01:00
|
|
|
|
core: track why unit dependencies came to be
This replaces the dependencies Set* objects by Hashmap* objects, where
the key is the depending Unit, and the value is a bitmask encoding why
the specific dependency was created.
The bitmask contains a number of different, defined bits, that indicate
why dependencies exist, for example whether they are created due to
explicitly configured deps in files, by udev rules or implicitly.
Note that memory usage is not increased by this change, even though we
store more information, as we manage to encode the bit mask inside the
value pointer each Hashmap entry contains.
Why this all? When we know how a dependency came to be, we can update
dependencies correctly when a configuration source changes but others
are left unaltered. Specifically:
1. We can fix UDEV_WANTS dependency generation: so far we kept adding
dependencies configured that way, but if a device lost such a
dependency we couldn't them again as there was no scheme for removing
of dependencies in place.
2. We can implement "pin-pointed" reload of unit files. If we know what
dependencies were created as result of configuration in a unit file,
then we know what to flush out when we want to reload it.
3. It's useful for debugging: "systemd-analyze dump" now shows
this information, helping substantially with understanding how
systemd's dependency tree came to be the way it came to be.
2017-10-25 20:46:01 +02:00
|
|
|
r = unit_add_dependency_by_name(u, dependency, entry, *p, true, UNIT_DEPENDENCY_FILE);
|
2017-02-05 02:50:44 +01:00
|
|
|
if (r < 0)
|
2017-11-09 11:13:36 +01:00
|
|
|
log_unit_warning_errno(u, r, "Cannot add %s dependency on %s, ignoring: %m",
|
|
|
|
unit_dependency_to_string(dependency), entry);
|
2017-02-05 02:50:44 +01:00
|
|
|
}
|
2010-04-15 03:11:11 +02:00
|
|
|
|
2013-01-11 00:21:06 +01:00
|
|
|
return 0;
|
2010-04-15 03:11:11 +02:00
|
|
|
}
|
2010-01-23 01:52:57 +01:00
|
|
|
|
2013-04-01 12:32:35 +02:00
|
|
|
int unit_load_dropin(Unit *u) {
|
2016-02-26 17:05:33 +01:00
|
|
|
_cleanup_strv_free_ char **l = NULL;
|
2017-02-05 02:50:44 +01:00
|
|
|
char **f;
|
2014-12-15 05:12:40 +01:00
|
|
|
int r;
|
2010-11-15 04:24:04 +01:00
|
|
|
|
|
|
|
assert(u);
|
|
|
|
|
2017-02-05 02:50:44 +01:00
|
|
|
/* Load dependencies from .wants and .requires directories */
|
|
|
|
r = process_deps(u, UNIT_WANTS, ".wants");
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2010-11-15 04:24:04 +01:00
|
|
|
|
2017-02-05 02:50:44 +01:00
|
|
|
r = process_deps(u, UNIT_REQUIRES, ".requires");
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2010-01-27 00:15:56 +01:00
|
|
|
|
2017-02-05 02:50:44 +01:00
|
|
|
/* Load .conf dropins */
|
2016-02-26 17:05:33 +01:00
|
|
|
r = unit_find_dropin_paths(u, &l);
|
2014-12-15 05:12:40 +01:00
|
|
|
if (r <= 0)
|
2013-04-01 12:32:35 +02:00
|
|
|
return 0;
|
2013-01-11 01:04:11 +01:00
|
|
|
|
2018-04-05 07:26:26 +02:00
|
|
|
if (!u->dropin_paths)
|
|
|
|
u->dropin_paths = TAKE_PTR(l);
|
|
|
|
else {
|
2016-02-26 17:05:33 +01:00
|
|
|
r = strv_extend_strv(&u->dropin_paths, l, true);
|
|
|
|
if (r < 0)
|
|
|
|
return log_oom();
|
|
|
|
}
|
|
|
|
|
2017-11-09 00:26:11 +01:00
|
|
|
STRV_FOREACH(f, u->dropin_paths)
|
|
|
|
(void) config_parse(u->id, *f, NULL,
|
|
|
|
UNIT_VTABLE(u)->sections,
|
|
|
|
config_item_perf_lookup, load_fragment_gperf_lookup,
|
|
|
|
0, u);
|
2013-01-11 01:04:11 +01:00
|
|
|
|
2013-04-01 12:32:35 +02:00
|
|
|
u->dropin_mtime = now(CLOCK_REALTIME);
|
|
|
|
|
2010-01-23 01:52:57 +01:00
|
|
|
return 0;
|
|
|
|
}
|