Merge pull request #25437 from YHNdnzj/systemctl-disable-warn-statically-enabled-services
systemctl: warn if trying to disable a unit with no install info
This commit is contained in:
@@ -209,6 +209,10 @@ node /org/freedesktop/systemd1 {
|
||||
DisableUnitFilesWithFlags(in as files,
|
||||
in t flags,
|
||||
out a(sss) changes);
|
||||
DisableUnitFilesWithFlagsAndInstallInfo(in as files,
|
||||
in t flags,
|
||||
out b carries_install_info,
|
||||
out a(sss) changes);
|
||||
ReenableUnitFiles(in as files,
|
||||
in b runtime,
|
||||
in b force,
|
||||
@@ -916,6 +920,8 @@ node /org/freedesktop/systemd1 {
|
||||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="DisableUnitFilesWithFlags()"/>
|
||||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="DisableUnitFilesWithFlagsAndInstallInfo()"/>
|
||||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="ReenableUnitFiles()"/>
|
||||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="LinkUnitFiles()"/>
|
||||
@@ -1417,7 +1423,7 @@ node /org/freedesktop/systemd1 {
|
||||
enabled for runtime only (true, <filename>/run/</filename>), or persistently (false,
|
||||
<filename>/etc/</filename>). The second one controls whether symlinks pointing to other units shall be
|
||||
replaced if necessary. This method returns one boolean and an array of the changes made. The boolean
|
||||
signals whether the unit files contained any enablement information (i.e. an [Install]) section. The
|
||||
signals whether the unit files contained any enablement information (i.e. an [Install] section). The
|
||||
changes array consists of structures with three strings: the type of the change (one of
|
||||
<literal>symlink</literal> or <literal>unlink</literal>), the file name of the symlink and the
|
||||
destination of the symlink. Note that most of the following calls return a changes list in the same
|
||||
@@ -1440,6 +1446,11 @@ node /org/freedesktop/systemd1 {
|
||||
replaced if necessary. <varname>SD_SYSTEMD_UNIT_PORTABLE</varname> will add or remove the symlinks in
|
||||
<filename>/etc/systemd/system.attached</filename> and <filename>/run/systemd/system.attached</filename>.</para>
|
||||
|
||||
<para><function>DisableUnitFilesWithFlagsAndInstallInfo()</function> is similar to
|
||||
<function>DisableUnitFilesWithFlags()</function> and takes the same arguments, but returns
|
||||
a boolean to indicate whether the unit files contain any enablement information, like
|
||||
<function>EnableUnitFiles()</function>. The changes made are still returned in an array.</para>
|
||||
|
||||
<para>Similarly, <function>ReenableUnitFiles()</function> applies the changes to one or more units that
|
||||
would result from disabling and enabling the unit quickly one after the other in an atomic
|
||||
fashion. This is useful to apply updated [Install] information contained in unit files.</para>
|
||||
|
||||
+16
-2
@@ -771,6 +771,9 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
|
||||
account.
|
||||
</para>
|
||||
|
||||
<para>When using this operation on units without install information, a warning about it is shown.
|
||||
<option>--no-warn</option> can be used to suppress the warning.</para>
|
||||
|
||||
<para>Enabling units should not be confused with starting (activating) units, as done by the
|
||||
<command>start</command> command. Enabling and starting units is orthogonal: units may be enabled without
|
||||
being started and started without being enabled. Enabling simply hooks the unit into various suggested
|
||||
@@ -814,8 +817,8 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
|
||||
executed. This output may be suppressed by passing <option>--quiet</option>.
|
||||
</para>
|
||||
|
||||
<para>This command honors <option>--system</option>, <option>--user</option>, <option>--runtime</option>
|
||||
and <option>--global</option> in a similar way as <command>enable</command>.</para>
|
||||
<para>This command honors <option>--system</option>, <option>--user</option>, <option>--runtime</option>,
|
||||
<option>--global</option> and <option>--no-warn</option> in a similar way as <command>enable</command>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
@@ -1997,6 +2000,17 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--no-warn</option></term>
|
||||
|
||||
<listitem>
|
||||
<para>Don't generate the warning shown by default when using
|
||||
<command>enable</command> or <command>disable</command> on units
|
||||
without install information (i.e. don't have or have an empty
|
||||
[Install] section).</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--no-block</option></term>
|
||||
|
||||
|
||||
+16
-5
@@ -2425,6 +2425,7 @@ static int method_disable_unit_files_generic(
|
||||
sd_bus_message *message,
|
||||
Manager *m,
|
||||
int (*call)(LookupScope scope, UnitFileFlags flags, const char *root_dir, char *files[], InstallChange **changes, size_t *n_changes),
|
||||
bool carries_install_info,
|
||||
sd_bus_error *error) {
|
||||
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
@@ -2440,7 +2441,8 @@ static int method_disable_unit_files_generic(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (sd_bus_message_is_method_call(message, NULL, "DisableUnitFilesWithFlags")) {
|
||||
if (sd_bus_message_is_method_call(message, NULL, "DisableUnitFilesWithFlags") ||
|
||||
sd_bus_message_is_method_call(message, NULL, "DisableUnitFilesWithFlagsAndInstallInfo")) {
|
||||
uint64_t raw_flags;
|
||||
|
||||
r = sd_bus_message_read(message, "t", &raw_flags);
|
||||
@@ -2469,19 +2471,23 @@ static int method_disable_unit_files_generic(
|
||||
if (r < 0)
|
||||
return install_error(error, r, changes, n_changes);
|
||||
|
||||
return reply_install_changes_and_free(m, message, -1, changes, n_changes, error);
|
||||
return reply_install_changes_and_free(m, message, carries_install_info ? r : -1, changes, n_changes, error);
|
||||
}
|
||||
|
||||
static int method_disable_unit_files_with_flags(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
return method_disable_unit_files_generic(message, userdata, unit_file_disable, error);
|
||||
return method_disable_unit_files_generic(message, userdata, unit_file_disable, /* carries_install_info = */ false, error);
|
||||
}
|
||||
|
||||
static int method_disable_unit_files_with_flags_and_install_info(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
return method_disable_unit_files_generic(message, userdata, unit_file_disable, /* carries_install_info = */ true, error);
|
||||
}
|
||||
|
||||
static int method_disable_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
return method_disable_unit_files_generic(message, userdata, unit_file_disable, error);
|
||||
return method_disable_unit_files_generic(message, userdata, unit_file_disable, /* carries_install_info = */ false, error);
|
||||
}
|
||||
|
||||
static int method_unmask_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
return method_disable_unit_files_generic(message, userdata, unit_file_unmask, error);
|
||||
return method_disable_unit_files_generic(message, userdata, unit_file_unmask, /* carries_install_info = */ false, error);
|
||||
}
|
||||
|
||||
static int method_revert_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
@@ -3194,6 +3200,11 @@ const sd_bus_vtable bus_manager_vtable[] = {
|
||||
SD_BUS_RESULT("a(sss)", changes),
|
||||
method_disable_unit_files_with_flags,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD_WITH_ARGS("DisableUnitFilesWithFlagsAndInstallInfo",
|
||||
SD_BUS_ARGS("as", files, "t", flags),
|
||||
SD_BUS_RESULT("b", carries_install_info, "a(sss)", changes),
|
||||
method_disable_unit_files_with_flags_and_install_info,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD_WITH_ARGS("ReenableUnitFiles",
|
||||
SD_BUS_ARGS("as", files, "b", runtime, "b", force),
|
||||
SD_BUS_RESULT("b", carries_install_info, "a(sss)", changes),
|
||||
|
||||
@@ -19,21 +19,21 @@ case "$command" in
|
||||
|
||||
remove-system-units)
|
||||
if [ -d /run/systemd/system ]; then
|
||||
systemctl --no-reload disable --now "$@"
|
||||
systemctl --no-reload disable --now --no-warn "$@"
|
||||
else
|
||||
systemctl --no-reload disable "$@"
|
||||
systemctl --no-reload disable --no-warn "$@"
|
||||
fi
|
||||
;;
|
||||
|
||||
remove-user-units)
|
||||
systemctl --global disable "$@"
|
||||
systemctl --global disable --no-warn "$@"
|
||||
|
||||
[ -d /run/systemd/system ] || exit 0
|
||||
|
||||
users=$(systemctl list-units 'user@*' --legend=no | sed -n -r 's/.*user@([0-9]+).service.*/\1/p')
|
||||
for user in $users; do
|
||||
SYSTEMD_BUS_TIMEOUT={{UPDATE_HELPER_USER_TIMEOUT}} \
|
||||
systemctl --user -M "$user@" disable --now "$@" &
|
||||
systemctl --user -M "$user@" disable --now --no-warn "$@" &
|
||||
done
|
||||
wait
|
||||
;;
|
||||
|
||||
+17
-4
@@ -2790,25 +2790,38 @@ static int do_unit_file_disable(
|
||||
|
||||
_cleanup_(install_context_done) InstallContext ctx = { .scope = scope };
|
||||
_cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
|
||||
InstallInfo *info;
|
||||
bool has_install_info = false;
|
||||
int r;
|
||||
|
||||
STRV_FOREACH(name, names) {
|
||||
if (!unit_name_is_valid(*name, UNIT_NAME_ANY))
|
||||
return install_changes_add(changes, n_changes, -EUCLEAN, *name, NULL);
|
||||
|
||||
r = install_info_add(&ctx, *name, NULL, lp->root_dir, /* auxiliary= */ false, NULL);
|
||||
r = install_info_add(&ctx, *name, NULL, lp->root_dir, /* auxiliary= */ false, &info);
|
||||
if (r >= 0)
|
||||
r = install_info_traverse(&ctx, lp, info, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, NULL);
|
||||
|
||||
if (r < 0)
|
||||
return r;
|
||||
return install_changes_add(changes, n_changes, r, *name, NULL);
|
||||
|
||||
/* If we enable multiple units, some with install info and others without,
|
||||
* the "empty [Install] section" warning is not shown. Let's make the behavior
|
||||
* of disable align with that. */
|
||||
has_install_info = has_install_info || install_info_has_rules(info) || install_info_has_also(info);
|
||||
}
|
||||
|
||||
r = install_context_mark_for_removal(&ctx, lp, &remove_symlinks_to, config_path, changes, n_changes);
|
||||
if (r >= 0)
|
||||
r = remove_marked_symlinks(remove_symlinks_to, config_path, lp, flags & UNIT_FILE_DRY_RUN, changes, n_changes);
|
||||
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return remove_marked_symlinks(remove_symlinks_to, config_path, lp, flags & UNIT_FILE_DRY_RUN, changes, n_changes);
|
||||
/* The warning is shown only if it's a no-op */
|
||||
return install_changes_have_modification(*changes, *n_changes) || has_install_info;
|
||||
}
|
||||
|
||||
|
||||
int unit_file_disable(
|
||||
LookupScope scope,
|
||||
UnitFileFlags flags,
|
||||
|
||||
@@ -67,7 +67,7 @@ int verb_enable(int argc, char *argv[], void *userdata) {
|
||||
InstallChange *changes = NULL;
|
||||
size_t n_changes = 0;
|
||||
int carries_install_info = -1;
|
||||
bool ignore_carries_install_info = arg_quiet;
|
||||
bool ignore_carries_install_info = arg_quiet || arg_no_warn;
|
||||
int r;
|
||||
|
||||
if (!argv[1])
|
||||
@@ -109,9 +109,10 @@ int verb_enable(int argc, char *argv[], void *userdata) {
|
||||
if (streq(verb, "enable")) {
|
||||
r = unit_file_enable(arg_scope, flags, arg_root, names, &changes, &n_changes);
|
||||
carries_install_info = r;
|
||||
} else if (streq(verb, "disable"))
|
||||
} else if (streq(verb, "disable")) {
|
||||
r = unit_file_disable(arg_scope, flags, arg_root, names, &changes, &n_changes);
|
||||
else if (streq(verb, "reenable")) {
|
||||
carries_install_info = r;
|
||||
} else if (streq(verb, "reenable")) {
|
||||
r = unit_file_reenable(arg_scope, flags, arg_root, names, &changes, &n_changes);
|
||||
carries_install_info = r;
|
||||
} else if (streq(verb, "link"))
|
||||
@@ -165,7 +166,8 @@ int verb_enable(int argc, char *argv[], void *userdata) {
|
||||
method = "EnableUnitFiles";
|
||||
expect_carries_install_info = true;
|
||||
} else if (streq(verb, "disable")) {
|
||||
method = "DisableUnitFiles";
|
||||
method = "DisableUnitFilesWithFlagsAndInstallInfo";
|
||||
expect_carries_install_info = true;
|
||||
send_force = false;
|
||||
} else if (streq(verb, "reenable")) {
|
||||
method = "ReenableUnitFiles";
|
||||
@@ -208,7 +210,10 @@ int verb_enable(int argc, char *argv[], void *userdata) {
|
||||
}
|
||||
|
||||
if (send_runtime) {
|
||||
r = sd_bus_message_append(m, "b", arg_runtime);
|
||||
if (streq(method, "DisableUnitFilesWithFlagsAndInstallInfo"))
|
||||
r = sd_bus_message_append(m, "t", arg_runtime ? UNIT_FILE_RUNTIME : 0);
|
||||
else
|
||||
r = sd_bus_message_append(m, "b", arg_runtime);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
}
|
||||
@@ -245,7 +250,7 @@ int verb_enable(int argc, char *argv[], void *userdata) {
|
||||
if (carries_install_info == 0 && !ignore_carries_install_info)
|
||||
log_notice("The unit files have no installation config (WantedBy=, RequiredBy=, Also=,\n"
|
||||
"Alias= settings in the [Install] section, and DefaultInstance= for template\n"
|
||||
"units). This means they are not meant to be enabled using systemctl.\n"
|
||||
"units). This means they are not meant to be enabled or disabled using systemctl.\n"
|
||||
" \n" /* trick: the space is needed so that the line does not get stripped from output */
|
||||
"Possible reasons for having this kind of units are:\n"
|
||||
"%1$s A unit may be statically enabled by being symlinked from another unit's\n"
|
||||
|
||||
@@ -84,6 +84,7 @@ bool arg_show_types = false;
|
||||
int arg_check_inhibitors = -1;
|
||||
bool arg_dry_run = false;
|
||||
bool arg_quiet = false;
|
||||
bool arg_no_warn = false;
|
||||
bool arg_full = false;
|
||||
bool arg_recursive = false;
|
||||
bool arg_with_dependencies = false;
|
||||
@@ -277,6 +278,8 @@ static int systemctl_help(void) {
|
||||
" kexec, suspend, hibernate, suspend-then-hibernate,\n"
|
||||
" hybrid-sleep, default, rescue, emergency, and exit.\n"
|
||||
" -q --quiet Suppress output\n"
|
||||
" --no-warn Don't generate warning when trying to enable/disable\n"
|
||||
" units without install information\n"
|
||||
" --wait For (re)start, wait until service stopped again\n"
|
||||
" For is-system-running, wait until startup is completed\n"
|
||||
" --no-block Do not wait until operation finished\n"
|
||||
@@ -433,6 +436,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
|
||||
ARG_READ_ONLY,
|
||||
ARG_MKDIR,
|
||||
ARG_MARKED,
|
||||
ARG_NO_WARN,
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
@@ -465,6 +469,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
|
||||
{ "no-wall", no_argument, NULL, ARG_NO_WALL },
|
||||
{ "dry-run", no_argument, NULL, ARG_DRY_RUN },
|
||||
{ "quiet", no_argument, NULL, 'q' },
|
||||
{ "no-warn", no_argument, NULL, ARG_NO_WARN },
|
||||
{ "root", required_argument, NULL, ARG_ROOT },
|
||||
{ "image", required_argument, NULL, ARG_IMAGE },
|
||||
{ "force", no_argument, NULL, 'f' },
|
||||
@@ -926,6 +931,10 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
|
||||
arg_marked = true;
|
||||
break;
|
||||
|
||||
case ARG_NO_WARN:
|
||||
arg_no_warn = true;
|
||||
break;
|
||||
|
||||
case '.':
|
||||
/* Output an error mimicking getopt, and print a hint afterwards */
|
||||
log_error("%s: invalid option -- '.'", program_invocation_name);
|
||||
|
||||
@@ -65,6 +65,7 @@ extern bool arg_show_types;
|
||||
extern int arg_check_inhibitors;
|
||||
extern bool arg_dry_run;
|
||||
extern bool arg_quiet;
|
||||
extern bool arg_no_warn;
|
||||
extern bool arg_full;
|
||||
extern bool arg_recursive;
|
||||
extern bool arg_with_dependencies;
|
||||
|
||||
Reference in New Issue
Block a user