<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>
<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>
<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>
<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>
</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
<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
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;
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;
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)
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
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) {
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);
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,
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);
{ "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 },
{}
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(
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;
}
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);
char **aliases;
char **wanted_by;
char **required_by;
+ char **upheld_by;
char **also;
char *default_instance;
}
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"