mirror of
https://git.proxmox.com/git/systemd
synced 2025-05-25 21:41:18 +00:00
Imported Upstream version 226
This commit is contained in:
parent
13d276d0d7
commit
d9dfd2336c
28
CODING_STYLE
28
CODING_STYLE
@ -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
|
||||
|
@ -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 \
|
||||
|
83
Makefile.am
83
Makefile.am
@ -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
210
NEWS
@ -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
4
README
@ -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
24
TODO
@ -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:
|
||||
|
16
configure.ac
16
configure.ac
@ -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}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
##########################################
|
||||
|
@ -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
87
m4/ax_compiler_vendor.m4
Normal 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`
|
||||
])
|
||||
])
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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, &t);
|
||||
if (t == (uint64_t) -1)
|
||||
msec = -1;
|
||||
msec = -1;
|
||||
else {
|
||||
struct timespec ts;
|
||||
uint64_t n;
|
||||
clock_getttime(CLOCK_MONOTONIC, &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, &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>
|
||||
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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'>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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>,
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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
383
man/systemd.nspawn.xml
Normal 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>
|
@ -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
|
||||
|
@ -12,3 +12,6 @@ Name=host0
|
||||
[Network]
|
||||
DHCP=yes
|
||||
LinkLocalAddressing=yes
|
||||
|
||||
[DHCP]
|
||||
UseTimezone=yes
|
||||
|
@ -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
|
||||
|
99
po/pl.po
99
po/pl.po
@ -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 "
|
||||
|
70
shell-completion/bash/networkctl
Normal file
70
shell-completion/bash/networkctl
Normal 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
|
@ -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
|
||||
|
@ -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
|
||||
|
60
shell-completion/bash/systemd-path
Normal file
60
shell-completion/bash/systemd-path
Normal 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
|
@ -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
|
||||
;;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
@ -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_;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)))
|
||||
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
219
src/cgls/cgls.c
219
src/cgls/cgls.c
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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 = {
|
||||
|
@ -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",
|
||||
|
@ -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_;
|
||||
|
@ -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)
|
||||
|
@ -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",
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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" },
|
||||
|
@ -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);
|
||||
|
@ -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",
|
||||
|
@ -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, ...) {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -770,6 +770,5 @@ const UnitVTable path_vtable = {
|
||||
|
||||
.reset_failed = path_reset_failed,
|
||||
|
||||
.bus_interface = "org.freedesktop.systemd1.Path",
|
||||
.bus_vtable = bus_path_vtable
|
||||
};
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "log.h"
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
_printf_(2,3)
|
||||
static int null_log(int type, const char *fmt, ...) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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.",
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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 = {
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user