Imported Upstream version 226

This commit is contained in:
Martin Pitt 2015-09-09 07:26:01 +02:00
parent 13d276d0d7
commit d9dfd2336c
233 changed files with 10948 additions and 5530 deletions

View File

@ -295,25 +295,15 @@
EXIT_FAILURE and EXIT_SUCCESS as defined by libc.
- The order in which header files are included doesn't matter too
much. However, please try to include the headers of external
libraries first (these are all headers enclosed in <>), followed by
the headers of our own public headers (these are all headers
starting with "sd-"), internal utility libraries from src/shared/,
followed by the headers of the specific component. Or in other
words:
#include <stdio.h>
#include "sd-daemon.h"
#include "util.h"
#include "frobnicator.h"
Where stdio.h is a public glibc API, sd-daemon.h is a public API of
our own, util.h is a utility library header from src/shared, and
frobnicator.h is an placeholder name for any systemd component. The
benefit of following this ordering is that more local definitions
are always defined after more global ones. Thus, our local
definitions will never "leak" into the global header files, possibly
altering their effect due to #ifdeffery.
much. systemd-internal headers must not rely on an include order, so
it is safe to include them in any order possible.
However, to not clutter global includes, and to make sure internal
definitions will not affect global headers, please always include the
headers of external components first (these are all headers enclosed
in <>), followed by our own exported headers (usually everything
that's prefixed by "sd-"), and then followed by internal headers.
Furthermore, in all three groups, order all includes alphabetically
so duplicate includes can easily be detected.
- To implement an endless loop, use "for (;;)" rather than "while
(1)". The latter is a bit ugly anyway, since you probably really

View File

@ -130,6 +130,7 @@ MANPAGES += \
man/systemd.kill.5 \
man/systemd.link.5 \
man/systemd.mount.5 \
man/systemd.nspawn.5 \
man/systemd.path.5 \
man/systemd.preset.5 \
man/systemd.resource-control.5 \
@ -1937,6 +1938,7 @@ MANPAGES_ALIAS += \
man/sd_login_monitor_get_fd.3 \
man/sd_login_monitor_get_timeout.3 \
man/sd_login_monitor_unref.3 \
man/sd_peer_get_cgroup.3 \
man/sd_peer_get_machine_name.3 \
man/sd_peer_get_owner_uid.3 \
man/sd_peer_get_session.3 \
@ -1944,6 +1946,7 @@ MANPAGES_ALIAS += \
man/sd_peer_get_unit.3 \
man/sd_peer_get_user_slice.3 \
man/sd_peer_get_user_unit.3 \
man/sd_pid_get_cgroup.3 \
man/sd_pid_get_machine_name.3 \
man/sd_pid_get_owner_uid.3 \
man/sd_pid_get_slice.3 \
@ -1981,6 +1984,7 @@ man/sd_login_monitor_get_events.3: man/sd_login_monitor_new.3
man/sd_login_monitor_get_fd.3: man/sd_login_monitor_new.3
man/sd_login_monitor_get_timeout.3: man/sd_login_monitor_new.3
man/sd_login_monitor_unref.3: man/sd_login_monitor_new.3
man/sd_peer_get_cgroup.3: man/sd_pid_get_session.3
man/sd_peer_get_machine_name.3: man/sd_pid_get_session.3
man/sd_peer_get_owner_uid.3: man/sd_pid_get_session.3
man/sd_peer_get_session.3: man/sd_pid_get_session.3
@ -1988,6 +1992,7 @@ man/sd_peer_get_slice.3: man/sd_pid_get_session.3
man/sd_peer_get_unit.3: man/sd_pid_get_session.3
man/sd_peer_get_user_slice.3: man/sd_pid_get_session.3
man/sd_peer_get_user_unit.3: man/sd_pid_get_session.3
man/sd_pid_get_cgroup.3: man/sd_pid_get_session.3
man/sd_pid_get_machine_name.3: man/sd_pid_get_session.3
man/sd_pid_get_owner_uid.3: man/sd_pid_get_session.3
man/sd_pid_get_slice.3: man/sd_pid_get_session.3
@ -2043,6 +2048,9 @@ man/sd_login_monitor_get_timeout.html: man/sd_login_monitor_new.html
man/sd_login_monitor_unref.html: man/sd_login_monitor_new.html
$(html-alias)
man/sd_peer_get_cgroup.html: man/sd_pid_get_session.html
$(html-alias)
man/sd_peer_get_machine_name.html: man/sd_pid_get_session.html
$(html-alias)
@ -2064,6 +2072,9 @@ man/sd_peer_get_user_slice.html: man/sd_pid_get_session.html
man/sd_peer_get_user_unit.html: man/sd_pid_get_session.html
$(html-alias)
man/sd_pid_get_cgroup.html: man/sd_pid_get_session.html
$(html-alias)
man/sd_pid_get_machine_name.html: man/sd_pid_get_session.html
$(html-alias)
@ -2372,6 +2383,7 @@ EXTRA_DIST += \
man/systemd.mount.xml \
man/systemd.netdev.xml \
man/systemd.network.xml \
man/systemd.nspawn.xml \
man/systemd.path.xml \
man/systemd.preset.xml \
man/systemd.resource-control.xml \

View File

@ -42,9 +42,9 @@ LIBUDEV_CURRENT=7
LIBUDEV_REVISION=4
LIBUDEV_AGE=6
LIBSYSTEMD_CURRENT=10
LIBSYSTEMD_REVISION=2
LIBSYSTEMD_AGE=10
LIBSYSTEMD_CURRENT=11
LIBSYSTEMD_REVISION=0
LIBSYSTEMD_AGE=11
# The following four libraries only exist for compatibility reasons,
# their version info should not be bumped anymore
@ -155,6 +155,7 @@ noinst_PROGRAMS =
TESTS =
endif
udevlibexec_PROGRAMS =
gperf_gperf_sources =
in_files = $(filter %.in,$(EXTRA_DIST))
in_in_files = $(filter %.in.in, $(in_files))
@ -220,6 +221,7 @@ AM_CPPFLAGS = \
-I $(top_builddir)/src/journal \
-I $(top_srcdir)/src/timedate \
-I $(top_srcdir)/src/timesync \
-I $(top_srcdir)/src/nspawn \
-I $(top_srcdir)/src/resolve \
-I $(top_builddir)/src/resolve \
-I $(top_srcdir)/src/systemd \
@ -2776,11 +2778,31 @@ systemd_cgtop_LDADD = \
# ------------------------------------------------------------------------------
systemd_nspawn_SOURCES = \
src/nspawn/nspawn.c \
src/nspawn/nspawn-settings.c \
src/nspawn/nspawn-settings.h \
src/nspawn/nspawn-mount.c \
src/nspawn/nspawn-mount.h \
src/nspawn/nspawn-network.c \
src/nspawn/nspawn-network.h \
src/nspawn/nspawn-expose-ports.c \
src/nspawn/nspawn-expose-ports.h \
src/nspawn/nspawn-cgroup.c \
src/nspawn/nspawn-cgroup.h \
src/nspawn/nspawn-register.c \
src/nspawn/nspawn-register.h \
src/nspawn/nspawn-setuid.c \
src/nspawn/nspawn-setuid.h \
src/core/mount-setup.c \
src/core/mount-setup.h \
src/core/loopback-setup.c \
src/core/loopback-setup.h
nodist_systemd_nspawn_SOURCES = \
src/nspawn/nspawn-gperf.c
gperf_gperf_sources += \
src/nspawn/nspawn-gperf.gperf
systemd_nspawn_CFLAGS = \
$(AM_CFLAGS) \
$(BLKID_CFLAGS) \
@ -3486,7 +3508,7 @@ nodist_libudev_core_la_SOURCES = \
src/udev/keyboard-keys-to-name.h \
src/udev/net/link-config-gperf.c
gperf_gperf_sources = \
gperf_gperf_sources += \
src/udev/net/link-config-gperf.gperf
libudev_core_la_CFLAGS = \
@ -5167,41 +5189,48 @@ libnetworkd_core_la_SOURCES = \
src/libsystemd-network/network-internal.h \
src/network/networkd.h \
src/network/networkd-link.h \
src/network/networkd-netdev.h \
src/network/networkd-netdev-tunnel.h \
src/network/networkd-netdev-veth.h \
src/network/networkd-netdev-vxlan.h \
src/network/networkd-netdev-vlan.h \
src/network/networkd-netdev-macvlan.h \
src/network/networkd-netdev-ipvlan.h \
src/network/networkd-netdev-dummy.h \
src/network/networkd-netdev-tuntap.h \
src/network/networkd-netdev-bond.h \
src/network/networkd-netdev-bridge.h \
src/network/networkd-netdev.c \
src/network/networkd-netdev-tunnel.c \
src/network/networkd-netdev-veth.c \
src/network/networkd-netdev-vxlan.c \
src/network/networkd-netdev-vlan.c \
src/network/networkd-netdev-macvlan.c \
src/network/networkd-netdev-ipvlan.c \
src/network/networkd-netdev-dummy.c \
src/network/networkd-netdev-tuntap.c \
src/network/networkd-netdev-bond.c \
src/network/networkd-netdev-bridge.c \
src/network/networkd-link.c \
src/network/networkd-netdev.h \
src/network/networkd-netdev.c \
src/network/networkd-netdev-tunnel.h \
src/network/networkd-netdev-tunnel.c \
src/network/networkd-netdev-veth.h \
src/network/networkd-netdev-veth.c \
src/network/networkd-netdev-vxlan.h \
src/network/networkd-netdev-vxlan.c \
src/network/networkd-netdev-vlan.h \
src/network/networkd-netdev-vlan.c \
src/network/networkd-netdev-macvlan.h \
src/network/networkd-netdev-macvlan.c \
src/network/networkd-netdev-ipvlan.h \
src/network/networkd-netdev-ipvlan.c \
src/network/networkd-netdev-dummy.h \
src/network/networkd-netdev-dummy.c \
src/network/networkd-netdev-tuntap.h \
src/network/networkd-netdev-tuntap.c \
src/network/networkd-netdev-bond.h \
src/network/networkd-netdev-bond.c \
src/network/networkd-netdev-bridge.h \
src/network/networkd-netdev-bridge.c \
src/network/networkd-link-bus.c \
src/network/networkd-ipv4ll.c \
src/network/networkd-dhcp4.c \
src/network/networkd-dhcp6.c \
src/network/networkd-network.h \
src/network/networkd-network.c \
src/network/networkd-network-bus.c \
src/network/networkd-address.h \
src/network/networkd-address.c \
src/network/networkd-route.h \
src/network/networkd-route.c \
src/network/networkd-manager.c \
src/network/networkd-manager-bus.c \
src/network/networkd-fdb.h \
src/network/networkd-fdb.c \
src/network/networkd-address-pool.c
src/network/networkd-address-pool.h \
src/network/networkd-address-pool.c \
src/network/networkd-util.h \
src/network/networkd-util.c
nodist_libnetworkd_core_la_SOURCES = \
src/network/networkd-network-gperf.c \

210
NEWS
View File

@ -1,27 +1,195 @@
systemd System and Service Manager
CHANGES WITH 226:
* The DHCP implementation of systemd-networkd gained a set of
new features:
- The DHCP server now supports emitting DNS and NTP
information. It may be enabled and configured via
EmitDNS=, DNS=, EmitNTP=, and NTP=. If transmission of DNS
and NTP information is enabled, but no servers are
configured, the corresponding uplink information (if there
is any) is propagated.
- Server and client now support transmission and reception
of timezone information. It can be configured via the
newly introduced network options UseTimezone=,
EmitTimezone=, and Timezone=. Transmission of timezone
information is enabled between host and containers by
default now: the container will change its local timezone
to what the host has set.
- Lease timeouts can now be configured via
MaxLeaseTimeSec= and DefaultLeaseTimeSec=.
- The DHCP server improved on the stability of
leases. Clients are more likely to get the same lease
information back, even if the server loses state.
- The DHCP server supports two new configuration options to
control the lease address pool metrics, PoolOffset= and
PoolSize=.
* The encapsulation limit of tunnels in systemd-networkd may
now be configured via 'EncapsulationLimit='. It allows
modifying the maximum additional levels of encapsulation
that are permitted to be prepended to a packet.
* systemd now supports the concept of user buses replacing
session buses, if used with dbus-1.10 (and enabled via dbus
--enable-user-session). It previously only supported this on
kdbus-enabled systems, and this release expands this to
'dbus-daemon' systems.
* systemd-networkd now supports predictable interface names
for virtio devices.
* systemd now optionally supports the new Linux kernel
"unified" control group hierarchy. If enabled via the kernel
command-line option 'systemd.unified_cgroup_hierarchy=1',
systemd will try to mount the unified cgroup hierarchy
directly on /sys/fs/cgroup. If not enabled, or not
available, systemd will fall back to the legacy cgroup
hierarchy setup, as before. Host system and containers can
mix and match legacy and unified hierarchies as they
wish. nspawn understands the $UNIFIED_CROUP_HIERARCHY
environment variable to individually select the hierarchy to
use for executed containers. By default, nspawn will use the
unified hierarchy for the containers if the host uses the
unified hierarchy, and the legacy hierarchy otherwise.
Please note that at this point the unified hierarchy is an
experimental kernel feature and is likely to change in one
of the next kernel releases. Therefore, it should not be
enabled by default in downstream distributions yet. The
minimum required kernel version for the unified hierarchy to
work is 4.2. Note that when the unified hierarchy is used
for the first time delegated access to controllers is
safe. Because of this systemd-nspawn containers will get
access to controllers now, as will systemd user
sessions. This means containers and user sessions may now
manage their own resources, partitioning up what the system
grants them.
* A new special scope unit "init.scope" has been introduced
that encapsulates PID 1 of the system. It may be used to
determine resource usage and enforce resource limits on PID
1 itself. PID 1 hence moved out of the root of the control
group tree.
* The cgtop tool gained support for filtering out kernel
threads when counting tasks in a control group. Also, the
count of processes is now recursively summed up by
default. Two options -k and --recursive= have been added to
revert to old behaviour. The tool has also been updated to
work correctly in containers now.
* systemd-nspawn's --bind= and --bind-ro= options have been
extended to allow creation of non-recursive bind mounts.
* libsystemd gained two new calls sd_pid_get_cgroup() and
sd_peer_get_cgroup() which return the control group path of
a process or peer of a connected AF_UNIX socket. This
function call is particularly useful when implementing
delegated subtrees support in the control group hierarchy.
* The "sd-event" event loop API of libsystemd now supports
correct dequeuing of real-time signals, without losing
signal events.
* When systemd requests a PolicyKit decision when managing
units it will now add additional fields to the request,
including unit name and desired operation. This enables more
powerful PolicyKit policies, that make decisions depending
on these parameters.
* nspawn learnt support for .nspawn settings files, that may
accompany the image files or directories of containers, and
may contain additional settings for the container. This is
an alternative to configuring container parameters via the
nspawn command line.
Contributions from: Cristian Rodríguez, Daniel Mack, David
Herrmann, Eugene Yakubovich, Evgeny Vereshchagin, Filipe
Brandenburger, Hans de Goede, Jan Alexander Steffens, Jan
Synacek, Kay Sievers, Lennart Poettering, Mangix, Marcel
Holtmann, Martin Pitt, Michael Biebl, Michael Chapman, Michal
Sekletar, Peter Hutterer, Piotr Drąg, reverendhomer, Robin
Hack, Susant Sahani, Sylvain Pasche, Thomas Hindoe Paaboel
Andersen, Tom Gundersen, Torstein Husebø
-- Berlin, 2015-09-08
CHANGES WITH 225:
* machinectl gained a new verb 'shell' which opens a fresh shell on the
target machine. It is similar to 'login', but spawns the shell
directly. The pseudo machine '.host' now refers to the local host and
is used by default. Hence, 'machinectl shell' can be used as
replacement for 'su' which spawns the session as a fresh systemd
unit.
* machinectl gained a new verb 'shell' which opens a fresh
shell on the target container or the host. It is similar to
the existing 'login' command of machinectl, but spawns the
shell directly without prompting for username or
password. The pseudo machine '.host' now refers to the local
host and is used by default. Hence, 'machinectl shell' can
be used as replacement for 'su -' which spawns a session as
a fresh systemd unit in a way that is fully isolated from
the originating session.
* systemd-networkd learned to cope with private-zone DHCP options and
allows other programs to query the values.
* systemd-networkd learned to cope with private-zone DHCP
options and allows other programs to query the values.
Contributions from: Alastair Hughes, Alex Crawford, Daniel Mack, David
Herrmann, Dimitri John Ledkov, Eric Kostrowski, Evgeny Vereshchagin,
Felipe Sateler, HATAYAMA Daisuke, Jan Pokorný, Jan Synacek, Johnny
Robeson, Karel Zak, Kay Sievers, Kefeng Wang, Lennart Poettering, Major
Hayden, Marcel Holtmann, Markus Elfring, Martin Mikkelsen, Martin Pitt,
Matt Turner, Maxim Mikityanskiy, Michael Biebl, Namhyung Kim, Nicolas
Cornu, Owen W. Taylor, Patrik Flykt, Peter Hutterer, reverendhomer,
Richard Maw, Ronny Chevalier, Seth Jennings, Stef Walter, Susant Sahani,
Thomas Blume, Thomas Hindoe Paaboel Andersen, Thomas Meyer, Tom
Gundersen, Vincent Batts, WaLyong Cho, Zbigniew Jędrzejewski-Szmek
* SELinux access control when enabling/disabling units is no
longer enforced with this release. The previous
implementation was incorrect, and a new corrected
implementation is not yet available. As unit file operations
are still protected via PolicyKit and D-Bus policy this is
not a security problem. Yet, distributions which care about
optimal SELinux support should probably not stabilize on
this release.
* sd-bus gained support for matches of type "arg0has=", that
test for membership of strings in string arrays sent in bus
messages.
* systemd-resolved now dumps the contents of its DNS and LLMNR
caches to the logs on reception of the SIGUSR1 signal. This
is useful to debug DNS behaviour.
* The coredumpctl tool gained a new --directory= option to
operate on journal files in a specific directory.
* "systemctl reboot" and related commands gained a new
"--message=" option which may be used to set a free-text
wall message when shutting down or rebooting the
system. This message is also logged, which is useful for
figuring out the reason for a reboot or shutdown a
posteriori.
* The "systemd-resolve-host" tool's -i switch now takes
network interface numbers as alternative to interface names.
* A new unit file setting for services has been introduced:
UtmpMode= allows configuration of how precisely systemd
handles utmp and wtmp entries for the service if this is
enabled. This allows writing services that appear similar to
user sessions in the output of the "w", "who", "last" and
"lastlog" tools.
* systemd-resolved will now locally synthesize DNS resource
records for the "localhost" and "gateway" domains as well as
the local hostname. This should ensure that clients querying
RRs via resolved will get similar results as those going via
NSS, if nss-myhostname is enabled.
Contributions from: Alastair Hughes, Alex Crawford, Daniel
Mack, David Herrmann, Dimitri John Ledkov, Eric Kostrowski,
Evgeny Vereshchagin, Felipe Sateler, HATAYAMA Daisuke, Jan
Pokorný, Jan Synacek, Johnny Robeson, Karel Zak, Kay Sievers,
Kefeng Wang, Lennart Poettering, Major Hayden, Marcel
Holtmann, Markus Elfring, Martin Mikkelsen, Martin Pitt, Matt
Turner, Maxim Mikityanskiy, Michael Biebl, Namhyung Kim,
Nicolas Cornu, Owen W. Taylor, Patrik Flykt, Peter Hutterer,
reverendhomer, Richard Maw, Ronny Chevalier, Seth Jennings,
Stef Walter, Susant Sahani, Thomas Blume, Thomas Hindoe
Paaboel Andersen, Thomas Meyer, Tom Gundersen, Vincent Batts,
WaLyong Cho, Zbigniew Jędrzejewski-Szmek
-- Berlin, 2015-08-27
@ -30,9 +198,9 @@ CHANGES WITH 224:
* The systemd-efi-boot-generator functionality was merged into
systemd-gpt-auto-generator.
* systemd-networkd now supports Group Policy for vxlan devices. It can
be enabled via the new boolean configuration option called
'GroupPolicyExtension='.
* systemd-networkd now supports Group Policy for vxlan
devices. It can be enabled via the new boolean configuration
option called 'GroupPolicyExtension='.
Contributions from: Andreas Kempf, Christian Hesse, Daniel Mack, David
Herrmann, Herman Fries, Johannes Nixdorf, Kay Sievers, Lennart

4
README
View File

@ -36,8 +36,8 @@ LICENSE:
- except src/udev/* which is (currently still) GPLv2, GPLv2+
REQUIREMENTS:
Linux kernel >= 3.7
Linux kernel >= 3.8 for Smack support
Linux kernel >= 3.11
Linux kernel >= 4.2 for unified cgroup hierarchy support
Kernel Config Options:
CONFIG_DEVTMPFS

24
TODO
View File

@ -26,16 +26,14 @@ External:
Features:
* sd-event: maybe add support for inotify events
* PID 1 should send out sd_notify("WATCHDOG=1") messages (for usage in the --user mode, and when run via nspawn)
* nspawn should send out sd_notify("WATCHDOG=1") messages
* nspawn should optionally support receiving WATCHDOG=1 messages from its payload PID 1...
* introduce "machinectl shell" that is like systemd-run -M foo /bin/bash -t but also adds PAMName=login
* allow loging into host with "machinectl login".
* consider throwing a warning if a service declares it wants to be "Before=" a .device unit.
* "systemctl edit" should know a mode to create a new unit file
@ -65,10 +63,6 @@ Features:
* logind: follow PropertiesChanged state more closely, to deal with quick logouts and relogins
* change to KillMode=mixed by default
* introduce argv0contains=
* invent a better systemd-run scheme for naming scopes, that works with remoting
* add journalctl -H that talks via ssh to a remote peer and passes through binary logs data
@ -209,8 +203,6 @@ Features:
* "machinectl list-images" should show os-release data, as well as machine-info data (including deployment level)
* nspawn: when start a container "foobar" look for its configuration in a file "foobar.nspawn" in /etc/systemd/nspawn/ as well as next to the actualy directory or image to boot
* Port various tools to make use of verbs.[ch], where applicable
* "machinectl history"
@ -256,8 +248,6 @@ Features:
* figure out when we can use the coarse timers
* sd-resolve: drop res_query wrapping, people should call via the bus to resolved instead
* add "systemctl start -v foobar.service" that shows logs of a service
while the start command runs. This is non-trivial to do without
races though, since we should flush out all journal messages before
@ -322,26 +312,22 @@ Features:
(throughout the codebase, not only PID1)
* networkd:
- make DHCP server IP range configurable, including only with a single IP address
- dhcp server: try to assign stable IP addresses based on client's MAC address
- add LLDP client side support
- the DHCP lease data (such as NTP/DNS) is still made available when
a carrier is lost on a link. It should be removed instantly.
- expose in the API the following bits:
- option 15, domain name and/or option 119, search list
- option 12, host name and/or option 81, fqdn
- option 100, 101, timezone
- option 123, 144, geolocation
- option 252, configure http proxy (PAC/wpad)
- networkd's dhcp server should transparently pass on the DNS and
NTP server list it got from user configuration and its dhcp client
to clients. It should also pass on its own timezone information.
- provide a way to define a per-network interface default metric value
for all routes to it. possibly a second default for DHCP routes.
- allow Name= to be specified repeatedly in the [Match] section. Maybe also
support Name=foo*|bar*|baz ?
- duplicate address check for static IPs (like ARPCHECK in network-scripts)
- allow DUID/IAID to be customized, see issue #394.
- support configuration option for TSO (tcp segmentation offload)
- networkd: whenever uplink info changes, make DHCP server send out FORCERENEW
* resolved:
- put networkd events and rtnl events at a higher priority, so that
@ -473,7 +459,6 @@ Features:
* sd-bus:
- EBADSLT handling
- change argv list matching logic
- GetAllProperties() on a non-existing object does not result in a failure currently
- kdbus: process fd=-1 for incoming msgs
- port to sd-resolve for connecting to TCP dbus servers
@ -895,7 +880,6 @@ Features:
* dhcp:
- figure out how much we can increase Maximum Message Size
- export timezone information
- support RFC4702 (pass FQDN)
* dhcp6:

View File

@ -20,7 +20,7 @@
AC_PREREQ([2.64])
AC_INIT([systemd],
[225],
[226],
[http://github.com/systemd/systemd/issues],
[systemd],
[http://www.freedesktop.org/wiki/Software/systemd])
@ -39,9 +39,14 @@ AM_SILENT_RULES([yes])
AC_CANONICAL_HOST
AC_DEFINE_UNQUOTED([CANONICAL_HOST], "$host", [Canonical host string.])
AC_CHECK_TOOLS([AR], [gcc-ar ar], [:])
AC_CHECK_TOOLS([NM], [gcc-nm nm], [:])
AC_CHECK_TOOLS([RANLIB], [gcc-ranlib ranlib], [:])
AC_PROG_CC_C99
AX_COMPILER_VENDOR
AS_IF([test "x$ax_cv_c_compiler_vendor" = "xgnu"], [
AC_CHECK_TOOLS([AR], [gcc-ar ar], [:])
AC_CHECK_TOOLS([NM], [gcc-nm nm], [:])
AC_CHECK_TOOLS([RANLIB], [gcc-ranlib ranlib], [:])
])
LT_PREREQ(2.2)
LT_INIT([disable-static])
@ -87,8 +92,6 @@ AC_PROG_SED
AC_PROG_GREP
AC_PROG_AWK
AC_PROG_CC_C99
AC_PATH_PROG([M4], [m4])
AC_PATH_PROG([XSLTPROC], [xsltproc])
@ -1552,7 +1555,6 @@ AC_MSG_RESULT([
SysV init scripts: ${SYSTEM_SYSVINIT_PATH}
SysV rc?.d directories: ${SYSTEM_SYSVRCND_PATH}
Build Python: ${PYTHON}
sphinx binary: ${SPHINX_BUILD}
PAM modules dir: ${with_pamlibdir}
PAM configuration dir: ${with_pamconfdir}
D-Bus policy dir: ${with_dbuspolicydir}

View File

@ -1898,3 +1898,36 @@ bluetooth:v0275*
bluetooth:v0276*
ID_VENDOR_FROM_DATABASE=E.G.O. Elektro-Gertebau GmbH
bluetooth:v0277*
ID_VENDOR_FROM_DATABASE=bewhere inc
bluetooth:v0278*
ID_VENDOR_FROM_DATABASE=Johnson Outdoors Inc
bluetooth:v0279*
ID_VENDOR_FROM_DATABASE=steute Schaltgerate GmbH & Co. KG
bluetooth:v027A*
ID_VENDOR_FROM_DATABASE=Ekomini inc.
bluetooth:v027B*
ID_VENDOR_FROM_DATABASE=DEFA AS
bluetooth:v027C*
ID_VENDOR_FROM_DATABASE=Aseptika Ltd
bluetooth:v027D*
ID_VENDOR_FROM_DATABASE=HUAWEI Technologies Co., Ltd. ( 华为技术有限公司 )
bluetooth:v027E*
ID_VENDOR_FROM_DATABASE=HabitAware, LLC
bluetooth:v027F*
ID_VENDOR_FROM_DATABASE=ruwido austria gmbh
bluetooth:v0280*
ID_VENDOR_FROM_DATABASE=ITEC corporation
bluetooth:v0281*
ID_VENDOR_FROM_DATABASE=StoneL

View File

@ -124,6 +124,10 @@ mouse:usb:v04f2p0963:name:Chicony 2.4G Multimedia Wireless Kit:
# Dell
##########################################
# Dell MUAR DEL7
mouse:usb:v413cp3012:name:Dell Dell USB Optical Mouse:
MOUSE_DPI=400@166
# Dell USB Laser Mouse
mouse:usb:v046dpc063:name:DELL DELL USB Laser Mouse:
MOUSE_DPI=1000@125
@ -173,6 +177,10 @@ mouse:usb:v093ap2510:name:PIXART USB OPTICAL MOUSE:
mouse:usb:v17efp6019:name:Lenovo Optical USB Mouse:
MOUSE_DPI=1000@125
# Lenovo M-U0025-O
mouse:usb:v17efp6019:name:Logitech Lenovo USB Optical Mouse:
MOUSE_DPI=1000@166
# ThinkPad USB Laser Mouse
mouse:usb:v17efp6044:name:ThinkPad USB Laser Mouse:
MOUSE_DPI=1200@125
@ -181,6 +189,13 @@ mouse:usb:v17efp6044:name:ThinkPad USB Laser Mouse:
mouse:usb:v17efp6050:name:Lenovo Precision USB Mouse:
MOUSE_DPI=1200@127
# Lenovo MOBGUL
mouse:usb:v17efp601d:name:Primax Lenovo Laser Mouse:
# Lenovo MOBGULA
mouse:usb:v17efp6045:name:Lenovo USB Laser Mouse:
MOUSE_DPI=1600@125
##########################################
# Logitech
##########################################
@ -220,6 +235,8 @@ mouse:usb:v046dpc52b:name:Logitech Unifying Device. Wireless PID:400a:
MOUSE_DPI=600@166
MOUSE_WHEEL_CLICK_ANGLE=20
# Logitech MX400 Performance Laser Mouse
mouse:usb:v046dpc043:name:Logitech USB-PS/2 Optical Mouse:
# Logitech MX1000 Laser Cordless Mouse
mouse:usb:v046dpc50e:name:Logitech USB RECEIVER:
# Logitech Cordless Click! Plus
@ -234,16 +251,16 @@ mouse:usb:v046dpc01e:name:Logitech USB-PS/2 Optical Mouse:
# Logitech, Inc. RX 250 Optical Mouse
mouse:usb:v046dpc050:name:Logitech USB-PS/2 Optical Mouse:
MOUSE_DPI=800@142
MOUSE_DPI=1000@142
# Logitech Wireless Mouse M185
mouse:usb:v046dp4008:name:Logitech M185:
mouse:usb:v046dpc52b:name:Logitech Unifying Device. Wireless PID:4008:
# Logitech Wireless Mouse M510
mouse:usb:v046dp1025:name:Logitech M510:
# Logitech M705 (marathon mouse)
mouse:usb:v046dp101b:name:Logitech M705:
mouse:usb:v046dpc52b:name:Logitech Unifying Device. Wireless PID:101b:
# Logitech Performance MX
mouse:usb:v046dp101a:name:Logitech Performance MX:
MOUSE_DPI=800@166
# Logitech MX Revolution
@ -274,14 +291,24 @@ mouse:usb:v046dp101d:name:Logitech M505:
mouse:usb:v046dpc52b:name:Logitech Unifying Device. Wireless PID:101d:
MOUSE_DPI=900@166
# Logitech Cordless Desktop Wave Mouse
mouse:usb:v046dpc517:name:Logitech USB Receiver:
MOUSE_DPI=950@125
# Logitech RX1000 Laser Mouse
mouse:usb:v046dpc046:name:Logitech USB Optical Mouse:
# Logitech M100 Optical Mouse
mouse:usb:v046dpc05a:name:Logitech USB Optical Mouse:
# Logitech USB Laser Mouse M-U0011-O rebranded as "terra Laser"
mouse:usb:v046dpc065:name:Logitech USB Laser Mouse:
# Logitech V500 Cordless Notebook Mouse
mouse:usb:v046dpc510:name:Logitech USB Receiver:
MOUSE_DPI=1000@125
# Logitech V220 Cordless Optical Mouse
mouse:usb:v046dpc51b:name:Logitech USB Receiver:
# Logitech Performance MX
mouse:usb:v046dp101a:name:Logitech Performance MX:
# Logitech MX Master
mouse:usb:v046dp4041:name:Logitech MX Master:
MOUSE_DPI=1000@166
@ -296,6 +323,10 @@ mouse:usb:v046dpc06b:name:Logitech G700 Laser Mouse:
mouse:usb:v046dpc531:name:Logitech USB Receiver:
MOUSE_DPI=*1000@500 3800@500 500@1000 1500@1000 2000@1000
# Logitech Wireless Mouse M310
mouse:usb:v046dp1024:name:Logitech M310:
MOUSE_DPI=1100@168
# Logitech USB Laser Mouse M-UAS144 [LS1 Laser Mouse]
mouse:usb:v046dpc062:name:Logitech USB Laser Mouse:
# Logitech USB Laser Mouse M-U0007
@ -321,6 +352,10 @@ mouse:usb:v046dpc52b:name:Logitech Unifying Device. Wireless PID:4026:
mouse:usb:v046dpc068:name:Logitech G500:
MOUSE_DPI=*1600@500 2600@500 3600@500
# Logitech MX1000 Laser Cordless Mouse
mouse:bluetooth:v046dpb003:name:Logitech MX1000 mouse:
MOUSE_DPI=800@80
# Logitech Ultrathin Touch Mouse
mouse:bluetooth:v046dpb00d:name:Ultrathin Touch Mouse:
MOUSE_DPI=1000@1000
@ -347,6 +382,8 @@ mouse:usb:v045ep0040:name:Microsoft Microsoft 3-Button Mouse with IntelliEye(TM)
mouse:usb:v045ep0745:name:Microsoft Microsoft® 2.4GHz Transceiver v6.0:
MOUSE_DPI=800@142
# Microsoft Wireless Mobile Mouse 4000
mouse:usb:v045ep0745:name:Microsoft Microsoft® Nano Transceiver v2.0:
# Microsoft Sculpt Ergonomic Mouse
mouse:usb:v045ep07a5:name:Microsoft Microsoft® 2.4GHz Transceiver v9.0:
MOUSE_DPI=1000@142
@ -363,6 +400,15 @@ mouse:bluetooth:v045ep0702:name:Microsoft Wireless Laser Mouse 8000:
mouse:bluetooth:v045ep07f3:name:Arc Touch Mouse SE:
MOUSE_DPI=1000@2000
##########################################
# Mionix
##########################################
#Mionix Avior 7000
mouse:usb:v22d4p1308:name:Laview Technology Mionix Avior 7000:
MOUSE_DPI=400@1000 *1600@1000 7000@1000
MOUSE_WHEEL_CLICK_ANGLE=15
##########################################
# Oklick
##########################################

View File

@ -88,6 +88,8 @@ evdev:name:*DualPoint Stick:dmi:bvn*:bvr*:bd*:svnDellInc.:pnLatitudeE6400*:pvr*
# Lenovo
#########################################
# Lenovo Thinkpad X230
evdev:name:TPPS/2 IBM TrackPoint:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPadX230:*
# Lenovo Thinkpad X230 tablet
evdev:name:TPPS/2 IBM TrackPoint:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPadX230Tablet:*
# Lenovo Thinkpad X240
@ -96,6 +98,8 @@ evdev:name:TPPS/2 IBM TrackPoint:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPadX240
evdev:name:TPPS/2 IBM TrackPoint:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPadT440s:*
# Lenovo Thinkpad T540p
evdev:name:TPPS/2 IBM TrackPoint:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPadT540p:*
# Lenovo Thinkpad T550 / W550s
evdev:name:TPPS/2 IBM TrackPoint:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPadT550:*
POINTINGSTICK_SENSITIVITY=200
POINTINGSTICK_CONST_ACCEL=1.0

87
m4/ax_compiler_vendor.m4 Normal file
View File

@ -0,0 +1,87 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_compiler_vendor.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_COMPILER_VENDOR
#
# DESCRIPTION
#
# Determine the vendor of the C/C++ compiler, e.g., gnu, intel, ibm, sun,
# hp, borland, comeau, dec, cray, kai, lcc, metrowerks, sgi, microsoft,
# watcom, etc. The vendor is returned in the cache variable
# $ax_cv_c_compiler_vendor for C and $ax_cv_cxx_compiler_vendor for C++.
#
# LICENSE
#
# Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu>
# Copyright (c) 2008 Matteo Frigo
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 15
AC_DEFUN([AX_COMPILER_VENDOR],
[AC_CACHE_CHECK([for _AC_LANG compiler vendor], ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor,
dnl Please add if possible support to ax_compiler_version.m4
[# note: don't check for gcc first since some other compilers define __GNUC__
vendors="intel: __ICC,__ECC,__INTEL_COMPILER
ibm: __xlc__,__xlC__,__IBMC__,__IBMCPP__
pathscale: __PATHCC__,__PATHSCALE__
clang: __clang__
cray: _CRAYC
fujitsu: __FUJITSU
gnu: __GNUC__
sun: __SUNPRO_C,__SUNPRO_CC
hp: __HP_cc,__HP_aCC
dec: __DECC,__DECCXX,__DECC_VER,__DECCXX_VER
borland: __BORLANDC__,__CODEGEARC__,__TURBOC__
comeau: __COMO__
kai: __KCC
lcc: __LCC__
sgi: __sgi,sgi
microsoft: _MSC_VER
metrowerks: __MWERKS__
watcom: __WATCOMC__
portland: __PGI
tcc: __TINYC__
unknown: UNKNOWN"
for ventest in $vendors; do
case $ventest in
*:) vendor=$ventest; continue ;;
*) vencpp="defined("`echo $ventest | sed 's/,/) || defined(/g'`")" ;;
esac
AC_COMPILE_IFELSE([AC_LANG_PROGRAM(,[
#if !($vencpp)
thisisanerror;
#endif
])], [break])
done
ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor=`echo $vendor | cut -d: -f1`
])
])

View File

@ -87,6 +87,7 @@
<xi:include href="standard-options.xml" xpointer="help" />
<xi:include href="standard-options.xml" xpointer="version" />
<xi:include href="standard-options.xml" xpointer="no-legend" />
<xi:include href="standard-options.xml" xpointer="no-pager" />
</variablelist>

View File

@ -111,8 +111,8 @@
<para>Here's an example <filename>/etc/nsswitch.conf</filename>
file, that enables <command>myhostname</command> correctly:</para>
<programlisting>passwd: compat
group: compat
<programlisting>passwd: compat mymachines
group: compat mymachines
shadow: compat
hosts: files resolve mymachines <command>myhostname</command>

View File

@ -82,8 +82,8 @@
<para>Here's an example <filename>/etc/nsswitch.conf</filename>
file, that enables <command>resolve</command> correctly:</para>
<programlisting>passwd: compat
group: compat
<programlisting>passwd: compat mymachines
group: compat mymachines
shadow: compat
hosts: files <command>resolve</command> mymachines myhostname

View File

@ -214,10 +214,11 @@
<varlistentry>
<term><varname>CPE_NAME=</varname></term>
<listitem><para>A CPE name for the operating system, following
the <ulink url="https://cpe.mitre.org/specification/">Common
<listitem><para>A CPE name for the operating system, in URI
binding syntax, following the
<ulink url="http://scap.nist.gov/specifications/cpe/">Common
Platform Enumeration Specification</ulink> as proposed by the
MITRE Corporation. This field is optional. Example:
NIST. This field is optional. Example:
<literal>CPE_NAME="cpe:/o:fedoraproject:fedora:17"</literal>
</para></listitem>
</varlistentry>

View File

@ -115,6 +115,29 @@
errno-style error code.</para>
</refsect1>
<refsect1>
<title>Errors</title>
<para>Returned errors may indicate the following problems:</para>
<variablelist>
<varlistentry>
<term><constant>-EINVAL</constant></term>
<listitem><para>An input parameter was invalid (out of range,
or NULL, where that's not accepted).</para></listitem>
</varlistentry>
<varlistentry>
<term><constant>-ENOMEM</constant></term>
<listitem><para>Memory allocation failed.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Notes</title>

View File

@ -161,20 +161,20 @@
is no timeout to wait for this will fill in <constant>(uint64_t)
-1</constant> instead. Note that <function>poll()</function> takes
a relative timeout in milliseconds rather than an absolute timeout
in microseconds. To convert the absolute 'us' timeout into
in microseconds. To convert the absolute 'µs' timeout into
relative 'ms', use code like the following:</para>
<programlisting>uint64_t t;
int msec;
sd_login_monitor_get_timeout(m, &amp;t);
if (t == (uint64_t) -1)
msec = -1;
msec = -1;
else {
struct timespec ts;
uint64_t n;
clock_getttime(CLOCK_MONOTONIC, &amp;ts);
n = (uint64_t) ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
msec = t > n ? (int) ((t - n + 999) / 1000) : 0;
struct timespec ts;
uint64_t n;
clock_getttime(CLOCK_MONOTONIC, &amp;ts);
n = (uint64_t) ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
msec = t > n ? (int) ((t - n + 999) / 1000) : 0;
}</programlisting>
<para>The code above does not do any error checking for brevity's
@ -203,6 +203,29 @@ else {
always returns <constant>NULL</constant>.</para>
</refsect1>
<refsect1>
<title>Errors</title>
<para>Returned errors may indicate the following problems:</para>
<variablelist>
<varlistentry>
<term><constant>-EINVAL</constant></term>
<listitem><para>An input parameter was invalid (out of range,
or NULL, where that's not accepted). The specified category to
watch is not known.</para></listitem>
</varlistentry>
<varlistentry>
<term><constant>-ENOMEM</constant></term>
<listitem><para>Memory allocation failed.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Notes</title>

View File

@ -56,7 +56,7 @@
<funcprototype>
<funcdef>int <function>sd_machine_get_class</function></funcdef>
<paramdef>const char* <parameter>machine</parameter></paramdef>
<paramdef>char *<parameter>class</parameter></paramdef>
<paramdef>char **<parameter>class</parameter></paramdef>
</funcprototype>
<funcprototype>
@ -98,6 +98,35 @@
code.</para>
</refsect1>
<refsect1>
<title>Errors</title>
<para>Returned errors may indicate the following problems:</para>
<variablelist>
<varlistentry>
<term><constant>-ENXIO</constant></term>
<listitem><para>The specified machine does not exist or is currently not running.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><constant>-EINVAL</constant></term>
<listitem><para>An input parameter was invalid (out of range,
or NULL, where that's not accepted).</para></listitem>
</varlistentry>
<varlistentry>
<term><constant>-ENOMEM</constant></term>
<listitem><para>Memory allocation failed.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Notes</title>

View File

@ -1,4 +1,4 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
@ -50,6 +50,7 @@
<refname>sd_pid_get_machine_name</refname>
<refname>sd_pid_get_slice</refname>
<refname>sd_pid_get_user_slice</refname>
<refname>sd_pid_get_cgroup</refname>
<refname>sd_peer_get_session</refname>
<refname>sd_peer_get_unit</refname>
<refname>sd_peer_get_user_unit</refname>
@ -57,6 +58,7 @@
<refname>sd_peer_get_machine_name</refname>
<refname>sd_peer_get_slice</refname>
<refname>sd_peer_get_user_slice</refname>
<refname>sd_peer_get_cgroup</refname>
<refpurpose>Determine session, unit, owner of a session,
container/VM or slice of a specific PID or socket
peer</refpurpose>
@ -108,6 +110,12 @@
<paramdef>char **<parameter>slice</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_pid_get_cgroup</function></funcdef>
<paramdef>pid_t <parameter>pid</parameter></paramdef>
<paramdef>char **<parameter>cgroup</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_peer_get_session</function></funcdef>
<paramdef>int <parameter>fd</parameter></paramdef>
@ -149,6 +157,12 @@
<paramdef>int <parameter>fd</parameter></paramdef>
<paramdef>char **<parameter>slice</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_peer_get_cgroup</function></funcdef>
<paramdef>int <parameter>fd</parameter></paramdef>
<paramdef>char **<parameter>cgroup</parameter></paramdef>
</funcprototype>
</funcsynopsis>
</refsynopsisdiv>
@ -163,7 +177,7 @@
processes, user processes that are shared between multiple
sessions of the same user, or kernel threads). For processes not
being part of a login session this function will fail with
-ENXIO. The returned string needs to be freed with the libc
-ENODATA. The returned string needs to be freed with the libc
<citerefentry
project='man-pages'><refentrytitle>free</refentrytitle><manvolnum>3</manvolnum></citerefentry>
call after use.</para>
@ -175,9 +189,9 @@
paths. Note that not all processes are part of a system
unit/service (e.g. user processes, or kernel threads). For
processes not being part of a systemd system unit this function
will fail with -ENXIO (More specifically: this call will not work
for kernel threads.) The returned string needs to be freed with
the libc <citerefentry
will fail with -ENODATA (More specifically: this call will not
work for kernel threads.) The returned string needs to be freed
with the libc <citerefentry
project='man-pages'><refentrytitle>free</refentrytitle><manvolnum>3</manvolnum></citerefentry>
call after use.</para>
@ -194,7 +208,7 @@
multiple login sessions of the same user, where
<function>sd_pid_get_session()</function> will fail. For processes
not being part of a login session and not being a shared process
of a user this function will fail with -ENXIO.</para>
of a user this function will fail with -ENODATA.</para>
<para><function>sd_pid_get_machine_name()</function> may be used
to determine the name of the VM or container is a member of. The
@ -203,7 +217,7 @@
<citerefentry
project='man-pages'><refentrytitle>free</refentrytitle><manvolnum>3</manvolnum></citerefentry>
call after use. For processes not part of a VM or containers this
function fails with -ENXIO.</para>
function fails with -ENODATA.</para>
<para><function>sd_pid_get_slice()</function> may be used to
determine the slice unit the process is a member of. See
@ -217,6 +231,17 @@
returns the user slice (as managed by the user's systemd instance)
of a process.</para>
<para><function>sd_pid_get_cgroup()</function> returns the control
group path of the specified process, relative to the root of the
hierarchy. Returns the path without trailing slash, except for
processes located in the root control group, where "/" is
returned. To find the actual control group path in the file system
the returned path needs to be prefixed with
<filename>/sys/fs/cgroup/</filename> (if the unified control group
setup is used), or
<filename>/sys/fs/cgroup/<replaceable>HIERARCHY</replaceable>/</filename>
(if the legacy multi-hierarchy control group setup is used).</para>
<para>If the <varname>pid</varname> parameter of any of these
functions is passed as 0, the operation is executed for the
calling process.</para>
@ -226,13 +251,14 @@
<function>sd_peer_get_user_unit()</function>,
<function>sd_peer_get_owner_uid()</function>,
<function>sd_peer_get_machine_name()</function>,
<function>sd_peer_get_slice()</function> and
<function>sd_peer_get_user_slice()</function> calls operate
similar to their PID counterparts, but operate on a connected
AF_UNIX socket and retrieve information about the connected peer
process. Note that these fields are retrieved via
<filename>/proc</filename>, and hence are not suitable for
authorization purposes, as they are subject to races.</para>
<function>sd_peer_get_slice()</function>,
<function>sd_peer_get_user_slice()</function> and
<function>sd_peer_get_cgroup()</function> calls operate similar to
their PID counterparts, but operate on a connected AF_UNIX socket
and retrieve information about the connected peer process. Note
that these fields are retrieved via <filename>/proc</filename>,
and hence are not suitable for authorization purposes, as they are
subject to races.</para>
</refsect1>
<refsect1>
@ -251,7 +277,22 @@
<variablelist>
<varlistentry>
<term><constant>-ENXIO</constant></term>
<term><constant>-ESRCH</constant></term>
<listitem><para>The specified PID does not refer to a running
process.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><constant>-BADF</constant></term>
<listitem><para>The specified socket file descriptor was
invalid.</para></listitem>
</varlistentry>
<varlistentry>
<term><constant>-ENODATA</constant></term>
<listitem><para>Given field is not specified for the described
process or peer.</para>
@ -259,11 +300,10 @@
</varlistentry>
<varlistentry>
<term><constant>-ESRCH</constant></term>
<term><constant>-EINVAL</constant></term>
<listitem><para>The specified PID does not refer to a running
process.</para>
</listitem>
<listitem><para>An input parameter was invalid (out of range,
or NULL, where that's not accepted).</para></listitem>
</varlistentry>
<varlistentry>

View File

@ -148,6 +148,43 @@
errno-style error code.</para>
</refsect1>
<refsect1>
<title>Errors</title>
<para>Returned errors may indicate the following problems:</para>
<variablelist>
<varlistentry>
<term><constant>-ENODATA</constant></term>
<listitem><para>Given field is not specified for the described
seat.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><constant>-ENXIO</constant></term>
<listitem><para>The specified seat is unknown.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><constant>-EINVAL</constant></term>
<listitem><para>An input parameter was invalid (out of range,
or NULL, where that's not accepted).</para></listitem>
</varlistentry>
<varlistentry>
<term><constant>-ENOMEM</constant></term>
<listitem><para>Memory allocation failed.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Notes</title>

View File

@ -289,6 +289,43 @@
negative errno-style error code.</para>
</refsect1>
<refsect1>
<title>Errors</title>
<para>Returned errors may indicate the following problems:</para>
<variablelist>
<varlistentry>
<term><constant>-ENXIO</constant></term>
<listitem><para>The specified session does not exist.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><constant>-ENODATA</constant></term>
<listitem><para>Given field is not specified for the described
session.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><constant>-EINVAL</constant></term>
<listitem><para>An input parameter was invalid (out of range,
or NULL, where that's not accepted).</para></listitem>
</varlistentry>
<varlistentry>
<term><constant>-ENOMEM</constant></term>
<listitem><para>Memory allocation failed.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Notes</title>

View File

@ -169,6 +169,45 @@
errno-style error code.</para>
</refsect1>
<refsect1>
<title>Errors</title>
<para>Returned errors may indicate the following problems:</para>
<variablelist>
<varlistentry>
<term><constant>-ENODATA</constant></term>
<listitem><para>Given field is not specified for the described
user.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><constant>-ENXIO</constant></term>
<listitem><para>The specified seat is unknown.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><constant>-EINVAL</constant></term>
<listitem><para>An input parameter was invalid (out of range,
or NULL, where that's not accepted). This is also returned if
the passed user ID is 0xFFFF or 0xFFFFFFFF, which are
undefined on Linux.</para></listitem>
</varlistentry>
<varlistentry>
<term><constant>-ENOMEM</constant></term>
<listitem><para>Memory allocation failed.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Notes</title>

View File

@ -30,7 +30,9 @@
the vendor, the recommended way is to place a symlink to
<filename>/dev/null</filename> in the configuration directory in
<filename>/etc/</filename>, with the same filename as the vendor
configuration file.</para>
configuration file. If the vendor configuration file is included in
the initrd image, the image has to be regenerated.</para>
</refsection>
<refsection id='main-conf'>

View File

@ -918,6 +918,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
<varname>RequiresOverridable=</varname>,
<varname>Requisite=</varname>,
<varname>RequisiteOverridable=</varname>,
<varname>ConsistsOf=</varname>,
<varname>Wants=</varname>, <varname>BindsTo=</varname>
dependencies. If no unit is specified,
<filename>default.target</filename> is implied.</para>

View File

@ -1,4 +1,4 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
@ -64,10 +64,10 @@
regular intervals (by default every 1s), similar in style to
<citerefentry project='man-pages'><refentrytitle>top</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para>
<para>If <command>systemd-cgtop</command> is not connected to a tty, no
column headers are printed and the default is to only run one iteration.
The <varname>--iterations</varname> argument, if given, is still honored.
This mode is suitable for scripting.</para>
<para>If <command>systemd-cgtop</command> is not connected to a
tty, no column headers are printed and the default is to only run
one iteration. The <varname>--iterations=</varname> argument, if
given, is honored. This mode is suitable for scripting.</para>
<para>Resource usage is only accounted for control groups in the
relevant hierarchy, i.e. CPU usage is only accounted for control
@ -104,6 +104,7 @@
<variablelist>
<varlistentry>
<term><option>-p</option></term>
<term><option>--order=path</option></term>
<listitem><para>Order by control group
path name.</para></listitem>
@ -111,25 +112,28 @@
<varlistentry>
<term><option>-t</option></term>
<term><option>--order=tasks</option></term>
<listitem><para>Order by number of tasks in control group
(i.e. threads and processes).</para></listitem>
<listitem><para>Order by number of processes in control group.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-c</option></term>
<term><option>--order=cpu</option></term>
<listitem><para>Order by CPU load.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-m</option></term>
<term><option>--order=memory</option></term>
<listitem><para>Order by memory usage.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-i</option></term>
<term><option>--order=io</option></term>
<listitem><para>Order by disk I/O load.</para></listitem>
</varlistentry>
@ -140,7 +144,7 @@
<listitem><para>Run in "batch" mode: do not accept input and
run until the iteration limit set with
<option>--iterations</option> is exhausted or until killed.
<option>--iterations=</option> is exhausted or until killed.
This mode could be useful for sending output from
<command>systemd-cgtop</command> to other programs or to a
file.</para></listitem>
@ -155,12 +159,45 @@
numbers.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--cpu=percentage</option></term>
<term><option>--cpu=time</option></term>
<listitem><para>Controls whether the CPU usage is shown as
percentage or time. By default the CPU usage is shown as
percentage. This setting may also be toggled at runtime by
pressing the <keycap>%</keycap> key.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-k</option></term>
<listitem><para>Include kernel threads when counting tasks in
control groups. By default, kernel threads are not included in
the count. This setting may also be toggled at runtime by
pressing the <keycap>k</keycap> key.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--recursive=</option></term>
<listitem><para>Controls whether the number of tasks shown for
a control group shall include all tasks that are contained in
any of the child control groups as well. Takes a boolean
argument, defaults to <literal>yes</literal>. If enabled the
tasks in child control groups are included, if disabled only
the tasks in the control group itself are counted. This
setting may also be toggled at runtime by pressing the
<keycap>r</keycap> key.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-n</option></term>
<term><option>--iterations=</option></term>
<listitem><para>Perform only this many iterations. A value of 0
indicates that the program should run indefinitely.</para></listitem>
<listitem><para>Perform only this many iterations. A value of
0 indicates that the program should run
indefinitely.</para></listitem>
</varlistentry>
<varlistentry>
@ -168,10 +205,11 @@
<term><option>--delay=</option></term>
<listitem><para>Specify refresh delay in seconds (or if one of
<literal>ms</literal>,
<literal>us</literal>,
<literal>ms</literal>, <literal>us</literal>,
<literal>min</literal> is specified as unit in this time
unit).</para></listitem>
unit). This setting may also be increased and decreased at
runtime by pressing the <keycap>+</keycap> and
<keycap>-</keycap> keys.</para></listitem>
</varlistentry>
<varlistentry>
@ -191,7 +229,6 @@
</refsect1>
<refsect1>
<title>Keys</title>
@ -200,49 +237,72 @@
<variablelist>
<varlistentry>
<term>h</term>
<term><keycap>h</keycap></term>
<listitem><para>Shows a short help text.</para></listitem>
</varlistentry>
<varlistentry>
<term>SPACE</term>
<term><keycap function="space"/></term>
<listitem><para>Immediately refresh output.</para></listitem>
</varlistentry>
<varlistentry>
<term>q</term>
<term><keycap>q</keycap></term>
<listitem><para>Terminate the program.</para></listitem>
</varlistentry>
<varlistentry>
<term>p</term>
<term>t</term>
<term>c</term>
<term>m</term>
<term>i</term>
<term><keycap>p</keycap></term>
<term><keycap>t</keycap></term>
<term><keycap>c</keycap></term>
<term><keycap>m</keycap></term>
<term><keycap>i</keycap></term>
<listitem><para>Sort the control groups by path, number of
tasks, CPU load, memory usage, or IO load, respectively.
</para></listitem>
tasks, CPU load, memory usage, or IO load, respectively. This
setting may also be controlled using the
<option>--order=</option> command line
switch.</para></listitem>
</varlistentry>
<varlistentry>
<term>%</term>
<term><keycap>%</keycap></term>
<listitem><para>Toggle between showing CPU time as time or
percentage.</para></listitem>
percentage. This setting may also be controlled using the
<option>--cpu=</option> command line switch.</para></listitem>
</varlistentry>
<varlistentry>
<term>+</term>
<term>-</term>
<term><keycap>+</keycap></term>
<term><keycap>-</keycap></term>
<listitem><para>Increase or decrease refresh delay,
respectively.</para></listitem>
respectively. This setting may also be controlled using the
<option>--delay=</option> command line
switch.</para></listitem>
</varlistentry>
<varlistentry>
<term><keycap>k</keycap></term>
<listitem><para>Toggle between including or excluding kernel
threads in control group task counts. This setting may also be
controlled using the <option>-k</option> command line
switch.</para></listitem>
</varlistentry>
<varlistentry>
<term><keycap>r</keycap></term>
<listitem><para>Toggle between recursively including or
excluding tasks in child control groups in control group task
counts. This setting may also be controlled using the
<option>--recursive=</option> command line
switch.</para></listitem>
</varlistentry>
</variablelist>

View File

@ -88,7 +88,7 @@
</thead>
<tbody>
<row>
<entry morerows="8">VM</entry>
<entry morerows="9">VM</entry>
<entry><varname>qemu</varname></entry>
<entry>QEMU software virtualization</entry>
</row>
@ -133,6 +133,11 @@
<entry>User-mode Linux</entry>
</row>
<row>
<entry><varname>parallels</varname></entry>
<entry>Parallels Desktop, Parallels Server</entry>
</row>
<row>
<entry morerows="5">container</entry>
<entry><varname>openvz</varname></entry>

View File

@ -69,7 +69,7 @@
units are explicitly configured (for example, listed in
<citerefentry
project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>),
the units this generator creates are overriden, but additional
the units this generator creates are overridden, but additional
automatic dependencies might be created.</para>
<para>This generator will only look for root partitions on the

View File

@ -1,4 +1,4 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
@ -576,12 +576,15 @@
<term><option>--bind-ro=</option></term>
<listitem><para>Bind mount a file or directory from the host
into the container. Either takes a path argument -- in which
into the container. Takes one of: a path argument -- in which
case the specified path will be mounted from the host to the
same path in the container --, or a colon-separated pair of
paths -- in which case the first specified path is the source
in the host, and the second path is the destination in the
container. Backslash escapes are interpreted so
container --, or a colon-separated triple of source path,
destination path and mount options. Mount options are comma
separated and currently only "rbind" and "norbind"
are allowed. Defaults to "rbind". Backslash escapes are interpreted so
<literal>\:</literal> may be used to embed colons in either path.
This option may be specified multiple times for
creating multiple independent bind mount points. The
@ -745,34 +748,86 @@
</varlistentry>
<varlistentry>
<term><option>--volatile</option><replaceable>=MODE</replaceable></term>
<term><option>--volatile</option></term>
<term><option>--volatile=</option><replaceable>MODE</replaceable></term>
<listitem><para>Boots the container in volatile mode. When no
mode parameter is passed or when mode is specified as
<literal>yes</literal> full volatile mode is enabled. This
<option>yes</option> full volatile mode is enabled. This
means the root directory is mounted as mostly unpopulated
<literal>tmpfs</literal> instance, and
<filename>/usr</filename> from the OS tree is mounted into it,
read-only (the system thus starts up with read-only OS
resources, but pristine state and configuration, any changes
to the either are lost on shutdown). When the mode parameter
is specified as <literal>state</literal> the OS tree is
is specified as <option>state</option> the OS tree is
mounted read-only, but <filename>/var</filename> is mounted as
<literal>tmpfs</literal> instance into it (the system thus
starts up with read-only OS resources and configuration, but
pristine state, any changes to the latter are lost on
shutdown). When the mode parameter is specified as
<literal>no</literal> (the default) the whole OS tree is made
<option>no</option> (the default) the whole OS tree is made
available writable.</para>
<para>Note that setting this to <literal>yes</literal> or
<literal>state</literal> will only work correctly with
<para>Note that setting this to <option>yes</option> or
<option>state</option> will only work correctly with
operating systems in the container that can boot up with only
<filename>/usr</filename> mounted, and are able to populate
<filename>/var</filename> automatically, as
needed.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--settings=</option><replaceable>MODE</replaceable></term>
<listitem><para>Controls whether
<command>systemd-nspawn</command> shall search for and use
additional per-container settings from
<filename>.nspawn</filename> files. Takes a boolean or the
special values <option>override</option> or
<option>trusted</option>.</para>
<para>If enabled (the default) a settings file named after the
machine (as specified with the <option>--machine=</option>
setting, or derived from the directory or image file name)
with the suffix <filename>.nspawn</filename> is searched in
<filename>/etc/systemd/nspawn/</filename> and
<filename>/run/systemd/nspawn/</filename>. If it is found
there, its settings are read and used. If it is not found
there it is subsequently searched in the same directory as the
image file or in the immediate parent of the root directory of
the container. In this case, if the file is found its settings
will be also read and used, but potentially unsafe settings
are ignored. Note that in both these cases settings on the
command line take precedence over the corresponding settings
from loaded <filename>.nspawn</filename> files, if both are
specified. Unsafe settings are considered all settings that
elevate the container's privileges or grant access to
additional resources such as files or directories of the
host. For details about the format and contents of
<filename>.nspawn</filename> files consult
<citerefentry><refentrytitle>systemd.nspawn</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
<para>If this option is set to <option>override</option> the
file is searched, read and used the same way, however the order of
precedence is reversed: settings read from the
<filename>.nspawn</filename> file will take precedence over
the corresponding command line options, if both are
specified.</para>
<para>If this option is set to <option>trusted</option> the
file is searched, read and used the same way, but regardless
if found in <filename>/etc/systemd/nspawn/</filename>,
<filename>/run/systemd/nspawn/</filename> or next to the image
file or container root directory, all settings will take
effect, however command line arguments still take precedence
over corresponding settings.</para>
<para>If disabled no <filename>.nspawn</filename> file is read
and no settings except the ones on the command line are in
effect.</para></listitem>
</varlistentry>
<xi:include href="standard-options.xml" xpointer="help" />
<xi:include href="standard-options.xml" xpointer="version" />
</variablelist>
@ -856,6 +911,7 @@
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.nspawn</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry project='man-pages'><refentrytitle>chroot</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry project='mankier'><refentrytitle>dnf</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry project='die-net'><refentrytitle>yum</refentrytitle><manvolnum>8</manvolnum></citerefentry>,

View File

@ -64,9 +64,9 @@
<para>When invoked without arguments a list of known paths and
their current values is shown. When at least one argument is
passed the path with this is name is queried and its value shown.
passed the path with this name is queried and its value shown.
The variables whose name begins with <literal>search-</literal>
don't refer to individual paths, but instead a to a list of
don't refer to individual paths, but instead to a list of
colon-separated search paths, in their order of precedence.</para>
</refsect1>

View File

@ -61,15 +61,22 @@
resolver and an LLMNR resolver and responder. It also generates
<filename>/run/systemd/resolve/resolv.conf</filename> for
compatibility which may be symlinked from
<filename>/etc/resolv.conf</filename>.</para>
<filename>/etc/resolv.conf</filename>. The glibc NSS module
<citerefentry><refentrytitle>nss-resolve</refentrytitle><manvolnum>8</manvolnum></citerefentry>
is necessary to allow libc's NSS resolver functions to resolve
host names via <command>systemd-resolved</command>.</para>
<para>The DNS servers contacted are determined from the global
settings in
<citerefentry><refentrytitle>resolved.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
the per-link static settings in <filename>.network</filename>
files, and the per-link dynamic settings received over DHCP. See
settings in <filename>/etc/systemd/resolved.conf</filename>, the
per-link static settings in <filename>/etc/systemd/network/*.network</filename> files,
and the per-link dynamic settings received over DHCP. See
<citerefentry><refentrytitle>resolved.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
and
<citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for more details.</para>
for details. To improve compatibility
<filename>/etc/resolv.conf</filename> is read in order to discover
configured system DNS servers, however only if it is not a symlink
to <filename>/run/systemd/resolve/resolv.conf</filename> (see above).</para>
<para><command>systemd-resolved</command> synthesizes DNS RRs for the following cases:</para>
@ -137,6 +144,7 @@
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>resolved.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>nss-resolve</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
</para>

View File

@ -112,6 +112,13 @@
<para>The following options are understood:</para>
<variablelist>
<varlistentry>
<term><option>--no-ask-password</option></term>
<listitem><para>Do not query the user for authentication for
privileged operations.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--scope</option></term>

View File

@ -534,6 +534,19 @@
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>EncapsulationLimit=</varname></term>
<listitem>
<para>The Tunnel Encapsulation Limit option specifies how many additional
levels of encapsulation are permitted to be prepended to the packet.
For example, a Tunnel Encapsulation Limit option containing a limit
value of zero means that a packet carrying that option may not enter
another tunnel before exiting the current tunnel.
(see <ulink url="https://tools.ietf.org/html/rfc2473#section-4.1.1"> RFC 2473</ulink>).
The valid range is 0-255 and <literal>none</literal>. Defaults to 4.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>Mode=</varname></term>
<listitem>

View File

@ -1,4 +1,4 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
@ -223,7 +223,7 @@
<varlistentry>
<term><varname>DHCP=</varname></term>
<listitem>
<para>Enables DHCPv4 and/or DHCPv6 support. Accepts
<para>Enables DHCPv4 and/or DHCPv6 client support. Accepts
<literal>yes</literal>, <literal>no</literal>,
<literal>ipv4</literal>, or <literal>ipv6</literal>.</para>
@ -235,9 +235,10 @@
<varlistentry>
<term><varname>DHCPServer=</varname></term>
<listitem>
<para>A boolean. Enables a basic DHCPv4 server on the
device. Mostly useful for handing out leases to container
instances.</para>
<para>A boolean. Enables DHCPv4 server support. Defaults
to <literal>no</literal>. Further settings for the DHCP
server may be set in the <literal>[DHCPServer]</literal>
section described below.</para>
</listitem>
</varlistentry>
<varlistentry>
@ -541,7 +542,9 @@
<refsect1>
<title>[DHCP] Section Options</title>
<para>The <literal>[DHCP]</literal> section accepts the following keys:</para>
<para>The <literal>[DHCP]</literal> section configures the
DHCPv4 and DHCP6 client, if it is enabled with the
<varname>DHCP=</varname> setting described above:</para>
<variablelist class='network-directives'>
<varlistentry>
@ -552,7 +555,8 @@
any statically configured ones.</para>
<para>This corresponds to the <option>nameserver</option>
option in <citerefentry project='man-pages'><refentrytitle>resolv.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
option in <citerefentry
project='man-pages'><refentrytitle>resolv.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
</listitem>
</varlistentry>
<varlistentry>
@ -582,7 +586,7 @@
<term><varname>UseHostname=</varname></term>
<listitem>
<para>When true (the default), the hostname received from
the DHCP server will be used as the transient hostname.
the DHCP server will be set as the transient hostname of the system
</para>
</listitem>
</varlistentry>
@ -615,6 +619,15 @@
table with metric of 1024.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>UseTimezone=</varname></term>
<listitem><para>When true, the timezone received from the
DHCP server will be set as as timezone of the local
system. Defaults to <literal>no</literal>.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>CriticalConnection=</varname></term>
<listitem>
@ -658,10 +671,113 @@
DHCP server.</para>
</listitem>
</varlistentry>
</variablelist>
</variablelist>
</refsect1>
<refsect1>
<title>[DHCPServer] Section Options</title>
<para>The <literal>[DHCPServer]</literal> section contains
settings for the DHCP server, if enabled via the
<varname>DHCPServer=</varname> option described above:</para>
<variablelist class='network-directives'>
<varlistentry>
<term><varname>PoolOffset=</varname></term>
<term><varname>PoolSize=</varname></term>
<listitem><para>Configures the pool of addresses to hand out. The pool
is a contiguous sequence of IP addresses in the subnet configured for
the server address, which does not include the subnet nor the broadcast
address. <varname>PoolOffset=</varname> takes the offset of the pool
from the start of subnet, or zero to use the default value.
<varname>PoolSize=</varname> takes the number of IP addresses in the
pool or zero to use the default value. By default the pool starts at
the first address after the subnet address and takes up the rest of
the subnet, excluding the broadcast address. If the pool includes
the server address (the default), this is reserved and not handed
out to clients.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>DefaultLeaseTimeSec=</varname></term>
<term><varname>MaxLeaseTimeSec=</varname></term>
<listitem><para>Control the default and maximum DHCP lease
time to pass to clients. These settings take time values in seconds or
another common time unit, depending on the suffix. The default
lease time is used for clients that did not ask for a specific
lease time. If a client asks for a lease time longer than the
maximum lease time it is automatically shortened to the
specified time. The default lease time defaults to 1h, the
maximum lease time to 12h. Shorter lease times are beneficial
if the configuration data in DHCP leases changes frequently
and clients shall learn the new settings with shorter
latencies. Longer lease times reduce the generated DHCP
network traffic.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>EmitDNS=</varname></term>
<term><varname>DNS=</varname></term>
<listitem><para>Configures whether the DHCP leases handed out
to clients shall contain DNS server information. The
<varname>EmitDNS=</varname> setting takes a boolean argument
and defaults to <literal>yes</literal>. The DNS servers to
pass to clients may be configured with the
<varname>DNS=</varname> option, which takes a list of IPv4
addresses. If the <varname>EmitDNS=</varname> option is
enabled but no servers configured the servers are
automatically propagated from an "uplink" interface that has
appropriate servers set. The "uplink" interface is determined
by the default route of the system with the highest
priority. Note that this information is acquired at the time
the lease is handed out, and does not take uplink interfaces
into account that acquire DNS or NTP server information at a
later point. DNS server propagation does not take
<filename>/etc/resolv.conf</filename> into account. Also, note
that the leases are not refreshed if uplink network
configuration changes. To ensure clients regularly acquire the
most current uplink DNS server information it is thus
advisable to shorten the DHCP lease time via
<varname>MaxLeaseTimeSec=</varname> described
above.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>EmitNTP=</varname></term>
<term><varname>NTP=</varname></term>
<listitem><para>Similar to the <varname>EmitDNS=</varname> and
<varname>DNS=</varname> settings described above these
settings configure whether and what NTP server information
shall be emitted as part of the DHCP lease. The same syntax,
propagation semantics and defaults apply as for
<varname>EmitDNS=</varname> and
<varname>DNS=</varname>.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>EmitTimezone=</varname></term>
<term><varname>Timezone=</varname></term>
<listitem><para>Configures whether the DHCP leases handed out
to clients shall contain timezone information. The
<varname>EmitTimezone=</varname> setting takes a boolean
argument and defaults to <literal>yes</literal>. The
<varname>Timezone=</varname> setting takes a timezone string
(such as <literal>Europe/Berlin</literal> or
<literal>UTC</literal>) to pass to clients. If no explicit
timezone is set the system timezone of the local host is
propagated, as determined by the
<filename>/etc/localtime</filename> symlink.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>[Bridge] Section Options</title>
<para>The <literal>[Bridge]</literal> section accepts the

383
man/systemd.nspawn.xml Normal file
View File

@ -0,0 +1,383 @@
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
<!ENTITY % entities SYSTEM "custom-entities.ent" >
%entities;
]>
<!--
This file is part of systemd.
Copyright 2015 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
-->
<refentry id="systemd.nspawn">
<refentryinfo>
<title>systemd.nspawn</title>
<productname>systemd</productname>
<authorgroup>
<author>
<contrib>Developer</contrib>
<firstname>Lennart</firstname>
<surname>Poettering</surname>
<email>lennart@poettering.net</email>
</author>
</authorgroup>
</refentryinfo>
<refmeta>
<refentrytitle>systemd.nspawn</refentrytitle>
<manvolnum>5</manvolnum>
</refmeta>
<refnamediv>
<refname>systemd.nspawn</refname>
<refpurpose>Container settings</refpurpose>
</refnamediv>
<refsynopsisdiv>
<para><filename>/etc/systemd/nspawn/<replaceable>machine</replaceable>.nspawn</filename></para>
<para><filename>/run/systemd/nspawn/<replaceable>machine</replaceable>.nspawn</filename></para>
<para><filename>/var/lib/machines/<replaceable>machine</replaceable>.nspawn</filename></para>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para>An nspawn container settings file (suffix
<filename>.nspawn</filename>) encodes additional runtime
information about a local container, and is searched, read and
used by
<citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>
when starting a container. Files of this type are named after the
containers they define settings for. They are optional, and only
required for containers whose execution environment shall differ
from the defaults. Files of this type mostly contain settings that
may also be set on the <command>systemd-nspawn</command> command
line, and make it easier to persistently attach specific settings
to specific containers. The syntax of these files is inspired by
<filename>.desktop</filename> files following the <ulink
url="http://standards.freedesktop.org/desktop-entry-spec/latest/">XDG
Desktop Entry Specification</ulink>, which are in turn inspired by
Microsoft Windows <filename>.ini</filename> files.</para>
<para>Boolean arguments used in these settings files can be
written in various formats. For positive settings the strings
<option>1</option>, <option>yes</option>, <option>true</option>
and <option>on</option> are equivalent. For negative settings, the
strings <option>0</option>, <option>no</option>,
<option>false</option> and <option>off</option> are
equivalent.</para>
<para>Empty lines and lines starting with # or ; are
ignored. This may be used for commenting. Lines ending
in a backslash are concatenated with the following
line while reading and the backslash is replaced by a
space character. This may be used to wrap long lines.</para>
</refsect1>
<refsect1>
<title><filename>.nspawn</filename> File Discovery</title>
<para>Files are searched by appending the
<filename>.nspawn</filename> suffix to the machine name of the
container, as specified with the <option>--machine=</option>
switch of <command>systemd-nspawn</command>, or derived from the
directory or image file name. This file is first searched in
<filename>/etc/systemd/nspawn/</filename> and
<filename>/run/systemd/nspawn/</filename>. If found in these
directories its settings are read and all of them take full effect
(but are possibly overridden by corresponding command line
arguments). If not found the file will then be searched next to
the image file or in the immediate parent of the root directory of
the container. If the file is found there only a subset of the
settings will take effect however. All settings that possibly
elevate privileges or grant additional access to resources of the
host (such as files or directories) are ignored. To which options
this applies is documented below.</para>
<para>Persistent settings file created and maintained by the
administrator (and thus trusted) should be placed in
<filename>/etc/systemd/nspawn/</filename>, while automatically
downloaded (and thus potentially untrusted) settings files are
placed in <filename>/var/lib/machines/</filename> instead (next to
the container images), where their security impact is limited. In
order to add privileged settings to <filename>.nspawn</filename>
files acquired from the image vendor it is recommended to copy the
settings files into <filename>/etc/systemd/nspawn/</filename> and
edit them there, so that the privileged options become
available. The precise algorithm how the files are searched and
interpreted may be configured with
<command>systemd-nspawn</command>'s <option>--settings=</option>
switch, see
<citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>
for details.</para>
</refsect1>
<refsect1>
<title>[Exec] Section Options</title>
<para>Settings files may include an <literal>[Exec]</literal>
section, which carries various execution parameters:</para>
<variablelist>
<varlistentry>
<term><varname>Boot=</varname></term>
<listitem><para>Takes a boolean argument, defaults to off. If
enabled <command>systemd-nspawn</command> will automatically
search for an <filename>init</filename> executable and invoke
it. In this case the specified parameters using
<varname>Parameters=</varname> are passed as additional
arguments to the <filename>init</filename> process. This
setting corresponds to the <option>--boot</option> switch on
the <command>systemd-nspawn</command> command
line. </para></listitem>
</varlistentry>
<varlistentry>
<term><varname>Parameters=</varname></term>
<listitem><para>Takes a space separated list of
arguments. This is either a command line, beginning with the
binary name to execute, or if <varname>Boot=</varname> is
enabled the list of arguments to pass to the init
process. This setting corresponds to the command line
parameters passed on the <command>systemd-nspawn</command>
command line.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>Environment=</varname></term>
<listitem><para>Takes an environment variable assignment
consisting of key and value, separated by
<literal>=</literal>. Sets an environment variable for the
main process invoked in the container. This setting may be
used multiple times to set multiple environment variables. It
corresponds to the <option>--setenv=</option> command line
switch.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>User=</varname></term>
<listitem><para>Takes a UNIX user name. Specifies the user
name to invoke the main process of the container as. This user
must be known in the container's user database. This
corresponds to the <option>--user=</option> command line
switch.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>Capability=</varname></term>
<term><varname>DropCapability=</varname></term>
<listitem><para>Takes a space separated list of Linux process
capabilities (see
<citerefentry><refentrytitle>capabilities</refentrytitle><manvolnum>7</manvolnum></citerefentry>
for details). The <varname>Capability=</varname> setting
specifies additional capabilities to pass on top of the
default set of capabilities. The
<varname>DropCapability=</varname> setting specifies
capabilities to drop from the default set. These settings
correspond to the <option>--capability=</option> and
<option>--drop-capability=</option> command line
switches. Note that <varname>Capability=</varname> is a
privileged setting, and only takes effect in
<filename>.nspawn</filename> files in
<filename>/etc/systemd/nspawn/</filename> and
<filename>/run/system/nspawn/</filename> (see above). On the
other hand <varname>DropCapability=</varname> takes effect in
all cases.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>Personality=</varname></term>
<listitem><para>Configures the kernel personality for the
container. This is equivalent to the
<option>--personality=</option> switch.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>MachineID=</varname></term>
<listitem><para>Configures the 128bit machine ID (UUID) to pass to
the container. This is equivalent to the
<option>--uuid=</option> command line switch. This option is
privileged (see above). </para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>[Files] Section Options</title>
<para>Settings files may include a <literal>[Files]</literal>
section, which carries various parameters configuring the file
system of the container:</para>
<variablelist>
<varlistentry>
<term><varname>ReadOnly=</varname></term>
<listitem><para>Takes a boolean argument, defaults to off. If
specified the container will be run with a read-only file
system. This setting corresponds to the
<option>--read-only</option> command line
switch.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>Volatile=</varname></term>
<listitem><para>Takes a boolean argument, or the special value
<literal>state</literal>. This configures whether to run the
container with volatile state and/or configuration. This
option is equivalent to <option>--volatile=</option>, see
<citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>
for details about the specific options
supported.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>Bind=</varname></term>
<term><varname>BindReadOnly=</varname></term>
<listitem><para>Adds a bind mount from the host into the
container. Takes a single path, a pair of two paths separated
by a colon, or a triplet of two paths plus an option string
separated by colons. This option may be used multiple times to
configure multiple bind mounts. This option is equivalent to
the command line switches <option>--bind=</option> and
<option>--bind-ro=</option>, see
<citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>
for details about the specific options supported. This setting
is privileged (see above).</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>TemporaryFileSystem=</varname></term>
<listitem><para>Adds a <literal>tmpfs</literal> mount to the
container. Takes a path or a pair of path and option string,
separated by a colon. This option may be used multiple times to
configure multiple <literal>tmpfs</literal> mounts. This
option is equivalent to the command line switch
<option>--tmpfs=</option>, see
<citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>
for details about the specific options supported. This setting
is privileged (see above).</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>[Network] Section Options</title>
<para>Settings files may include a <literal>[Network]</literal>
section, which carries various parameters configuring the network
connectivity of the container:</para>
<variablelist>
<varlistentry>
<term><varname>Private=</varname></term>
<listitem><para>Takes a boolean argument, defaults to off. If
enabled the container will run in its own network namespace
and not share network interfaces and configuration with the
host. This setting corresponds to the
<option>--private-network</option> command line
switch.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>VirtualEthernet=</varname></term>
<listitem><para>Takes a boolean argument. Configures whether
to create a virtual ethernet connection
(<literal>veth</literal>) between host and the container. This
setting implies <varname>Private=yes</varname>. This setting
corresponds to the <option>--network-veth</option> command
line switch. This option is privileged (see
above).</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>Interface=</varname></term>
<listitem><para>Takes a space separated list of interfaces to
add to the container. This option corresponds to the
<option>--network-interface=</option> command line switch and
implies <varname>Private=yes</varname>. This option is
privileged (see above).</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>MACVLAN=</varname></term>
<term><varname>IPVLAN=</varname></term>
<listitem><para>Takes a space separated list of interfaces to
add MACLVAN or IPVLAN interfaces to, which are then added to
the container. These options correspond to the
<option>--network-macvlan=</option> and
<option>--network-ipvlan=</option> command line switches and
imply <varname>Private=yes</varname>. These options are
privileged (see above).</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>Bridge=</varname></term>
<listitem><para>Takes an interface name. This setting implies
<varname>VirtualEthernet=yes</varname> and
<varname>Private=yes</varname> and has the effect that the
host side of the created virtual Ethernet link is connected to
the specified bridge interface. This option corresponds to the
<option>--network-bridge=</option> command line switch. This
option is privileged (see above).</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>Port=</varname></term>
<listitem><para>Exposes a TCP or UDP port of the container on
the host. This option corresponds to the
<option>--port=</option> command line switch, see
<citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>
for the precise syntax of the argument this option takes. This
option is privileged (see above).</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.directives</refentrytitle><manvolnum>7</manvolnum></citerefentry>
</para>
</refsect1>
</refentry>

View File

@ -256,7 +256,7 @@
</refsect1>
<refsect1>
<title>Unit Load Path</title>
<title>Unit File Load Path</title>
<para>Unit files are loaded from a set of paths determined during
compilation, described in the two tables below. Unit files found

View File

@ -12,3 +12,6 @@ Name=host0
[Network]
DHCP=yes
LinkLocalAddressing=yes
[DHCP]
UseTimezone=yes

View File

@ -5,3 +5,4 @@ src/locale/org.freedesktop.locale1.policy.in
src/login/org.freedesktop.login1.policy.in
src/machine/org.freedesktop.machine1.policy.in
src/timedate/org.freedesktop.timedate1.policy.in
src/core/dbus-unit.c

View File

@ -6,8 +6,8 @@ msgid ""
msgstr ""
"Project-Id-Version: systemd\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-06-18 00:53+0200\n"
"PO-Revision-Date: 2015-04-12 01:44+0200\n"
"POT-Creation-Date: 2015-09-06 20:39+0200\n"
"PO-Revision-Date: 2015-09-06 20:40+0200\n"
"Last-Translator: Piotr Drąg <piotrdrag@gmail.com>\n"
"Language-Team: Polish <trans-pl@lists.fedoraproject.org>\n"
"Language: pl\n"
@ -430,6 +430,14 @@ msgstr ""
"Wymagane jest uwierzytelnienie, aby wskazać oprogramowaniu sprzętowemu, że "
"należy uruchomić interfejs ustawień."
#: ../src/login/org.freedesktop.login1.policy.in.h:55
msgid "Set a wall message"
msgstr "Ustawienie komunikatu wall"
#: ../src/login/org.freedesktop.login1.policy.in.h:56
msgid "Authentication is required to set a wall message"
msgstr "Wymagane jest uwierzytelnienie, aby ustawić komunikat wall"
#: ../src/machine/org.freedesktop.machine1.policy.in.h:1
msgid "Log into a local container"
msgstr "Logowanie do lokalnego kontenera"
@ -440,21 +448,68 @@ msgstr ""
"Wymagane jest uwierzytelnienie, aby zalogować się do lokalnego kontenera."
#: ../src/machine/org.freedesktop.machine1.policy.in.h:3
msgid "Log into the local host"
msgstr "Logowanie do lokalnego komputera"
#: ../src/machine/org.freedesktop.machine1.policy.in.h:4
msgid "Authentication is required to log into the local host."
msgstr ""
"Wymagane jest uwierzytelnienie, aby zalogować się do lokalnego komputera."
#: ../src/machine/org.freedesktop.machine1.policy.in.h:5
msgid "Acquire a shell in a local container"
msgstr "Uzyskanie powłoki w lokalnym kontenerze"
#: ../src/machine/org.freedesktop.machine1.policy.in.h:6
msgid "Authentication is required to acquire a shell in a local container."
msgstr ""
"Wymagane jest uwierzytelnienie, aby uzyskać powłokę w lokalnym kontenerze."
#: ../src/machine/org.freedesktop.machine1.policy.in.h:7
msgid "Acquire a shell on the local host"
msgstr "Uzyskanie powłoki na lokalnym komputerze"
#: ../src/machine/org.freedesktop.machine1.policy.in.h:8
msgid "Authentication is required to acquire a shell on the local host."
msgstr ""
"Wymagane jest uwierzytelnienie, aby uzyskać powłokę na lokalnym komputerze."
#: ../src/machine/org.freedesktop.machine1.policy.in.h:9
msgid "Acquire a pseudo TTY in a local container"
msgstr "Uzyskanie pseudo-TTY w lokalnym kontenerze"
#: ../src/machine/org.freedesktop.machine1.policy.in.h:10
msgid ""
"Authentication is required to acquire a pseudo TTY in a local container."
msgstr ""
"Wymagane jest uwierzytelnienie, aby uzyskać pseudo-TTY w lokalnym kontenerze."
#: ../src/machine/org.freedesktop.machine1.policy.in.h:11
msgid "Acquire a pseudo TTY on the local host"
msgstr "Uzyskanie pseudo-TTY na lokalnym komputerze"
#: ../src/machine/org.freedesktop.machine1.policy.in.h:12
msgid "Authentication is required to acquire a pseudo TTY on the local host."
msgstr ""
"Wymagane jest uwierzytelnienie, aby uzyskać pseudo-TTY na lokalnym "
"komputerze."
#: ../src/machine/org.freedesktop.machine1.policy.in.h:13
msgid "Manage local virtual machines and containers"
msgstr "Zarządzanie lokalnymi maszynami wirtualnymi i kontenerami"
#: ../src/machine/org.freedesktop.machine1.policy.in.h:4
#: ../src/machine/org.freedesktop.machine1.policy.in.h:14
msgid ""
"Authentication is required to manage local virtual machines and containers."
msgstr ""
"Wymagane jest uwierzytelnienie, aby zarządzać lokalnymi maszynami "
"wirtualnymi i kontenerami."
#: ../src/machine/org.freedesktop.machine1.policy.in.h:5
#: ../src/machine/org.freedesktop.machine1.policy.in.h:15
msgid "Manage local virtual machine and container images"
msgstr "Zarządzanie lokalnymi obrazami maszyn wirtualnych i kontenerów"
#: ../src/machine/org.freedesktop.machine1.policy.in.h:6
#: ../src/machine/org.freedesktop.machine1.policy.in.h:16
msgid ""
"Authentication is required to manage local virtual machine and container "
"images."
@ -502,6 +557,40 @@ msgstr ""
"Wymagane jest uwierzytelnienie, aby kontrolować, czy włączyć synchronizację "
"czasu przez sieć."
#: ../src/core/dbus-unit.c:428
msgid "Authentication is required to start '$(unit)'."
msgstr "Wymagane jest uwierzytelnienie, aby uruchomić jednostkę „$(unit)”."
#: ../src/core/dbus-unit.c:429
msgid "Authentication is required to stop '$(unit)'."
msgstr "Wymagane jest uwierzytelnienie, aby zatrzymać jednostkę „$(unit)”."
#: ../src/core/dbus-unit.c:430
msgid "Authentication is required to reload '$(unit)'."
msgstr ""
"Wymagane jest uwierzytelnienie, aby ponownie wczytać jednostkę „$(unit)”."
#: ../src/core/dbus-unit.c:431 ../src/core/dbus-unit.c:432
msgid "Authentication is required to restart '$(unit)'."
msgstr ""
"Wymagane jest uwierzytelnienie, aby ponownie uruchomić jednostkę „$(unit)”."
#: ../src/core/dbus-unit.c:535
msgid "Authentication is required to kill '$(unit)'."
msgstr ""
"Wymagane jest uwierzytelnienie, aby wymusić wyłączenie jednostki „$(unit)”."
#: ../src/core/dbus-unit.c:565
msgid "Authentication is required to reset the \"failed\" state of '$(unit)'."
msgstr ""
"Wymagane jest uwierzytelnienie, aby przywrócić stan „failed” (niepowodzenia) "
"jednostki „$(unit)”."
#: ../src/core/dbus-unit.c:597
msgid "Authentication is required to set properties on '$(unit)'."
msgstr ""
"Wymagane jest uwierzytelnienie, aby ustawić właściwości jednostki „$(unit)”."
#~ msgid "Press Ctrl+C to cancel all filesystem checks in progress"
#~ msgstr ""
#~ "Naciśnięcie klawiszy Ctrl+C anuluje wszystkie trwające procesy "

View File

@ -0,0 +1,70 @@
# networkctl(1) completion -*- shell-script -*-
#
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# systemd is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with systemd; If not, see <http://www.gnu.org/licenses/>.
__contains_word () {
local w word=$1; shift
for w in "$@"; do
[[ $w = "$word" ]] && return
done
return 1
}
__get_links() {
networkctl list --no-legend --no-pager --all | awk '{ print $2 }' | sort -u
}
_networkctl() {
local i verb comps
local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]}
local -A OPTS=(
[STANDALONE]='-a --all -h --help --version --no-pager --no-legend'
[ARG]=''
)
local -A VERBS=(
[STANDALONE]='list lldp'
[LINKS]='status'
)
_init_completion || return
for ((i=0; i < COMP_CWORD; i++)); do
if __contains_word "${COMP_WORDS[i]}" ${VERBS[*]} &&
! __contains_word "${COMP_WORDS[i-1]}" ${OPTS[ARG]}; then
verb=${COMP_WORDS[i]}
break
fi
done
if [[ "$cur" = -* ]]; then
COMPREPLY=( $(compgen -W '${OPTS[*]}' -- "$cur") )
return 0
fi
if [[ -z $verb ]]; then
comps=${VERBS[*]}
elif __contains_word "$verb" ${VERBS[STANDALONE]}; then
comps=''
elif __contains_word "$verb" ${VERBS[LINKS]}; then
comps=$( __get_links )
fi
COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
return 0
}
complete -F _networkctl networkctl

View File

@ -85,6 +85,12 @@ __get_masked_units () { __systemctl $1 list-unit-files \
| { while read -r a b c ; do [[ $b == "masked" ]] && echo " $a"; done; }; }
__get_all_unit_files () { { __systemctl $1 list-unit-files; } | { while read -r a b; do echo " $a"; done; }; }
__get_machines() {
local a b
(machinectl list-images --no-legend --no-pager; machinectl list --no-legend --no-pager) | \
{ while read a b; do echo " $a"; done; } | sort -u;
}
_systemctl () {
local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]}
local i verb comps mode
@ -92,8 +98,10 @@ _systemctl () {
local -A OPTS=(
[STANDALONE]='--all -a --reverse --after --before --defaults --failed --force -f --full -l --global
--help -h --no-ask-password --no-block --no-legend --no-pager --no-reload --no-wall
--quiet -q --privileged -P --system --user --version --runtime --recursive -r --firmware-setup'
[ARG]='--host -H --kill-who --property -p --signal -s --type -t --state --job-mode --root'
--quiet -q --privileged -P --system --user --version --runtime --recursive -r --firmware-setup
--show-types -i --ignore-inhibitors --plain'
[ARG]='--host -H --kill-who --property -p --signal -s --type -t --state --job-mode --root
--preset-mode -n --lines -o --output -M --machine'
)
if __contains_word "--user" ${COMP_WORDS[*]}; then
@ -112,7 +120,7 @@ _systemctl () {
;;
--state)
comps='loaded not-found stub
active inactive
active inactive failed
dead elapsed exited listening mounted plugged running waiting'
;;
--job-mode)
@ -132,6 +140,16 @@ _systemctl () {
--property|-p)
comps=$(__systemd_properties $mode)
;;
--preset-mode)
comps='full enable-only disable-only'
;;
--output|-o)
comps='short short-iso short-precise short-monotonic verbose export json
json-pretty json-sse cat'
;;
--machine|-M)
comps=$( __get_machines )
;;
esac
COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
return 0

View File

@ -35,8 +35,8 @@ _systemd_analyze() {
local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]}
local -A OPTS=(
[STANDALONE]='--help --version --system --user --from-pattern --to-pattern --order --require --no-pager'
[ARG]='-H --host -M --machine --fuzz --man'
[STANDALONE]='--help --version --system --user --order --require --no-pager --man'
[ARG]='-H --host -M --machine --fuzz --from-pattern --to-pattern '
)
local -A VERBS=(
@ -102,7 +102,7 @@ _systemd_analyze() {
elif __contains_word "$verb" ${VERBS[VERIFY]}; then
if [[ $cur = -* ]]; then
comps='--help --version --system --user --no-man'
comps='--help --version --system --user --man'
else
comps=$( compgen -A file -- "$cur" )
compopt -o filenames

View File

@ -0,0 +1,60 @@
# systemd-path(1) completion -*- shell-script -*-
#
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# systemd is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with systemd; If not, see <http://www.gnu.org/licenses/>.
__contains_word () {
local w word=$1; shift
for w in "$@"; do
[[ $w = "$word" ]] && return
done
return 1
}
__get_names() {
systemd-path | cut -d: -f1 | sort -u
}
_systemd_path() {
local comps
local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]}
local -A OPTS=(
[STANDALONE]='-h --help --version'
[ARG]='--suffix'
)
_init_completion || return
if __contains_word "$prev" ${OPTS[ARG]}; then
case $prev in
--suffix)
comps=''
;;
esac
COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
return 0
fi
if [[ "$cur" = -* ]]; then
COMPREPLY=( $(compgen -W '${OPTS[*]}' -- "$cur") )
return 0
fi
comps=$( __get_names )
COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
return 0
}
complete -F _systemd_path systemd-path

View File

@ -34,10 +34,16 @@ _systemd_run() {
local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]}
local OPTS='-h --help --version --user --system --scope --unit --description --slice
-r --remain-after-exit --send-sighup -H --host -M --machine --service-type
--uid --gid --nice --setenv -p --property'
--on-active --on-boot --on-startup --on-unit-active --on-unit-inactive
--on-calendar --timer-property -t --pty -q --quiet --no-block
--uid --gid --nice --setenv -p --property --no-ask-password'
local mode=--system
local i
local opts_with_values=(
--unit --description --slice --service-type -H --host -M --machine -p --property --on-active
--on-boot --on-startup --on-unit-active --on-unit-inactive --on-calendar --timer-property
)
for (( i=1; i <= COMP_CWORD; i++ )); do
if [[ ${COMP_WORDS[i]} != -* ]]; then
local root_command=${COMP_WORDS[i]}
@ -47,11 +53,11 @@ _systemd_run() {
[[ ${COMP_WORDS[i]} == "--user" ]] && mode=--user
[[ $i -lt $COMP_CWORD && ${COMP_WORDS[i]} == @(--unit|--description|--slice|--service-type|-H|--host|-M|--machine|-p|--property) ]] && ((i++))
[[ $i -lt $COMP_CWORD && " ${opts_with_values[@]} " =~ " ${COMP_WORDS[i]} " ]] && ((i++))
done
case "$prev" in
--unit|--description)
--unit|--description|--on-active|--on-boot|--on-startup|--on-unit-active|--on-unit-inactive|--on-calendar)
# argument required but no completions available
return
;;
@ -89,6 +95,11 @@ _systemd_run() {
-M|--machine)
local comps=$( __get_machines )
COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
return 0
;;
--timer-property)
local comps='AccuracySec= WakeSystem='
COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
return 0
;;

View File

@ -1092,12 +1092,59 @@ static int graph_one(sd_bus *bus, const UnitInfo *u, char *patterns[]) {
return 0;
}
static int expand_patterns(sd_bus *bus, char **patterns, char ***ret) {
_cleanup_strv_free_ char **expanded_patterns = NULL;
char **pattern;
int r;
STRV_FOREACH(pattern, patterns) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_free_ char *unit = NULL, *unit_id = NULL;
if (strv_extend(&expanded_patterns, *pattern) < 0)
return log_oom();
if (string_is_glob(*pattern))
continue;
unit = unit_dbus_path_from_name(*pattern);
if (!unit)
return log_oom();
r = sd_bus_get_property_string(
bus,
"org.freedesktop.systemd1",
unit,
"org.freedesktop.systemd1.Unit",
"Id",
&error,
&unit_id);
if (r < 0)
return log_error_errno(r, "Failed to get ID: %s", bus_error_message(&error, r));
if (!streq(*pattern, unit_id)) {
if (strv_extend(&expanded_patterns, unit_id) < 0)
return log_oom();
}
}
*ret = expanded_patterns;
expanded_patterns = NULL; /* do not free */
return 0;
}
static int dot(sd_bus *bus, char* patterns[]) {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_strv_free_ char **expanded_patterns = NULL;
int r;
UnitInfo u;
r = expand_patterns(bus, patterns, &expanded_patterns);
if (r < 0)
return r;
r = sd_bus_call_method(
bus,
"org.freedesktop.systemd1",
@ -1120,7 +1167,7 @@ static int dot(sd_bus *bus, char* patterns[]) {
while ((r = bus_parse_unit_info(reply, &u)) > 0) {
r = graph_one(bus, &u, patterns);
r = graph_one(bus, &u, expanded_patterns);
if (r < 0)
return r;
}

View File

@ -36,6 +36,11 @@ int audit_session_from_pid(pid_t pid, uint32_t *id) {
assert(id);
/* We don't convert ENOENT to ESRCH here, since we can't
* really distuingish between "audit is not available in the
* kernel" and "the process does not exist", both which will
* result in ENOENT. */
p = procfs_file_alloca(pid, "sessionid");
r = read_one_line_file(p, &s);
@ -47,7 +52,7 @@ int audit_session_from_pid(pid_t pid, uint32_t *id) {
return r;
if (u == AUDIT_SESSION_INVALID || u <= 0)
return -ENXIO;
return -ENODATA;
*id = u;
return 0;
@ -68,6 +73,8 @@ int audit_loginuid_from_pid(pid_t pid, uid_t *uid) {
return r;
r = parse_uid(s, &u);
if (r == -ENXIO) /* the UID was -1 */
return -ENODATA;
if (r < 0)
return r;

File diff suppressed because it is too large Load Diff

View File

@ -28,15 +28,28 @@
#include "set.h"
#include "def.h"
/* An enum of well known cgroup controllers */
typedef enum CGroupController {
CGROUP_CONTROLLER_CPU,
CGROUP_CONTROLLER_CPUACCT,
CGROUP_CONTROLLER_BLKIO,
CGROUP_CONTROLLER_MEMORY,
CGROUP_CONTROLLER_DEVICE,
_CGROUP_CONTROLLER_MAX,
_CGROUP_CONTROLLER_INVALID = -1,
} CGroupController;
#define CGROUP_CONTROLLER_TO_MASK(c) (1 << (c))
/* A bit mask of well known cgroup controllers */
typedef enum CGroupControllerMask {
CGROUP_CPU = 1,
CGROUP_CPUACCT = 2,
CGROUP_BLKIO = 4,
CGROUP_MEMORY = 8,
CGROUP_DEVICE = 16,
_CGROUP_CONTROLLER_MASK_ALL = 31
} CGroupControllerMask;
typedef enum CGroupMask {
CGROUP_MASK_CPU = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_CPU),
CGROUP_MASK_CPUACCT = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_CPUACCT),
CGROUP_MASK_BLKIO = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_BLKIO),
CGROUP_MASK_MEMORY = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_MEMORY),
CGROUP_MASK_DEVICE = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_DEVICE),
_CGROUP_MASK_ALL = CGROUP_CONTROLLER_TO_MASK(_CGROUP_CONTROLLER_MAX) - 1
} CGroupMask;
/*
* General rules:
@ -77,7 +90,6 @@ int cg_pid_get_path(const char *controller, pid_t pid, char **path);
int cg_trim(const char *controller, const char *path, bool delete_root);
int cg_rmdir(const char *controller, const char *path);
int cg_delete(const char *controller, const char *path);
int cg_create(const char *controller, const char *path);
int cg_attach(const char *controller, const char *path, pid_t pid);
@ -93,8 +105,8 @@ int cg_set_task_access(const char *controller, const char *path, mode_t mode, ui
int cg_install_release_agent(const char *controller, const char *agent);
int cg_uninstall_release_agent(const char *controller);
int cg_is_empty(const char *controller, const char *path, bool ignore_self);
int cg_is_empty_recursive(const char *controller, const char *path, bool ignore_self);
int cg_is_empty(const char *controller, const char *path);
int cg_is_empty_recursive(const char *controller, const char *path);
int cg_get_root_path(char **path);
@ -126,14 +138,24 @@ bool cg_controller_is_valid(const char *p);
int cg_slice_to_path(const char *unit, char **ret);
typedef const char* (*cg_migrate_callback_t)(CGroupControllerMask mask, void *userdata);
typedef const char* (*cg_migrate_callback_t)(CGroupMask mask, void *userdata);
int cg_create_everywhere(CGroupControllerMask supported, CGroupControllerMask mask, const char *path);
int cg_attach_everywhere(CGroupControllerMask supported, const char *path, pid_t pid, cg_migrate_callback_t callback, void *userdata);
int cg_attach_many_everywhere(CGroupControllerMask supported, const char *path, Set* pids, cg_migrate_callback_t callback, void *userdata);
int cg_migrate_everywhere(CGroupControllerMask supported, const char *from, const char *to, cg_migrate_callback_t callback, void *userdata);
int cg_trim_everywhere(CGroupControllerMask supported, const char *path, bool delete_root);
int cg_create_everywhere(CGroupMask supported, CGroupMask mask, const char *path);
int cg_attach_everywhere(CGroupMask supported, const char *path, pid_t pid, cg_migrate_callback_t callback, void *userdata);
int cg_attach_many_everywhere(CGroupMask supported, const char *path, Set* pids, cg_migrate_callback_t callback, void *userdata);
int cg_migrate_everywhere(CGroupMask supported, const char *from, const char *to, cg_migrate_callback_t callback, void *userdata);
int cg_trim_everywhere(CGroupMask supported, const char *path, bool delete_root);
int cg_enable_everywhere(CGroupMask supported, CGroupMask mask, const char *p);
CGroupControllerMask cg_mask_supported(void);
int cg_mask_supported(CGroupMask *ret);
int cg_kernel_controllers(Set *controllers);
int cg_unified(void);
void cg_unified_flush(void);
bool cg_is_unified_wanted(void);
bool cg_is_legacy_wanted(void);
const char* cgroup_controller_to_string(CGroupController c) _const_;
CGroupController cgroup_controller_from_string(const char *s) _pure_;

View File

@ -22,7 +22,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
int conf_files_list(char ***strv, const char *suffix, const char *root, const char *dir, ...);
int conf_files_list_strv(char ***strv, const char *suffix, const char *root, const char* const* dirs);
int conf_files_list_nulstr(char ***strv, const char *suffix, const char *root, const char *dirs);
int conf_files_list(char ***ret, const char *suffix, const char *root, const char *dir, ...);
int conf_files_list_strv(char ***ret, const char *suffix, const char *root, const char* const* dirs);
int conf_files_list_nulstr(char ***ret, const char *suffix, const char *root, const char *dirs);

View File

@ -30,7 +30,7 @@
#define COPY_BUFFER_SIZE (16*1024)
int copy_bytes(int fdf, int fdt, off_t max_bytes, bool try_reflink) {
bool try_sendfile = true;
bool try_sendfile = true, try_splice = true;
int r;
assert(fdf >= 0);
@ -69,7 +69,23 @@ int copy_bytes(int fdf, int fdt, off_t max_bytes, bool try_reflink) {
} else if (n == 0) /* EOF */
break;
else if (n > 0)
/* Succcess! */
/* Success! */
goto next;
}
/* The try splice, unless we already tried */
if (try_splice) {
n = splice(fdf, NULL, fdt, NULL, m, 0);
if (n < 0) {
if (errno != EINVAL && errno != ENOSYS)
return -errno;
try_splice = false;
/* use fallback below */
} else if (n == 0) /* EOF */
break;
else if (n > 0)
/* Success! */
goto next;
}

View File

@ -35,7 +35,7 @@
* the watchdog pings will keep the loop busy. */
#define DEFAULT_EXIT_USEC (30*USEC_PER_SEC)
#define SYSTEMD_CGROUP_CONTROLLER "systemd"
#define SYSTEMD_CGROUP_CONTROLLER "name=systemd"
#define SIGNALS_CRASH_HANDLER SIGSEGV,SIGILL,SIGFPE,SIGBUS,SIGQUIT,SIGABRT
#define SIGNALS_IGNORE SIGPIPE

View File

@ -298,6 +298,9 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) {
#define PTR_TO_GID(p) ((gid_t) (((uintptr_t) (p))-1))
#define GID_TO_PTR(u) ((void*) (((uintptr_t) (u))+1))
#define PTR_TO_PID(p) ((pid_t) ((uintptr_t) p))
#define PID_TO_PTR(p) ((void*) ((uintptr_t) p))
#define memzero(x,l) (memset((x), 0, (l)))
#define zero(x) (memzero(&(x), sizeof(x)))

View File

@ -492,6 +492,14 @@ struct btrfs_ioctl_quota_ctl_args {
#define BTRFS_SUPER_MAGIC 0x9123683E
#endif
#ifndef CGROUP_SUPER_MAGIC
#define CGROUP_SUPER_MAGIC 0x27e0eb
#endif
#ifndef TMPFS_MAGIC
#define TMPFS_MAGIC 0x01021994
#endif
#ifndef MS_MOVE
#define MS_MOVE 8192
#endif

View File

@ -181,10 +181,10 @@ int is_kernel_thread(pid_t pid) {
bool eof;
FILE *f;
if (pid == 0)
if (pid == 0 || pid == 1) /* pid 1, and we ourselves certainly aren't a kernel thread */
return 0;
assert(pid > 0);
assert(pid > 1);
p = procfs_file_alloca(pid, "cmdline");
f = fopen(p, "re");

View File

@ -21,7 +21,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
/* A type-safe atomic refcounter */
/* A type-safe atomic refcounter.
*
* DO NOT USE THIS UNLESS YOU ACTUALLY CARE ABOUT THREAD SAFETY! */
typedef struct {
volatile unsigned _value;

View File

@ -50,7 +50,6 @@ int ring_push(Ring *r, const void *u8, size_t size);
void ring_pull(Ring *r, size_t size);
/* return size of occupied buffer in bytes */
static inline size_t ring_get_size(Ring *r)
{
static inline size_t ring_get_size(Ring *r) {
return r->used;
}

View File

@ -199,11 +199,11 @@ int mac_selinux_get_create_label_from_exe(const char *exe, char **label) {
if (!mac_selinux_use())
return -EOPNOTSUPP;
r = getcon(&mycon);
r = getcon_raw(&mycon);
if (r < 0)
return -errno;
r = getfilecon(exe, &fcon);
r = getfilecon_raw(exe, &fcon);
if (r < 0)
return -errno;
@ -225,7 +225,7 @@ int mac_selinux_get_our_label(char **label) {
if (!mac_selinux_use())
return -EOPNOTSUPP;
r = getcon(label);
r = getcon_raw(label);
if (r < 0)
return -errno;
#endif
@ -249,7 +249,7 @@ int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *
if (!mac_selinux_use())
return -EOPNOTSUPP;
r = getcon(&mycon);
r = getcon_raw(&mycon);
if (r < 0)
return -errno;
@ -260,7 +260,7 @@ int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *
if (!exec_label) {
/* If there is no context set for next exec let's use context
of target executable */
r = getfilecon(exe, &fcon);
r = getfilecon_raw(exe, &fcon);
if (r < 0)
return -errno;
}

View File

@ -28,12 +28,14 @@ Set *internal_set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
#define set_new(ops) internal_set_new(ops HASHMAP_DEBUG_SRC_ARGS)
static inline void set_free(Set *s) {
static inline Set *set_free(Set *s) {
internal_hashmap_free(HASHMAP_BASE(s));
return NULL;
}
static inline void set_free_free(Set *s) {
static inline Set *set_free_free(Set *s) {
internal_hashmap_free_free(HASHMAP_BASE(s));
return NULL;
}
/* no set_free_free_free */

View File

@ -115,3 +115,6 @@
#define SPECIAL_USER_SLICE "user.slice"
#define SPECIAL_MACHINE_SLICE "machine.slice"
#define SPECIAL_ROOT_SLICE "-.slice"
/* The scope unit systemd itself lives in. */
#define SPECIAL_INIT_SCOPE "init.scope"

View File

@ -1074,3 +1074,22 @@ int get_ctty(pid_t pid, dev_t *_devnr, char **r) {
return 0;
}
int ptsname_namespace(int pty, char **ret) {
int no = -1, r;
/* Like ptsname(), but doesn't assume that the path is
* accessible in the local namespace. */
r = ioctl(pty, TIOCGPTN, &no);
if (r < 0)
return -errno;
if (no < 0)
return -EIO;
if (asprintf(ret, "/dev/pts/%i", no) < 0)
return -ENOMEM;
return 0;
}

View File

@ -107,3 +107,5 @@ int get_ctty(pid_t, dev_t *_devnr, char **r);
int getttyname_malloc(int fd, char **r);
int getttyname_harder(int fd, char **r);
int ptsname_namespace(int pty, char **ret);

View File

@ -26,6 +26,7 @@
#include "util.h"
#include "time-util.h"
#include "path-util.h"
#include "strv.h"
usec_t now(clockid_t clock_id) {
@ -36,6 +37,14 @@ usec_t now(clockid_t clock_id) {
return timespec_load(&ts);
}
nsec_t now_nsec(clockid_t clock_id) {
struct timespec ts;
assert_se(clock_gettime(clock_id, &ts) == 0);
return timespec_load_nsec(&ts);
}
dual_timestamp* dual_timestamp_get(dual_timestamp *ts) {
assert(ts);
@ -129,6 +138,18 @@ usec_t timespec_load(const struct timespec *ts) {
(usec_t) ts->tv_nsec / NSEC_PER_USEC;
}
nsec_t timespec_load_nsec(const struct timespec *ts) {
assert(ts);
if (ts->tv_sec == (time_t) -1 &&
ts->tv_nsec == (long) -1)
return NSEC_INFINITY;
return
(nsec_t) ts->tv_sec * NSEC_PER_SEC +
(nsec_t) ts->tv_nsec;
}
struct timespec *timespec_store(struct timespec *ts, usec_t u) {
assert(ts);
@ -971,7 +992,10 @@ bool timezone_is_valid(const char *name) {
const char *p, *t;
struct stat st;
if (!name || *name == 0 || *name == '/')
if (isempty(name))
return false;
if (name[0] == '/')
return false;
for (p = name; *p; p++) {
@ -1021,3 +1045,30 @@ clockid_t clock_boottime_or_monotonic(void) {
return clock;
}
int get_timezone(char **tz) {
_cleanup_free_ char *t = NULL;
const char *e;
char *z;
int r;
r = readlink_malloc("/etc/localtime", &t);
if (r < 0)
return r; /* returns EINVAL if not a symlink */
e = path_startswith(t, "/usr/share/zoneinfo/");
if (!e)
e = path_startswith(t, "../usr/share/zoneinfo/");
if (!e)
return -EINVAL;
if (!timezone_is_valid(e))
return -EINVAL;
z = strdup(e);
if (!z)
return -ENOMEM;
*tz = z;
return 0;
}

View File

@ -70,6 +70,7 @@ typedef struct dual_timestamp {
#define DUAL_TIMESTAMP_NULL ((struct dual_timestamp) { 0ULL, 0ULL })
usec_t now(clockid_t clock);
nsec_t now_nsec(clockid_t clock);
dual_timestamp* dual_timestamp_get(dual_timestamp *ts);
dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u);
@ -87,6 +88,8 @@ struct timespec *timespec_store(struct timespec *ts, usec_t u);
usec_t timeval_load(const struct timeval *tv) _pure_;
struct timeval *timeval_store(struct timeval *tv, usec_t u);
nsec_t timespec_load_nsec(const struct timespec *ts) _pure_;
char *format_timestamp(char *buf, size_t l, usec_t t);
char *format_timestamp_utc(char *buf, size_t l, usec_t t);
char *format_timestamp_us(char *buf, size_t l, usec_t t);
@ -110,3 +113,5 @@ bool timezone_is_valid(const char *name);
clockid_t clock_boottime_or_monotonic(void);
#define xstrftime(buf, fmt, tm) assert_se(strftime(buf, ELEMENTSOF(buf), fmt, tm) > 0)
int get_timezone(char **timezone);

View File

@ -586,6 +586,42 @@ int unit_name_from_dbus_path(const char *path, char **name) {
return 0;
}
const char* unit_dbus_interface_from_type(UnitType t) {
static const char *const table[_UNIT_TYPE_MAX] = {
[UNIT_SERVICE] = "org.freedesktop.systemd1.Service",
[UNIT_SOCKET] = "org.freedesktop.systemd1.Socket",
[UNIT_BUSNAME] = "org.freedesktop.systemd1.BusName",
[UNIT_TARGET] = "org.freedesktop.systemd1.Target",
[UNIT_SNAPSHOT] = "org.freedesktop.systemd1.Snapshot",
[UNIT_DEVICE] = "org.freedesktop.systemd1.Device",
[UNIT_MOUNT] = "org.freedesktop.systemd1.Mount",
[UNIT_AUTOMOUNT] = "org.freedesktop.systemd1.Automount",
[UNIT_SWAP] = "org.freedesktop.systemd1.Swap",
[UNIT_TIMER] = "org.freedesktop.systemd1.Timer",
[UNIT_PATH] = "org.freedesktop.systemd1.Path",
[UNIT_SLICE] = "org.freedesktop.systemd1.Slice",
[UNIT_SCOPE] = "org.freedesktop.systemd1.Scope",
};
if (t < 0)
return NULL;
if (t >= _UNIT_TYPE_MAX)
return NULL;
return table[t];
}
const char *unit_dbus_interface_from_name(const char *name) {
UnitType t;
t = unit_name_to_type(name);
if (t < 0)
return NULL;
return unit_dbus_interface_from_type(t);
}
static char *do_escape_mangle(const char *f, UnitNameMangle allow_globs, char *t) {
const char *valid_chars;
@ -787,7 +823,7 @@ static const char* const unit_type_table[_UNIT_TYPE_MAX] = {
[UNIT_TIMER] = "timer",
[UNIT_PATH] = "path",
[UNIT_SLICE] = "slice",
[UNIT_SCOPE] = "scope"
[UNIT_SCOPE] = "scope",
};
DEFINE_STRING_TABLE_LOOKUP(unit_type, UnitType);

View File

@ -152,6 +152,9 @@ int unit_name_to_path(const char *name, char **ret);
char *unit_dbus_path_from_name(const char *name);
int unit_name_from_dbus_path(const char *path, char **name);
const char* unit_dbus_interface_from_type(UnitType t);
const char *unit_dbus_interface_from_name(const char *name);
typedef enum UnitNameMangle {
UNIT_NAME_NOGLOB,
UNIT_NAME_GLOB,

View File

@ -373,6 +373,19 @@ int parse_pid(const char *s, pid_t* ret_pid) {
return 0;
}
bool uid_is_valid(uid_t uid) {
/* Some libc APIs use UID_INVALID as special placeholder */
if (uid == (uid_t) 0xFFFFFFFF)
return false;
/* A long time ago UIDs where 16bit, hence explicitly avoid the 16bit -1 too */
if (uid == (uid_t) 0xFFFF)
return false;
return true;
}
int parse_uid(const char *s, uid_t* ret_uid) {
unsigned long ul = 0;
uid_t uid;
@ -389,13 +402,11 @@ int parse_uid(const char *s, uid_t* ret_uid) {
if ((unsigned long) uid != ul)
return -ERANGE;
/* Some libc APIs use UID_INVALID as special placeholder */
if (uid == (uid_t) 0xFFFFFFFF)
return -ENXIO;
/* A long time ago UIDs where 16bit, hence explicitly avoid the 16bit -1 too */
if (uid == (uid_t) 0xFFFF)
return -ENXIO;
if (!uid_is_valid(uid))
return -ENXIO; /* we return ENXIO instead of EINVAL
* here, to make it easy to distuingish
* invalid numeric uids invalid
* strings. */
if (ret_uid)
*ret_uid = uid;
@ -4273,7 +4284,7 @@ bool is_locale_utf8(void) {
/* Check result, but ignore the result if C was set
* explicitly. */
cached_answer =
streq(set, "C") &&
STR_IN_SET(set, "C", "POSIX") &&
!getenv("LC_ALL") &&
!getenv("LC_CTYPE") &&
!getenv("LANG");
@ -5754,40 +5765,39 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra
switch (state) {
case START:
if (c == 0) {
if (flags & EXTRACT_DONT_COALESCE_SEPARATORS)
if (!GREEDY_REALLOC(s, allocated, sz+1))
return -ENOMEM;
if (flags & EXTRACT_DONT_COALESCE_SEPARATORS)
if (!GREEDY_REALLOC(s, allocated, sz+1))
return -ENOMEM;
if (c == 0)
goto finish_force_terminate;
} else if (strchr(separators, c)) {
else if (strchr(separators, c)) {
if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) {
if (!GREEDY_REALLOC(s, allocated, sz+1))
return -ENOMEM;
(*p) ++;
goto finish_force_next;
}
break;
}
/* We found a non-blank character, so we will always
* want to return a string (even if it is empty),
* allocate it here. */
if (!GREEDY_REALLOC(s, allocated, sz+1))
return -ENOMEM;
state = VALUE;
/* fallthrough */
case VALUE:
if (c == 0)
goto finish_force_terminate;
else if (c == '\'' && (flags & EXTRACT_QUOTES)) {
if (!GREEDY_REALLOC(s, allocated, sz+1))
return -ENOMEM;
else if (c == '\'' && (flags & EXTRACT_QUOTES))
state = SINGLE_QUOTE;
} else if (c == '\\')
else if (c == '\\')
state = VALUE_ESCAPE;
else if (c == '\"' && (flags & EXTRACT_QUOTES)) {
if (!GREEDY_REALLOC(s, allocated, sz+1))
return -ENOMEM;
else if (c == '\"' && (flags & EXTRACT_QUOTES))
state = DOUBLE_QUOTE;
} else if (strchr(separators, c)) {
else if (strchr(separators, c)) {
if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) {
(*p) ++;
goto finish_force_next;
@ -5891,8 +5901,6 @@ end_escape:
case SEPARATOR:
if (c == 0)
goto finish_force_terminate;
if (flags & EXTRACT_DONT_COALESCE_SEPARATORS)
goto finish_force_next;
if (!strchr(separators, c))
goto finish;
break;
@ -6098,6 +6106,9 @@ int openpt_in_namespace(pid_t pid, int flags) {
if (master < 0)
_exit(EXIT_FAILURE);
if (unlockpt(master) < 0)
_exit(EXIT_FAILURE);
cmsg = CMSG_FIRSTHDR(&mh);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;

View File

@ -83,7 +83,7 @@ int strcmp_ptr(const char *a, const char *b) _pure_;
#define newdup(t, p, n) ((t*) memdup_multiply(p, sizeof(t), (n)))
#define malloc0(n) (calloc((n), 1))
#define malloc0(n) (calloc(1, (n)))
static inline void *mfree(void *memory) {
free(memory);
@ -154,7 +154,10 @@ int parse_size(const char *t, off_t base, off_t *size);
int parse_boolean(const char *v) _pure_;
int parse_pid(const char *s, pid_t* ret_pid);
int parse_uid(const char *s, uid_t* ret_uid);
#define parse_gid(s, ret_uid) parse_uid(s, ret_uid)
#define parse_gid(s, ret_gid) parse_uid(s, ret_gid)
bool uid_is_valid(uid_t uid);
#define gid_is_valid(gid) uid_is_valid(gid)
int safe_atou(const char *s, unsigned *ret_u);
int safe_atoi(const char *s, int *ret_i);
@ -363,6 +366,9 @@ int fd_is_temporary_fs(int fd);
int pipe_eof(int fd);
DEFINE_TRIVIAL_CLEANUP_FUNC(cpu_set_t*, CPU_FREE);
#define _cleanup_cpu_free_ _cleanup_(CPU_FREEp)
cpu_set_t* cpu_set_malloc(unsigned *ncpus);
#define xsprintf(buf, fmt, ...) assert_se((size_t) snprintf(buf, ELEMENTSOF(buf), fmt, __VA_ARGS__) < ELEMENTSOF(buf))
@ -561,6 +567,7 @@ void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
void *arg);
#define _(String) gettext (String)
#define N_(String) String
void init_gettext(void);
bool is_locale_utf8(void);

View File

@ -156,7 +156,8 @@ static int detect_vm_dmi(const char **_id) {
"VMW\0" "vmware\0"
"innotek GmbH\0" "oracle\0"
"Xen\0" "xen\0"
"Bochs\0" "bochs\0";
"Bochs\0" "bochs\0"
"Parallels\0" "parallels\0";
unsigned i;
for (i = 0; i < ELEMENTSOF(dmi_vendors); i++) {
@ -244,8 +245,9 @@ int detect_vm(const char **id) {
r = detect_vm_dmi(&_id);
/* kvm with and without Virtualbox */
/* Parallels exports KVMKVMKVM leaf */
if (streq_ptr(_id_cpuid, "kvm")) {
if (r > 0 && streq(_id, "oracle"))
if (r > 0 && (streq(_id, "oracle") || streq(_id, "parallels")))
goto finish;
_id = _id_cpuid;

View File

@ -70,16 +70,14 @@ typedef struct {
BOOLEAN no_editor;
} Config;
static VOID cursor_left(UINTN *cursor, UINTN *first)
{
static VOID cursor_left(UINTN *cursor, UINTN *first) {
if ((*cursor) > 0)
(*cursor)--;
else if ((*first) > 0)
(*first)--;
}
static VOID cursor_right(UINTN *cursor, UINTN *first, UINTN x_max, UINTN len)
{
static VOID cursor_right(UINTN *cursor, UINTN *first, UINTN x_max, UINTN len) {
if ((*cursor)+1 < x_max)
(*cursor)++;
else if ((*first) + (*cursor) < len)
@ -856,13 +854,11 @@ static VOID config_entry_free(ConfigEntry *entry) {
FreePool(entry->options);
}
static BOOLEAN is_digit(CHAR16 c)
{
static BOOLEAN is_digit(CHAR16 c) {
return (c >= '0') && (c <= '9');
}
static UINTN c_order(CHAR16 c)
{
static UINTN c_order(CHAR16 c) {
if (c == '\0')
return 0;
if (is_digit(c))
@ -873,8 +869,7 @@ static UINTN c_order(CHAR16 c)
return c + 0x10000;
}
static INTN str_verscmp(CHAR16 *s1, CHAR16 *s2)
{
static INTN str_verscmp(CHAR16 *s1, CHAR16 *s2) {
CHAR16 *os1 = s1;
CHAR16 *os2 = s2;

View File

@ -54,7 +54,7 @@ static void help(void) {
" -a --all Show all groups, including empty\n"
" -l --full Do not ellipsize output\n"
" -k Include kernel threads in output\n"
" -M --machine Show container\n"
" -M --machine= Show container\n"
, program_invocation_short_name);
}
@ -123,146 +123,161 @@ static int parse_argv(int argc, char *argv[]) {
return 1;
}
int main(int argc, char *argv[]) {
int r = 0, retval = EXIT_FAILURE;
int output_flags;
_cleanup_free_ char *root = NULL;
static int get_cgroup_root(char **ret) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
_cleanup_free_ char *unit = NULL, *path = NULL;
const char *m;
int r;
if (!arg_machine) {
r = cg_get_root_path(ret);
if (r < 0)
return log_error_errno(r, "Failed to get root control group path: %m");
return 0;
}
m = strjoina("/run/systemd/machines/", arg_machine);
r = parse_env_file(m, NEWLINE, "SCOPE", &unit, NULL);
if (r < 0)
return log_error_errno(r, "Failed to load machine data: %m");
path = unit_dbus_path_from_name(unit);
if (!path)
return log_oom();
r = bus_open_transport(BUS_TRANSPORT_LOCAL, NULL, false, &bus);
if (r < 0)
return log_error_errno(r, "Failed to create bus connection: %m");
r = sd_bus_get_property_string(
bus,
"org.freedesktop.systemd1",
path,
unit_dbus_interface_from_name(unit),
"ControlGroup",
&error,
ret);
if (r < 0)
return log_error_errno(r, "Failed to query unit control group path: %s", bus_error_message(&error, r));
return 0;
}
int main(int argc, char *argv[]) {
int r, output_flags;
log_parse_environment();
log_open();
r = parse_argv(argc, argv);
if (r < 0)
if (r <= 0)
goto finish;
else if (r == 0) {
retval = EXIT_SUCCESS;
goto finish;
}
if (!arg_no_pager) {
r = pager_open(false);
if (r > 0) {
if (arg_full == -1)
arg_full = true;
}
if (r > 0 && arg_full < 0)
arg_full = true;
}
output_flags =
arg_all * OUTPUT_SHOW_ALL |
(arg_full > 0) * OUTPUT_FULL_WIDTH;
r = bus_open_transport(BUS_TRANSPORT_LOCAL, NULL, false, &bus);
if (r < 0) {
log_error_errno(r, "Failed to create bus connection: %m");
goto finish;
}
if (optind < argc) {
_cleanup_free_ char *root = NULL;
int i;
r = get_cgroup_root(&root);
if (r < 0)
goto finish;
for (i = optind; i < argc; i++) {
int q;
fprintf(stdout, "%s:\n", argv[i]);
fflush(stdout);
if (path_startswith(argv[i], "/sys/fs/cgroup")) {
if (arg_machine)
root = strjoin("machine/", arg_machine, "/", argv[i], NULL);
else
root = strdup(argv[i]);
if (!root)
return log_oom();
printf("Directory %s:\n", argv[i]);
fflush(stdout);
q = show_cgroup_by_path(argv[i], NULL, 0, arg_kernel_threads, output_flags);
} else {
_cleanup_free_ char *c = NULL, *p = NULL, *j = NULL;
const char *controller, *path;
r = cg_split_spec(argv[i], &c, &p);
if (r < 0) {
log_error_errno(r, "Failed to split argument %s: %m", argv[i]);
goto finish;
}
controller = c ?: SYSTEMD_CGROUP_CONTROLLER;
if (p) {
j = strjoin(root, "/", p, NULL);
if (!j) {
r = log_oom();
goto finish;
}
path_kill_slashes(j);
path = j;
} else
path = root;
if (cg_unified() > 0)
printf("Control group %s:\n", path);
else
printf("Controller %s; control group %s:\n", controller, path);
fflush(stdout);
q = show_cgroup(controller, path, NULL, 0, arg_kernel_threads, output_flags);
}
q = show_cgroup_by_path(root, NULL, 0,
arg_kernel_threads, output_flags);
if (q < 0)
r = q;
}
} else {
_cleanup_free_ char *p;
bool done = false;
p = get_current_dir_name();
if (!p) {
log_error_errno(errno, "Cannot determine current working directory: %m");
goto finish;
}
if (!arg_machine) {
_cleanup_free_ char *cwd = NULL;
if (path_startswith(p, "/sys/fs/cgroup") && !arg_machine) {
printf("Working Directory %s:\n", p);
r = show_cgroup_by_path(p, NULL, 0,
arg_kernel_threads, output_flags);
} else {
if (arg_machine) {
char *m;
const char *cgroup;
_cleanup_free_ char *unit = NULL;
_cleanup_free_ char *path = NULL;
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
m = strjoina("/run/systemd/machines/", arg_machine);
r = parse_env_file(m, NEWLINE, "SCOPE", &unit, NULL);
if (r < 0) {
log_error_errno(r, "Failed to get machine path: %m");
goto finish;
}
path = unit_dbus_path_from_name(unit);
if (!path) {
log_oom();
goto finish;
}
r = sd_bus_get_property(
bus,
"org.freedesktop.systemd1",
path,
endswith(unit, ".scope") ? "org.freedesktop.systemd1.Scope" : "org.freedesktop.systemd1.Service",
"ControlGroup",
&error,
&reply,
"s");
if (r < 0) {
log_error("Failed to query ControlGroup: %s", bus_error_message(&error, -r));
goto finish;
}
r = sd_bus_message_read(reply, "s", &cgroup);
if (r < 0) {
bus_log_parse_error(r);
goto finish;
}
root = strdup(cgroup);
if (!root) {
log_oom();
goto finish;
}
} else
r = cg_get_root_path(&root);
if (r < 0) {
log_error_errno(r, "Failed to get %s path: %m",
arg_machine ? "machine" : "root");
cwd = get_current_dir_name();
if (!cwd) {
r = log_error_errno(errno, "Cannot determine current working directory: %m");
goto finish;
}
r = show_cgroup(SYSTEMD_CGROUP_CONTROLLER, root, NULL, 0,
arg_kernel_threads, output_flags);
if (path_startswith(cwd, "/sys/fs/cgroup")) {
printf("Working directory %s:\n", cwd);
fflush(stdout);
r = show_cgroup_by_path(cwd, NULL, 0, arg_kernel_threads, output_flags);
done = true;
}
}
if (!done) {
_cleanup_free_ char *root = NULL;
r = get_cgroup_root(&root);
if (r < 0)
goto finish;
printf("Control group %s:\n", isempty(root) ? "/" : root);
fflush(stdout);
r = show_cgroup(SYSTEMD_CGROUP_CONTROLLER, root, NULL, 0, arg_kernel_threads, output_flags);
}
}
if (r < 0) {
log_error_errno(r, "Failed to list cgroup tree %s: %m", root);
retval = EXIT_FAILURE;
} else
retval = EXIT_SUCCESS;
if (r < 0)
log_error_errno(r, "Failed to list cgroup tree: %m");
finish:
pager_close();
return retval;
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}

View File

@ -19,7 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#define __STDC_FORMAT_MACROS
#include <errno.h>
#include <string.h>
#include <stdlib.h>
@ -31,6 +30,7 @@
#include "path-util.h"
#include "terminal-util.h"
#include "process-util.h"
#include "util.h"
#include "hashmap.h"
#include "cgroup-util.h"
@ -48,23 +48,25 @@ typedef struct Group {
unsigned n_tasks;
unsigned cpu_iteration;
uint64_t cpu_usage;
struct timespec cpu_timestamp;
nsec_t cpu_usage;
nsec_t cpu_timestamp;
double cpu_fraction;
uint64_t memory;
unsigned io_iteration;
uint64_t io_input, io_output;
struct timespec io_timestamp;
nsec_t io_timestamp;
uint64_t io_input_bps, io_output_bps;
} Group;
static unsigned arg_depth = 3;
static unsigned arg_iterations = (unsigned)-1;
static unsigned arg_iterations = (unsigned) -1;
static bool arg_batch = false;
static bool arg_raw = false;
static usec_t arg_delay = 1*USEC_PER_SEC;
static bool arg_kernel_threads = false;
static bool arg_recursive = true;
static enum {
ORDER_PATH,
@ -108,12 +110,16 @@ static const char *maybe_format_bytes(char *buf, size_t l, bool is_valid, off_t
return format_bytes(buf, l, t);
}
static int process(const char *controller, const char *path, Hashmap *a, Hashmap *b, unsigned iteration) {
static int process(
const char *controller,
const char *path,
Hashmap *a,
Hashmap *b,
unsigned iteration,
Group **ret) {
Group *g;
int r;
FILE *f = NULL;
pid_t pid;
unsigned n;
assert(controller);
assert(path);
@ -142,104 +148,111 @@ static int process(const char *controller, const char *path, Hashmap *a, Hashmap
r = hashmap_move_one(a, b, path);
if (r < 0)
return r;
g->cpu_valid = g->memory_valid = g->io_valid = g->n_tasks_valid = false;
}
}
/* Regardless which controller, let's find the maximum number
* of processes in any of it */
if (streq(controller, SYSTEMD_CGROUP_CONTROLLER)) {
_cleanup_fclose_ FILE *f = NULL;
pid_t pid;
r = cg_enumerate_processes(controller, path, &f);
if (r < 0)
return r;
r = cg_enumerate_processes(controller, path, &f);
if (r == -ENOENT)
return 0;
if (r < 0)
return r;
n = 0;
while (cg_read_pid(f, &pid) > 0)
n++;
fclose(f);
g->n_tasks = 0;
while (cg_read_pid(f, &pid) > 0) {
if (n > 0) {
if (g->n_tasks_valid)
g->n_tasks = MAX(g->n_tasks, n);
else
g->n_tasks = n;
if (!arg_kernel_threads && is_kernel_thread(pid) > 0)
continue;
g->n_tasks_valid = true;
}
g->n_tasks++;
}
if (streq(controller, "cpuacct")) {
if (g->n_tasks > 0)
g->n_tasks_valid = true;
} else if (streq(controller, "cpuacct") && cg_unified() <= 0) {
_cleanup_free_ char *p = NULL, *v = NULL;
uint64_t new_usage;
char *p, *v;
struct timespec ts;
nsec_t timestamp;
r = cg_get_path(controller, path, "cpuacct.usage", &p);
if (r < 0)
return r;
r = read_one_line_file(p, &v);
free(p);
if (r == -ENOENT)
return 0;
if (r < 0)
return r;
r = safe_atou64(v, &new_usage);
free(v);
if (r < 0)
return r;
assert_se(clock_gettime(CLOCK_MONOTONIC, &ts) == 0);
timestamp = now_nsec(CLOCK_MONOTONIC);
if (g->cpu_iteration == iteration - 1) {
uint64_t x, y;
if (g->cpu_iteration == iteration - 1 &&
(nsec_t) new_usage > g->cpu_usage) {
x = ((uint64_t) ts.tv_sec * 1000000000ULL + (uint64_t) ts.tv_nsec) -
((uint64_t) g->cpu_timestamp.tv_sec * 1000000000ULL + (uint64_t) g->cpu_timestamp.tv_nsec);
nsec_t x, y;
y = new_usage - g->cpu_usage;
x = timestamp - g->cpu_timestamp;
if (x < 1)
x = 1;
if (y > 0) {
g->cpu_fraction = (double) y / (double) x;
g->cpu_valid = true;
}
y = (nsec_t) new_usage - g->cpu_usage;
g->cpu_fraction = (double) y / (double) x;
g->cpu_valid = true;
}
g->cpu_usage = new_usage;
g->cpu_timestamp = ts;
g->cpu_usage = (nsec_t) new_usage;
g->cpu_timestamp = timestamp;
g->cpu_iteration = iteration;
} else if (streq(controller, "memory")) {
char *p, *v;
_cleanup_free_ char *p = NULL, *v = NULL;
r = cg_get_path(controller, path, "memory.usage_in_bytes", &p);
if (cg_unified() <= 0)
r = cg_get_path(controller, path, "memory.usage_in_bytes", &p);
else
r = cg_get_path(controller, path, "memory.current", &p);
if (r < 0)
return r;
r = read_one_line_file(p, &v);
free(p);
if (r == -ENOENT)
return 0;
if (r < 0)
return r;
r = safe_atou64(v, &g->memory);
free(v);
if (r < 0)
return r;
if (g->memory > 0)
g->memory_valid = true;
} else if (streq(controller, "blkio")) {
char *p;
} else if (streq(controller, "blkio") && cg_unified() <= 0) {
_cleanup_fclose_ FILE *f = NULL;
_cleanup_free_ char *p = NULL;
uint64_t wr = 0, rd = 0;
struct timespec ts;
nsec_t timestamp;
r = cg_get_path(controller, path, "blkio.io_service_bytes", &p);
if (r < 0)
return r;
f = fopen(p, "re");
free(p);
if (!f)
if (!f) {
if (errno == ENOENT)
return 0;
return -errno;
}
for (;;) {
char line[LINE_MAX], *l;
@ -269,20 +282,26 @@ static int process(const char *controller, const char *path, Hashmap *a, Hashmap
*q += k;
}
fclose(f);
assert_se(clock_gettime(CLOCK_MONOTONIC, &ts) == 0);
timestamp = now_nsec(CLOCK_MONOTONIC);
if (g->io_iteration == iteration - 1) {
uint64_t x, yr, yw;
x = ((uint64_t) ts.tv_sec * 1000000000ULL + (uint64_t) ts.tv_nsec) -
((uint64_t) g->io_timestamp.tv_sec * 1000000000ULL + (uint64_t) g->io_timestamp.tv_nsec);
x = (uint64_t) (timestamp - g->io_timestamp);
if (x < 1)
x = 1;
yr = rd - g->io_input;
yw = wr - g->io_output;
if (rd > g->io_input)
yr = rd - g->io_input;
else
yr = 0;
if (g->io_input > 0 || g->io_output > 0) {
if (wr > g->io_output)
yw = wr - g->io_output;
else
yw = 0;
if (yr > 0 || yw > 0) {
g->io_input_bps = (yr * 1000000000ULL) / x;
g->io_output_bps = (yw * 1000000000ULL) / x;
g->io_valid = true;
@ -291,10 +310,13 @@ static int process(const char *controller, const char *path, Hashmap *a, Hashmap
g->io_input = rd;
g->io_output = wr;
g->io_timestamp = ts;
g->io_timestamp = timestamp;
g->io_iteration = iteration;
}
if (ret)
*ret = g;
return 0;
}
@ -304,9 +326,11 @@ static int refresh_one(
Hashmap *a,
Hashmap *b,
unsigned iteration,
unsigned depth) {
unsigned depth,
Group **ret) {
DIR *d = NULL;
_cleanup_closedir_ DIR *d = NULL;
Group *ours;
int r;
assert(controller);
@ -316,83 +340,100 @@ static int refresh_one(
if (depth > arg_depth)
return 0;
r = process(controller, path, a, b, iteration);
r = process(controller, path, a, b, iteration, &ours);
if (r < 0)
return r;
r = cg_enumerate_subgroups(controller, path, &d);
if (r < 0) {
if (r == -ENOENT)
return 0;
if (r == -ENOENT)
return 0;
if (r < 0)
return r;
}
for (;;) {
char *fn, *p;
_cleanup_free_ char *fn = NULL, *p = NULL;
Group *child = NULL;
r = cg_read_subgroup(d, &fn);
if (r <= 0)
goto finish;
if (r < 0)
return r;
if (r == 0)
break;
p = strjoin(path, "/", fn, NULL);
free(fn);
if (!p) {
r = -ENOMEM;
goto finish;
}
if (!p)
return -ENOMEM;
path_kill_slashes(p);
r = refresh_one(controller, p, a, b, iteration, depth + 1);
free(p);
r = refresh_one(controller, p, a, b, iteration, depth + 1, &child);
if (r < 0)
goto finish;
return r;
if (arg_recursive &&
child &&
child->n_tasks_valid &&
streq(controller, SYSTEMD_CGROUP_CONTROLLER)) {
/* Recursively sum up processes */
if (ours->n_tasks_valid)
ours->n_tasks += child->n_tasks;
else {
ours->n_tasks = child->n_tasks;
ours->n_tasks_valid = true;
}
}
}
finish:
if (d)
closedir(d);
if (ret)
*ret = ours;
return r;
return 1;
}
static int refresh(Hashmap *a, Hashmap *b, unsigned iteration) {
static int refresh(const char *root, Hashmap *a, Hashmap *b, unsigned iteration) {
int r;
assert(a);
r = refresh_one("name=systemd", "/", a, b, iteration, 0);
r = refresh_one(SYSTEMD_CGROUP_CONTROLLER, root, a, b, iteration, 0, NULL);
if (r < 0)
if (r != -ENOENT)
return r;
r = refresh_one("cpuacct", "/", a, b, iteration, 0);
return r;
r = refresh_one("cpuacct", root, a, b, iteration, 0, NULL);
if (r < 0)
if (r != -ENOENT)
return r;
r = refresh_one("memory", "/", a, b, iteration, 0);
return r;
r = refresh_one("memory", root, a, b, iteration, 0, NULL);
if (r < 0)
if (r != -ENOENT)
return r;
return r;
r = refresh_one("blkio", root, a, b, iteration, 0, NULL);
if (r < 0)
return r;
r = refresh_one("blkio", "/", a, b, iteration, 0);
if (r < 0)
if (r != -ENOENT)
return r;
return 0;
}
static int group_compare(const void*a, const void *b) {
const Group *x = *(Group**)a, *y = *(Group**)b;
if (path_startswith(y->path, x->path))
return -1;
if (path_startswith(x->path, y->path))
return 1;
if (arg_order != ORDER_TASKS || arg_recursive) {
/* Let's make sure that the parent is always before
* the child. Except when ordering by tasks and
* recursive summing is off, since that is actually
* not accumulative for all children. */
if (arg_order == ORDER_CPU) {
if (path_startswith(y->path, x->path))
return -1;
if (path_startswith(x->path, y->path))
return 1;
}
switch (arg_order) {
case ORDER_PATH:
break;
case ORDER_CPU:
if (arg_cpu_type == CPU_PERCENT) {
if (x->cpu_valid && y->cpu_valid) {
if (x->cpu_fraction > y->cpu_fraction)
@ -409,10 +450,10 @@ static int group_compare(const void*a, const void *b) {
else if (x->cpu_usage < y->cpu_usage)
return 1;
}
}
if (arg_order == ORDER_TASKS) {
break;
case ORDER_TASKS:
if (x->n_tasks_valid && y->n_tasks_valid) {
if (x->n_tasks > y->n_tasks)
return -1;
@ -422,9 +463,10 @@ static int group_compare(const void*a, const void *b) {
return -1;
else if (y->n_tasks_valid)
return 1;
}
if (arg_order == ORDER_MEMORY) {
break;
case ORDER_MEMORY:
if (x->memory_valid && y->memory_valid) {
if (x->memory > y->memory)
return -1;
@ -434,9 +476,10 @@ static int group_compare(const void*a, const void *b) {
return -1;
else if (y->memory_valid)
return 1;
}
if (arg_order == ORDER_IO) {
break;
case ORDER_IO:
if (x->io_valid && y->io_valid) {
if (x->io_input_bps + x->io_output_bps > y->io_input_bps + y->io_output_bps)
return -1;
@ -448,13 +491,13 @@ static int group_compare(const void*a, const void *b) {
return 1;
}
return strcmp(x->path, y->path);
return path_compare(x->path, y->path);
}
#define ON ANSI_HIGHLIGHT_ON
#define OFF ANSI_HIGHLIGHT_OFF
static int display(Hashmap *a) {
static void display(Hashmap *a) {
Iterator i;
Group *g;
Group **array;
@ -481,9 +524,10 @@ static int display(Hashmap *a) {
for (j = 0; j < n; j++) {
unsigned cputlen, pathtlen;
format_timespan(buffer, sizeof(buffer), (nsec_t) (array[j]->cpu_usage / NSEC_PER_USEC), 0);
format_timespan(buffer, sizeof(buffer), (usec_t) (array[j]->cpu_usage / NSEC_PER_USEC), 0);
cputlen = strlen(buffer);
maxtcpu = MAX(maxtcpu, cputlen);
pathtlen = strlen(array[j]->path);
maxtpath = MAX(maxtpath, pathtlen);
}
@ -503,7 +547,7 @@ static int display(Hashmap *a) {
path_columns = 10;
printf("%s%-*s%s %s%7s%s %s%s%s %s%8s%s %s%8s%s %s%8s%s\n\n",
arg_order == ORDER_PATH ? ON : "", path_columns, "Path",
arg_order == ORDER_PATH ? ON : "", path_columns, "Control Group",
arg_order == ORDER_PATH ? OFF : "",
arg_order == ORDER_TASKS ? ON : "", "Tasks",
arg_order == ORDER_TASKS ? OFF : "",
@ -519,16 +563,17 @@ static int display(Hashmap *a) {
path_columns = maxtpath;
for (j = 0; j < n; j++) {
char *p;
_cleanup_free_ char *ellipsized = NULL;
const char *path;
if (on_tty() && j + 5 > rows)
break;
g = array[j];
p = ellipsize(g->path, path_columns, 33);
printf("%-*s", path_columns, p ? p : g->path);
free(p);
path = isempty(g->path) ? "/" : g->path;
ellipsized = ellipsize(path, path_columns, 33);
printf("%-*s", path_columns, ellipsized ?: path);
if (g->n_tasks_valid)
printf(" %7u", g->n_tasks);
@ -541,7 +586,7 @@ static int display(Hashmap *a) {
else
fputs(" -", stdout);
} else
printf(" %*s", maxtcpu, format_timespan(buffer, sizeof(buffer), (nsec_t) (g->cpu_usage / NSEC_PER_USEC), 0));
printf(" %*s", maxtcpu, format_timespan(buffer, sizeof(buffer), (usec_t) (g->cpu_usage / NSEC_PER_USEC), 0));
printf(" %8s", maybe_format_bytes(buffer, sizeof(buffer), g->memory_valid, g->memory));
printf(" %8s", maybe_format_bytes(buffer, sizeof(buffer), g->io_valid, g->io_input_bps));
@ -549,22 +594,23 @@ static int display(Hashmap *a) {
putchar('\n');
}
return 0;
}
static void help(void) {
printf("%s [OPTIONS...]\n\n"
"Show top control groups by their resource usage.\n\n"
" -h --help Show this help\n"
" --version Print version and exit\n"
" -p Order by path\n"
" -t Order by number of tasks\n"
" -c Order by CPU load\n"
" -m Order by memory load\n"
" -i Order by IO load\n"
" --version Show package version\n"
" -p --order=path Order by path\n"
" -t --order=tasks Order by number of tasks\n"
" -c --order=cpu Order by CPU load (default)\n"
" -m --order=memory Order by memory load\n"
" -i --order=io Order by IO load\n"
" -r --raw Provide raw (not human-readable) numbers\n"
" --cpu[=TYPE] Show CPU usage as time or percentage (default)\n"
" --cpu=percentage Show CPU usage as percentage (default)\n"
" --cpu=time Show CPU usage as time\n"
" -k Include kernel threads in task count\n"
" --recursive=BOOL Sum up task count recursively\n"
" -d --delay=DELAY Delay between updates\n"
" -n --iterations=N Run for N iterations before exiting\n"
" -b --batch Run in batch mode, accepting no input\n"
@ -577,28 +623,31 @@ static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
ARG_DEPTH,
ARG_CPU_TYPE
ARG_CPU_TYPE,
ARG_ORDER,
ARG_RECURSIVE,
};
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "delay", required_argument, NULL, 'd' },
{ "iterations", required_argument, NULL, 'n' },
{ "batch", no_argument, NULL, 'b' },
{ "raw", no_argument, NULL, 'r' },
{ "depth", required_argument, NULL, ARG_DEPTH },
{ "cpu", optional_argument, NULL, ARG_CPU_TYPE},
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "delay", required_argument, NULL, 'd' },
{ "iterations", required_argument, NULL, 'n' },
{ "batch", no_argument, NULL, 'b' },
{ "raw", no_argument, NULL, 'r' },
{ "depth", required_argument, NULL, ARG_DEPTH },
{ "cpu", optional_argument, NULL, ARG_CPU_TYPE },
{ "order", required_argument, NULL, ARG_ORDER },
{ "recursive", required_argument, NULL, ARG_RECURSIVE },
{}
};
int c;
int r;
int c, r;
assert(argc >= 1);
assert(argv);
while ((c = getopt_long(argc, argv, "hptcmin:brd:", options, NULL)) >= 0)
while ((c = getopt_long(argc, argv, "hptcmin:brd:k", options, NULL)) >= 0)
switch (c) {
@ -613,13 +662,17 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_CPU_TYPE:
if (optarg) {
if (strcmp(optarg, "time") == 0)
if (streq(optarg, "time"))
arg_cpu_type = CPU_TIME;
else if (strcmp(optarg, "percentage") == 0)
else if (streq(optarg, "percentage"))
arg_cpu_type = CPU_PERCENT;
else
else {
log_error("Unknown argument to --cpu=: %s", optarg);
return -EINVAL;
}
}
} else
arg_cpu_type = CPU_TIME;
break;
case ARG_DEPTH:
@ -677,6 +730,37 @@ static int parse_argv(int argc, char *argv[]) {
arg_order = ORDER_IO;
break;
case ARG_ORDER:
if (streq(optarg, "path"))
arg_order = ORDER_PATH;
else if (streq(optarg, "tasks"))
arg_order = ORDER_TASKS;
else if (streq(optarg, "cpu"))
arg_order = ORDER_CPU;
else if (streq(optarg, "memory"))
arg_order = ORDER_MEMORY;
else if (streq(optarg, "io"))
arg_order = ORDER_IO;
else {
log_error("Invalid argument to --order=: %s", optarg);
return -EINVAL;
}
break;
case 'k':
arg_kernel_threads = true;
break;
case ARG_RECURSIVE:
r = parse_boolean(optarg);
if (r < 0) {
log_error("Failed to parse --recursive= argument: %s", optarg);
return r;
}
arg_recursive = r;
break;
case '?':
return -EINVAL;
@ -698,6 +782,7 @@ int main(int argc, char *argv[]) {
unsigned iteration = 0;
usec_t last_refresh = 0;
bool quit = false, immediate_refresh = false;
_cleanup_free_ char *root = NULL;
log_parse_environment();
log_open();
@ -706,6 +791,12 @@ int main(int argc, char *argv[]) {
if (r <= 0)
goto finish;
r = cg_get_root_path(&root);
if (r < 0) {
log_error_errno(r, "Failed to get root control group path: %m");
goto finish;
}
a = hashmap_new(&string_hash_ops);
b = hashmap_new(&string_hash_ops);
if (!a || !b) {
@ -715,7 +806,7 @@ int main(int argc, char *argv[]) {
signal(SIGWINCH, columns_lines_cache_reset);
if (arg_iterations == (unsigned)-1)
if (arg_iterations == (unsigned) -1)
arg_iterations = on_tty() ? 0 : 1;
while (!quit) {
@ -728,9 +819,11 @@ int main(int argc, char *argv[]) {
if (t >= last_refresh + arg_delay || immediate_refresh) {
r = refresh(a, b, iteration++);
if (r < 0)
r = refresh(root, a, b, iteration++);
if (r < 0) {
log_error_errno(r, "Failed to refresh: %m");
goto finish;
}
group_hashmap_clear(b);
@ -742,9 +835,7 @@ int main(int argc, char *argv[]) {
immediate_refresh = false;
}
r = display(b);
if (r < 0)
goto finish;
display(b);
if (arg_iterations && iteration >= arg_iterations)
break;
@ -753,11 +844,10 @@ int main(int argc, char *argv[]) {
fputs("\n", stdout);
fflush(stdout);
if (arg_batch) {
usleep(last_refresh + arg_delay - t);
} else {
r = read_one_char(stdin, &key,
last_refresh + arg_delay - t, NULL);
if (arg_batch)
(void) usleep(last_refresh + arg_delay - t);
else {
r = read_one_char(stdin, &key, last_refresh + arg_delay - t, NULL);
if (r == -ETIMEDOUT)
continue;
if (r < 0) {
@ -808,6 +898,20 @@ int main(int argc, char *argv[]) {
arg_cpu_type = arg_cpu_type == CPU_TIME ? CPU_PERCENT : CPU_TIME;
break;
case 'k':
arg_kernel_threads = !arg_kernel_threads;
fprintf(stdout, "\nCounting kernel threads: %s.", yes_no(arg_kernel_threads));
fflush(stdout);
sleep(1);
break;
case 'r':
arg_recursive = !arg_recursive;
fprintf(stdout, "\nRecursive task counting: %s", yes_no(arg_recursive));
fflush(stdout);
sleep(1);
break;
case '+':
if (arg_delay < USEC_PER_SEC)
arg_delay += USEC_PER_MSEC*250;
@ -836,14 +940,17 @@ int main(int argc, char *argv[]) {
case 'h':
fprintf(stdout,
"\t<" ON "p" OFF "> By path; <" ON "t" OFF "> By tasks; <" ON "c" OFF "> By CPU; <" ON "m" OFF "> By memory; <" ON "i" OFF "> By I/O\n"
"\t<" ON "+" OFF "> Increase delay; <" ON "-" OFF "> Decrease delay; <" ON "%%" OFF "> Toggle time\n"
"\t<" ON "q" OFF "> Quit; <" ON "SPACE" OFF "> Refresh");
"\t<" ON "+" OFF "> Inc. delay; <" ON "-" OFF "> Dec. delay; <" ON "%%" OFF "> Toggle time; <" ON "SPACE" OFF "> Refresh\n"
"\t<" ON "k" OFF "> Count kernel threads; <" ON "r" OFF "> Count recursively; <" ON "q" OFF "> Quit");
fflush(stdout);
sleep(3);
break;
default:
fprintf(stdout, "\nUnknown key '%c'. Ignoring.", key);
if (key < ' ')
fprintf(stdout, "\nUnknown key '\\x%x'. Ignoring.", key);
else
fprintf(stdout, "\nUnknown key '%c'. Ignoring.", key);
fflush(stdout);
sleep(1);
break;
@ -856,10 +963,5 @@ finish:
group_hashmap_free(a);
group_hashmap_free(b);
if (r < 0) {
log_error_errno(r, "Exiting with failure: %m");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}

View File

@ -1075,7 +1075,6 @@ const UnitVTable automount_vtable = {
.reset_failed = automount_reset_failed,
.bus_interface = "org.freedesktop.systemd1.Automount",
.bus_vtable = bus_automount_vtable,
.shutdown = automount_shutdown,

View File

@ -1058,7 +1058,6 @@ const UnitVTable busname_vtable = {
.supported = busname_supported,
.bus_interface = "org.freedesktop.systemd1.BusName",
.bus_vtable = bus_busname_vtable,
.status_message_formats = {

View File

@ -283,7 +283,7 @@ fail:
return -errno;
}
void cgroup_context_apply(CGroupContext *c, CGroupControllerMask mask, const char *path, ManagerState state) {
void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, ManagerState state) {
bool is_root;
int r;
@ -304,7 +304,7 @@ void cgroup_context_apply(CGroupContext *c, CGroupControllerMask mask, const cha
* cgroup trees (assuming we are running in a container then),
* and missing cgroups, i.e. EROFS and ENOENT. */
if ((mask & CGROUP_CPU) && !is_root) {
if ((mask & CGROUP_MASK_CPU) && !is_root) {
char buf[MAX(DECIMAL_STR_MAX(unsigned long), DECIMAL_STR_MAX(usec_t)) + 1];
sprintf(buf, "%lu\n",
@ -331,7 +331,7 @@ void cgroup_context_apply(CGroupContext *c, CGroupControllerMask mask, const cha
"Failed to set cpu.cfs_quota_us on %s: %m", path);
}
if (mask & CGROUP_BLKIO) {
if (mask & CGROUP_MASK_BLKIO) {
char buf[MAX3(DECIMAL_STR_MAX(unsigned long)+1,
DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(unsigned long)*1,
DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(uint64_t)+1)];
@ -381,21 +381,30 @@ void cgroup_context_apply(CGroupContext *c, CGroupControllerMask mask, const cha
}
}
if ((mask & CGROUP_MEMORY) && !is_root) {
if ((mask & CGROUP_MASK_MEMORY) && !is_root) {
if (c->memory_limit != (uint64_t) -1) {
char buf[DECIMAL_STR_MAX(uint64_t) + 1];
sprintf(buf, "%" PRIu64 "\n", c->memory_limit);
r = cg_set_attribute("memory", path, "memory.limit_in_bytes", buf);
} else
r = cg_set_attribute("memory", path, "memory.limit_in_bytes", "-1");
if (cg_unified() <= 0)
r = cg_set_attribute("memory", path, "memory.limit_in_bytes", buf);
else
r = cg_set_attribute("memory", path, "memory.max", buf);
} else {
if (cg_unified() <= 0)
r = cg_set_attribute("memory", path, "memory.limit_in_bytes", "-1");
else
r = cg_set_attribute("memory", path, "memory.max", "max");
}
if (r < 0)
log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r,
"Failed to set memory.limit_in_bytes on %s: %m", path);
"Failed to set memory.limit_in_bytes/memory.max on %s: %m", path);
}
if ((mask & CGROUP_DEVICE) && !is_root) {
if ((mask & CGROUP_MASK_DEVICE) && !is_root) {
CGroupDeviceAllow *a;
/* Changing the devices list of a populated cgroup
@ -459,8 +468,8 @@ void cgroup_context_apply(CGroupContext *c, CGroupControllerMask mask, const cha
}
}
CGroupControllerMask cgroup_context_get_mask(CGroupContext *c) {
CGroupControllerMask mask = 0;
CGroupMask cgroup_context_get_mask(CGroupContext *c) {
CGroupMask mask = 0;
/* Figure out which controllers we need */
@ -468,52 +477,62 @@ CGroupControllerMask cgroup_context_get_mask(CGroupContext *c) {
c->cpu_shares != (unsigned long) -1 ||
c->startup_cpu_shares != (unsigned long) -1 ||
c->cpu_quota_per_sec_usec != USEC_INFINITY)
mask |= CGROUP_CPUACCT | CGROUP_CPU;
mask |= CGROUP_MASK_CPUACCT | CGROUP_MASK_CPU;
if (c->blockio_accounting ||
c->blockio_weight != (unsigned long) -1 ||
c->startup_blockio_weight != (unsigned long) -1 ||
c->blockio_device_weights ||
c->blockio_device_bandwidths)
mask |= CGROUP_BLKIO;
mask |= CGROUP_MASK_BLKIO;
if (c->memory_accounting ||
c->memory_limit != (uint64_t) -1)
mask |= CGROUP_MEMORY;
mask |= CGROUP_MASK_MEMORY;
if (c->device_allow ||
c->device_policy != CGROUP_AUTO)
mask |= CGROUP_DEVICE;
mask |= CGROUP_MASK_DEVICE;
return mask;
}
CGroupControllerMask unit_get_cgroup_mask(Unit *u) {
CGroupMask unit_get_own_mask(Unit *u) {
CGroupContext *c;
/* Returns the mask of controllers the unit needs for itself */
c = unit_get_cgroup_context(u);
if (!c)
return 0;
/* If delegation is turned on, then turn on all cgroups,
* unless the process we fork into it is known to drop
* privileges anyway, and shouldn't get access to the
* controllers anyway. */
* unless we are on the legacy hierarchy and the process we
* fork into it is known to drop privileges, and hence
* shouldn't get access to the controllers.
*
* Note that on the unified hierarchy it is safe to delegate
* controllers to unprivileged services. */
if (c->delegate) {
ExecContext *e;
e = unit_get_exec_context(u);
if (!e || exec_context_maintains_privileges(e))
return _CGROUP_CONTROLLER_MASK_ALL;
if (!e ||
exec_context_maintains_privileges(e) ||
cg_unified() > 0)
return _CGROUP_MASK_ALL;
}
return cgroup_context_get_mask(c);
}
CGroupControllerMask unit_get_members_mask(Unit *u) {
CGroupMask unit_get_members_mask(Unit *u) {
assert(u);
/* Returns the mask of controllers all of the unit's children
* require, merged */
if (u->cgroup_members_mask_valid)
return u->cgroup_members_mask;
@ -532,7 +551,7 @@ CGroupControllerMask unit_get_members_mask(Unit *u) {
continue;
u->cgroup_members_mask |=
unit_get_cgroup_mask(member) |
unit_get_own_mask(member) |
unit_get_members_mask(member);
}
}
@ -541,19 +560,52 @@ CGroupControllerMask unit_get_members_mask(Unit *u) {
return u->cgroup_members_mask;
}
CGroupControllerMask unit_get_siblings_mask(Unit *u) {
CGroupMask unit_get_siblings_mask(Unit *u) {
assert(u);
/* Returns the mask of controllers all of the unit's siblings
* require, i.e. the members mask of the unit's parent slice
* if there is one. */
if (UNIT_ISSET(u->slice))
return unit_get_members_mask(UNIT_DEREF(u->slice));
return unit_get_cgroup_mask(u) | unit_get_members_mask(u);
return unit_get_own_mask(u) | unit_get_members_mask(u);
}
CGroupControllerMask unit_get_target_mask(Unit *u) {
CGroupControllerMask mask;
CGroupMask unit_get_subtree_mask(Unit *u) {
mask = unit_get_cgroup_mask(u) | unit_get_members_mask(u) | unit_get_siblings_mask(u);
/* Returns the mask of this subtree, meaning of the group
* itself and its children. */
return unit_get_own_mask(u) | unit_get_members_mask(u);
}
CGroupMask unit_get_target_mask(Unit *u) {
CGroupMask mask;
/* This returns the cgroup mask of all controllers to enable
* for a specific cgroup, i.e. everything it needs itself,
* plus all that its children need, plus all that its siblings
* need. This is primarily useful on the legacy cgroup
* hierarchy, where we need to duplicate each cgroup in each
* hierarchy that shall be enabled for it. */
mask = unit_get_own_mask(u) | unit_get_members_mask(u) | unit_get_siblings_mask(u);
mask &= u->manager->cgroup_supported;
return mask;
}
CGroupMask unit_get_enable_mask(Unit *u) {
CGroupMask mask;
/* This returns the cgroup mask of all controllers to enable
* for the children of a specific cgroup. This is primarily
* useful for the unified cgroup hierarchy, where each cgroup
* controls which controllers are enabled for its children. */
mask = unit_get_members_mask(u);
mask &= u->manager->cgroup_supported;
return mask;
@ -562,13 +614,13 @@ CGroupControllerMask unit_get_target_mask(Unit *u) {
/* Recurse from a unit up through its containing slices, propagating
* mask bits upward. A unit is also member of itself. */
void unit_update_cgroup_members_masks(Unit *u) {
CGroupControllerMask m;
CGroupMask m;
bool more;
assert(u);
/* Calculate subtree mask */
m = unit_get_cgroup_mask(u) | unit_get_members_mask(u);
m = unit_get_subtree_mask(u);
/* See if anything changed from the previous invocation. If
* not, we're done. */
@ -608,7 +660,7 @@ void unit_update_cgroup_members_masks(Unit *u) {
}
}
static const char *migrate_callback(CGroupControllerMask mask, void *userdata) {
static const char *migrate_callback(CGroupMask mask, void *userdata) {
Unit *u = userdata;
assert(mask != 0);
@ -626,7 +678,115 @@ static const char *migrate_callback(CGroupControllerMask mask, void *userdata) {
return NULL;
}
static int unit_create_cgroups(Unit *u, CGroupControllerMask mask) {
char *unit_default_cgroup_path(Unit *u) {
_cleanup_free_ char *escaped = NULL, *slice = NULL;
int r;
assert(u);
if (unit_has_name(u, SPECIAL_ROOT_SLICE))
return strdup(u->manager->cgroup_root);
if (UNIT_ISSET(u->slice) && !unit_has_name(UNIT_DEREF(u->slice), SPECIAL_ROOT_SLICE)) {
r = cg_slice_to_path(UNIT_DEREF(u->slice)->id, &slice);
if (r < 0)
return NULL;
}
escaped = cg_escape(u->id);
if (!escaped)
return NULL;
if (slice)
return strjoin(u->manager->cgroup_root, "/", slice, "/", escaped, NULL);
else
return strjoin(u->manager->cgroup_root, "/", escaped, NULL);
}
int unit_set_cgroup_path(Unit *u, const char *path) {
_cleanup_free_ char *p = NULL;
int r;
assert(u);
if (path) {
p = strdup(path);
if (!p)
return -ENOMEM;
} else
p = NULL;
if (streq_ptr(u->cgroup_path, p))
return 0;
if (p) {
r = hashmap_put(u->manager->cgroup_unit, p, u);
if (r < 0)
return r;
}
unit_release_cgroup(u);
u->cgroup_path = p;
p = NULL;
return 1;
}
int unit_watch_cgroup(Unit *u) {
_cleanup_free_ char *populated = NULL;
int r;
assert(u);
if (!u->cgroup_path)
return 0;
if (u->cgroup_inotify_wd >= 0)
return 0;
/* Only applies to the unified hierarchy */
r = cg_unified();
if (r < 0)
return log_unit_error_errno(u, r, "Failed detect wether the unified hierarchy is used: %m");
if (r == 0)
return 0;
/* Don't watch the root slice, it's pointless. */
if (unit_has_name(u, SPECIAL_ROOT_SLICE))
return 0;
r = hashmap_ensure_allocated(&u->manager->cgroup_inotify_wd_unit, &trivial_hash_ops);
if (r < 0)
return log_oom();
r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, "cgroup.populated", &populated);
if (r < 0)
return log_oom();
u->cgroup_inotify_wd = inotify_add_watch(u->manager->cgroup_inotify_fd, populated, IN_MODIFY);
if (u->cgroup_inotify_wd < 0) {
if (errno == ENOENT) /* If the directory is already
* gone we don't need to track
* it, so this is not an error */
return 0;
return log_unit_error_errno(u, errno, "Failed to add inotify watch descriptor for control group %s: %m", u->cgroup_path);
}
r = hashmap_put(u->manager->cgroup_inotify_wd_unit, INT_TO_PTR(u->cgroup_inotify_wd), u);
if (r < 0)
return log_unit_error_errno(u, r, "Failed to add inotify watch descriptor to hash map: %m");
return 0;
}
static int unit_create_cgroup(
Unit *u,
CGroupMask target_mask,
CGroupMask enable_mask) {
CGroupContext *c;
int r;
@ -643,25 +803,29 @@ static int unit_create_cgroups(Unit *u, CGroupControllerMask mask) {
if (!path)
return log_oom();
r = hashmap_put(u->manager->cgroup_unit, path, u);
if (r < 0) {
log_error(r == -EEXIST ? "cgroup %s exists already: %s" : "hashmap_put failed for %s: %s", path, strerror(-r));
return r;
}
if (r > 0) {
u->cgroup_path = path;
path = NULL;
}
r = unit_set_cgroup_path(u, path);
if (r == -EEXIST)
return log_unit_error_errno(u, r, "Control group %s exists already.", path);
if (r < 0)
return log_unit_error_errno(u, r, "Failed to set unit's control group path to %s: %m", path);
}
/* First, create our own group */
r = cg_create_everywhere(u->manager->cgroup_supported, mask, u->cgroup_path);
r = cg_create_everywhere(u->manager->cgroup_supported, target_mask, u->cgroup_path);
if (r < 0)
return log_error_errno(r, "Failed to create cgroup %s: %m", u->cgroup_path);
return log_unit_error_errno(u, r, "Failed to create cgroup %s: %m", u->cgroup_path);
/* Start watching it */
(void) unit_watch_cgroup(u);
/* Enable all controllers we need */
r = cg_enable_everywhere(u->manager->cgroup_supported, enable_mask, u->cgroup_path);
if (r < 0)
log_unit_warning_errno(u, r, "Failed to enable controllers on cgroup %s, ignoring: %m", u->cgroup_path);
/* Keep track that this is now realized */
u->cgroup_realized = true;
u->cgroup_realized_mask = mask;
u->cgroup_realized_mask = target_mask;
if (u->type != UNIT_SLICE && !c->delegate) {
@ -670,7 +834,7 @@ static int unit_create_cgroups(Unit *u, CGroupControllerMask mask) {
* for slice and delegation units. */
r = cg_migrate_everywhere(u->manager->cgroup_supported, u->cgroup_path, u->cgroup_path, migrate_callback, u);
if (r < 0)
log_warning_errno(r, "Failed to migrate cgroup from to %s: %m", u->cgroup_path);
log_unit_warning_errno(u, r, "Failed to migrate cgroup from to %s, ignoring: %m", u->cgroup_path);
}
return 0;
@ -691,10 +855,10 @@ int unit_attach_pids_to_cgroup(Unit *u) {
return 0;
}
static bool unit_has_mask_realized(Unit *u, CGroupControllerMask mask) {
static bool unit_has_mask_realized(Unit *u, CGroupMask target_mask) {
assert(u);
return u->cgroup_realized && u->cgroup_realized_mask == mask;
return u->cgroup_realized && u->cgroup_realized_mask == target_mask;
}
/* Check if necessary controllers and attributes for a unit are in place.
@ -704,7 +868,7 @@ static bool unit_has_mask_realized(Unit *u, CGroupControllerMask mask) {
*
* Returns 0 on success and < 0 on failure. */
static int unit_realize_cgroup_now(Unit *u, ManagerState state) {
CGroupControllerMask mask;
CGroupMask target_mask, enable_mask;
int r;
assert(u);
@ -714,9 +878,8 @@ static int unit_realize_cgroup_now(Unit *u, ManagerState state) {
u->in_cgroup_queue = false;
}
mask = unit_get_target_mask(u);
if (unit_has_mask_realized(u, mask))
target_mask = unit_get_target_mask(u);
if (unit_has_mask_realized(u, target_mask))
return 0;
/* First, realize parents */
@ -727,12 +890,13 @@ static int unit_realize_cgroup_now(Unit *u, ManagerState state) {
}
/* And then do the real work */
r = unit_create_cgroups(u, mask);
enable_mask = unit_get_enable_mask(u);
r = unit_create_cgroup(u, target_mask, enable_mask);
if (r < 0)
return r;
/* Finally, apply the necessary attributes. */
cgroup_context_apply(unit_get_cgroup_context(u), mask, u->cgroup_path, state);
cgroup_context_apply(unit_get_cgroup_context(u), target_mask, u->cgroup_path, state);
return 0;
}
@ -759,7 +923,7 @@ unsigned manager_dispatch_cgroup_queue(Manager *m) {
r = unit_realize_cgroup_now(i, state);
if (r < 0)
log_warning_errno(r, "Failed to realize cgroups for queued unit %s: %m", i->id);
log_warning_errno(r, "Failed to realize cgroups for queued unit %s, ignoring: %m", i->id);
n++;
}
@ -806,12 +970,9 @@ static void unit_queue_siblings(Unit *u) {
}
int unit_realize_cgroup(Unit *u) {
CGroupContext *c;
assert(u);
c = unit_get_cgroup_context(u);
if (!c)
if (!UNIT_HAS_CGROUP_CONTEXT(u))
return 0;
/* So, here's the deal: when realizing the cgroups for this
@ -832,39 +993,67 @@ int unit_realize_cgroup(Unit *u) {
return unit_realize_cgroup_now(u, manager_state(u->manager));
}
void unit_destroy_cgroup_if_empty(Unit *u) {
void unit_release_cgroup(Unit *u) {
assert(u);
/* Forgets all cgroup details for this cgroup */
if (u->cgroup_path) {
(void) hashmap_remove(u->manager->cgroup_unit, u->cgroup_path);
u->cgroup_path = mfree(u->cgroup_path);
}
if (u->cgroup_inotify_wd >= 0) {
if (inotify_rm_watch(u->manager->cgroup_inotify_fd, u->cgroup_inotify_wd) < 0)
log_unit_debug_errno(u, errno, "Failed to remove cgroup inotify watch %i for %s, ignoring", u->cgroup_inotify_wd, u->id);
(void) hashmap_remove(u->manager->cgroup_inotify_wd_unit, INT_TO_PTR(u->cgroup_inotify_wd));
u->cgroup_inotify_wd = -1;
}
}
void unit_prune_cgroup(Unit *u) {
int r;
bool is_root_slice;
assert(u);
/* Removes the cgroup, if empty and possible, and stops watching it. */
if (!u->cgroup_path)
return;
r = cg_trim_everywhere(u->manager->cgroup_supported, u->cgroup_path, !unit_has_name(u, SPECIAL_ROOT_SLICE));
is_root_slice = unit_has_name(u, SPECIAL_ROOT_SLICE);
r = cg_trim_everywhere(u->manager->cgroup_supported, u->cgroup_path, !is_root_slice);
if (r < 0) {
log_debug_errno(r, "Failed to destroy cgroup %s: %m", u->cgroup_path);
log_debug_errno(r, "Failed to destroy cgroup %s, ignoring: %m", u->cgroup_path);
return;
}
hashmap_remove(u->manager->cgroup_unit, u->cgroup_path);
if (is_root_slice)
return;
unit_release_cgroup(u);
free(u->cgroup_path);
u->cgroup_path = NULL;
u->cgroup_realized = false;
u->cgroup_realized_mask = 0;
}
pid_t unit_search_main_pid(Unit *u) {
int unit_search_main_pid(Unit *u, pid_t *ret) {
_cleanup_fclose_ FILE *f = NULL;
pid_t pid = 0, npid, mypid;
int r;
assert(u);
assert(ret);
if (!u->cgroup_path)
return 0;
return -ENXIO;
if (cg_enumerate_processes(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, &f) < 0)
return 0;
r = cg_enumerate_processes(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, &f);
if (r < 0)
return r;
mypid = getpid();
while (cg_read_pid(f, &npid) > 0) {
@ -877,90 +1066,274 @@ pid_t unit_search_main_pid(Unit *u) {
if (get_parent_of_pid(npid, &ppid) >= 0 && ppid != mypid)
continue;
if (pid != 0) {
if (pid != 0)
/* Dang, there's more than one daemonized PID
in this group, so we don't know what process
is the main process. */
pid = 0;
break;
}
return -ENODATA;
pid = npid;
}
return pid;
*ret = pid;
return 0;
}
static int unit_watch_pids_in_path(Unit *u, const char *path) {
_cleanup_closedir_ DIR *d = NULL;
_cleanup_fclose_ FILE *f = NULL;
int ret = 0, r;
assert(u);
assert(path);
r = cg_enumerate_processes(SYSTEMD_CGROUP_CONTROLLER, path, &f);
if (r < 0)
ret = r;
else {
pid_t pid;
while ((r = cg_read_pid(f, &pid)) > 0) {
r = unit_watch_pid(u, pid);
if (r < 0 && ret >= 0)
ret = r;
}
if (r < 0 && ret >= 0)
ret = r;
}
r = cg_enumerate_subgroups(SYSTEMD_CGROUP_CONTROLLER, path, &d);
if (r < 0) {
if (ret >= 0)
ret = r;
} else {
char *fn;
while ((r = cg_read_subgroup(d, &fn)) > 0) {
_cleanup_free_ char *p = NULL;
p = strjoin(path, "/", fn, NULL);
free(fn);
if (!p)
return -ENOMEM;
r = unit_watch_pids_in_path(u, p);
if (r < 0 && ret >= 0)
ret = r;
}
if (r < 0 && ret >= 0)
ret = r;
}
return ret;
}
int unit_watch_all_pids(Unit *u) {
assert(u);
/* Adds all PIDs from our cgroup to the set of PIDs we
* watch. This is a fallback logic for cases where we do not
* get reliable cgroup empty notifications: we try to use
* SIGCHLD as replacement. */
if (!u->cgroup_path)
return -ENOENT;
if (cg_unified() > 0) /* On unified we can use proper notifications */
return 0;
return unit_watch_pids_in_path(u, u->cgroup_path);
}
int unit_notify_cgroup_empty(Unit *u) {
int r;
assert(u);
if (!u->cgroup_path)
return 0;
r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path);
if (r <= 0)
return r;
unit_add_to_gc_queue(u);
if (UNIT_VTABLE(u)->notify_cgroup_empty)
UNIT_VTABLE(u)->notify_cgroup_empty(u);
return 0;
}
static int on_cgroup_inotify_event(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
Manager *m = userdata;
assert(s);
assert(fd >= 0);
assert(m);
for (;;) {
union inotify_event_buffer buffer;
struct inotify_event *e;
ssize_t l;
l = read(fd, &buffer, sizeof(buffer));
if (l < 0) {
if (errno == EINTR || errno == EAGAIN)
return 0;
return log_error_errno(errno, "Failed to read control group inotify events: %m");
}
FOREACH_INOTIFY_EVENT(e, buffer, l) {
Unit *u;
if (e->wd < 0)
/* Queue overflow has no watch descriptor */
continue;
if (e->mask & IN_IGNORED)
/* The watch was just removed */
continue;
u = hashmap_get(m->cgroup_inotify_wd_unit, INT_TO_PTR(e->wd));
if (!u) /* Not that inotify might deliver
* events for a watch even after it
* was removed, because it was queued
* before the removal. Let's ignore
* this here safely. */
continue;
(void) unit_notify_cgroup_empty(u);
}
}
}
int manager_setup_cgroup(Manager *m) {
_cleanup_free_ char *path = NULL;
int r;
CGroupController c;
int r, unified;
char *e;
assert(m);
/* 1. Determine hierarchy */
free(m->cgroup_root);
m->cgroup_root = NULL;
m->cgroup_root = mfree(m->cgroup_root);
r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 0, &m->cgroup_root);
if (r < 0)
return log_error_errno(r, "Cannot determine cgroup we are running in: %m");
/* LEGACY: Already in /system.slice? If so, let's cut this
* off. This is to support live upgrades from older systemd
* versions where PID 1 was moved there. */
if (m->running_as == MANAGER_SYSTEM) {
char *e;
/* Chop off the init scope, if we are already located in it */
e = endswith(m->cgroup_root, "/" SPECIAL_INIT_SCOPE);
/* LEGACY: Also chop off the system slice if we are in
* it. This is to support live upgrades from older systemd
* versions where PID 1 was moved there. Also see
* cg_get_root_path(). */
if (!e && m->running_as == MANAGER_SYSTEM) {
e = endswith(m->cgroup_root, "/" SPECIAL_SYSTEM_SLICE);
if (!e)
e = endswith(m->cgroup_root, "/system");
if (e)
*e = 0;
e = endswith(m->cgroup_root, "/system"); /* even more legacy */
}
if (e)
*e = 0;
/* And make sure to store away the root value without trailing
* slash, even for the root dir, so that we can easily prepend
* it everywhere. */
if (streq(m->cgroup_root, "/"))
m->cgroup_root[0] = 0;
while ((e = endswith(m->cgroup_root, "/")))
*e = 0;
/* 2. Show data */
r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_root, NULL, &path);
if (r < 0)
return log_error_errno(r, "Cannot find cgroup mount point: %m");
log_debug("Using cgroup controller " SYSTEMD_CGROUP_CONTROLLER ". File system hierarchy is at %s.", path);
unified = cg_unified();
if (unified < 0)
return log_error_errno(r, "Couldn't determine if we are running in the unified hierarchy: %m");
if (unified > 0)
log_debug("Unified cgroup hierarchy is located at %s.", path);
else
log_debug("Using cgroup controller " SYSTEMD_CGROUP_CONTROLLER ". File system hierarchy is at %s.", path);
if (!m->test_run) {
const char *scope_path;
/* 3. Install agent */
if (m->running_as == MANAGER_SYSTEM) {
if (unified) {
/* In the unified hierarchy we can can get
* cgroup empty notifications via inotify. */
m->cgroup_inotify_event_source = sd_event_source_unref(m->cgroup_inotify_event_source);
safe_close(m->cgroup_inotify_fd);
m->cgroup_inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
if (m->cgroup_inotify_fd < 0)
return log_error_errno(errno, "Failed to create control group inotify object: %m");
r = sd_event_add_io(m->event, &m->cgroup_inotify_event_source, m->cgroup_inotify_fd, EPOLLIN, on_cgroup_inotify_event, m);
if (r < 0)
return log_error_errno(r, "Failed to watch control group inotify object: %m");
r = sd_event_source_set_priority(m->cgroup_inotify_event_source, SD_EVENT_PRIORITY_IDLE - 5);
if (r < 0)
return log_error_errno(r, "Failed to set priority of inotify event source: %m");
(void) sd_event_source_set_description(m->cgroup_inotify_event_source, "cgroup-inotify");
} else if (m->running_as == MANAGER_SYSTEM) {
/* On the legacy hierarchy we only get
* notifications via cgroup agents. (Which
* isn't really reliable, since it does not
* generate events when control groups with
* children run empty. */
r = cg_install_release_agent(SYSTEMD_CGROUP_CONTROLLER, SYSTEMD_CGROUP_AGENT_PATH);
if (r < 0)
log_warning_errno(r, "Failed to install release agent, ignoring: %m");
else if (r > 0)
log_debug("Installed release agent.");
else
else if (r == 0)
log_debug("Release agent already installed.");
}
/* 4. Make sure we are in the root cgroup */
r = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_root, 0);
/* 4. Make sure we are in the special "init.scope" unit in the root slice. */
scope_path = strjoina(m->cgroup_root, "/" SPECIAL_INIT_SCOPE);
r = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, scope_path, 0);
if (r < 0)
return log_error_errno(r, "Failed to create root cgroup hierarchy: %m");
return log_error_errno(r, "Failed to create %s control group: %m", scope_path);
/* also, move all other userspace processes remaining
* in the root cgroup into that scope. */
r = cg_migrate(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_root, SYSTEMD_CGROUP_CONTROLLER, scope_path, false);
if (r < 0)
log_warning_errno(r, "Couldn't move remaining userspace processes, ignoring: %m");
/* 5. And pin it, so that it cannot be unmounted */
safe_close(m->pin_cgroupfs_fd);
m->pin_cgroupfs_fd = open(path, O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOCTTY|O_NONBLOCK);
if (m->pin_cgroupfs_fd < 0)
return log_error_errno(errno, "Failed to open pin file: %m");
/* 6. Always enable hierarchical support if it exists... */
cg_set_attribute("memory", "/", "memory.use_hierarchy", "1");
if (!unified)
(void) cg_set_attribute("memory", "/", "memory.use_hierarchy", "1");
}
/* 7. Figure out which controllers are supported */
m->cgroup_supported = cg_mask_supported();
r = cg_mask_supported(&m->cgroup_supported);
if (r < 0)
return log_error_errno(r, "Failed to determine supported controllers: %m");
for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++)
log_debug("Controller '%s' supported: %s", cgroup_controller_to_string(c), yes_no(m->cgroup_supported & c));
return 0;
}
@ -971,12 +1344,16 @@ void manager_shutdown_cgroup(Manager *m, bool delete) {
/* We can't really delete the group, since we are in it. But
* let's trim it. */
if (delete && m->cgroup_root)
cg_trim(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_root, false);
(void) cg_trim(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_root, false);
m->cgroup_inotify_wd_unit = hashmap_free(m->cgroup_inotify_wd_unit);
m->cgroup_inotify_event_source = sd_event_source_unref(m->cgroup_inotify_event_source);
m->cgroup_inotify_fd = safe_close(m->cgroup_inotify_fd);
m->pin_cgroupfs_fd = safe_close(m->pin_cgroupfs_fd);
free(m->cgroup_root);
m->cgroup_root = NULL;
m->cgroup_root = mfree(m->cgroup_root);
}
Unit* manager_get_unit_by_cgroup(Manager *m, const char *cgroup) {
@ -995,8 +1372,8 @@ Unit* manager_get_unit_by_cgroup(Manager *m, const char *cgroup) {
char *e;
e = strrchr(p, '/');
if (e == p || !e)
return NULL;
if (!e || e == p)
return hashmap_get(m->cgroup_unit, SPECIAL_ROOT_SLICE);
*e = 0;
@ -1006,13 +1383,13 @@ Unit* manager_get_unit_by_cgroup(Manager *m, const char *cgroup) {
}
}
Unit *manager_get_unit_by_pid(Manager *m, pid_t pid) {
Unit *manager_get_unit_by_pid_cgroup(Manager *m, pid_t pid) {
_cleanup_free_ char *cgroup = NULL;
int r;
assert(m);
if (pid <= 1)
if (pid <= 0)
return NULL;
r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &cgroup);
@ -1022,9 +1399,30 @@ Unit *manager_get_unit_by_pid(Manager *m, pid_t pid) {
return manager_get_unit_by_cgroup(m, cgroup);
}
Unit *manager_get_unit_by_pid(Manager *m, pid_t pid) {
Unit *u;
assert(m);
if (pid <= 0)
return NULL;
if (pid == 1)
return hashmap_get(m->units, SPECIAL_INIT_SCOPE);
u = hashmap_get(m->watch_pids1, PID_TO_PTR(pid));
if (u)
return u;
u = hashmap_get(m->watch_pids2, PID_TO_PTR(pid));
if (u)
return u;
return manager_get_unit_by_pid_cgroup(m, pid);
}
int manager_notify_cgroup_empty(Manager *m, const char *cgroup) {
Unit *u;
int r;
assert(m);
assert(cgroup);
@ -1033,15 +1431,7 @@ int manager_notify_cgroup_empty(Manager *m, const char *cgroup) {
if (!u)
return 0;
r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, true);
if (r <= 0)
return r;
if (UNIT_VTABLE(u)->notify_cgroup_empty)
UNIT_VTABLE(u)->notify_cgroup_empty(u);
unit_add_to_gc_queue(u);
return 0;
return unit_notify_cgroup_empty(u);
}
int unit_get_memory_current(Unit *u, uint64_t *ret) {
@ -1054,10 +1444,13 @@ int unit_get_memory_current(Unit *u, uint64_t *ret) {
if (!u->cgroup_path)
return -ENODATA;
if ((u->cgroup_realized_mask & CGROUP_MEMORY) == 0)
if ((u->cgroup_realized_mask & CGROUP_MASK_MEMORY) == 0)
return -ENODATA;
r = cg_get_attribute("memory", u->cgroup_path, "memory.usage_in_bytes", &v);
if (cg_unified() <= 0)
r = cg_get_attribute("memory", u->cgroup_path, "memory.usage_in_bytes", &v);
else
r = cg_get_attribute("memory", u->cgroup_path, "memory.current", &v);
if (r == -ENOENT)
return -ENODATA;
if (r < 0)
@ -1077,7 +1470,7 @@ static int unit_get_cpu_usage_raw(Unit *u, nsec_t *ret) {
if (!u->cgroup_path)
return -ENODATA;
if ((u->cgroup_realized_mask & CGROUP_CPUACCT) == 0)
if ((u->cgroup_realized_mask & CGROUP_MASK_CPUACCT) == 0)
return -ENODATA;
r = cg_get_attribute("cpuacct", u->cgroup_path, "cpuacct.usage", &v);
@ -1127,6 +1520,18 @@ int unit_reset_cpu_usage(Unit *u) {
return 0;
}
bool unit_cgroup_delegate(Unit *u) {
CGroupContext *c;
assert(u);
c = unit_get_cgroup_context(u);
if (!c)
return false;
return c->delegate;
}
static const char* const cgroup_device_policy_table[_CGROUP_DEVICE_POLICY_MAX] = {
[CGROUP_AUTO] = "auto",
[CGROUP_CLOSED] = "closed",

View File

@ -96,22 +96,32 @@ struct CGroupContext {
void cgroup_context_init(CGroupContext *c);
void cgroup_context_done(CGroupContext *c);
void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix);
void cgroup_context_apply(CGroupContext *c, CGroupControllerMask mask, const char *path, ManagerState state);
void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, ManagerState state);
CGroupControllerMask cgroup_context_get_mask(CGroupContext *c);
CGroupMask cgroup_context_get_mask(CGroupContext *c);
void cgroup_context_free_device_allow(CGroupContext *c, CGroupDeviceAllow *a);
void cgroup_context_free_blockio_device_weight(CGroupContext *c, CGroupBlockIODeviceWeight *w);
void cgroup_context_free_blockio_device_bandwidth(CGroupContext *c, CGroupBlockIODeviceBandwidth *b);
CGroupControllerMask unit_get_cgroup_mask(Unit *u);
CGroupControllerMask unit_get_siblings_mask(Unit *u);
CGroupControllerMask unit_get_members_mask(Unit *u);
CGroupControllerMask unit_get_target_mask(Unit *u);
CGroupMask unit_get_own_mask(Unit *u);
CGroupMask unit_get_siblings_mask(Unit *u);
CGroupMask unit_get_members_mask(Unit *u);
CGroupMask unit_get_subtree_mask(Unit *u);
CGroupMask unit_get_target_mask(Unit *u);
CGroupMask unit_get_enable_mask(Unit *u);
void unit_update_cgroup_members_masks(Unit *u);
char *unit_default_cgroup_path(Unit *u);
int unit_set_cgroup_path(Unit *u, const char *path);
int unit_realize_cgroup(Unit *u);
void unit_destroy_cgroup_if_empty(Unit *u);
void unit_release_cgroup(Unit *u);
void unit_prune_cgroup(Unit *u);
int unit_watch_cgroup(Unit *u);
int unit_attach_pids_to_cgroup(Unit *u);
int manager_setup_cgroup(Manager *m);
@ -120,15 +130,20 @@ void manager_shutdown_cgroup(Manager *m, bool delete);
unsigned manager_dispatch_cgroup_queue(Manager *m);
Unit *manager_get_unit_by_cgroup(Manager *m, const char *cgroup);
Unit *manager_get_unit_by_pid_cgroup(Manager *m, pid_t pid);
Unit* manager_get_unit_by_pid(Manager *m, pid_t pid);
pid_t unit_search_main_pid(Unit *u);
int manager_notify_cgroup_empty(Manager *m, const char *group);
int unit_search_main_pid(Unit *u, pid_t *ret);
int unit_watch_all_pids(Unit *u);
int unit_get_memory_current(Unit *u, uint64_t *ret);
int unit_get_cpu_usage(Unit *u, nsec_t *ret);
int unit_reset_cpu_usage(Unit *u);
bool unit_cgroup_delegate(Unit *u);
int unit_notify_cgroup_empty(Unit *u);
int manager_notify_cgroup_empty(Manager *m, const char *group);
const char* cgroup_device_policy_to_string(CGroupDevicePolicy i) _const_;
CGroupDevicePolicy cgroup_device_policy_from_string(const char *s) _pure_;

View File

@ -228,7 +228,7 @@ int bus_cgroup_set_property(
if (mode != UNIT_CHECK) {
c->cpu_accounting = b;
u->cgroup_realized_mask &= ~CGROUP_CPUACCT;
u->cgroup_realized_mask &= ~CGROUP_MASK_CPUACCT;
unit_write_drop_in_private(u, mode, name, b ? "CPUAccounting=yes" : "CPUAccounting=no");
}
@ -252,7 +252,7 @@ int bus_cgroup_set_property(
if (mode != UNIT_CHECK) {
c->cpu_shares = ul;
u->cgroup_realized_mask &= ~CGROUP_CPU;
u->cgroup_realized_mask &= ~CGROUP_MASK_CPU;
unit_write_drop_in_private_format(u, mode, name, "CPUShares=%lu", ul);
}
@ -276,7 +276,7 @@ int bus_cgroup_set_property(
if (mode != UNIT_CHECK) {
c->startup_cpu_shares = ul;
u->cgroup_realized_mask &= ~CGROUP_CPU;
u->cgroup_realized_mask &= ~CGROUP_MASK_CPU;
unit_write_drop_in_private_format(u, mode, name, "StartupCPUShares=%lu", ul);
}
@ -294,7 +294,7 @@ int bus_cgroup_set_property(
if (mode != UNIT_CHECK) {
c->cpu_quota_per_sec_usec = u64;
u->cgroup_realized_mask &= ~CGROUP_CPU;
u->cgroup_realized_mask &= ~CGROUP_MASK_CPU;
unit_write_drop_in_private_format(u, mode, "CPUQuota", "CPUQuota=%0.f%%", (double) (c->cpu_quota_per_sec_usec / 10000));
}
@ -309,7 +309,7 @@ int bus_cgroup_set_property(
if (mode != UNIT_CHECK) {
c->blockio_accounting = b;
u->cgroup_realized_mask &= ~CGROUP_BLKIO;
u->cgroup_realized_mask &= ~CGROUP_MASK_BLKIO;
unit_write_drop_in_private(u, mode, name, b ? "BlockIOAccounting=yes" : "BlockIOAccounting=no");
}
@ -333,7 +333,7 @@ int bus_cgroup_set_property(
if (mode != UNIT_CHECK) {
c->blockio_weight = ul;
u->cgroup_realized_mask &= ~CGROUP_BLKIO;
u->cgroup_realized_mask &= ~CGROUP_MASK_BLKIO;
unit_write_drop_in_private_format(u, mode, name, "BlockIOWeight=%lu", ul);
}
@ -357,7 +357,7 @@ int bus_cgroup_set_property(
if (mode != UNIT_CHECK) {
c->startup_blockio_weight = ul;
u->cgroup_realized_mask &= ~CGROUP_BLKIO;
u->cgroup_realized_mask &= ~CGROUP_MASK_BLKIO;
unit_write_drop_in_private_format(u, mode, name, "StartupBlockIOWeight=%lu", ul);
}
@ -427,7 +427,7 @@ int bus_cgroup_set_property(
cgroup_context_free_blockio_device_bandwidth(c, a);
}
u->cgroup_realized_mask &= ~CGROUP_BLKIO;
u->cgroup_realized_mask &= ~CGROUP_MASK_BLKIO;
f = open_memstream(&buf, &size);
if (!f)
@ -510,7 +510,7 @@ int bus_cgroup_set_property(
cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
}
u->cgroup_realized_mask &= ~CGROUP_BLKIO;
u->cgroup_realized_mask &= ~CGROUP_MASK_BLKIO;
f = open_memstream(&buf, &size);
if (!f)
@ -535,7 +535,7 @@ int bus_cgroup_set_property(
if (mode != UNIT_CHECK) {
c->memory_accounting = b;
u->cgroup_realized_mask &= ~CGROUP_MEMORY;
u->cgroup_realized_mask &= ~CGROUP_MASK_MEMORY;
unit_write_drop_in_private(u, mode, name, b ? "MemoryAccounting=yes" : "MemoryAccounting=no");
}
@ -550,7 +550,7 @@ int bus_cgroup_set_property(
if (mode != UNIT_CHECK) {
c->memory_limit = limit;
u->cgroup_realized_mask &= ~CGROUP_MEMORY;
u->cgroup_realized_mask &= ~CGROUP_MASK_MEMORY;
unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu64, name, limit);
}
@ -572,7 +572,7 @@ int bus_cgroup_set_property(
char *buf;
c->device_policy = p;
u->cgroup_realized_mask &= ~CGROUP_DEVICE;
u->cgroup_realized_mask &= ~CGROUP_MASK_DEVICE;
buf = strjoina("DevicePolicy=", policy);
unit_write_drop_in_private(u, mode, name, buf);
@ -651,7 +651,7 @@ int bus_cgroup_set_property(
cgroup_context_free_device_allow(c, c->device_allow);
}
u->cgroup_realized_mask &= ~CGROUP_DEVICE;
u->cgroup_realized_mask &= ~CGROUP_MASK_DEVICE;
f = open_memstream(&buf, &size);
if (!f)

View File

@ -25,6 +25,7 @@
#include "cgroup-util.h"
#include "strv.h"
#include "bus-common-errors.h"
#include "special.h"
#include "dbus.h"
#include "dbus-unit.h"
@ -390,6 +391,29 @@ static int property_get_load_error(
return sd_bus_message_append(reply, "(ss)", e.name, e.message);
}
static int bus_verify_manage_units_async_full(
Unit *u,
const char *verb,
int capability,
const char *polkit_message,
sd_bus_message *call,
sd_bus_error *error) {
const char *details[9] = {
"unit", u->id,
"verb", verb,
};
if (polkit_message) {
details[4] = "polkit.message";
details[5] = polkit_message;
details[6] = "polkit.gettext_domain";
details[7] = GETTEXT_PACKAGE;
}
return bus_verify_polkit_async(call, capability, "org.freedesktop.systemd1.manage-units", details, false, UID_INVALID, &u->manager->polkit_registry, error);
}
int bus_unit_method_start_generic(
sd_bus_message *message,
Unit *u,
@ -399,6 +423,14 @@ int bus_unit_method_start_generic(
const char *smode;
JobMode mode;
_cleanup_free_ char *verb = NULL;
static const char *const polkit_message_for_job[_JOB_TYPE_MAX] = {
[JOB_START] = N_("Authentication is required to start '$(unit)'."),
[JOB_STOP] = N_("Authentication is required to stop '$(unit)'."),
[JOB_RELOAD] = N_("Authentication is required to reload '$(unit)'."),
[JOB_RESTART] = N_("Authentication is required to restart '$(unit)'."),
[JOB_TRY_RESTART] = N_("Authentication is required to restart '$(unit)'."),
};
int r;
assert(message);
@ -417,7 +449,20 @@ int bus_unit_method_start_generic(
if (mode < 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Job mode %s invalid", smode);
r = bus_verify_manage_units_async(u->manager, message, error);
if (reload_if_possible)
verb = strjoin("reload-or-", job_type_to_string(job_type), NULL);
else
verb = strdup(job_type_to_string(job_type));
if (!verb)
return -ENOMEM;
r = bus_verify_manage_units_async_full(
u,
verb,
CAP_SYS_ADMIN,
job_type < _JOB_TYPE_MAX ? polkit_message_for_job[job_type] : NULL,
message,
error);
if (r < 0)
return r;
if (r == 0)
@ -483,7 +528,13 @@ int bus_unit_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *
if (signo <= 0 || signo >= _NSIG)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Signal number out of range.");
r = bus_verify_manage_units_async_for_kill(u->manager, message, error);
r = bus_verify_manage_units_async_full(
u,
"kill",
CAP_KILL,
N_("Authentication is required to kill '$(unit)'."),
message,
error);
if (r < 0)
return r;
if (r == 0)
@ -507,7 +558,13 @@ int bus_unit_method_reset_failed(sd_bus_message *message, void *userdata, sd_bus
if (r < 0)
return r;
r = bus_verify_manage_units_async(u->manager, message, error);
r = bus_verify_manage_units_async_full(
u,
"reset-failed",
CAP_SYS_ADMIN,
N_("Authentication is required to reset the \"failed\" state of '$(unit)'."),
message,
error);
if (r < 0)
return r;
if (r == 0)
@ -533,7 +590,13 @@ int bus_unit_method_set_properties(sd_bus_message *message, void *userdata, sd_b
if (r < 0)
return r;
r = bus_verify_manage_units_async(u->manager, message, error);
r = bus_verify_manage_units_async_full(
u,
"set-property",
CAP_SYS_ADMIN,
N_("Authentication is required to set properties on '$(unit)'."),
message,
error);
if (r < 0)
return r;
if (r == 0)
@ -783,7 +846,7 @@ static int send_changed_signal(sd_bus *bus, void *userdata) {
r = sd_bus_emit_properties_changed_strv(
bus, p,
UNIT_VTABLE(u)->bus_interface,
unit_dbus_interface_from_type(u->type),
NULL);
if (r < 0)
return r;
@ -965,38 +1028,41 @@ static int bus_unit_set_transient_property(
return 1;
} else if (streq(name, "Slice") && unit_get_cgroup_context(u)) {
} else if (streq(name, "Slice")) {
Unit *slice;
const char *s;
if (!UNIT_HAS_CGROUP_CONTEXT(u))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "The slice property is only available for units with control groups.");
if (u->type == UNIT_SLICE)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Slice may not be set for slice units.");
if (unit_has_name(u, SPECIAL_INIT_SCOPE))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot set slice for init.scope");
r = sd_bus_message_read(message, "s", &s);
if (r < 0)
return r;
if (!unit_name_is_valid(s, UNIT_NAME_PLAIN) || !endswith(s, ".slice"))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid slice name %s", s);
if (!unit_name_is_valid(s, UNIT_NAME_PLAIN))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name '%s'", s);
if (isempty(s)) {
if (mode != UNIT_CHECK) {
unit_ref_unset(&u->slice);
unit_remove_drop_in(u, mode, name);
}
} else {
Unit *slice;
r = manager_load_unit(u->manager, s, NULL, error, &slice);
if (r < 0)
return r;
r = manager_load_unit(u->manager, s, NULL, error, &slice);
if (slice->type != UNIT_SLICE)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unit name '%s' is not a slice", s);
if (mode != UNIT_CHECK) {
r = unit_set_slice(u, slice);
if (r < 0)
return r;
if (slice->type != UNIT_SLICE)
return -EINVAL;
if (mode != UNIT_CHECK) {
unit_ref_set(&u->slice, slice);
unit_write_drop_in_private_format(u, mode, name, "Slice=%s\n", s);
}
unit_write_drop_in_private_format(u, mode, name, "Slice=%s\n", s);
}
return 1;
} else if (STR_IN_SET(name,
"Requires", "RequiresOverridable",
"Requisite", "RequisiteOverridable",

View File

@ -356,7 +356,7 @@ static int bus_unit_interface_find(sd_bus *bus, const char *path, const char *in
if (r <= 0)
return r;
if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface))
if (!streq_ptr(interface, unit_dbus_interface_from_type(u->type)))
return 0;
*found = u;
@ -378,10 +378,10 @@ static int bus_unit_cgroup_find(sd_bus *bus, const char *path, const char *inter
if (r <= 0)
return r;
if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface))
if (!streq_ptr(interface, unit_dbus_interface_from_type(u->type)))
return 0;
if (!unit_get_cgroup_context(u))
if (!UNIT_HAS_CGROUP_CONTEXT(u))
return 0;
*found = u;
@ -404,7 +404,7 @@ static int bus_cgroup_context_find(sd_bus *bus, const char *path, const char *in
if (r <= 0)
return r;
if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface))
if (!streq_ptr(interface, unit_dbus_interface_from_type(u->type)))
return 0;
c = unit_get_cgroup_context(u);
@ -431,7 +431,7 @@ static int bus_exec_context_find(sd_bus *bus, const char *path, const char *inte
if (r <= 0)
return r;
if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface))
if (!streq_ptr(interface, unit_dbus_interface_from_type(u->type)))
return 0;
c = unit_get_exec_context(u);
@ -458,7 +458,7 @@ static int bus_kill_context_find(sd_bus *bus, const char *path, const char *inte
if (r <= 0)
return r;
if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface))
if (!streq_ptr(interface, unit_dbus_interface_from_type(u->type)))
return 0;
c = unit_get_kill_context(u);
@ -555,30 +555,34 @@ static int bus_setup_api_vtables(Manager *m, sd_bus *bus) {
return log_error_errno(r, "Failed to add job enumerator: %m");
for (t = 0; t < _UNIT_TYPE_MAX; t++) {
r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, unit_vtable[t]->bus_vtable, bus_unit_interface_find, m);
const char *interface;
assert_se(interface = unit_dbus_interface_from_type(t));
r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", interface, unit_vtable[t]->bus_vtable, bus_unit_interface_find, m);
if (r < 0)
return log_error_errno(r, "Failed to register type specific vtable for %s: %m", unit_vtable[t]->bus_interface);
return log_error_errno(r, "Failed to register type specific vtable for %s: %m", interface);
if (unit_vtable[t]->cgroup_context_offset > 0) {
r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_unit_cgroup_vtable, bus_unit_cgroup_find, m);
r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", interface, bus_unit_cgroup_vtable, bus_unit_cgroup_find, m);
if (r < 0)
return log_error_errno(r, "Failed to register control group unit vtable for %s: %m", unit_vtable[t]->bus_interface);
return log_error_errno(r, "Failed to register control group unit vtable for %s: %m", interface);
r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_cgroup_vtable, bus_cgroup_context_find, m);
r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", interface, bus_cgroup_vtable, bus_cgroup_context_find, m);
if (r < 0)
return log_error_errno(r, "Failed to register control group vtable for %s: %m", unit_vtable[t]->bus_interface);
return log_error_errno(r, "Failed to register control group vtable for %s: %m", interface);
}
if (unit_vtable[t]->exec_context_offset > 0) {
r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_exec_vtable, bus_exec_context_find, m);
r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", interface, bus_exec_vtable, bus_exec_context_find, m);
if (r < 0)
return log_error_errno(r, "Failed to register execute vtable for %s: %m", unit_vtable[t]->bus_interface);
return log_error_errno(r, "Failed to register execute vtable for %s: %m", interface);
}
if (unit_vtable[t]->kill_context_offset > 0) {
r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_kill_vtable, bus_kill_context_find, m);
r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", interface, bus_kill_vtable, bus_kill_context_find, m);
if (r < 0)
return log_error_errno(r, "Failed to register kill vtable for %s: %m", unit_vtable[t]->bus_interface);
return log_error_errno(r, "Failed to register kill vtable for %s: %m", interface);
}
}
@ -1194,22 +1198,17 @@ int bus_track_coldplug(Manager *m, sd_bus_track **t, char ***l) {
}
int bus_verify_manage_units_async(Manager *m, sd_bus_message *call, sd_bus_error *error) {
return bus_verify_polkit_async(call, CAP_SYS_ADMIN, "org.freedesktop.systemd1.manage-units", false, UID_INVALID, &m->polkit_registry, error);
}
/* Same as bus_verify_manage_unit_async(), but checks for CAP_KILL instead of CAP_SYS_ADMIN */
int bus_verify_manage_units_async_for_kill(Manager *m, sd_bus_message *call, sd_bus_error *error) {
return bus_verify_polkit_async(call, CAP_KILL, "org.freedesktop.systemd1.manage-units", false, UID_INVALID, &m->polkit_registry, error);
return bus_verify_polkit_async(call, CAP_SYS_ADMIN, "org.freedesktop.systemd1.manage-units", NULL, false, UID_INVALID, &m->polkit_registry, error);
}
int bus_verify_manage_unit_files_async(Manager *m, sd_bus_message *call, sd_bus_error *error) {
return bus_verify_polkit_async(call, CAP_SYS_ADMIN, "org.freedesktop.systemd1.manage-unit-files", false, UID_INVALID, &m->polkit_registry, error);
return bus_verify_polkit_async(call, CAP_SYS_ADMIN, "org.freedesktop.systemd1.manage-unit-files", NULL, false, UID_INVALID, &m->polkit_registry, error);
}
int bus_verify_reload_daemon_async(Manager *m, sd_bus_message *call, sd_bus_error *error) {
return bus_verify_polkit_async(call, CAP_SYS_ADMIN, "org.freedesktop.systemd1.reload-daemon", false, UID_INVALID, &m->polkit_registry, error);
return bus_verify_polkit_async(call, CAP_SYS_ADMIN, "org.freedesktop.systemd1.reload-daemon", NULL, false, UID_INVALID, &m->polkit_registry, error);
}
int bus_verify_set_environment_async(Manager *m, sd_bus_message *call, sd_bus_error *error) {
return bus_verify_polkit_async(call, CAP_SYS_ADMIN, "org.freedesktop.systemd1.set-environment", false, UID_INVALID, &m->polkit_registry, error);
return bus_verify_polkit_async(call, CAP_SYS_ADMIN, "org.freedesktop.systemd1.set-environment", NULL, false, UID_INVALID, &m->polkit_registry, error);
}

View File

@ -37,7 +37,6 @@ int bus_track_coldplug(Manager *m, sd_bus_track **t, char ***l);
int bus_foreach_bus(Manager *m, sd_bus_track *subscribed2, int (*send_message)(sd_bus *bus, void *userdata), void *userdata);
int bus_verify_manage_units_async(Manager *m, sd_bus_message *call, sd_bus_error *error);
int bus_verify_manage_units_async_for_kill(Manager *m, sd_bus_message *call, sd_bus_error *error);
int bus_verify_manage_unit_files_async(Manager *m, sd_bus_message *call, sd_bus_error *error);
int bus_verify_reload_daemon_async(Manager *m, sd_bus_message *call, sd_bus_error *error);
int bus_verify_set_environment_async(Manager *m, sd_bus_message *call, sd_bus_error *error);

View File

@ -849,7 +849,6 @@ const UnitVTable device_vtable = {
.active_state = device_active_state,
.sub_state_to_string = device_sub_state_to_string,
.bus_interface = "org.freedesktop.systemd1.Device",
.bus_vtable = bus_device_vtable,
.following = device_following,

View File

@ -214,7 +214,7 @@ struct ExecParameters {
bool apply_tty_stdin;
bool confirm_spawn;
bool selinux_context_net;
CGroupControllerMask cgroup_supported;
CGroupMask cgroup_supported;
const char *cgroup_path;
bool cgroup_delegate;
const char *runtime_prefix;

View File

@ -108,7 +108,7 @@ static void wait_for_children(Set *pids, sigset_t *mask) {
return;
}
set_remove(pids, ULONG_TO_PTR(pid));
(void) set_remove(pids, PID_TO_PTR(pid));
}
/* Now explicitly check who might be remaining, who
@ -117,7 +117,7 @@ static void wait_for_children(Set *pids, sigset_t *mask) {
/* We misuse getpgid as a check whether a
* process still exists. */
if (getpgid((pid_t) PTR_TO_ULONG(p)) >= 0)
if (getpgid(PTR_TO_PID(p)) >= 0)
continue;
if (errno != ESRCH)
@ -179,7 +179,7 @@ static int killall(int sig, Set *pids, bool send_sighup) {
if (kill(pid, sig) >= 0) {
if (pids) {
r = set_put(pids, ULONG_TO_PTR(pid));
r = set_put(pids, PID_TO_PTR(pid));
if (r < 0)
log_oom();
}

View File

@ -106,7 +106,7 @@ m4_define(`KILL_CONTEXT_CONFIG_ITEMS',
`$1.SendSIGKILL, config_parse_bool, 0, offsetof($1, kill_context.send_sigkill)
$1.SendSIGHUP, config_parse_bool, 0, offsetof($1, kill_context.send_sighup)
$1.KillMode, config_parse_kill_mode, 0, offsetof($1, kill_context.kill_mode)
$1.KillSignal, config_parse_kill_signal, 0, offsetof($1, kill_context.kill_signal)'
$1.KillSignal, config_parse_signal, 0, offsetof($1, kill_context.kill_signal)'
)m4_dnl
m4_define(`CGROUP_CONTEXT_CONFIG_ITEMS',
`$1.Slice, config_parse_unit_slice, 0, 0

View File

@ -1048,7 +1048,7 @@ int config_parse_bounding_set(const char *unit,
cap = capability_from_name(t);
if (cap < 0) {
log_syntax(unit, LOG_ERR, filename, line, errno, "Failed to parse capability in bounding set, ignoring: %s", t);
log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse capability in bounding set, ignoring: %s", t);
continue;
}
@ -1143,39 +1143,8 @@ int config_parse_sysv_priority(const char *unit,
#endif
DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_utmp_mode, exec_utmp_mode, ExecUtmpMode, "Failed to parse utmp mode");
DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
int config_parse_kill_signal(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) {
int *sig = data;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(sig);
r = signal_from_string_try_harder(rvalue);
if (r <= 0) {
log_syntax(unit, LOG_ERR, filename, line, -r,
"Failed to parse kill signal, ignoring: %s", rvalue);
return 0;
}
*sig = r;
return 0;
}
int config_parse_exec_mount_flags(const char *unit,
const char *filename,
unsigned line,
@ -2602,7 +2571,7 @@ int config_parse_unit_slice(
void *userdata) {
_cleanup_free_ char *k = NULL;
Unit *u = userdata, *slice;
Unit *u = userdata, *slice = NULL;
int r;
assert(filename);
@ -2611,29 +2580,23 @@ int config_parse_unit_slice(
assert(u);
r = unit_name_printf(u, rvalue, &k);
if (r < 0)
log_syntax(unit, LOG_ERR, filename, line, -r,
"Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
if (!k) {
k = strdup(rvalue);
if (!k)
return log_oom();
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
return 0;
}
r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, -r,
"Failed to load slice unit %s. Ignoring.", k);
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load slice unit %s. Ignoring.", k);
return 0;
}
if (slice->type != UNIT_SLICE) {
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
"Slice unit %s is not a slice. Ignoring.", k);
r = unit_set_slice(u, slice);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to assign slice %s to unit %s. Ignoring.", slice->id, u->id);
return 0;
}
unit_ref_set(&u->slice, slice);
return 0;
}
@ -3027,36 +2990,6 @@ int config_parse_job_mode_isolate(
return 0;
}
int config_parse_personality(
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) {
unsigned long *personality = data, p;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(personality);
p = personality_from_string(rvalue);
if (p == PERSONALITY_INVALID) {
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
"Failed to parse personality, ignoring: %s", rvalue);
return 0;
}
*personality = p;
return 0;
}
int config_parse_runtime_directory(
const char *unit,
const char *filename,
@ -3603,6 +3536,11 @@ int unit_load_fragment(Unit *u) {
assert(u->load_state == UNIT_STUB);
assert(u->id);
if (u->transient) {
u->load_state = UNIT_LOADED;
return 0;
}
/* First, try to find the unit under its id. We always look
* for unit files in the default directories, to make it easy
* to override things by placing things in /etc/systemd/system */
@ -3721,7 +3659,7 @@ void unit_dump_config_items(FILE *f) {
{ config_parse_sysv_priority, "SYSVPRIORITY" },
#endif
{ config_parse_kill_mode, "KILLMODE" },
{ config_parse_kill_signal, "SIGNAL" },
{ config_parse_signal, "SIGNAL" },
{ config_parse_socket_listen, "SOCKET [...]" },
{ config_parse_socket_bind, "SOCKETBIND" },
{ config_parse_socket_bindtodevice, "NETWORKINTERFACE" },

View File

@ -92,7 +92,6 @@ int config_parse_blockio_bandwidth(const char *unit, const char *filename, unsig
int config_parse_job_mode(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);
int config_parse_job_mode_isolate(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);
int config_parse_exec_selinux_context(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);
int config_parse_personality(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);
int config_parse_exec_apparmor_profile(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);
int config_parse_exec_smack_process_label(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);
int config_parse_address_families(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);

View File

@ -433,25 +433,28 @@ static int config_parse_cpu_affinity2(
void *data,
void *userdata) {
const char *word, *state;
size_t l;
cpu_set_t *c = NULL;
const char *whole_rvalue = rvalue;
_cleanup_cpu_free_ cpu_set_t *c = NULL;
unsigned ncpus = 0;
assert(filename);
assert(lvalue);
assert(rvalue);
FOREACH_WORD_QUOTED(word, l, rvalue, state) {
char *t;
int r;
for (;;) {
_cleanup_free_ char *word = NULL;
unsigned cpu;
int r;
if (!(t = strndup(word, l)))
return log_oom();
r = extract_first_word(&rvalue, &word, WHITESPACE, EXTRACT_QUOTES);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Invalid value for %s: %s", lvalue, whole_rvalue);
return r;
}
if (r == 0)
break;
r = safe_atou(t, &cpu);
free(t);
r = safe_atou(word, &cpu);
if (!c)
if (!(c = cpu_set_malloc(&ncpus)))
@ -460,23 +463,19 @@ static int config_parse_cpu_affinity2(
if (r < 0 || cpu >= ncpus) {
log_syntax(unit, LOG_ERR, filename, line, -r,
"Failed to parse CPU affinity '%s'", rvalue);
CPU_FREE(c);
return -EBADMSG;
}
CPU_SET_S(cpu, CPU_ALLOC_SIZE(ncpus), c);
}
if (!isempty(state))
if (!isempty(rvalue))
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
"Trailing garbage, ignoring.");
if (c) {
if (c)
if (sched_setaffinity(0, CPU_ALLOC_SIZE(ncpus), c) < 0)
log_warning("Failed to set CPU affinity: %m");
CPU_FREE(c);
}
return 0;
}
@ -538,9 +537,8 @@ static int config_parse_join_controllers(const char *unit,
void *data,
void *userdata) {
const char *whole_rvalue = rvalue;
unsigned n = 0;
const char *word, *state;
size_t length;
assert(filename);
assert(lvalue);
@ -548,16 +546,22 @@ static int config_parse_join_controllers(const char *unit,
free_join_controllers();
FOREACH_WORD_QUOTED(word, length, rvalue, state) {
char *s, **l;
for (;;) {
_cleanup_free_ char *word = NULL;
char **l;
int r;
s = strndup(word, length);
if (!s)
return log_oom();
l = strv_split(s, ",");
free(s);
r = extract_first_word(&rvalue, &word, WHITESPACE, EXTRACT_QUOTES);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Invalid value for %s: %s", lvalue, whole_rvalue);
return r;
}
if (r == 0)
break;
l = strv_split(word, ",");
if (!l)
log_oom();
strv_uniq(l);
if (strv_length(l) <= 1) {
@ -617,7 +621,7 @@ static int config_parse_join_controllers(const char *unit,
arg_join_controllers = t;
}
}
if (!isempty(state))
if (!isempty(rvalue))
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
"Trailing garbage, ignoring.");
@ -1391,8 +1395,7 @@ int main(int argc, char *argv[]) {
/* clear the kernel timestamp,
* because we are not PID 1 */
kernel_timestamp.monotonic = 0ULL;
kernel_timestamp.realtime = 0ULL;
kernel_timestamp = DUAL_TIMESTAMP_NULL;
}
/* Initialize default unit */
@ -2044,7 +2047,7 @@ finish:
* kernel; at this point, we will not listen to the
* signals anyway */
if (detect_container(NULL) <= 0)
cg_uninstall_release_agent(SYSTEMD_CGROUP_CONTROLLER);
(void) cg_uninstall_release_agent(SYSTEMD_CGROUP_CONTROLLER);
execve(SYSTEMD_SHUTDOWN_BINARY_PATH, (char **) command_line, env_block);
log_error_errno(errno, "Failed to execute shutdown binary, %s: %m",

View File

@ -250,8 +250,8 @@ static int manager_dispatch_ask_password_fd(sd_event_source *source,
static void manager_close_ask_password(Manager *m) {
assert(m);
m->ask_password_inotify_fd = safe_close(m->ask_password_inotify_fd);
m->ask_password_event_source = sd_event_source_unref(m->ask_password_event_source);
m->ask_password_inotify_fd = safe_close(m->ask_password_inotify_fd);
m->have_ask_password = -EINVAL;
}
@ -568,11 +568,14 @@ int manager_new(ManagerRunningAs running_as, bool test_run, Manager **_m) {
m->idle_pipe[0] = m->idle_pipe[1] = m->idle_pipe[2] = m->idle_pipe[3] = -1;
m->pin_cgroupfs_fd = m->notify_fd = m->signal_fd = m->time_change_fd = m->dev_autofs_fd = m->private_listen_fd = m->kdbus_fd = m->utab_inotify_fd = -1;
m->pin_cgroupfs_fd = m->notify_fd = m->signal_fd = m->time_change_fd =
m->dev_autofs_fd = m->private_listen_fd = m->kdbus_fd = m->utab_inotify_fd =
m->cgroup_inotify_fd = -1;
m->current_job_id = 1; /* start as id #1, so that we can leave #0 around as "null-like" value */
m->ask_password_inotify_fd = -1;
m->have_ask_password = -EINVAL; /* we don't know */
m->first_boot = -1;
m->test_run = test_run;
@ -1582,19 +1585,19 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t
/* Notify every unit that might be interested, but try
* to avoid notifying the same one multiple times. */
u1 = manager_get_unit_by_pid(m, ucred->pid);
u1 = manager_get_unit_by_pid_cgroup(m, ucred->pid);
if (u1) {
manager_invoke_notify_message(m, u1, ucred->pid, buf, n, fds);
found = true;
}
u2 = hashmap_get(m->watch_pids1, LONG_TO_PTR(ucred->pid));
u2 = hashmap_get(m->watch_pids1, PID_TO_PTR(ucred->pid));
if (u2 && u2 != u1) {
manager_invoke_notify_message(m, u2, ucred->pid, buf, n, fds);
found = true;
}
u3 = hashmap_get(m->watch_pids2, LONG_TO_PTR(ucred->pid));
u3 = hashmap_get(m->watch_pids2, PID_TO_PTR(ucred->pid));
if (u3 && u3 != u2 && u3 != u1) {
manager_invoke_notify_message(m, u3, ucred->pid, buf, n, fds);
found = true;
@ -1660,13 +1663,13 @@ static int manager_dispatch_sigchld(Manager *m) {
/* And now figure out the unit this belongs
* to, it might be multiple... */
u1 = manager_get_unit_by_pid(m, si.si_pid);
u1 = manager_get_unit_by_pid_cgroup(m, si.si_pid);
if (u1)
invoke_sigchld_event(m, u1, &si);
u2 = hashmap_get(m->watch_pids1, LONG_TO_PTR(si.si_pid));
u2 = hashmap_get(m->watch_pids1, PID_TO_PTR(si.si_pid));
if (u2 && u2 != u1)
invoke_sigchld_event(m, u2, &si);
u3 = hashmap_get(m->watch_pids2, LONG_TO_PTR(si.si_pid));
u3 = hashmap_get(m->watch_pids2, PID_TO_PTR(si.si_pid));
if (u3 && u3 != u2 && u3 != u1)
invoke_sigchld_event(m, u3, &si);
}
@ -2721,7 +2724,7 @@ void manager_check_finished(Manager *m) {
SET_FOREACH(u, m->startup_units, i)
if (u->cgroup_path)
cgroup_context_apply(unit_get_cgroup_context(u), unit_get_cgroup_mask(u), u->cgroup_path, manager_state(m));
cgroup_context_apply(unit_get_cgroup_context(u), unit_get_own_mask(u), u->cgroup_path, manager_state(m));
}
static int create_generator_dir(Manager *m, char **generator, const char *name) {
@ -2998,12 +3001,14 @@ void manager_set_first_boot(Manager *m, bool b) {
if (m->running_as != MANAGER_SYSTEM)
return;
m->first_boot = b;
if (m->first_boot != (int) b) {
if (b)
(void) touch("/run/systemd/first-boot");
else
(void) unlink("/run/systemd/first-boot");
}
if (m->first_boot)
touch("/run/systemd/first-boot");
else
unlink("/run/systemd/first-boot");
m->first_boot = b;
}
void manager_status_printf(Manager *m, StatusType type, const char *status, const char *format, ...) {

View File

@ -215,16 +215,22 @@ struct Manager {
/* Data specific to the cgroup subsystem */
Hashmap *cgroup_unit;
CGroupControllerMask cgroup_supported;
CGroupMask cgroup_supported;
char *cgroup_root;
int gc_marker;
unsigned n_in_gc_queue;
/* Notifications from cgroups, when the unified hierarchy is
* used is done via inotify. */
int cgroup_inotify_fd;
sd_event_source *cgroup_inotify_event_source;
Hashmap *cgroup_inotify_wd_unit;
/* Make sure the user cannot accidentally unmount our cgroup
* file system */
int pin_cgroupfs_fd;
int gc_marker;
unsigned n_in_gc_queue;
/* Flags */
ManagerRunningAs running_as;
ManagerExitCode exit_code:5;
@ -233,7 +239,6 @@ struct Manager {
bool dispatching_dbus_queue:1;
bool taint_usr:1;
bool first_boot:1;
bool test_run:1;
@ -295,6 +300,8 @@ struct Manager {
const char *unit_log_field;
const char *unit_log_format_string;
int first_boot;
};
int manager_new(ManagerRunningAs running_as, bool test_run, Manager **m);

View File

@ -93,12 +93,14 @@ static const MountPoint mount_table[] = {
#endif
{ "tmpfs", "/run", "tmpfs", "mode=755", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
NULL, MNT_FATAL|MNT_IN_CONTAINER },
{ "cgroup", "/sys/fs/cgroup", "cgroup", "__DEVEL__sane_behavior", MS_NOSUID|MS_NOEXEC|MS_NODEV,
cg_is_unified_wanted, MNT_FATAL|MNT_IN_CONTAINER },
{ "tmpfs", "/sys/fs/cgroup", "tmpfs", "mode=755", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME,
NULL, MNT_FATAL|MNT_IN_CONTAINER },
cg_is_legacy_wanted, MNT_FATAL|MNT_IN_CONTAINER },
{ "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd,xattr", MS_NOSUID|MS_NOEXEC|MS_NODEV,
NULL, MNT_IN_CONTAINER },
cg_is_legacy_wanted, MNT_IN_CONTAINER },
{ "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd", MS_NOSUID|MS_NOEXEC|MS_NODEV,
NULL, MNT_FATAL|MNT_IN_CONTAINER },
cg_is_legacy_wanted, MNT_FATAL|MNT_IN_CONTAINER },
{ "pstore", "/sys/fs/pstore", "pstore", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
NULL, MNT_NONE },
#ifdef ENABLE_EFI
@ -217,6 +219,9 @@ int mount_cgroup_controllers(char ***join_controllers) {
_cleanup_set_free_free_ Set *controllers = NULL;
int r;
if (!cg_is_legacy_wanted())
return 0;
/* Mount all available cgroup controllers that are built into the kernel. */
controllers = set_new(&string_hash_ops);

View File

@ -521,7 +521,7 @@ static int mount_add_extras(Mount *m) {
if (r < 0)
return r;
r = unit_add_default_slice(u, &m->cgroup_context);
r = unit_set_default_slice(u);
if (r < 0)
return r;
@ -1871,7 +1871,6 @@ const UnitVTable mount_vtable = {
.reset_failed = mount_reset_failed,
.bus_interface = "org.freedesktop.systemd1.Mount",
.bus_vtable = bus_mount_vtable,
.bus_set_property = bus_mount_set_property,
.bus_commit_properties = bus_mount_commit_properties,

View File

@ -770,6 +770,5 @@ const UnitVTable path_vtable = {
.reset_failed = path_reset_failed,
.bus_interface = "org.freedesktop.systemd1.Path",
.bus_vtable = bus_path_vtable
};

View File

@ -22,12 +22,13 @@
#include <errno.h>
#include <unistd.h>
#include "unit.h"
#include "scope.h"
#include "log.h"
#include "dbus-scope.h"
#include "strv.h"
#include "special.h"
#include "unit-name.h"
#include "unit.h"
#include "scope.h"
#include "dbus-scope.h"
#include "load-dropin.h"
static const UnitActiveState state_translation_table[_SCOPE_STATE_MAX] = {
@ -136,7 +137,9 @@ static int scope_verify(Scope *s) {
if (UNIT(s)->load_state != UNIT_LOADED)
return 0;
if (set_isempty(UNIT(s)->pids) && UNIT(s)->manager->n_reloading <= 0) {
if (set_isempty(UNIT(s)->pids) &&
!manager_is_reloading_or_reexecuting(UNIT(s)->manager) &&
!unit_has_name(UNIT(s), SPECIAL_INIT_SCOPE)) {
log_unit_error(UNIT(s), "Scope has no PIDs. Refusing.");
return -EINVAL;
}
@ -151,7 +154,7 @@ static int scope_load(Unit *u) {
assert(s);
assert(u->load_state == UNIT_STUB);
if (!u->transient && UNIT(s)->manager->n_reloading <= 0)
if (!u->transient && !manager_is_reloading_or_reexecuting(u->manager))
return -ENOENT;
u->load_state = UNIT_LOADED;
@ -164,7 +167,7 @@ static int scope_load(Unit *u) {
if (r < 0)
return r;
r = unit_add_default_slice(u, &s->cgroup_context);
r = unit_set_default_slice(u);
if (r < 0)
return r;
@ -279,6 +282,9 @@ static int scope_start(Unit *u) {
assert(s);
if (unit_has_name(u, SPECIAL_INIT_SCOPE))
return -EPERM;
if (s->state == SCOPE_FAILED)
return -EPERM;
@ -289,7 +295,7 @@ static int scope_start(Unit *u) {
assert(s->state == SCOPE_DEAD);
if (!u->transient && UNIT(s)->manager->n_reloading <= 0)
if (!u->transient && !manager_is_reloading_or_reexecuting(u->manager))
return -ENOENT;
(void) unit_realize_cgroup(u);
@ -396,7 +402,7 @@ static bool scope_check_gc(Unit *u) {
if (u->cgroup_path) {
int r;
r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, true);
r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path);
if (r <= 0)
return true;
}
@ -464,6 +470,9 @@ static int scope_dispatch_timer(sd_event_source *source, usec_t usec, void *user
int scope_abandon(Scope *s) {
assert(s);
if (unit_has_name(UNIT(s), SPECIAL_INIT_SCOPE))
return -EPERM;
if (!IN_SET(s->state, SCOPE_RUNNING, SCOPE_ABANDONED))
return -ESTALE;
@ -499,6 +508,48 @@ _pure_ static const char *scope_sub_state_to_string(Unit *u) {
return scope_state_to_string(SCOPE(u)->state);
}
static int scope_enumerate(Manager *m) {
Unit *u;
int r;
assert(m);
/* Let's unconditionally add the "init.scope" special unit
* that encapsulates PID 1. Note that PID 1 already is in the
* cgroup for this, we hence just need to allocate the object
* for it and that's it. */
u = manager_get_unit(m, SPECIAL_INIT_SCOPE);
if (!u) {
u = unit_new(m, sizeof(Scope));
if (!u)
return log_oom();
r = unit_add_name(u, SPECIAL_INIT_SCOPE);
if (r < 0) {
unit_free(u);
return log_error_errno(r, "Failed to add init.scope name");
}
}
u->transient = true;
u->default_dependencies = false;
u->no_gc = true;
SCOPE(u)->deserialized_state = SCOPE_RUNNING;
SCOPE(u)->kill_context.kill_signal = SIGRTMIN+14;
/* Prettify things, if we can. */
if (!u->description)
u->description = strdup("System and Service Manager");
if (!u->documentation)
(void) strv_extend(&u->documentation, "man:systemd(1)");
unit_add_to_load_queue(u);
unit_add_to_dbus_queue(u);
return 0;
}
static const char* const scope_state_table[_SCOPE_STATE_MAX] = {
[SCOPE_DEAD] = "dead",
[SCOPE_RUNNING] = "running",
@ -561,10 +612,11 @@ const UnitVTable scope_vtable = {
.notify_cgroup_empty = scope_notify_cgroup_empty_event,
.bus_interface = "org.freedesktop.systemd1.Scope",
.bus_vtable = bus_scope_vtable,
.bus_set_property = bus_scope_set_property,
.bus_commit_properties = bus_scope_commit_properties,
.can_transient = true
.can_transient = true,
.enumerate = scope_enumerate,
};

View File

@ -246,7 +246,7 @@ int mac_selinux_generic_access_check(
if (path) {
/* Get the file context of the unit file */
r = getfilecon(path, &fcon);
r = getfilecon_raw(path, &fcon);
if (r < 0) {
r = sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Failed to get file context on %s.", path);
goto finish;
@ -254,7 +254,7 @@ int mac_selinux_generic_access_check(
tclass = "service";
} else {
r = getcon(&fcon);
r = getcon_raw(&fcon);
if (r < 0) {
r = sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Failed to get current context.");
goto finish;

View File

@ -34,6 +34,7 @@
#include "log.h"
#ifdef HAVE_SELINUX
_printf_(2,3)
static int null_log(int type, const char *fmt, ...) {
return 0;
}

View File

@ -556,7 +556,7 @@ static int service_add_extras(Service *s) {
if (r < 0)
return r;
r = unit_add_default_slice(UNIT(s), &s->cgroup_context);
r = unit_set_default_slice(UNIT(s));
if (r < 0)
return r;
@ -767,7 +767,7 @@ static int service_load_pid_file(Service *s, bool may_warn) {
}
static int service_search_main_pid(Service *s) {
pid_t pid;
pid_t pid = 0;
int r;
assert(s);
@ -782,9 +782,9 @@ static int service_search_main_pid(Service *s) {
assert(s->main_pid <= 0);
pid = unit_search_main_pid(UNIT(s));
if (pid <= 0)
return -ENOENT;
r = unit_search_main_pid(UNIT(s), &pid);
if (r < 0)
return r;
log_unit_debug(UNIT(s), "Main PID guessed: "PID_FMT, pid);
r = service_set_main_pid(s, pid);
@ -860,7 +860,7 @@ static void service_set_state(Service *s, ServiceState state) {
/* For the inactive states unit_notify() will trim the cgroup,
* but for exit we have to do that ourselves... */
if (state == SERVICE_EXITED && UNIT(s)->manager->n_reloading <= 0)
unit_destroy_cgroup_if_empty(UNIT(s));
unit_prune_cgroup(UNIT(s));
/* For remain_after_exit services, let's see if we can "release" the
* hold on the console, since unit_notify() only does that in case of
@ -1269,7 +1269,7 @@ static int cgroup_good(Service *s) {
if (!UNIT(s)->cgroup_path)
return 0;
r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, UNIT(s)->cgroup_path, true);
r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, UNIT(s)->cgroup_path);
if (r < 0)
return r;
@ -1520,18 +1520,33 @@ fail:
service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_RESOURCES);
}
static bool service_good(Service *s) {
int main_pid_ok;
assert(s);
if (s->type == SERVICE_DBUS && !s->bus_name_good)
return false;
main_pid_ok = main_pid_good(s);
if (main_pid_ok > 0) /* It's alive */
return true;
if (main_pid_ok == 0) /* It's dead */
return false;
/* OK, we don't know anything about the main PID, maybe
* because there is none. Let's check the control group
* instead. */
return cgroup_good(s) != 0;
}
static void service_enter_running(Service *s, ServiceResult f) {
int main_pid_ok, cgroup_ok;
assert(s);
if (f != SERVICE_SUCCESS)
s->result = f;
main_pid_ok = main_pid_good(s);
cgroup_ok = cgroup_good(s);
if ((main_pid_ok > 0 || (main_pid_ok < 0 && cgroup_ok != 0)) &&
(s->bus_name_good || s->type != SERVICE_DBUS)) {
if (service_good(s)) {
/* If there are any queued up sd_notify()
* notifications, process them now */
@ -2629,7 +2644,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
break;
}
} else
service_search_main_pid(s);
(void) service_search_main_pid(s);
service_enter_start_post(s);
break;
@ -2651,7 +2666,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
break;
}
} else
service_search_main_pid(s);
(void) service_search_main_pid(s);
service_enter_running(s, SERVICE_SUCCESS);
break;
@ -2659,7 +2674,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
case SERVICE_RELOAD:
if (f == SERVICE_SUCCESS) {
service_load_pid_file(s, true);
service_search_main_pid(s);
(void) service_search_main_pid(s);
}
s->reload_result = f;
@ -3214,7 +3229,6 @@ const UnitVTable service_vtable = {
.bus_name_owner_change = service_bus_name_owner_change,
.bus_interface = "org.freedesktop.systemd1.Service",
.bus_vtable = bus_service_vtable,
.bus_set_property = bus_service_set_property,
.bus_commit_properties = bus_service_commit_properties,

View File

@ -21,12 +21,13 @@
#include <errno.h>
#include "unit.h"
#include "slice.h"
#include "log.h"
#include "dbus-slice.h"
#include "strv.h"
#include "special.h"
#include "unit-name.h"
#include "unit.h"
#include "slice.h"
#include "dbus-slice.h"
static const UnitActiveState state_translation_table[_SLICE_STATE_MAX] = {
[SLICE_DEAD] = UNIT_INACTIVE,
@ -252,6 +253,40 @@ _pure_ static const char *slice_sub_state_to_string(Unit *u) {
return slice_state_to_string(SLICE(u)->state);
}
static int slice_enumerate(Manager *m) {
Unit *u;
int r;
assert(m);
u = manager_get_unit(m, SPECIAL_ROOT_SLICE);
if (!u) {
u = unit_new(m, sizeof(Slice));
if (!u)
return log_oom();
r = unit_add_name(u, SPECIAL_ROOT_SLICE);
if (r < 0) {
unit_free(u);
return log_error_errno(r, "Failed to add -.slice name");
}
}
u->default_dependencies = false;
u->no_gc = true;
SLICE(u)->deserialized_state = SLICE_ACTIVE;
if (!u->description)
u->description = strdup("Root Slice");
if (!u->documentation)
(void) strv_extend(&u->documentation, "man:systemd.special(7)");
unit_add_to_load_queue(u);
unit_add_to_dbus_queue(u);
return 0;
}
static const char* const slice_state_table[_SLICE_STATE_MAX] = {
[SLICE_DEAD] = "dead",
[SLICE_ACTIVE] = "active"
@ -289,11 +324,12 @@ const UnitVTable slice_vtable = {
.active_state = slice_active_state,
.sub_state_to_string = slice_sub_state_to_string,
.bus_interface = "org.freedesktop.systemd1.Slice",
.bus_vtable = bus_slice_vtable,
.bus_set_property = bus_slice_set_property,
.bus_commit_properties = bus_slice_commit_properties,
.enumerate = slice_enumerate,
.status_message_formats = {
.finished_start_job = {
[JOB_DONE] = "Created slice %s.",

View File

@ -302,6 +302,5 @@ const UnitVTable snapshot_vtable = {
.active_state = snapshot_active_state,
.sub_state_to_string = snapshot_sub_state_to_string,
.bus_interface = "org.freedesktop.systemd1.Snapshot",
.bus_vtable = bus_snapshot_vtable
};

View File

@ -345,7 +345,7 @@ static int socket_add_extras(Socket *s) {
if (r < 0)
return r;
r = unit_add_default_slice(u, &s->cgroup_context);
r = unit_set_default_slice(u);
if (r < 0)
return r;
}
@ -839,7 +839,7 @@ static void socket_apply_socket_options(Socket *s, int fd) {
if (s->keep_alive_cnt) {
int value = s->keep_alive_cnt;
if (setsockopt(fd, SOL_SOCKET, TCP_KEEPCNT, &value, sizeof(value)) < 0)
if (setsockopt(fd, SOL_TCP, TCP_KEEPCNT, &value, sizeof(value)) < 0)
log_unit_warning_errno(UNIT(s), errno, "TCP_KEEPCNT failed: %m");
}
@ -2709,7 +2709,6 @@ const UnitVTable socket_vtable = {
.reset_failed = socket_reset_failed,
.bus_interface = "org.freedesktop.systemd1.Socket",
.bus_vtable = bus_socket_vtable,
.bus_set_property = bus_socket_set_property,
.bus_commit_properties = bus_socket_commit_properties,

View File

@ -326,7 +326,7 @@ static int swap_load(Unit *u) {
if (r < 0)
return r;
r = unit_add_default_slice(u, &s->cgroup_context);
r = unit_set_default_slice(u);
if (r < 0)
return r;
@ -1485,7 +1485,6 @@ const UnitVTable swap_vtable = {
.reset_failed = swap_reset_failed,
.bus_interface = "org.freedesktop.systemd1.Swap",
.bus_vtable = bus_swap_vtable,
.bus_set_property = bus_swap_set_property,
.bus_commit_properties = bus_swap_commit_properties,

View File

@ -221,7 +221,6 @@ const UnitVTable target_vtable = {
.active_state = target_active_state,
.sub_state_to_string = target_sub_state_to_string,
.bus_interface = "org.freedesktop.systemd1.Target",
.bus_vtable = bus_target_vtable,
.status_message_formats = {

View File

@ -772,7 +772,6 @@ const UnitVTable timer_vtable = {
.reset_failed = timer_reset_failed,
.time_change = timer_time_change,
.bus_interface = "org.freedesktop.systemd1.Timer",
.bus_vtable = bus_timer_vtable,
.bus_set_property = bus_timer_set_property,

Some files were not shown because too many files have changed in this diff Show More