]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
systemctl: support disable/mask --now with unit template
authorMike Yuan <me@yhndnzj.com>
Wed, 7 Feb 2024 14:15:05 +0000 (22:15 +0800)
committerMike Yuan <me@yhndnzj.com>
Fri, 9 Feb 2024 08:18:44 +0000 (16:18 +0800)
Closes #15620
Replaces #28240

src/systemctl/systemctl-enable.c
test/units/testsuite-26.sh

index 7d9b7c794a17697a0b6c8e8a8f8dbd8cc08dde88..4f5e1f119e3408ff5c4165d71859faeb9717f368 100644 (file)
@@ -313,24 +313,45 @@ int verb_enable(int argc, char *argv[], void *userdata) {
         }
 
         if (arg_now && STR_IN_SET(argv[0], "enable", "disable", "mask")) {
+                _cleanup_strv_free_ char **new_args = NULL;
                 sd_bus *bus;
-                size_t len, i;
 
                 r = acquire_bus(BUS_MANAGER, &bus);
                 if (r < 0)
                         return r;
 
-                len = strv_length(names);
-                {
-                        char *new_args[len + 2];
+                if (strv_extend(&new_args, streq(verb, "enable") ? "start" : "stop") < 0)
+                        return log_oom();
 
-                        new_args[0] = (char*) (streq(argv[0], "enable") ? "start" : "stop");
-                        for (i = 0; i < len; i++)
-                                new_args[i + 1] = basename(names[i]);
-                        new_args[i + 1] = NULL;
+                STRV_FOREACH(name, names) {
+                        if (streq(verb, "enable")) {
+                                char *fn;
+
+                                /* 'enable' accept path to unit files, so extract it first. Don't try to
+                                 * glob them though, as starting globbed unit seldomly makes sense and
+                                 * actually changes the semantic (we're operating on DefaultInstance=
+                                 * when enabling). */
+
+                                r = path_extract_filename(*name, &fn);
+                                if (r < 0)
+                                        return log_error_errno(r, "Failed to extract filename of '%s': %m", *name);
+
+                                r = strv_consume(&new_args, fn);
+                        } else if (unit_name_is_valid(*name, UNIT_NAME_TEMPLATE)) {
+                                char *globbed;
 
-                        r = verb_start(len + 1, new_args, userdata);
+                                r = unit_name_replace_instance_full(*name, "*", /* accept_glob = */ true, &globbed);
+                                if (r < 0)
+                                        return log_error_errno(r, "Failed to glob unit name '%s': %m", *name);
+
+                                r = strv_consume(&new_args, globbed);
+                        } else
+                                r = strv_extend(&new_args, *name);
+                        if (r < 0)
+                                return log_oom();
                 }
+
+                return verb_start(strv_length(new_args), new_args, userdata);
         }
 
         return 0;
index 9f672c738a36633aa0f14ecb9b77a289bffe1470..910e7531b1e887b10a901b85a33e0687597822cd 100755 (executable)
@@ -207,6 +207,24 @@ test_mask_unmask_revert() {
 test_mask_unmask_revert
 test_mask_unmask_revert --root=/
 
+# disable --now with template unit
+cat >/run/systemd/system/test-disable@.service <<EOF
+[Service]
+ExecStart=sleep infinity
+
+[Install]
+WantedBy=multi-user.target
+EOF
+systemctl enable --now test-disable@1.service test-disable@2.service
+systemctl is-active test-disable@1.service
+systemctl is-active test-disable@2.service
+systemctl disable --now test-disable@.service
+for u in test-disable@{1,2}.service; do
+    (! systemctl is-active "$u")
+    (! systemctl is-enabled "$u")
+done
+rm /run/systemd/system/test-disable@.service
+
 # add-wants/add-requires
 (! systemctl show -P Wants "$UNIT_NAME" | grep "systemd-journald.service")
 systemctl add-wants "$UNIT_NAME" "systemd-journald.service"