mirror of
https://github.com/systemd/systemd.git
synced 2024-11-24 02:33:36 +08:00
Merge pull request #27638 from YHNdnzj/upheldby-unit-file
unit-file: support UpheldBy= in [Install] settings (adding Upholds= deps from .upholds/)
This commit is contained in:
commit
0313c41068
@ -367,10 +367,9 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
|
||||
<listitem>
|
||||
<para>Shows units required and wanted by the specified
|
||||
units. This recursively lists units following the
|
||||
<varname>Requires=</varname>,
|
||||
<varname>Requisite=</varname>,
|
||||
<varname>ConsistsOf=</varname>,
|
||||
<varname>Wants=</varname>, <varname>BindsTo=</varname>
|
||||
<varname>Requires=</varname>, <varname>Requisite=</varname>,
|
||||
<varname>Wants=</varname>, <varname>ConsistsOf=</varname>,
|
||||
<varname>BindsTo=</varname>, and <varname>Upholds=</varname>
|
||||
dependencies. If no units are specified,
|
||||
<filename>default.target</filename> is implied.</para>
|
||||
|
||||
@ -1791,7 +1790,7 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
|
||||
<para>Show reverse dependencies between units with
|
||||
<command>list-dependencies</command>, i.e. follow
|
||||
dependencies of type <varname>WantedBy=</varname>,
|
||||
<varname>RequiredBy=</varname>,
|
||||
<varname>RequiredBy=</varname>, <varname>UpheldBy=</varname>,
|
||||
<varname>PartOf=</varname>, <varname>BoundBy=</varname>,
|
||||
instead of <varname>Wants=</varname> and similar.
|
||||
</para>
|
||||
|
@ -749,8 +749,7 @@
|
||||
|
||||
<para>When <varname>Upholds=b.service</varname> is used on <filename>a.service</filename>, this
|
||||
dependency will show as <varname>UpheldBy=a.service</varname> in the property listing of
|
||||
<filename>b.service</filename>. The <varname>UpheldBy=</varname> dependency cannot be specified
|
||||
directly.</para>
|
||||
<filename>b.service</filename>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
@ -1848,6 +1847,12 @@
|
||||
<entry>[Unit] section</entry>
|
||||
<entry>[Install] section</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><varname>Upholds=</varname></entry>
|
||||
<entry><varname>UpheldBy=</varname></entry>
|
||||
<entry>[Unit] section</entry>
|
||||
<entry>[Install] section</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><varname>PartOf=</varname></entry>
|
||||
<entry><varname>ConsistsOf=</varname></entry>
|
||||
@ -1895,10 +1900,10 @@
|
||||
</tgroup>
|
||||
</table>
|
||||
|
||||
<para>Note: <varname>WantedBy=</varname> and <varname>RequiredBy=</varname> are
|
||||
used in the [Install] section to create symlinks in <filename>.wants/</filename>
|
||||
and <filename>.requires/</filename> directories. They cannot be used directly as a
|
||||
unit configuration setting.</para>
|
||||
<para>Note: <varname>WantedBy=</varname>, <varname>RequiredBy=</varname>, and <varname>UpheldBy=</varname>
|
||||
are used in the [Install] section to create symlinks in <filename>.wants/</filename>,
|
||||
<filename>.requires/</filename>, and <filename>.upholds/</filename> directories. They cannot be used
|
||||
directly as a unit configuration setting.</para>
|
||||
|
||||
<para>Note: <varname>ConsistsOf=</varname>, <varname>BoundBy=</varname>,
|
||||
<varname>RequisiteOf=</varname>, <varname>ConflictedBy=</varname> are created
|
||||
@ -1947,23 +1952,23 @@
|
||||
<varlistentry>
|
||||
<term><varname>WantedBy=</varname></term>
|
||||
<term><varname>RequiredBy=</varname></term>
|
||||
<term><varname>UpheldBy=</varname></term>
|
||||
|
||||
<listitem><para>This option may be used more than once, or a space-separated list of unit names may
|
||||
be given. A symbolic link is created in the <filename>.wants/</filename> or
|
||||
<filename>.requires/</filename> directory of each of the listed units when this unit is installed by
|
||||
<command>systemctl enable</command>. This has the effect of a dependency of type
|
||||
<varname>Wants=</varname> or <varname>Requires=</varname> being added from the listed unit to the
|
||||
current unit. The primary result is that the current unit will be started when the listed unit is
|
||||
started, see the description of <varname>Wants=</varname> and <varname>Requires=</varname> in the
|
||||
[Unit] section for details.</para>
|
||||
be given. A symbolic link is created in the <filename>.wants/</filename>, <filename>.requires/</filename>,
|
||||
or <filename>.upholds/</filename> directory of each of the listed units when this unit is installed
|
||||
by <command>systemctl enable</command>. This has the effect of a dependency of type
|
||||
<varname>Wants=</varname>, <varname>Requires=</varname>, or <varname>Upholds=</varname> being added
|
||||
from the listed unit to the current unit. See the description of the mentioned dependency types
|
||||
in the [Unit] section for details.</para>
|
||||
|
||||
<para>In case of template units listing non template units, the listing unit must have
|
||||
<varname>DefaultInstance=</varname> set, or <command>systemctl enable</command> must be called with
|
||||
an instance name. The instance (default or specified) will be added to the
|
||||
<filename>.wants/</filename> or <filename>.requires/</filename> list of the listed unit. For example,
|
||||
<command>WantedBy=getty.target</command> in a service <filename>getty@.service</filename> will result
|
||||
in <command>systemctl enable getty@tty2.service</command> creating a
|
||||
<filename>getty.target.wants/getty@tty2.service</filename> link to
|
||||
<filename>.wants/</filename>, <filename>.requires/</filename>, or <filename>.upholds/</filename>
|
||||
list of the listed unit. For example, <command>WantedBy=getty.target</command> in a service
|
||||
<filename>getty@.service</filename> will result in <command>systemctl enable getty@tty2.service</command>
|
||||
creating a <filename>getty.target.wants/getty@tty2.service</filename> link to
|
||||
<filename>getty@.service</filename>. This also applies to listing specific instances of templated
|
||||
units: this specific instance will gain the dependency. A template unit may also list a template
|
||||
unit, in which case a generic dependency will be added where each instance of the listing unit will
|
||||
|
@ -250,9 +250,10 @@ bool lookup_paths_timestamp_hash_same(const LookupPaths *lp, uint64_t timestamp_
|
||||
|
||||
static int directory_name_is_valid(const char *name) {
|
||||
|
||||
/* Accept a directory whose name is a valid unit file name ending in .wants/, .requires/ or .d/ */
|
||||
/* Accept a directory whose name is a valid unit file name ending in .wants/, .requires/,
|
||||
* .upholds/ or .d/ */
|
||||
|
||||
FOREACH_STRING(suffix, ".wants", ".requires", ".d") {
|
||||
FOREACH_STRING(suffix, ".wants", ".requires", ".upholds", ".d") {
|
||||
_cleanup_free_ char *chopped = NULL;
|
||||
const char *e;
|
||||
|
||||
|
@ -88,7 +88,7 @@ int unit_load_dropin(Unit *u) {
|
||||
|
||||
assert(u);
|
||||
|
||||
/* Load dependencies from .wants and .requires directories */
|
||||
/* Load dependencies from .wants, .requires and .upholds directories */
|
||||
r = process_deps(u, UNIT_WANTS, ".wants");
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -97,6 +97,10 @@ int unit_load_dropin(Unit *u) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = process_deps(u, UNIT_UPHOLDS, ".upholds");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Load .conf dropins */
|
||||
r = unit_find_dropin_paths(u, &l);
|
||||
if (r <= 0)
|
||||
|
@ -580,5 +580,6 @@ Scope.OOMPolicy, config_parse_oom_policy,
|
||||
Install.Alias, NULL, 0, 0
|
||||
Install.WantedBy, NULL, 0, 0
|
||||
Install.RequiredBy, NULL, 0, 0
|
||||
Install.UpheldBy, NULL, 0, 0
|
||||
Install.Also, NULL, 0, 0
|
||||
Install.DefaultInstance, NULL, 0, 0
|
||||
|
@ -73,7 +73,8 @@ static bool install_info_has_rules(const InstallInfo *i) {
|
||||
|
||||
return !strv_isempty(i->aliases) ||
|
||||
!strv_isempty(i->wanted_by) ||
|
||||
!strv_isempty(i->required_by);
|
||||
!strv_isempty(i->required_by) ||
|
||||
!strv_isempty(i->upheld_by);
|
||||
}
|
||||
|
||||
static bool install_info_has_also(const InstallInfo *i) {
|
||||
@ -942,7 +943,7 @@ static int find_symlinks(
|
||||
continue;
|
||||
|
||||
suffix = strrchr(de->d_name, '.');
|
||||
if (!STRPTR_IN_SET(suffix, ".wants", ".requires"))
|
||||
if (!STRPTR_IN_SET(suffix, ".wants", ".requires", ".upholds"))
|
||||
continue;
|
||||
|
||||
path = path_join(config_path, de->d_name);
|
||||
@ -967,7 +968,8 @@ static int find_symlinks(
|
||||
log_debug_errno(r, "Failed to look up symlinks in \"%s\": %m", path);
|
||||
}
|
||||
|
||||
/* We didn't find any suitable symlinks in .wants or .requires directories, let's look for linked unit files in this directory. */
|
||||
/* We didn't find any suitable symlinks in .wants, .requires or .upholds directories,
|
||||
* let's look for linked unit files in this directory. */
|
||||
rewinddir(config_dir);
|
||||
return find_symlinks_in_directory(config_dir, config_path, root_dir, i,
|
||||
/* ignore_destination= */ false,
|
||||
@ -1081,6 +1083,7 @@ static void install_info_clear(InstallInfo *i) {
|
||||
i->aliases = strv_free(i->aliases);
|
||||
i->wanted_by = strv_free(i->wanted_by);
|
||||
i->required_by = strv_free(i->required_by);
|
||||
i->upheld_by = strv_free(i->upheld_by);
|
||||
i->also = strv_free(i->also);
|
||||
i->default_instance = mfree(i->default_instance);
|
||||
i->symlink_target = mfree(i->symlink_target);
|
||||
@ -1337,6 +1340,7 @@ static int unit_file_load(
|
||||
{ "Install", "Alias", config_parse_alias, 0, &info->aliases },
|
||||
{ "Install", "WantedBy", config_parse_strv, 0, &info->wanted_by },
|
||||
{ "Install", "RequiredBy", config_parse_strv, 0, &info->required_by },
|
||||
{ "Install", "UpheldBy", config_parse_strv, 0, &info->upheld_by },
|
||||
{ "Install", "DefaultInstance", config_parse_default_instance, 0, info },
|
||||
{ "Install", "Also", config_parse_also, 0, ctx },
|
||||
{}
|
||||
@ -1440,7 +1444,8 @@ static int unit_file_load(
|
||||
return
|
||||
(int) strv_length(info->aliases) +
|
||||
(int) strv_length(info->wanted_by) +
|
||||
(int) strv_length(info->required_by);
|
||||
(int) strv_length(info->required_by) +
|
||||
(int) strv_length(info->upheld_by);
|
||||
}
|
||||
|
||||
static int unit_file_load_or_readlink(
|
||||
@ -2113,6 +2118,10 @@ static int install_info_apply(
|
||||
if (r == 0)
|
||||
r = q;
|
||||
|
||||
q = install_info_symlink_wants(scope, file_flags, info, lp, config_path, info->upheld_by, ".upholds/", changes, n_changes);
|
||||
if (r == 0)
|
||||
r = q;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -2733,8 +2742,10 @@ int unit_file_add_dependency(
|
||||
|
||||
if (dep == UNIT_WANTS)
|
||||
l = &info->wanted_by;
|
||||
else
|
||||
else if (dep == UNIT_REQUIRES)
|
||||
l = &info->required_by;
|
||||
else
|
||||
l = &info->upheld_by;
|
||||
|
||||
strv_free(*l);
|
||||
*l = strv_new(target_info->name);
|
||||
|
@ -92,6 +92,7 @@ struct InstallInfo {
|
||||
char **aliases;
|
||||
char **wanted_by;
|
||||
char **required_by;
|
||||
char **upheld_by;
|
||||
char **also;
|
||||
|
||||
char *default_instance;
|
||||
|
@ -248,9 +248,9 @@ 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 or disabled using systemctl.\n"
|
||||
log_notice("The unit files have no installation config (WantedBy=, RequiredBy=, UpheldBy=,\n"
|
||||
"Also=, or Alias= settings in the [Install] section, and DefaultInstance= for\n"
|
||||
"template 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"
|
||||
|
@ -1135,6 +1135,9 @@ TEST(verify_alias) {
|
||||
verify_one(&plain_service, "alias.socket", -EXDEV, NULL);
|
||||
verify_one(&plain_service, "alias@.service", -EXDEV, NULL);
|
||||
verify_one(&plain_service, "alias@inst.service", -EXDEV, NULL);
|
||||
|
||||
/* Setting WantedBy= and RequiredBy= through Alias= is supported for the sake of backwards
|
||||
* compatibility. */
|
||||
verify_one(&plain_service, "foo.target.wants/plain.service", 0, NULL);
|
||||
verify_one(&plain_service, "foo.target.wants/plain.socket", -EXDEV, NULL);
|
||||
verify_one(&plain_service, "foo.target.wants/plain@.service", -EXDEV, NULL);
|
||||
@ -1143,9 +1146,14 @@ TEST(verify_alias) {
|
||||
verify_one(&plain_service, "foo.target.requires/plain.socket", -EXDEV, NULL);
|
||||
verify_one(&plain_service, "foo.target.requires/plain@.service", -EXDEV, NULL);
|
||||
verify_one(&plain_service, "foo.target.requires/service", -EXDEV, NULL);
|
||||
verify_one(&plain_service, "foo.target.conf/plain.service", -EXDEV, NULL);
|
||||
verify_one(&plain_service, "foo.service/plain.service", -EXDEV, NULL); /* missing dir suffix */
|
||||
verify_one(&plain_service, "asdf.requires/plain.service", -EXDEV, NULL); /* invalid unit name component */
|
||||
/* The newly-added UpheldBy= (.upholds/) and other suffixes should be rejected */
|
||||
verify_one(&plain_service, "foo.target.upholds/plain.service", -EXDEV, NULL);
|
||||
verify_one(&plain_service, "foo.target.upholds/plain.socket", -EXDEV, NULL);
|
||||
verify_one(&plain_service, "foo.target.upholds/plain@.service", -EXDEV, NULL);
|
||||
verify_one(&plain_service, "foo.target.upholds/service", -EXDEV, NULL);
|
||||
verify_one(&plain_service, "foo.service/plain.service", -EXDEV, NULL); /* missing dir suffix */
|
||||
verify_one(&plain_service, "foo.target.conf/plain.service", -EXDEV, NULL);
|
||||
|
||||
verify_one(&bare_template, "alias.service", -EXDEV, NULL);
|
||||
verify_one(&bare_template, "alias.socket", -EXDEV, NULL);
|
||||
|
@ -269,6 +269,8 @@ Type=
|
||||
USBFunctionDescriptors=
|
||||
USBFunctionStrings=
|
||||
Unit=
|
||||
UpheldBy=
|
||||
Upholds=
|
||||
User=
|
||||
WakeSystem=
|
||||
WantedBy=
|
||||
|
@ -0,0 +1,9 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
[Unit]
|
||||
Description=Unit that sets UpheldBy= through [Install]
|
||||
|
||||
[Service]
|
||||
ExecStart=/bin/sleep infinity
|
||||
|
||||
[Install]
|
||||
UpheldBy=testsuite-23-retry-uphold.service
|
@ -30,6 +30,8 @@ done
|
||||
|
||||
systemctl stop testsuite-23-uphold.service
|
||||
|
||||
systemctl enable testsuite-23-upheldby-install.service
|
||||
|
||||
# Idea is this:
|
||||
# 1. we start testsuite-23-retry-uphold.service
|
||||
# 2. which through Uphold= starts testsuite-23-retry-upheld.service
|
||||
@ -42,12 +44,13 @@ systemctl stop testsuite-23-uphold.service
|
||||
|
||||
rm -f /tmp/testsuite-23-retry-fail
|
||||
systemctl start testsuite-23-retry-uphold.service
|
||||
systemctl is-active testsuite-23-upheldby-install.service
|
||||
|
||||
while ! systemctl is-failed testsuite-23-retry-fail.service ; do
|
||||
sleep .5
|
||||
done
|
||||
|
||||
systemctl is-active testsuite-23-retry-upheld.service && { echo 'unexpected success'; exit 1; }
|
||||
(! systemctl is-active testsuite-23-retry-upheld.service)
|
||||
|
||||
touch /tmp/testsuite-23-retry-fail
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user