dcavalca / rpms / systemd

Forked from rpms/systemd 3 months ago
Clone
ac3a84
From 201c651eaaf886064987272cc88b03995fd2715d Mon Sep 17 00:00:00 2001
ac3a84
From: Mike Yuan <me@yhndnzj.com>
ac3a84
Date: Fri, 18 Nov 2022 15:43:34 +0800
ac3a84
Subject: [PATCH] systemctl: warn if trying to disable a unit with no install
ac3a84
 info
ac3a84
ac3a84
Trying to disable a unit with no install info is mostly useless, so
ac3a84
adding a warning like we do for enable (with the new dbus method
ac3a84
'DisableUnitFilesWithFlagsAndInstallInfo()'). Note that it would
ac3a84
still find and remove symlinks to the unit in /etc, regardless of
ac3a84
whether it has install info or not, just like before. And if there are
ac3a84
actually files to remove, we suppress the warning.
ac3a84
ac3a84
Fixes #17689
ac3a84
ac3a84
(cherry picked from commit bf1bea43f15b04152a3948702ba1695a0835c2bf)
ac3a84
ac3a84
Related: #2141979
ac3a84
---
ac3a84
 man/org.freedesktop.systemd1.xml | 13 ++++++++++++-
ac3a84
 src/core/dbus-manager.c          | 21 ++++++++++++++++-----
ac3a84
 src/shared/install.c             | 21 +++++++++++++++++----
ac3a84
 src/systemctl/systemctl-enable.c | 15 ++++++++++-----
ac3a84
 4 files changed, 55 insertions(+), 15 deletions(-)
ac3a84
ac3a84
diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml
ac3a84
index 5e08b35234..c2f70870c7 100644
ac3a84
--- a/man/org.freedesktop.systemd1.xml
ac3a84
+++ b/man/org.freedesktop.systemd1.xml
ac3a84
@@ -209,6 +209,10 @@ node /org/freedesktop/systemd1 {
ac3a84
       DisableUnitFilesWithFlags(in  as files,
ac3a84
                                 in  t flags,
ac3a84
                                 out a(sss) changes);
ac3a84
+      DisableUnitFilesWithFlagsAndInstallInfo(in  as files,
ac3a84
+                                              in  t flags,
ac3a84
+                                              out b carries_install_info,
ac3a84
+                                              out a(sss) changes);
ac3a84
       ReenableUnitFiles(in  as files,
ac3a84
                         in  b runtime,
ac3a84
                         in  b force,
ac3a84
@@ -916,6 +920,8 @@ node /org/freedesktop/systemd1 {
ac3a84
 
ac3a84
     <variablelist class="dbus-method" generated="True" extra-ref="DisableUnitFilesWithFlags()"/>
ac3a84
 
ac3a84
+    <variablelist class="dbus-method" generated="True" extra-ref="DisableUnitFilesWithFlagsAndInstallInfo()"/>
ac3a84
+
ac3a84
     <variablelist class="dbus-method" generated="True" extra-ref="ReenableUnitFiles()"/>
ac3a84
 
ac3a84
     <variablelist class="dbus-method" generated="True" extra-ref="LinkUnitFiles()"/>
ac3a84
@@ -1417,7 +1423,7 @@ node /org/freedesktop/systemd1 {
ac3a84
       enabled for runtime only (true, <filename>/run/</filename>), or persistently (false,
ac3a84
       <filename>/etc/</filename>). The second one controls whether symlinks pointing to other units shall be
ac3a84
       replaced if necessary. This method returns one boolean and an array of the changes made. The boolean
ac3a84
-      signals whether the unit files contained any enablement information (i.e. an [Install]) section. The
ac3a84
+      signals whether the unit files contained any enablement information (i.e. an [Install] section). The
ac3a84
       changes array consists of structures with three strings: the type of the change (one of
ac3a84
       <literal>symlink</literal> or <literal>unlink</literal>), the file name of the symlink and the
ac3a84
       destination of the symlink. Note that most of the following calls return a changes list in the same
ac3a84
@@ -1440,6 +1446,11 @@ node /org/freedesktop/systemd1 {
ac3a84
       replaced if necessary. <varname>SD_SYSTEMD_UNIT_PORTABLE</varname> will add or remove the symlinks in
ac3a84
       <filename>/etc/systemd/system.attached</filename> and <filename>/run/systemd/system.attached</filename>.</para>
ac3a84
 
ac3a84
+      <para><function>DisableUnitFilesWithFlagsAndInstallInfo()</function> is similar to
ac3a84
+      <function>DisableUnitFilesWithFlags()</function> and takes the same arguments, but returns
ac3a84
+      a boolean to indicate whether the unit files contain any enablement information, like
ac3a84
+      <function>EnableUnitFiles()</function>. The changes made are still returned in an array.</para>
ac3a84
+
ac3a84
       <para>Similarly, <function>ReenableUnitFiles()</function> applies the changes to one or more units that
ac3a84
       would result from disabling and enabling the unit quickly one after the other in an atomic
ac3a84
       fashion. This is useful to apply updated [Install] information contained in unit files.</para>
ac3a84
diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
ac3a84
index 88f098ec86..2db12721a1 100644
ac3a84
--- a/src/core/dbus-manager.c
ac3a84
+++ b/src/core/dbus-manager.c
ac3a84
@@ -2425,6 +2425,7 @@ static int method_disable_unit_files_generic(
ac3a84
                 sd_bus_message *message,
ac3a84
                 Manager *m,
ac3a84
                 int (*call)(LookupScope scope, UnitFileFlags flags, const char *root_dir, char *files[], InstallChange **changes, size_t *n_changes),
ac3a84
+                bool carries_install_info,
ac3a84
                 sd_bus_error *error) {
ac3a84
 
ac3a84
         _cleanup_strv_free_ char **l = NULL;
ac3a84
@@ -2440,7 +2441,8 @@ static int method_disable_unit_files_generic(
ac3a84
         if (r < 0)
ac3a84
                 return r;
ac3a84
 
ac3a84
-        if (sd_bus_message_is_method_call(message, NULL, "DisableUnitFilesWithFlags")) {
ac3a84
+        if (sd_bus_message_is_method_call(message, NULL, "DisableUnitFilesWithFlags") ||
ac3a84
+            sd_bus_message_is_method_call(message, NULL, "DisableUnitFilesWithFlagsAndInstallInfo")) {
ac3a84
                 uint64_t raw_flags;
ac3a84
 
ac3a84
                 r = sd_bus_message_read(message, "t", &raw_flags);
ac3a84
@@ -2469,19 +2471,23 @@ static int method_disable_unit_files_generic(
ac3a84
         if (r < 0)
ac3a84
                 return install_error(error, r, changes, n_changes);
ac3a84
 
ac3a84
-        return reply_install_changes_and_free(m, message, -1, changes, n_changes, error);
ac3a84
+        return reply_install_changes_and_free(m, message, carries_install_info ? r : -1, changes, n_changes, error);
ac3a84
 }
ac3a84
 
ac3a84
 static int method_disable_unit_files_with_flags(sd_bus_message *message, void *userdata, sd_bus_error *error) {
ac3a84
-        return method_disable_unit_files_generic(message, userdata, unit_file_disable, error);
ac3a84
+        return method_disable_unit_files_generic(message, userdata, unit_file_disable, /* carries_install_info = */ false, error);
ac3a84
+}
ac3a84
+
ac3a84
+static int method_disable_unit_files_with_flags_and_install_info(sd_bus_message *message, void *userdata, sd_bus_error *error) {
ac3a84
+        return method_disable_unit_files_generic(message, userdata, unit_file_disable, /* carries_install_info = */ true, error);
ac3a84
 }
ac3a84
 
ac3a84
 static int method_disable_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
ac3a84
-        return method_disable_unit_files_generic(message, userdata, unit_file_disable, error);
ac3a84
+        return method_disable_unit_files_generic(message, userdata, unit_file_disable, /* carries_install_info = */ false, error);
ac3a84
 }
ac3a84
 
ac3a84
 static int method_unmask_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
ac3a84
-        return method_disable_unit_files_generic(message, userdata, unit_file_unmask, error);
ac3a84
+        return method_disable_unit_files_generic(message, userdata, unit_file_unmask, /* carries_install_info = */ false, error);
ac3a84
 }
ac3a84
 
ac3a84
 static int method_revert_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
ac3a84
@@ -3194,6 +3200,11 @@ const sd_bus_vtable bus_manager_vtable[] = {
ac3a84
                                 SD_BUS_RESULT("a(sss)", changes),
ac3a84
                                 method_disable_unit_files_with_flags,
ac3a84
                                 SD_BUS_VTABLE_UNPRIVILEGED),
ac3a84
+        SD_BUS_METHOD_WITH_ARGS("DisableUnitFilesWithFlagsAndInstallInfo",
ac3a84
+                                SD_BUS_ARGS("as", files, "t", flags),
ac3a84
+                                SD_BUS_RESULT("b", carries_install_info, "a(sss)", changes),
ac3a84
+                                method_disable_unit_files_with_flags_and_install_info,
ac3a84
+                                SD_BUS_VTABLE_UNPRIVILEGED),
ac3a84
         SD_BUS_METHOD_WITH_ARGS("ReenableUnitFiles",
ac3a84
                                 SD_BUS_ARGS("as", files, "b", runtime, "b", force),
ac3a84
                                 SD_BUS_RESULT("b", carries_install_info, "a(sss)", changes),
ac3a84
diff --git a/src/shared/install.c b/src/shared/install.c
ac3a84
index 834a1c59e3..4b610b20a5 100644
ac3a84
--- a/src/shared/install.c
ac3a84
+++ b/src/shared/install.c
ac3a84
@@ -2790,25 +2790,38 @@ static int do_unit_file_disable(
ac3a84
 
ac3a84
         _cleanup_(install_context_done) InstallContext ctx = { .scope = scope };
ac3a84
         _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
ac3a84
+        InstallInfo *info;
ac3a84
+        bool has_install_info = false;
ac3a84
         int r;
ac3a84
 
ac3a84
         STRV_FOREACH(name, names) {
ac3a84
                 if (!unit_name_is_valid(*name, UNIT_NAME_ANY))
ac3a84
                         return install_changes_add(changes, n_changes, -EUCLEAN, *name, NULL);
ac3a84
 
ac3a84
-                r = install_info_add(&ctx, *name, NULL, lp->root_dir, /* auxiliary= */ false, NULL);
ac3a84
+                r = install_info_add(&ctx, *name, NULL, lp->root_dir, /* auxiliary= */ false, &info;;
ac3a84
+                if (r >= 0)
ac3a84
+                        r = install_info_traverse(&ctx, lp, info, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, NULL);
ac3a84
+
ac3a84
                 if (r < 0)
ac3a84
-                        return r;
ac3a84
+                        return install_changes_add(changes, n_changes, r, *name, NULL);
ac3a84
+
ac3a84
+                /* If we enable multiple units, some with install info and others without,
ac3a84
+                 * the "empty [Install] section" warning is not shown. Let's make the behavior
ac3a84
+                 * of disable align with that. */
ac3a84
+                has_install_info = has_install_info || install_info_has_rules(info) || install_info_has_also(info);
ac3a84
         }
ac3a84
 
ac3a84
         r = install_context_mark_for_removal(&ctx, lp, &remove_symlinks_to, config_path, changes, n_changes);
ac3a84
+        if (r >= 0)
ac3a84
+                r = remove_marked_symlinks(remove_symlinks_to, config_path, lp, flags & UNIT_FILE_DRY_RUN, changes, n_changes);
ac3a84
+
ac3a84
         if (r < 0)
ac3a84
                 return r;
ac3a84
 
ac3a84
-        return remove_marked_symlinks(remove_symlinks_to, config_path, lp, flags & UNIT_FILE_DRY_RUN, changes, n_changes);
ac3a84
+        /* The warning is shown only if it's a no-op */
ac3a84
+        return install_changes_have_modification(*changes, *n_changes) || has_install_info;
ac3a84
 }
ac3a84
 
ac3a84
-
ac3a84
 int unit_file_disable(
ac3a84
                 LookupScope scope,
ac3a84
                 UnitFileFlags flags,
ac3a84
diff --git a/src/systemctl/systemctl-enable.c b/src/systemctl/systemctl-enable.c
ac3a84
index 5be4c0c725..aea66872de 100644
ac3a84
--- a/src/systemctl/systemctl-enable.c
ac3a84
+++ b/src/systemctl/systemctl-enable.c
ac3a84
@@ -109,9 +109,10 @@ int verb_enable(int argc, char *argv[], void *userdata) {
ac3a84
                 if (streq(verb, "enable")) {
ac3a84
                         r = unit_file_enable(arg_scope, flags, arg_root, names, &changes, &n_changes);
ac3a84
                         carries_install_info = r;
ac3a84
-                } else if (streq(verb, "disable"))
ac3a84
+                } else if (streq(verb, "disable")) {
ac3a84
                         r = unit_file_disable(arg_scope, flags, arg_root, names, &changes, &n_changes);
ac3a84
-                else if (streq(verb, "reenable")) {
ac3a84
+                        carries_install_info = r;
ac3a84
+                } else if (streq(verb, "reenable")) {
ac3a84
                         r = unit_file_reenable(arg_scope, flags, arg_root, names, &changes, &n_changes);
ac3a84
                         carries_install_info = r;
ac3a84
                 } else if (streq(verb, "link"))
ac3a84
@@ -165,7 +166,8 @@ int verb_enable(int argc, char *argv[], void *userdata) {
ac3a84
                         method = "EnableUnitFiles";
ac3a84
                         expect_carries_install_info = true;
ac3a84
                 } else if (streq(verb, "disable")) {
ac3a84
-                        method = "DisableUnitFiles";
ac3a84
+                        method = "DisableUnitFilesWithFlagsAndInstallInfo";
ac3a84
+                        expect_carries_install_info = true;
ac3a84
                         send_force = false;
ac3a84
                 } else if (streq(verb, "reenable")) {
ac3a84
                         method = "ReenableUnitFiles";
ac3a84
@@ -208,7 +210,10 @@ int verb_enable(int argc, char *argv[], void *userdata) {
ac3a84
                 }
ac3a84
 
ac3a84
                 if (send_runtime) {
ac3a84
-                        r = sd_bus_message_append(m, "b", arg_runtime);
ac3a84
+                        if (streq(method, "DisableUnitFilesWithFlagsAndInstallInfo"))
ac3a84
+                                r = sd_bus_message_append(m, "t", arg_runtime ? UNIT_FILE_RUNTIME : 0);
ac3a84
+                        else
ac3a84
+                                r = sd_bus_message_append(m, "b", arg_runtime);
ac3a84
                         if (r < 0)
ac3a84
                                 return bus_log_create_error(r);
ac3a84
                 }
ac3a84
@@ -245,7 +250,7 @@ int verb_enable(int argc, char *argv[], void *userdata) {
ac3a84
         if (carries_install_info == 0 && !ignore_carries_install_info)
ac3a84
                 log_notice("The unit files have no installation config (WantedBy=, RequiredBy=, Also=,\n"
ac3a84
                            "Alias= settings in the [Install] section, and DefaultInstance= for template\n"
ac3a84
-                           "units). This means they are not meant to be enabled using systemctl.\n"
ac3a84
+                           "units). This means they are not meant to be enabled or disabled using systemctl.\n"
ac3a84
                            " \n" /* trick: the space is needed so that the line does not get stripped from output */
ac3a84
                            "Possible reasons for having this kind of units are:\n"
ac3a84
                            "%1$s A unit may be statically enabled by being symlinked from another unit's\n"