one is then considered the main process of the unit (if it can be determined). This is different
for service units of other types, where the process forked off by the manager for
<varname>ExecStart=</varname> is always the main process itself. A service unit consists of zero or
- one main process, zero or one control process plus any number of additional processes. Not all unit
- types manage processes of these types however. For example, for mount units, control processes are
- defined (which are the invocations of <filename>&MOUNT_PATH;</filename> and
- <filename>&UMOUNT_PATH;</filename>), but no main process is defined. If omitted, defaults to
- <option>all</option>.</para>
+ one main process, zero or one control process plus any number of additional processes part of the
+ unit's control group. Not all unit types manage processes of these types however. For example, for
+ mount units, control processes are defined (which are the invocations of
+ <filename>&MOUNT_PATH;</filename> and <filename>&UMOUNT_PATH;</filename>), but no main process is
+ defined. If omitted, defaults to <option>all</option>, except if <option>--kill-subgroup=</option>
+ is used in which case defaults to <option>cgroup</option>.</para>
<xi:include href="version-info.xml" xpointer="v252"/>
</listitem>
<xi:include href="version-info.xml" xpointer="v254"/></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--kill-subgroup=<replaceable>PATH</replaceable></option></term>
+
+ <listitem><para>Takes a control group sub-path to send signals to, for use with the
+ <command>kill</command> command. By default the chosen signal is delivered to all processes of the
+ unit's cgroups (as well as the main/control processes (if outside) – subject to
+ <option>--kill-whom=</option>). But with this option a subgroup can be selelected instead. This
+ functionality is only available if <literal>cgroup</literal> or <literal>cgroup-fail</literal> are
+ used with <option>--kill-whom=</option>, and in fact the former is the default if
+ <option>--kill-subgroup=</option> is used.</para>
+
+ <para>The specified path may, but doesn't have to be prefixed with a slash, and its absence or
+ presence has no effect, the path is either way taken relative to the unit's main control group
+ path.</para>
+
+ <para>This functionality is only available on units where control group delegation is enabled (see
+ <varname>Delegate=</varname> in
+ <member><citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry></member>).</para>
+
+ <xi:include href="version-info.xml" xpointer="v258"/></listitem>
+ </varlistentry>
+
<xi:include href="standard-options.xml" xpointer="signal" />
<varlistentry>
sd_bus *bus;
int r, q;
+ if (arg_kill_subgroup && arg_kill_value_set)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--kill-subgroup= and --kill-value= may not be combined.");
+
r = acquire_bus(BUS_MANAGER, &bus);
if (r < 0)
return r;
polkit_agent_open_maybe();
- kill_whom = arg_kill_whom ?: "all";
+ kill_whom = arg_kill_whom ?: arg_kill_subgroup ? "cgroup" : "all";
/* --fail was specified */
if (streq(arg_job_mode(), "fail"))
&error,
NULL,
"ssii", *name, kill_whom, arg_signal, arg_kill_value);
+ else if (arg_kill_subgroup)
+ q = bus_call_method(
+ bus,
+ bus_systemd_mgr,
+ "KillUnitSubgroup",
+ &error,
+ NULL,
+ "sssi", *name, kill_whom, arg_kill_subgroup, arg_signal);
else
q = bus_call_method(
bus,
#include "pager.h"
#include "parse-argument.h"
#include "parse-util.h"
+#include "path-util.h"
#include "pretty-print.h"
#include "static-destruct.h"
#include "string-table.h"
bool arg_marked = false;
const char *arg_drop_in = NULL;
ImagePolicy *arg_image_policy = NULL;
+char *arg_kill_subgroup = NULL;
STATIC_DESTRUCTOR_REGISTER(arg_types, strv_freep);
STATIC_DESTRUCTOR_REGISTER(arg_states, strv_freep);
STATIC_DESTRUCTOR_REGISTER(arg_clean_what, strv_freep);
STATIC_DESTRUCTOR_REGISTER(arg_drop_in, unsetp);
STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep);
+STATIC_DESTRUCTOR_REGISTER(arg_kill_subgroup, freep);
static int systemctl_help(void) {
_cleanup_free_ char *link = NULL;
" Whether to check inhibitors before shutting down,\n"
" sleeping, or hibernating\n"
" -i Shortcut for --check-inhibitors=no\n"
+ " -s --signal=SIGNAL Which signal to send\n"
" --kill-whom=WHOM Whom to send signal to\n"
" --kill-value=INT Signal value to enqueue\n"
- " -s --signal=SIGNAL Which signal to send\n"
+ " --kill-subgroup=PATH\n"
+ " Send signal to sub-control-group only\n"
" --what=RESOURCES Which types of resources to remove\n"
" --now Start or stop unit after enabling or disabling it\n"
" --dry-run Only print what would be done\n"
ARG_DROP_IN,
ARG_WHEN,
ARG_STDIN,
+ ARG_KILL_SUBGROUP,
};
static const struct option options[] = {
{ "drop-in", required_argument, NULL, ARG_DROP_IN },
{ "when", required_argument, NULL, ARG_WHEN },
{ "stdin", no_argument, NULL, ARG_STDIN },
+ { "kill-subgroup", required_argument, NULL, ARG_KILL_SUBGROUP },
{}
};
arg_stdin = true;
break;
+ case ARG_KILL_SUBGROUP: {
+ if (empty_or_root(optarg)) {
+ arg_kill_subgroup = mfree(arg_kill_subgroup);
+ break;
+ }
+
+ _cleanup_free_ char *p = NULL;
+ if (path_simplify_alloc(optarg, &p) < 0)
+ return log_oom();
+
+ if (!path_is_safe(p))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Control group sub-path '%s' is not valid.", p);
+
+ free_and_replace(arg_kill_subgroup, p);
+ break;
+ }
+
case '.':
/* Output an error mimicking getopt, and print a hint afterwards */
log_error("%s: invalid option -- '.'", program_invocation_name);
extern bool arg_marked;
extern const char *arg_drop_in;
extern ImagePolicy *arg_image_policy;
+extern char *arg_kill_subgroup;
static inline const char* arg_job_mode(void) {
return _arg_job_mode ?: "replace";