summaryrefslogtreecommitdiff
path: root/src/shared/install.c
diff options
context:
space:
mode:
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2022-08-26 12:02:43 +0200
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2022-10-13 19:44:47 +0200
commitbf3b0d5f29d769fc248808d323ee95b23eae86df (patch)
tree6ceac07c732455b4e262a0a0d08fdb69a32c0f21 /src/shared/install.c
parentacb5b834381c7938c371b0b2a912bd8c420c4a4d (diff)
downloadsystemd-bf3b0d5f29d769fc248808d323ee95b23eae86df.tar.gz
shared/install: print warning when unmasking unit with cmdline mask
'systemctl unmask foo' will try to remove the symlink to /dev/null under /etc/. But the unit may also be masked by a symlink under /run/generator, in particular the one created by systemd-debug-generator based on systemd.mask=foo on the kernel commandline. The unmask call cannot anything about this: even if it removed the symlink from /run/generator, it'll be recreated on the next daemon-reload. Thus, we can only warn about it. Initially, I wanted to check if 'systemctl.mask' is defined on the kernel command-line, but that's not effective, because such mask symlinks can be created by other generators based on other conditions. Checking for runtime mask is "dumber", but is more robust because it doesn't assume who created the mask and why. The handling of InstallInfo is the copied from install_info_symlink_wants(). It's pretty ugly, this whole code should be rewritten from scratch. The message is printed, but the whole operation is still "successful". This keep backwards compatibility: people might call unmask to remove filesystem masks even if there's still a cmdline param in place. We allow 'systemctl mask' to create such a mask, so 'unmask' should be able to remove it. Fixes #22689.
Diffstat (limited to 'src/shared/install.c')
-rw-r--r--src/shared/install.c32
1 files changed, 29 insertions, 3 deletions
diff --git a/src/shared/install.c b/src/shared/install.c
index 7cf73fe0aa..e45ad01092 100644
--- a/src/shared/install.c
+++ b/src/shared/install.c
@@ -352,6 +352,11 @@ void install_changes_dump(int r, const char *verb, const InstallChange *changes,
if (!quiet)
log_info("Unit %s is masked, ignoring.", changes[i].path);
break;
+ case INSTALL_CHANGE_IS_MASKED_GENERATOR:
+ if (!quiet)
+ log_info("Unit %s is masked via a generator and cannot be unmasked.",
+ changes[i].path);
+ break;
case INSTALL_CHANGE_IS_DANGLING:
if (!quiet)
log_info("Unit %s is an alias to a unit that is not present, ignoring.",
@@ -2287,12 +2292,32 @@ int unit_file_unmask(
bool dry_run = flags & UNIT_FILE_DRY_RUN;
STRV_FOREACH(name, names) {
- _cleanup_free_ char *path = NULL;
-
if (!unit_name_is_valid(*name, UNIT_NAME_ANY))
return -EINVAL;
- path = path_make_absolute(*name, config_path);
+ /* If root_dir is set, we don't care about kernel commandline or generators.
+ * But if it is not set, we need to check for interference. */
+ if (!root_dir) {
+ _cleanup_(install_info_clear) InstallInfo info = {
+ .name = *name, /* We borrow *name temporarily… */
+ .install_mode = _INSTALL_MODE_INVALID,
+ };
+
+ r = unit_file_search(NULL, &info, &lp, 0);
+ if (r < 0) {
+ if (r != -ENOENT)
+ log_debug_errno(r, "Failed to look up unit %s, ignoring: %m", info.name);
+ } else {
+ if (info.install_mode == INSTALL_MODE_MASKED &&
+ path_is_generator(&lp, info.path))
+ install_changes_add(changes, n_changes,
+ INSTALL_CHANGE_IS_MASKED_GENERATOR, info.name, info.path);
+ }
+
+ TAKE_PTR(info.name); /* … and give it back here */
+ }
+
+ _cleanup_free_ char *path = path_make_absolute(*name, config_path);
if (!path)
return -ENOMEM;
@@ -3645,6 +3670,7 @@ static const char* const install_change_table[_INSTALL_CHANGE_MAX] = {
[INSTALL_CHANGE_SYMLINK] = "symlink",
[INSTALL_CHANGE_UNLINK] = "unlink",
[INSTALL_CHANGE_IS_MASKED] = "masked",
+ [INSTALL_CHANGE_IS_MASKED_GENERATOR] = "masked by generator",
[INSTALL_CHANGE_IS_DANGLING] = "dangling",
[INSTALL_CHANGE_DESTINATION_NOT_PRESENT] = "destination not present",
[INSTALL_CHANGE_AUXILIARY_FAILED] = "auxiliary unit failed",