diff --git a/man/systemctl.xml b/man/systemctl.xml
index e589711ea8..55389a910b 100644
--- a/man/systemctl.xml
+++ b/man/systemctl.xml
@@ -973,6 +973,11 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
enabled with to the defaults configured in its [Install] section. This command expects
a unit name only, it does not accept paths to unit files.
+ This command implicitly reloads the system manager configuration after completing the operation.
+ Note that this command does not implicitly restart the units that are being disabled. If this is
+ desired, either combine this command with the switch, or invoke
+ the try-restart command with appropriate arguments later.
+
@@ -2583,11 +2588,9 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
- When used with enable, the units
- will also be started. When used with disable or
- mask, the units will also be stopped. The start
- or stop operation is only carried out when the respective enable or
- disable operation has been successful.
+ When used with enable, disable, mask,
+ or reenable, also start/stop/try-restart the units after the specified
+ unit file operations succeed.
diff --git a/src/systemctl/systemctl-enable.c b/src/systemctl/systemctl-enable.c
index c8211e80c7..ad90765029 100644
--- a/src/systemctl/systemctl-enable.c
+++ b/src/systemctl/systemctl-enable.c
@@ -316,10 +316,26 @@ int verb_enable(int argc, char *argv[], void *userdata) {
if (arg_now) {
_cleanup_strv_free_ char **new_args = NULL;
+ const char *start_verb;
+ bool accept_path, prohibit_templates;
- if (!STR_IN_SET(verb, "enable", "disable", "mask"))
+ if (streq(verb, "enable")) {
+ start_verb = "start";
+ accept_path = true;
+ prohibit_templates = true;
+ } else if (STR_IN_SET(verb, "disable", "mask")) {
+ start_verb = "stop";
+ accept_path = false;
+ prohibit_templates = false;
+ } else if (streq(verb, "reenable")) {
+ /* Note that we use try-restart here. This matches the semantics of reenable better,
+ * and allows us to glob template units. */
+ start_verb = "try-restart";
+ accept_path = true;
+ prohibit_templates = false;
+ } else
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "--now can only be used with verb enable, disable, or mask.");
+ "--now can only be used with verb enable, disable, reenable, or mask.");
if (install_client_side())
return log_error_errno(SYNTHETIC_ERRNO(EREMOTE),
@@ -327,33 +343,46 @@ int verb_enable(int argc, char *argv[], void *userdata) {
assert(bus);
- if (strv_extend(&new_args, streq(verb, "enable") ? "start" : "stop") < 0)
+ if (strv_extend(&new_args, start_verb) < 0)
return log_oom();
STRV_FOREACH(name, names) {
- if (streq(verb, "enable")) {
- char *fn;
+ _cleanup_free_ char *fn = NULL;
+ const char *unit_name;
- /* 'enable' accept path to unit files, so extract it first. Don't try to
- * glob them though, as starting globbed unit seldom makes sense and
- * actually changes the semantic (we're operating on DefaultInstance=
- * when enabling). */
+ if (accept_path) {
+ /* 'enable' and 'reenable' accept path to unit files, so extract it first. */
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)) {
+ unit_name = fn;
+ } else
+ unit_name = *name;
+
+ if (unit_name_is_valid(unit_name, UNIT_NAME_TEMPLATE)) {
char *globbed;
- r = unit_name_replace_instance_full(*name, "*", /* accept_glob = */ true, &globbed);
+ if (prohibit_templates) {
+ /* Skip template units when enabling. Globbing doesn't make sense
+ * since the semantics would be altered (we're operating on
+ * DefaultInstance= when enabling), and starting template unit
+ * is not supported anyway. */
+ log_warning("Template unit is not supported by %s --now, skipping: %s",
+ verb, unit_name);
+ continue;
+ }
+
+ assert(!STR_IN_SET(start_verb, "start", "restart"));
+
+ r = unit_name_replace_instance_full(unit_name, "*", /* accept_glob = */ true, &globbed);
if (r < 0)
- return log_error_errno(r, "Failed to glob unit name '%s': %m", *name);
+ return log_error_errno(r, "Failed to glob unit name '%s': %m", unit_name);
r = strv_consume(&new_args, globbed);
} else
- r = strv_extend(&new_args, *name);
+ r = strv_extend(&new_args, unit_name);
if (r < 0)
return log_oom();
}