mirror of
https://github.com/systemd/systemd
synced 2025-10-09 05:34:45 +02:00
Compare commits
40 Commits
a2123bf9d4
...
18eafedb1a
Author | SHA1 | Date | |
---|---|---|---|
![]() |
18eafedb1a | ||
![]() |
0d8f8be2fd | ||
![]() |
a5ddad2795 | ||
![]() |
8cf772edc1 | ||
![]() |
6b02854f50 | ||
![]() |
0f23564ad4 | ||
![]() |
9afe65d974 | ||
![]() |
3ef791876b | ||
![]() |
ef6b6f31c7 | ||
![]() |
bb176bdb51 | ||
![]() |
825a1f9ecb | ||
![]() |
c777c05125 | ||
![]() |
e8e274c8da | ||
![]() |
a89afe1948 | ||
![]() |
26c6f3271a | ||
![]() |
744086b58d | ||
![]() |
81e6b3685a | ||
![]() |
652ba6e0dc | ||
![]() |
1e7ba4780d | ||
![]() |
2030922e2d | ||
![]() |
9880c7f103 | ||
![]() |
a1c7aa6a95 | ||
![]() |
199989e168 | ||
![]() |
6fbb1abf03 | ||
![]() |
f273212797 | ||
![]() |
dc537d9479 | ||
![]() |
7af676c1b6 | ||
![]() |
ed82caeb39 | ||
![]() |
00c4851af0 | ||
![]() |
432e42703e | ||
![]() |
92172973b1 | ||
![]() |
09f380e4e7 | ||
![]() |
f3393148a5 | ||
![]() |
f26d5d76e9 | ||
![]() |
65df8be24b | ||
![]() |
24e67cea45 | ||
![]() |
90fa161b5b | ||
![]() |
bda934d4e5 | ||
![]() |
2d9759ae6a | ||
![]() |
3bb59e28f9 |
4
TODO
4
TODO
@ -122,6 +122,10 @@ Deprecations and removals:
|
|||||||
https://github.com/util-linux/util-linux/commit/508fb0e7ac103b68531a59db2a4473897853ab52
|
https://github.com/util-linux/util-linux/commit/508fb0e7ac103b68531a59db2a4473897853ab52
|
||||||
has hit the prominent distributions, revert --issue-file= hack in units/*getty*service.in
|
has hit the prominent distributions, revert --issue-file= hack in units/*getty*service.in
|
||||||
|
|
||||||
|
* Once kernel baseline is 5.7, obsolete DefaultMemoryMin/Low= and DefaultStartupMemoryLow=
|
||||||
|
since we can systematically enable memory_recursiveprot on cgroupfs and have those
|
||||||
|
enforced by the kernel
|
||||||
|
|
||||||
Features:
|
Features:
|
||||||
|
|
||||||
* replace bootctl's PE version check to actually use APIs from pe-binary.[ch]
|
* replace bootctl's PE version check to actually use APIs from pe-binary.[ch]
|
||||||
|
14
docs/DISK-QUOTAS-PROJECTIDS.md
Normal file
14
docs/DISK-QUOTAS-PROJECTIDS.md
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
---
|
||||||
|
title: Project IDs for Disk Quotas on Exec Directories
|
||||||
|
category: Exec directories
|
||||||
|
layout: default
|
||||||
|
SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
---
|
||||||
|
|
||||||
|
# Project IDs on systemd Systems
|
||||||
|
|
||||||
|
Project IDs are needed to enforce disk quotas for Exec Directories.
|
||||||
|
Project IDs are unsigned, 32-bit integers. For disk quota enforcement,
|
||||||
|
the range used is 2147483648 - 4294967294, which is the highest range
|
||||||
|
inspired from `UIDS-GUID.md`. The range is defined through `PROJ_ID_MIN`
|
||||||
|
and `PROJ_ID_MAX` in `exec-invoke.c`.
|
@ -257,10 +257,16 @@ All execution-related settings are available for transient units.
|
|||||||
✓ RuntimeDirectoryMode=
|
✓ RuntimeDirectoryMode=
|
||||||
✓ RuntimeDirectory=
|
✓ RuntimeDirectory=
|
||||||
✓ StateDirectoryMode=
|
✓ StateDirectoryMode=
|
||||||
|
✓ StateDirectoryAccounting=
|
||||||
|
✓ StateDirectoryQuota=
|
||||||
✓ StateDirectory=
|
✓ StateDirectory=
|
||||||
✓ CacheDirectoryMode=
|
✓ CacheDirectoryMode=
|
||||||
|
✓ CacheDirectoryAccounting=
|
||||||
|
✓ CacheDirectoryQuota=
|
||||||
✓ CacheDirectory=
|
✓ CacheDirectory=
|
||||||
✓ LogsDirectoryMode=
|
✓ LogsDirectoryMode=
|
||||||
|
✓ LogsDirectoryAccounting=
|
||||||
|
✓ LogsDirectoryQuota=
|
||||||
✓ LogsDirectory=
|
✓ LogsDirectory=
|
||||||
✓ ConfigurationDirectoryMode=
|
✓ ConfigurationDirectoryMode=
|
||||||
✓ ConfigurationDirectory=
|
✓ ConfigurationDirectory=
|
||||||
|
@ -112,6 +112,10 @@ node /org/freedesktop/systemd1 {
|
|||||||
KillUnit(in s name,
|
KillUnit(in s name,
|
||||||
in s whom,
|
in s whom,
|
||||||
in i signal);
|
in i signal);
|
||||||
|
KillUnitSubgroup(in s name,
|
||||||
|
in s whom,
|
||||||
|
in s subgroup,
|
||||||
|
in i signal);
|
||||||
QueueSignalUnit(in s name,
|
QueueSignalUnit(in s name,
|
||||||
in s whom,
|
in s whom,
|
||||||
in i signal,
|
in i signal,
|
||||||
@ -831,6 +835,8 @@ node /org/freedesktop/systemd1 {
|
|||||||
|
|
||||||
<variablelist class="dbus-method" generated="True" extra-ref="KillUnit()"/>
|
<variablelist class="dbus-method" generated="True" extra-ref="KillUnit()"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-method" generated="True" extra-ref="KillUnitSubgroup()"/>
|
||||||
|
|
||||||
<variablelist class="dbus-method" generated="True" extra-ref="QueueSignalUnit()"/>
|
<variablelist class="dbus-method" generated="True" extra-ref="QueueSignalUnit()"/>
|
||||||
|
|
||||||
<variablelist class="dbus-method" generated="True" extra-ref="CleanUnit()"/>
|
<variablelist class="dbus-method" generated="True" extra-ref="CleanUnit()"/>
|
||||||
@ -1315,12 +1321,24 @@ node /org/freedesktop/systemd1 {
|
|||||||
<para><function>KillUnit()</function> may be used to kill (i.e. send a signal to) all processes of a
|
<para><function>KillUnit()</function> may be used to kill (i.e. send a signal to) all processes of a
|
||||||
unit. It takes the unit <varname>name</varname>, an enum <varname>who</varname> and a UNIX
|
unit. It takes the unit <varname>name</varname>, an enum <varname>who</varname> and a UNIX
|
||||||
<varname>signal</varname> number to send. The <varname>who</varname> enum is one of
|
<varname>signal</varname> number to send. The <varname>who</varname> enum is one of
|
||||||
<literal>main</literal>, <literal>control</literal> or <literal>all</literal>. If
|
<literal>main</literal>, <literal>control</literal>, <literal>cgroup</literal> or
|
||||||
<literal>main</literal>, only the main process of the unit is killed. If <literal>control</literal>, only
|
<literal>all</literal>. If <literal>main</literal>, only the main process of the unit is killed. If
|
||||||
the control process of the unit is killed. If <literal>all</literal>, all processes are killed. A
|
<literal>control</literal>, only the control process of the unit is killed. If
|
||||||
|
<literal>cgroup</literal> is specified only the processes in the control group of the unit are killed,
|
||||||
|
which might or might not include the main and control processes too. If <literal>all</literal>, all
|
||||||
|
processes are killed, i.e. the main process, the control process and those in the control group. A
|
||||||
<literal>control</literal> process is for example a process that is configured via
|
<literal>control</literal> process is for example a process that is configured via
|
||||||
<varname>ExecStop=</varname> and is spawned in parallel to the main daemon process in order to shut it
|
<varname>ExecStop=</varname> and is spawned in parallel to the main daemon process in order to shut it
|
||||||
down.</para>
|
down. The value may be suffixed by <literal>-fail</literal> in which case the operation will fail of no
|
||||||
|
matching process was found (otherwise it will return successfully, executing no operation).</para>
|
||||||
|
|
||||||
|
<para><function>KillUnitSubgroup()</function> is just like <function>KillUnit()</function> but takes an
|
||||||
|
additional path argument that selects a sub-control-group of the unit's control group. Only processes
|
||||||
|
in that subgroup are killed. The path my be specified with our without leading <literal>/</literal>, in
|
||||||
|
both cases it is taken relatively to the unit's control group. If the subgroup path is specified as an
|
||||||
|
empty string or as <literal>/</literal> it has the same effect as <function>KillUnit()</function>. If
|
||||||
|
it is specified as anything else the <literal>who</literal> parameter must be set to either
|
||||||
|
<literal>cgroup</literal> or <literal>cgroup-fail</literal>.</para>
|
||||||
|
|
||||||
<para><function>QueueSignalUnit()</function> is similar to <function>KillUnit()</function> but may be
|
<para><function>QueueSignalUnit()</function> is similar to <function>KillUnit()</function> but may be
|
||||||
used to enqueue a POSIX Realtime Signal (i.e. <constant>SIGRTMIN+…</constant> and
|
used to enqueue a POSIX Realtime Signal (i.e. <constant>SIGRTMIN+…</constant> and
|
||||||
@ -1886,8 +1904,8 @@ node /org/freedesktop/systemd1 {
|
|||||||
<para>Read access is generally granted to all clients. Additionally, for unprivileged clients, some
|
<para>Read access is generally granted to all clients. Additionally, for unprivileged clients, some
|
||||||
operations are allowed through the polkit privilege system. Operations which modify unit state
|
operations are allowed through the polkit privilege system. Operations which modify unit state
|
||||||
(<function>StartUnit()</function>, <function>StopUnit()</function>, <function>KillUnit()</function>,
|
(<function>StartUnit()</function>, <function>StopUnit()</function>, <function>KillUnit()</function>,
|
||||||
<function>QueueSignalUnit()</function>, <function>RestartUnit()</function> and similar,
|
<function>KillUnitSubgroup()</function>, <function>QueueSignalUnit()</function>,
|
||||||
<function>SetProperty()</function>) require
|
<function>RestartUnit()</function> and similar, <function>SetProperty()</function>) require
|
||||||
<interfacename>org.freedesktop.systemd1.manage-units</interfacename>. Operations which modify unit file
|
<interfacename>org.freedesktop.systemd1.manage-units</interfacename>. Operations which modify unit file
|
||||||
enablement state (<function>EnableUnitFiles()</function>, <function>DisableUnitFiles()</function>,
|
enablement state (<function>EnableUnitFiles()</function>, <function>DisableUnitFiles()</function>,
|
||||||
<function>EnableUnitFilesWithFlags()</function>, <function>DisableUnitFilesWithFlags()</function>,
|
<function>EnableUnitFilesWithFlags()</function>, <function>DisableUnitFilesWithFlags()</function>,
|
||||||
@ -1936,6 +1954,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
|||||||
out a(uosos) affected_jobs);
|
out a(uosos) affected_jobs);
|
||||||
Kill(in s whom,
|
Kill(in s whom,
|
||||||
in i signal);
|
in i signal);
|
||||||
|
KillSubgroup(in s subgroup,
|
||||||
|
in i signal);
|
||||||
QueueSignal(in s whom,
|
QueueSignal(in s whom,
|
||||||
in i signal,
|
in i signal,
|
||||||
in i value);
|
in i value);
|
||||||
@ -2259,6 +2279,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
|||||||
|
|
||||||
<variablelist class="dbus-method" generated="True" extra-ref="Kill()"/>
|
<variablelist class="dbus-method" generated="True" extra-ref="Kill()"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-method" generated="True" extra-ref="KillSubgroup()"/>
|
||||||
|
|
||||||
<variablelist class="dbus-method" generated="True" extra-ref="QueueSignal()"/>
|
<variablelist class="dbus-method" generated="True" extra-ref="QueueSignal()"/>
|
||||||
|
|
||||||
<variablelist class="dbus-method" generated="True" extra-ref="ResetFailed()"/>
|
<variablelist class="dbus-method" generated="True" extra-ref="ResetFailed()"/>
|
||||||
@ -2487,13 +2509,13 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
|||||||
<para><function>Start()</function>, <function>Stop()</function>, <function>Reload()</function>,
|
<para><function>Start()</function>, <function>Stop()</function>, <function>Reload()</function>,
|
||||||
<function>Restart()</function>, <function>TryRestart()</function>,
|
<function>Restart()</function>, <function>TryRestart()</function>,
|
||||||
<function>ReloadOrRestart()</function>, <function>ReloadOrTryRestart()</function>,
|
<function>ReloadOrRestart()</function>, <function>ReloadOrTryRestart()</function>,
|
||||||
<function>Kill()</function>, <function>QueueSignal()</function>, <function>ResetFailed()</function>,
|
<function>Kill()</function>, <function>KillSubgroup()</function>, <function>QueueSignal()</function>,
|
||||||
and <function>SetProperties()</function> implement the same operation as the respective methods on the
|
<function>ResetFailed()</function>, and <function>SetProperties()</function> implement the same
|
||||||
<interfacename>Manager</interfacename> object (see above). However, these methods operate on the unit
|
operation as the respective methods on the <interfacename>Manager</interfacename> object (see
|
||||||
object and hence do not take a unit name parameter. Invoking the methods directly on the Manager object
|
above). However, these methods operate on the unit object and hence do not take a unit name
|
||||||
has the advantage of not requiring a <function>GetUnit()</function> call to get the unit object for a
|
parameter. Invoking the methods directly on the Manager object has the advantage of not requiring a
|
||||||
specific unit name. Calling the methods on the Manager object is hence a round trip
|
<function>GetUnit()</function> call to get the unit object for a specific unit name. Calling the
|
||||||
optimization.</para>
|
methods on the Manager object is hence a round trip optimization.</para>
|
||||||
</refsect2>
|
</refsect2>
|
||||||
|
|
||||||
<refsect2>
|
<refsect2>
|
||||||
@ -3288,18 +3310,30 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
|||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly u StateDirectoryMode = ...;
|
readonly u StateDirectoryMode = ...;
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
|
readonly b StateDirectoryAccounting = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
|
readonly (tus) StateDirectoryQuota = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly as StateDirectory = ['...', ...];
|
readonly as StateDirectory = ['...', ...];
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly a(sst) CacheDirectorySymlink = [...];
|
readonly a(sst) CacheDirectorySymlink = [...];
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly u CacheDirectoryMode = ...;
|
readonly u CacheDirectoryMode = ...;
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
|
readonly b CacheDirectoryAccounting = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
|
readonly (tus) CacheDirectoryQuota = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly as CacheDirectory = ['...', ...];
|
readonly as CacheDirectory = ['...', ...];
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly a(sst) LogsDirectorySymlink = [...];
|
readonly a(sst) LogsDirectorySymlink = [...];
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly u LogsDirectoryMode = ...;
|
readonly u LogsDirectoryMode = ...;
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
|
readonly b LogsDirectoryAccounting = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
|
readonly (tus) LogsDirectoryQuota = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly as LogsDirectory = ['...', ...];
|
readonly as LogsDirectory = ['...', ...];
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly u ConfigurationDirectoryMode = ...;
|
readonly u ConfigurationDirectoryMode = ...;
|
||||||
@ -3351,6 +3385,12 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
|||||||
readonly s MountImagePolicy = '...';
|
readonly s MountImagePolicy = '...';
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly s ExtensionImagePolicy = '...';
|
readonly s ExtensionImagePolicy = '...';
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
|
readonly (tt) StateDirectoryQuotaUsage = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
|
readonly (tt) CacheDirectoryQuotaUsage = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
|
readonly (tt) LogsDirectoryQuotaUsage = ...;
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly s KillMode = '...';
|
readonly s KillMode = '...';
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
@ -3885,10 +3925,22 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
|||||||
|
|
||||||
<!--property StateDirectoryMode is not documented!-->
|
<!--property StateDirectoryMode is not documented!-->
|
||||||
|
|
||||||
|
<!--property StateDirectoryAccounting is not documented!-->
|
||||||
|
|
||||||
|
<!--property StateDirectoryQuota is not documented!-->
|
||||||
|
|
||||||
<!--property CacheDirectoryMode is not documented!-->
|
<!--property CacheDirectoryMode is not documented!-->
|
||||||
|
|
||||||
|
<!--property CacheDirectoryAccounting is not documented!-->
|
||||||
|
|
||||||
|
<!--property CacheDirectoryQuota is not documented!-->
|
||||||
|
|
||||||
<!--property LogsDirectoryMode is not documented!-->
|
<!--property LogsDirectoryMode is not documented!-->
|
||||||
|
|
||||||
|
<!--property LogsDirectoryAccounting is not documented!-->
|
||||||
|
|
||||||
|
<!--property LogsDirectoryQuota is not documented!-->
|
||||||
|
|
||||||
<!--property ConfigurationDirectoryMode is not documented!-->
|
<!--property ConfigurationDirectoryMode is not documented!-->
|
||||||
|
|
||||||
<!--property ConfigurationDirectory is not documented!-->
|
<!--property ConfigurationDirectory is not documented!-->
|
||||||
@ -3935,6 +3987,12 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
|||||||
|
|
||||||
<!--property ExtensionImagePolicy is not documented!-->
|
<!--property ExtensionImagePolicy is not documented!-->
|
||||||
|
|
||||||
|
<!--property StateDirectoryQuotaUsage is not documented!-->
|
||||||
|
|
||||||
|
<!--property CacheDirectoryQuotaUsage is not documented!-->
|
||||||
|
|
||||||
|
<!--property LogsDirectoryQuotaUsage is not documented!-->
|
||||||
|
|
||||||
<!--property KillMode is not documented!-->
|
<!--property KillMode is not documented!-->
|
||||||
|
|
||||||
<!--property KillSignal is not documented!-->
|
<!--property KillSignal is not documented!-->
|
||||||
@ -4579,18 +4637,30 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
|||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="StateDirectoryMode"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="StateDirectoryMode"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="StateDirectoryAccounting"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="StateDirectoryQuota"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="StateDirectory"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="StateDirectory"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="CacheDirectorySymlink"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="CacheDirectorySymlink"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="CacheDirectoryMode"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="CacheDirectoryMode"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="CacheDirectoryAccounting"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="CacheDirectoryQuota"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="CacheDirectory"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="CacheDirectory"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="LogsDirectorySymlink"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="LogsDirectorySymlink"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="LogsDirectoryMode"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="LogsDirectoryMode"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="LogsDirectoryAccounting"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="LogsDirectoryQuota"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="LogsDirectory"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="LogsDirectory"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="ConfigurationDirectoryMode"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="ConfigurationDirectoryMode"/>
|
||||||
@ -4643,6 +4713,12 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
|||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="ExtensionImagePolicy"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="ExtensionImagePolicy"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="StateDirectoryQuotaUsage"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="CacheDirectoryQuotaUsage"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="LogsDirectoryQuotaUsage"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="KillMode"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="KillMode"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="KillSignal"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="KillSignal"/>
|
||||||
@ -5443,18 +5519,30 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
|
|||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly u StateDirectoryMode = ...;
|
readonly u StateDirectoryMode = ...;
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
|
readonly b StateDirectoryAccounting = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
|
readonly (tus) StateDirectoryQuota = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly as StateDirectory = ['...', ...];
|
readonly as StateDirectory = ['...', ...];
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly a(sst) CacheDirectorySymlink = [...];
|
readonly a(sst) CacheDirectorySymlink = [...];
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly u CacheDirectoryMode = ...;
|
readonly u CacheDirectoryMode = ...;
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
|
readonly b CacheDirectoryAccounting = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
|
readonly (tus) CacheDirectoryQuota = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly as CacheDirectory = ['...', ...];
|
readonly as CacheDirectory = ['...', ...];
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly a(sst) LogsDirectorySymlink = [...];
|
readonly a(sst) LogsDirectorySymlink = [...];
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly u LogsDirectoryMode = ...;
|
readonly u LogsDirectoryMode = ...;
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
|
readonly b LogsDirectoryAccounting = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
|
readonly (tus) LogsDirectoryQuota = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly as LogsDirectory = ['...', ...];
|
readonly as LogsDirectory = ['...', ...];
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly u ConfigurationDirectoryMode = ...;
|
readonly u ConfigurationDirectoryMode = ...;
|
||||||
@ -5506,6 +5594,12 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
|
|||||||
readonly s MountImagePolicy = '...';
|
readonly s MountImagePolicy = '...';
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly s ExtensionImagePolicy = '...';
|
readonly s ExtensionImagePolicy = '...';
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
|
readonly (tt) StateDirectoryQuotaUsage = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
|
readonly (tt) CacheDirectoryQuotaUsage = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
|
readonly (tt) LogsDirectoryQuotaUsage = ...;
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly s KillMode = '...';
|
readonly s KillMode = '...';
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
@ -6060,10 +6154,22 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
|
|||||||
|
|
||||||
<!--property StateDirectoryMode is not documented!-->
|
<!--property StateDirectoryMode is not documented!-->
|
||||||
|
|
||||||
|
<!--property StateDirectoryAccounting is not documented!-->
|
||||||
|
|
||||||
|
<!--property StateDirectoryQuota is not documented!-->
|
||||||
|
|
||||||
<!--property CacheDirectoryMode is not documented!-->
|
<!--property CacheDirectoryMode is not documented!-->
|
||||||
|
|
||||||
|
<!--property CacheDirectoryAccounting is not documented!-->
|
||||||
|
|
||||||
|
<!--property CacheDirectoryQuota is not documented!-->
|
||||||
|
|
||||||
<!--property LogsDirectoryMode is not documented!-->
|
<!--property LogsDirectoryMode is not documented!-->
|
||||||
|
|
||||||
|
<!--property LogsDirectoryAccounting is not documented!-->
|
||||||
|
|
||||||
|
<!--property LogsDirectoryQuota is not documented!-->
|
||||||
|
|
||||||
<!--property ConfigurationDirectoryMode is not documented!-->
|
<!--property ConfigurationDirectoryMode is not documented!-->
|
||||||
|
|
||||||
<!--property ConfigurationDirectory is not documented!-->
|
<!--property ConfigurationDirectory is not documented!-->
|
||||||
@ -6110,6 +6216,12 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
|
|||||||
|
|
||||||
<!--property ExtensionImagePolicy is not documented!-->
|
<!--property ExtensionImagePolicy is not documented!-->
|
||||||
|
|
||||||
|
<!--property StateDirectoryQuotaUsage is not documented!-->
|
||||||
|
|
||||||
|
<!--property CacheDirectoryQuotaUsage is not documented!-->
|
||||||
|
|
||||||
|
<!--property LogsDirectoryQuotaUsage is not documented!-->
|
||||||
|
|
||||||
<!--property KillMode is not documented!-->
|
<!--property KillMode is not documented!-->
|
||||||
|
|
||||||
<!--property KillSignal is not documented!-->
|
<!--property KillSignal is not documented!-->
|
||||||
@ -6734,18 +6846,30 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
|
|||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="StateDirectoryMode"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="StateDirectoryMode"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="StateDirectoryAccounting"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="StateDirectoryQuota"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="StateDirectory"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="StateDirectory"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="CacheDirectorySymlink"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="CacheDirectorySymlink"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="CacheDirectoryMode"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="CacheDirectoryMode"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="CacheDirectoryAccounting"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="CacheDirectoryQuota"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="CacheDirectory"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="CacheDirectory"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="LogsDirectorySymlink"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="LogsDirectorySymlink"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="LogsDirectoryMode"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="LogsDirectoryMode"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="LogsDirectoryAccounting"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="LogsDirectoryQuota"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="LogsDirectory"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="LogsDirectory"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="ConfigurationDirectoryMode"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="ConfigurationDirectoryMode"/>
|
||||||
@ -6798,6 +6922,12 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
|
|||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="ExtensionImagePolicy"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="ExtensionImagePolicy"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="StateDirectoryQuotaUsage"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="CacheDirectoryQuotaUsage"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="LogsDirectoryQuotaUsage"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="KillMode"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="KillMode"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="KillSignal"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="KillSignal"/>
|
||||||
@ -7422,18 +7552,30 @@ node /org/freedesktop/systemd1/unit/home_2emount {
|
|||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly u StateDirectoryMode = ...;
|
readonly u StateDirectoryMode = ...;
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
|
readonly b StateDirectoryAccounting = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
|
readonly (tus) StateDirectoryQuota = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly as StateDirectory = ['...', ...];
|
readonly as StateDirectory = ['...', ...];
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly a(sst) CacheDirectorySymlink = [...];
|
readonly a(sst) CacheDirectorySymlink = [...];
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly u CacheDirectoryMode = ...;
|
readonly u CacheDirectoryMode = ...;
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
|
readonly b CacheDirectoryAccounting = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
|
readonly (tus) CacheDirectoryQuota = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly as CacheDirectory = ['...', ...];
|
readonly as CacheDirectory = ['...', ...];
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly a(sst) LogsDirectorySymlink = [...];
|
readonly a(sst) LogsDirectorySymlink = [...];
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly u LogsDirectoryMode = ...;
|
readonly u LogsDirectoryMode = ...;
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
|
readonly b LogsDirectoryAccounting = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
|
readonly (tus) LogsDirectoryQuota = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly as LogsDirectory = ['...', ...];
|
readonly as LogsDirectory = ['...', ...];
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly u ConfigurationDirectoryMode = ...;
|
readonly u ConfigurationDirectoryMode = ...;
|
||||||
@ -7485,6 +7627,12 @@ node /org/freedesktop/systemd1/unit/home_2emount {
|
|||||||
readonly s MountImagePolicy = '...';
|
readonly s MountImagePolicy = '...';
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly s ExtensionImagePolicy = '...';
|
readonly s ExtensionImagePolicy = '...';
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
|
readonly (tt) StateDirectoryQuotaUsage = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
|
readonly (tt) CacheDirectoryQuotaUsage = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
|
readonly (tt) LogsDirectoryQuotaUsage = ...;
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly s KillMode = '...';
|
readonly s KillMode = '...';
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
@ -7961,10 +8109,22 @@ node /org/freedesktop/systemd1/unit/home_2emount {
|
|||||||
|
|
||||||
<!--property StateDirectoryMode is not documented!-->
|
<!--property StateDirectoryMode is not documented!-->
|
||||||
|
|
||||||
|
<!--property StateDirectoryAccounting is not documented!-->
|
||||||
|
|
||||||
|
<!--property StateDirectoryQuota is not documented!-->
|
||||||
|
|
||||||
<!--property CacheDirectoryMode is not documented!-->
|
<!--property CacheDirectoryMode is not documented!-->
|
||||||
|
|
||||||
|
<!--property CacheDirectoryAccounting is not documented!-->
|
||||||
|
|
||||||
|
<!--property CacheDirectoryQuota is not documented!-->
|
||||||
|
|
||||||
<!--property LogsDirectoryMode is not documented!-->
|
<!--property LogsDirectoryMode is not documented!-->
|
||||||
|
|
||||||
|
<!--property LogsDirectoryAccounting is not documented!-->
|
||||||
|
|
||||||
|
<!--property LogsDirectoryQuota is not documented!-->
|
||||||
|
|
||||||
<!--property ConfigurationDirectoryMode is not documented!-->
|
<!--property ConfigurationDirectoryMode is not documented!-->
|
||||||
|
|
||||||
<!--property ConfigurationDirectory is not documented!-->
|
<!--property ConfigurationDirectory is not documented!-->
|
||||||
@ -8011,6 +8171,12 @@ node /org/freedesktop/systemd1/unit/home_2emount {
|
|||||||
|
|
||||||
<!--property ExtensionImagePolicy is not documented!-->
|
<!--property ExtensionImagePolicy is not documented!-->
|
||||||
|
|
||||||
|
<!--property StateDirectoryQuotaUsage is not documented!-->
|
||||||
|
|
||||||
|
<!--property CacheDirectoryQuotaUsage is not documented!-->
|
||||||
|
|
||||||
|
<!--property LogsDirectoryQuotaUsage is not documented!-->
|
||||||
|
|
||||||
<!--property KillMode is not documented!-->
|
<!--property KillMode is not documented!-->
|
||||||
|
|
||||||
<!--property KillSignal is not documented!-->
|
<!--property KillSignal is not documented!-->
|
||||||
@ -8543,18 +8709,30 @@ node /org/freedesktop/systemd1/unit/home_2emount {
|
|||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="StateDirectoryMode"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="StateDirectoryMode"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="StateDirectoryAccounting"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="StateDirectoryQuota"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="StateDirectory"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="StateDirectory"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="CacheDirectorySymlink"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="CacheDirectorySymlink"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="CacheDirectoryMode"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="CacheDirectoryMode"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="CacheDirectoryAccounting"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="CacheDirectoryQuota"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="CacheDirectory"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="CacheDirectory"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="LogsDirectorySymlink"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="LogsDirectorySymlink"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="LogsDirectoryMode"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="LogsDirectoryMode"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="LogsDirectoryAccounting"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="LogsDirectoryQuota"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="LogsDirectory"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="LogsDirectory"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="ConfigurationDirectoryMode"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="ConfigurationDirectoryMode"/>
|
||||||
@ -8607,6 +8785,12 @@ node /org/freedesktop/systemd1/unit/home_2emount {
|
|||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="ExtensionImagePolicy"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="ExtensionImagePolicy"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="StateDirectoryQuotaUsage"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="CacheDirectoryQuotaUsage"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="LogsDirectoryQuotaUsage"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="KillMode"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="KillMode"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="KillSignal"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="KillSignal"/>
|
||||||
@ -9364,18 +9548,30 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
|
|||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly u StateDirectoryMode = ...;
|
readonly u StateDirectoryMode = ...;
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
|
readonly b StateDirectoryAccounting = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
|
readonly (tus) StateDirectoryQuota = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly as StateDirectory = ['...', ...];
|
readonly as StateDirectory = ['...', ...];
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly a(sst) CacheDirectorySymlink = [...];
|
readonly a(sst) CacheDirectorySymlink = [...];
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly u CacheDirectoryMode = ...;
|
readonly u CacheDirectoryMode = ...;
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
|
readonly b CacheDirectoryAccounting = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
|
readonly (tus) CacheDirectoryQuota = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly as CacheDirectory = ['...', ...];
|
readonly as CacheDirectory = ['...', ...];
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly a(sst) LogsDirectorySymlink = [...];
|
readonly a(sst) LogsDirectorySymlink = [...];
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly u LogsDirectoryMode = ...;
|
readonly u LogsDirectoryMode = ...;
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
|
readonly b LogsDirectoryAccounting = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
|
readonly (tus) LogsDirectoryQuota = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly as LogsDirectory = ['...', ...];
|
readonly as LogsDirectory = ['...', ...];
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly u ConfigurationDirectoryMode = ...;
|
readonly u ConfigurationDirectoryMode = ...;
|
||||||
@ -9427,6 +9623,12 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
|
|||||||
readonly s MountImagePolicy = '...';
|
readonly s MountImagePolicy = '...';
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly s ExtensionImagePolicy = '...';
|
readonly s ExtensionImagePolicy = '...';
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
|
readonly (tt) StateDirectoryQuotaUsage = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
|
readonly (tt) CacheDirectoryQuotaUsage = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
|
readonly (tt) LogsDirectoryQuotaUsage = ...;
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly s KillMode = '...';
|
readonly s KillMode = '...';
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
@ -9885,10 +10087,22 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
|
|||||||
|
|
||||||
<!--property StateDirectoryMode is not documented!-->
|
<!--property StateDirectoryMode is not documented!-->
|
||||||
|
|
||||||
|
<!--property StateDirectoryAccounting is not documented!-->
|
||||||
|
|
||||||
|
<!--property StateDirectoryQuota is not documented!-->
|
||||||
|
|
||||||
<!--property CacheDirectoryMode is not documented!-->
|
<!--property CacheDirectoryMode is not documented!-->
|
||||||
|
|
||||||
|
<!--property CacheDirectoryAccounting is not documented!-->
|
||||||
|
|
||||||
|
<!--property CacheDirectoryQuota is not documented!-->
|
||||||
|
|
||||||
<!--property LogsDirectoryMode is not documented!-->
|
<!--property LogsDirectoryMode is not documented!-->
|
||||||
|
|
||||||
|
<!--property LogsDirectoryAccounting is not documented!-->
|
||||||
|
|
||||||
|
<!--property LogsDirectoryQuota is not documented!-->
|
||||||
|
|
||||||
<!--property ConfigurationDirectoryMode is not documented!-->
|
<!--property ConfigurationDirectoryMode is not documented!-->
|
||||||
|
|
||||||
<!--property ConfigurationDirectory is not documented!-->
|
<!--property ConfigurationDirectory is not documented!-->
|
||||||
@ -9935,6 +10149,12 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
|
|||||||
|
|
||||||
<!--property ExtensionImagePolicy is not documented!-->
|
<!--property ExtensionImagePolicy is not documented!-->
|
||||||
|
|
||||||
|
<!--property StateDirectoryQuotaUsage is not documented!-->
|
||||||
|
|
||||||
|
<!--property CacheDirectoryQuotaUsage is not documented!-->
|
||||||
|
|
||||||
|
<!--property LogsDirectoryQuotaUsage is not documented!-->
|
||||||
|
|
||||||
<!--property KillMode is not documented!-->
|
<!--property KillMode is not documented!-->
|
||||||
|
|
||||||
<!--property KillSignal is not documented!-->
|
<!--property KillSignal is not documented!-->
|
||||||
@ -10449,18 +10669,30 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
|
|||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="StateDirectoryMode"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="StateDirectoryMode"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="StateDirectoryAccounting"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="StateDirectoryQuota"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="StateDirectory"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="StateDirectory"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="CacheDirectorySymlink"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="CacheDirectorySymlink"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="CacheDirectoryMode"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="CacheDirectoryMode"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="CacheDirectoryAccounting"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="CacheDirectoryQuota"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="CacheDirectory"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="CacheDirectory"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="LogsDirectorySymlink"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="LogsDirectorySymlink"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="LogsDirectoryMode"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="LogsDirectoryMode"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="LogsDirectoryAccounting"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="LogsDirectoryQuota"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="LogsDirectory"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="LogsDirectory"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="ConfigurationDirectoryMode"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="ConfigurationDirectoryMode"/>
|
||||||
@ -10513,6 +10745,12 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
|
|||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="ExtensionImagePolicy"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="ExtensionImagePolicy"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="StateDirectoryQuotaUsage"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="CacheDirectoryQuotaUsage"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="LogsDirectoryQuotaUsage"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="KillMode"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="KillMode"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="KillSignal"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="KillSignal"/>
|
||||||
@ -12008,7 +12246,8 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \
|
|||||||
<para><varname>ShutdownStartTimestamp</varname>,
|
<para><varname>ShutdownStartTimestamp</varname>,
|
||||||
<varname>ShutdownStartTimestampMonotonic</varname>, and
|
<varname>ShutdownStartTimestampMonotonic</varname>, and
|
||||||
<varname>SoftRebootsCount</varname> were added in version 256.</para>
|
<varname>SoftRebootsCount</varname> were added in version 256.</para>
|
||||||
<para><function>RemoveSubgroupFromUnit()</function> was added in version 258.</para>
|
<para><function>RemoveSubgroupFromUnit()</function>, and
|
||||||
|
<function>KillUnitSubgroup()</function> were added in version 258.</para>
|
||||||
</refsect2>
|
</refsect2>
|
||||||
<refsect2>
|
<refsect2>
|
||||||
<title>Unit Objects</title>
|
<title>Unit Objects</title>
|
||||||
@ -12076,8 +12315,18 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \
|
|||||||
<varname>PrivateUsersEx</varname>, and
|
<varname>PrivateUsersEx</varname>, and
|
||||||
<varname>PrivatePIDs</varname> were added in version 257.</para>
|
<varname>PrivatePIDs</varname> were added in version 257.</para>
|
||||||
<para><varname>ProtectHostnameEx</varname>,
|
<para><varname>ProtectHostnameEx</varname>,
|
||||||
<varname>DelegateNamespaces</varname>, and
|
<varname>DelegateNamespaces</varname>,
|
||||||
<function>RemoveSubGroup()</function> were added in version 258.</para>
|
<function>RemoveSubGroup()</function>,
|
||||||
|
<varname>StateDirectoryQuota</varname>,
|
||||||
|
<varname>StateDirectoryQuotaUsage</varname>,
|
||||||
|
<varname>StateDirectoryAccounting</varname>,
|
||||||
|
<varname>CacheDirectoryQuota</varname>,
|
||||||
|
<varname>CacheDirectoryQuotaUsage</varname>,
|
||||||
|
<varname>CacheDirectoryAccounting</varname>,
|
||||||
|
<varname>LogsDirectoryQuota</varname>,
|
||||||
|
<varname>LogsDirectoryQuotaUsage</varname>,
|
||||||
|
<varname>LogsDirectoryAccounting</varname>, and
|
||||||
|
<function>KillSubgroup()</function> were added in version 258.</para>
|
||||||
</refsect2>
|
</refsect2>
|
||||||
<refsect2>
|
<refsect2>
|
||||||
<title>Socket Unit Objects</title>
|
<title>Socket Unit Objects</title>
|
||||||
@ -12126,8 +12375,18 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \
|
|||||||
<varname>AcceptFileDescriptors</varname>,
|
<varname>AcceptFileDescriptors</varname>,
|
||||||
<varname>DelegateNamespaces</varname>,
|
<varname>DelegateNamespaces</varname>,
|
||||||
<function>RemoveSubgroup()</function>,
|
<function>RemoveSubgroup()</function>,
|
||||||
<varname>DeferTrigger</varname>, and
|
<varname>DeferTrigger</varname>,
|
||||||
<varname>DeferTriggerMaxUSec</varname> were added in version 258.</para>
|
<varname>DeferTriggerMaxUSec</varname>,
|
||||||
|
<varname>StateDirectoryQuota</varname>,
|
||||||
|
<varname>StateDirectoryQuotaUsage</varname>,
|
||||||
|
<varname>StateDirectoryAccounting</varname>,
|
||||||
|
<varname>CacheDirectoryQuota</varname>,
|
||||||
|
<varname>CacheDirectoryQuotaUsage</varname>,
|
||||||
|
<varname>CacheDirectoryAccounting</varname>,
|
||||||
|
<varname>LogsDirectoryQuota</varname>,
|
||||||
|
<varname>LogsDirectoryQuotaUsage</varname>,
|
||||||
|
<varname>LogsDirectoryAccounting</varname>, and
|
||||||
|
<function>KillSubgroup()</function> were added in version 258.</para>
|
||||||
</refsect2>
|
</refsect2>
|
||||||
<refsect2>
|
<refsect2>
|
||||||
<title>Mount Unit Objects</title>
|
<title>Mount Unit Objects</title>
|
||||||
@ -12171,8 +12430,18 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \
|
|||||||
<para><varname>ProtectHostnameEx</varname>,
|
<para><varname>ProtectHostnameEx</varname>,
|
||||||
<varname>DelegateNamespaces</varname>,
|
<varname>DelegateNamespaces</varname>,
|
||||||
<function>RemoveSubgroup()</function>,
|
<function>RemoveSubgroup()</function>,
|
||||||
<varname>ReloadResult</varname>, and
|
<varname>ReloadResult</varname>,
|
||||||
<varname>CleanResult</varname> were added in version 258.</para>
|
<varname>CleanResult</varname>,
|
||||||
|
<varname>StateDirectoryQuota</varname>,
|
||||||
|
<varname>StateDirectoryQuotaUsage</varname>,
|
||||||
|
<varname>StateDirectoryAccounting</varname>,
|
||||||
|
<varname>CacheDirectoryQuota</varname>,
|
||||||
|
<varname>CacheDirectoryQuotaUsage</varname>,
|
||||||
|
<varname>CacheDirectoryAccounting</varname>,
|
||||||
|
<varname>LogsDirectoryQuota</varname>,
|
||||||
|
<varname>LogsDirectoryQuotaUsage</varname>,
|
||||||
|
<varname>LogsDirectoryAccounting</varname>, and
|
||||||
|
<function>KillSubgroup()</function> were added in version 258.</para>
|
||||||
</refsect2>
|
</refsect2>
|
||||||
<refsect2>
|
<refsect2>
|
||||||
<title>Swap Unit Objects</title>
|
<title>Swap Unit Objects</title>
|
||||||
@ -12214,8 +12483,18 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \
|
|||||||
<varname>ProtectControlGroupsEx</varname>, and
|
<varname>ProtectControlGroupsEx</varname>, and
|
||||||
<varname>PrivatePIDs</varname> were added in version 257.</para>
|
<varname>PrivatePIDs</varname> were added in version 257.</para>
|
||||||
<para><varname>ProtectHostnameEx</varname>,
|
<para><varname>ProtectHostnameEx</varname>,
|
||||||
<varname>DelegateNamespaces</varname>, and
|
<varname>DelegateNamespaces</varname>,
|
||||||
<function>RemoveSubgroup()</function> were added in version 258.</para>
|
<function>RemoveSubgroup()</function>,
|
||||||
|
<varname>StateDirectoryQuota</varname>,
|
||||||
|
<varname>StateDirectoryQuotaUsage</varname>,
|
||||||
|
<varname>StateDirectoryAccounting</varname>,
|
||||||
|
<varname>CacheDirectoryQuota</varname>,
|
||||||
|
<varname>CacheDirectoryQuotaUsage</varname>,
|
||||||
|
<varname>CacheDirectoryAccounting</varname>,
|
||||||
|
<varname>LogsDirectoryQuota</varname>,
|
||||||
|
<varname>LogsDirectoryQuotaUsage</varname>,
|
||||||
|
<varname>LogsDirectoryAccounting</varname>, and
|
||||||
|
<function>KillSubgroup()</function> were added in version 258.</para>
|
||||||
</refsect2>
|
</refsect2>
|
||||||
<refsect2>
|
<refsect2>
|
||||||
<title>Slice Unit Objects</title>
|
<title>Slice Unit Objects</title>
|
||||||
@ -12243,8 +12522,9 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \
|
|||||||
<para><varname>ManagedOOMMemoryPressureDurationUSec</varname> was added in version 257.</para>
|
<para><varname>ManagedOOMMemoryPressureDurationUSec</varname> was added in version 257.</para>
|
||||||
<para><varname>ConcurrencyHardMax</varname>,
|
<para><varname>ConcurrencyHardMax</varname>,
|
||||||
<varname>ConcurrencySoftMax</varname>,
|
<varname>ConcurrencySoftMax</varname>,
|
||||||
<varname>NCurrentlyActive</varname> and
|
<varname>NCurrentlyActive</varname>,
|
||||||
<function>RemoveSubgroup()</function> were added in version 258.</para>
|
<function>RemoveSubgroup()</function>, and
|
||||||
|
<function>KillSubgroup()</function> were added in version 258.</para>
|
||||||
</refsect2>
|
</refsect2>
|
||||||
<refsect2>
|
<refsect2>
|
||||||
<title>Scope Unit Objects</title>
|
<title>Scope Unit Objects</title>
|
||||||
@ -12271,7 +12551,8 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \
|
|||||||
<varname>EffectiveTasksMax</varname>, and
|
<varname>EffectiveTasksMax</varname>, and
|
||||||
<varname>MemoryZSwapWriteback</varname> were added in version 256.</para>
|
<varname>MemoryZSwapWriteback</varname> were added in version 256.</para>
|
||||||
<para><varname>ManagedOOMMemoryPressureDurationUSec</varname> was added in version 257.</para>
|
<para><varname>ManagedOOMMemoryPressureDurationUSec</varname> was added in version 257.</para>
|
||||||
<para><function>RemoveSubgroup()</function> was added in version 258.</para>
|
<para><function>RemoveSubgroup()</function> and
|
||||||
|
<function>KillSubgroup()</function> were added in version 258.</para>
|
||||||
</refsect2>
|
</refsect2>
|
||||||
<refsect2>
|
<refsect2>
|
||||||
<title>Job Objects</title>
|
<title>Job Objects</title>
|
||||||
|
@ -8,8 +8,9 @@
|
|||||||
<refsect1>
|
<refsect1>
|
||||||
<title/>
|
<title/>
|
||||||
|
|
||||||
<para id="controllers-text">The following controller names may be specified: <option>cpu</option>, <option>cpuacct</option>,
|
<para id="controllers-text">The following controller names may be specified: <option>cpu</option>,
|
||||||
<option>cpuset</option>, <option>io</option>, <option>blkio</option>, <option>memory</option>, <option>devices</option>,
|
<option>cpuset</option>, <option>io</option>, <option>memory</option>, <option>pids</option>,
|
||||||
<option>pids</option>, <option>bpf-firewall</option>, and <option>bpf-devices</option>.</para>
|
<option>bpf-firewall</option>, <option>bpf-devices</option>, <option>bpf-foreign</option>,
|
||||||
|
<option>bpf-socket-bind</option>, and <option>bpf-restrict-network-interfaces</option>.</para>
|
||||||
|
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
@ -2481,23 +2481,25 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
|
|||||||
|
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>When used with <command>kill</command>, choose which processes to send a UNIX process signal
|
<para>When used with <command>kill</command>, choose which processes to send a UNIX process signal
|
||||||
to. Must be one of <option>main</option>, <option>control</option> or <option>all</option> to
|
to. Must be one of <option>main</option>, <option>control</option>, <option>cgroup</option> or
|
||||||
select whether to kill only the main process, the control process or all processes of the unit. The
|
<option>all</option> to select whether to kill only the main process, the control process, all
|
||||||
main process of the unit is the one that defines the life-time of it. A control process of a unit
|
processes in the unit's control group or all processes of the unit. The main process of the unit is
|
||||||
is one that is invoked by the manager to induce state changes of it. For example, all processes
|
the one that defines the life-time of it. A control process of a unit is one that is invoked by the
|
||||||
started due to the <varname>ExecStartPre=</varname>, <varname>ExecStop=</varname> or
|
manager to induce state changes of it. For example, all processes started due to the
|
||||||
<varname>ExecReload=</varname> settings of service units are control processes. Note that there is
|
<varname>ExecStartPre=</varname>, <varname>ExecStop=</varname> or <varname>ExecReload=</varname>
|
||||||
only one control process per unit at a time, as only one state change is executed at a time. For
|
settings of service units are control processes. Note that there is only one control process per
|
||||||
services of type <varname>Type=forking</varname>, the initial process started by the manager for
|
unit at a time, as only one state change is executed at a time. For services of type
|
||||||
|
<varname>Type=forking</varname>, the initial process started by the manager for
|
||||||
<varname>ExecStart=</varname> is a control process, while the process ultimately forked off by that
|
<varname>ExecStart=</varname> is a control process, while the process ultimately forked off by that
|
||||||
one is then considered the main process of the unit (if it can be determined). This is different
|
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
|
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
|
<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
|
one main process, zero or one control process plus any number of additional processes part of the
|
||||||
types manage processes of these types however. For example, for mount units, control processes are
|
unit's control group. Not all unit types manage processes of these types however. For example, for
|
||||||
defined (which are the invocations of <filename>&MOUNT_PATH;</filename> and
|
mount units, control processes are defined (which are the invocations of
|
||||||
<filename>&UMOUNT_PATH;</filename>), but no main process is defined. If omitted, defaults to
|
<filename>&MOUNT_PATH;</filename> and <filename>&UMOUNT_PATH;</filename>), but no main process is
|
||||||
<option>all</option>.</para>
|
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"/>
|
<xi:include href="version-info.xml" xpointer="v252"/>
|
||||||
</listitem>
|
</listitem>
|
||||||
@ -2524,6 +2526,28 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
|
|||||||
<xi:include href="version-info.xml" xpointer="v254"/></listitem>
|
<xi:include href="version-info.xml" xpointer="v254"/></listitem>
|
||||||
</varlistentry>
|
</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" />
|
<xi:include href="standard-options.xml" xpointer="signal" />
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
|
@ -1680,6 +1680,46 @@ StateDirectory=aaa/bbb ccc</programlisting>
|
|||||||
<xi:include href="version-info.xml" xpointer="v234"/></listitem>
|
<xi:include href="version-info.xml" xpointer="v234"/></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><varname>StateDirectoryQuota=</varname></term>
|
||||||
|
<term><varname>CacheDirectoryQuota=</varname></term>
|
||||||
|
<term><varname>LogsDirectoryQuota=</varname></term>
|
||||||
|
|
||||||
|
<listitem><para>Specifies the storage limits for the directories specified in <varname>StateDirectory=</varname>,
|
||||||
|
<varname>CacheDirectory=</varname>, or <varname>LogsDirectory=</varname> respectively.</para>
|
||||||
|
|
||||||
|
<para>The storage quota is defined in terms of disk blocks and inodes, as per
|
||||||
|
<ulink url="https://man7.org/linux/man-pages/man2/quotactl.2.html">quotactl</ulink>. Takes an absolute size limit
|
||||||
|
in bytes. If the value is suffixed with K, M, G or T, the specified size is parsed as Kilobytes, Megabytes, Gigabytes,
|
||||||
|
or Terabytes (with the base 1024), respectively. If an absolute size limit is specified, only the block quota is set
|
||||||
|
(rounded up to the nearest block). Alternatively, a percentage value may be specified, which applies the same percent
|
||||||
|
quota to both blocks and inodes. Defaults to <constant>off</constant>, in which case no storage limits will be set.</para>
|
||||||
|
|
||||||
|
<para>Only hard limits are set, not soft limits. If the underlying filesystem for the specified directories does not
|
||||||
|
support project quotas, the specified storage limits will not be set. In addition to enabling per-unit quotas with
|
||||||
|
these settings, it is necessary to enable <constant>prjquota</constant> on the file system level as well
|
||||||
|
(i.e. <command>tune2fs -Q prjquota</command>). Quotas must also be turned on with
|
||||||
|
<ulink url="https://linux.die.net/man/8/quotaon">quotaon.</ulink></para>
|
||||||
|
|
||||||
|
<xi:include href="version-info.xml" xpointer="v258"/></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><varname>StateDirectoryAccounting=</varname></term>
|
||||||
|
<term><varname>CacheDirectoryAccounting=</varname></term>
|
||||||
|
<term><varname>LogsDirectoryAccounting=</varname></term>
|
||||||
|
|
||||||
|
<listitem><para>Takes a boolean argument. If true, a project ID is assigned to the directories specified in
|
||||||
|
<varname>StateDirectory=</varname>, <varname>CacheDirectory=</varname>, or <varname>LogsDirectory=</varname>
|
||||||
|
respectively, which is used for tracking disk usage when disk quotas are turned on
|
||||||
|
(see <ulink url="https://man7.org/linux/man-pages/man8/repquota.8.html">repquota</ulink>). Defaults to false.</para>
|
||||||
|
|
||||||
|
<para>To set and enforce disk quotas, <varname>StateDirectoryQuota=</varname>, <varname>CacheDirectoryQuota=</varname>,
|
||||||
|
or <varname>LogsDirectoryQuota=</varname> must be specified.</para>
|
||||||
|
|
||||||
|
<xi:include href="version-info.xml" xpointer="v258"/></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><varname>RuntimeDirectoryPreserve=</varname></term>
|
<term><varname>RuntimeDirectoryPreserve=</varname></term>
|
||||||
|
|
||||||
|
@ -1695,7 +1695,7 @@ WantedBy=multi-user.target</programlisting>
|
|||||||
just starts one process in the background:</para>
|
just starts one process in the background:</para>
|
||||||
|
|
||||||
<programlisting>[Unit]
|
<programlisting>[Unit]
|
||||||
Description=Some simple daemon
|
Description=My Simple Daemon
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=forking
|
Type=forking
|
||||||
@ -1721,7 +1721,7 @@ WantedBy=multi-user.target</programlisting>
|
|||||||
The following example shows a typical DBus service:</para>
|
The following example shows a typical DBus service:</para>
|
||||||
|
|
||||||
<programlisting>[Unit]
|
<programlisting>[Unit]
|
||||||
Description=Simple DBus service
|
Description=Simple DBus Service
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=dbus
|
Type=dbus
|
||||||
@ -1760,7 +1760,7 @@ SystemdService=simple-dbus-service.service</programlisting>
|
|||||||
daemon would look like this:</para>
|
daemon would look like this:</para>
|
||||||
|
|
||||||
<programlisting>[Unit]
|
<programlisting>[Unit]
|
||||||
Description=Simple notifying service
|
Description=Simple Notifying Service
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=notify-reload
|
Type=notify-reload
|
||||||
|
@ -607,6 +607,7 @@ foreach ident : [
|
|||||||
['pivot_root', '''#include <sys/syscall.h>'''], # no known header declares pivot_root
|
['pivot_root', '''#include <sys/syscall.h>'''], # no known header declares pivot_root
|
||||||
['setxattrat', '''#include <sys/xattr.h>'''], # no known header declares setxattrat
|
['setxattrat', '''#include <sys/xattr.h>'''], # no known header declares setxattrat
|
||||||
['removexattrat', '''#include <sys/xattr.h>'''], # no known header declares removexattrat
|
['removexattrat', '''#include <sys/xattr.h>'''], # no known header declares removexattrat
|
||||||
|
['open_tree_attr', '''#include <sys/mount.h>'''], # no known header declares open_tree_attr
|
||||||
]
|
]
|
||||||
|
|
||||||
have = cc.has_function(ident[0], prefix : ident[1], args : '-D_GNU_SOURCE')
|
have = cc.has_function(ident[0], prefix : ident[1], args : '-D_GNU_SOURCE')
|
||||||
|
5
mkosi/mkosi.repart/20-disk.conf
Normal file
5
mkosi/mkosi.repart/20-disk.conf
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
[Partition]
|
||||||
|
Type=linux-generic
|
||||||
|
Format=ext4
|
||||||
|
SizeMinBytes=498M
|
||||||
|
SizeMaxBytes=498M
|
@ -10,6 +10,7 @@
|
|||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "fs-util.h"
|
#include "fs-util.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "recurse-dir.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
|
|
||||||
int chattr_full(
|
int chattr_full(
|
||||||
@ -169,3 +170,81 @@ int read_attr_at(int dir_fd, const char *path, unsigned *ret) {
|
|||||||
|
|
||||||
return read_attr_fd(fd, ret);
|
return read_attr_fd(fd, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int read_fs_xattr_fd(int fd, uint32_t *ret_xflags, uint32_t *ret_projid) {
|
||||||
|
struct fsxattr attrs;
|
||||||
|
_cleanup_close_ int fd_reopened = -EBADF;
|
||||||
|
|
||||||
|
assert(fd >= 0);
|
||||||
|
|
||||||
|
fd = fd_reopen_condition(fd, O_RDONLY|O_CLOEXEC|O_NOCTTY, O_PATH, &fd_reopened);
|
||||||
|
if (fd < 0)
|
||||||
|
return fd;
|
||||||
|
|
||||||
|
if (ioctl(fd, FS_IOC_FSGETXATTR, &attrs) < 0)
|
||||||
|
return -errno;
|
||||||
|
|
||||||
|
if (ret_xflags)
|
||||||
|
*ret_xflags = attrs.fsx_xflags;
|
||||||
|
|
||||||
|
if (ret_projid)
|
||||||
|
*ret_projid = attrs.fsx_projid;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int set_proj_id(int fd, uint32_t proj_id) {
|
||||||
|
struct fsxattr attrs;
|
||||||
|
_cleanup_close_ int fd_reopened = -EBADF;
|
||||||
|
|
||||||
|
assert(fd >= 0);
|
||||||
|
|
||||||
|
fd = fd_reopen_condition(fd, O_RDONLY|O_CLOEXEC|O_NOCTTY, O_PATH, &fd_reopened);
|
||||||
|
if (fd < 0)
|
||||||
|
return fd;
|
||||||
|
|
||||||
|
if (ioctl(fd, FS_IOC_FSGETXATTR, &attrs) < 0)
|
||||||
|
return -errno;
|
||||||
|
|
||||||
|
struct stat statbuf;
|
||||||
|
if (fstat(fd, &statbuf) < 0)
|
||||||
|
return -errno;
|
||||||
|
|
||||||
|
if (attrs.fsx_projid == proj_id && (!S_ISDIR(statbuf.st_mode) || FLAGS_SET(attrs.fsx_xflags, FS_XFLAG_PROJINHERIT)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
attrs.fsx_projid = proj_id;
|
||||||
|
if (S_ISDIR(statbuf.st_mode))
|
||||||
|
attrs.fsx_xflags |= FS_XFLAG_PROJINHERIT;
|
||||||
|
|
||||||
|
return RET_NERRNO(ioctl(fd, FS_IOC_FSSETXATTR, &attrs));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int set_proj_id_cb(
|
||||||
|
RecurseDirEvent event,
|
||||||
|
const char *path,
|
||||||
|
int dir_fd,
|
||||||
|
int inode_fd,
|
||||||
|
const struct dirent *de,
|
||||||
|
const struct statx *sx,
|
||||||
|
void *userdata) {
|
||||||
|
|
||||||
|
if (!IN_SET(event, RECURSE_DIR_ENTER, RECURSE_DIR_ENTRY))
|
||||||
|
return RECURSE_DIR_CONTINUE;
|
||||||
|
|
||||||
|
if (de && !IN_SET(de->d_type, DT_DIR, DT_REG))
|
||||||
|
return RECURSE_DIR_CONTINUE;
|
||||||
|
|
||||||
|
return set_proj_id(inode_fd, PTR_TO_UINT32(userdata));
|
||||||
|
}
|
||||||
|
|
||||||
|
int set_proj_id_recursive(int fd, uint32_t proj_id) {
|
||||||
|
return recurse_dir_at(
|
||||||
|
fd,
|
||||||
|
/* path = */ NULL,
|
||||||
|
/* statx_mask = */ 0,
|
||||||
|
/* n_depth_max = */ UINT_MAX,
|
||||||
|
RECURSE_DIR_ENSURE_TYPE|RECURSE_DIR_TOPLEVEL|RECURSE_DIR_INODE_FD,
|
||||||
|
set_proj_id_cb,
|
||||||
|
UINT32_TO_PTR(proj_id));
|
||||||
|
}
|
||||||
|
@ -50,6 +50,10 @@ static inline int chattr_path(const char *path, unsigned value, unsigned mask) {
|
|||||||
|
|
||||||
int read_attr_fd(int fd, unsigned *ret);
|
int read_attr_fd(int fd, unsigned *ret);
|
||||||
int read_attr_at(int dir_fd, const char *path, unsigned *ret);
|
int read_attr_at(int dir_fd, const char *path, unsigned *ret);
|
||||||
|
int read_fs_xattr_fd(int fd, uint32_t *ret_xflags, uint32_t *ret_projid);
|
||||||
|
|
||||||
|
int set_proj_id(int fd, uint32_t proj_id);
|
||||||
|
int set_proj_id_recursive(int fd, uint32_t proj_id);
|
||||||
|
|
||||||
/* Combination of chattr flags, that should be appropriate for secrets stored on disk: Secure Remove +
|
/* Combination of chattr flags, that should be appropriate for secrets stored on disk: Secure Remove +
|
||||||
* Exclusion from Dumping + Synchronous Writing (i.e. not caching in memory) + In-Place Updating (i.e. not
|
* Exclusion from Dumping + Synchronous Writing (i.e. not caching in memory) + In-Place Updating (i.e. not
|
||||||
|
@ -36,6 +36,7 @@ struct in_addr;
|
|||||||
struct in6_addr;
|
struct in6_addr;
|
||||||
struct inotify_event;
|
struct inotify_event;
|
||||||
struct iovec;
|
struct iovec;
|
||||||
|
struct mount_attr;
|
||||||
struct msghdr;
|
struct msghdr;
|
||||||
struct passwd;
|
struct passwd;
|
||||||
struct pollfd;
|
struct pollfd;
|
||||||
|
@ -120,3 +120,13 @@ static inline int missing_mount_setattr(int dfd, const char *path, unsigned flag
|
|||||||
}
|
}
|
||||||
# define mount_setattr missing_mount_setattr
|
# define mount_setattr missing_mount_setattr
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if HAVE_OPEN_TREE_ATTR
|
||||||
|
extern int open_tree_attr(int __dfd, const char *__filename, unsigned int __flags, struct mount_attr *__uattr, size_t __usize) __THROW;
|
||||||
|
#else
|
||||||
|
static inline int missing_open_tree_attr(int dfd, const char *filename, unsigned int flags, struct mount_attr *attr, size_t size) {
|
||||||
|
return syscall(__NR_open_tree_attr, dfd, filename, flags, attr, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
# define open_tree_attr missing_open_tree_attr
|
||||||
|
#endif
|
||||||
|
@ -6,8 +6,6 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "forward.h"
|
|
||||||
|
|
||||||
/* Note: if this code looks strange, this is because it is derived from the same
|
/* Note: if this code looks strange, this is because it is derived from the same
|
||||||
* template as the per-syscall blocks below. */
|
* template as the per-syscall blocks below. */
|
||||||
# if defined(__aarch64__)
|
# if defined(__aarch64__)
|
||||||
@ -100,7 +98,7 @@
|
|||||||
/* may be an (invalid) negative number due to libseccomp, see PR 13319 */
|
/* may be an (invalid) negative number due to libseccomp, see PR 13319 */
|
||||||
# if defined __NR_close_range && __NR_close_range >= 0
|
# if defined __NR_close_range && __NR_close_range >= 0
|
||||||
# if defined systemd_NR_close_range
|
# if defined systemd_NR_close_range
|
||||||
assert_cc(__NR_close_range == systemd_NR_close_range);
|
_Static_assert(__NR_close_range == systemd_NR_close_range, "");
|
||||||
# endif
|
# endif
|
||||||
# else
|
# else
|
||||||
# if defined __NR_close_range
|
# if defined __NR_close_range
|
||||||
@ -168,7 +166,7 @@ assert_cc(__NR_close_range == systemd_NR_close_range);
|
|||||||
/* may be an (invalid) negative number due to libseccomp, see PR 13319 */
|
/* may be an (invalid) negative number due to libseccomp, see PR 13319 */
|
||||||
# if defined __NR_fchmodat2 && __NR_fchmodat2 >= 0
|
# if defined __NR_fchmodat2 && __NR_fchmodat2 >= 0
|
||||||
# if defined systemd_NR_fchmodat2
|
# if defined systemd_NR_fchmodat2
|
||||||
assert_cc(__NR_fchmodat2 == systemd_NR_fchmodat2);
|
_Static_assert(__NR_fchmodat2 == systemd_NR_fchmodat2, "");
|
||||||
# endif
|
# endif
|
||||||
# else
|
# else
|
||||||
# if defined __NR_fchmodat2
|
# if defined __NR_fchmodat2
|
||||||
@ -236,7 +234,7 @@ assert_cc(__NR_fchmodat2 == systemd_NR_fchmodat2);
|
|||||||
/* may be an (invalid) negative number due to libseccomp, see PR 13319 */
|
/* may be an (invalid) negative number due to libseccomp, see PR 13319 */
|
||||||
# if defined __NR_mount_setattr && __NR_mount_setattr >= 0
|
# if defined __NR_mount_setattr && __NR_mount_setattr >= 0
|
||||||
# if defined systemd_NR_mount_setattr
|
# if defined systemd_NR_mount_setattr
|
||||||
assert_cc(__NR_mount_setattr == systemd_NR_mount_setattr);
|
_Static_assert(__NR_mount_setattr == systemd_NR_mount_setattr, "");
|
||||||
# endif
|
# endif
|
||||||
# else
|
# else
|
||||||
# if defined __NR_mount_setattr
|
# if defined __NR_mount_setattr
|
||||||
@ -304,7 +302,7 @@ assert_cc(__NR_mount_setattr == systemd_NR_mount_setattr);
|
|||||||
/* may be an (invalid) negative number due to libseccomp, see PR 13319 */
|
/* may be an (invalid) negative number due to libseccomp, see PR 13319 */
|
||||||
# if defined __NR_openat2 && __NR_openat2 >= 0
|
# if defined __NR_openat2 && __NR_openat2 >= 0
|
||||||
# if defined systemd_NR_openat2
|
# if defined systemd_NR_openat2
|
||||||
assert_cc(__NR_openat2 == systemd_NR_openat2);
|
_Static_assert(__NR_openat2 == systemd_NR_openat2, "");
|
||||||
# endif
|
# endif
|
||||||
# else
|
# else
|
||||||
# if defined __NR_openat2
|
# if defined __NR_openat2
|
||||||
@ -372,7 +370,7 @@ assert_cc(__NR_openat2 == systemd_NR_openat2);
|
|||||||
/* may be an (invalid) negative number due to libseccomp, see PR 13319 */
|
/* may be an (invalid) negative number due to libseccomp, see PR 13319 */
|
||||||
# if defined __NR_quotactl_fd && __NR_quotactl_fd >= 0
|
# if defined __NR_quotactl_fd && __NR_quotactl_fd >= 0
|
||||||
# if defined systemd_NR_quotactl_fd
|
# if defined systemd_NR_quotactl_fd
|
||||||
assert_cc(__NR_quotactl_fd == systemd_NR_quotactl_fd);
|
_Static_assert(__NR_quotactl_fd == systemd_NR_quotactl_fd, "");
|
||||||
# endif
|
# endif
|
||||||
# else
|
# else
|
||||||
# if defined __NR_quotactl_fd
|
# if defined __NR_quotactl_fd
|
||||||
@ -440,7 +438,7 @@ assert_cc(__NR_quotactl_fd == systemd_NR_quotactl_fd);
|
|||||||
/* may be an (invalid) negative number due to libseccomp, see PR 13319 */
|
/* may be an (invalid) negative number due to libseccomp, see PR 13319 */
|
||||||
# if defined __NR_removexattrat && __NR_removexattrat >= 0
|
# if defined __NR_removexattrat && __NR_removexattrat >= 0
|
||||||
# if defined systemd_NR_removexattrat
|
# if defined systemd_NR_removexattrat
|
||||||
assert_cc(__NR_removexattrat == systemd_NR_removexattrat);
|
_Static_assert(__NR_removexattrat == systemd_NR_removexattrat, "");
|
||||||
# endif
|
# endif
|
||||||
# else
|
# else
|
||||||
# if defined __NR_removexattrat
|
# if defined __NR_removexattrat
|
||||||
@ -508,7 +506,7 @@ assert_cc(__NR_removexattrat == systemd_NR_removexattrat);
|
|||||||
/* may be an (invalid) negative number due to libseccomp, see PR 13319 */
|
/* may be an (invalid) negative number due to libseccomp, see PR 13319 */
|
||||||
# if defined __NR_setxattrat && __NR_setxattrat >= 0
|
# if defined __NR_setxattrat && __NR_setxattrat >= 0
|
||||||
# if defined systemd_NR_setxattrat
|
# if defined systemd_NR_setxattrat
|
||||||
assert_cc(__NR_setxattrat == systemd_NR_setxattrat);
|
_Static_assert(__NR_setxattrat == systemd_NR_setxattrat, "");
|
||||||
# endif
|
# endif
|
||||||
# else
|
# else
|
||||||
# if defined __NR_setxattrat
|
# if defined __NR_setxattrat
|
||||||
@ -519,3 +517,71 @@ assert_cc(__NR_setxattrat == systemd_NR_setxattrat);
|
|||||||
# endif
|
# endif
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef __IGNORE_open_tree_attr
|
||||||
|
# if defined(__aarch64__)
|
||||||
|
# define systemd_NR_open_tree_attr 467
|
||||||
|
# elif defined(__alpha__)
|
||||||
|
# define systemd_NR_open_tree_attr 577
|
||||||
|
# elif defined(__arc__) || defined(__tilegx__)
|
||||||
|
# define systemd_NR_open_tree_attr 467
|
||||||
|
# elif defined(__arm__)
|
||||||
|
# define systemd_NR_open_tree_attr 467
|
||||||
|
# elif defined(__i386__)
|
||||||
|
# define systemd_NR_open_tree_attr 467
|
||||||
|
# elif defined(__ia64__)
|
||||||
|
# define systemd_NR_open_tree_attr -1
|
||||||
|
# elif defined(__loongarch_lp64)
|
||||||
|
# define systemd_NR_open_tree_attr 467
|
||||||
|
# elif defined(__m68k__)
|
||||||
|
# define systemd_NR_open_tree_attr 467
|
||||||
|
# elif defined(_MIPS_SIM)
|
||||||
|
# if _MIPS_SIM == _MIPS_SIM_ABI32
|
||||||
|
# define systemd_NR_open_tree_attr 4467
|
||||||
|
# elif _MIPS_SIM == _MIPS_SIM_NABI32
|
||||||
|
# define systemd_NR_open_tree_attr 6467
|
||||||
|
# elif _MIPS_SIM == _MIPS_SIM_ABI64
|
||||||
|
# define systemd_NR_open_tree_attr 5467
|
||||||
|
# else
|
||||||
|
# error "Unknown MIPS ABI"
|
||||||
|
# endif
|
||||||
|
# elif defined(__hppa__)
|
||||||
|
# define systemd_NR_open_tree_attr 467
|
||||||
|
# elif defined(__powerpc__)
|
||||||
|
# define systemd_NR_open_tree_attr 467
|
||||||
|
# elif defined(__riscv)
|
||||||
|
# if __riscv_xlen == 32
|
||||||
|
# define systemd_NR_open_tree_attr 467
|
||||||
|
# elif __riscv_xlen == 64
|
||||||
|
# define systemd_NR_open_tree_attr 467
|
||||||
|
# else
|
||||||
|
# error "Unknown RISC-V ABI"
|
||||||
|
# endif
|
||||||
|
# elif defined(__s390__)
|
||||||
|
# define systemd_NR_open_tree_attr 467
|
||||||
|
# elif defined(__sparc__)
|
||||||
|
# define systemd_NR_open_tree_attr 467
|
||||||
|
# elif defined(__x86_64__)
|
||||||
|
# if defined(__ILP32__)
|
||||||
|
# define systemd_NR_open_tree_attr (467 | /* __X32_SYSCALL_BIT */ 0x40000000)
|
||||||
|
# else
|
||||||
|
# define systemd_NR_open_tree_attr 467
|
||||||
|
# endif
|
||||||
|
# elif !defined(missing_arch_template)
|
||||||
|
# warning "open_tree_attr() syscall number is unknown for your architecture"
|
||||||
|
# endif
|
||||||
|
|
||||||
|
/* may be an (invalid) negative number due to libseccomp, see PR 13319 */
|
||||||
|
# if defined __NR_open_tree_attr && __NR_open_tree_attr >= 0
|
||||||
|
# if defined systemd_NR_open_tree_attr
|
||||||
|
_Static_assert(__NR_open_tree_attr == systemd_NR_open_tree_attr, "");
|
||||||
|
# endif
|
||||||
|
# else
|
||||||
|
# if defined __NR_open_tree_attr
|
||||||
|
# undef __NR_open_tree_attr
|
||||||
|
# endif
|
||||||
|
# if defined systemd_NR_open_tree_attr && systemd_NR_open_tree_attr >= 0
|
||||||
|
# define __NR_open_tree_attr systemd_NR_open_tree_attr
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
@ -9,6 +9,7 @@ SYSCALLS = [
|
|||||||
'close_range', # defined in glibc header since glibc-2.33
|
'close_range', # defined in glibc header since glibc-2.33
|
||||||
'fchmodat2', # defined in glibc header since glibc-2.39
|
'fchmodat2', # defined in glibc header since glibc-2.39
|
||||||
'mount_setattr', # defined in glibc header since glibc-2.34
|
'mount_setattr', # defined in glibc header since glibc-2.34
|
||||||
|
'open_tree_attr',
|
||||||
'openat2', # defined in glibc header since glibc-2.32
|
'openat2', # defined in glibc header since glibc-2.32
|
||||||
'quotactl_fd', # defined in glibc header since glibc-2.35
|
'quotactl_fd', # defined in glibc header since glibc-2.35
|
||||||
'removexattrat',
|
'removexattrat',
|
||||||
@ -96,7 +97,7 @@ DEF_TEMPLATE_C = '''\
|
|||||||
/* may be an (invalid) negative number due to libseccomp, see PR 13319 */
|
/* may be an (invalid) negative number due to libseccomp, see PR 13319 */
|
||||||
# if defined __NR_{syscall} && __NR_{syscall} >= 0
|
# if defined __NR_{syscall} && __NR_{syscall} >= 0
|
||||||
# if defined systemd_NR_{syscall}
|
# if defined systemd_NR_{syscall}
|
||||||
assert_cc(__NR_{syscall} == systemd_NR_{syscall});
|
_Static_assert(__NR_{syscall} == systemd_NR_{syscall}, "");
|
||||||
# endif
|
# endif
|
||||||
# else
|
# else
|
||||||
# if defined __NR_{syscall}
|
# if defined __NR_{syscall}
|
||||||
|
@ -57,7 +57,7 @@
|
|||||||
#include "bpf/restrict_fs/restrict-fs-skel.h"
|
#include "bpf/restrict_fs/restrict-fs-skel.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define CGROUP_CPU_QUOTA_DEFAULT_PERIOD_USEC ((usec_t) 100 * USEC_PER_MSEC)
|
#define CGROUP_CPU_QUOTA_DEFAULT_PERIOD_USEC (100 * USEC_PER_MSEC)
|
||||||
|
|
||||||
/* Returns the log level to use when cgroup attribute writes fail. When an attribute is missing or we have access
|
/* Returns the log level to use when cgroup attribute writes fail. When an attribute is missing or we have access
|
||||||
* problems we downgrade to LOG_DEBUG. This is supposed to be nice to container managers and kernels which want to mask
|
* problems we downgrade to LOG_DEBUG. This is supposed to be nice to container managers and kernels which want to mask
|
||||||
@ -90,6 +90,19 @@ bool manager_owns_host_root_cgroup(Manager *m) {
|
|||||||
return empty_or_root(m->cgroup_root);
|
return empty_or_root(m->cgroup_root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool unit_has_host_root_cgroup(const Unit *u) {
|
||||||
|
assert(u);
|
||||||
|
assert(u->manager);
|
||||||
|
|
||||||
|
/* Returns whether this unit manages the root cgroup. This will return true if this unit is the root slice and
|
||||||
|
* the manager manages the root cgroup. */
|
||||||
|
|
||||||
|
if (!manager_owns_host_root_cgroup(u->manager))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return unit_has_name(u, SPECIAL_ROOT_SLICE);
|
||||||
|
}
|
||||||
|
|
||||||
bool unit_has_startup_cgroup_constraints(Unit *u) {
|
bool unit_has_startup_cgroup_constraints(Unit *u) {
|
||||||
assert(u);
|
assert(u);
|
||||||
|
|
||||||
@ -112,32 +125,21 @@ bool unit_has_startup_cgroup_constraints(Unit *u) {
|
|||||||
c->startup_memory_low_set;
|
c->startup_memory_low_set;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool unit_has_host_root_cgroup(const Unit *u) {
|
static int set_attribute_and_warn(Unit *u, const char *attribute, const char *value) {
|
||||||
assert(u);
|
|
||||||
assert(u->manager);
|
|
||||||
|
|
||||||
/* Returns whether this unit manages the root cgroup. This will return true if this unit is the root slice and
|
|
||||||
* the manager manages the root cgroup. */
|
|
||||||
|
|
||||||
if (!manager_owns_host_root_cgroup(u->manager))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return unit_has_name(u, SPECIAL_ROOT_SLICE);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int set_attribute_and_warn(Unit *u, const char *controller, const char *attribute, const char *value) {
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(u);
|
assert(u);
|
||||||
|
assert(attribute);
|
||||||
|
assert(value);
|
||||||
|
|
||||||
CGroupRuntime *crt = unit_get_cgroup_runtime(u);
|
CGroupRuntime *crt = unit_get_cgroup_runtime(u);
|
||||||
if (!crt || !crt->cgroup_path)
|
if (!crt || !crt->cgroup_path)
|
||||||
return -EOWNERDEAD;
|
return -EOWNERDEAD;
|
||||||
|
|
||||||
r = cg_set_attribute(controller, crt->cgroup_path, attribute, value);
|
r = cg_set_attribute(SYSTEMD_CGROUP_CONTROLLER, crt->cgroup_path, attribute, value);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_unit_full_errno(u, LOG_LEVEL_CGROUP_WRITE(r), r, "Failed to set '%s' attribute on '%s' to '%.*s': %m",
|
log_unit_full_errno(u, LOG_LEVEL_CGROUP_WRITE(r), r, "Failed to set '%s' attribute on '%s' to '%.*s': %m",
|
||||||
strna(attribute), empty_to_root(crt->cgroup_path), (int) strcspn(value, NEWLINE), value);
|
attribute, empty_to_root(crt->cgroup_path), (int) strcspn(value, NEWLINE), value);
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
@ -1121,7 +1123,7 @@ static void cgroup_apply_cpu_weight(Unit *u, uint64_t weight) {
|
|||||||
if (weight == CGROUP_WEIGHT_IDLE)
|
if (weight == CGROUP_WEIGHT_IDLE)
|
||||||
return;
|
return;
|
||||||
xsprintf(buf, "%" PRIu64 "\n", weight);
|
xsprintf(buf, "%" PRIu64 "\n", weight);
|
||||||
(void) set_attribute_and_warn(u, "cpu", "cpu.weight", buf);
|
(void) set_attribute_and_warn(u, "cpu.weight", buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cgroup_apply_cpu_idle(Unit *u, uint64_t weight) {
|
static void cgroup_apply_cpu_idle(Unit *u, uint64_t weight) {
|
||||||
@ -1154,7 +1156,7 @@ static void cgroup_apply_cpu_quota(Unit *u, usec_t quota, usec_t period) {
|
|||||||
MAX(quota * period / USEC_PER_SEC, USEC_PER_MSEC), period);
|
MAX(quota * period / USEC_PER_SEC, USEC_PER_MSEC), period);
|
||||||
else
|
else
|
||||||
xsprintf(buf, "max " USEC_FMT "\n", period);
|
xsprintf(buf, "max " USEC_FMT "\n", period);
|
||||||
(void) set_attribute_and_warn(u, "cpu", "cpu.max", buf);
|
(void) set_attribute_and_warn(u, "cpu.max", buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cgroup_apply_cpuset(Unit *u, const CPUSet *cpus, const char *name) {
|
static void cgroup_apply_cpuset(Unit *u, const CPUSet *cpus, const char *name) {
|
||||||
@ -1166,7 +1168,7 @@ static void cgroup_apply_cpuset(Unit *u, const CPUSet *cpus, const char *name) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
(void) set_attribute_and_warn(u, "cpuset", name, buf);
|
(void) set_attribute_and_warn(u, name, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool cgroup_context_has_io_config(CGroupContext *c) {
|
static bool cgroup_context_has_io_config(CGroupContext *c) {
|
||||||
@ -1187,10 +1189,8 @@ static uint64_t cgroup_context_io_weight(CGroupContext *c, ManagerState state) {
|
|||||||
return CGROUP_WEIGHT_DEFAULT;
|
return CGROUP_WEIGHT_DEFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int set_bfq_weight(Unit *u, const char *controller, dev_t dev, uint64_t io_weight) {
|
static int set_bfq_weight(Unit *u, dev_t dev, uint64_t io_weight) {
|
||||||
static bool warned = false;
|
|
||||||
char buf[DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(uint64_t)+STRLEN("\n")];
|
char buf[DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(uint64_t)+STRLEN("\n")];
|
||||||
const char *p;
|
|
||||||
uint64_t bfq_weight;
|
uint64_t bfq_weight;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -1203,7 +1203,6 @@ static int set_bfq_weight(Unit *u, const char *controller, dev_t dev, uint64_t i
|
|||||||
/* FIXME: drop this function when distro kernels properly support BFQ through "io.weight"
|
/* FIXME: drop this function when distro kernels properly support BFQ through "io.weight"
|
||||||
* See also: https://github.com/systemd/systemd/pull/13335 and
|
* See also: https://github.com/systemd/systemd/pull/13335 and
|
||||||
* https://github.com/torvalds/linux/commit/65752aef0a407e1ef17ec78a7fc31ba4e0b360f9. */
|
* https://github.com/torvalds/linux/commit/65752aef0a407e1ef17ec78a7fc31ba4e0b360f9. */
|
||||||
p = strjoina(controller, ".bfq.weight");
|
|
||||||
/* Adjust to kernel range is 1..1000, the default is 100. */
|
/* Adjust to kernel range is 1..1000, the default is 100. */
|
||||||
bfq_weight = BFQ_WEIGHT(io_weight);
|
bfq_weight = BFQ_WEIGHT(io_weight);
|
||||||
|
|
||||||
@ -1212,22 +1211,11 @@ static int set_bfq_weight(Unit *u, const char *controller, dev_t dev, uint64_t i
|
|||||||
else
|
else
|
||||||
xsprintf(buf, "%" PRIu64 "\n", bfq_weight);
|
xsprintf(buf, "%" PRIu64 "\n", bfq_weight);
|
||||||
|
|
||||||
r = cg_set_attribute(controller, crt->cgroup_path, p, buf);
|
r = cg_set_attribute(SYSTEMD_CGROUP_CONTROLLER, crt->cgroup_path, "io.bfq.weight", buf);
|
||||||
|
if (r >= 0 && io_weight != bfq_weight)
|
||||||
/* FIXME: drop this when kernels prior
|
log_unit_debug(u, "%s=%" PRIu64 " scaled to io.bfq.weight=%" PRIu64,
|
||||||
* 795fe54c2a82 ("bfq: Add per-device weight") v5.4
|
|
||||||
* are not interesting anymore. Old kernels will fail with EINVAL, while new kernels won't return
|
|
||||||
* EINVAL on properly formatted input by us. Treat EINVAL accordingly. */
|
|
||||||
if (r == -EINVAL && major(dev) > 0) {
|
|
||||||
if (!warned) {
|
|
||||||
log_unit_warning(u, "Kernel version does not accept per-device setting in %s.", p);
|
|
||||||
warned = true;
|
|
||||||
}
|
|
||||||
r = -EOPNOTSUPP; /* mask as unconfigured device */
|
|
||||||
} else if (r >= 0 && io_weight != bfq_weight)
|
|
||||||
log_unit_debug(u, "%s=%" PRIu64 " scaled to %s=%" PRIu64,
|
|
||||||
major(dev) > 0 ? "IODeviceWeight" : "IOWeight",
|
major(dev) > 0 ? "IODeviceWeight" : "IOWeight",
|
||||||
io_weight, p, bfq_weight);
|
io_weight, bfq_weight);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1245,7 +1233,7 @@ static void cgroup_apply_io_device_weight(Unit *u, const char *dev_path, uint64_
|
|||||||
if (lookup_block_device(dev_path, &dev) < 0)
|
if (lookup_block_device(dev_path, &dev) < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
r1 = set_bfq_weight(u, "io", dev, io_weight);
|
r1 = set_bfq_weight(u, dev, io_weight);
|
||||||
|
|
||||||
xsprintf(buf, DEVNUM_FORMAT_STR " %" PRIu64 "\n", DEVNUM_FORMAT_VAL(dev), io_weight);
|
xsprintf(buf, DEVNUM_FORMAT_STR " %" PRIu64 "\n", DEVNUM_FORMAT_VAL(dev), io_weight);
|
||||||
r2 = cg_set_attribute("io", crt->cgroup_path, "io.weight", buf);
|
r2 = cg_set_attribute("io", crt->cgroup_path, "io.weight", buf);
|
||||||
@ -1273,7 +1261,7 @@ static void cgroup_apply_io_device_latency(Unit *u, const char *dev_path, usec_t
|
|||||||
else
|
else
|
||||||
xsprintf(buf, DEVNUM_FORMAT_STR " target=max\n", DEVNUM_FORMAT_VAL(dev));
|
xsprintf(buf, DEVNUM_FORMAT_STR " target=max\n", DEVNUM_FORMAT_VAL(dev));
|
||||||
|
|
||||||
(void) set_attribute_and_warn(u, "io", "io.latency", buf);
|
(void) set_attribute_and_warn(u, "io.latency", buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cgroup_apply_io_device_limit(Unit *u, const char *dev_path, uint64_t *limits) {
|
static void cgroup_apply_io_device_limit(Unit *u, const char *dev_path, uint64_t *limits) {
|
||||||
@ -1293,7 +1281,7 @@ static void cgroup_apply_io_device_limit(Unit *u, const char *dev_path, uint64_t
|
|||||||
xsprintf(buf, DEVNUM_FORMAT_STR " rbps=%s wbps=%s riops=%s wiops=%s\n", DEVNUM_FORMAT_VAL(dev),
|
xsprintf(buf, DEVNUM_FORMAT_STR " rbps=%s wbps=%s riops=%s wiops=%s\n", DEVNUM_FORMAT_VAL(dev),
|
||||||
limit_bufs[CGROUP_IO_RBPS_MAX], limit_bufs[CGROUP_IO_WBPS_MAX],
|
limit_bufs[CGROUP_IO_RBPS_MAX], limit_bufs[CGROUP_IO_WBPS_MAX],
|
||||||
limit_bufs[CGROUP_IO_RIOPS_MAX], limit_bufs[CGROUP_IO_WIOPS_MAX]);
|
limit_bufs[CGROUP_IO_RIOPS_MAX], limit_bufs[CGROUP_IO_WIOPS_MAX]);
|
||||||
(void) set_attribute_and_warn(u, "io", "io.max", buf);
|
(void) set_attribute_and_warn(u, "io.max", buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool unit_has_memory_config(Unit *u) {
|
static bool unit_has_memory_config(Unit *u) {
|
||||||
@ -1317,7 +1305,7 @@ static void cgroup_apply_memory_limit(Unit *u, const char *file, uint64_t v) {
|
|||||||
if (v != CGROUP_LIMIT_MAX)
|
if (v != CGROUP_LIMIT_MAX)
|
||||||
xsprintf(buf, "%" PRIu64 "\n", v);
|
xsprintf(buf, "%" PRIu64 "\n", v);
|
||||||
|
|
||||||
(void) set_attribute_and_warn(u, "memory", file, buf);
|
(void) set_attribute_and_warn(u, file, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cgroup_apply_firewall(Unit *u) {
|
static void cgroup_apply_firewall(Unit *u) {
|
||||||
@ -1462,10 +1450,10 @@ static void set_io_weight(Unit *u, uint64_t weight) {
|
|||||||
|
|
||||||
assert(u);
|
assert(u);
|
||||||
|
|
||||||
(void) set_bfq_weight(u, "io", makedev(0, 0), weight);
|
(void) set_bfq_weight(u, makedev(0, 0), weight);
|
||||||
|
|
||||||
xsprintf(buf, "default %" PRIu64 "\n", weight);
|
xsprintf(buf, "default %" PRIu64 "\n", weight);
|
||||||
(void) set_attribute_and_warn(u, "io", "io.weight", buf);
|
(void) set_attribute_and_warn(u, "io.weight", buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cgroup_apply_bpf_foreign_program(Unit *u) {
|
static void cgroup_apply_bpf_foreign_program(Unit *u) {
|
||||||
@ -1570,8 +1558,8 @@ static void cgroup_context_apply(
|
|||||||
cgroup_apply_memory_limit(u, "memory.swap.max", swap_max);
|
cgroup_apply_memory_limit(u, "memory.swap.max", swap_max);
|
||||||
cgroup_apply_memory_limit(u, "memory.zswap.max", zswap_max);
|
cgroup_apply_memory_limit(u, "memory.zswap.max", zswap_max);
|
||||||
|
|
||||||
(void) set_attribute_and_warn(u, "memory", "memory.oom.group", one_zero(c->memory_oom_group));
|
(void) set_attribute_and_warn(u, "memory.oom.group", one_zero(c->memory_oom_group));
|
||||||
(void) set_attribute_and_warn(u, "memory", "memory.zswap.writeback", one_zero(c->memory_zswap_writeback));
|
(void) set_attribute_and_warn(u, "memory.zswap.writeback", one_zero(c->memory_zswap_writeback));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (apply_mask & CGROUP_MASK_PIDS) {
|
if (apply_mask & CGROUP_MASK_PIDS) {
|
||||||
@ -1609,9 +1597,9 @@ static void cgroup_context_apply(
|
|||||||
char buf[DECIMAL_STR_MAX(uint64_t) + 1];
|
char buf[DECIMAL_STR_MAX(uint64_t) + 1];
|
||||||
|
|
||||||
xsprintf(buf, "%" PRIu64 "\n", cgroup_tasks_max_resolve(&c->tasks_max));
|
xsprintf(buf, "%" PRIu64 "\n", cgroup_tasks_max_resolve(&c->tasks_max));
|
||||||
(void) set_attribute_and_warn(u, "pids", "pids.max", buf);
|
(void) set_attribute_and_warn(u, "pids.max", buf);
|
||||||
} else
|
} else
|
||||||
(void) set_attribute_and_warn(u, "pids", "pids.max", "max\n");
|
(void) set_attribute_and_warn(u, "pids.max", "max\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1714,15 +1702,14 @@ static CGroupMask unit_get_cgroup_mask(Unit *u) {
|
|||||||
mask |= CGROUP_MASK_CPUSET;
|
mask |= CGROUP_MASK_CPUSET;
|
||||||
|
|
||||||
if (cgroup_context_has_io_config(c))
|
if (cgroup_context_has_io_config(c))
|
||||||
mask |= CGROUP_MASK_IO | CGROUP_MASK_BLKIO;
|
mask |= CGROUP_MASK_IO;
|
||||||
|
|
||||||
if (c->memory_accounting ||
|
if (c->memory_accounting ||
|
||||||
unit_has_memory_config(u))
|
unit_has_memory_config(u))
|
||||||
mask |= CGROUP_MASK_MEMORY;
|
mask |= CGROUP_MASK_MEMORY;
|
||||||
|
|
||||||
if (c->device_allow ||
|
if (cgroup_context_has_device_policy(c))
|
||||||
c->device_policy != CGROUP_DEVICE_POLICY_AUTO)
|
mask |= CGROUP_MASK_BPF_DEVICES;
|
||||||
mask |= CGROUP_MASK_DEVICES | CGROUP_MASK_BPF_DEVICES;
|
|
||||||
|
|
||||||
if (c->tasks_accounting ||
|
if (c->tasks_accounting ||
|
||||||
cgroup_tasks_max_isset(&c->tasks_max))
|
cgroup_tasks_max_isset(&c->tasks_max))
|
||||||
@ -1840,7 +1827,7 @@ static CGroupMask unit_get_disable_mask(Unit *u) {
|
|||||||
return c->disable_controllers;
|
return c->disable_controllers;
|
||||||
}
|
}
|
||||||
|
|
||||||
CGroupMask unit_get_ancestor_disable_mask(Unit *u) {
|
static CGroupMask unit_get_ancestor_disable_mask(Unit *u) {
|
||||||
CGroupMask mask;
|
CGroupMask mask;
|
||||||
Unit *slice;
|
Unit *slice;
|
||||||
|
|
||||||
@ -2486,7 +2473,6 @@ static int unit_realize_cgroup_now_disable(Unit *u, ManagerState state) {
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* We must disable those below us first in order to release the controller. */
|
/* We must disable those below us first in order to release the controller. */
|
||||||
if (m->type == UNIT_SLICE)
|
|
||||||
(void) unit_realize_cgroup_now_disable(m, state);
|
(void) unit_realize_cgroup_now_disable(m, state);
|
||||||
|
|
||||||
target_mask = unit_get_target_mask(m);
|
target_mask = unit_get_target_mask(m);
|
||||||
@ -3954,46 +3940,38 @@ int unit_reset_accounting(Unit *u) {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
void unit_invalidate_cgroup(Unit *u, CGroupMask m) {
|
bool unit_invalidate_cgroup(Unit *u, CGroupMask m) {
|
||||||
assert(u);
|
assert(u);
|
||||||
|
|
||||||
if (!UNIT_HAS_CGROUP_CONTEXT(u))
|
if (!UNIT_HAS_CGROUP_CONTEXT(u))
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
CGroupRuntime *crt = unit_get_cgroup_runtime(u);
|
CGroupRuntime *crt = unit_get_cgroup_runtime(u);
|
||||||
if (!crt)
|
if (!crt)
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
if (FLAGS_SET(crt->cgroup_invalidated_mask, m)) /* NOP? */
|
if (FLAGS_SET(crt->cgroup_invalidated_mask, m)) /* NOP? */
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
crt->cgroup_invalidated_mask |= m;
|
crt->cgroup_invalidated_mask |= m;
|
||||||
unit_add_to_cgroup_realize_queue(u);
|
unit_add_to_cgroup_realize_queue(u);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void unit_invalidate_cgroup_bpf(Unit *u) {
|
void unit_invalidate_cgroup_bpf_firewall(Unit *u) {
|
||||||
assert(u);
|
assert(u);
|
||||||
|
|
||||||
if (!UNIT_HAS_CGROUP_CONTEXT(u))
|
if (!unit_invalidate_cgroup(u, CGROUP_MASK_BPF_FIREWALL))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
CGroupRuntime *crt = unit_get_cgroup_runtime(u);
|
|
||||||
if (!crt)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (crt->cgroup_invalidated_mask & CGROUP_MASK_BPF_FIREWALL) /* NOP? */
|
|
||||||
return;
|
|
||||||
|
|
||||||
crt->cgroup_invalidated_mask |= CGROUP_MASK_BPF_FIREWALL;
|
|
||||||
unit_add_to_cgroup_realize_queue(u);
|
|
||||||
|
|
||||||
/* If we are a slice unit, we also need to put compile a new BPF program for all our children, as the IP access
|
/* If we are a slice unit, we also need to put compile a new BPF program for all our children, as the IP access
|
||||||
* list of our children includes our own. */
|
* list of our children includes our own. */
|
||||||
if (u->type == UNIT_SLICE) {
|
if (u->type == UNIT_SLICE) {
|
||||||
Unit *member;
|
Unit *member;
|
||||||
|
|
||||||
UNIT_FOREACH_DEPENDENCY(member, u, UNIT_ATOM_SLICE_OF)
|
UNIT_FOREACH_DEPENDENCY(member, u, UNIT_ATOM_SLICE_OF)
|
||||||
unit_invalidate_cgroup_bpf(member);
|
unit_invalidate_cgroup_bpf_firewall(member);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4033,7 +4011,7 @@ void manager_invalidate_startup_units(Manager *m) {
|
|||||||
assert(m);
|
assert(m);
|
||||||
|
|
||||||
SET_FOREACH(u, m->startup_units)
|
SET_FOREACH(u, m->startup_units)
|
||||||
unit_invalidate_cgroup(u, CGROUP_MASK_CPU|CGROUP_MASK_IO|CGROUP_MASK_BLKIO|CGROUP_MASK_CPUSET);
|
unit_invalidate_cgroup(u, CGROUP_MASK_CPU|CGROUP_MASK_IO|CGROUP_MASK_CPUSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int unit_cgroup_freezer_kernel_state(Unit *u, FreezerState *ret) {
|
static int unit_cgroup_freezer_kernel_state(Unit *u, FreezerState *ret) {
|
||||||
|
@ -14,7 +14,7 @@ typedef struct CGroupTasksMax {
|
|||||||
uint64_t scale;
|
uint64_t scale;
|
||||||
} CGroupTasksMax;
|
} CGroupTasksMax;
|
||||||
|
|
||||||
#define CGROUP_TASKS_MAX_UNSET ((CGroupTasksMax) { .value = UINT64_MAX, .scale = 0 })
|
#define CGROUP_TASKS_MAX_UNSET ((const CGroupTasksMax) { .value = UINT64_MAX, .scale = 0 })
|
||||||
|
|
||||||
static inline bool cgroup_tasks_max_isset(const CGroupTasksMax *tasks_max) {
|
static inline bool cgroup_tasks_max_isset(const CGroupTasksMax *tasks_max) {
|
||||||
return tasks_max->value != UINT64_MAX || tasks_max->scale != 0;
|
return tasks_max->value != UINT64_MAX || tasks_max->scale != 0;
|
||||||
@ -339,8 +339,8 @@ uint64_t cgroup_context_cpu_weight(CGroupContext *c, ManagerState state);
|
|||||||
usec_t cgroup_cpu_adjust_period(usec_t period, usec_t quota, usec_t resolution, usec_t max_period);
|
usec_t cgroup_cpu_adjust_period(usec_t period, usec_t quota, usec_t resolution, usec_t max_period);
|
||||||
|
|
||||||
void cgroup_context_init(CGroupContext *c);
|
void cgroup_context_init(CGroupContext *c);
|
||||||
int cgroup_context_copy(CGroupContext *dst, const CGroupContext *src);
|
|
||||||
void cgroup_context_done(CGroupContext *c);
|
void cgroup_context_done(CGroupContext *c);
|
||||||
|
|
||||||
void cgroup_context_dump(Unit *u, FILE* f, const char *prefix);
|
void cgroup_context_dump(Unit *u, FILE* f, const char *prefix);
|
||||||
void cgroup_context_dump_socket_bind_item(const CGroupSocketBindItem *item, FILE *f);
|
void cgroup_context_dump_socket_bind_item(const CGroupSocketBindItem *item, FILE *f);
|
||||||
void cgroup_context_dump_socket_bind_items(const CGroupSocketBindItem *items, FILE *f);
|
void cgroup_context_dump_socket_bind_items(const CGroupSocketBindItem *items, FILE *f);
|
||||||
@ -359,6 +359,13 @@ static inline bool cgroup_context_want_memory_pressure(const CGroupContext *c) {
|
|||||||
(c->memory_pressure_watch == CGROUP_PRESSURE_WATCH_AUTO && c->memory_accounting);
|
(c->memory_pressure_watch == CGROUP_PRESSURE_WATCH_AUTO && c->memory_accounting);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool cgroup_context_has_device_policy(const CGroupContext *c) {
|
||||||
|
assert(c);
|
||||||
|
|
||||||
|
return c->device_policy != CGROUP_DEVICE_POLICY_AUTO ||
|
||||||
|
c->device_allow;
|
||||||
|
}
|
||||||
|
|
||||||
int cgroup_context_add_device_allow(CGroupContext *c, const char *dev, CGroupDevicePermissions p);
|
int cgroup_context_add_device_allow(CGroupContext *c, const char *dev, CGroupDevicePermissions p);
|
||||||
int cgroup_context_add_or_update_device_allow(CGroupContext *c, const char *dev, CGroupDevicePermissions p);
|
int cgroup_context_add_or_update_device_allow(CGroupContext *c, const char *dev, CGroupDevicePermissions p);
|
||||||
int cgroup_context_add_bpf_foreign_program(CGroupContext *c, uint32_t attach_type, const char *path);
|
int cgroup_context_add_bpf_foreign_program(CGroupContext *c, uint32_t attach_type, const char *path);
|
||||||
@ -369,7 +376,6 @@ CGroupMask unit_get_own_mask(Unit *u);
|
|||||||
CGroupMask unit_get_delegate_mask(Unit *u);
|
CGroupMask unit_get_delegate_mask(Unit *u);
|
||||||
CGroupMask unit_get_members_mask(Unit *u);
|
CGroupMask unit_get_members_mask(Unit *u);
|
||||||
CGroupMask unit_get_siblings_mask(Unit *u);
|
CGroupMask unit_get_siblings_mask(Unit *u);
|
||||||
CGroupMask unit_get_ancestor_disable_mask(Unit *u);
|
|
||||||
|
|
||||||
CGroupMask unit_get_target_mask(Unit *u);
|
CGroupMask unit_get_target_mask(Unit *u);
|
||||||
CGroupMask unit_get_enable_mask(Unit *u);
|
CGroupMask unit_get_enable_mask(Unit *u);
|
||||||
@ -430,8 +436,8 @@ bool unit_has_host_root_cgroup(const Unit *u);
|
|||||||
|
|
||||||
bool unit_has_startup_cgroup_constraints(Unit *u);
|
bool unit_has_startup_cgroup_constraints(Unit *u);
|
||||||
|
|
||||||
void unit_invalidate_cgroup(Unit *u, CGroupMask m);
|
bool unit_invalidate_cgroup(Unit *u, CGroupMask m);
|
||||||
void unit_invalidate_cgroup_bpf(Unit *u);
|
void unit_invalidate_cgroup_bpf_firewall(Unit *u);
|
||||||
|
|
||||||
void manager_invalidate_startup_units(Manager *m);
|
void manager_invalidate_startup_units(Manager *m);
|
||||||
|
|
||||||
|
@ -614,7 +614,7 @@ static int bus_cgroup_set_transient_property(
|
|||||||
if (n == 0)
|
if (n == 0)
|
||||||
*filters = strv_free(*filters);
|
*filters = strv_free(*filters);
|
||||||
|
|
||||||
unit_invalidate_cgroup_bpf(u);
|
unit_invalidate_cgroup_bpf_firewall(u);
|
||||||
|
|
||||||
f = memstream_init(&m);
|
f = memstream_init(&m);
|
||||||
if (!f)
|
if (!f)
|
||||||
@ -1527,7 +1527,7 @@ int bus_cgroup_set_property(
|
|||||||
|
|
||||||
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
|
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
|
||||||
c->device_policy = p;
|
c->device_policy = p;
|
||||||
unit_invalidate_cgroup(u, CGROUP_MASK_DEVICES);
|
unit_invalidate_cgroup(u, CGROUP_MASK_BPF_DEVICES);
|
||||||
unit_write_settingf(u, flags, name, "DevicePolicy=%s", policy);
|
unit_write_settingf(u, flags, name, "DevicePolicy=%s", policy);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1579,7 +1579,7 @@ int bus_cgroup_set_property(
|
|||||||
while (c->device_allow)
|
while (c->device_allow)
|
||||||
cgroup_context_free_device_allow(c, c->device_allow);
|
cgroup_context_free_device_allow(c, c->device_allow);
|
||||||
|
|
||||||
unit_invalidate_cgroup(u, CGROUP_MASK_DEVICES);
|
unit_invalidate_cgroup(u, CGROUP_MASK_BPF_DEVICES);
|
||||||
|
|
||||||
f = memstream_init(&m);
|
f = memstream_init(&m);
|
||||||
if (!f)
|
if (!f)
|
||||||
@ -1608,7 +1608,7 @@ int bus_cgroup_set_property(
|
|||||||
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
|
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
|
||||||
c->ip_accounting = b;
|
c->ip_accounting = b;
|
||||||
|
|
||||||
unit_invalidate_cgroup_bpf(u);
|
unit_invalidate_cgroup_bpf_firewall(u);
|
||||||
unit_write_settingf(u, flags, name, "IPAccounting=%s", yes_no(b));
|
unit_write_settingf(u, flags, name, "IPAccounting=%s", yes_no(b));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1670,7 +1670,7 @@ int bus_cgroup_set_property(
|
|||||||
bool *reduced;
|
bool *reduced;
|
||||||
FILE *f;
|
FILE *f;
|
||||||
|
|
||||||
unit_invalidate_cgroup_bpf(u);
|
unit_invalidate_cgroup_bpf_firewall(u);
|
||||||
|
|
||||||
f = memstream_init(&m);
|
f = memstream_init(&m);
|
||||||
if (!f)
|
if (!f)
|
||||||
|
@ -31,7 +31,9 @@
|
|||||||
#include "namespace.h"
|
#include "namespace.h"
|
||||||
#include "nsflags.h"
|
#include "nsflags.h"
|
||||||
#include "ordered-set.h"
|
#include "ordered-set.h"
|
||||||
|
#include "parse-util.h"
|
||||||
#include "path-util.h"
|
#include "path-util.h"
|
||||||
|
#include "percent-util.h"
|
||||||
#include "pcre2-util.h"
|
#include "pcre2-util.h"
|
||||||
#include "process-util.h"
|
#include "process-util.h"
|
||||||
#include "rlimit-util.h"
|
#include "rlimit-util.h"
|
||||||
@ -1000,6 +1002,22 @@ static int property_get_exec_dir_symlink(
|
|||||||
return sd_bus_message_close_container(reply);
|
return sd_bus_message_close_container(reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int property_get_exec_quota(sd_bus *bus,
|
||||||
|
const char *path,
|
||||||
|
const char *interface,
|
||||||
|
const char *property,
|
||||||
|
sd_bus_message *reply,
|
||||||
|
void *userdata,
|
||||||
|
sd_bus_error *error) {
|
||||||
|
|
||||||
|
QuotaLimit *q = ASSERT_PTR(userdata);
|
||||||
|
|
||||||
|
assert(bus);
|
||||||
|
assert(reply);
|
||||||
|
|
||||||
|
return sd_bus_message_append(reply, "(tus)", q->quota_absolute, q->quota_scale, yes_no(q->quota_enforce));
|
||||||
|
}
|
||||||
|
|
||||||
static int property_get_image_policy(
|
static int property_get_image_policy(
|
||||||
sd_bus *bus,
|
sd_bus *bus,
|
||||||
const char *path,
|
const char *path,
|
||||||
@ -1266,12 +1284,18 @@ const sd_bus_vtable bus_exec_vtable[] = {
|
|||||||
SD_BUS_PROPERTY("RuntimeDirectory", "as", property_get_exec_dir, offsetof(ExecContext, directories[EXEC_DIRECTORY_RUNTIME]), SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("RuntimeDirectory", "as", property_get_exec_dir, offsetof(ExecContext, directories[EXEC_DIRECTORY_RUNTIME]), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("StateDirectorySymlink", "a(sst)", property_get_exec_dir_symlink, offsetof(ExecContext, directories[EXEC_DIRECTORY_STATE]), SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("StateDirectorySymlink", "a(sst)", property_get_exec_dir_symlink, offsetof(ExecContext, directories[EXEC_DIRECTORY_STATE]), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("StateDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, directories[EXEC_DIRECTORY_STATE].mode), SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("StateDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, directories[EXEC_DIRECTORY_STATE].mode), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
|
SD_BUS_PROPERTY("StateDirectoryAccounting", "b", bus_property_get_bool, offsetof(ExecContext, directories[EXEC_DIRECTORY_STATE].exec_quota.quota_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
|
SD_BUS_PROPERTY("StateDirectoryQuota", "(tus)", property_get_exec_quota, offsetof(ExecContext, directories[EXEC_DIRECTORY_STATE].exec_quota), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("StateDirectory", "as", property_get_exec_dir, offsetof(ExecContext, directories[EXEC_DIRECTORY_STATE]), SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("StateDirectory", "as", property_get_exec_dir, offsetof(ExecContext, directories[EXEC_DIRECTORY_STATE]), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("CacheDirectorySymlink", "a(sst)", property_get_exec_dir_symlink, offsetof(ExecContext, directories[EXEC_DIRECTORY_CACHE]), SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("CacheDirectorySymlink", "a(sst)", property_get_exec_dir_symlink, offsetof(ExecContext, directories[EXEC_DIRECTORY_CACHE]), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("CacheDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, directories[EXEC_DIRECTORY_CACHE].mode), SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("CacheDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, directories[EXEC_DIRECTORY_CACHE].mode), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
|
SD_BUS_PROPERTY("CacheDirectoryAccounting", "b", bus_property_get_bool, offsetof(ExecContext, directories[EXEC_DIRECTORY_CACHE].exec_quota.quota_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
|
SD_BUS_PROPERTY("CacheDirectoryQuota", "(tus)", property_get_exec_quota, offsetof(ExecContext, directories[EXEC_DIRECTORY_CACHE].exec_quota), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("CacheDirectory", "as", property_get_exec_dir, offsetof(ExecContext, directories[EXEC_DIRECTORY_CACHE]), SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("CacheDirectory", "as", property_get_exec_dir, offsetof(ExecContext, directories[EXEC_DIRECTORY_CACHE]), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("LogsDirectorySymlink", "a(sst)", property_get_exec_dir_symlink, offsetof(ExecContext, directories[EXEC_DIRECTORY_LOGS]), SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("LogsDirectorySymlink", "a(sst)", property_get_exec_dir_symlink, offsetof(ExecContext, directories[EXEC_DIRECTORY_LOGS]), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("LogsDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, directories[EXEC_DIRECTORY_LOGS].mode), SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("LogsDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, directories[EXEC_DIRECTORY_LOGS].mode), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
|
SD_BUS_PROPERTY("LogsDirectoryAccounting", "b", bus_property_get_bool, offsetof(ExecContext, directories[EXEC_DIRECTORY_LOGS].exec_quota.quota_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
|
SD_BUS_PROPERTY("LogsDirectoryQuota", "(tus)", property_get_exec_quota, offsetof(ExecContext, directories[EXEC_DIRECTORY_LOGS].exec_quota), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("LogsDirectory", "as", property_get_exec_dir, offsetof(ExecContext, directories[EXEC_DIRECTORY_LOGS]), SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("LogsDirectory", "as", property_get_exec_dir, offsetof(ExecContext, directories[EXEC_DIRECTORY_LOGS]), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("ConfigurationDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, directories[EXEC_DIRECTORY_CONFIGURATION].mode), SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("ConfigurationDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, directories[EXEC_DIRECTORY_CONFIGURATION].mode), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("ConfigurationDirectory", "as", property_get_exec_dir, offsetof(ExecContext, directories[EXEC_DIRECTORY_CONFIGURATION]), SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("ConfigurationDirectory", "as", property_get_exec_dir, offsetof(ExecContext, directories[EXEC_DIRECTORY_CONFIGURATION]), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
@ -1309,6 +1333,60 @@ const sd_bus_vtable bus_exec_vtable[] = {
|
|||||||
SD_BUS_VTABLE_END
|
SD_BUS_VTABLE_END
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int property_get_quota_usage(
|
||||||
|
sd_bus *bus,
|
||||||
|
const char *path,
|
||||||
|
const char *interface,
|
||||||
|
const char *property,
|
||||||
|
sd_bus_message *reply,
|
||||||
|
void *userdata,
|
||||||
|
sd_bus_error *error) {
|
||||||
|
|
||||||
|
Unit *u = ASSERT_PTR(userdata);
|
||||||
|
ExecContext *c = ASSERT_PTR(unit_get_exec_context(u));
|
||||||
|
uint64_t current_usage_bytes = UINT64_MAX, limit_bytes = UINT64_MAX;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(bus);
|
||||||
|
assert(reply);
|
||||||
|
|
||||||
|
ExecDirectoryType dt;
|
||||||
|
if (streq(property, "StateDirectoryQuotaUsage"))
|
||||||
|
dt = EXEC_DIRECTORY_STATE;
|
||||||
|
else if (streq(property, "CacheDirectoryQuotaUsage"))
|
||||||
|
dt = EXEC_DIRECTORY_CACHE;
|
||||||
|
else if (streq(property, "LogsDirectoryQuotaUsage"))
|
||||||
|
dt = EXEC_DIRECTORY_LOGS;
|
||||||
|
else
|
||||||
|
assert_not_reached();
|
||||||
|
|
||||||
|
const QuotaLimit *q;
|
||||||
|
q = &c->directories[dt].exec_quota;
|
||||||
|
|
||||||
|
if (q->quota_enforce || q->quota_accounting) {
|
||||||
|
r = unit_get_exec_quota_stats(u, c, dt, ¤t_usage_bytes, &limit_bytes);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!q->quota_enforce)
|
||||||
|
limit_bytes = UINT64_MAX;
|
||||||
|
if (!q->quota_accounting)
|
||||||
|
current_usage_bytes = UINT64_MAX;
|
||||||
|
|
||||||
|
return sd_bus_message_append(reply, "(tt)", current_usage_bytes, limit_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
const sd_bus_vtable bus_unit_exec_vtable[] = {
|
||||||
|
SD_BUS_VTABLE_START(0),
|
||||||
|
|
||||||
|
SD_BUS_PROPERTY("StateDirectoryQuotaUsage", "(tt)", property_get_quota_usage, 0, 0),
|
||||||
|
SD_BUS_PROPERTY("CacheDirectoryQuotaUsage", "(tt)", property_get_quota_usage, 0, 0),
|
||||||
|
SD_BUS_PROPERTY("LogsDirectoryQuotaUsage", "(tt)", property_get_quota_usage, 0, 0),
|
||||||
|
|
||||||
|
SD_BUS_VTABLE_END
|
||||||
|
};
|
||||||
|
|
||||||
static int append_exec_command(sd_bus_message *reply, ExecCommand *c) {
|
static int append_exec_command(sd_bus_message *reply, ExecCommand *c) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -2210,6 +2288,15 @@ int bus_exec_context_set_transient_property(
|
|||||||
if (streq(name, "RuntimeDirectoryMode"))
|
if (streq(name, "RuntimeDirectoryMode"))
|
||||||
return bus_set_transient_mode_t(u, name, &c->directories[EXEC_DIRECTORY_RUNTIME].mode, message, flags, error);
|
return bus_set_transient_mode_t(u, name, &c->directories[EXEC_DIRECTORY_RUNTIME].mode, message, flags, error);
|
||||||
|
|
||||||
|
if (streq(name, "StateDirectoryAccounting"))
|
||||||
|
return bus_set_transient_bool(u, name, &c->directories[EXEC_DIRECTORY_STATE].exec_quota.quota_accounting, message, flags, error);
|
||||||
|
|
||||||
|
if (streq(name, "CacheDirectoryAccounting"))
|
||||||
|
return bus_set_transient_bool(u, name, &c->directories[EXEC_DIRECTORY_CACHE].exec_quota.quota_accounting, message, flags, error);
|
||||||
|
|
||||||
|
if (streq(name, "LogsDirectoryAccounting"))
|
||||||
|
return bus_set_transient_bool(u, name, &c->directories[EXEC_DIRECTORY_LOGS].exec_quota.quota_accounting, message, flags, error);
|
||||||
|
|
||||||
if (streq(name, "StateDirectoryMode"))
|
if (streq(name, "StateDirectoryMode"))
|
||||||
return bus_set_transient_mode_t(u, name, &c->directories[EXEC_DIRECTORY_STATE].mode, message, flags, error);
|
return bus_set_transient_mode_t(u, name, &c->directories[EXEC_DIRECTORY_STATE].mode, message, flags, error);
|
||||||
|
|
||||||
@ -2315,7 +2402,7 @@ int bus_exec_context_set_transient_property(
|
|||||||
|
|
||||||
STRV_FOREACH(p, l)
|
STRV_FOREACH(p, l)
|
||||||
if (!isempty(*p) && !valid_user_group_name(*p, VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX|VALID_USER_WARN))
|
if (!isempty(*p) && !valid_user_group_name(*p, VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX|VALID_USER_WARN))
|
||||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||||
"Invalid supplementary group names");
|
"Invalid supplementary group names");
|
||||||
|
|
||||||
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
|
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
|
||||||
@ -3603,6 +3690,47 @@ int bus_exec_context_set_transient_property(
|
|||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
} else if (STR_IN_SET(name, "StateDirectoryQuota", "CacheDirectoryQuota", "LogsDirectoryQuota")) {
|
||||||
|
uint64_t quota_absolute = UINT64_MAX;
|
||||||
|
uint32_t quota_scale = UINT32_MAX;
|
||||||
|
const char *enforce_flag;
|
||||||
|
int quota_enforce;
|
||||||
|
|
||||||
|
r = sd_bus_message_read(message, "(tus)", "a_absolute, "a_scale, &enforce_flag);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
quota_enforce = parse_boolean(enforce_flag);
|
||||||
|
if (quota_enforce < 0)
|
||||||
|
return quota_enforce;
|
||||||
|
|
||||||
|
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
|
||||||
|
ExecDirectoryType dt;
|
||||||
|
if (streq(name, "StateDirectoryQuota"))
|
||||||
|
dt = EXEC_DIRECTORY_STATE;
|
||||||
|
else if (streq(name, "CacheDirectoryQuota"))
|
||||||
|
dt = EXEC_DIRECTORY_CACHE;
|
||||||
|
else if (streq(name, "LogsDirectoryQuota"))
|
||||||
|
dt = EXEC_DIRECTORY_LOGS;
|
||||||
|
else
|
||||||
|
assert_not_reached();
|
||||||
|
|
||||||
|
if (quota_enforce) {
|
||||||
|
c->directories[dt].exec_quota.quota_absolute = quota_absolute;
|
||||||
|
c->directories[dt].exec_quota.quota_scale = quota_scale;
|
||||||
|
|
||||||
|
if (quota_absolute != UINT64_MAX)
|
||||||
|
unit_write_settingf(u, flags, name, "%s=%" PRIu64, name, quota_absolute);
|
||||||
|
else
|
||||||
|
unit_write_settingf(u, flags, name, "%s=%d%%", name, UINT32_SCALE_TO_PERCENT(quota_scale));
|
||||||
|
} else
|
||||||
|
unit_write_settingf(u, flags, name, "%s=", name);
|
||||||
|
|
||||||
|
c->directories[dt].exec_quota.quota_enforce = quota_enforce;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
|
||||||
} else if (STR_IN_SET(name, "AppArmorProfile", "SmackProcessLabel")) {
|
} else if (STR_IN_SET(name, "AppArmorProfile", "SmackProcessLabel")) {
|
||||||
int ignore;
|
int ignore;
|
||||||
const char *s;
|
const char *s;
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
SD_BUS_PROPERTY(name, "a(sasasttttuii)", bus_property_get_exec_ex_command_list, offset, flags)
|
SD_BUS_PROPERTY(name, "a(sasasttttuii)", bus_property_get_exec_ex_command_list, offset, flags)
|
||||||
|
|
||||||
extern const sd_bus_vtable bus_exec_vtable[];
|
extern const sd_bus_vtable bus_exec_vtable[];
|
||||||
|
extern const sd_bus_vtable bus_unit_exec_vtable[];
|
||||||
|
|
||||||
int bus_property_get_exec_output(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *ret_error);
|
int bus_property_get_exec_output(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *ret_error);
|
||||||
int bus_property_get_exec_command(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *ret_error);
|
int bus_property_get_exec_command(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *ret_error);
|
||||||
|
@ -831,6 +831,12 @@ static int method_kill_unit(sd_bus_message *message, void *userdata, sd_bus_erro
|
|||||||
return method_generic_unit_operation(message, userdata, error, bus_unit_method_kill, 0);
|
return method_generic_unit_operation(message, userdata, error, bus_unit_method_kill, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int method_kill_unit_subgroup(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||||
|
/* We don't bother with GENERIC_UNIT_LOAD nor GENERIC_UNIT_VALIDATE_LOADED here, as it shouldn't
|
||||||
|
* matter whether a unit is loaded for killing any processes possibly in the unit's cgroup. */
|
||||||
|
return method_generic_unit_operation(message, userdata, error, bus_unit_method_kill_subgroup, 0);
|
||||||
|
}
|
||||||
|
|
||||||
static int method_clean_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
static int method_clean_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||||
/* Load the unit if necessary, in order to load it, and insist on the unit being loaded to be
|
/* Load the unit if necessary, in order to load it, and insist on the unit being loaded to be
|
||||||
* cleaned */
|
* cleaned */
|
||||||
@ -989,7 +995,7 @@ static int transient_unit_from_message(
|
|||||||
t = unit_name_to_type(name);
|
t = unit_name_to_type(name);
|
||||||
if (t < 0)
|
if (t < 0)
|
||||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||||
"Invalid unit name or type.");
|
"Invalid unit name or type: %s", name);
|
||||||
|
|
||||||
if (!unit_vtable[t]->can_transient)
|
if (!unit_vtable[t]->can_transient)
|
||||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||||
@ -1542,7 +1548,7 @@ static int method_reload(sd_bus_message *message, void *userdata, sd_bus_error *
|
|||||||
/* Check the rate limit after the authorization succeeds, to avoid denial-of-service issues. */
|
/* Check the rate limit after the authorization succeeds, to avoid denial-of-service issues. */
|
||||||
if (!ratelimit_below(&m->reload_reexec_ratelimit)) {
|
if (!ratelimit_below(&m->reload_reexec_ratelimit)) {
|
||||||
log_warning("Reloading request rejected due to rate limit.");
|
log_warning("Reloading request rejected due to rate limit.");
|
||||||
return sd_bus_error_setf(error,
|
return sd_bus_error_set(error,
|
||||||
SD_BUS_ERROR_LIMITS_EXCEEDED,
|
SD_BUS_ERROR_LIMITS_EXCEEDED,
|
||||||
"Reload() request rejected due to rate limit.");
|
"Reload() request rejected due to rate limit.");
|
||||||
}
|
}
|
||||||
@ -1584,7 +1590,7 @@ static int method_reexecute(sd_bus_message *message, void *userdata, sd_bus_erro
|
|||||||
/* Check the rate limit after the authorization succeeds, to avoid denial-of-service issues. */
|
/* Check the rate limit after the authorization succeeds, to avoid denial-of-service issues. */
|
||||||
if (!ratelimit_below(&m->reload_reexec_ratelimit)) {
|
if (!ratelimit_below(&m->reload_reexec_ratelimit)) {
|
||||||
log_warning("Reexecution request rejected due to rate limit.");
|
log_warning("Reexecution request rejected due to rate limit.");
|
||||||
return sd_bus_error_setf(error,
|
return sd_bus_error_set(error,
|
||||||
SD_BUS_ERROR_LIMITS_EXCEEDED,
|
SD_BUS_ERROR_LIMITS_EXCEEDED,
|
||||||
"Reexecute() request rejected due to rate limit.");
|
"Reexecute() request rejected due to rate limit.");
|
||||||
}
|
}
|
||||||
@ -1883,7 +1889,7 @@ static int method_unset_environment(sd_bus_message *message, void *userdata, sd_
|
|||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (!strv_env_name_or_assignment_is_valid(minus))
|
if (!strv_env_name_or_assignment_is_valid(minus))
|
||||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||||
"Invalid environment variable names or assignments");
|
"Invalid environment variable names or assignments");
|
||||||
|
|
||||||
r = bus_verify_set_environment_async(m, message, error);
|
r = bus_verify_set_environment_async(m, message, error);
|
||||||
@ -1919,10 +1925,10 @@ static int method_unset_and_set_environment(sd_bus_message *message, void *userd
|
|||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (!strv_env_name_or_assignment_is_valid(minus))
|
if (!strv_env_name_or_assignment_is_valid(minus))
|
||||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||||
"Invalid environment variable names or assignments");
|
"Invalid environment variable names or assignments");
|
||||||
if (!strv_env_is_valid(plus))
|
if (!strv_env_is_valid(plus))
|
||||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||||
"Invalid environment assignments");
|
"Invalid environment assignments");
|
||||||
|
|
||||||
r = bus_verify_set_environment_async(m, message, error);
|
r = bus_verify_set_environment_async(m, message, error);
|
||||||
@ -1971,7 +1977,7 @@ static int method_lookup_dynamic_user_by_name(sd_bus_message *message, void *use
|
|||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (!MANAGER_IS_SYSTEM(m))
|
if (!MANAGER_IS_SYSTEM(m))
|
||||||
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED,
|
return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED,
|
||||||
"Dynamic users are only supported in the system instance.");
|
"Dynamic users are only supported in the system instance.");
|
||||||
if (!valid_user_group_name(name, VALID_USER_RELAX))
|
if (!valid_user_group_name(name, VALID_USER_RELAX))
|
||||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||||
@ -2001,7 +2007,7 @@ static int method_lookup_dynamic_user_by_uid(sd_bus_message *message, void *user
|
|||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (!MANAGER_IS_SYSTEM(m))
|
if (!MANAGER_IS_SYSTEM(m))
|
||||||
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED,
|
return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED,
|
||||||
"Dynamic users are only supported in the system instance.");
|
"Dynamic users are only supported in the system instance.");
|
||||||
if (!uid_is_valid(uid))
|
if (!uid_is_valid(uid))
|
||||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||||
@ -2028,7 +2034,7 @@ static int method_get_dynamic_users(sd_bus_message *message, void *userdata, sd_
|
|||||||
assert_cc(sizeof(uid_t) == sizeof(uint32_t));
|
assert_cc(sizeof(uid_t) == sizeof(uint32_t));
|
||||||
|
|
||||||
if (!MANAGER_IS_SYSTEM(m))
|
if (!MANAGER_IS_SYSTEM(m))
|
||||||
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED,
|
return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED,
|
||||||
"Dynamic users are only supported in the system instance.");
|
"Dynamic users are only supported in the system instance.");
|
||||||
|
|
||||||
r = sd_bus_message_new_method_return(message, &reply);
|
r = sd_bus_message_new_method_return(message, &reply);
|
||||||
@ -2046,7 +2052,7 @@ static int method_get_dynamic_users(sd_bus_message *message, void *userdata, sd_
|
|||||||
if (r == -EAGAIN) /* not realized yet? */
|
if (r == -EAGAIN) /* not realized yet? */
|
||||||
continue;
|
continue;
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED,
|
return sd_bus_error_set(error, SD_BUS_ERROR_FAILED,
|
||||||
"Failed to look up a dynamic user.");
|
"Failed to look up a dynamic user.");
|
||||||
|
|
||||||
r = sd_bus_message_append(reply, "(us)", uid, d->name);
|
r = sd_bus_message_append(reply, "(us)", uid, d->name);
|
||||||
@ -2229,7 +2235,7 @@ static int method_get_default_target(sd_bus_message *message, void *userdata, sd
|
|||||||
|
|
||||||
r = unit_file_get_default(m->runtime_scope, NULL, &default_target);
|
r = unit_file_get_default(m->runtime_scope, NULL, &default_target);
|
||||||
if (r == -ERFKILL)
|
if (r == -ERFKILL)
|
||||||
sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED, "Unit file is masked.");
|
return sd_bus_error_set(error, BUS_ERROR_UNIT_MASKED, "Default target unit file is masked.");
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -3025,6 +3031,11 @@ const sd_bus_vtable bus_manager_vtable[] = {
|
|||||||
SD_BUS_NO_RESULT,
|
SD_BUS_NO_RESULT,
|
||||||
method_kill_unit,
|
method_kill_unit,
|
||||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||||
|
SD_BUS_METHOD_WITH_ARGS("KillUnitSubgroup",
|
||||||
|
SD_BUS_ARGS("s", name, "s", whom, "s", subgroup, "i", signal),
|
||||||
|
SD_BUS_NO_RESULT,
|
||||||
|
method_kill_unit_subgroup,
|
||||||
|
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||||
SD_BUS_METHOD_WITH_ARGS("QueueSignalUnit",
|
SD_BUS_METHOD_WITH_ARGS("QueueSignalUnit",
|
||||||
SD_BUS_ARGS("s", name, "s", whom, "i", signal, "i", value),
|
SD_BUS_ARGS("s", name, "s", whom, "i", signal, "i", value),
|
||||||
SD_BUS_NO_RESULT,
|
SD_BUS_NO_RESULT,
|
||||||
|
@ -572,7 +572,60 @@ int bus_unit_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *
|
|||||||
if (r == 0)
|
if (r == 0)
|
||||||
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
|
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
|
||||||
|
|
||||||
r = unit_kill(u, whom, signo, code, value, error);
|
r = unit_kill(u, whom, /* subgroup= */ NULL, signo, code, value, error);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
return sd_bus_reply_method_return(message, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int bus_unit_method_kill_subgroup(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||||
|
Unit *u = ASSERT_PTR(userdata);
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(message);
|
||||||
|
|
||||||
|
r = mac_selinux_unit_access_check(u, message, "stop", error);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
const char *swhom, *subgroup;
|
||||||
|
int32_t signo;
|
||||||
|
r = sd_bus_message_read(message, "ssi", &swhom, &subgroup, &signo);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
KillWhom whom;
|
||||||
|
if (isempty(swhom))
|
||||||
|
whom = KILL_CGROUP;
|
||||||
|
else {
|
||||||
|
whom = kill_whom_from_string(swhom);
|
||||||
|
if (whom < 0)
|
||||||
|
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid whom argument: %s", swhom);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isempty(subgroup))
|
||||||
|
subgroup = NULL;
|
||||||
|
else if (!path_is_normalized(subgroup))
|
||||||
|
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Specified cgroup sub-path is not valid.");
|
||||||
|
else if (!IN_SET(whom, KILL_CGROUP, KILL_CGROUP_FAIL))
|
||||||
|
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Subgroup can only be specified in combination with 'cgroup' or 'cgroup-fail'.");
|
||||||
|
|
||||||
|
if (!SIGNAL_VALID(signo))
|
||||||
|
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Signal number out of range.");
|
||||||
|
|
||||||
|
r = bus_verify_manage_units_async_full(
|
||||||
|
u,
|
||||||
|
"kill-subgroup",
|
||||||
|
N_("Authentication is required to send a UNIX signal to the processes of subgroup of '$(unit)'."),
|
||||||
|
message,
|
||||||
|
error);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
if (r == 0)
|
||||||
|
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
|
||||||
|
|
||||||
|
r = unit_kill(u, whom, subgroup, signo, SI_USER, /* value= */ 0, error);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -986,6 +1039,11 @@ const sd_bus_vtable bus_unit_vtable[] = {
|
|||||||
SD_BUS_NO_RESULT,
|
SD_BUS_NO_RESULT,
|
||||||
bus_unit_method_kill,
|
bus_unit_method_kill,
|
||||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||||
|
SD_BUS_METHOD_WITH_ARGS("KillSubgroup",
|
||||||
|
SD_BUS_ARGS("s", subgroup, "i", signal),
|
||||||
|
SD_BUS_NO_RESULT,
|
||||||
|
bus_unit_method_kill_subgroup,
|
||||||
|
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||||
SD_BUS_METHOD_WITH_ARGS("QueueSignal",
|
SD_BUS_METHOD_WITH_ARGS("QueueSignal",
|
||||||
SD_BUS_ARGS("s", whom, "i", signal, "i", value),
|
SD_BUS_ARGS("s", whom, "i", signal, "i", value),
|
||||||
SD_BUS_NO_RESULT,
|
SD_BUS_NO_RESULT,
|
||||||
@ -1619,7 +1677,7 @@ int bus_unit_method_remove_subgroup(sd_bus_message *message, void *userdata, sd_
|
|||||||
|
|
||||||
/* Allow this only if the client is privileged, is us, or is the user of the unit itself. */
|
/* Allow this only if the client is privileged, is us, or is the user of the unit itself. */
|
||||||
if (sender_uid != 0 && sender_uid != getuid() && sender_uid != u->ref_uid)
|
if (sender_uid != 0 && sender_uid != getuid() && sender_uid != u->ref_uid)
|
||||||
return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Client is not permitted to alter cgroup.");
|
return sd_bus_error_set(error, SD_BUS_ERROR_ACCESS_DENIED, "Client is not permitted to alter cgroup.");
|
||||||
|
|
||||||
r = unit_remove_subcgroup(u, path);
|
r = unit_remove_subcgroup(u, path);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
@ -16,6 +16,7 @@ void bus_unit_send_removed_signal(Unit *u);
|
|||||||
int bus_unit_method_start_generic(sd_bus_message *message, Unit *u, JobType job_type, bool reload_if_possible, sd_bus_error *error);
|
int bus_unit_method_start_generic(sd_bus_message *message, Unit *u, JobType job_type, bool reload_if_possible, sd_bus_error *error);
|
||||||
int bus_unit_method_enqueue_job(sd_bus_message *message, void *userdata, sd_bus_error *error);
|
int bus_unit_method_enqueue_job(sd_bus_message *message, void *userdata, sd_bus_error *error);
|
||||||
int bus_unit_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error);
|
int bus_unit_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error);
|
||||||
|
int bus_unit_method_kill_subgroup(sd_bus_message *message, void *userdata, sd_bus_error *error);
|
||||||
int bus_unit_method_reset_failed(sd_bus_message *message, void *userdata, sd_bus_error *error);
|
int bus_unit_method_reset_failed(sd_bus_message *message, void *userdata, sd_bus_error *error);
|
||||||
|
|
||||||
int bus_unit_set_properties(Unit *u, sd_bus_message *message, UnitWriteFlags flags, bool commit, sd_bus_error *error);
|
int bus_unit_set_properties(Unit *u, sd_bus_message *message, UnitWriteFlags flags, bool commit, sd_bus_error *error);
|
||||||
|
@ -338,9 +338,8 @@ static int bus_cgroup_context_find(sd_bus *bus, const char *path, const char *in
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bus_exec_context_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
|
static int bus_unit_exec_context_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
|
||||||
Manager *m = ASSERT_PTR(userdata);
|
Manager *m = ASSERT_PTR(userdata);
|
||||||
ExecContext *c;
|
|
||||||
Unit *u;
|
Unit *u;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -356,6 +355,27 @@ static int bus_exec_context_find(sd_bus *bus, const char *path, const char *inte
|
|||||||
if (!streq_ptr(interface, unit_dbus_interface_from_type(u->type)))
|
if (!streq_ptr(interface, unit_dbus_interface_from_type(u->type)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (!UNIT_HAS_EXEC_CONTEXT(u))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
*found = u;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int bus_exec_context_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
|
||||||
|
ExecContext *c;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(bus);
|
||||||
|
assert(path);
|
||||||
|
assert(interface);
|
||||||
|
assert(found);
|
||||||
|
|
||||||
|
Unit *u;
|
||||||
|
r = bus_unit_exec_context_find(bus, path, interface, userdata, (void**) &u, error);
|
||||||
|
if (r <= 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
c = unit_get_exec_context(u);
|
c = unit_get_exec_context(u);
|
||||||
if (!c)
|
if (!c)
|
||||||
return 0;
|
return 0;
|
||||||
@ -443,6 +463,7 @@ static const BusObjectImplementation bus_mount_object = {
|
|||||||
{ bus_unit_cgroup_vtable, bus_unit_cgroup_find },
|
{ bus_unit_cgroup_vtable, bus_unit_cgroup_find },
|
||||||
{ bus_cgroup_vtable, bus_cgroup_context_find },
|
{ bus_cgroup_vtable, bus_cgroup_context_find },
|
||||||
{ bus_exec_vtable, bus_exec_context_find },
|
{ bus_exec_vtable, bus_exec_context_find },
|
||||||
|
{ bus_unit_exec_vtable, bus_unit_exec_context_find },
|
||||||
{ bus_kill_vtable, bus_kill_context_find }),
|
{ bus_kill_vtable, bus_kill_context_find }),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -471,6 +492,7 @@ static const BusObjectImplementation bus_service_object = {
|
|||||||
{ bus_unit_cgroup_vtable, bus_unit_cgroup_find },
|
{ bus_unit_cgroup_vtable, bus_unit_cgroup_find },
|
||||||
{ bus_cgroup_vtable, bus_cgroup_context_find },
|
{ bus_cgroup_vtable, bus_cgroup_context_find },
|
||||||
{ bus_exec_vtable, bus_exec_context_find },
|
{ bus_exec_vtable, bus_exec_context_find },
|
||||||
|
{ bus_unit_exec_vtable, bus_unit_exec_context_find },
|
||||||
{ bus_kill_vtable, bus_kill_context_find }),
|
{ bus_kill_vtable, bus_kill_context_find }),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -491,6 +513,7 @@ static const BusObjectImplementation bus_socket_object = {
|
|||||||
{ bus_unit_cgroup_vtable, bus_unit_cgroup_find },
|
{ bus_unit_cgroup_vtable, bus_unit_cgroup_find },
|
||||||
{ bus_cgroup_vtable, bus_cgroup_context_find },
|
{ bus_cgroup_vtable, bus_cgroup_context_find },
|
||||||
{ bus_exec_vtable, bus_exec_context_find },
|
{ bus_exec_vtable, bus_exec_context_find },
|
||||||
|
{ bus_unit_exec_vtable, bus_unit_exec_context_find },
|
||||||
{ bus_kill_vtable, bus_kill_context_find }),
|
{ bus_kill_vtable, bus_kill_context_find }),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -502,6 +525,7 @@ static const BusObjectImplementation bus_swap_object = {
|
|||||||
{ bus_unit_cgroup_vtable, bus_unit_cgroup_find },
|
{ bus_unit_cgroup_vtable, bus_unit_cgroup_find },
|
||||||
{ bus_cgroup_vtable, bus_cgroup_context_find },
|
{ bus_cgroup_vtable, bus_cgroup_context_find },
|
||||||
{ bus_exec_vtable, bus_exec_context_find },
|
{ bus_exec_vtable, bus_exec_context_find },
|
||||||
|
{ bus_unit_exec_vtable, bus_unit_exec_context_find },
|
||||||
{ bus_kill_vtable, bus_kill_context_find }),
|
{ bus_kill_vtable, bus_kill_context_find }),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1160,6 +1184,7 @@ void dump_bus_properties(FILE *f) {
|
|||||||
vtable_dump_bus_properties(f, bus_cgroup_vtable);
|
vtable_dump_bus_properties(f, bus_cgroup_vtable);
|
||||||
vtable_dump_bus_properties(f, bus_device_vtable);
|
vtable_dump_bus_properties(f, bus_device_vtable);
|
||||||
vtable_dump_bus_properties(f, bus_exec_vtable);
|
vtable_dump_bus_properties(f, bus_exec_vtable);
|
||||||
|
vtable_dump_bus_properties(f, bus_unit_exec_vtable);
|
||||||
vtable_dump_bus_properties(f, bus_job_vtable);
|
vtable_dump_bus_properties(f, bus_job_vtable);
|
||||||
vtable_dump_bus_properties(f, bus_kill_vtable);
|
vtable_dump_bus_properties(f, bus_kill_vtable);
|
||||||
vtable_dump_bus_properties(f, bus_manager_vtable);
|
vtable_dump_bus_properties(f, bus_manager_vtable);
|
||||||
|
@ -445,8 +445,7 @@ static bool device_nodes_restricted(
|
|||||||
if (c->private_devices)
|
if (c->private_devices)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (cgroup_context->device_policy != CGROUP_DEVICE_POLICY_AUTO ||
|
if (cgroup_context_has_device_policy(cgroup_context))
|
||||||
cgroup_context->device_allow)
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <sys/mount.h>
|
#include <sys/mount.h>
|
||||||
#include <sys/prctl.h>
|
#include <sys/prctl.h>
|
||||||
|
#include <sys/statvfs.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#if HAVE_PAM
|
#if HAVE_PAM
|
||||||
@ -30,6 +31,7 @@
|
|||||||
#include "cgroup-setup.h"
|
#include "cgroup-setup.h"
|
||||||
#include "cgroup.h"
|
#include "cgroup.h"
|
||||||
#include "chase.h"
|
#include "chase.h"
|
||||||
|
#include "chattr-util.h"
|
||||||
#include "chown-recursive.h"
|
#include "chown-recursive.h"
|
||||||
#include "constants.h"
|
#include "constants.h"
|
||||||
#include "copy.h"
|
#include "copy.h"
|
||||||
@ -60,15 +62,19 @@
|
|||||||
#include "open-file.h"
|
#include "open-file.h"
|
||||||
#include "osc-context.h"
|
#include "osc-context.h"
|
||||||
#include "path-util.h"
|
#include "path-util.h"
|
||||||
|
#include "percent-util.h"
|
||||||
#include "pidref.h"
|
#include "pidref.h"
|
||||||
#include "proc-cmdline.h"
|
#include "proc-cmdline.h"
|
||||||
#include "process-util.h"
|
#include "process-util.h"
|
||||||
#include "psi-util.h"
|
#include "psi-util.h"
|
||||||
|
#include "quota-util.h"
|
||||||
|
#include "random-util.h"
|
||||||
#include "rlimit-util.h"
|
#include "rlimit-util.h"
|
||||||
#include "seccomp-util.h"
|
#include "seccomp-util.h"
|
||||||
#include "selinux-util.h"
|
#include "selinux-util.h"
|
||||||
#include "set.h"
|
#include "set.h"
|
||||||
#include "signal-util.h"
|
#include "signal-util.h"
|
||||||
|
#include "siphash24.h"
|
||||||
#include "smack-util.h"
|
#include "smack-util.h"
|
||||||
#include "socket-util.h"
|
#include "socket-util.h"
|
||||||
#include "stat-util.h"
|
#include "stat-util.h"
|
||||||
@ -84,6 +90,11 @@
|
|||||||
|
|
||||||
#define SNDBUF_SIZE (8*1024*1024)
|
#define SNDBUF_SIZE (8*1024*1024)
|
||||||
|
|
||||||
|
/* Project id range for disk quotas */
|
||||||
|
#define PROJ_ID_MIN UINT32_C(2147483648)
|
||||||
|
#define PROJ_ID_MAX UINT32_C(4294967294)
|
||||||
|
#define PROJ_ID_CLAMP_INTO_QUOTA_RANGE(id) ((uint32_t) ((id) % (PROJ_ID_MAX - PROJ_ID_MIN + 1)) + PROJ_ID_MIN)
|
||||||
|
|
||||||
static int flag_fds(
|
static int flag_fds(
|
||||||
const int fds[],
|
const int fds[],
|
||||||
size_t n_socket_fds,
|
size_t n_socket_fds,
|
||||||
@ -2575,6 +2586,217 @@ static int create_many_symlinks(const char *root, const char *source, char **sym
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int set_exec_storage_quota(int fd, uint32_t proj_id, const QuotaLimit *ql) {
|
||||||
|
int r;
|
||||||
|
uint64_t block_limit = 0, inode_limit = 0;
|
||||||
|
|
||||||
|
assert(fd >= 0);
|
||||||
|
assert(ql);
|
||||||
|
|
||||||
|
if (ql->quota_absolute == 0 || ql->quota_scale == 0)
|
||||||
|
/* Limit of 0 means no usage is allowed. For quotactl, use 1 as the limit, since 0 means that
|
||||||
|
* hard limits are disabled */
|
||||||
|
block_limit = inode_limit = 1;
|
||||||
|
else if (ql->quota_absolute == UINT64_MAX) {
|
||||||
|
_cleanup_close_ int fd_parent = -EBADF;
|
||||||
|
|
||||||
|
/* Use target_dir's parent when setting quotas. If a FD for target_dir has been previously
|
||||||
|
* used for quotactl_fd(SET) and is passed again for fstatvfs(), the total number of blocks is not
|
||||||
|
* reported accurately (instead, the block limit is reported as total blocks). Thus, use the FD
|
||||||
|
* associated with the parent, so that total blocks is accurate */
|
||||||
|
fd_parent = openat(fd, "..", O_PATH|O_CLOEXEC|O_DIRECTORY);
|
||||||
|
if (fd_parent < 0)
|
||||||
|
return -errno;
|
||||||
|
|
||||||
|
uint32_t xattr_flags = 0;
|
||||||
|
r = read_fs_xattr_fd(fd_parent, &xattr_flags, /* ret_projid = */ NULL);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
/* Refuse if parent has FS_XFLAG_PROJINHERIT since this will mean the total number of blocks will not
|
||||||
|
* be reported accurately */
|
||||||
|
if (FLAGS_SET(xattr_flags, FS_XFLAG_PROJINHERIT))
|
||||||
|
return -ENOMEDIUM;
|
||||||
|
|
||||||
|
struct statvfs disk_st;
|
||||||
|
if (fstatvfs(fd_parent, &disk_st) < 0)
|
||||||
|
return -errno;
|
||||||
|
|
||||||
|
block_limit = (uint64_t) DIV_ROUND_UP((uint64_t)((double) (disk_st.f_frsize * disk_st.f_blocks) / UINT32_MAX * ql->quota_scale), QIF_DQBLKSIZE);
|
||||||
|
inode_limit = (uint64_t) ((double) disk_st.f_files / UINT32_MAX * ql->quota_scale);
|
||||||
|
} else
|
||||||
|
block_limit = (uint64_t) DIV_ROUND_UP(ql->quota_absolute, QIF_DQBLKSIZE);
|
||||||
|
|
||||||
|
struct dqblk req = {
|
||||||
|
.dqb_bhardlimit = block_limit,
|
||||||
|
.dqb_ihardlimit = inode_limit,
|
||||||
|
.dqb_valid = QIF_LIMITS,
|
||||||
|
};
|
||||||
|
|
||||||
|
r = quotactl_fd_with_fallback(fd, QCMD_FIXED(Q_SETQUOTA, PRJQUOTA), proj_id, &req);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
log_debug("Storage quotas set for project id %" PRIu32 ". Block limit = %" PRIu64 ", inode limit = %" PRIu64, proj_id, block_limit, inode_limit);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int unset_exec_storage_quota(int fd, uint32_t proj_id, bool quota_accounting) {
|
||||||
|
int r, quota_supported;
|
||||||
|
struct dqblk req;
|
||||||
|
|
||||||
|
assert(fd >= 0);
|
||||||
|
|
||||||
|
quota_supported = quota_query_proj_id(fd, proj_id, &req);
|
||||||
|
if (quota_supported < 0)
|
||||||
|
return log_debug_errno(quota_supported, "Failed to query disk quota for project ID %" PRIu32 ": %m", proj_id);
|
||||||
|
|
||||||
|
/* Do not enforce quotas anymore */
|
||||||
|
if (quota_supported && FLAGS_SET(req.dqb_valid, QIF_BLIMITS) && (req.dqb_bhardlimit > 0 || req.dqb_ihardlimit > 0)) {
|
||||||
|
req.dqb_bhardlimit = 0, req.dqb_ihardlimit = 0;
|
||||||
|
|
||||||
|
r = quotactl_fd_with_fallback(fd, QCMD_FIXED(Q_SETQUOTA, PRJQUOTA), proj_id, &req);
|
||||||
|
if (r < 0)
|
||||||
|
return log_debug_errno(r, "Failed to disable project quotas for project ID %" PRIu32 ": %m", proj_id);
|
||||||
|
|
||||||
|
log_debug("Storage quotas for project ID %" PRIu32 " were disabled", proj_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Release project ID if no accounting needed */
|
||||||
|
if (!quota_accounting) {
|
||||||
|
r = set_proj_id_recursive(fd, 0);
|
||||||
|
if (r < 0)
|
||||||
|
log_warning_errno(r, "Failed to release project ID %" PRIu32 ", ignoring: %m", proj_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int apply_exec_quotas(
|
||||||
|
const char *target_dir,
|
||||||
|
const char *cgroup_path,
|
||||||
|
ExecDirectoryType type,
|
||||||
|
const QuotaLimit *ql,
|
||||||
|
uint32_t *exec_dt_proj_id, /* in/out */
|
||||||
|
bool *already_enforced) { /* in/out */
|
||||||
|
|
||||||
|
_cleanup_close_ int fd = -EBADF;
|
||||||
|
int r, quota_supported = 0;
|
||||||
|
|
||||||
|
assert(target_dir);
|
||||||
|
assert(cgroup_path);
|
||||||
|
assert(ql);
|
||||||
|
assert(exec_dt_proj_id);
|
||||||
|
assert(already_enforced);
|
||||||
|
|
||||||
|
/* Do not apply to the Runtime directory since tmpfs does not support project IDs yet */
|
||||||
|
if (!IN_SET(type, EXEC_DIRECTORY_STATE, EXEC_DIRECTORY_CACHE, EXEC_DIRECTORY_LOGS))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fd = open(target_dir, O_PATH|O_CLOEXEC|O_DIRECTORY);
|
||||||
|
if (fd < 0)
|
||||||
|
return log_debug_errno(errno, "Failed to open %s: %m", target_dir);
|
||||||
|
|
||||||
|
/* Get the project ID of the current directory */
|
||||||
|
uint32_t proj_id;
|
||||||
|
r = read_fs_xattr_fd(fd, /* ret_xflags = */ NULL, &proj_id);
|
||||||
|
if (ERRNO_IS_NEG_IOCTL_NOT_SUPPORTED(r)) {
|
||||||
|
log_debug_errno(r, "Not applying storage quotas. FS_IOC_FSGETXATTR not supported for %s: %m", target_dir);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (r < 0)
|
||||||
|
return log_debug_errno(r, "Failed to retrieve project ID for %s: %m", target_dir);
|
||||||
|
|
||||||
|
/* If the first directory of this ExecType already has a project ID, adopt it as the project ID for all dirs of this ExecType */
|
||||||
|
bool proj_id_exists = PROJ_ID_MIN <= proj_id && proj_id <= PROJ_ID_MAX;
|
||||||
|
if (proj_id_exists && *exec_dt_proj_id == 0)
|
||||||
|
*exec_dt_proj_id = proj_id;
|
||||||
|
|
||||||
|
/* Check if enforcement should be disabled. Do not release project ID if accounting is enabled */
|
||||||
|
if (!ql->quota_enforce) {
|
||||||
|
if (proj_id_exists) {
|
||||||
|
r = unset_exec_storage_quota(fd, proj_id, ql->quota_accounting);
|
||||||
|
if (r < 0)
|
||||||
|
return log_debug_errno(r, "Failed to unset project quotas for %s: %m", target_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ql->quota_accounting)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*exec_dt_proj_id > 0 && *exec_dt_proj_id != proj_id) {
|
||||||
|
/* Set the existing project ID only if the current directory's ID does not exist or does not match */
|
||||||
|
proj_id = *exec_dt_proj_id;
|
||||||
|
r = quota_proj_id_set_recursive(fd, proj_id, false);
|
||||||
|
if (r < 0)
|
||||||
|
return log_debug_errno(r, "Failed to set project ID for %s: %m", target_dir);
|
||||||
|
} else if (*exec_dt_proj_id == 0) {
|
||||||
|
/* Only generate a new project ID if it's the first directory of this ExecType to be processed and does not have an existing ID */
|
||||||
|
static const sd_id128_t k = SD_ID128_ARRAY(e1,4a,79,9b,64,40,41,4a,a8,46,c2,f3,f9,19,4f,01);
|
||||||
|
_cleanup_free_ char *proj_id_plain = NULL;
|
||||||
|
|
||||||
|
/* Generate candidate project id */
|
||||||
|
proj_id_plain = strjoin(cgroup_path, "|", exec_directory_type_to_string(type));
|
||||||
|
if (!proj_id_plain)
|
||||||
|
return log_oom_debug();
|
||||||
|
|
||||||
|
struct siphash state;
|
||||||
|
siphash24_init(&state, k.bytes);
|
||||||
|
siphash24_compress_string(proj_id_plain, &state);
|
||||||
|
proj_id = PROJ_ID_CLAMP_INTO_QUOTA_RANGE(siphash24_finalize(&state));
|
||||||
|
|
||||||
|
#define MAX_PROJ_ID_RETRIES 10
|
||||||
|
for (unsigned attempt = 0;; attempt++) {
|
||||||
|
if (attempt >= MAX_PROJ_ID_RETRIES)
|
||||||
|
return log_debug_errno(SYNTHETIC_ERRNO(EBUSY), "Failed to generate unique project ID for %s: %m", target_dir);
|
||||||
|
|
||||||
|
/* Check if project quotas are supported */
|
||||||
|
struct dqblk req;
|
||||||
|
quota_supported = quota_query_proj_id(fd, proj_id, &req);
|
||||||
|
if (quota_supported < 0)
|
||||||
|
return log_debug_errno(quota_supported, "Failed to query disk quota for project ID %" PRIu32 ": %m", proj_id);
|
||||||
|
if (!quota_supported) {
|
||||||
|
log_debug("Not applying storage quotas. Project quotas are not supported for %s", target_dir);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!quota_dqblk_is_populated(&req)) {
|
||||||
|
int proj_id_was_set = quota_proj_id_set_recursive(fd, proj_id, true);
|
||||||
|
if (proj_id_was_set < 0)
|
||||||
|
return log_debug_errno(proj_id_was_set, "Failed to set project ID for %s: %m", target_dir);
|
||||||
|
if (proj_id_was_set) {
|
||||||
|
*exec_dt_proj_id = proj_id;
|
||||||
|
log_debug("Project ID %u generated for %s", proj_id, target_dir);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
proj_id = (uint32_t) (random_u64_range(PROJ_ID_MAX - PROJ_ID_MIN + 1) + PROJ_ID_MIN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ql->quota_enforce && !*already_enforced) {
|
||||||
|
if (!quota_supported) {
|
||||||
|
struct dqblk req;
|
||||||
|
quota_supported = quota_query_proj_id(fd, proj_id, &req);
|
||||||
|
if (quota_supported < 0)
|
||||||
|
return log_debug_errno(quota_supported, "Failed to query disk quota for project ID %" PRIu32 ": %m", proj_id);
|
||||||
|
if (!quota_supported) {
|
||||||
|
log_debug("Not applying storage quotas. Project quotas are not supported for %s", target_dir);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
r = set_exec_storage_quota(fd, proj_id, ql);
|
||||||
|
if (r < 0)
|
||||||
|
return log_debug_errno(r, "Failed to set storage quotas for %s: %m", target_dir);
|
||||||
|
|
||||||
|
*already_enforced = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
static int setup_exec_directory(
|
static int setup_exec_directory(
|
||||||
const ExecContext *context,
|
const ExecContext *context,
|
||||||
const ExecParameters *params,
|
const ExecParameters *params,
|
||||||
@ -2608,6 +2830,9 @@ static int setup_exec_directory(
|
|||||||
gid = 0;
|
gid = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t exec_dt_proj_id = 0;
|
||||||
|
bool quota_already_enforced = false;
|
||||||
|
|
||||||
FOREACH_ARRAY(i, context->directories[type].items, context->directories[type].n_items) {
|
FOREACH_ARRAY(i, context->directories[type].items, context->directories[type].n_items) {
|
||||||
_cleanup_free_ char *p = NULL, *pp = NULL;
|
_cleanup_free_ char *p = NULL, *pp = NULL;
|
||||||
|
|
||||||
@ -2898,6 +3123,11 @@ static int setup_exec_directory(
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Apply storage quotas and accounting */
|
||||||
|
r = apply_exec_quotas(target_dir, params->cgroup_path, type, &context->directories[type].exec_quota, &exec_dt_proj_id, "a_already_enforced);
|
||||||
|
if (r < 0)
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we are not going to run in a namespace, set up the symlinks - otherwise
|
/* If we are not going to run in a namespace, set up the symlinks - otherwise
|
||||||
|
@ -1848,6 +1848,28 @@ static int exec_context_serialize(const ExecContext *c, FILE *f) {
|
|||||||
r = serialize_item(f, key, value);
|
r = serialize_item(f, key, value);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
if (c->directories[dt].exec_quota.quota_enforce) {
|
||||||
|
_cleanup_free_ char *key_quota = NULL;
|
||||||
|
key_quota = strjoin("exec-context-quota-directories-", exec_directory_type_to_string(dt));
|
||||||
|
if (!key_quota)
|
||||||
|
return log_oom_debug();
|
||||||
|
|
||||||
|
r = serialize_item_format(f, key_quota, "%" PRIu64 " %" PRIu32, c->directories[dt].exec_quota.quota_absolute,
|
||||||
|
c->directories[dt].exec_quota.quota_scale);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
} else if (c->directories[dt].exec_quota.quota_accounting) {
|
||||||
|
_cleanup_free_ char *key_quota = NULL;
|
||||||
|
key_quota = strjoin("exec-context-quota-accounting-directories-", exec_directory_type_to_string(dt));
|
||||||
|
if (!key_quota)
|
||||||
|
return log_oom_debug();
|
||||||
|
|
||||||
|
r = serialize_bool(f, key_quota, c->directories[dt].exec_quota.quota_accounting);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
r = serialize_usec(f, "exec-context-timeout-clean-usec", c->timeout_clean_usec);
|
r = serialize_usec(f, "exec-context-timeout-clean-usec", c->timeout_clean_usec);
|
||||||
@ -2735,7 +2757,7 @@ static int exec_context_deserialize(ExecContext *c, FILE *f) {
|
|||||||
|
|
||||||
dt = exec_directory_type_from_string(type);
|
dt = exec_directory_type_from_string(type);
|
||||||
if (dt < 0)
|
if (dt < 0)
|
||||||
return -EINVAL;
|
return dt;
|
||||||
|
|
||||||
r = parse_mode(mode, &c->directories[dt].mode);
|
r = parse_mode(mode, &c->directories[dt].mode);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -2793,6 +2815,48 @@ static int exec_context_deserialize(ExecContext *c, FILE *f) {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if ((val = startswith(l, "exec-context-quota-accounting-directories-"))) {
|
||||||
|
_cleanup_free_ char *type = NULL, *quota_accounting = NULL;
|
||||||
|
ExecDirectoryType dt;
|
||||||
|
|
||||||
|
r = split_pair(val, "=", &type, "a_accounting);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
dt = exec_directory_type_from_string(type);
|
||||||
|
if (dt < 0)
|
||||||
|
return dt;
|
||||||
|
|
||||||
|
r = parse_boolean(quota_accounting);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
c->directories[dt].exec_quota.quota_accounting = r;
|
||||||
|
} else if ((val = startswith(l, "exec-context-quota-directories-"))) {
|
||||||
|
_cleanup_free_ char *type = NULL, *quota_info = NULL, *quota_absolute = NULL, *quota_scale = NULL;
|
||||||
|
ExecDirectoryType dt;
|
||||||
|
|
||||||
|
r = split_pair(val, "=", &type, "a_info);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = split_pair(quota_info, " ", "a_absolute, "a_scale);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
dt = exec_directory_type_from_string(type);
|
||||||
|
if (dt < 0)
|
||||||
|
return dt;
|
||||||
|
|
||||||
|
r = safe_atou64(quota_absolute, &c->directories[dt].exec_quota.quota_absolute);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = safe_atou32(quota_scale, &c->directories[dt].exec_quota.quota_scale);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
c->directories[dt].exec_quota.quota_enforce = true;
|
||||||
} else if ((val = startswith(l, "exec-context-timeout-clean-usec="))) {
|
} else if ((val = startswith(l, "exec-context-timeout-clean-usec="))) {
|
||||||
r = deserialize_usec(val, &c->timeout_clean_usec);
|
r = deserialize_usec(val, &c->timeout_clean_usec);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
@ -3000,17 +3000,6 @@ static const char* const exec_preserve_mode_table[_EXEC_PRESERVE_MODE_MAX] = {
|
|||||||
|
|
||||||
DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(exec_preserve_mode, ExecPreserveMode, EXEC_PRESERVE_YES);
|
DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(exec_preserve_mode, ExecPreserveMode, EXEC_PRESERVE_YES);
|
||||||
|
|
||||||
/* This table maps ExecDirectoryType to the setting it is configured with in the unit */
|
|
||||||
static const char* const exec_directory_type_table[_EXEC_DIRECTORY_TYPE_MAX] = {
|
|
||||||
[EXEC_DIRECTORY_RUNTIME] = "RuntimeDirectory",
|
|
||||||
[EXEC_DIRECTORY_STATE] = "StateDirectory",
|
|
||||||
[EXEC_DIRECTORY_CACHE] = "CacheDirectory",
|
|
||||||
[EXEC_DIRECTORY_LOGS] = "LogsDirectory",
|
|
||||||
[EXEC_DIRECTORY_CONFIGURATION] = "ConfigurationDirectory",
|
|
||||||
};
|
|
||||||
|
|
||||||
DEFINE_STRING_TABLE_LOOKUP(exec_directory_type, ExecDirectoryType);
|
|
||||||
|
|
||||||
/* This table maps ExecDirectoryType to the symlink setting it is configured with in the unit */
|
/* This table maps ExecDirectoryType to the symlink setting it is configured with in the unit */
|
||||||
static const char* const exec_directory_type_symlink_table[_EXEC_DIRECTORY_TYPE_MAX] = {
|
static const char* const exec_directory_type_symlink_table[_EXEC_DIRECTORY_TYPE_MAX] = {
|
||||||
[EXEC_DIRECTORY_RUNTIME] = "RuntimeDirectorySymlink",
|
[EXEC_DIRECTORY_RUNTIME] = "RuntimeDirectorySymlink",
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "cgroup-util.h"
|
#include "cgroup-util.h"
|
||||||
#include "core-forward.h"
|
#include "core-forward.h"
|
||||||
#include "cpu-set-util.h"
|
#include "cpu-set-util.h"
|
||||||
|
#include "exec-directory-util.h"
|
||||||
#include "exec-util.h"
|
#include "exec-util.h"
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
#include "log-context.h"
|
#include "log-context.h"
|
||||||
@ -126,22 +127,19 @@ typedef struct ExecRuntime {
|
|||||||
int ephemeral_storage_socket[2];
|
int ephemeral_storage_socket[2];
|
||||||
} ExecRuntime;
|
} ExecRuntime;
|
||||||
|
|
||||||
typedef enum ExecDirectoryType {
|
|
||||||
EXEC_DIRECTORY_RUNTIME,
|
|
||||||
EXEC_DIRECTORY_STATE,
|
|
||||||
EXEC_DIRECTORY_CACHE,
|
|
||||||
EXEC_DIRECTORY_LOGS,
|
|
||||||
EXEC_DIRECTORY_CONFIGURATION,
|
|
||||||
_EXEC_DIRECTORY_TYPE_MAX,
|
|
||||||
_EXEC_DIRECTORY_TYPE_INVALID = -EINVAL,
|
|
||||||
} ExecDirectoryType;
|
|
||||||
|
|
||||||
static inline bool EXEC_DIRECTORY_TYPE_SHALL_CHOWN(ExecDirectoryType t) {
|
static inline bool EXEC_DIRECTORY_TYPE_SHALL_CHOWN(ExecDirectoryType t) {
|
||||||
/* Returns true for the ExecDirectoryTypes that we shall chown()ing for the user to. We do this for
|
/* Returns true for the ExecDirectoryTypes that we shall chown()ing for the user to. We do this for
|
||||||
* all of them, except for configuration */
|
* all of them, except for configuration */
|
||||||
return t >= 0 && t < _EXEC_DIRECTORY_TYPE_MAX && t != EXEC_DIRECTORY_CONFIGURATION;
|
return t >= 0 && t < _EXEC_DIRECTORY_TYPE_MAX && t != EXEC_DIRECTORY_CONFIGURATION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct QuotaLimit {
|
||||||
|
uint64_t quota_absolute; /* absolute quota in bytes; if UINT64_MAX relative quota configured, see below */
|
||||||
|
uint32_t quota_scale; /* relative quota to backend size, scaled to 0…UINT32_MAX */
|
||||||
|
bool quota_enforce;
|
||||||
|
bool quota_accounting;
|
||||||
|
} QuotaLimit;
|
||||||
|
|
||||||
typedef struct ExecDirectoryItem {
|
typedef struct ExecDirectoryItem {
|
||||||
char *path;
|
char *path;
|
||||||
char **symlinks;
|
char **symlinks;
|
||||||
@ -153,6 +151,7 @@ typedef struct ExecDirectory {
|
|||||||
mode_t mode;
|
mode_t mode;
|
||||||
size_t n_items;
|
size_t n_items;
|
||||||
ExecDirectoryItem *items;
|
ExecDirectoryItem *items;
|
||||||
|
QuotaLimit exec_quota;
|
||||||
} ExecDirectory;
|
} ExecDirectory;
|
||||||
|
|
||||||
typedef enum ExecCleanMask {
|
typedef enum ExecCleanMask {
|
||||||
@ -581,9 +580,6 @@ ExecPreserveMode exec_preserve_mode_from_string(const char *s) _pure_;
|
|||||||
const char* exec_keyring_mode_to_string(ExecKeyringMode i) _const_;
|
const char* exec_keyring_mode_to_string(ExecKeyringMode i) _const_;
|
||||||
ExecKeyringMode exec_keyring_mode_from_string(const char *s) _pure_;
|
ExecKeyringMode exec_keyring_mode_from_string(const char *s) _pure_;
|
||||||
|
|
||||||
const char* exec_directory_type_to_string(ExecDirectoryType i) _const_;
|
|
||||||
ExecDirectoryType exec_directory_type_from_string(const char *s) _pure_;
|
|
||||||
|
|
||||||
const char* exec_directory_type_symlink_to_string(ExecDirectoryType i) _const_;
|
const char* exec_directory_type_symlink_to_string(ExecDirectoryType i) _const_;
|
||||||
ExecDirectoryType exec_directory_type_symlink_from_string(const char *s) _pure_;
|
ExecDirectoryType exec_directory_type_symlink_from_string(const char *s) _pure_;
|
||||||
|
|
||||||
|
@ -54,6 +54,8 @@ static const char* const kill_whom_table[_KILL_WHOM_MAX] = {
|
|||||||
[KILL_MAIN_FAIL] = "main-fail",
|
[KILL_MAIN_FAIL] = "main-fail",
|
||||||
[KILL_CONTROL_FAIL] = "control-fail",
|
[KILL_CONTROL_FAIL] = "control-fail",
|
||||||
[KILL_ALL_FAIL] = "all-fail",
|
[KILL_ALL_FAIL] = "all-fail",
|
||||||
|
[KILL_CGROUP] = "cgroup",
|
||||||
|
[KILL_CGROUP_FAIL] = "cgroup-fail",
|
||||||
};
|
};
|
||||||
|
|
||||||
DEFINE_STRING_TABLE_LOOKUP(kill_whom, KillWhom);
|
DEFINE_STRING_TABLE_LOOKUP(kill_whom, KillWhom);
|
||||||
|
@ -31,6 +31,8 @@ typedef enum KillWhom {
|
|||||||
KILL_MAIN_FAIL,
|
KILL_MAIN_FAIL,
|
||||||
KILL_CONTROL_FAIL,
|
KILL_CONTROL_FAIL,
|
||||||
KILL_ALL_FAIL,
|
KILL_ALL_FAIL,
|
||||||
|
KILL_CGROUP,
|
||||||
|
KILL_CGROUP_FAIL,
|
||||||
_KILL_WHOM_MAX,
|
_KILL_WHOM_MAX,
|
||||||
_KILL_WHOM_INVALID = -EINVAL,
|
_KILL_WHOM_INVALID = -EINVAL,
|
||||||
} KillWhom;
|
} KillWhom;
|
||||||
|
@ -145,10 +145,16 @@
|
|||||||
{{type}}.RuntimeDirectoryMode, config_parse_mode, 0, offsetof({{type}}, exec_context.directories[EXEC_DIRECTORY_RUNTIME].mode)
|
{{type}}.RuntimeDirectoryMode, config_parse_mode, 0, offsetof({{type}}, exec_context.directories[EXEC_DIRECTORY_RUNTIME].mode)
|
||||||
{{type}}.RuntimeDirectory, config_parse_exec_directories, 0, offsetof({{type}}, exec_context.directories[EXEC_DIRECTORY_RUNTIME])
|
{{type}}.RuntimeDirectory, config_parse_exec_directories, 0, offsetof({{type}}, exec_context.directories[EXEC_DIRECTORY_RUNTIME])
|
||||||
{{type}}.StateDirectoryMode, config_parse_mode, 0, offsetof({{type}}, exec_context.directories[EXEC_DIRECTORY_STATE].mode)
|
{{type}}.StateDirectoryMode, config_parse_mode, 0, offsetof({{type}}, exec_context.directories[EXEC_DIRECTORY_STATE].mode)
|
||||||
|
{{type}}.StateDirectoryAccounting, config_parse_bool, 0, offsetof({{type}}, exec_context.directories[EXEC_DIRECTORY_STATE].exec_quota.quota_accounting)
|
||||||
|
{{type}}.StateDirectoryQuota, config_parse_exec_quota, 0, offsetof({{type}}, exec_context.directories[EXEC_DIRECTORY_STATE].exec_quota)
|
||||||
{{type}}.StateDirectory, config_parse_exec_directories, 0, offsetof({{type}}, exec_context.directories[EXEC_DIRECTORY_STATE])
|
{{type}}.StateDirectory, config_parse_exec_directories, 0, offsetof({{type}}, exec_context.directories[EXEC_DIRECTORY_STATE])
|
||||||
{{type}}.CacheDirectoryMode, config_parse_mode, 0, offsetof({{type}}, exec_context.directories[EXEC_DIRECTORY_CACHE].mode)
|
{{type}}.CacheDirectoryMode, config_parse_mode, 0, offsetof({{type}}, exec_context.directories[EXEC_DIRECTORY_CACHE].mode)
|
||||||
|
{{type}}.CacheDirectoryAccounting, config_parse_bool, 0, offsetof({{type}}, exec_context.directories[EXEC_DIRECTORY_CACHE].exec_quota.quota_accounting)
|
||||||
|
{{type}}.CacheDirectoryQuota, config_parse_exec_quota, 0, offsetof({{type}}, exec_context.directories[EXEC_DIRECTORY_CACHE].exec_quota)
|
||||||
{{type}}.CacheDirectory, config_parse_exec_directories, 0, offsetof({{type}}, exec_context.directories[EXEC_DIRECTORY_CACHE])
|
{{type}}.CacheDirectory, config_parse_exec_directories, 0, offsetof({{type}}, exec_context.directories[EXEC_DIRECTORY_CACHE])
|
||||||
{{type}}.LogsDirectoryMode, config_parse_mode, 0, offsetof({{type}}, exec_context.directories[EXEC_DIRECTORY_LOGS].mode)
|
{{type}}.LogsDirectoryMode, config_parse_mode, 0, offsetof({{type}}, exec_context.directories[EXEC_DIRECTORY_LOGS].mode)
|
||||||
|
{{type}}.LogsDirectoryAccounting, config_parse_bool, 0, offsetof({{type}}, exec_context.directories[EXEC_DIRECTORY_LOGS].exec_quota.quota_accounting)
|
||||||
|
{{type}}.LogsDirectoryQuota, config_parse_exec_quota, 0, offsetof({{type}}, exec_context.directories[EXEC_DIRECTORY_LOGS].exec_quota)
|
||||||
{{type}}.LogsDirectory, config_parse_exec_directories, 0, offsetof({{type}}, exec_context.directories[EXEC_DIRECTORY_LOGS])
|
{{type}}.LogsDirectory, config_parse_exec_directories, 0, offsetof({{type}}, exec_context.directories[EXEC_DIRECTORY_LOGS])
|
||||||
{{type}}.ConfigurationDirectoryMode, config_parse_mode, 0, offsetof({{type}}, exec_context.directories[EXEC_DIRECTORY_CONFIGURATION].mode)
|
{{type}}.ConfigurationDirectoryMode, config_parse_mode, 0, offsetof({{type}}, exec_context.directories[EXEC_DIRECTORY_CONFIGURATION].mode)
|
||||||
{{type}}.ConfigurationDirectory, config_parse_exec_directories, 0, offsetof({{type}}, exec_context.directories[EXEC_DIRECTORY_CONFIGURATION])
|
{{type}}.ConfigurationDirectory, config_parse_exec_directories, 0, offsetof({{type}}, exec_context.directories[EXEC_DIRECTORY_CONFIGURATION])
|
||||||
|
@ -4602,6 +4602,48 @@ int config_parse_exec_directories(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int config_parse_exec_quota(
|
||||||
|
const char *unit,
|
||||||
|
const char *filename,
|
||||||
|
unsigned line,
|
||||||
|
const char *section,
|
||||||
|
unsigned section_line,
|
||||||
|
const char *lvalue,
|
||||||
|
int ltype,
|
||||||
|
const char *rvalue,
|
||||||
|
void *data,
|
||||||
|
void *userdata) {
|
||||||
|
|
||||||
|
QuotaLimit *quota_limit = ASSERT_PTR(data);
|
||||||
|
uint64_t quota_absolute = UINT64_MAX;
|
||||||
|
uint32_t quota_scale = UINT32_MAX;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (isempty(rvalue) || streq(rvalue, "off")) {
|
||||||
|
quota_limit->quota_enforce = false;
|
||||||
|
quota_limit->quota_absolute = UINT64_MAX;
|
||||||
|
quota_limit->quota_scale = UINT32_MAX;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = parse_permyriad(rvalue);
|
||||||
|
if (r < 0) {
|
||||||
|
r = parse_size(rvalue, 1024, "a_absolute);
|
||||||
|
if (r < 0) {
|
||||||
|
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse disk quota value, ignoring: %s", rvalue);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
/* Normalize to 2^32-1 == 100% */
|
||||||
|
quota_scale = UINT32_SCALE_FROM_PERMYRIAD(r);
|
||||||
|
|
||||||
|
quota_limit->quota_absolute = quota_absolute;
|
||||||
|
quota_limit->quota_scale = quota_scale;
|
||||||
|
quota_limit->quota_enforce = true;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int config_parse_set_credential(
|
int config_parse_set_credential(
|
||||||
const char *unit,
|
const char *unit,
|
||||||
const char *filename,
|
const char *filename,
|
||||||
|
@ -101,6 +101,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_exec_smack_process_label);
|
|||||||
CONFIG_PARSER_PROTOTYPE(config_parse_address_families);
|
CONFIG_PARSER_PROTOTYPE(config_parse_address_families);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_exec_preserve_mode);
|
CONFIG_PARSER_PROTOTYPE(config_parse_exec_preserve_mode);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_exec_directories);
|
CONFIG_PARSER_PROTOTYPE(config_parse_exec_directories);
|
||||||
|
CONFIG_PARSER_PROTOTYPE(config_parse_exec_quota);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_set_credential);
|
CONFIG_PARSER_PROTOTYPE(config_parse_set_credential);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_load_credential);
|
CONFIG_PARSER_PROTOTYPE(config_parse_load_credential);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_import_credential);
|
CONFIG_PARSER_PROTOTYPE(config_parse_import_credential);
|
||||||
|
@ -246,6 +246,10 @@
|
|||||||
send_interface="org.freedesktop.systemd1.Manager"
|
send_interface="org.freedesktop.systemd1.Manager"
|
||||||
send_member="KillUnit"/>
|
send_member="KillUnit"/>
|
||||||
|
|
||||||
|
<allow send_destination="org.freedesktop.systemd1"
|
||||||
|
send_interface="org.freedesktop.systemd1.Manager"
|
||||||
|
send_member="KillUnitSubgroup"/>
|
||||||
|
|
||||||
<allow send_destination="org.freedesktop.systemd1"
|
<allow send_destination="org.freedesktop.systemd1"
|
||||||
send_interface="org.freedesktop.systemd1.Manager"
|
send_interface="org.freedesktop.systemd1.Manager"
|
||||||
send_member="QueueSignalUnit"/>
|
send_member="QueueSignalUnit"/>
|
||||||
@ -410,6 +414,10 @@
|
|||||||
send_interface="org.freedesktop.systemd1.Unit"
|
send_interface="org.freedesktop.systemd1.Unit"
|
||||||
send_member="Kill"/>
|
send_member="Kill"/>
|
||||||
|
|
||||||
|
<allow send_destination="org.freedesktop.systemd1"
|
||||||
|
send_interface="org.freedesktop.systemd1.Unit"
|
||||||
|
send_member="KillSubgroup"/>
|
||||||
|
|
||||||
<allow send_destination="org.freedesktop.systemd1"
|
<allow send_destination="org.freedesktop.systemd1"
|
||||||
send_interface="org.freedesktop.systemd1.Unit"
|
send_interface="org.freedesktop.systemd1.Unit"
|
||||||
send_member="QueueSignal"/>
|
send_member="QueueSignal"/>
|
||||||
|
@ -376,7 +376,7 @@ int unit_deserialize_state(Unit *u, FILE *f, FDSet *fds) {
|
|||||||
unit_release_cgroup(u, /* drop_cgroup_runtime = */ false);
|
unit_release_cgroup(u, /* drop_cgroup_runtime = */ false);
|
||||||
else {
|
else {
|
||||||
unit_invalidate_cgroup(u, _CGROUP_MASK_ALL);
|
unit_invalidate_cgroup(u, _CGROUP_MASK_ALL);
|
||||||
unit_invalidate_cgroup_bpf(u);
|
unit_invalidate_cgroup_bpf_firewall(u);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
103
src/core/unit.c
103
src/core/unit.c
@ -19,6 +19,7 @@
|
|||||||
#include "cgroup-setup.h"
|
#include "cgroup-setup.h"
|
||||||
#include "cgroup-util.h"
|
#include "cgroup-util.h"
|
||||||
#include "chase.h"
|
#include "chase.h"
|
||||||
|
#include "chattr-util.h"
|
||||||
#include "condition.h"
|
#include "condition.h"
|
||||||
#include "dbus-unit.h"
|
#include "dbus-unit.h"
|
||||||
#include "dropin.h"
|
#include "dropin.h"
|
||||||
@ -45,6 +46,7 @@
|
|||||||
#include "mountpoint-util.h"
|
#include "mountpoint-util.h"
|
||||||
#include "path-util.h"
|
#include "path-util.h"
|
||||||
#include "process-util.h"
|
#include "process-util.h"
|
||||||
|
#include "quota-util.h"
|
||||||
#include "rm-rf.h"
|
#include "rm-rf.h"
|
||||||
#include "serialize.h"
|
#include "serialize.h"
|
||||||
#include "set.h"
|
#include "set.h"
|
||||||
@ -4039,6 +4041,7 @@ static int unit_kill_one(
|
|||||||
int unit_kill(
|
int unit_kill(
|
||||||
Unit *u,
|
Unit *u,
|
||||||
KillWhom whom,
|
KillWhom whom,
|
||||||
|
const char *subgroup,
|
||||||
int signo,
|
int signo,
|
||||||
int code,
|
int code,
|
||||||
int value,
|
int value,
|
||||||
@ -4058,11 +4061,19 @@ int unit_kill(
|
|||||||
assert(SIGNAL_VALID(signo));
|
assert(SIGNAL_VALID(signo));
|
||||||
assert(IN_SET(code, SI_USER, SI_QUEUE));
|
assert(IN_SET(code, SI_USER, SI_QUEUE));
|
||||||
|
|
||||||
|
if (subgroup) {
|
||||||
|
if (!IN_SET(whom, KILL_CGROUP, KILL_CGROUP_FAIL))
|
||||||
|
return sd_bus_error_set(ret_error, SD_BUS_ERROR_NOT_SUPPORTED, "Killing by subgroup is only supported for 'cgroup' or 'cgroup-kill' modes.");
|
||||||
|
|
||||||
|
if (!unit_cgroup_delegate(u))
|
||||||
|
return sd_bus_error_set(ret_error, SD_BUS_ERROR_NOT_SUPPORTED, "Killing by subgroup is only available for units with control group delegation enabled.");
|
||||||
|
}
|
||||||
|
|
||||||
main_pid = unit_main_pid(u);
|
main_pid = unit_main_pid(u);
|
||||||
control_pid = unit_control_pid(u);
|
control_pid = unit_control_pid(u);
|
||||||
|
|
||||||
if (!UNIT_HAS_CGROUP_CONTEXT(u) && !main_pid && !control_pid)
|
if (!UNIT_HAS_CGROUP_CONTEXT(u) && !main_pid && !control_pid)
|
||||||
return sd_bus_error_setf(ret_error, SD_BUS_ERROR_NOT_SUPPORTED, "Unit type does not support process killing.");
|
return sd_bus_error_set(ret_error, SD_BUS_ERROR_NOT_SUPPORTED, "Unit type does not support process killing.");
|
||||||
|
|
||||||
if (IN_SET(whom, KILL_MAIN, KILL_MAIN_FAIL)) {
|
if (IN_SET(whom, KILL_MAIN, KILL_MAIN_FAIL)) {
|
||||||
if (!main_pid)
|
if (!main_pid)
|
||||||
@ -4093,54 +4104,66 @@ int unit_kill(
|
|||||||
/* Note: if we shall enqueue rather than kill we won't do this via the cgroup mechanism, since it
|
/* Note: if we shall enqueue rather than kill we won't do this via the cgroup mechanism, since it
|
||||||
* doesn't really make much sense (and given that enqueued values are a relatively expensive
|
* doesn't really make much sense (and given that enqueued values are a relatively expensive
|
||||||
* resource, and we shouldn't allow us to be subjects for such allocation sprees) */
|
* resource, and we shouldn't allow us to be subjects for such allocation sprees) */
|
||||||
if (IN_SET(whom, KILL_ALL, KILL_ALL_FAIL) && code == SI_USER) {
|
if (IN_SET(whom, KILL_ALL, KILL_ALL_FAIL, KILL_CGROUP, KILL_CGROUP_FAIL) && code == SI_USER) {
|
||||||
CGroupRuntime *crt = unit_get_cgroup_runtime(u);
|
CGroupRuntime *crt = unit_get_cgroup_runtime(u);
|
||||||
if (crt && crt->cgroup_path) {
|
if (crt && crt->cgroup_path) {
|
||||||
_cleanup_set_free_ Set *pid_set = NULL;
|
_cleanup_set_free_ Set *pid_set = NULL;
|
||||||
|
_cleanup_free_ char *joined = NULL;
|
||||||
|
const char *p;
|
||||||
|
|
||||||
|
if (empty_or_root(subgroup))
|
||||||
|
p = crt->cgroup_path;
|
||||||
|
else {
|
||||||
|
joined = path_join(crt->cgroup_path, subgroup);
|
||||||
|
if (!joined)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
p = joined;
|
||||||
|
}
|
||||||
|
|
||||||
if (signo == SIGKILL) {
|
if (signo == SIGKILL) {
|
||||||
r = cg_kill_kernel_sigkill(crt->cgroup_path);
|
r = cg_kill_kernel_sigkill(p);
|
||||||
if (r >= 0) {
|
if (r >= 0) {
|
||||||
killed = true;
|
killed = true;
|
||||||
log_unit_info(u, "Killed unit cgroup with SIGKILL on client request.");
|
log_unit_info(u, "Killed unit cgroup '%s' with SIGKILL on client request.", p);
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
if (r != -EOPNOTSUPP) {
|
if (r != -EOPNOTSUPP) {
|
||||||
if (ret >= 0)
|
if (ret >= 0)
|
||||||
sd_bus_error_set_errnof(ret_error, r,
|
sd_bus_error_set_errnof(ret_error, r,
|
||||||
"Failed to kill unit cgroup: %m");
|
"Failed to kill unit cgroup: %m");
|
||||||
RET_GATHER(ret, log_unit_warning_errno(u, r, "Failed to kill unit cgroup: %m"));
|
RET_GATHER(ret, log_unit_warning_errno(u, r, "Failed to kill unit cgroup '%s': %m", p));
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
/* Fall back to manual enumeration */
|
/* Fall back to manual enumeration */
|
||||||
} else {
|
} else if (IN_SET(whom, KILL_ALL, KILL_ALL_FAIL)) {
|
||||||
/* Exclude the main/control pids from being killed via the cgroup if
|
/* Exclude the main/control pids from being killed via the cgroup if not
|
||||||
* not SIGKILL */
|
* SIGKILL */
|
||||||
r = unit_pid_set(u, &pid_set);
|
r = unit_pid_set(u, &pid_set);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
}
|
}
|
||||||
|
|
||||||
r = cg_kill_recursive(crt->cgroup_path, signo, 0, pid_set, kill_common_log, u);
|
r = cg_kill_recursive(p, signo, /* flags= */ 0, pid_set, kill_common_log, u);
|
||||||
if (r < 0 && !IN_SET(r, -ESRCH, -ENOENT)) {
|
if (r < 0 && !IN_SET(r, -ESRCH, -ENOENT)) {
|
||||||
if (ret >= 0)
|
if (ret >= 0)
|
||||||
sd_bus_error_set_errnof(
|
sd_bus_error_set_errnof(
|
||||||
ret_error, r,
|
ret_error, r,
|
||||||
"Failed to send signal SIG%s to auxiliary processes: %m",
|
"Failed to send signal SIG%s to processes in unit cgroup '%s': %m",
|
||||||
signal_to_string(signo));
|
signal_to_string(signo), p);
|
||||||
|
|
||||||
RET_GATHER(ret, log_unit_warning_errno(
|
RET_GATHER(ret, log_unit_warning_errno(
|
||||||
u, r,
|
u, r,
|
||||||
"Failed to send signal SIG%s to auxiliary processes on client request: %m",
|
"Failed to send signal SIG%s to processes in unit cgroup '%s' on client request: %m",
|
||||||
signal_to_string(signo)));
|
signal_to_string(signo), p));
|
||||||
}
|
}
|
||||||
killed = killed || r >= 0;
|
killed = killed || r > 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
finish:
|
finish:
|
||||||
/* If the "fail" versions of the operation are requested, then complain if the set of processes we killed is empty */
|
/* If the "fail" versions of the operation are requested, then complain if the set of processes we killed is empty */
|
||||||
if (ret >= 0 && !killed && IN_SET(whom, KILL_ALL_FAIL, KILL_CONTROL_FAIL, KILL_MAIN_FAIL))
|
if (ret >= 0 && !killed && IN_SET(whom, KILL_ALL_FAIL, KILL_CONTROL_FAIL, KILL_MAIN_FAIL, KILL_CGROUP_FAIL))
|
||||||
return sd_bus_error_set_const(ret_error, BUS_ERROR_NO_SUCH_PROCESS, "No matching processes to kill");
|
return sd_bus_error_set_const(ret_error, BUS_ERROR_NO_SUCH_PROCESS, "No matching processes to kill");
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -4425,7 +4448,7 @@ int unit_patch_contexts(Unit *u) {
|
|||||||
cc->device_policy = CGROUP_DEVICE_POLICY_CLOSED;
|
cc->device_policy = CGROUP_DEVICE_POLICY_CLOSED;
|
||||||
|
|
||||||
/* Only add these if needed, as they imply that everything else is blocked. */
|
/* Only add these if needed, as they imply that everything else is blocked. */
|
||||||
if (cc->device_policy != CGROUP_DEVICE_POLICY_AUTO || cc->device_allow) {
|
if (cgroup_context_has_device_policy(cc)) {
|
||||||
if (ec->root_image || ec->mount_images) {
|
if (ec->root_image || ec->mount_images) {
|
||||||
|
|
||||||
/* When RootImage= or MountImages= is specified, the following devices are touched. */
|
/* When RootImage= or MountImages= is specified, the following devices are touched. */
|
||||||
@ -6076,7 +6099,7 @@ int unit_pid_attachable(Unit *u, PidRef *pid, sd_bus_error *error) {
|
|||||||
|
|
||||||
/* First, a simple range check */
|
/* First, a simple range check */
|
||||||
if (!pidref_is_set(pid))
|
if (!pidref_is_set(pid))
|
||||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Process identifier is not valid.");
|
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Process identifier is not valid.");
|
||||||
|
|
||||||
/* Some extra safety check */
|
/* Some extra safety check */
|
||||||
if (pid->pid == 1 || pidref_is_self(pid))
|
if (pid->pid == 1 || pidref_is_self(pid))
|
||||||
@ -6722,6 +6745,52 @@ static uint64_t unit_get_cpu_weight(Unit *u) {
|
|||||||
return cc ? cgroup_context_cpu_weight(cc, manager_state(u->manager)) : CGROUP_WEIGHT_DEFAULT;
|
return cc ? cgroup_context_cpu_weight(cc, manager_state(u->manager)) : CGROUP_WEIGHT_DEFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int unit_get_exec_quota_stats(Unit *u, ExecContext *c, ExecDirectoryType dt, uint64_t *ret_usage, uint64_t *ret_limit) {
|
||||||
|
int r;
|
||||||
|
_cleanup_close_ int fd = -EBADF;
|
||||||
|
_cleanup_free_ char *p = NULL, *pp = NULL;
|
||||||
|
|
||||||
|
assert(u);
|
||||||
|
assert(c);
|
||||||
|
|
||||||
|
if (c->directories[dt].n_items == 0) {
|
||||||
|
*ret_usage = UINT64_MAX;
|
||||||
|
*ret_limit = UINT64_MAX;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExecDirectoryItem *i = &c->directories[dt].items[0];
|
||||||
|
p = path_join(u->manager->prefix[dt], i->path);
|
||||||
|
if (!p)
|
||||||
|
return log_oom_debug();
|
||||||
|
|
||||||
|
if (exec_directory_is_private(c, dt)) {
|
||||||
|
pp = path_join(u->manager->prefix[dt], "private", i->path);
|
||||||
|
if (!pp)
|
||||||
|
return log_oom_debug();
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *target_dir = pp ?: p;
|
||||||
|
fd = open(target_dir, O_PATH | O_CLOEXEC | O_DIRECTORY);
|
||||||
|
if (fd < 0)
|
||||||
|
return log_unit_debug_errno(u, errno, "Failed to get exec quota stats: %m");
|
||||||
|
|
||||||
|
uint32_t proj_id;
|
||||||
|
r = read_fs_xattr_fd(fd, /* ret_xflags = */ NULL, &proj_id);
|
||||||
|
if (r < 0)
|
||||||
|
return log_unit_debug_errno(u, r, "Failed to get project ID for exec quota stats: %m");
|
||||||
|
|
||||||
|
struct dqblk req;
|
||||||
|
r = quota_query_proj_id(fd, proj_id, &req);
|
||||||
|
if (r <= 0)
|
||||||
|
return log_unit_debug_errno(u, r, "Failed to query project ID for exec quota stats: %m");
|
||||||
|
|
||||||
|
*ret_usage = req.dqb_curspace;
|
||||||
|
*ret_limit = req.dqb_bhardlimit * QIF_DQBLKSIZE;
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
int unit_compare_priority(Unit *a, Unit *b) {
|
int unit_compare_priority(Unit *a, Unit *b) {
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -886,7 +886,7 @@ int unit_start(Unit *u, ActivationDetails *details);
|
|||||||
int unit_stop(Unit *u);
|
int unit_stop(Unit *u);
|
||||||
int unit_reload(Unit *u);
|
int unit_reload(Unit *u);
|
||||||
|
|
||||||
int unit_kill(Unit *u, KillWhom w, int signo, int code, int value, sd_bus_error *ret_error);
|
int unit_kill(Unit *u, KillWhom w, const char *subgroup, int signo, int code, int value, sd_bus_error *ret_error);
|
||||||
|
|
||||||
void unit_notify_cgroup_oom(Unit *u, bool managed_oom);
|
void unit_notify_cgroup_oom(Unit *u, bool managed_oom);
|
||||||
|
|
||||||
@ -938,6 +938,8 @@ int unit_add_default_target_dependency(Unit *u, Unit *target);
|
|||||||
void unit_start_on_termination_deps(Unit *u, UnitDependencyAtom atom);
|
void unit_start_on_termination_deps(Unit *u, UnitDependencyAtom atom);
|
||||||
void unit_trigger_notify(Unit *u);
|
void unit_trigger_notify(Unit *u);
|
||||||
|
|
||||||
|
int unit_get_exec_quota_stats(Unit *u, ExecContext *c, ExecDirectoryType dt, uint64_t *ret_usage, uint64_t *ret_limit);
|
||||||
|
|
||||||
UnitFileState unit_get_unit_file_state(Unit *u);
|
UnitFileState unit_get_unit_file_state(Unit *u);
|
||||||
PresetAction unit_get_unit_file_preset(Unit *u);
|
PresetAction unit_get_unit_file_preset(Unit *u);
|
||||||
|
|
||||||
|
@ -442,7 +442,7 @@ int bus_home_update_record(
|
|||||||
return r;
|
return r;
|
||||||
|
|
||||||
if ((flags & ~SD_HOMED_UPDATE_FLAGS_ALL) != 0)
|
if ((flags & ~SD_HOMED_UPDATE_FLAGS_ALL) != 0)
|
||||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid flags provided.");
|
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid flags provided.");
|
||||||
|
|
||||||
if (blobs) {
|
if (blobs) {
|
||||||
const char *failed = NULL;
|
const char *failed = NULL;
|
||||||
|
@ -549,7 +549,7 @@ static int method_adopt_home(
|
|||||||
if (!path_is_absolute(image_path) || !path_is_safe(image_path))
|
if (!path_is_absolute(image_path) || !path_is_safe(image_path))
|
||||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Specified path is not absolute or not valid: %s", image_path);
|
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Specified path is not absolute or not valid: %s", image_path);
|
||||||
if (flags != 0)
|
if (flags != 0)
|
||||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Flags field must be zero.");
|
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Flags field must be zero.");
|
||||||
|
|
||||||
r = bus_verify_polkit_async(
|
r = bus_verify_polkit_async(
|
||||||
message,
|
message,
|
||||||
@ -598,7 +598,7 @@ static int method_create_home(sd_bus_message *message, void *userdata, sd_bus_er
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
if ((flags & ~SD_HOMED_CREATE_FLAGS_ALL) != 0)
|
if ((flags & ~SD_HOMED_CREATE_FLAGS_ALL) != 0)
|
||||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid flags provided.");
|
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid flags provided.");
|
||||||
}
|
}
|
||||||
|
|
||||||
r = bus_verify_polkit_async(
|
r = bus_verify_polkit_async(
|
||||||
@ -963,11 +963,11 @@ static int method_add_signing_key(sd_bus_message *message, void *userdata, sd_bu
|
|||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (flags != 0)
|
if (flags != 0)
|
||||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Flags parameter must be zero.");
|
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Flags parameter must be zero.");
|
||||||
if (!valid_public_key_name(fn))
|
if (!valid_public_key_name(fn))
|
||||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Public key name not valid: %s", fn);
|
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Public key name not valid: %s", fn);
|
||||||
if (streq(fn, "local.public"))
|
if (streq(fn, "local.public"))
|
||||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Refusing to write local public key.");
|
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Refusing to write local public key.");
|
||||||
|
|
||||||
_cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey = NULL;
|
_cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey = NULL;
|
||||||
r = openssl_pubkey_from_pem(pem, /* pem_size= */ SIZE_MAX, &pkey);
|
r = openssl_pubkey_from_pem(pem, /* pem_size= */ SIZE_MAX, &pkey);
|
||||||
@ -1040,13 +1040,13 @@ static int method_remove_signing_key(sd_bus_message *message, void *userdata, sd
|
|||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (flags != 0)
|
if (flags != 0)
|
||||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Flags parameter must be zero.");
|
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Flags parameter must be zero.");
|
||||||
|
|
||||||
if (!valid_public_key_name(fn))
|
if (!valid_public_key_name(fn))
|
||||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Public key name not valid: %s", fn);
|
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Public key name not valid: %s", fn);
|
||||||
|
|
||||||
if (streq(fn, "local.public"))
|
if (streq(fn, "local.public"))
|
||||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Refusing to remove local key.");
|
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Refusing to remove local key.");
|
||||||
|
|
||||||
if (!hashmap_contains(m->public_keys, fn))
|
if (!hashmap_contains(m->public_keys, fn))
|
||||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Public key name does not exist: %s", fn);
|
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Public key name does not exist: %s", fn);
|
||||||
|
@ -128,7 +128,7 @@ static int get_sender_session(
|
|||||||
session = hashmap_get(m->sessions, name);
|
session = hashmap_get(m->sessions, name);
|
||||||
|
|
||||||
if (!session)
|
if (!session)
|
||||||
return sd_bus_error_setf(error, BUS_ERROR_NO_SESSION_FOR_PID,
|
return sd_bus_error_set(error, BUS_ERROR_NO_SESSION_FOR_PID,
|
||||||
consult_display ?
|
consult_display ?
|
||||||
"Caller does not belong to any known session and doesn't own any suitable session." :
|
"Caller does not belong to any known session and doesn't own any suitable session." :
|
||||||
"Caller does not belong to any known session.");
|
"Caller does not belong to any known session.");
|
||||||
@ -183,7 +183,7 @@ static int get_sender_user(Manager *m, sd_bus_message *message, sd_bus_error *er
|
|||||||
user = hashmap_get(m->users, UID_TO_PTR(uid));
|
user = hashmap_get(m->users, UID_TO_PTR(uid));
|
||||||
|
|
||||||
if (!user)
|
if (!user)
|
||||||
return sd_bus_error_setf(error, BUS_ERROR_NO_USER_FOR_PID,
|
return sd_bus_error_set(error, BUS_ERROR_NO_USER_FOR_PID,
|
||||||
"Caller does not belong to any logged in or lingering user");
|
"Caller does not belong to any logged in or lingering user");
|
||||||
|
|
||||||
*ret = user;
|
*ret = user;
|
||||||
@ -1183,7 +1183,7 @@ static int manager_create_session_by_bus(
|
|||||||
if (vtnr == 0)
|
if (vtnr == 0)
|
||||||
vtnr = (uint32_t) v;
|
vtnr = (uint32_t) v;
|
||||||
else if (vtnr != (uint32_t) v)
|
else if (vtnr != (uint32_t) v)
|
||||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||||
"Specified TTY and VT number do not match");
|
"Specified TTY and VT number do not match");
|
||||||
|
|
||||||
} else if (tty_is_console(tty)) {
|
} else if (tty_is_console(tty)) {
|
||||||
@ -1191,22 +1191,22 @@ static int manager_create_session_by_bus(
|
|||||||
if (!seat)
|
if (!seat)
|
||||||
seat = m->seat0;
|
seat = m->seat0;
|
||||||
else if (seat != m->seat0)
|
else if (seat != m->seat0)
|
||||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||||
"Console TTY specified but seat is not seat0");
|
"Console TTY specified but seat is not seat0");
|
||||||
|
|
||||||
if (vtnr != 0)
|
if (vtnr != 0)
|
||||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||||
"Console TTY specified but VT number is not 0");
|
"Console TTY specified but VT number is not 0");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (seat) {
|
if (seat) {
|
||||||
if (seat_has_vts(seat)) {
|
if (seat_has_vts(seat)) {
|
||||||
if (!vtnr_is_valid(vtnr))
|
if (!vtnr_is_valid(vtnr))
|
||||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||||
"VT number out of range");
|
"VT number out of range");
|
||||||
} else {
|
} else {
|
||||||
if (vtnr != 0)
|
if (vtnr != 0)
|
||||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||||
"Seat has no VTs but VT number not 0");
|
"Seat has no VTs but VT number not 0");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1229,7 +1229,7 @@ static int manager_create_session_by_bus(
|
|||||||
remote_host,
|
remote_host,
|
||||||
&session);
|
&session);
|
||||||
if (r == -EBUSY)
|
if (r == -EBUSY)
|
||||||
return sd_bus_error_setf(error, BUS_ERROR_SESSION_BUSY, "Already running in a session or user slice");
|
return sd_bus_error_set(error, BUS_ERROR_SESSION_BUSY, "Already running in a session or user slice");
|
||||||
if (r == -EADDRNOTAVAIL)
|
if (r == -EADDRNOTAVAIL)
|
||||||
return sd_bus_error_set(error, BUS_ERROR_SESSION_BUSY, "Virtual terminal already occupied by a session");
|
return sd_bus_error_set(error, BUS_ERROR_SESSION_BUSY, "Virtual terminal already occupied by a session");
|
||||||
if (r == -EUSERS)
|
if (r == -EUSERS)
|
||||||
@ -2240,7 +2240,7 @@ static int verify_shutdown_creds(
|
|||||||
if (!FLAGS_SET(flags, SD_LOGIND_SKIP_INHIBITORS) &&
|
if (!FLAGS_SET(flags, SD_LOGIND_SKIP_INHIBITORS) &&
|
||||||
(offending->mode != INHIBIT_BLOCK_WEAK ||
|
(offending->mode != INHIBIT_BLOCK_WEAK ||
|
||||||
(uid == 0 && FLAGS_SET(flags, SD_LOGIND_ROOT_CHECK_INHIBITORS))))
|
(uid == 0 && FLAGS_SET(flags, SD_LOGIND_ROOT_CHECK_INHIBITORS))))
|
||||||
return sd_bus_error_setf(error, BUS_ERROR_BLOCKED_BY_INHIBITOR_LOCK,
|
return sd_bus_error_set(error, BUS_ERROR_BLOCKED_BY_INHIBITOR_LOCK,
|
||||||
"Operation denied due to active block inhibitor");
|
"Operation denied due to active block inhibitor");
|
||||||
|
|
||||||
/* We want to always ask here, even for root, to only allow bypassing if explicitly allowed
|
/* We want to always ask here, even for root, to only allow bypassing if explicitly allowed
|
||||||
@ -3136,7 +3136,7 @@ static int method_set_reboot_parameter(
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
if (r > 0)
|
if (r > 0)
|
||||||
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED,
|
return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED,
|
||||||
"Reboot parameter not supported in containers, refusing.");
|
"Reboot parameter not supported in containers, refusing.");
|
||||||
|
|
||||||
r = bus_verify_polkit_async(
|
r = bus_verify_polkit_async(
|
||||||
@ -3801,7 +3801,7 @@ static int method_inhibit(sd_bus_message *message, void *userdata, sd_bus_error
|
|||||||
|
|
||||||
/* Delay is only supported for shutdown/sleep */
|
/* Delay is only supported for shutdown/sleep */
|
||||||
if (mm == INHIBIT_DELAY && (w & ~(INHIBIT_SHUTDOWN|INHIBIT_SLEEP)))
|
if (mm == INHIBIT_DELAY && (w & ~(INHIBIT_SHUTDOWN|INHIBIT_SLEEP)))
|
||||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||||
"Delay inhibitors only supported for shutdown and sleep");
|
"Delay inhibitors only supported for shutdown and sleep");
|
||||||
|
|
||||||
/* Don't allow taking delay locks while we are already
|
/* Don't allow taking delay locks while we are already
|
||||||
@ -3809,7 +3809,7 @@ static int method_inhibit(sd_bus_message *message, void *userdata, sd_bus_error
|
|||||||
* that the lock was successful if the machine is about to go
|
* that the lock was successful if the machine is about to go
|
||||||
* down/suspend any moment. */
|
* down/suspend any moment. */
|
||||||
if (m->delayed_action && m->delayed_action->inhibit_what & w)
|
if (m->delayed_action && m->delayed_action->inhibit_what & w)
|
||||||
return sd_bus_error_setf(error, BUS_ERROR_OPERATION_IN_PROGRESS,
|
return sd_bus_error_set(error, BUS_ERROR_OPERATION_IN_PROGRESS,
|
||||||
"The operation inhibition has been requested for is already running");
|
"The operation inhibition has been requested for is already running");
|
||||||
|
|
||||||
BIT_FOREACH(i, w) {
|
BIT_FOREACH(i, w) {
|
||||||
|
@ -470,17 +470,17 @@ static int method_set_class(sd_bus_message *message, void *userdata, sd_bus_erro
|
|||||||
|
|
||||||
/* For now, we'll allow only upgrades user-incomplete → user */
|
/* For now, we'll allow only upgrades user-incomplete → user */
|
||||||
if (class != SESSION_USER)
|
if (class != SESSION_USER)
|
||||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||||
"Class may only be set to 'user'");
|
"Class may only be set to 'user'");
|
||||||
|
|
||||||
if (s->class == SESSION_USER) /* No change, shortcut */
|
if (s->class == SESSION_USER) /* No change, shortcut */
|
||||||
return sd_bus_reply_method_return(message, NULL);
|
return sd_bus_reply_method_return(message, NULL);
|
||||||
if (s->class != SESSION_USER_INCOMPLETE)
|
if (s->class != SESSION_USER_INCOMPLETE)
|
||||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||||
"Only sessions with class 'user-incomplete' may change class");
|
"Only sessions with class 'user-incomplete' may change class");
|
||||||
|
|
||||||
if (s->upgrade_message)
|
if (s->upgrade_message)
|
||||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||||
"Set session class operation already in progress");
|
"Set session class operation already in progress");
|
||||||
|
|
||||||
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
|
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
#include "chase.h"
|
#include "chase.h"
|
||||||
|
#include "errno-util.h"
|
||||||
#include "escape.h"
|
#include "escape.h"
|
||||||
#include "extract-word.h"
|
#include "extract-word.h"
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
@ -814,7 +815,28 @@ static int mount_bind(const char *dest, CustomMount *m, uid_t uid_shift, uid_t u
|
|||||||
if (m->rm_rf_tmpdir && chown(m->source, uid_shift, uid_shift) < 0)
|
if (m->rm_rf_tmpdir && chown(m->source, uid_shift, uid_shift) < 0)
|
||||||
return log_error_errno(errno, "Failed to chown %s: %m", m->source);
|
return log_error_errno(errno, "Failed to chown %s: %m", m->source);
|
||||||
|
|
||||||
if (stat(m->source, &source_st) < 0)
|
/* UID/GIDs of idmapped mounts are always resolved in the caller's user namespace. In other
|
||||||
|
* words, they're not nested. If we're doing an idmapped mount from a bind mount that's
|
||||||
|
* already idmapped itself, the old idmap is replaced with the new one. This means that the
|
||||||
|
* source uid which we put in the idmap userns has to be the uid of mount source in the
|
||||||
|
* caller's userns *without* any mount idmapping in place. To get that uid, we clone the
|
||||||
|
* mount source tree and clear any existing idmapping and temporarily mount that tree over
|
||||||
|
* the mount source before we stat the mount source to figure out the source uid. */
|
||||||
|
_cleanup_close_ int fd_clone = open_tree_attr_fallback(
|
||||||
|
AT_FDCWD,
|
||||||
|
m->source,
|
||||||
|
OPEN_TREE_CLONE|OPEN_TREE_CLOEXEC,
|
||||||
|
&(struct mount_attr) {
|
||||||
|
.attr_clr = MOUNT_ATTR_IDMAP,
|
||||||
|
});
|
||||||
|
if (ERRNO_IS_NEG_NOT_SUPPORTED(fd_clone))
|
||||||
|
/* We can only clear idmapped mounts with open_tree_attr(), but there might not be one in
|
||||||
|
* the first place, so we keep going if we get a not supported error. */
|
||||||
|
fd_clone = open_tree(AT_FDCWD, m->source, OPEN_TREE_CLONE|OPEN_TREE_CLOEXEC);
|
||||||
|
if (fd_clone < 0)
|
||||||
|
return log_error_errno(errno, "Failed to clone %s: %m", m->source);
|
||||||
|
|
||||||
|
if (fstat(fd_clone, &source_st) < 0)
|
||||||
return log_error_errno(errno, "Failed to stat %s: %m", m->source);
|
return log_error_errno(errno, "Failed to stat %s: %m", m->source);
|
||||||
|
|
||||||
r = chase(m->destination, dest, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &where, NULL);
|
r = chase(m->destination, dest, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &where, NULL);
|
||||||
@ -859,9 +881,10 @@ static int mount_bind(const char *dest, CustomMount *m, uid_t uid_shift, uid_t u
|
|||||||
dest_uid = uid_shift;
|
dest_uid = uid_shift;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = mount_nofollow_verbose(LOG_ERR, m->source, where, NULL, mount_flags, mount_opts);
|
if (move_mount(fd_clone, "", AT_FDCWD, where, MOVE_MOUNT_F_EMPTY_PATH) < 0)
|
||||||
if (r < 0)
|
return log_error_errno(errno, "Failed to mount %s to %s: %m", m->source, where);
|
||||||
return r;
|
|
||||||
|
fd_clone = safe_close(fd_clone);
|
||||||
|
|
||||||
if (m->read_only) {
|
if (m->read_only) {
|
||||||
r = bind_remount_recursive(where, MS_RDONLY, MS_RDONLY, NULL);
|
r = bind_remount_recursive(where, MS_RDONLY, MS_RDONLY, NULL);
|
||||||
|
@ -32,37 +32,37 @@
|
|||||||
#include "strv.h"
|
#include "strv.h"
|
||||||
#include "uki.h"
|
#include "uki.h"
|
||||||
|
|
||||||
static const char* const boot_entry_type_table[_BOOT_ENTRY_TYPE_MAX] = {
|
static const char* const boot_entry_type_description_table[_BOOT_ENTRY_TYPE_MAX] = {
|
||||||
[BOOT_ENTRY_CONF] = "Boot Loader Specification Type #1 (.conf)",
|
[BOOT_ENTRY_TYPE1] = "Boot Loader Specification Type #1 (.conf)",
|
||||||
[BOOT_ENTRY_UNIFIED] = "Boot Loader Specification Type #2 (.efi)",
|
[BOOT_ENTRY_TYPE2] = "Boot Loader Specification Type #2 (UKI, .efi)",
|
||||||
[BOOT_ENTRY_LOADER] = "Reported by Boot Loader",
|
[BOOT_ENTRY_LOADER] = "Reported by Boot Loader",
|
||||||
[BOOT_ENTRY_LOADER_AUTO] = "Automatic",
|
[BOOT_ENTRY_AUTO] = "Automatic",
|
||||||
|
};
|
||||||
|
|
||||||
|
DEFINE_STRING_TABLE_LOOKUP_TO_STRING(boot_entry_type_description, BootEntryType);
|
||||||
|
|
||||||
|
static const char* const boot_entry_type_table[_BOOT_ENTRY_TYPE_MAX] = {
|
||||||
|
[BOOT_ENTRY_TYPE1] = "type1",
|
||||||
|
[BOOT_ENTRY_TYPE2] = "type2",
|
||||||
|
[BOOT_ENTRY_LOADER] = "loader",
|
||||||
|
[BOOT_ENTRY_AUTO] = "auto",
|
||||||
};
|
};
|
||||||
|
|
||||||
DEFINE_STRING_TABLE_LOOKUP_TO_STRING(boot_entry_type, BootEntryType);
|
DEFINE_STRING_TABLE_LOOKUP_TO_STRING(boot_entry_type, BootEntryType);
|
||||||
|
|
||||||
static const char* const boot_entry_type_json_table[_BOOT_ENTRY_TYPE_MAX] = {
|
static const char* const boot_entry_source_description_table[_BOOT_ENTRY_SOURCE_MAX] = {
|
||||||
[BOOT_ENTRY_CONF] = "type1",
|
|
||||||
[BOOT_ENTRY_UNIFIED] = "type2",
|
|
||||||
[BOOT_ENTRY_LOADER] = "loader",
|
|
||||||
[BOOT_ENTRY_LOADER_AUTO] = "auto",
|
|
||||||
};
|
|
||||||
|
|
||||||
DEFINE_STRING_TABLE_LOOKUP_TO_STRING(boot_entry_type_json, BootEntryType);
|
|
||||||
|
|
||||||
static const char* const boot_entry_source_table[_BOOT_ENTRY_SOURCE_MAX] = {
|
|
||||||
[BOOT_ENTRY_ESP] = "EFI System Partition",
|
[BOOT_ENTRY_ESP] = "EFI System Partition",
|
||||||
[BOOT_ENTRY_XBOOTLDR] = "Extended Boot Loader Partition",
|
[BOOT_ENTRY_XBOOTLDR] = "Extended Boot Loader Partition",
|
||||||
};
|
};
|
||||||
|
|
||||||
DEFINE_STRING_TABLE_LOOKUP_TO_STRING(boot_entry_source, BootEntrySource);
|
DEFINE_STRING_TABLE_LOOKUP_TO_STRING(boot_entry_source_description, BootEntrySource);
|
||||||
|
|
||||||
static const char* const boot_entry_source_json_table[_BOOT_ENTRY_SOURCE_MAX] = {
|
static const char* const boot_entry_source_table[_BOOT_ENTRY_SOURCE_MAX] = {
|
||||||
[BOOT_ENTRY_ESP] = "esp",
|
[BOOT_ENTRY_ESP] = "esp",
|
||||||
[BOOT_ENTRY_XBOOTLDR] = "xbootldr",
|
[BOOT_ENTRY_XBOOTLDR] = "xbootldr",
|
||||||
};
|
};
|
||||||
|
|
||||||
DEFINE_STRING_TABLE_LOOKUP_TO_STRING(boot_entry_source_json, BootEntrySource);
|
DEFINE_STRING_TABLE_LOOKUP_TO_STRING(boot_entry_source, BootEntrySource);
|
||||||
|
|
||||||
static void boot_entry_addons_done(BootEntryAddons *addons) {
|
static void boot_entry_addons_done(BootEntryAddons *addons) {
|
||||||
assert(addons);
|
assert(addons);
|
||||||
@ -319,7 +319,7 @@ static int boot_entry_load_type1(
|
|||||||
const char *fname,
|
const char *fname,
|
||||||
BootEntry *ret) {
|
BootEntry *ret) {
|
||||||
|
|
||||||
_cleanup_(boot_entry_free) BootEntry tmp = BOOT_ENTRY_INIT(BOOT_ENTRY_CONF, source);
|
_cleanup_(boot_entry_free) BootEntry tmp = BOOT_ENTRY_INIT(BOOT_ENTRY_TYPE1, source);
|
||||||
char *c;
|
char *c;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -759,7 +759,7 @@ static int boot_entry_load_unified(
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to extract file name from '%s': %m", path);
|
return log_error_errno(r, "Failed to extract file name from '%s': %m", path);
|
||||||
|
|
||||||
_cleanup_(boot_entry_free) BootEntry tmp = BOOT_ENTRY_INIT(BOOT_ENTRY_UNIFIED, source);
|
_cleanup_(boot_entry_free) BootEntry tmp = BOOT_ENTRY_INIT(BOOT_ENTRY_TYPE2, source);
|
||||||
|
|
||||||
r = boot_filename_extract_tries(fname, &tmp.id, &tmp.tries_left, &tmp.tries_done);
|
r = boot_filename_extract_tries(fname, &tmp.id, &tmp.tries_left, &tmp.tries_done);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -1620,7 +1620,7 @@ int boot_config_augment_from_loader(
|
|||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
config->entries[config->n_entries++] = (BootEntry) {
|
config->entries[config->n_entries++] = (BootEntry) {
|
||||||
.type = startswith(*i, "auto-") ? BOOT_ENTRY_LOADER_AUTO : BOOT_ENTRY_LOADER,
|
.type = startswith(*i, "auto-") ? BOOT_ENTRY_AUTO : BOOT_ENTRY_LOADER,
|
||||||
.id = TAKE_PTR(c),
|
.id = TAKE_PTR(c),
|
||||||
.title = TAKE_PTR(t),
|
.title = TAKE_PTR(t),
|
||||||
.path = TAKE_PTR(p),
|
.path = TAKE_PTR(p),
|
||||||
@ -1823,7 +1823,7 @@ int show_boot_entry(
|
|||||||
assert(e);
|
assert(e);
|
||||||
|
|
||||||
printf(" type: %s\n",
|
printf(" type: %s\n",
|
||||||
boot_entry_type_to_string(e->type));
|
boot_entry_type_description_to_string(e->type));
|
||||||
|
|
||||||
printf(" title: %s%s%s",
|
printf(" title: %s%s%s",
|
||||||
ansi_highlight(), boot_entry_title(e), ansi_normal());
|
ansi_highlight(), boot_entry_title(e), ansi_normal());
|
||||||
@ -1840,7 +1840,7 @@ int show_boot_entry(
|
|||||||
if (e->type == BOOT_ENTRY_LOADER)
|
if (e->type == BOOT_ENTRY_LOADER)
|
||||||
printf(" %s(reported/absent)%s",
|
printf(" %s(reported/absent)%s",
|
||||||
ansi_highlight_red(), ansi_normal());
|
ansi_highlight_red(), ansi_normal());
|
||||||
else if (!e->reported_by_loader && e->type != BOOT_ENTRY_LOADER_AUTO)
|
else if (!e->reported_by_loader && e->type != BOOT_ENTRY_AUTO)
|
||||||
printf(" %s(not reported/new)%s",
|
printf(" %s(not reported/new)%s",
|
||||||
ansi_highlight_green(), ansi_normal());
|
ansi_highlight_green(), ansi_normal());
|
||||||
}
|
}
|
||||||
@ -1867,12 +1867,12 @@ int show_boot_entry(
|
|||||||
|
|
||||||
/* Let's urlify the link to make it easy to view in an editor, but only if it is a text
|
/* Let's urlify the link to make it easy to view in an editor, but only if it is a text
|
||||||
* file. Unified images are binary ELFs, and EFI variables are not pure text either. */
|
* file. Unified images are binary ELFs, and EFI variables are not pure text either. */
|
||||||
if (e->type == BOOT_ENTRY_CONF)
|
if (e->type == BOOT_ENTRY_TYPE1)
|
||||||
(void) terminal_urlify_path(e->path, text, &link);
|
(void) terminal_urlify_path(e->path, text, &link);
|
||||||
|
|
||||||
printf(" source: %s (on the %s)\n",
|
printf(" source: %s (on the %s)\n",
|
||||||
link ?: text ?: e->path,
|
link ?: text ?: e->path,
|
||||||
boot_entry_source_to_string(e->source));
|
boot_entry_source_description_to_string(e->source));
|
||||||
}
|
}
|
||||||
if (e->tries_left != UINT_MAX) {
|
if (e->tries_left != UINT_MAX) {
|
||||||
printf(" tries: %u left", e->tries_left);
|
printf(" tries: %u left", e->tries_left);
|
||||||
@ -1942,8 +1942,8 @@ int boot_entry_to_json(const BootConfig *c, size_t i, sd_json_variant **ret) {
|
|||||||
|
|
||||||
r = sd_json_variant_merge_objectbo(
|
r = sd_json_variant_merge_objectbo(
|
||||||
&v,
|
&v,
|
||||||
SD_JSON_BUILD_PAIR("type", SD_JSON_BUILD_STRING(boot_entry_type_json_to_string(e->type))),
|
SD_JSON_BUILD_PAIR("type", SD_JSON_BUILD_STRING(boot_entry_type_to_string(e->type))),
|
||||||
SD_JSON_BUILD_PAIR("source", SD_JSON_BUILD_STRING(boot_entry_source_json_to_string(e->source))),
|
SD_JSON_BUILD_PAIR("source", SD_JSON_BUILD_STRING(boot_entry_source_to_string(e->source))),
|
||||||
SD_JSON_BUILD_PAIR_CONDITION(!!e->id, "id", SD_JSON_BUILD_STRING(e->id)),
|
SD_JSON_BUILD_PAIR_CONDITION(!!e->id, "id", SD_JSON_BUILD_STRING(e->id)),
|
||||||
SD_JSON_BUILD_PAIR_CONDITION(!!e->path, "path", SD_JSON_BUILD_STRING(e->path)),
|
SD_JSON_BUILD_PAIR_CONDITION(!!e->path, "path", SD_JSON_BUILD_STRING(e->path)),
|
||||||
SD_JSON_BUILD_PAIR_CONDITION(!!e->root, "root", SD_JSON_BUILD_STRING(e->root)),
|
SD_JSON_BUILD_PAIR_CONDITION(!!e->root, "root", SD_JSON_BUILD_STRING(e->root)),
|
||||||
|
@ -5,10 +5,10 @@
|
|||||||
#include "forward.h"
|
#include "forward.h"
|
||||||
|
|
||||||
typedef enum BootEntryType {
|
typedef enum BootEntryType {
|
||||||
BOOT_ENTRY_CONF, /* Boot Loader Specification Type #1 entries: *.conf files */
|
BOOT_ENTRY_TYPE1, /* Boot Loader Specification Type #1 entries: *.conf files */
|
||||||
BOOT_ENTRY_UNIFIED, /* Boot Loader Specification Type #2 entries: *.efi files */
|
BOOT_ENTRY_TYPE2, /* Boot Loader Specification Type #2 entries: *.efi files (UKIs) */
|
||||||
BOOT_ENTRY_LOADER, /* Additional entries augmented from LoaderEntries EFI variable (regular entries) */
|
BOOT_ENTRY_LOADER, /* Additional entries augmented from LoaderEntries EFI variable (regular entries) */
|
||||||
BOOT_ENTRY_LOADER_AUTO, /* Additional entries augmented from LoaderEntries EFI variable (special "automatic" entries) */
|
BOOT_ENTRY_AUTO, /* Additional entries augmented from LoaderEntries EFI variable (special "automatic" entries) */
|
||||||
_BOOT_ENTRY_TYPE_MAX,
|
_BOOT_ENTRY_TYPE_MAX,
|
||||||
_BOOT_ENTRY_TYPE_INVALID = -EINVAL,
|
_BOOT_ENTRY_TYPE_INVALID = -EINVAL,
|
||||||
} BootEntryType;
|
} BootEntryType;
|
||||||
@ -91,11 +91,11 @@ typedef struct BootConfig {
|
|||||||
.selected_entry = -1, \
|
.selected_entry = -1, \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* boot_entry_type_description_to_string(BootEntryType) _const_;
|
||||||
const char* boot_entry_type_to_string(BootEntryType) _const_;
|
const char* boot_entry_type_to_string(BootEntryType) _const_;
|
||||||
const char* boot_entry_type_json_to_string(BootEntryType) _const_;
|
|
||||||
|
|
||||||
|
const char* boot_entry_source_description_to_string(BootEntrySource) _const_;
|
||||||
const char* boot_entry_source_to_string(BootEntrySource) _const_;
|
const char* boot_entry_source_to_string(BootEntrySource) _const_;
|
||||||
const char* boot_entry_source_json_to_string(BootEntrySource) _const_;
|
|
||||||
|
|
||||||
BootEntry* boot_config_find_entry(BootConfig *config, const char *id);
|
BootEntry* boot_config_find_entry(BootConfig *config, const char *id);
|
||||||
|
|
||||||
|
@ -2059,6 +2059,31 @@ static int bus_append_directory(sd_bus_message *m, const char *field, const char
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int bus_append_quota_directory(sd_bus_message *m, const char *field, const char *eq) {
|
||||||
|
uint64_t quota_absolute = UINT64_MAX;
|
||||||
|
uint32_t quota_scale = UINT32_MAX;
|
||||||
|
int quota_enforce = false;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (!isempty(eq) && !streq(eq, "off")) {
|
||||||
|
r = parse_permyriad(eq);
|
||||||
|
if (r < 0) {
|
||||||
|
r = parse_size(eq, 1024, "a_absolute);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse argument: %s=%s", field, eq);
|
||||||
|
} else
|
||||||
|
quota_scale = UINT32_SCALE_FROM_PERMYRIAD(r);
|
||||||
|
|
||||||
|
quota_enforce = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = sd_bus_message_append(m, "(sv)", field, "(tus)", quota_absolute, quota_scale, yes_no(quota_enforce));
|
||||||
|
if (r < 0)
|
||||||
|
return bus_log_create_error(r);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static int bus_append_protect_hostname(sd_bus_message *m, const char *field, const char *eq) {
|
static int bus_append_protect_hostname(sd_bus_message *m, const char *field, const char *eq) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -2514,6 +2539,12 @@ static const BusProperty execute_properties[] = {
|
|||||||
{ "ProtectControlGroupsEx", bus_append_boolean_or_ex_string }, /* compat */
|
{ "ProtectControlGroupsEx", bus_append_boolean_or_ex_string }, /* compat */
|
||||||
{ "PrivateUsers", bus_append_boolean_or_ex_string },
|
{ "PrivateUsers", bus_append_boolean_or_ex_string },
|
||||||
{ "PrivateUsersEx", bus_append_boolean_or_ex_string }, /* compat */
|
{ "PrivateUsersEx", bus_append_boolean_or_ex_string }, /* compat */
|
||||||
|
{ "StateDirectoryQuota", bus_append_quota_directory },
|
||||||
|
{ "CacheDirectoryQuota", bus_append_quota_directory },
|
||||||
|
{ "LogsDirectoryQuota", bus_append_quota_directory },
|
||||||
|
{ "StateDirectoryAccounting", bus_append_parse_boolean },
|
||||||
|
{ "CacheDirectoryAccounting", bus_append_parse_boolean },
|
||||||
|
{ "LogsDirectoryAccounting", bus_append_parse_boolean },
|
||||||
|
|
||||||
{ NULL, bus_try_append_resource_limit, dump_resource_limits },
|
{ NULL, bus_try_append_resource_limit, dump_resource_limits },
|
||||||
{}
|
{}
|
||||||
|
15
src/shared/exec-directory-util.c
Normal file
15
src/shared/exec-directory-util.c
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
|
||||||
|
#include "exec-directory-util.h"
|
||||||
|
#include "string-table.h"
|
||||||
|
|
||||||
|
/* This table maps ExecDirectoryType to the setting it is configured with in the unit */
|
||||||
|
static const char* const exec_directory_type_table[_EXEC_DIRECTORY_TYPE_MAX] = {
|
||||||
|
[EXEC_DIRECTORY_RUNTIME] = "RuntimeDirectory",
|
||||||
|
[EXEC_DIRECTORY_STATE] = "StateDirectory",
|
||||||
|
[EXEC_DIRECTORY_CACHE] = "CacheDirectory",
|
||||||
|
[EXEC_DIRECTORY_LOGS] = "LogsDirectory",
|
||||||
|
[EXEC_DIRECTORY_CONFIGURATION] = "ConfigurationDirectory",
|
||||||
|
};
|
||||||
|
|
||||||
|
DEFINE_STRING_TABLE_LOOKUP(exec_directory_type, ExecDirectoryType);
|
19
src/shared/exec-directory-util.h
Normal file
19
src/shared/exec-directory-util.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "macro-fundamental.h"
|
||||||
|
|
||||||
|
typedef enum ExecDirectoryType {
|
||||||
|
EXEC_DIRECTORY_RUNTIME,
|
||||||
|
EXEC_DIRECTORY_STATE,
|
||||||
|
EXEC_DIRECTORY_CACHE,
|
||||||
|
EXEC_DIRECTORY_LOGS,
|
||||||
|
EXEC_DIRECTORY_CONFIGURATION,
|
||||||
|
_EXEC_DIRECTORY_TYPE_MAX,
|
||||||
|
_EXEC_DIRECTORY_TYPE_INVALID = -EINVAL,
|
||||||
|
} ExecDirectoryType;
|
||||||
|
|
||||||
|
const char* exec_directory_type_to_string(ExecDirectoryType i) _const_;
|
||||||
|
ExecDirectoryType exec_directory_type_from_string(const char *s) _pure_;
|
@ -69,6 +69,7 @@ shared_sources = files(
|
|||||||
'elf-util.c',
|
'elf-util.c',
|
||||||
'enable-mempool.c',
|
'enable-mempool.c',
|
||||||
'ethtool-util.c',
|
'ethtool-util.c',
|
||||||
|
'exec-directory-util.c',
|
||||||
'exec-util.c',
|
'exec-util.c',
|
||||||
'exit-status.c',
|
'exit-status.c',
|
||||||
'extension-util.c',
|
'extension-util.c',
|
||||||
|
@ -1441,6 +1441,28 @@ int make_userns(uid_t uid_shift,
|
|||||||
return TAKE_FD(userns_fd);
|
return TAKE_FD(userns_fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int open_tree_attr_fallback(int dir_fd, const char *path, unsigned int flags, struct mount_attr *attr) {
|
||||||
|
assert(attr);
|
||||||
|
|
||||||
|
_cleanup_close_ int fd = open_tree_attr(dir_fd, path, flags, attr, sizeof(struct mount_attr));
|
||||||
|
if (fd >= 0)
|
||||||
|
return TAKE_FD(fd);
|
||||||
|
if (!ERRNO_IS_NOT_SUPPORTED(errno))
|
||||||
|
return log_debug_errno(errno, "Failed to open tree and set mount attributes: %m");
|
||||||
|
|
||||||
|
if (attr->attr_clr & MOUNT_ATTR_IDMAP)
|
||||||
|
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Cannot clear idmap from mount without open_tree_attr()");
|
||||||
|
|
||||||
|
fd = open_tree(dir_fd, path, flags);
|
||||||
|
if (fd < 0)
|
||||||
|
return log_debug_errno(errno, "Failed to open tree: %m");
|
||||||
|
|
||||||
|
if (mount_setattr(fd, "", AT_EMPTY_PATH | (flags & AT_RECURSIVE), attr, sizeof(struct mount_attr)) < 0)
|
||||||
|
return log_debug_errno(errno, "Failed to change mount attributes: %m");
|
||||||
|
|
||||||
|
return TAKE_FD(fd);
|
||||||
|
}
|
||||||
|
|
||||||
int remount_idmap_fd(
|
int remount_idmap_fd(
|
||||||
char **paths,
|
char **paths,
|
||||||
int userns_fd,
|
int userns_fd,
|
||||||
@ -1469,22 +1491,19 @@ int remount_idmap_fd(
|
|||||||
CLEANUP_ARRAY(mount_fds, n_mounts_fds, close_many_and_free);
|
CLEANUP_ARRAY(mount_fds, n_mounts_fds, close_many_and_free);
|
||||||
|
|
||||||
for (size_t i = 0; i < n; i++) {
|
for (size_t i = 0; i < n; i++) {
|
||||||
int mntfd;
|
/* Clone the mount point and et the user namespace mapping attribute on the cloned mount point. */
|
||||||
|
mount_fds[n_mounts_fds] = open_tree_attr_fallback(
|
||||||
/* Clone the mount point */
|
/* dir_fd= */ -EBADF,
|
||||||
mntfd = mount_fds[n_mounts_fds] = open_tree(-EBADF, paths[i], OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC);
|
paths[i],
|
||||||
if (mount_fds[n_mounts_fds] < 0)
|
OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC,
|
||||||
return log_debug_errno(errno, "Failed to open tree of mounted filesystem '%s': %m", paths[i]);
|
|
||||||
|
|
||||||
n_mounts_fds++;
|
|
||||||
|
|
||||||
/* Set the user namespace mapping attribute on the cloned mount point */
|
|
||||||
if (mount_setattr(mntfd, "", AT_EMPTY_PATH,
|
|
||||||
&(struct mount_attr) {
|
&(struct mount_attr) {
|
||||||
.attr_set = MOUNT_ATTR_IDMAP | extra_mount_attr_set,
|
.attr_set = MOUNT_ATTR_IDMAP | extra_mount_attr_set,
|
||||||
.userns_fd = userns_fd,
|
.userns_fd = userns_fd,
|
||||||
}, sizeof(struct mount_attr)) < 0)
|
});
|
||||||
return log_debug_errno(errno, "Failed to change bind mount attributes for clone of '%s': %m", paths[i]);
|
if (mount_fds[n_mounts_fds] < 0)
|
||||||
|
return mount_fds[n_mounts_fds];
|
||||||
|
|
||||||
|
n_mounts_fds++;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = n; i > 0; i--) { /* Unmount the paths right-to-left */
|
for (size_t i = n; i > 0; i--) { /* Unmount the paths right-to-left */
|
||||||
|
@ -148,6 +148,8 @@ typedef enum RemountIdmapping {
|
|||||||
_REMOUNT_IDMAPPING_INVALID = -EINVAL,
|
_REMOUNT_IDMAPPING_INVALID = -EINVAL,
|
||||||
} RemountIdmapping;
|
} RemountIdmapping;
|
||||||
|
|
||||||
|
int open_tree_attr_fallback(int dir_fd, const char *path, unsigned int flags, struct mount_attr *attr);
|
||||||
|
|
||||||
int make_userns(uid_t uid_shift, uid_t uid_range, uid_t host_owner, uid_t dest_owner, RemountIdmapping idmapping);
|
int make_userns(uid_t uid_shift, uid_t uid_range, uid_t host_owner, uid_t dest_owner, RemountIdmapping idmapping);
|
||||||
int remount_idmap_fd(char **p, int userns_fd, uint64_t extra_mount_attr_set);
|
int remount_idmap_fd(char **p, int userns_fd, uint64_t extra_mount_attr_set);
|
||||||
int remount_idmap(char **p, uid_t uid_shift, uid_t uid_range, uid_t host_owner, uid_t dest_owner, RemountIdmapping idmapping);
|
int remount_idmap(char **p, uid_t uid_shift, uid_t uid_range, uid_t host_owner, uid_t dest_owner, RemountIdmapping idmapping);
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
#include "blockdev-util.h"
|
#include "blockdev-util.h"
|
||||||
|
#include "chattr-util.h"
|
||||||
#include "device-util.h"
|
#include "device-util.h"
|
||||||
#include "errno-util.h"
|
#include "errno-util.h"
|
||||||
#include "missing_syscall.h"
|
#include "missing_syscall.h"
|
||||||
@ -33,3 +34,66 @@ int quotactl_fd_with_fallback(int fd, int cmd, int id, void *addr) {
|
|||||||
|
|
||||||
return RET_NERRNO(quotactl(cmd, devnode, id, addr));
|
return RET_NERRNO(quotactl(cmd, devnode, id, addr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int quota_query_proj_id(int fd, uint32_t proj_id, struct dqblk *ret_req) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(fd >= 0);
|
||||||
|
assert(ret_req);
|
||||||
|
|
||||||
|
r = quotactl_fd_with_fallback(fd, QCMD_FIXED(Q_GETQUOTA, PRJQUOTA), proj_id, ret_req);
|
||||||
|
if (r == -ESRCH || ERRNO_IS_NEG_NOT_SUPPORTED(r) || ERRNO_IS_NEG_PRIVILEGE(r)) {
|
||||||
|
zero(ret_req);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int quota_proj_id_set_recursive(int fd, uint32_t proj_id, bool verify_exclusive) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(fd >= 0);
|
||||||
|
|
||||||
|
/* Confirm only the current inode has the project id (in case of race conditions) */
|
||||||
|
if (verify_exclusive) {
|
||||||
|
/* Set to top level first because of the case where directories already exist with multiple subdirectories,
|
||||||
|
* in which case, number of inodes will be > 1 if applied recursively only */
|
||||||
|
r = set_proj_id(fd, proj_id);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
struct dqblk req;
|
||||||
|
r = quotactl_fd_with_fallback(fd, QCMD_FIXED(Q_GETQUOTA, PRJQUOTA), proj_id, &req);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (req.dqb_curinodes == 0)
|
||||||
|
return -ENOTRECOVERABLE;
|
||||||
|
|
||||||
|
if (req.dqb_curinodes != 1)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = set_proj_id_recursive(fd, proj_id);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool quota_dqblk_is_populated(const struct dqblk *req) {
|
||||||
|
assert(req);
|
||||||
|
|
||||||
|
return FLAGS_SET(req->dqb_valid, QIF_BLIMITS|QIF_SPACE|QIF_ILIMITS|QIF_INODES|QIF_BTIME|QIF_ITIME) &&
|
||||||
|
(req->dqb_bhardlimit > 0 ||
|
||||||
|
req->dqb_bsoftlimit > 0 ||
|
||||||
|
req->dqb_ihardlimit > 0 ||
|
||||||
|
req->dqb_isoftlimit > 0 ||
|
||||||
|
req->dqb_curspace > 0 ||
|
||||||
|
req->dqb_curinodes > 0 ||
|
||||||
|
req->dqb_btime > 0 ||
|
||||||
|
req->dqb_itime > 0);
|
||||||
|
}
|
||||||
|
@ -16,3 +16,6 @@ static inline int QCMD_FIXED(uint32_t cmd, uint32_t type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int quotactl_fd_with_fallback(int fd, int cmd, int id, void *addr);
|
int quotactl_fd_with_fallback(int fd, int cmd, int id, void *addr);
|
||||||
|
int quota_query_proj_id(int fd, uint32_t proj_id, struct dqblk *ret_req);
|
||||||
|
int quota_proj_id_set_recursive(int fd, uint32_t proj_id, bool verify_exclusive);
|
||||||
|
bool quota_dqblk_is_populated(const struct dqblk *dqblk);
|
||||||
|
@ -20,6 +20,9 @@ int verb_kill(int argc, char *argv[], void *userdata) {
|
|||||||
sd_bus *bus;
|
sd_bus *bus;
|
||||||
int r, q;
|
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);
|
r = acquire_bus(BUS_MANAGER, &bus);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
@ -32,7 +35,7 @@ int verb_kill(int argc, char *argv[], void *userdata) {
|
|||||||
|
|
||||||
polkit_agent_open_maybe();
|
polkit_agent_open_maybe();
|
||||||
|
|
||||||
kill_whom = arg_kill_whom ?: "all";
|
kill_whom = arg_kill_whom ?: arg_kill_subgroup ? "cgroup" : "all";
|
||||||
|
|
||||||
/* --fail was specified */
|
/* --fail was specified */
|
||||||
if (streq(arg_job_mode(), "fail"))
|
if (streq(arg_job_mode(), "fail"))
|
||||||
@ -53,6 +56,14 @@ int verb_kill(int argc, char *argv[], void *userdata) {
|
|||||||
&error,
|
&error,
|
||||||
NULL,
|
NULL,
|
||||||
"ssii", *name, kill_whom, arg_signal, arg_kill_value);
|
"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
|
else
|
||||||
q = bus_call_method(
|
q = bus_call_method(
|
||||||
bus,
|
bus,
|
||||||
|
@ -15,8 +15,10 @@
|
|||||||
#include "cgroup-show.h"
|
#include "cgroup-show.h"
|
||||||
#include "cpu-set-util.h"
|
#include "cpu-set-util.h"
|
||||||
#include "errno-util.h"
|
#include "errno-util.h"
|
||||||
|
#include "exec-directory-util.h"
|
||||||
#include "exec-util.h"
|
#include "exec-util.h"
|
||||||
#include "exit-status.h"
|
#include "exit-status.h"
|
||||||
|
#include "extract-word.h"
|
||||||
#include "format-util.h"
|
#include "format-util.h"
|
||||||
#include "hexdecoct.h"
|
#include "hexdecoct.h"
|
||||||
#include "hostname-setup.h"
|
#include "hostname-setup.h"
|
||||||
@ -33,6 +35,7 @@
|
|||||||
#include "pager.h"
|
#include "pager.h"
|
||||||
#include "parse-util.h"
|
#include "parse-util.h"
|
||||||
#include "path-util.h"
|
#include "path-util.h"
|
||||||
|
#include "percent-util.h"
|
||||||
#include "pretty-print.h"
|
#include "pretty-print.h"
|
||||||
#include "process-util.h"
|
#include "process-util.h"
|
||||||
#include "set.h"
|
#include "set.h"
|
||||||
@ -161,6 +164,13 @@ typedef struct UnitCondition {
|
|||||||
LIST_FIELDS(struct UnitCondition, conditions);
|
LIST_FIELDS(struct UnitCondition, conditions);
|
||||||
} UnitCondition;
|
} UnitCondition;
|
||||||
|
|
||||||
|
typedef struct QuotaInfo {
|
||||||
|
bool quota_enforce;
|
||||||
|
bool quota_accounting;
|
||||||
|
uint64_t quota_usage;
|
||||||
|
uint64_t quota_limit;
|
||||||
|
} QuotaInfo;
|
||||||
|
|
||||||
static UnitCondition* unit_condition_free(UnitCondition *c) {
|
static UnitCondition* unit_condition_free(UnitCondition *c) {
|
||||||
if (!c)
|
if (!c)
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -299,6 +309,9 @@ typedef struct UnitStatusInfo {
|
|||||||
uint64_t default_memory_low;
|
uint64_t default_memory_low;
|
||||||
uint64_t default_startup_memory_low;
|
uint64_t default_startup_memory_low;
|
||||||
|
|
||||||
|
/* Exec Quotas */
|
||||||
|
QuotaInfo exec_directories_quota[_EXEC_DIRECTORY_TYPE_MAX];
|
||||||
|
|
||||||
LIST_HEAD(ExecStatusInfo, exec_status_info_list);
|
LIST_HEAD(ExecStatusInfo, exec_status_info_list);
|
||||||
} UnitStatusInfo;
|
} UnitStatusInfo;
|
||||||
|
|
||||||
@ -338,6 +351,22 @@ static void format_enable_state(const char *enable_state, const char **enable_on
|
|||||||
*enable_on = *enable_off = "";
|
*enable_on = *enable_off = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void print_exec_directory_quota(UnitStatusInfo *i, ExecDirectoryType dt) {
|
||||||
|
assert(i);
|
||||||
|
|
||||||
|
if (!IN_SET(dt, EXEC_DIRECTORY_STATE, EXEC_DIRECTORY_CACHE, EXEC_DIRECTORY_LOGS))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (i->exec_directories_quota[dt].quota_accounting) {
|
||||||
|
printf(" %s: %s", exec_directory_type_to_string(dt), FORMAT_BYTES(i->exec_directories_quota[dt].quota_usage));
|
||||||
|
|
||||||
|
if (i->exec_directories_quota[dt].quota_enforce)
|
||||||
|
printf(" (max: %s)", FORMAT_BYTES(i->exec_directories_quota[dt].quota_limit));
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void print_status_info(
|
static void print_status_info(
|
||||||
sd_bus *bus,
|
sd_bus *bus,
|
||||||
UnitStatusInfo *i,
|
UnitStatusInfo *i,
|
||||||
@ -877,6 +906,9 @@ static void print_status_info(
|
|||||||
if (i->cpu_usage_nsec != UINT64_MAX)
|
if (i->cpu_usage_nsec != UINT64_MAX)
|
||||||
printf(" CPU: %s\n", FORMAT_TIMESPAN(i->cpu_usage_nsec / NSEC_PER_USEC, USEC_PER_MSEC));
|
printf(" CPU: %s\n", FORMAT_TIMESPAN(i->cpu_usage_nsec / NSEC_PER_USEC, USEC_PER_MSEC));
|
||||||
|
|
||||||
|
for (ExecDirectoryType dt = 0; dt < _EXEC_DIRECTORY_TYPE_MAX; dt++)
|
||||||
|
print_exec_directory_quota(i, dt);
|
||||||
|
|
||||||
if (i->control_group) {
|
if (i->control_group) {
|
||||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||||
static const char prefix[] = " ";
|
static const char prefix[] = " ";
|
||||||
@ -1122,6 +1154,25 @@ static int map_exec(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_e
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int map_quota(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
|
||||||
|
int r;
|
||||||
|
QuotaInfo *qi = ASSERT_PTR(userdata);
|
||||||
|
uint64_t quota_usage, quota_limit;
|
||||||
|
|
||||||
|
r = sd_bus_message_read(m, "(tt)", "a_usage, "a_limit);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
*qi = (QuotaInfo) {
|
||||||
|
.quota_enforce = quota_limit != UINT64_MAX,
|
||||||
|
.quota_accounting = quota_usage != UINT64_MAX,
|
||||||
|
.quota_usage = quota_usage,
|
||||||
|
.quota_limit = quota_limit
|
||||||
|
};
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int print_property(const char *name, const char *expected_value, sd_bus_message *m, BusPrintPropertyFlags flags) {
|
static int print_property(const char *name, const char *expected_value, sd_bus_message *m, BusPrintPropertyFlags flags) {
|
||||||
char bus_type;
|
char bus_type;
|
||||||
const char *contents;
|
const char *contents;
|
||||||
@ -1338,6 +1389,27 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m
|
|||||||
fputc('\n', stdout);
|
fputc('\n', stdout);
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
|
} else if (STR_IN_SET(name, "StateDirectoryQuota", "CacheDirectoryQuota", "LogsDirectoryQuota")) {
|
||||||
|
uint64_t quota_absolute;
|
||||||
|
uint32_t quota_scale;
|
||||||
|
const char *quota_enforce;
|
||||||
|
|
||||||
|
r = sd_bus_message_read(m, "(tus)", "a_absolute, "a_scale, "a_enforce);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = parse_boolean(quota_enforce);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (!r)
|
||||||
|
bus_print_property_value(name, expected_value, flags, "[not set]");
|
||||||
|
else if (quota_absolute != UINT64_MAX)
|
||||||
|
bus_print_property_valuef(name, expected_value, flags, "%" PRIu64, quota_absolute);
|
||||||
|
else
|
||||||
|
bus_print_property_valuef(name, expected_value, flags, "%d%%", UINT32_SCALE_TO_PERCENT(quota_scale));
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -2201,6 +2273,9 @@ static int show_one(
|
|||||||
{ "IPEgressBytes", "t", NULL, offsetof(UnitStatusInfo, ip_egress_bytes) },
|
{ "IPEgressBytes", "t", NULL, offsetof(UnitStatusInfo, ip_egress_bytes) },
|
||||||
{ "IOReadBytes", "t", NULL, offsetof(UnitStatusInfo, io_read_bytes) },
|
{ "IOReadBytes", "t", NULL, offsetof(UnitStatusInfo, io_read_bytes) },
|
||||||
{ "IOWriteBytes", "t", NULL, offsetof(UnitStatusInfo, io_write_bytes) },
|
{ "IOWriteBytes", "t", NULL, offsetof(UnitStatusInfo, io_write_bytes) },
|
||||||
|
{ "StateDirectoryQuotaUsage", "(tt)", map_quota, offsetof(UnitStatusInfo, exec_directories_quota[EXEC_DIRECTORY_STATE]) },
|
||||||
|
{ "CacheDirectoryQuotaUsage", "(tt)", map_quota, offsetof(UnitStatusInfo, exec_directories_quota[EXEC_DIRECTORY_CACHE]) },
|
||||||
|
{ "LogsDirectoryQuotaUsage", "(tt)", map_quota, offsetof(UnitStatusInfo, exec_directories_quota[EXEC_DIRECTORY_LOGS]) },
|
||||||
{ "ExecCondition", "a(sasbttttuii)", map_exec, 0 },
|
{ "ExecCondition", "a(sasbttttuii)", map_exec, 0 },
|
||||||
{ "ExecConditionEx", "a(sasasttttuii)", map_exec, 0 },
|
{ "ExecConditionEx", "a(sasasttttuii)", map_exec, 0 },
|
||||||
{ "ExecStartPre", "a(sasbttttuii)", map_exec, 0 },
|
{ "ExecStartPre", "a(sasbttttuii)", map_exec, 0 },
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include "pager.h"
|
#include "pager.h"
|
||||||
#include "parse-argument.h"
|
#include "parse-argument.h"
|
||||||
#include "parse-util.h"
|
#include "parse-util.h"
|
||||||
|
#include "path-util.h"
|
||||||
#include "pretty-print.h"
|
#include "pretty-print.h"
|
||||||
#include "static-destruct.h"
|
#include "static-destruct.h"
|
||||||
#include "string-table.h"
|
#include "string-table.h"
|
||||||
@ -88,6 +89,7 @@ bool arg_mkdir = false;
|
|||||||
bool arg_marked = false;
|
bool arg_marked = false;
|
||||||
const char *arg_drop_in = NULL;
|
const char *arg_drop_in = NULL;
|
||||||
ImagePolicy *arg_image_policy = NULL;
|
ImagePolicy *arg_image_policy = NULL;
|
||||||
|
char *arg_kill_subgroup = NULL;
|
||||||
|
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_types, strv_freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_types, strv_freep);
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_states, strv_freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_states, strv_freep);
|
||||||
@ -103,6 +105,7 @@ STATIC_DESTRUCTOR_REGISTER(arg_boot_loader_entry, unsetp);
|
|||||||
STATIC_DESTRUCTOR_REGISTER(arg_clean_what, strv_freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_clean_what, strv_freep);
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_drop_in, unsetp);
|
STATIC_DESTRUCTOR_REGISTER(arg_drop_in, unsetp);
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep);
|
||||||
|
STATIC_DESTRUCTOR_REGISTER(arg_kill_subgroup, freep);
|
||||||
|
|
||||||
static int systemctl_help(void) {
|
static int systemctl_help(void) {
|
||||||
_cleanup_free_ char *link = NULL;
|
_cleanup_free_ char *link = NULL;
|
||||||
@ -253,9 +256,11 @@ static int systemctl_help(void) {
|
|||||||
" Whether to check inhibitors before shutting down,\n"
|
" Whether to check inhibitors before shutting down,\n"
|
||||||
" sleeping, or hibernating\n"
|
" sleeping, or hibernating\n"
|
||||||
" -i Shortcut for --check-inhibitors=no\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-whom=WHOM Whom to send signal to\n"
|
||||||
" --kill-value=INT Signal value to enqueue\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"
|
" --what=RESOURCES Which types of resources to remove\n"
|
||||||
" --now Start or stop unit after enabling or disabling it\n"
|
" --now Start or stop unit after enabling or disabling it\n"
|
||||||
" --dry-run Only print what would be done\n"
|
" --dry-run Only print what would be done\n"
|
||||||
@ -438,6 +443,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
|
|||||||
ARG_DROP_IN,
|
ARG_DROP_IN,
|
||||||
ARG_WHEN,
|
ARG_WHEN,
|
||||||
ARG_STDIN,
|
ARG_STDIN,
|
||||||
|
ARG_KILL_SUBGROUP,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct option options[] = {
|
static const struct option options[] = {
|
||||||
@ -507,6 +513,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
|
|||||||
{ "drop-in", required_argument, NULL, ARG_DROP_IN },
|
{ "drop-in", required_argument, NULL, ARG_DROP_IN },
|
||||||
{ "when", required_argument, NULL, ARG_WHEN },
|
{ "when", required_argument, NULL, ARG_WHEN },
|
||||||
{ "stdin", no_argument, NULL, ARG_STDIN },
|
{ "stdin", no_argument, NULL, ARG_STDIN },
|
||||||
|
{ "kill-subgroup", required_argument, NULL, ARG_KILL_SUBGROUP },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1021,6 +1028,23 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
|
|||||||
arg_stdin = true;
|
arg_stdin = true;
|
||||||
break;
|
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 '.':
|
case '.':
|
||||||
/* Output an error mimicking getopt, and print a hint afterwards */
|
/* Output an error mimicking getopt, and print a hint afterwards */
|
||||||
log_error("%s: invalid option -- '.'", program_invocation_name);
|
log_error("%s: invalid option -- '.'", program_invocation_name);
|
||||||
|
@ -100,6 +100,7 @@ extern bool arg_mkdir;
|
|||||||
extern bool arg_marked;
|
extern bool arg_marked;
|
||||||
extern const char *arg_drop_in;
|
extern const char *arg_drop_in;
|
||||||
extern ImagePolicy *arg_image_policy;
|
extern ImagePolicy *arg_image_policy;
|
||||||
|
extern char *arg_kill_subgroup;
|
||||||
|
|
||||||
static inline const char* arg_job_mode(void) {
|
static inline const char* arg_job_mode(void) {
|
||||||
return _arg_job_mode ?: "replace";
|
return _arg_job_mode ?: "replace";
|
||||||
|
@ -73,9 +73,9 @@ TEST_RET(cgroup_mask, .sd_booted = true) {
|
|||||||
ASSERT_CGROUP_MASK(unit_get_own_mask(son), CGROUP_MASK_CPU);
|
ASSERT_CGROUP_MASK(unit_get_own_mask(son), CGROUP_MASK_CPU);
|
||||||
ASSERT_CGROUP_MASK(unit_get_own_mask(grandchild), 0);
|
ASSERT_CGROUP_MASK(unit_get_own_mask(grandchild), 0);
|
||||||
ASSERT_CGROUP_MASK(unit_get_own_mask(parent_deep), CGROUP_MASK_MEMORY);
|
ASSERT_CGROUP_MASK(unit_get_own_mask(parent_deep), CGROUP_MASK_MEMORY);
|
||||||
ASSERT_CGROUP_MASK(unit_get_own_mask(parent), (CGROUP_MASK_IO | CGROUP_MASK_BLKIO));
|
ASSERT_CGROUP_MASK(unit_get_own_mask(parent), CGROUP_MASK_IO);
|
||||||
ASSERT_CGROUP_MASK(unit_get_own_mask(nomem_parent), 0);
|
ASSERT_CGROUP_MASK(unit_get_own_mask(nomem_parent), 0);
|
||||||
ASSERT_CGROUP_MASK(unit_get_own_mask(nomem_leaf), (CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY));
|
ASSERT_CGROUP_MASK(unit_get_own_mask(nomem_leaf), (CGROUP_MASK_IO | CGROUP_MASK_MEMORY));
|
||||||
ASSERT_CGROUP_MASK(unit_get_own_mask(root), 0);
|
ASSERT_CGROUP_MASK(unit_get_own_mask(root), 0);
|
||||||
|
|
||||||
/* Verify aggregation of member masks */
|
/* Verify aggregation of member masks */
|
||||||
@ -84,29 +84,29 @@ TEST_RET(cgroup_mask, .sd_booted = true) {
|
|||||||
ASSERT_CGROUP_MASK(unit_get_members_mask(grandchild), 0);
|
ASSERT_CGROUP_MASK(unit_get_members_mask(grandchild), 0);
|
||||||
ASSERT_CGROUP_MASK(unit_get_members_mask(parent_deep), 0);
|
ASSERT_CGROUP_MASK(unit_get_members_mask(parent_deep), 0);
|
||||||
ASSERT_CGROUP_MASK(unit_get_members_mask(parent), (CGROUP_MASK_CPU | CGROUP_MASK_MEMORY));
|
ASSERT_CGROUP_MASK(unit_get_members_mask(parent), (CGROUP_MASK_CPU | CGROUP_MASK_MEMORY));
|
||||||
ASSERT_CGROUP_MASK(unit_get_members_mask(nomem_parent), (CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY));
|
ASSERT_CGROUP_MASK(unit_get_members_mask(nomem_parent), (CGROUP_MASK_IO | CGROUP_MASK_MEMORY));
|
||||||
ASSERT_CGROUP_MASK(unit_get_members_mask(nomem_leaf), 0);
|
ASSERT_CGROUP_MASK(unit_get_members_mask(nomem_leaf), 0);
|
||||||
ASSERT_CGROUP_MASK(unit_get_members_mask(root), (CGROUP_MASK_CPU | CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY));
|
ASSERT_CGROUP_MASK(unit_get_members_mask(root), (CGROUP_MASK_CPU | CGROUP_MASK_IO | CGROUP_MASK_MEMORY));
|
||||||
|
|
||||||
/* Verify aggregation of sibling masks. */
|
/* Verify aggregation of sibling masks. */
|
||||||
ASSERT_CGROUP_MASK(unit_get_siblings_mask(son), (CGROUP_MASK_CPU | CGROUP_MASK_MEMORY));
|
ASSERT_CGROUP_MASK(unit_get_siblings_mask(son), (CGROUP_MASK_CPU | CGROUP_MASK_MEMORY));
|
||||||
ASSERT_CGROUP_MASK(unit_get_siblings_mask(daughter), (CGROUP_MASK_CPU | CGROUP_MASK_MEMORY));
|
ASSERT_CGROUP_MASK(unit_get_siblings_mask(daughter), (CGROUP_MASK_CPU | CGROUP_MASK_MEMORY));
|
||||||
ASSERT_CGROUP_MASK(unit_get_siblings_mask(grandchild), 0);
|
ASSERT_CGROUP_MASK(unit_get_siblings_mask(grandchild), 0);
|
||||||
ASSERT_CGROUP_MASK(unit_get_siblings_mask(parent_deep), (CGROUP_MASK_CPU | CGROUP_MASK_MEMORY));
|
ASSERT_CGROUP_MASK(unit_get_siblings_mask(parent_deep), (CGROUP_MASK_CPU | CGROUP_MASK_MEMORY));
|
||||||
ASSERT_CGROUP_MASK(unit_get_siblings_mask(parent), (CGROUP_MASK_CPU | CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY));
|
ASSERT_CGROUP_MASK(unit_get_siblings_mask(parent), (CGROUP_MASK_CPU | CGROUP_MASK_IO | CGROUP_MASK_MEMORY));
|
||||||
ASSERT_CGROUP_MASK(unit_get_siblings_mask(nomem_parent), (CGROUP_MASK_CPU | CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY));
|
ASSERT_CGROUP_MASK(unit_get_siblings_mask(nomem_parent), (CGROUP_MASK_CPU | CGROUP_MASK_IO | CGROUP_MASK_MEMORY));
|
||||||
ASSERT_CGROUP_MASK(unit_get_siblings_mask(nomem_leaf), (CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY));
|
ASSERT_CGROUP_MASK(unit_get_siblings_mask(nomem_leaf), (CGROUP_MASK_IO | CGROUP_MASK_MEMORY));
|
||||||
ASSERT_CGROUP_MASK(unit_get_siblings_mask(root), (CGROUP_MASK_CPU | CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY));
|
ASSERT_CGROUP_MASK(unit_get_siblings_mask(root), (CGROUP_MASK_CPU | CGROUP_MASK_IO | CGROUP_MASK_MEMORY));
|
||||||
|
|
||||||
/* Verify aggregation of target masks. */
|
/* Verify aggregation of target masks. */
|
||||||
ASSERT_CGROUP_MASK(unit_get_target_mask(son), ((CGROUP_MASK_CPU | CGROUP_MASK_MEMORY) & m->cgroup_supported));
|
ASSERT_CGROUP_MASK(unit_get_target_mask(son), ((CGROUP_MASK_CPU | CGROUP_MASK_MEMORY) & m->cgroup_supported));
|
||||||
ASSERT_CGROUP_MASK(unit_get_target_mask(daughter), ((CGROUP_MASK_CPU | CGROUP_MASK_MEMORY) & m->cgroup_supported));
|
ASSERT_CGROUP_MASK(unit_get_target_mask(daughter), ((CGROUP_MASK_CPU | CGROUP_MASK_MEMORY) & m->cgroup_supported));
|
||||||
ASSERT_CGROUP_MASK(unit_get_target_mask(grandchild), 0);
|
ASSERT_CGROUP_MASK(unit_get_target_mask(grandchild), 0);
|
||||||
ASSERT_CGROUP_MASK(unit_get_target_mask(parent_deep), ((CGROUP_MASK_CPU | CGROUP_MASK_MEMORY) & m->cgroup_supported));
|
ASSERT_CGROUP_MASK(unit_get_target_mask(parent_deep), ((CGROUP_MASK_CPU | CGROUP_MASK_MEMORY) & m->cgroup_supported));
|
||||||
ASSERT_CGROUP_MASK(unit_get_target_mask(parent), ((CGROUP_MASK_CPU | CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY) & m->cgroup_supported));
|
ASSERT_CGROUP_MASK(unit_get_target_mask(parent), ((CGROUP_MASK_CPU | CGROUP_MASK_IO | CGROUP_MASK_MEMORY) & m->cgroup_supported));
|
||||||
ASSERT_CGROUP_MASK(unit_get_target_mask(nomem_parent), ((CGROUP_MASK_CPU | CGROUP_MASK_IO | CGROUP_MASK_BLKIO) & m->cgroup_supported));
|
ASSERT_CGROUP_MASK(unit_get_target_mask(nomem_parent), ((CGROUP_MASK_CPU | CGROUP_MASK_IO) & m->cgroup_supported));
|
||||||
ASSERT_CGROUP_MASK(unit_get_target_mask(nomem_leaf), ((CGROUP_MASK_IO | CGROUP_MASK_BLKIO) & m->cgroup_supported));
|
ASSERT_CGROUP_MASK(unit_get_target_mask(nomem_leaf), (CGROUP_MASK_IO & m->cgroup_supported));
|
||||||
ASSERT_CGROUP_MASK(unit_get_target_mask(root), ((CGROUP_MASK_CPU | CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY) & m->cgroup_supported));
|
ASSERT_CGROUP_MASK(unit_get_target_mask(root), ((CGROUP_MASK_CPU | CGROUP_MASK_IO | CGROUP_MASK_MEMORY) & m->cgroup_supported));
|
||||||
|
|
||||||
/* Verify aggregation of enable masks. */
|
/* Verify aggregation of enable masks. */
|
||||||
ASSERT_CGROUP_MASK(unit_get_enable_mask(son), 0);
|
ASSERT_CGROUP_MASK(unit_get_enable_mask(son), 0);
|
||||||
@ -114,9 +114,9 @@ TEST_RET(cgroup_mask, .sd_booted = true) {
|
|||||||
ASSERT_CGROUP_MASK(unit_get_enable_mask(grandchild), 0);
|
ASSERT_CGROUP_MASK(unit_get_enable_mask(grandchild), 0);
|
||||||
ASSERT_CGROUP_MASK(unit_get_enable_mask(parent_deep), 0);
|
ASSERT_CGROUP_MASK(unit_get_enable_mask(parent_deep), 0);
|
||||||
ASSERT_CGROUP_MASK(unit_get_enable_mask(parent), ((CGROUP_MASK_CPU | CGROUP_MASK_MEMORY) & m->cgroup_supported));
|
ASSERT_CGROUP_MASK(unit_get_enable_mask(parent), ((CGROUP_MASK_CPU | CGROUP_MASK_MEMORY) & m->cgroup_supported));
|
||||||
ASSERT_CGROUP_MASK(unit_get_enable_mask(nomem_parent), ((CGROUP_MASK_IO | CGROUP_MASK_BLKIO) & m->cgroup_supported));
|
ASSERT_CGROUP_MASK(unit_get_enable_mask(nomem_parent), (CGROUP_MASK_IO & m->cgroup_supported));
|
||||||
ASSERT_CGROUP_MASK(unit_get_enable_mask(nomem_leaf), 0);
|
ASSERT_CGROUP_MASK(unit_get_enable_mask(nomem_leaf), 0);
|
||||||
ASSERT_CGROUP_MASK(unit_get_enable_mask(root), ((CGROUP_MASK_CPU | CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY) & m->cgroup_supported));
|
ASSERT_CGROUP_MASK(unit_get_enable_mask(root), ((CGROUP_MASK_CPU | CGROUP_MASK_IO | CGROUP_MASK_MEMORY) & m->cgroup_supported));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,7 @@ static int time_handler(sd_event_source *s, uint64_t usec, void *userdata) {
|
|||||||
int r;
|
int r;
|
||||||
|
|
||||||
log_error("Test timeout when testing %s", unit->id);
|
log_error("Test timeout when testing %s", unit->id);
|
||||||
r = unit_kill(unit, KILL_ALL, SIGKILL, SI_USER, 0, NULL);
|
r = unit_kill(unit, KILL_ALL, /* subgroup= */ NULL, SIGKILL, SI_USER, /* value= */ 0, /* ret_error= */ NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_error_errno(r, "Failed to kill %s, ignoring: %m", unit->id);
|
log_error_errno(r, "Failed to kill %s, ignoring: %m", unit->id);
|
||||||
|
|
||||||
|
@ -1350,7 +1350,7 @@ static int discover_boot_entry(const char *root, char **ret_linux, char ***ret_i
|
|||||||
|
|
||||||
const BootEntry *boot_entry = boot_config_default_entry(&config);
|
const BootEntry *boot_entry = boot_config_default_entry(&config);
|
||||||
|
|
||||||
if (boot_entry && !IN_SET(boot_entry->type, BOOT_ENTRY_UNIFIED, BOOT_ENTRY_CONF))
|
if (boot_entry && !IN_SET(boot_entry->type, BOOT_ENTRY_TYPE1, BOOT_ENTRY_TYPE2))
|
||||||
boot_entry = NULL;
|
boot_entry = NULL;
|
||||||
|
|
||||||
/* If we cannot determine a default entry search for UKIs (Type #2 EFI Unified Kernel Images)
|
/* If we cannot determine a default entry search for UKIs (Type #2 EFI Unified Kernel Images)
|
||||||
@ -1358,14 +1358,14 @@ static int discover_boot_entry(const char *root, char **ret_linux, char ***ret_i
|
|||||||
* https://uapi-group.org/specifications/specs/boot_loader_specification */
|
* https://uapi-group.org/specifications/specs/boot_loader_specification */
|
||||||
if (!boot_entry)
|
if (!boot_entry)
|
||||||
FOREACH_ARRAY(entry, config.entries, config.n_entries)
|
FOREACH_ARRAY(entry, config.entries, config.n_entries)
|
||||||
if (entry->type == BOOT_ENTRY_UNIFIED) {
|
if (entry->type == BOOT_ENTRY_TYPE2) { /* UKI */
|
||||||
boot_entry = entry;
|
boot_entry = entry;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!boot_entry)
|
if (!boot_entry)
|
||||||
FOREACH_ARRAY(entry, config.entries, config.n_entries)
|
FOREACH_ARRAY(entry, config.entries, config.n_entries)
|
||||||
if (entry->type == BOOT_ENTRY_CONF) {
|
if (entry->type == BOOT_ENTRY_TYPE1) { /* .conf */
|
||||||
boot_entry = entry;
|
boot_entry = entry;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1373,15 +1373,15 @@ static int discover_boot_entry(const char *root, char **ret_linux, char ***ret_i
|
|||||||
if (!boot_entry)
|
if (!boot_entry)
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(ENOENT), "Failed to discover any boot entries.");
|
return log_error_errno(SYNTHETIC_ERRNO(ENOENT), "Failed to discover any boot entries.");
|
||||||
|
|
||||||
log_debug("Discovered boot entry %s (%s)", boot_entry->id, boot_entry_type_to_string(boot_entry->type));
|
log_debug("Discovered boot entry %s (%s)", boot_entry->id, boot_entry_type_description_to_string(boot_entry->type));
|
||||||
|
|
||||||
_cleanup_free_ char *linux_kernel = NULL;
|
_cleanup_free_ char *linux_kernel = NULL;
|
||||||
_cleanup_strv_free_ char **initrds = NULL;
|
_cleanup_strv_free_ char **initrds = NULL;
|
||||||
if (boot_entry->type == BOOT_ENTRY_UNIFIED) {
|
if (boot_entry->type == BOOT_ENTRY_TYPE2) { /* UKI */
|
||||||
linux_kernel = path_join(boot_entry->root, boot_entry->kernel);
|
linux_kernel = path_join(boot_entry->root, boot_entry->kernel);
|
||||||
if (!linux_kernel)
|
if (!linux_kernel)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
} else if (boot_entry->type == BOOT_ENTRY_CONF) {
|
} else if (boot_entry->type == BOOT_ENTRY_TYPE1) { /* .conf */
|
||||||
linux_kernel = path_join(boot_entry->root, boot_entry->kernel);
|
linux_kernel = path_join(boot_entry->root, boot_entry->kernel);
|
||||||
if (!linux_kernel)
|
if (!linux_kernel)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
@ -784,6 +784,8 @@ CPUSchedulingPriority=
|
|||||||
CPUSchedulingResetOnFork=
|
CPUSchedulingResetOnFork=
|
||||||
CacheDirectory=
|
CacheDirectory=
|
||||||
CacheDirectoryMode=
|
CacheDirectoryMode=
|
||||||
|
CacheDirectoryAccounting=
|
||||||
|
CacheDirectoryQuota=
|
||||||
Capability=
|
Capability=
|
||||||
Compress=
|
Compress=
|
||||||
ConfigurationDirectory=
|
ConfigurationDirectory=
|
||||||
@ -861,6 +863,8 @@ LogRateLimitBurst=
|
|||||||
LogFilterPatterns=
|
LogFilterPatterns=
|
||||||
LogsDirectory=
|
LogsDirectory=
|
||||||
LogsDirectoryMode=
|
LogsDirectoryMode=
|
||||||
|
LogsDirectoryAccounting=
|
||||||
|
LogsDirectoryQuota=
|
||||||
MACVLAN=
|
MACVLAN=
|
||||||
MachineID=
|
MachineID=
|
||||||
MaxFileSec=
|
MaxFileSec=
|
||||||
@ -943,6 +947,8 @@ StandardInputText=
|
|||||||
StandardOutput=
|
StandardOutput=
|
||||||
StateDirectory=
|
StateDirectory=
|
||||||
StateDirectoryMode=
|
StateDirectoryMode=
|
||||||
|
StateDirectoryAccounting=
|
||||||
|
StateDirectoryQuota=
|
||||||
Storage=
|
Storage=
|
||||||
SuspendKeyIgnoreInhibited=
|
SuspendKeyIgnoreInhibited=
|
||||||
SyncIntervalSec=
|
SyncIntervalSec=
|
||||||
|
95
test/units/TEST-07-PID1.quota.sh
Executable file
95
test/units/TEST-07-PID1.quota.sh
Executable file
@ -0,0 +1,95 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
# shellcheck disable=SC2016
|
||||||
|
set -eux
|
||||||
|
set -o pipefail
|
||||||
|
|
||||||
|
systemd-analyze log-level debug
|
||||||
|
|
||||||
|
test_quotas() {
|
||||||
|
|
||||||
|
local directory="$1"
|
||||||
|
local exec_directory_directive="$2"
|
||||||
|
local exec_quota_directive="$3"
|
||||||
|
local mountpoint="/datadrive"
|
||||||
|
|
||||||
|
dev_num=$(lsblk | grep "498M" | awk '{print $1}' | sed 's/[^a-zA-Z0-9]*//g')
|
||||||
|
|
||||||
|
if ! tune2fs -Q prjquota "/dev/${dev_num}"; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
mkdir -p "${mountpoint}"
|
||||||
|
mount "/dev/${dev_num}" "${mountpoint}"
|
||||||
|
|
||||||
|
mv /var/lib/ "${mountpoint}"
|
||||||
|
rm -rf /var/lib/ && ln -s "${mountpoint}/lib/" /var/
|
||||||
|
|
||||||
|
rm -rf "${directory}/quotadir"
|
||||||
|
|
||||||
|
cat >/run/systemd/system/testservice-07-check-quotas.service <<EOF
|
||||||
|
[Unit]
|
||||||
|
Description=Check quotas with ExecDirectory
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
# Relevant only for sanitizer runs
|
||||||
|
EnvironmentFile=-/usr/lib/systemd/systemd-asan-env
|
||||||
|
Type=oneshot
|
||||||
|
|
||||||
|
MountAPIVFS=yes
|
||||||
|
DynamicUser=yes
|
||||||
|
PrivateUsers=yes
|
||||||
|
TemporaryFileSystem=/run /var/opt /var/lib /vol
|
||||||
|
${exec_directory_directive}
|
||||||
|
${exec_quota_directive}
|
||||||
|
ExecStart=/bin/bash -c ' \
|
||||||
|
set -eux; \
|
||||||
|
set -o pipefail; \
|
||||||
|
touch ${directory}/quotadir/testfile; \
|
||||||
|
'
|
||||||
|
EOF
|
||||||
|
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl start testservice-07-check-quotas.service
|
||||||
|
|
||||||
|
proj_id=$(lsattr -p "${directory}" | grep "quotadir" | awk '{print $1}')
|
||||||
|
[[ $proj_id -gt 0 ]]
|
||||||
|
|
||||||
|
block_limit=$(repquota -P "${mountpoint}" | grep -E "#$proj_id " | awk '{print $5}')
|
||||||
|
inode_limit=$(repquota -P "${mountpoint}" | grep -E "#$proj_id " | awk '{print $8}')
|
||||||
|
[[ $block_limit -gt 0 ]]
|
||||||
|
[[ $inode_limit -gt 0 ]]
|
||||||
|
|
||||||
|
# Test exceed limit
|
||||||
|
rm -rf "${directory}/quotadir"
|
||||||
|
|
||||||
|
cat >/run/systemd/system/testservice-07-check-quotas.service <<EOF
|
||||||
|
[Unit]
|
||||||
|
Description=Check quotas with ExecDirectory
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
# Relevant only for sanitizer runs
|
||||||
|
EnvironmentFile=-/usr/lib/systemd/systemd-asan-env
|
||||||
|
Type=oneshot
|
||||||
|
|
||||||
|
MountAPIVFS=yes
|
||||||
|
DynamicUser=yes
|
||||||
|
PrivateUsers=yes
|
||||||
|
TemporaryFileSystem=/run /var/opt /var/lib /vol
|
||||||
|
${exec_directory_directive}
|
||||||
|
${exec_quota_directive}
|
||||||
|
ExecStart=/bin/bash -c ' \
|
||||||
|
set -eux; \
|
||||||
|
set -o pipefail; \
|
||||||
|
(! fallocate -l 10000G ${directory}/quotadir/largefile); \
|
||||||
|
'
|
||||||
|
EOF
|
||||||
|
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl start testservice-07-check-quotas.service
|
||||||
|
}
|
||||||
|
|
||||||
|
test_quotas "/var/lib/private" "StateDirectory=quotadir" "StateDirectoryQuota=1%"
|
||||||
|
|
||||||
|
systemd-analyze log-level info
|
||||||
|
|
||||||
|
touch /testok
|
39
test/units/TEST-07-PID1.subgroup-kill.sh
Executable file
39
test/units/TEST-07-PID1.subgroup-kill.sh
Executable file
@ -0,0 +1,39 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
# shellcheck disable=SC2016
|
||||||
|
set -eux
|
||||||
|
set -o pipefail
|
||||||
|
|
||||||
|
# shellcheck source=test/units/test-control.sh
|
||||||
|
. "$(dirname "$0")"/test-control.sh
|
||||||
|
# shellcheck source=test/units/util.sh
|
||||||
|
. "$(dirname "$0")"/util.sh
|
||||||
|
|
||||||
|
at_exit() {
|
||||||
|
loginctl disable-linger testuser ||:
|
||||||
|
run0 -u testuser systemctl --user stop subgroup-test.service ||:
|
||||||
|
}
|
||||||
|
|
||||||
|
trap at_exit EXIT
|
||||||
|
|
||||||
|
loginctl enable-linger testuser
|
||||||
|
run0 -u testuser systemd-run --user --unit=subgroup-test.service sleep infinity
|
||||||
|
|
||||||
|
systemctl kill user@"$(id -u testuser)".service --kill-subgroup=waldo
|
||||||
|
systemctl kill user@"$(id -u testuser)".service --kill-subgroup=/waldo
|
||||||
|
systemctl kill user@"$(id -u testuser)".service --kill-subgroup=waldo/knurz
|
||||||
|
systemctl kill user@"$(id -u testuser)".service --kill-subgroup=/waldo/knurz
|
||||||
|
|
||||||
|
(! systemctl kill user@"$(id -u testuser)".service --kill-subgroup=waldo --kill-whom=cgroup-fail)
|
||||||
|
(! systemctl kill user@"$(id -u testuser)".service --kill-subgroup=/waldo --kill-whom=cgroup-fail)
|
||||||
|
(! systemctl kill user@"$(id -u testuser)".service --kill-subgroup=waldo/knurz --kill-whom=cgroup-fail)
|
||||||
|
(! systemctl kill user@"$(id -u testuser)".service --kill-subgroup=/waldo/knurz --kill-whom=cgroup-fail)
|
||||||
|
|
||||||
|
run0 -u testuser systemctl --user is-active subgroup-test.service
|
||||||
|
(! systemctl kill user@"$(id -u testuser)".service --kill-subgroup=app.slice/subgroup-test.service/waldo --kill-whom=cgroup-fail)
|
||||||
|
run0 -u testuser systemctl --user is-active subgroup-test.service
|
||||||
|
systemctl kill user@"$(id -u testuser)".service --kill-subgroup=app.slice/subgroup-test.service/waldo
|
||||||
|
run0 -u testuser systemctl --user is-active subgroup-test.service
|
||||||
|
systemctl kill user@"$(id -u testuser)".service --kill-subgroup=app.slice/subgroup-test.service --kill-whom=cgroup-fail
|
||||||
|
|
||||||
|
timeout 60 bash -c 'while run0 -u testuser systemctl --user is-active subgroup-test.service ; do sleep 1 ; done'
|
Loading…
x
Reference in New Issue
Block a user