summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CODING_STYLE5
-rw-r--r--Makefile.am10
-rw-r--r--TODO12
-rw-r--r--catalog/systemd.be.catalog2
-rw-r--r--catalog/systemd.be@latin.catalog2
-rw-r--r--catalog/systemd.catalog2
-rw-r--r--catalog/systemd.da.catalog2
-rw-r--r--catalog/systemd.fr.catalog2
-rw-r--r--catalog/systemd.hr.catalog2
-rw-r--r--catalog/systemd.hu.catalog2
-rw-r--r--catalog/systemd.it.catalog2
-rw-r--r--catalog/systemd.ko.catalog2
-rw-r--r--catalog/systemd.pl.catalog2
-rw-r--r--catalog/systemd.pt_BR.catalog2
-rw-r--r--catalog/systemd.ru.catalog2
-rw-r--r--catalog/systemd.sr.catalog2
-rw-r--r--catalog/systemd.zh_CN.catalog2
-rw-r--r--catalog/systemd.zh_TW.catalog2
-rw-r--r--configure.ac11
-rw-r--r--hwdb/60-keyboard.hwdb1
-rw-r--r--man/journald.conf.xml6
-rw-r--r--man/machinectl.xml12
-rw-r--r--man/systemd-system.conf.xml6
-rw-r--r--man/systemd.exec.xml38
-rw-r--r--man/systemd.socket.xml16
-rw-r--r--man/systemd.timer.xml6
-rw-r--r--man/systemd.unit.xml13
-rw-r--r--src/basic/architecture.c3
-rw-r--r--src/basic/architecture.h4
-rw-r--r--src/basic/copy.c54
-rw-r--r--src/basic/copy.h1
-rw-r--r--src/basic/missing.h4
-rw-r--r--src/basic/path-util.c18
-rw-r--r--src/basic/process-util.c12
-rw-r--r--src/basic/process-util.h4
-rw-r--r--src/basic/rlimit-util.c52
-rw-r--r--src/core/dbus-manager.c3
-rw-r--r--src/core/dbus-socket.c2
-rw-r--r--src/core/dbus-unit.c3
-rw-r--r--src/core/load-fragment-gperf.gperf.m45
-rw-r--r--src/core/main.c4
-rw-r--r--src/core/service.c34
-rw-r--r--src/core/service.h1
-rw-r--r--src/core/socket.c81
-rw-r--r--src/core/socket.h3
-rw-r--r--src/core/system.conf2
-rw-r--r--src/core/unit.c14
-rw-r--r--src/core/user.conf2
-rw-r--r--src/import/pull-common.c2
-rw-r--r--src/journal/journal-file.c2
-rw-r--r--src/journal/journald-gperf.gperf2
-rw-r--r--src/journal/journald.conf2
-rw-r--r--src/machine/image-dbus.c75
-rw-r--r--src/machine/machine-dbus.c66
-rw-r--r--src/machine/machine.c24
-rw-r--r--src/machine/machine.h20
-rw-r--r--src/machine/machinectl.c69
-rw-r--r--src/machine/machined.c8
-rw-r--r--src/machine/machined.h4
-rw-r--r--src/machine/operation.c131
-rw-r--r--src/machine/operation.h47
-rw-r--r--src/shared/machine-image.c22
-rw-r--r--src/test/test-copy.c31
-rw-r--r--src/test/test-rlimit-util.c12
l---------[-rw-r--r--]test/TEST-06-SELINUX/Makefile11
l---------[-rw-r--r--]test/TEST-08-ISSUE-2730/Makefile11
l---------test/TEST-10-ISSUE-2467/Makefile1
-rwxr-xr-xtest/TEST-10-ISSUE-2467/test.sh88
-rwxr-xr-xtest/sysv-generator-test.py5
-rw-r--r--tmpfiles.d/systemd.conf.m423
70 files changed, 795 insertions, 333 deletions
diff --git a/CODING_STYLE b/CODING_STYLE
index c2b2e56d5d..b689355c9a 100644
--- a/CODING_STYLE
+++ b/CODING_STYLE
@@ -240,6 +240,11 @@
unlink("/foo/bar/baz");
+ Don't cast function calls to (void) that return no error
+ conditions. Specifically, the various xyz_unref() calls that return a NULL
+ object shouldn't be cast to (void), since not using the return value does not
+ hide any errors.
+
- Don't invoke exit(), ever. It is not replacement for proper error
handling. Please escalate errors up your call chain, and use normal
"return" to exit from the main function of a process. If you
diff --git a/Makefile.am b/Makefile.am
index b323de55c6..6b9d2a0398 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -4942,7 +4942,9 @@ libmachine_core_la_SOURCES = \
src/machine/machine-dbus.c \
src/machine/machine-dbus.h \
src/machine/image-dbus.c \
- src/machine/image-dbus.h
+ src/machine/image-dbus.h \
+ src/machine/operation.c \
+ src/machine/operation.h
libmachine_core_la_LIBADD = \
libshared.la
@@ -5827,6 +5829,12 @@ EXTRA_DIST += \
test/TEST-07-ISSUE-1981/Makefile \
test/TEST-07-ISSUE-1981/test-segfault.sh \
test/TEST-07-ISSUE-1981/test.sh \
+ test/TEST-08-ISSUE-2730/Makefile \
+ test/TEST-08-ISSUE-2730/test.sh \
+ test/TEST-09-ISSUE-2691/Makefile \
+ test/TEST-09-ISSUE-2691/test.sh \
+ test/TEST-10-ISSUE-2467/Makefile \
+ test/TEST-10-ISSUE-2467/test.sh \
test/test-functions
EXTRA_DIST += \
diff --git a/TODO b/TODO
index f088cac5b7..a930583f85 100644
--- a/TODO
+++ b/TODO
@@ -35,13 +35,9 @@ Features:
* journalctl: make sure -f ends when the container indicated by -M terminates
-* make "machinectl clone" properly async, and add fallback for non-tmpfs
-
* rework fopen_temporary() to make use of open_tmpfile_linkable() (problem: the
kernel doesn't support linkat() that replaces existing files, currently)
-* journalctl -f --no-tail fails for Lennart
-
* check if DeviceAllow= should split first, resolve specifiers later
* transient units: don't bother with actually setting unit properties, we
@@ -78,11 +74,9 @@ Features:
* PID1: find a way how we can reload unit file configuration for
specific units only, without reloading the whole of systemd
-* add an explicit parser for LimitNICE= and LimitRTPRIO= that verifies
+* add an explicit parser for LimitRTPRIO= that verifies
the specified range and generates sane error messages for incorrect
- specifications. Also, for LimitNICE= maybe introduce a syntax such
- as "+5" or "-7" in order to make the limits more readable as they
- are otherwise shifted by 20.
+ specifications.
* do something about "/control" subcgroups in the unified cgroup hierarchy
@@ -249,7 +243,7 @@ Features:
CAP_NET_ADMIN is set, more than the loopback device is defined, even
when it is otherwise off
-* MessageQueueMessageSize= should use parse_iec_size().
+* MessageQueueMessageSize= (and suchlike) should use parse_iec_size().
* "busctl status" works only as root on dbus1, since we cannot read
/proc/$PID/exe
diff --git a/catalog/systemd.be.catalog b/catalog/systemd.be.catalog
index be081d6efc..051f49492f 100644
--- a/catalog/systemd.be.catalog
+++ b/catalog/systemd.be.catalog
@@ -53,7 +53,7 @@ Documentation: man:journald.conf(5)
Паведамленні іншых сэрвісаў засталіся.
Мяжа, пасля якой паведамленні будуць адкінуты, наладжваецца з
-дапамогай RateLimitInterval= і RateLimitBurst= у файле
+дапамогай RateLimitIntervalSec= і RateLimitBurst= у файле
/etc/systemd/journald.conf. Глядзіце journald.conf(5) для дэталей.
-- e9bf28e6e834481bb6f48f548ad13606
diff --git a/catalog/systemd.be@latin.catalog b/catalog/systemd.be@latin.catalog
index 382fdb8b04..6ab361aafb 100644
--- a/catalog/systemd.be@latin.catalog
+++ b/catalog/systemd.be@latin.catalog
@@ -53,7 +53,7 @@ Majcie na ŭvazie, što byli adkinuty paviedamliennia toĺki hetaha servisu.
Paviedamlienni inšych servisaŭ zastalisia.
Miaža, paslia jakoj paviedamlienni buduć adkinuty, naladžvajecca z
-dapamohaj RateLimitInterval= i RateLimitBurst= u fajlie
+dapamohaj RateLimitIntervalSec= i RateLimitBurst= u fajlie
/etc/systemd/journald.conf. Hliadzicie journald.conf(5) dlia detaliej.
-- e9bf28e6e834481bb6f48f548ad13606
diff --git a/catalog/systemd.catalog b/catalog/systemd.catalog
index 077f182a5a..90929bca6d 100644
--- a/catalog/systemd.catalog
+++ b/catalog/systemd.catalog
@@ -66,7 +66,7 @@ Note that only messages from the service in question have been
dropped, other services' messages are unaffected.
The limits controlling when messages are dropped may be configured
-with RateLimitInterval= and RateLimitBurst= in
+with RateLimitIntervalSec= and RateLimitBurst= in
/etc/systemd/journald.conf. See journald.conf(5) for details.
-- e9bf28e6e834481bb6f48f548ad13606
diff --git a/catalog/systemd.da.catalog b/catalog/systemd.da.catalog
index bd4d742d8a..093e8139da 100644
--- a/catalog/systemd.da.catalog
+++ b/catalog/systemd.da.catalog
@@ -52,7 +52,7 @@ Kun beskeder fra omtalte service er smidt væk. Beskeder fra andre
services er ikke påvirket.
Grænsen for hvornår beskeder bliver smidt væk kan konfigureres
-med RateLimitInterval= og RateLimitBurst= i
+med RateLimitIntervalSec= og RateLimitBurst= i
/etc/systemd/journald.conf. Se journald.conf(5) for detaljer herom.
-- e9bf28e6e834481bb6f48f548ad13606
diff --git a/catalog/systemd.fr.catalog b/catalog/systemd.fr.catalog
index 03a457786f..d71c2902d7 100644
--- a/catalog/systemd.fr.catalog
+++ b/catalog/systemd.fr.catalog
@@ -51,7 +51,7 @@ Notez que seuls des messages de ce service ont été évincés, les messages des
autres services ne sont pas affectés.
Les limites définissant ce comportement peuvent être configurées avec les
-paramètres RateLimitInterval= et RateLimitBurst= dans le fichier
+paramètres RateLimitIntervalSec= et RateLimitBurst= dans le fichier
/etc/systemd/journald.conf. Voir journald.conf(5) pour plus de détails.
-- e9bf28e6e834481bb6f48f548ad13606
diff --git a/catalog/systemd.hr.catalog b/catalog/systemd.hr.catalog
index 4a6c5ac1fc..350988dd87 100644
--- a/catalog/systemd.hr.catalog
+++ b/catalog/systemd.hr.catalog
@@ -67,7 +67,7 @@ Zapamtite da samo poruke iz usluge u upitu su
odbačene, ostale poruke usluga nisu zahvaćene.
Ograničenja koja kontroliraju kada je poruka odbačena mogu se podesiti
-sa RateLimitInterval= i RateLimitBurst= u
+sa RateLimitIntervalSec= i RateLimitBurst= u
/etc/systemd/journald.conf. Pogledajte journald.conf(5) za više pojedinosti.
-- e9bf28e6e834481bb6f48f548ad13606
diff --git a/catalog/systemd.hu.catalog b/catalog/systemd.hu.catalog
index 30d76916cc..68e8c2572e 100644
--- a/catalog/systemd.hu.catalog
+++ b/catalog/systemd.hu.catalog
@@ -51,7 +51,7 @@ Ne feledje, hogy csak a kérdéses szolgáltatás üzenetei kerültek eldobásra
más szolgáltatások üzeneteit ez nem befolyásolja.
Az üzenetek eldobását vezérlő korlátok az /etc/systemd/journald.conf
-RateLimitInterval= és RateLimitBurst= beállításaival adhatók meg.
+RateLimitIntervalSec= és RateLimitBurst= beállításaival adhatók meg.
Részletekért lásd a journald.conf(5) man oldalt.
-- e9bf28e6e834481bb6f48f548ad13606
diff --git a/catalog/systemd.it.catalog b/catalog/systemd.it.catalog
index 861b92b74a..b6fca48221 100644
--- a/catalog/systemd.it.catalog
+++ b/catalog/systemd.it.catalog
@@ -46,7 +46,7 @@ Solo i messaggi del servizio indicato sono stati
eliminati, i messaggi degli altri servizi rimangono invariati.
I limiti oltre i quali i messaggi si eliminano si configurano
-con RateLimitInterval= e RateLimitBurst= in
+con RateLimitIntervalSec= e RateLimitBurst= in
/etc/systemd/journald.conf. Vedi journald.conf(5) per maggiori informazioni.
-- e9bf28e6e834481bb6f48f548ad13606
diff --git a/catalog/systemd.ko.catalog b/catalog/systemd.ko.catalog
index 3c3535a94c..2fc6b60b1b 100644
--- a/catalog/systemd.ko.catalog
+++ b/catalog/systemd.ko.catalog
@@ -55,7 +55,7 @@ Documentation: man:journald.conf(5)
다른 서비스의 메시지에는 영향을 주지 않습니다.
메시지 거절 제어 제한 값은 /etc/systemd/journald.conf 의
-RateLimitInterval= 변수와 RateLimitBurst= 변수로 설정합니다.
+RateLimitIntervalSec= 변수와 RateLimitBurst= 변수로 설정합니다.
자세한 내용은 ournald.conf(5)를 살펴보십시오.
-- e9bf28e6e834481bb6f48f548ad13606
diff --git a/catalog/systemd.pl.catalog b/catalog/systemd.pl.catalog
index 0d2e3d22cf..d8059e93cd 100644
--- a/catalog/systemd.pl.catalog
+++ b/catalog/systemd.pl.catalog
@@ -69,7 +69,7 @@ Proszę zauważyć, że tylko komunikaty z danej usługi zostały pominięte. Ni
to wpływu na komunikaty innych usług.
Ograniczenia kontrolujące pomijanie komunikatów mogą być konfigurowane
-za pomocą opcji RateLimitInterval= i RateLimitBurst= w pliku
+za pomocą opcji RateLimitIntervalSec= i RateLimitBurst= w pliku
/etc/systemd/journald.conf. Strona journald.conf(5) zawiera więcej informacji.
-- e9bf28e6e834481bb6f48f548ad13606
diff --git a/catalog/systemd.pt_BR.catalog b/catalog/systemd.pt_BR.catalog
index d9716e30f7..8b856e8355 100644
--- a/catalog/systemd.pt_BR.catalog
+++ b/catalog/systemd.pt_BR.catalog
@@ -53,7 +53,7 @@ Note que apenas mensagens de um serviço em questão foram descartadas; outras
mensagens dos serviços não foram afetadas.
Os controles de limites de quando as mensagens são descartadas pode ser
-configurado com RateLimitInterval= e RateLimitBurst= no
+configurado com RateLimitIntervalSec= e RateLimitBurst= no
/etc/systemd/journald.conf. Veja journald.conf(5) para detalhes.
-- e9bf28e6e834481bb6f48f548ad13606
diff --git a/catalog/systemd.ru.catalog b/catalog/systemd.ru.catalog
index eedbb8aa9c..e56dbe3acc 100644
--- a/catalog/systemd.ru.catalog
+++ b/catalog/systemd.ru.catalog
@@ -76,7 +76,7 @@ Documentation: man:journald.conf(5)
сообщения других служб не затронуты.
Предел, после которого служба журнала начинает игнорировать сообщения,
-настраивается параметрами RateLimitInterval= и RateLimitBurst= в файле
+настраивается параметрами RateLimitIntervalSec= и RateLimitBurst= в файле
/etc/systemd/journald.conf. Подробности смотрите на странице руководства
journald.conf(5).
diff --git a/catalog/systemd.sr.catalog b/catalog/systemd.sr.catalog
index cf700c477b..cc689b7956 100644
--- a/catalog/systemd.sr.catalog
+++ b/catalog/systemd.sr.catalog
@@ -52,7 +52,7 @@ Documentation: man:journald.conf(5)
услуге нису захваћене овим.
Ограничења која подешавају начин на који се поруке одбацују се могу подесити
-помоћу „RateLimitInterval=“ и „RateLimitBurst=“ параметара унутар датотеке
+помоћу „RateLimitIntervalSec=“ и „RateLimitBurst=“ параметара унутар датотеке
/etc/systemd/journald.conf. Погледајте journald.conf(5) за појединости.
-- e9bf28e6e834481bb6f48f548ad13606
diff --git a/catalog/systemd.zh_CN.catalog b/catalog/systemd.zh_CN.catalog
index 38639109e4..ed59fc9250 100644
--- a/catalog/systemd.zh_CN.catalog
+++ b/catalog/systemd.zh_CN.catalog
@@ -50,7 +50,7 @@ Documentation: man:journald.conf(5)
请注意只有由有问题的服务传来的消息被丢弃,
其它服务的消息不受影响。
-可以在 /etc/systemd/journald.conf 中设定 RateLimitInterval=
+可以在 /etc/systemd/journald.conf 中设定 RateLimitIntervalSec=
以及 RateLimitBurst = 的值以控制丢弃信息的限制。
请参见 journald.conf(5) 以了解详情。
diff --git a/catalog/systemd.zh_TW.catalog b/catalog/systemd.zh_TW.catalog
index 027ffe44e5..aa5004db08 100644
--- a/catalog/systemd.zh_TW.catalog
+++ b/catalog/systemd.zh_TW.catalog
@@ -53,7 +53,7 @@ Documentation: man:journald.conf(5)
其他服務的訊息則不受影響。
可以在 /etc/systemd/journald.conf 中設定
-RateLimitInterval= 以及 RateLimitBurst=
+RateLimitIntervalSec= 以及 RateLimitBurst=
來控制當訊息要開始被丟棄時的限制。參見 journald.conf(5) 以獲得更多資訊。
-- e9bf28e6e834481bb6f48f548ad13606
diff --git a/configure.ac b/configure.ac
index d4e8ab6664..d6320d2022 100644
--- a/configure.ac
+++ b/configure.ac
@@ -336,7 +336,7 @@ AC_CHECK_DECLS([IFLA_INET6_ADDR_GEN_MODE,
IFLA_BRIDGE_VLAN_INFO,
IFLA_BRPORT_PROXYARP,
IFLA_BRPORT_LEARNING_SYNC,
- IFLA_BR_PRIORITY,
+ IFLA_BR_VLAN_DEFAULT_PVID,
NDA_IFINDEX,
IFA_FLAGS],
[], [], [[
@@ -507,6 +507,14 @@ if test "x$enable_apparmor" != "xno"; then
fi
AM_CONDITIONAL(HAVE_APPARMOR, [test "$have_apparmor" = "yes"])
+have_adm_group=no
+AC_ARG_ENABLE(adm-group, AS_HELP_STRING([--disable-adm-group], [disable adm group]))
+AS_IF([test "x$enable_adm_group" != "xno"], [
+ AC_DEFINE(ENABLE_ADM_GROUP, 1, [Define if the ACL for adm group should be enabled])
+ have_adm_group=yes
+ M4_DEFINES="$M4_DEFINES -DENABLE_ADM_GROUP"
+])
+
have_wheel_group=no
AC_ARG_ENABLE(wheel-group, AS_HELP_STRING([--disable-wheel-group], [disable wheel group]))
AS_IF([test "x$enable_wheel_group" != "xno"], [
@@ -1657,6 +1665,7 @@ AC_MSG_RESULT([
Zsh completions dir: ${with_zshcompletiondir}
Extra start script: ${RC_LOCAL_SCRIPT_PATH_START}
Extra stop script: ${RC_LOCAL_SCRIPT_PATH_STOP}
+ Adm group: ${have_adm_group}
Wheel group: ${have_wheel_group}
Debug shell: ${SUSHELL} @ ${DEBUGTTY}
TTY GID: ${TTY_GID}
diff --git a/hwdb/60-keyboard.hwdb b/hwdb/60-keyboard.hwdb
index 48665ca744..fd49b03493 100644
--- a/hwdb/60-keyboard.hwdb
+++ b/hwdb/60-keyboard.hwdb
@@ -495,6 +495,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP*:pnHP*ProBook*4*:pvr*
# HP ZBook
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHPZBook*:pvr*
KEYBOARD_KEY_81=f20 # Fn+F8; Microphone mute button, should be micmute
+
# HP Folio 1040g2
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHPEliteBookFolio1040G2:pvr*
KEYBOARD_KEY_81=f20 # Fn+F8; Microphone mute button, should be micmute
diff --git a/man/journald.conf.xml b/man/journald.conf.xml
index a9690e8138..3964cd6bc5 100644
--- a/man/journald.conf.xml
+++ b/man/journald.conf.xml
@@ -148,12 +148,12 @@
</varlistentry>
<varlistentry>
- <term><varname>RateLimitInterval=</varname></term>
+ <term><varname>RateLimitIntervalSec=</varname></term>
<term><varname>RateLimitBurst=</varname></term>
<listitem><para>Configures the rate limiting that is applied
to all messages generated on the system. If, in the time
- interval defined by <varname>RateLimitInterval=</varname>,
+ interval defined by <varname>RateLimitIntervalSec=</varname>,
more messages than specified in
<varname>RateLimitBurst=</varname> are logged by a service,
all further messages within the interval are dropped until the
@@ -162,7 +162,7 @@
per-service, so that two services which log do not interfere
with each other's limits. Defaults to 1000 messages in 30s.
The time specification for
- <varname>RateLimitInterval=</varname> may be specified in the
+ <varname>RateLimitIntervalSec=</varname> may be specified in the
following units: <literal>s</literal>, <literal>min</literal>,
<literal>h</literal>, <literal>ms</literal>,
<literal>us</literal>. To turn off any kind of rate limiting,
diff --git a/man/machinectl.xml b/man/machinectl.xml
index 43a3b98840..4b7f9a0391 100644
--- a/man/machinectl.xml
+++ b/man/machinectl.xml
@@ -589,13 +589,11 @@
<varlistentry>
<term><command>clone</command> <replaceable>NAME</replaceable> <replaceable>NAME</replaceable></term>
- <listitem><para>Clones a container or VM image. The
- arguments specify the name of the image to clone and the name
- of the newly cloned image. Note that plain directory container
- images are cloned into subvolume images with this command.
- Note that cloning a container or VM image is optimized for
- btrfs file systems, and might not be efficient on others, due
- to file system limitations.</para>
+ <listitem><para>Clones a container or VM image. The arguments specify the name of the image to clone and the
+ name of the newly cloned image. Note that plain directory container images are cloned into btrfs subvolume
+ images with this command, if the underlying file system supports this. Note that cloning a container or VM
+ image is optimized for btrfs file systems, and might not be efficient on others, due to file system
+ limitations.</para>
<para>Note that this command leaves host name, machine ID and
all other settings that could identify the instance
diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml
index edc6df914a..8833e73c72 100644
--- a/man/systemd-system.conf.xml
+++ b/man/systemd-system.conf.xml
@@ -271,16 +271,16 @@
</varlistentry>
<varlistentry>
- <term><varname>DefaultStartLimitInterval=</varname></term>
+ <term><varname>DefaultStartLimitIntervalSec=</varname></term>
<term><varname>DefaultStartLimitBurst=</varname></term>
<listitem><para>Configure the default unit start rate
limiting, as configured per-service by
- <varname>StartLimitInterval=</varname> and
+ <varname>StartLimitIntervalSec=</varname> and
<varname>StartLimitBurst=</varname>. See
<citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for details on the per-service settings.
- <varname>DefaultStartLimitInterval=</varname> defaults to
+ <varname>DefaultStartLimitIntervalSec=</varname> defaults to
10s. <varname>DefaultStartLimitBurst=</varname> defaults to
5.</para></listitem>
</varlistentry>
diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
index 2d0fb63f1d..2a93760428 100644
--- a/man/systemd.exec.xml
+++ b/man/systemd.exec.xml
@@ -629,27 +629,23 @@
<term><varname>LimitNICE=</varname></term>
<term><varname>LimitRTPRIO=</varname></term>
<term><varname>LimitRTTIME=</varname></term>
- <listitem><para>These settings set both soft and hard limits
- of various resources for executed processes. See
- <citerefentry><refentrytitle>setrlimit</refentrytitle><manvolnum>2</manvolnum></citerefentry>
- for details. The resource limit is possible to specify in two formats,
- <option>value</option> to set soft and hard limits to the same value,
- or <option>soft:hard</option> to set both limits individually (e.g. LimitAS=4G:16G).
- Use the string <varname>infinity</varname> to
- configure no limit on a specific resource. The multiplicative
- suffixes K (=1024), M (=1024*1024) and so on for G, T, P and E
- may be used for resource limits measured in bytes
- (e.g. LimitAS=16G). For the limits referring to time values,
- the usual time units ms, s, min, h and so on may be used (see
- <citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry>
- for details). Note that if no time unit is specified for
- <varname>LimitCPU=</varname> the default unit of seconds is
- implied, while for <varname>LimitRTTIME=</varname> the default
- unit of microseconds is implied. Also, note that the effective
- granularity of the limits might influence their
- enforcement. For example, time limits specified for
- <varname>LimitCPU=</varname> will be rounded up implicitly to
- multiples of 1s.</para>
+ <listitem><para>Set soft and hard limits on various resources for executed processes. See
+ <citerefentry><refentrytitle>setrlimit</refentrytitle><manvolnum>2</manvolnum></citerefentry> for details on
+ the resource limit concept. Resource limits may be specified in two formats: either as single value to set a
+ specific soft and hard limit to the same value, or as colon-separated pair <option>soft:hard</option> to set
+ both limits individually (e.g. <literal>LimitAS=4G:16G</literal>). Use the string <varname>infinity</varname>
+ to configure no limit on a specific resource. The multiplicative suffixes K, M, G, T, P and E (to the base
+ 1024) may be used for resource limits measured in bytes (e.g. LimitAS=16G). For the limits referring to time
+ values, the usual time units ms, s, min, h and so on may be used (see
+ <citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
+ details). Note that if no time unit is specified for <varname>LimitCPU=</varname> the default unit of seconds
+ is implied, while for <varname>LimitRTTIME=</varname> the default unit of microseconds is implied. Also, note
+ that the effective granularity of the limits might influence their enforcement. For example, time limits
+ specified for <varname>LimitCPU=</varname> will be rounded up implicitly to multiples of 1s. For
+ <varname>LimitNICE=</varname> the value may be specified in two syntaxes: if prefixed with <literal>+</literal>
+ or <literal>-</literal>, the value is understood as regular Linux nice value in the range -20..19. If not
+ prefixed like this the value is understood as raw resource limit parameter in the range 0..40 (with 0 being
+ equivalent to 1).</para>
<para>Note that most process resource limits configured with
these options are per-process, and processes may fork in order
diff --git a/man/systemd.socket.xml b/man/systemd.socket.xml
index 2d6339680b..dc3fee5dfb 100644
--- a/man/systemd.socket.xml
+++ b/man/systemd.socket.xml
@@ -807,6 +807,22 @@
suffix.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>TriggerLimitIntervalSec=</varname></term>
+ <term><varname>TriggerLimitIntervalBurst=</varname></term>
+
+ <listitem><para>Configures a limit on how often this socket unit my be activated within a specific time
+ interval. The <varname>TriggerLimitIntervalSec=</varname> may be used to configure the length of the time
+ interval in the usual time units <literal>us</literal>, <literal>ms</literal>, <literal>s</literal>,
+ <literal>min</literal>, <literal>h</literal>, … and defaults to 5s (See
+ <citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry> for details on
+ the various time units available). The <varname>TriggerLimitBurst=</varname> setting takes an integer value and
+ specifies the numer of permitted activations per time interval, and defaults to 2500 (thus by default
+ permitting 2500 activations per 5s). Set either to 0 to disable any form of trigger rate limiting. If the limit
+ is hit, the socket unit is placed into a failure mode, and will not be connectible anymore until
+ restarted. Note that this limit is enforced before the service activation is enqueued.</para></listitem>
+ </varlistentry>
+
</variablelist>
<para>Check
diff --git a/man/systemd.timer.xml b/man/systemd.timer.xml
index eb0afee141..0d0cccf152 100644
--- a/man/systemd.timer.xml
+++ b/man/systemd.timer.xml
@@ -73,6 +73,12 @@
<filename>foo.timer</filename> activates a matching service
<filename>foo.service</filename>. The unit to activate may be
controlled by <varname>Unit=</varname> (see below).</para>
+
+ <para>Note that in case the unit to activate is already active at the time the timer elapses it is not restarted,
+ but simply left running. There is no concept of spawning new service instances in this case. Due to this, services
+ with <varname>RemainAfterExit=</varname> set (which stay around continously even after the service's main process
+ exited) are usually not suitable for activation via repetitive timers, as they will only be activated once, and
+ then stay around forever.</para>
</refsect1>
<refsect1>
diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml
index 69f56e3f0a..abd47bd237 100644
--- a/man/systemd.unit.xml
+++ b/man/systemd.unit.xml
@@ -751,14 +751,14 @@
</varlistentry>
<varlistentry>
- <term><varname>StartLimitInterval=</varname></term>
+ <term><varname>StartLimitIntervalSec=</varname></term>
<term><varname>StartLimitBurst=</varname></term>
<listitem><para>Configure unit start rate limiting. By default, units which are started more than 5 times
within 10 seconds are not permitted to start any more times until the 10 second interval ends. With these two
- options, this rate limiting may be modified. Use <varname>StartLimitInterval=</varname> to configure the
- checking interval (defaults to <varname>DefaultStartLimitInterval=</varname> in manager configuration file, set
- to 0 to disable any kind of rate limiting). Use <varname>StartLimitBurst=</varname> to configure how many
+ options, this rate limiting may be modified. Use <varname>StartLimitIntervalSec=</varname> to configure the
+ checking interval (defaults to <varname>DefaultStartLimitIntervalSec=</varname> in manager configuration file,
+ set to 0 to disable any kind of rate limiting). Use <varname>StartLimitBurst=</varname> to configure how many
starts per interval are allowed (defaults to <varname>DefaultStartLimitBurst=</varname> in manager
configuration file). These configuration options are particularly useful in conjunction with the service
setting <varname>Restart=</varname> (see
@@ -769,14 +769,15 @@
manually at a later point, from which point on, the restart logic is again activated. Note that
<command>systemctl reset-failed</command> will cause the restart rate counter for a service to be flushed,
which is useful if the administrator wants to manually start a unit and the start limit interferes with
- that.</para></listitem>
+ that. Note that this rate-limiting is enforced after any unit condition checks are executed, and hence unit
+ activations with failing conditions are not counted by this rate limiting.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>StartLimitAction=</varname></term>
<listitem><para>Configure the action to take if the rate limit configured with
- <varname>StartLimitInterval=</varname> and <varname>StartLimitBurst=</varname> is hit. Takes one of
+ <varname>StartLimitIntervalSec=</varname> and <varname>StartLimitBurst=</varname> is hit. Takes one of
<option>none</option>, <option>reboot</option>, <option>reboot-force</option>,
<option>reboot-immediate</option>, <option>poweroff</option>, <option>poweroff-force</option> or
<option>poweroff-immediate</option>. If <option>none</option> is set, hitting the rate limit will trigger no
diff --git a/src/basic/architecture.c b/src/basic/architecture.c
index a9ecfc1cd6..8e2c2b02d2 100644
--- a/src/basic/architecture.c
+++ b/src/basic/architecture.c
@@ -121,6 +121,8 @@ int uname_architecture(void) {
{ "tilegx", ARCHITECTURE_TILEGX },
#elif defined(__cris__)
{ "crisv32", ARCHITECTURE_CRIS },
+#elif defined(__nios2__)
+ { "nios2", ARCHITECTURE_NIOS2 },
#else
#error "Please register your architecture here!"
#endif
@@ -171,6 +173,7 @@ static const char *const architecture_table[_ARCHITECTURE_MAX] = {
[ARCHITECTURE_M68K] = "m68k",
[ARCHITECTURE_TILEGX] = "tilegx",
[ARCHITECTURE_CRIS] = "cris",
+ [ARCHITECTURE_NIOS2] = "nios2",
};
DEFINE_STRING_TABLE_LOOKUP(architecture, int);
diff --git a/src/basic/architecture.h b/src/basic/architecture.h
index c22cbc8279..91ec108e04 100644
--- a/src/basic/architecture.h
+++ b/src/basic/architecture.h
@@ -57,6 +57,7 @@ enum {
ARCHITECTURE_M68K,
ARCHITECTURE_TILEGX,
ARCHITECTURE_CRIS,
+ ARCHITECTURE_NIOS2,
_ARCHITECTURE_MAX,
_ARCHITECTURE_INVALID = -1
};
@@ -187,6 +188,9 @@ int uname_architecture(void);
#elif defined(__cris__)
# define native_architecture() ARCHITECTURE_CRIS
# error "Missing LIB_ARCH_TUPLE for CRIS"
+#elif defined(__nios2__)
+# define native_architecture() ARCHITECTURE_NIOS2
+# define LIB_ARCH_TUPLE "nios2-linux-gnu"
#else
# error "Please register your architecture here!"
#endif
diff --git a/src/basic/copy.c b/src/basic/copy.c
index 03487a6878..c3586728d0 100644
--- a/src/basic/copy.c
+++ b/src/basic/copy.c
@@ -305,6 +305,8 @@ static int fd_copy_directory(
fdf = openat(df, from, O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
else
fdf = fcntl(df, F_DUPFD_CLOEXEC, 3);
+ if (fdf < 0)
+ return -errno;
d = fdopendir(fdf);
if (!d)
@@ -325,22 +327,6 @@ static int fd_copy_directory(
r = 0;
- if (created) {
- struct timespec ut[2] = {
- st->st_atim,
- st->st_mtim
- };
-
- if (fchown(fdt, st->st_uid, st->st_gid) < 0)
- r = -errno;
-
- if (fchmod(fdt, st->st_mode & 07777) < 0)
- r = -errno;
-
- (void) futimens(fdt, ut);
- (void) copy_xattr(dirfd(d), fdt);
- }
-
FOREACH_DIRENT_ALL(de, d, return -errno) {
struct stat buf;
int q;
@@ -364,7 +350,7 @@ static int fd_copy_directory(
q = fd_copy_symlink(dirfd(d), de->d_name, &buf, fdt, de->d_name);
else if (S_ISFIFO(buf.st_mode))
q = fd_copy_fifo(dirfd(d), de->d_name, &buf, fdt, de->d_name);
- else if (S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode))
+ else if (S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode) || S_ISSOCK(buf.st_mode))
q = fd_copy_node(dirfd(d), de->d_name, &buf, fdt, de->d_name);
else
q = -EOPNOTSUPP;
@@ -376,6 +362,22 @@ static int fd_copy_directory(
r = q;
}
+ if (created) {
+ struct timespec ut[2] = {
+ st->st_atim,
+ st->st_mtim
+ };
+
+ if (fchown(fdt, st->st_uid, st->st_gid) < 0)
+ r = -errno;
+
+ if (fchmod(fdt, st->st_mode & 07777) < 0)
+ r = -errno;
+
+ (void) copy_xattr(dirfd(d), fdt);
+ (void) futimens(fdt, ut);
+ }
+
return r;
}
@@ -396,7 +398,7 @@ int copy_tree_at(int fdf, const char *from, int fdt, const char *to, bool merge)
return fd_copy_symlink(fdf, from, &st, fdt, to);
else if (S_ISFIFO(st.st_mode))
return fd_copy_fifo(fdf, from, &st, fdt, to);
- else if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode))
+ else if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode) || S_ISSOCK(st.st_mode))
return fd_copy_node(fdf, from, &st, fdt, to);
else
return -EOPNOTSUPP;
@@ -407,7 +409,6 @@ int copy_tree(const char *from, const char *to, bool merge) {
}
int copy_directory_fd(int dirfd, const char *to, bool merge) {
-
struct stat st;
assert(dirfd >= 0);
@@ -422,6 +423,21 @@ int copy_directory_fd(int dirfd, const char *to, bool merge) {
return fd_copy_directory(dirfd, NULL, &st, AT_FDCWD, to, st.st_dev, merge);
}
+int copy_directory(const char *from, const char *to, bool merge) {
+ struct stat st;
+
+ assert(from);
+ assert(to);
+
+ if (lstat(from, &st) < 0)
+ return -errno;
+
+ if (!S_ISDIR(st.st_mode))
+ return -ENOTDIR;
+
+ return fd_copy_directory(AT_FDCWD, from, &st, AT_FDCWD, to, st.st_dev, merge);
+}
+
int copy_file_fd(const char *from, int fdt, bool try_reflink) {
_cleanup_close_ int fdf = -1;
int r;
diff --git a/src/basic/copy.h b/src/basic/copy.h
index 3e5eb52506..b5d08ebafe 100644
--- a/src/basic/copy.h
+++ b/src/basic/copy.h
@@ -30,6 +30,7 @@ int copy_file_atomic(const char *from, const char *to, mode_t mode, bool replace
int copy_tree(const char *from, const char *to, bool merge);
int copy_tree_at(int fdf, const char *from, int fdt, const char *to, bool merge);
int copy_directory_fd(int dirfd, const char *to, bool merge);
+int copy_directory(const char *from, const char *to, bool merge);
int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink);
int copy_times(int fdf, int fdt);
int copy_xattr(int fdf, int fdt);
diff --git a/src/basic/missing.h b/src/basic/missing.h
index b389e94cf7..22ea8f67cc 100644
--- a/src/basic/missing.h
+++ b/src/basic/missing.h
@@ -557,7 +557,7 @@ struct btrfs_ioctl_quota_ctl_args {
#define IFLA_INET6_ADDR_GEN_MODE 8
#define __IFLA_INET6_MAX 9
-#define IFLA_INET6_MAX (__IFLA_INET6_MAX - 1)
+#define IFLA_INET6_MAX (__IFLA_INET6_MAX - 1)
#define IN6_ADDR_GEN_MODE_EUI64 0
#define IN6_ADDR_GEN_MODE_NONE 1
@@ -742,7 +742,7 @@ struct btrfs_ioctl_quota_ctl_args {
#define IFLA_BRIDGE_MAX (__IFLA_BRIDGE_MAX - 1)
#endif
-#if !HAVE_DECL_IFLA_BR_PRIORITY
+#if !HAVE_DECL_IFLA_BR_VLAN_DEFAULT_PVID
#define IFLA_BR_UNSPEC 0
#define IFLA_BR_FORWARD_DELAY 1
#define IFLA_BR_HELLO_TIME 2
diff --git a/src/basic/path-util.c b/src/basic/path-util.c
index 100e3f5af2..b2fa81a294 100644
--- a/src/basic/path-util.c
+++ b/src/basic/path-util.c
@@ -772,6 +772,19 @@ bool hidden_or_backup_file(const char *filename) {
if (!p)
return false;
+ /* Please, let's not add more entries to the list below. If external projects think it's a good idea to come up
+ * with always new suffixes and that everybody else should just adjust to that, then it really should be on
+ * them. Hence, in future, let's not add any more entries. Instead, let's ask those packages to instead adopt
+ * one of the generic suffixes/prefixes for hidden files or backups, possibly augmented with an additional
+ * string. Specifically: there's now:
+ *
+ * The generic suffixes "~" and ".bak" for backup files
+ * The generic prefix "." for hidden files
+ *
+ * Thus, if a new package manager "foopkg" wants its own set of ".foopkg-new", ".foopkg-old", ".foopkg-dist"
+ * or so registered, let's refuse that and ask them to use ".foopkg.new", ".foopkg.old" or ".foopkg~" instead.
+ */
+
return STR_IN_SET(p + 1,
"rpmnew",
"rpmsave",
@@ -786,7 +799,10 @@ bool hidden_or_backup_file(const char *filename) {
"ucf-new",
"ucf-old",
"ucf-dist",
- "swp");
+ "swp",
+ "bak",
+ "old",
+ "new");
}
bool is_device_path(const char *path) {
diff --git a/src/basic/process-util.c b/src/basic/process-util.c
index f2cea01979..4a7367cc92 100644
--- a/src/basic/process-util.c
+++ b/src/basic/process-util.c
@@ -528,14 +528,20 @@ int wait_for_terminate_and_warn(const char *name, pid_t pid, bool check_exit_cod
return -EPROTO;
}
-void sigkill_wait(pid_t *pid) {
+void sigkill_wait(pid_t pid) {
+ assert(pid > 1);
+
+ if (kill(pid, SIGKILL) > 0)
+ (void) wait_for_terminate(pid, NULL);
+}
+
+void sigkill_waitp(pid_t *pid) {
if (!pid)
return;
if (*pid <= 1)
return;
- if (kill(*pid, SIGKILL) > 0)
- (void) wait_for_terminate(*pid, NULL);
+ sigkill_wait(*pid);
}
int kill_and_sigcont(pid_t pid, int sig) {
diff --git a/src/basic/process-util.h b/src/basic/process-util.h
index ffd4bcb0ff..9f75088796 100644
--- a/src/basic/process-util.h
+++ b/src/basic/process-util.h
@@ -58,8 +58,8 @@ int get_process_ppid(pid_t pid, pid_t *ppid);
int wait_for_terminate(pid_t pid, siginfo_t *status);
int wait_for_terminate_and_warn(const char *name, pid_t pid, bool check_exit_code);
-void sigkill_wait(pid_t *pid);
-#define _cleanup_sigkill_wait_ _cleanup_(sigkill_wait)
+void sigkill_wait(pid_t pid);
+void sigkill_waitp(pid_t *pid);
int kill_and_sigcont(pid_t pid, int sig);
diff --git a/src/basic/rlimit-util.c b/src/basic/rlimit-util.c
index 7540b43215..ee063720ed 100644
--- a/src/basic/rlimit-util.c
+++ b/src/basic/rlimit-util.c
@@ -153,6 +153,56 @@ static int rlimit_parse_usec(const char *val, rlim_t *ret) {
return 0;
}
+static int rlimit_parse_nice(const char *val, rlim_t *ret) {
+ uint64_t rl;
+ int r;
+
+ /* So, Linux is weird. The range for RLIMIT_NICE is 40..1, mapping to the nice levels -20..19. However, the
+ * RLIMIT_NICE limit defaults to 0 by the kernel, i.e. a value that maps to nice level 20, which of course is
+ * bogus and does not exist. In order to permit parsing the RLIMIT_NICE of 0 here we hence implement a slight
+ * asymmetry: when parsing as positive nice level we permit 0..19. When parsing as negative nice level, we
+ * permit -20..0. But when parsing as raw resource limit value then we also allow the special value 0.
+ *
+ * Yeah, Linux is quality engineering sometimes... */
+
+ if (val[0] == '+') {
+
+ /* Prefixed with "+": Parse as positive user-friendly nice value */
+ r = safe_atou64(val + 1, &rl);
+ if (r < 0)
+ return r;
+
+ if (rl >= PRIO_MAX)
+ return -ERANGE;
+
+ rl = 20 - rl;
+
+ } else if (val[0] == '-') {
+
+ /* Prefixed with "-": Parse as negative user-friendly nice value */
+ r = safe_atou64(val + 1, &rl);
+ if (r < 0)
+ return r;
+
+ if (rl > (uint64_t) (-PRIO_MIN))
+ return -ERANGE;
+
+ rl = 20 + rl;
+ } else {
+
+ /* Not prefixed: parse as raw resource limit value */
+ r = safe_atou64(val, &rl);
+ if (r < 0)
+ return r;
+
+ if (rl > (uint64_t) (20 - PRIO_MIN))
+ return -ERANGE;
+ }
+
+ *ret = (rlim_t) rl;
+ return 0;
+}
+
static int (*const rlimit_parse_table[_RLIMIT_MAX])(const char *val, rlim_t *ret) = {
[RLIMIT_CPU] = rlimit_parse_sec,
[RLIMIT_FSIZE] = rlimit_parse_size,
@@ -167,7 +217,7 @@ static int (*const rlimit_parse_table[_RLIMIT_MAX])(const char *val, rlim_t *ret
[RLIMIT_LOCKS] = rlimit_parse_u64,
[RLIMIT_SIGPENDING] = rlimit_parse_u64,
[RLIMIT_MSGQUEUE] = rlimit_parse_size,
- [RLIMIT_NICE] = rlimit_parse_u64,
+ [RLIMIT_NICE] = rlimit_parse_nice,
[RLIMIT_RTPRIO] = rlimit_parse_u64,
[RLIMIT_RTTIME] = rlimit_parse_usec,
};
diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
index 73c50766d1..d45f511489 100644
--- a/src/core/dbus-manager.c
+++ b/src/core/dbus-manager.c
@@ -2050,7 +2050,8 @@ const sd_bus_vtable bus_manager_vtable[] = {
SD_BUS_PROPERTY("DefaultTimeoutStartUSec", "t", bus_property_get_usec, offsetof(Manager, default_timeout_start_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultTimeoutStopUSec", "t", bus_property_get_usec, offsetof(Manager, default_timeout_stop_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultRestartUSec", "t", bus_property_get_usec, offsetof(Manager, default_restart_usec), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DefaultStartLimitInterval", "t", bus_property_get_usec, offsetof(Manager, default_start_limit_interval), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultStartLimitIntervalSec", "t", bus_property_get_usec, offsetof(Manager, default_start_limit_interval), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultStartLimitInterval", "t", bus_property_get_usec, offsetof(Manager, default_start_limit_interval), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), /* obsolete alias name */
SD_BUS_PROPERTY("DefaultStartLimitBurst", "u", bus_property_get_unsigned, offsetof(Manager, default_start_limit_burst), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultCPUAccounting", "b", bus_property_get_bool, offsetof(Manager, default_cpu_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultBlockIOAccounting", "b", bus_property_get_bool, offsetof(Manager, default_blockio_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c
index d33e494f6b..bb09a515f8 100644
--- a/src/core/dbus-socket.c
+++ b/src/core/dbus-socket.c
@@ -149,6 +149,8 @@ const sd_bus_vtable bus_socket_vtable[] = {
SD_BUS_PROPERTY("NAccepted", "u", bus_property_get_unsigned, offsetof(Socket, n_accepted), 0),
SD_BUS_PROPERTY("FileDescriptorName", "s", property_get_fdname, 0, 0),
SD_BUS_PROPERTY("SocketProtocol", "i", bus_property_get_int, offsetof(Socket, socket_protocol), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("TriggerLimitIntervalSec", "t", bus_property_get_usec, offsetof(Socket, trigger_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("TriggerLimitBurst", "u", bus_property_get_unsigned, offsetof(Socket, trigger_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST),
BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPre", offsetof(Socket, exec_command[SOCKET_EXEC_START_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPost", offsetof(Socket, exec_command[SOCKET_EXEC_START_POST]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
BUS_EXEC_COMMAND_LIST_VTABLE("ExecStopPre", offsetof(Socket, exec_command[SOCKET_EXEC_STOP_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c
index abe30413c3..e912fe2192 100644
--- a/src/core/dbus-unit.c
+++ b/src/core/dbus-unit.c
@@ -704,7 +704,8 @@ const sd_bus_vtable bus_unit_vtable[] = {
SD_BUS_PROPERTY("Asserts", "a(sbbsi)", property_get_conditions, offsetof(Unit, asserts), 0),
SD_BUS_PROPERTY("LoadError", "(ss)", property_get_load_error, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Transient", "b", bus_property_get_bool, offsetof(Unit, transient), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("StartLimitInterval", "t", bus_property_get_usec, offsetof(Unit, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("StartLimitIntervalSec", "t", bus_property_get_usec, offsetof(Unit, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("StartLimitInterval", "t", bus_property_get_usec, offsetof(Unit, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), /* obsolete alias name */
SD_BUS_PROPERTY("StartLimitBurst", "u", bus_property_get_unsigned, offsetof(Unit, start_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("StartLimitAction", "s", property_get_failure_action, offsetof(Unit, start_limit_action), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RebootArgument", "s", NULL, offsetof(Unit, reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST),
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index 5568b4696f..928b913c7b 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -164,6 +164,8 @@ Unit.IgnoreOnSnapshot, config_parse_warn_compat, DISABLED_LE
Unit.JobTimeoutSec, config_parse_sec_fix_0, 0, offsetof(Unit, job_timeout)
Unit.JobTimeoutAction, config_parse_failure_action, 0, offsetof(Unit, job_timeout_action)
Unit.JobTimeoutRebootArgument, config_parse_string, 0, offsetof(Unit, job_timeout_reboot_arg)
+Unit.StartLimitIntervalSec, config_parse_sec, 0, offsetof(Unit, start_limit.interval)
+m4_dnl The following is a legacy alias name for compatibility
Unit.StartLimitInterval, config_parse_sec, 0, offsetof(Unit, start_limit.interval)
Unit.StartLimitBurst, config_parse_unsigned, 0, offsetof(Unit, start_limit.burst)
Unit.StartLimitAction, config_parse_failure_action, 0, offsetof(Unit, start_limit_action)
@@ -220,6 +222,7 @@ Service.TimeoutStartSec, config_parse_service_timeout, 0,
Service.TimeoutStopSec, config_parse_service_timeout, 0, 0
Service.RuntimeMaxSec, config_parse_sec, 0, offsetof(Service, runtime_max_usec)
Service.WatchdogSec, config_parse_sec, 0, offsetof(Service, watchdog_usec)
+m4_dnl The following three only exist for compatibility, they moved into Unit, see above
Service.StartLimitInterval, config_parse_sec, 0, offsetof(Unit, start_limit.interval)
Service.StartLimitBurst, config_parse_unsigned, 0, offsetof(Unit, start_limit.burst)
Service.StartLimitAction, config_parse_failure_action, 0, offsetof(Unit, start_limit_action)
@@ -297,6 +300,8 @@ Socket.RemoveOnStop, config_parse_bool, 0,
Socket.Symlinks, config_parse_unit_path_strv_printf, 0, offsetof(Socket, symlinks)
Socket.FileDescriptorName, config_parse_fdname, 0, 0
Socket.Service, config_parse_socket_service, 0, 0
+Socket.TriggerLimitIntervalSec, config_parse_sec, 0, offsetof(Socket, trigger_limit.interval)
+Socket.TriggerLimitBurst, config_parse_unsigned, 0, offsetof(Socket, trigger_limit.burst)
m4_ifdef(`HAVE_SMACK',
`Socket.SmackLabel, config_parse_string, 0, offsetof(Socket, smack)
Socket.SmackLabelIPIn, config_parse_string, 0, offsetof(Socket, smack_ip_in)
diff --git a/src/core/main.c b/src/core/main.c
index 75c5ff81f2..ed4d42c8cc 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -289,6 +289,7 @@ static int parse_crash_chvt(const char *value) {
}
static int set_machine_id(const char *m) {
+ assert(m);
if (sd_id128_from_string(m, &arg_machine_id) < 0)
return -EINVAL;
@@ -669,7 +670,8 @@ static int parse_config_file(void) {
{ "Manager", "DefaultTimeoutStartSec", config_parse_sec, 0, &arg_default_timeout_start_usec },
{ "Manager", "DefaultTimeoutStopSec", config_parse_sec, 0, &arg_default_timeout_stop_usec },
{ "Manager", "DefaultRestartSec", config_parse_sec, 0, &arg_default_restart_usec },
- { "Manager", "DefaultStartLimitInterval", config_parse_sec, 0, &arg_default_start_limit_interval },
+ { "Manager", "DefaultStartLimitInterval", config_parse_sec, 0, &arg_default_start_limit_interval }, /* obsolete alias */
+ { "Manager", "DefaultStartLimitIntervalSec",config_parse_sec, 0, &arg_default_start_limit_interval },
{ "Manager", "DefaultStartLimitBurst", config_parse_unsigned, 0, &arg_default_start_limit_burst },
{ "Manager", "DefaultEnvironment", config_parse_environ, 0, &arg_default_environment },
{ "Manager", "DefaultLimitCPU", config_parse_limit, RLIMIT_CPU, arg_default_rlimit },
diff --git a/src/core/service.c b/src/core/service.c
index b46dd8bcdd..f7a3fcf2b9 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -180,20 +180,17 @@ static int service_set_main_pid(Service *s, pid_t pid) {
return 0;
}
-static void service_close_socket_fd(Service *s) {
+void service_close_socket_fd(Service *s) {
assert(s);
- s->socket_fd = asynchronous_close(s->socket_fd);
-}
-
-static void service_connection_unref(Service *s) {
- assert(s);
+ /* Undo the effect of service_set_socket_fd(). */
- if (!UNIT_ISSET(s->accept_socket))
- return;
+ s->socket_fd = asynchronous_close(s->socket_fd);
- socket_connection_unref(SOCKET(UNIT_DEREF(s->accept_socket)));
- unit_ref_unset(&s->accept_socket);
+ if (UNIT_ISSET(s->accept_socket)) {
+ socket_connection_unref(SOCKET(UNIT_DEREF(s->accept_socket)));
+ unit_ref_unset(&s->accept_socket);
+ }
}
static void service_stop_watchdog(Service *s) {
@@ -321,7 +318,6 @@ static void service_done(Unit *u) {
s->bus_name_owner = mfree(s->bus_name_owner);
service_close_socket_fd(s);
- service_connection_unref(s);
unit_ref_unset(&s->accept_socket);
@@ -910,10 +906,8 @@ static void service_set_state(Service *s, ServiceState state) {
SERVICE_RUNNING, SERVICE_RELOAD,
SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL) &&
- !(state == SERVICE_DEAD && UNIT(s)->job)) {
+ !(state == SERVICE_DEAD && UNIT(s)->job))
service_close_socket_fd(s);
- service_connection_unref(s);
- }
if (!IN_SET(state, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD))
service_stop_watchdog(s);
@@ -3139,9 +3133,8 @@ int service_set_socket_fd(Service *s, int fd, Socket *sock, bool selinux_context
assert(s);
assert(fd >= 0);
- /* This is called by the socket code when instantiating a new
- * service for a stream socket and the socket needs to be
- * configured. */
+ /* This is called by the socket code when instantiating a new service for a stream socket and the socket needs
+ * to be configured. We take ownership of the passed fd on success. */
if (UNIT(s)->load_state != UNIT_LOADED)
return -EINVAL;
@@ -3169,12 +3162,15 @@ int service_set_socket_fd(Service *s, int fd, Socket *sock, bool selinux_context
return r;
}
+ r = unit_add_two_dependencies(UNIT(sock), UNIT_BEFORE, UNIT_TRIGGERS, UNIT(s), false);
+ if (r < 0)
+ return r;
+
s->socket_fd = fd;
s->socket_fd_selinux_context_net = selinux_context_net;
unit_ref_set(&s->accept_socket, UNIT(sock));
-
- return unit_add_two_dependencies(UNIT(sock), UNIT_BEFORE, UNIT_TRIGGERS, UNIT(s), false);
+ return 0;
}
static void service_reset_failed(Unit *u) {
diff --git a/src/core/service.h b/src/core/service.h
index cd9e41646e..c7f1e81bdb 100644
--- a/src/core/service.h
+++ b/src/core/service.h
@@ -198,6 +198,7 @@ struct Service {
extern const UnitVTable service_vtable;
int service_set_socket_fd(Service *s, int fd, struct Socket *socket, bool selinux_context_net);
+void service_close_socket_fd(Service *s);
const char* service_restart_to_string(ServiceRestart i) _const_;
ServiceRestart service_restart_from_string(const char *s) _pure_;
diff --git a/src/core/socket.c b/src/core/socket.c
index a9fff9c259..7eeed068bd 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -99,6 +99,8 @@ static void socket_init(Unit *u) {
s->exec_context.std_error = u->manager->default_std_error;
s->control_command_id = _SOCKET_EXEC_COMMAND_INVALID;
+
+ RATELIMIT_INIT(s->trigger_limit, 5*USEC_PER_SEC, 2500);
}
static void socket_unwatch_control_pid(Socket *s) {
@@ -227,7 +229,6 @@ int socket_instantiate_service(Socket *s) {
if (r < 0)
return r;
- u->no_gc = true;
unit_ref_set(&s->service, u);
return unit_add_two_dependencies(UNIT(s), UNIT_BEFORE, UNIT_TRIGGERS, u, false);
@@ -792,47 +793,45 @@ static void socket_close_fds(Socket *s) {
assert(s);
LIST_FOREACH(port, p, s->ports) {
+ bool was_open;
- p->event_source = sd_event_source_unref(p->event_source);
-
- if (p->fd < 0)
- continue;
+ was_open = p->fd >= 0;
+ p->event_source = sd_event_source_unref(p->event_source);
p->fd = safe_close(p->fd);
socket_cleanup_fd_list(p);
- /* One little note: we should normally not delete any
- * sockets in the file system here! After all some
- * other process we spawned might still have a
- * reference of this fd and wants to continue to use
- * it. Therefore we delete sockets in the file system
- * before we create a new one, not after we stopped
- * using one! */
+ /* One little note: we should normally not delete any sockets in the file system here! After all some
+ * other process we spawned might still have a reference of this fd and wants to continue to use
+ * it. Therefore we normally delete sockets in the file system before we create a new one, not after we
+ * stopped using one! That all said, if the user explicitly requested this, we'll delete them here
+ * anyway, but only then. */
- if (s->remove_on_stop) {
- switch (p->type) {
+ if (!was_open || !s->remove_on_stop)
+ continue;
- case SOCKET_FIFO:
- unlink(p->path);
- break;
+ switch (p->type) {
- case SOCKET_MQUEUE:
- mq_unlink(p->path);
- break;
+ case SOCKET_FIFO:
+ (void) unlink(p->path);
+ break;
- case SOCKET_SOCKET:
- socket_address_unlink(&p->address);
- break;
+ case SOCKET_MQUEUE:
+ (void) mq_unlink(p->path);
+ break;
- default:
- break;
- }
+ case SOCKET_SOCKET:
+ (void) socket_address_unlink(&p->address);
+ break;
+
+ default:
+ break;
}
}
if (s->remove_on_stop)
STRV_FOREACH(i, s->symlinks)
- unlink(*i);
+ (void) unlink(*i);
}
static void socket_apply_socket_options(Socket *s, int fd) {
@@ -1887,6 +1886,9 @@ static void socket_enter_running(Socket *s, int cfd) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
+ /* Note that this call takes possession of the connection fd passed. It either has to assign it somewhere or
+ * close it. */
+
assert(s);
/* We don't take connections anymore if we are supposed to
@@ -1896,7 +1898,7 @@ static void socket_enter_running(Socket *s, int cfd) {
log_unit_debug(UNIT(s), "Suppressing connection request since unit stop is scheduled.");
if (cfd >= 0)
- safe_close(cfd);
+ cfd = safe_close(cfd);
else {
/* Flush all sockets by closing and reopening them */
socket_close_fds(s);
@@ -1918,6 +1920,13 @@ static void socket_enter_running(Socket *s, int cfd) {
return;
}
+ if (!ratelimit_test(&s->trigger_limit)) {
+ safe_close(cfd);
+ log_unit_warning(UNIT(s), "Trigger limit hit, refusing further activation.");
+ socket_enter_stop_pre(s, SOCKET_FAILURE_TRIGGER_LIMIT_HIT);
+ return;
+ }
+
if (cfd < 0) {
Iterator i;
Unit *other;
@@ -1949,7 +1958,7 @@ static void socket_enter_running(Socket *s, int cfd) {
Service *service;
if (s->n_connections >= s->max_connections) {
- log_unit_warning(UNIT(s), "Too many incoming connections (%u)", s->n_connections);
+ log_unit_warning(UNIT(s), "Too many incoming connections (%u), refusing connection attempt.", s->n_connections);
safe_close(cfd);
return;
}
@@ -1965,6 +1974,7 @@ static void socket_enter_running(Socket *s, int cfd) {
/* ENOTCONN is legitimate if TCP RST was received.
* This connection is over, but the socket unit lives on. */
+ log_unit_debug(UNIT(s), "Got ENOTCONN on incoming socket, assuming aborted connection attempt, ignoring.");
safe_close(cfd);
return;
}
@@ -1983,22 +1993,24 @@ static void socket_enter_running(Socket *s, int cfd) {
service = SERVICE(UNIT_DEREF(s->service));
unit_ref_unset(&s->service);
- s->n_accepted++;
-
- UNIT(service)->no_gc = false;
+ s->n_accepted++;
unit_choose_id(UNIT(service), name);
r = service_set_socket_fd(service, cfd, s, s->selinux_context_from_net);
if (r < 0)
goto fail;
- cfd = -1;
+ cfd = -1; /* We passed ownership of the fd to the service now. Forget it here. */
s->n_connections++;
r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT(service), JOB_REPLACE, &error, NULL);
- if (r < 0)
+ if (r < 0) {
+ /* We failed to activate the new service, but it still exists. Let's make sure the service
+ * closes and forgets the connection fd again, immediately. */
+ service_close_socket_fd(service);
goto fail;
+ }
/* Notify clients about changed counters */
unit_add_to_dbus_queue(UNIT(s));
@@ -2806,6 +2818,7 @@ static const char* const socket_result_table[_SOCKET_RESULT_MAX] = {
[SOCKET_FAILURE_EXIT_CODE] = "exit-code",
[SOCKET_FAILURE_SIGNAL] = "signal",
[SOCKET_FAILURE_CORE_DUMP] = "core-dump",
+ [SOCKET_FAILURE_TRIGGER_LIMIT_HIT] = "trigger-limit-hit",
[SOCKET_FAILURE_SERVICE_START_LIMIT_HIT] = "service-start-limit-hit"
};
diff --git a/src/core/socket.h b/src/core/socket.h
index b537b026a7..2a4b1bb674 100644
--- a/src/core/socket.h
+++ b/src/core/socket.h
@@ -52,6 +52,7 @@ typedef enum SocketResult {
SOCKET_FAILURE_EXIT_CODE,
SOCKET_FAILURE_SIGNAL,
SOCKET_FAILURE_CORE_DUMP,
+ SOCKET_FAILURE_TRIGGER_LIMIT_HIT,
SOCKET_FAILURE_SERVICE_START_LIMIT_HIT,
_SOCKET_RESULT_MAX,
_SOCKET_RESULT_INVALID = -1
@@ -156,6 +157,8 @@ struct Socket {
bool reset_cpu_usage:1;
char *fdname;
+
+ RateLimit trigger_limit;
};
/* Called from the service code when collecting fds */
diff --git a/src/core/system.conf b/src/core/system.conf
index e2ded27333..eacd7ee282 100644
--- a/src/core/system.conf
+++ b/src/core/system.conf
@@ -34,7 +34,7 @@
#DefaultTimeoutStartSec=90s
#DefaultTimeoutStopSec=90s
#DefaultRestartSec=100ms
-#DefaultStartLimitInterval=10s
+#DefaultStartLimitIntervalSec=10s
#DefaultStartLimitBurst=5
#DefaultEnvironment=
#DefaultCPUAccounting=no
diff --git a/src/core/unit.c b/src/core/unit.c
index a2726f10a6..4ace6b075b 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -1500,11 +1500,6 @@ int unit_start(Unit *u) {
if (UNIT_IS_ACTIVE_OR_RELOADING(state))
return -EALREADY;
- /* Make sure we don't enter a busy loop of some kind. */
- r = unit_start_limit_test(u);
- if (r < 0)
- return r;
-
/* Units that aren't loaded cannot be started */
if (u->load_state != UNIT_LOADED)
return -EINVAL;
@@ -1546,6 +1541,11 @@ int unit_start(Unit *u) {
if (!UNIT_VTABLE(u)->start)
return -EBADR;
+ /* Make sure we don't enter a busy loop of some kind. */
+ r = unit_start_limit_test(u);
+ if (r < 0)
+ return r;
+
/* We don't suppress calls to ->start() here when we are
* already starting, to allow this request to be used as a
* "hurry up" call, for example when the unit is in some "auto
@@ -3225,6 +3225,10 @@ void unit_ref_unset(UnitRef *ref) {
if (!ref->unit)
return;
+ /* We are about to drop a reference to the unit, make sure the garbage collection has a look at it as it might
+ * be unreferenced now. */
+ unit_add_to_gc_queue(ref->unit);
+
LIST_REMOVE(refs, ref->unit->refs, ref);
ref->unit = NULL;
}
diff --git a/src/core/user.conf b/src/core/user.conf
index 87c8164378..b427f1ef6d 100644
--- a/src/core/user.conf
+++ b/src/core/user.conf
@@ -23,7 +23,7 @@
#DefaultTimeoutStartSec=90s
#DefaultTimeoutStopSec=90s
#DefaultRestartSec=100ms
-#DefaultStartLimitInterval=10s
+#DefaultStartLimitIntervalSec=10s
#DefaultStartLimitBurst=5
#DefaultEnvironment=
#DefaultLimitCPU=
diff --git a/src/import/pull-common.c b/src/import/pull-common.c
index d301d4d79e..dc4e4667a9 100644
--- a/src/import/pull-common.c
+++ b/src/import/pull-common.c
@@ -330,7 +330,7 @@ int pull_verify(PullJob *main_job,
_cleanup_close_ int sig_file = -1;
const char *p, *line;
char sig_file_path[] = "/tmp/sigXXXXXX", gpg_home[] = "/tmp/gpghomeXXXXXX";
- _cleanup_sigkill_wait_ pid_t pid = 0;
+ _cleanup_(sigkill_waitp) pid_t pid = 0;
bool gpg_home_created = false;
int r;
diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c
index c9ce5c73be..ec50333c2c 100644
--- a/src/journal/journal-file.c
+++ b/src/journal/journal-file.c
@@ -3293,7 +3293,7 @@ int journal_file_open_reliably(
/* btrfs doesn't cope well with our write pattern and
* fragments heavily. Let's defrag all files we rotate */
- (void) chattr_path(p, false, FS_NOCOW_FL);
+ (void) chattr_path(p, 0, FS_NOCOW_FL);
(void) btrfs_defrag(p);
log_warning_errno(r, "File %s corrupted or uncleanly shut down, renaming and replacing.", fname);
diff --git a/src/journal/journald-gperf.gperf b/src/journal/journald-gperf.gperf
index c154610c54..7fecd7a964 100644
--- a/src/journal/journald-gperf.gperf
+++ b/src/journal/journald-gperf.gperf
@@ -19,7 +19,9 @@ Journal.Storage, config_parse_storage, 0, offsetof(Server, storage
Journal.Compress, config_parse_bool, 0, offsetof(Server, compress)
Journal.Seal, config_parse_bool, 0, offsetof(Server, seal)
Journal.SyncIntervalSec, config_parse_sec, 0, offsetof(Server, sync_interval_usec)
+# The following is a legacy name for compatibility
Journal.RateLimitInterval, config_parse_sec, 0, offsetof(Server, rate_limit_interval)
+Journal.RateLimitIntervalSec,config_parse_sec, 0, offsetof(Server, rate_limit_interval)
Journal.RateLimitBurst, config_parse_unsigned, 0, offsetof(Server, rate_limit_burst)
Journal.SystemMaxUse, config_parse_iec_uint64, 0, offsetof(Server, system_metrics.max_use)
Journal.SystemMaxFileSize, config_parse_iec_uint64, 0, offsetof(Server, system_metrics.max_size)
diff --git a/src/journal/journald.conf b/src/journal/journald.conf
index 7beb96c671..2541b949be 100644
--- a/src/journal/journald.conf
+++ b/src/journal/journald.conf
@@ -17,7 +17,7 @@
#Seal=yes
#SplitMode=uid
#SyncIntervalSec=5m
-#RateLimitInterval=30s
+#RateLimitIntervalSec=30s
#RateLimitBurst=1000
#SystemMaxUse=
#SystemKeepFree=
diff --git a/src/machine/image-dbus.c b/src/machine/image-dbus.c
index b764bc43a0..0eed9b81bb 100644
--- a/src/machine/image-dbus.c
+++ b/src/machine/image-dbus.c
@@ -20,9 +20,11 @@
#include "alloc-util.h"
#include "bus-label.h"
#include "bus-util.h"
+#include "fd-util.h"
#include "image-dbus.h"
#include "io-util.h"
#include "machine-image.h"
+#include "process-util.h"
#include "strv.h"
#include "user-util.h"
@@ -33,13 +35,18 @@ int bus_image_method_remove(
void *userdata,
sd_bus_error *error) {
+ _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
Image *image = userdata;
Manager *m = image->userdata;
+ pid_t child;
int r;
assert(message);
assert(image);
+ if (m->n_operations >= OPERATIONS_MAX)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing operations.");
+
r = bus_verify_polkit_async(
message,
CAP_SYS_ADMIN,
@@ -54,11 +61,35 @@ int bus_image_method_remove(
if (r == 0)
return 1; /* Will call us back */
- r = image_remove(image);
- if (r < 0)
+ if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
+ return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
+
+ child = fork();
+ if (child < 0)
+ return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
+ if (child == 0) {
+ errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
+
+ r = image_remove(image);
+ if (r < 0) {
+ (void) write(errno_pipe_fd[1], &r, sizeof(r));
+ _exit(EXIT_FAILURE);
+ }
+
+ _exit(EXIT_SUCCESS);
+ }
+
+ errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
+
+ r = operation_new(m, NULL, child, message, errno_pipe_fd[0]);
+ if (r < 0) {
+ (void) sigkill_wait(child);
return r;
+ }
- return sd_bus_reply_method_return(message, NULL);
+ errno_pipe_fd[0] = -1;
+
+ return 1;
}
int bus_image_method_rename(
@@ -107,13 +138,19 @@ int bus_image_method_clone(
void *userdata,
sd_bus_error *error) {
+ _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
Image *image = userdata;
Manager *m = image->userdata;
const char *new_name;
int r, read_only;
+ pid_t child;
assert(message);
assert(image);
+ assert(m);
+
+ if (m->n_operations >= OPERATIONS_MAX)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing operations.");
r = sd_bus_message_read(message, "sb", &new_name, &read_only);
if (r < 0)
@@ -136,13 +173,35 @@ int bus_image_method_clone(
if (r == 0)
return 1; /* Will call us back */
- r = image_clone(image, new_name, read_only);
- if (r == -EOPNOTSUPP)
- return sd_bus_reply_method_errnof(message, r, "Image cloning is currently only supported on btrfs file systems.");
- if (r < 0)
+ if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
+ return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
+
+ child = fork();
+ if (child < 0)
+ return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
+ if (child == 0) {
+ errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
+
+ r = image_clone(image, new_name, read_only);
+ if (r < 0) {
+ (void) write(errno_pipe_fd[1], &r, sizeof(r));
+ _exit(EXIT_FAILURE);
+ }
+
+ _exit(EXIT_SUCCESS);
+ }
+
+ errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
+
+ r = operation_new(m, NULL, child, message, errno_pipe_fd[0]);
+ if (r < 0) {
+ (void) sigkill_wait(child);
return r;
+ }
- return sd_bus_reply_method_return(message, NULL);
+ errno_pipe_fd[0] = -1;
+
+ return 1;
}
int bus_image_method_mark_read_only(
diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c
index 5121bfdd18..7b9aa66d63 100644
--- a/src/machine/machine-dbus.c
+++ b/src/machine/machine-dbus.c
@@ -1085,52 +1085,11 @@ finish:
return r;
}
-static int machine_operation_done(sd_event_source *s, const siginfo_t *si, void *userdata) {
- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- MachineOperation *o = userdata;
- int r;
-
- assert(o);
- assert(si);
-
- o->pid = 0;
-
- if (si->si_code != CLD_EXITED) {
- r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
- goto fail;
- }
-
- if (si->si_status != EXIT_SUCCESS) {
- if (read(o->errno_fd, &r, sizeof(r)) == sizeof(r))
- r = sd_bus_error_set_errnof(&error, r, "%m");
- else
- r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Child failed.");
-
- goto fail;
- }
-
- r = sd_bus_reply_method_return(o->message, NULL);
- if (r < 0)
- log_error_errno(r, "Failed to reply to message: %m");
-
- machine_operation_unref(o);
- return 0;
-
-fail:
- r = sd_bus_reply_method_error(o->message, &error);
- if (r < 0)
- log_error_errno(r, "Failed to reply to message: %m");
-
- machine_operation_unref(o);
- return 0;
-}
-
int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_error *error) {
const char *src, *dest, *host_path, *container_path, *host_basename, *host_dirname, *container_basename, *container_dirname;
_cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
_cleanup_close_ int hostfd = -1;
Machine *m = userdata;
- MachineOperation *o;
bool copy_from;
pid_t child;
char *t;
@@ -1139,7 +1098,7 @@ int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_erro
assert(message);
assert(m);
- if (m->n_operations >= MACHINE_OPERATIONS_MAX)
+ if (m->manager->n_operations >= OPERATIONS_MAX)
return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing copies.");
if (m->class != MACHINE_CONTAINER)
@@ -1249,27 +1208,14 @@ int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_erro
errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
- /* Copying might take a while, hence install a watch the
- * child, and return */
+ /* Copying might take a while, hence install a watch on the child, and return */
- o = new0(MachineOperation, 1);
- if (!o)
- return log_oom();
-
- o->pid = child;
- o->message = sd_bus_message_ref(message);
- o->errno_fd = errno_pipe_fd[0];
- errno_pipe_fd[0] = -1;
-
- r = sd_event_add_child(m->manager->event, &o->event_source, child, WEXITED, machine_operation_done, o);
+ r = operation_new(m->manager, m, child, message, errno_pipe_fd[0]);
if (r < 0) {
- machine_operation_unref(o);
- return log_oom();
+ (void) sigkill_wait(child);
+ return r;
}
-
- LIST_PREPEND(operations, m->operations, o);
- m->n_operations++;
- o->machine = m;
+ errno_pipe_fd[0] = -1;
return 1;
}
diff --git a/src/machine/machine.c b/src/machine/machine.c
index 7d4270a8ff..c1fae57084 100644
--- a/src/machine/machine.c
+++ b/src/machine/machine.c
@@ -89,7 +89,7 @@ void machine_free(Machine *m) {
assert(m);
while (m->operations)
- machine_operation_unref(m->operations);
+ operation_free(m->operations);
if (m->in_gc_queue)
LIST_REMOVE(gc_queue, m->manager->machine_gc_queue, m);
@@ -596,28 +596,6 @@ int machine_open_terminal(Machine *m, const char *path, int mode) {
}
}
-MachineOperation *machine_operation_unref(MachineOperation *o) {
- if (!o)
- return NULL;
-
- sd_event_source_unref(o->event_source);
-
- safe_close(o->errno_fd);
-
- if (o->pid > 1)
- (void) kill(o->pid, SIGKILL);
-
- sd_bus_message_unref(o->message);
-
- if (o->machine) {
- LIST_REMOVE(operations, o->machine->operations, o);
- o->machine->n_operations--;
- }
-
- free(o);
- return NULL;
-}
-
void machine_release_unit(Machine *m) {
assert(m);
diff --git a/src/machine/machine.h b/src/machine/machine.h
index 1d8cc5911a..e5d75361a9 100644
--- a/src/machine/machine.h
+++ b/src/machine/machine.h
@@ -20,11 +20,11 @@
***/
typedef struct Machine Machine;
-typedef struct MachineOperation MachineOperation;
typedef enum KillWho KillWho;
#include "list.h"
#include "machined.h"
+#include "operation.h"
typedef enum MachineState {
MACHINE_OPENING, /* Machine is being registered */
@@ -49,17 +49,6 @@ enum KillWho {
_KILL_WHO_INVALID = -1
};
-#define MACHINE_OPERATIONS_MAX 64
-
-struct MachineOperation {
- Machine *machine;
- pid_t pid;
- sd_bus_message *message;
- int errno_fd;
- sd_event_source *event_source;
- LIST_FIELDS(MachineOperation, operations);
-};
-
struct Machine {
Manager *manager;
@@ -88,10 +77,9 @@ struct Machine {
int *netif;
unsigned n_netif;
- LIST_FIELDS(Machine, gc_queue);
+ LIST_HEAD(Operation, operations);
- MachineOperation *operations;
- unsigned n_operations;
+ LIST_FIELDS(Machine, gc_queue);
};
Machine* machine_new(Manager *manager, MachineClass class, const char *name);
@@ -109,8 +97,6 @@ void machine_release_unit(Machine *m);
MachineState machine_get_state(Machine *u);
-MachineOperation *machine_operation_unref(MachineOperation *o);
-
const char* machine_class_to_string(MachineClass t) _const_;
MachineClass machine_class_from_string(const char *s) _pure_;
diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c
index 5a68c4ceb2..1165ab5afa 100644
--- a/src/machine/machinectl.c
+++ b/src/machine/machinectl.c
@@ -1076,6 +1076,7 @@ static int terminate_machine(int argc, char *argv[], void *userdata) {
static int copy_files(int argc, char *argv[], void *userdata) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
_cleanup_free_ char *abs_host_path = NULL;
char *dest, *host_path, *container_path;
sd_bus *bus = userdata;
@@ -1099,19 +1100,28 @@ static int copy_files(int argc, char *argv[], void *userdata) {
host_path = abs_host_path;
}
- r = sd_bus_call_method(
+ r = sd_bus_message_new_method_call(
bus,
+ &m,
"org.freedesktop.machine1",
"/org/freedesktop/machine1",
"org.freedesktop.machine1.Manager",
- copy_from ? "CopyFromMachine" : "CopyToMachine",
- &error,
- NULL,
+ copy_from ? "CopyFromMachine" : "CopyToMachine");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append(
+ m,
"sss",
argv[1],
copy_from ? container_path : host_path,
copy_from ? host_path : container_path);
if (r < 0)
+ return bus_log_create_error(r);
+
+ /* This is a slow operation, hence turn off any method call timeouts */
+ r = sd_bus_call(bus, m, USEC_INFINITY, &error, NULL);
+ if (r < 0)
return log_error_errno(r, "Failed to copy: %s", bus_error_message(&error, r));
return 0;
@@ -1393,7 +1403,6 @@ static int shell_machine(int argc, char *argv[], void *userdata) {
}
static int remove_image(int argc, char *argv[], void *userdata) {
- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus *bus = userdata;
int r, i;
@@ -1402,19 +1411,27 @@ static int remove_image(int argc, char *argv[], void *userdata) {
polkit_agent_open_if_enabled();
for (i = 1; i < argc; i++) {
- r = sd_bus_call_method(
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+
+ r = sd_bus_message_new_method_call(
bus,
+ &m,
"org.freedesktop.machine1",
"/org/freedesktop/machine1",
"org.freedesktop.machine1.Manager",
- "RemoveImage",
- &error,
- NULL,
- "s", argv[i]);
- if (r < 0) {
- log_error("Could not remove image: %s", bus_error_message(&error, -r));
- return r;
- }
+ "RemoveImage");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append(m, "s", argv[i]);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ /* This is a slow operation, hence turn off any method call timeouts */
+ r = sd_bus_call(bus, m, USEC_INFINITY, &error, NULL);
+ if (r < 0)
+ return log_error_errno(r, "Could not remove image: %s", bus_error_message(&error, r));
}
return 0;
@@ -1446,24 +1463,30 @@ static int rename_image(int argc, char *argv[], void *userdata) {
static int clone_image(int argc, char *argv[], void *userdata) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
sd_bus *bus = userdata;
int r;
polkit_agent_open_if_enabled();
- r = sd_bus_call_method(
+ r = sd_bus_message_new_method_call(
bus,
+ &m,
"org.freedesktop.machine1",
"/org/freedesktop/machine1",
"org.freedesktop.machine1.Manager",
- "CloneImage",
- &error,
- NULL,
- "ssb", argv[1], argv[2], arg_read_only);
- if (r < 0) {
- log_error("Could not clone image: %s", bus_error_message(&error, -r));
- return r;
- }
+ "CloneImage");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append(m, "ssb", argv[1], argv[2], arg_read_only);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ /* This is a slow operation, hence turn off any method call timeouts */
+ r = sd_bus_call(bus, m, USEC_INFINITY, &error, NULL);
+ if (r < 0)
+ return log_error_errno(r, "Could not clone image: %s", bus_error_message(&error, r));
return 0;
}
diff --git a/src/machine/machined.c b/src/machine/machined.c
index f2c1966a6b..f7ceb5e603 100644
--- a/src/machine/machined.c
+++ b/src/machine/machined.c
@@ -70,6 +70,11 @@ void manager_free(Manager *m) {
assert(m);
+ while (m->operations)
+ operation_free(m->operations);
+
+ assert(m->n_operations == 0);
+
while ((machine = hashmap_first(m->machines)))
machine_free(machine);
@@ -336,6 +341,9 @@ int manager_startup(Manager *m) {
static bool check_idle(void *userdata) {
Manager *m = userdata;
+ if (m->operations)
+ return false;
+
manager_gc(m, true);
return hashmap_isempty(m->machines);
diff --git a/src/machine/machined.h b/src/machine/machined.h
index e7d7dfdceb..7b9b148044 100644
--- a/src/machine/machined.h
+++ b/src/machine/machined.h
@@ -32,6 +32,7 @@ typedef struct Manager Manager;
#include "image-dbus.h"
#include "machine-dbus.h"
#include "machine.h"
+#include "operation.h"
struct Manager {
sd_event *event;
@@ -49,6 +50,9 @@ struct Manager {
LIST_HEAD(Machine, machine_gc_queue);
Machine *host_machine;
+
+ LIST_HEAD(Operation, operations);
+ unsigned n_operations;
};
Manager *manager_new(void);
diff --git a/src/machine/operation.c b/src/machine/operation.c
new file mode 100644
index 0000000000..e6ddc41a55
--- /dev/null
+++ b/src/machine/operation.c
@@ -0,0 +1,131 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2016 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/>.
+***/
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "operation.h"
+#include "process-util.h"
+
+static int operation_done(sd_event_source *s, const siginfo_t *si, void *userdata) {
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ Operation *o = userdata;
+ int r;
+
+ assert(o);
+ assert(si);
+
+ log_debug("Operating " PID_FMT " is now complete with with code=%s status=%i",
+ o->pid,
+ sigchld_code_to_string(si->si_code), si->si_status);
+
+ o->pid = 0;
+
+ if (si->si_code != CLD_EXITED) {
+ r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
+ goto fail;
+ }
+
+ if (si->si_status != EXIT_SUCCESS) {
+ if (read(o->errno_fd, &r, sizeof(r)) == sizeof(r))
+ r = sd_bus_error_set_errnof(&error, r, "%m");
+ else
+ r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Child failed.");
+
+ goto fail;
+ }
+
+ r = sd_bus_reply_method_return(o->message, NULL);
+ if (r < 0)
+ log_error_errno(r, "Failed to reply to message: %m");
+
+ operation_free(o);
+ return 0;
+
+fail:
+ r = sd_bus_reply_method_error(o->message, &error);
+ if (r < 0)
+ log_error_errno(r, "Failed to reply to message: %m");
+
+ operation_free(o);
+ return 0;
+}
+
+int operation_new(Manager *manager, Machine *machine, pid_t child, sd_bus_message *message, int errno_fd) {
+ Operation *o;
+ int r;
+
+ assert(manager);
+ assert(child > 1);
+ assert(message);
+ assert(errno_fd >= 0);
+
+ o = new0(Operation, 1);
+ if (!o)
+ return -ENOMEM;
+
+ r = sd_event_add_child(manager->event, &o->event_source, child, WEXITED, operation_done, o);
+ if (r < 0) {
+ free(o);
+ return r;
+ }
+
+ o->pid = child;
+ o->message = sd_bus_message_ref(message);
+ o->errno_fd = errno_fd;
+
+ LIST_PREPEND(operations, manager->operations, o);
+ manager->n_operations++;
+ o->manager = manager;
+
+ if (machine) {
+ LIST_PREPEND(operations_by_machine, machine->operations, o);
+ o->machine = machine;
+ }
+
+ log_debug("Started new operation " PID_FMT ".", child);
+
+ /* At this point we took ownership of both the child and the errno file descriptor! */
+
+ return 0;
+}
+
+Operation *operation_free(Operation *o) {
+ if (!o)
+ return NULL;
+
+ sd_event_source_unref(o->event_source);
+
+ safe_close(o->errno_fd);
+
+ if (o->pid > 1)
+ (void) sigkill_wait(o->pid);
+
+ sd_bus_message_unref(o->message);
+
+ if (o->manager) {
+ LIST_REMOVE(operations, o->manager->operations, o);
+ o->manager->n_operations--;
+ }
+
+ if (o->machine)
+ LIST_REMOVE(operations_by_machine, o->machine->operations, o);
+
+ free(o);
+ return NULL;
+}
diff --git a/src/machine/operation.h b/src/machine/operation.h
new file mode 100644
index 0000000000..7ca47bc3af
--- /dev/null
+++ b/src/machine/operation.h
@@ -0,0 +1,47 @@
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2016 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/>.
+***/
+
+#include <sys/types.h>
+
+#include "sd-bus.h"
+#include "sd-event.h"
+
+#include "list.h"
+
+typedef struct Operation Operation;
+
+#include "machined.h"
+
+#define OPERATIONS_MAX 64
+
+struct Operation {
+ Manager *manager;
+ Machine *machine;
+ pid_t pid;
+ sd_bus_message *message;
+ int errno_fd;
+ sd_event_source *event_source;
+ LIST_FIELDS(Operation, operations);
+ LIST_FIELDS(Operation, operations_by_machine);
+};
+
+int operation_new(Manager *manager, Machine *machine, pid_t child, sd_bus_message *message, int errno_fd);
+Operation *operation_free(Operation *o);
diff --git a/src/shared/machine-image.c b/src/shared/machine-image.c
index bebfc40efe..66f58ecd92 100644
--- a/src/shared/machine-image.c
+++ b/src/shared/machine-image.c
@@ -423,7 +423,7 @@ int image_remove(Image *i) {
case IMAGE_DIRECTORY:
/* Allow deletion of read-only directories */
- (void) chattr_path(i->path, false, FS_IMMUTABLE_FL);
+ (void) chattr_path(i->path, 0, FS_IMMUTABLE_FL);
r = rm_rf(i->path, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
if (r < 0)
return r;
@@ -505,7 +505,7 @@ int image_rename(Image *i, const char *new_name) {
(void) read_attr_path(i->path, &file_attr);
if (file_attr & FS_IMMUTABLE_FL)
- (void) chattr_path(i->path, false, FS_IMMUTABLE_FL);
+ (void) chattr_path(i->path, 0, FS_IMMUTABLE_FL);
/* fall through */
@@ -538,7 +538,7 @@ int image_rename(Image *i, const char *new_name) {
/* Restore the immutable bit, if it was set before */
if (file_attr & FS_IMMUTABLE_FL)
- (void) chattr_path(new_path, true, FS_IMMUTABLE_FL);
+ (void) chattr_path(new_path, FS_IMMUTABLE_FL, FS_IMMUTABLE_FL);
free(i->path);
i->path = new_path;
@@ -603,13 +603,21 @@ int image_clone(Image *i, const char *new_name, bool read_only) {
case IMAGE_SUBVOLUME:
case IMAGE_DIRECTORY:
+ /* If we can we'll always try to create a new btrfs subvolume here, even if the source is a plain
+ * directory.*/
+
new_path = strjoina("/var/lib/machines/", new_name);
r = btrfs_subvol_snapshot(i->path, new_path, (read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE | BTRFS_SNAPSHOT_QUOTA);
+ if (r == -EOPNOTSUPP) {
+ /* No btrfs snapshots supported, create a normal directory then. */
- /* Enable "subtree" quotas for the copy, if we didn't
- * copy any quota from the source. */
- (void) btrfs_subvol_auto_qgroup(i->path, 0, true);
+ r = copy_directory(i->path, new_path, false);
+ if (r >= 0)
+ (void) chattr_path(new_path, read_only ? FS_IMMUTABLE_FL : 0, FS_IMMUTABLE_FL);
+ } else if (r >= 0)
+ /* Enable "subtree" quotas for the copy, if we didn't copy any quota from the source. */
+ (void) btrfs_subvol_auto_qgroup(new_path, 0, true);
break;
@@ -670,7 +678,7 @@ int image_read_only(Image *i, bool b) {
a read-only subvolume, but at least something, and
we can read the value back.*/
- r = chattr_path(i->path, b, FS_IMMUTABLE_FL);
+ r = chattr_path(i->path, b ? FS_IMMUTABLE_FL : 0, FS_IMMUTABLE_FL);
if (r < 0)
return r;
diff --git a/src/test/test-copy.c b/src/test/test-copy.c
index cb437754b4..68154fc4e8 100644
--- a/src/test/test-copy.c
+++ b/src/test/test-copy.c
@@ -95,6 +95,8 @@ static void test_copy_tree(void) {
char **links = STRV_MAKE("link", "file",
"link2", "dir1/file");
char **p, **link;
+ const char *unixsockp;
+ struct stat st;
log_info("%s", __func__);
@@ -102,26 +104,34 @@ static void test_copy_tree(void) {
(void) rm_rf(original_dir, REMOVE_ROOT|REMOVE_PHYSICAL);
STRV_FOREACH(p, files) {
- char *f = strjoina(original_dir, *p);
+ _cleanup_free_ char *f;
+
+ assert_se(f = strappend(original_dir, *p));
assert_se(mkdir_parents(f, 0755) >= 0);
assert_se(write_string_file(f, "file", WRITE_STRING_FILE_CREATE) == 0);
}
STRV_FOREACH_PAIR(link, p, links) {
- char *f = strjoina(original_dir, *p);
- char *l = strjoina(original_dir, *link);
+ _cleanup_free_ char *f, *l;
+
+ assert_se(f = strappend(original_dir, *p));
+ assert_se(l = strappend(original_dir, *link));
assert_se(mkdir_parents(l, 0755) >= 0);
assert_se(symlink(f, l) == 0);
}
+ unixsockp = strjoina(original_dir, "unixsock");
+ assert_se(mknod(unixsockp, S_IFSOCK|0644, 0) >= 0);
+
assert_se(copy_tree(original_dir, copy_dir, true) == 0);
STRV_FOREACH(p, files) {
- _cleanup_free_ char *buf = NULL;
+ _cleanup_free_ char *buf = NULL, *f;
size_t sz = 0;
- char *f = strjoina(copy_dir, *p);
+
+ assert_se(f = strappend(copy_dir, *p));
assert_se(access(f, F_OK) == 0);
assert_se(read_full_file(f, &buf, &sz) == 0);
@@ -129,14 +139,19 @@ static void test_copy_tree(void) {
}
STRV_FOREACH_PAIR(link, p, links) {
- _cleanup_free_ char *target = NULL;
- char *f = strjoina(original_dir, *p);
- char *l = strjoina(copy_dir, *link);
+ _cleanup_free_ char *target = NULL, *f, *l;
+
+ assert_se(f = strjoin(original_dir, *p, NULL));
+ assert_se(l = strjoin(copy_dir, *link, NULL));
assert_se(readlink_and_canonicalize(l, &target) == 0);
assert_se(path_equal(f, target));
}
+ unixsockp = strjoina(copy_dir, "unixsock");
+ assert_se(stat(unixsockp, &st) >= 0);
+ assert_se(S_ISSOCK(st.st_mode));
+
assert_se(copy_tree(original_dir, copy_dir, false) < 0);
assert_se(copy_tree("/tmp/inexistent/foo/bar/fsdoi", copy_dir, false) < 0);
diff --git a/src/test/test-rlimit-util.c b/src/test/test-rlimit-util.c
index d9ac9368cd..62afd2de5e 100644
--- a/src/test/test-rlimit-util.c
+++ b/src/test/test-rlimit-util.c
@@ -99,6 +99,18 @@ int main(int argc, char *argv[]) {
test_rlimit_parse_format(RLIMIT_NOFILE, "", 0, 0, -EINVAL, NULL);
test_rlimit_parse_format(RLIMIT_NOFILE, "5:4", 0, 0, -EILSEQ, NULL);
test_rlimit_parse_format(RLIMIT_NOFILE, "5:4:3", 0, 0, -EINVAL, NULL);
+ test_rlimit_parse_format(RLIMIT_NICE, "20", 20, 20, 0, "20");
+ test_rlimit_parse_format(RLIMIT_NICE, "40", 40, 40, 0, "40");
+ test_rlimit_parse_format(RLIMIT_NICE, "41", 41, 41, -ERANGE, "41");
+ test_rlimit_parse_format(RLIMIT_NICE, "0", 0, 0, 0, "0");
+ test_rlimit_parse_format(RLIMIT_NICE, "-7", 27, 27, 0, "27");
+ test_rlimit_parse_format(RLIMIT_NICE, "-20", 40, 40, 0, "40");
+ test_rlimit_parse_format(RLIMIT_NICE, "-21", 41, 41, -ERANGE, "41");
+ test_rlimit_parse_format(RLIMIT_NICE, "-0", 20, 20, 0, "20");
+ test_rlimit_parse_format(RLIMIT_NICE, "+7", 13, 13, 0, "13");
+ test_rlimit_parse_format(RLIMIT_NICE, "+19", 1, 1, 0, "1");
+ test_rlimit_parse_format(RLIMIT_NICE, "+20", 0, 0, -ERANGE, "0");
+ test_rlimit_parse_format(RLIMIT_NICE, "+0", 20, 20, 0, "20");
return 0;
}
diff --git a/test/TEST-06-SELINUX/Makefile b/test/TEST-06-SELINUX/Makefile
index 5e89a29eff..e9f93b1104 100644..120000
--- a/test/TEST-06-SELINUX/Makefile
+++ b/test/TEST-06-SELINUX/Makefile
@@ -1,10 +1 @@
-all:
- @make -s --no-print-directory -C ../.. all
- @basedir=../.. TEST_BASE_DIR=../ ./test.sh --all
-setup:
- @make --no-print-directory -C ../.. all
- @basedir=../.. TEST_BASE_DIR=../ ./test.sh --setup
-clean:
- @basedir=../.. TEST_BASE_DIR=../ ./test.sh --clean
-run:
- @basedir=../.. TEST_BASE_DIR=../ ./test.sh --run
+../TEST-01-BASIC/Makefile \ No newline at end of file
diff --git a/test/TEST-08-ISSUE-2730/Makefile b/test/TEST-08-ISSUE-2730/Makefile
index 5e89a29eff..e9f93b1104 100644..120000
--- a/test/TEST-08-ISSUE-2730/Makefile
+++ b/test/TEST-08-ISSUE-2730/Makefile
@@ -1,10 +1 @@
-all:
- @make -s --no-print-directory -C ../.. all
- @basedir=../.. TEST_BASE_DIR=../ ./test.sh --all
-setup:
- @make --no-print-directory -C ../.. all
- @basedir=../.. TEST_BASE_DIR=../ ./test.sh --setup
-clean:
- @basedir=../.. TEST_BASE_DIR=../ ./test.sh --clean
-run:
- @basedir=../.. TEST_BASE_DIR=../ ./test.sh --run
+../TEST-01-BASIC/Makefile \ No newline at end of file
diff --git a/test/TEST-10-ISSUE-2467/Makefile b/test/TEST-10-ISSUE-2467/Makefile
new file mode 120000
index 0000000000..e9f93b1104
--- /dev/null
+++ b/test/TEST-10-ISSUE-2467/Makefile
@@ -0,0 +1 @@
+../TEST-01-BASIC/Makefile \ No newline at end of file
diff --git a/test/TEST-10-ISSUE-2467/test.sh b/test/TEST-10-ISSUE-2467/test.sh
new file mode 100755
index 0000000000..a652b0d812
--- /dev/null
+++ b/test/TEST-10-ISSUE-2467/test.sh
@@ -0,0 +1,88 @@
+#!/bin/bash
+# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
+# ex: ts=8 sw=4 sts=4 et filetype=sh
+TEST_DESCRIPTION="https://github.com/systemd/systemd/issues/2467"
+
+. $TEST_BASE_DIR/test-functions
+SKIP_INITRD=yes
+
+check_result_qemu() {
+ ret=1
+ mkdir -p $TESTDIR/root
+ mount ${LOOPDEV}p1 $TESTDIR/root
+ [[ -e $TESTDIR/root/testok ]] && ret=0
+ [[ -f $TESTDIR/root/failed ]] && cp -a $TESTDIR/root/failed $TESTDIR
+ cp -a $TESTDIR/root/var/log/journal $TESTDIR
+ umount $TESTDIR/root
+ [[ -f $TESTDIR/failed ]] && cat $TESTDIR/failed
+ ls -l $TESTDIR/journal/*/*.journal
+ test -s $TESTDIR/failed && ret=$(($ret+1))
+ return $ret
+}
+
+test_run() {
+ run_qemu || return 1
+ check_result_qemu || return 1
+ return 0
+}
+
+test_setup() {
+ create_empty_image
+ mkdir -p $TESTDIR/root
+ mount ${LOOPDEV}p1 $TESTDIR/root
+
+ # Create what will eventually be our root filesystem onto an overlay
+ (
+ LOG_LEVEL=5
+ eval $(udevadm info --export --query=env --name=${LOOPDEV}p2)
+
+ setup_basic_environment
+ dracut_install nc true rm
+
+ # setup the testsuite service
+ cat >$initdir/etc/systemd/system/testsuite.service <<'EOF'
+[Unit]
+Description=Testsuite service
+After=multi-user.target
+
+[Service]
+Type=oneshot
+ExecStart=/bin/sh -e -x -c 'rm -f /tmp/nonexistent; systemctl start test.socket; echo a | nc -U /run/test.ctl; >/testok'
+TimeoutStartSec=10s
+EOF
+
+ cat >$initdir/etc/systemd/system/test.socket <<'EOF'
+[Socket]
+ListenStream=/run/test.ctl
+EOF
+
+ cat > $initdir/etc/systemd/system/test.service <<'EOF'
+[Unit]
+Requires=test.socket
+ConditionPathExistsGlob=/tmp/nonexistent
+
+[Service]
+ExecStart=/bin/true
+EOF
+
+ setup_testsuite
+ ) || return 1
+
+ # mask some services that we do not want to run in these tests
+ ln -s /dev/null $initdir/etc/systemd/system/systemd-hwdb-update.service
+ ln -s /dev/null $initdir/etc/systemd/system/systemd-journal-catalog-update.service
+ ln -s /dev/null $initdir/etc/systemd/system/systemd-networkd.service
+ ln -s /dev/null $initdir/etc/systemd/system/systemd-networkd.socket
+ ln -s /dev/null $initdir/etc/systemd/system/systemd-resolved.service
+
+ ddebug "umount $TESTDIR/root"
+ umount $TESTDIR/root
+}
+
+test_cleanup() {
+ umount $TESTDIR/root 2>/dev/null
+ [[ $LOOPDEV ]] && losetup -d $LOOPDEV
+ return 0
+}
+
+do_test "$@"
diff --git a/test/sysv-generator-test.py b/test/sysv-generator-test.py
index aadc29ebeb..838dd57a6f 100755
--- a/test/sysv-generator-test.py
+++ b/test/sysv-generator-test.py
@@ -397,11 +397,12 @@ class SysvGeneratorTest(unittest.TestCase):
# backup files (not enabled in rcN.d/)
shutil.copy(script, script + '.bak')
shutil.copy(script, script + '.old')
+ shutil.copy(script, script + '.tmp')
+ shutil.copy(script, script + '.new')
err, results = self.run_generator()
print(err)
- self.assertEqual(sorted(results),
- ['foo.bak.service', 'foo.old.service', 'foo.service'])
+ self.assertEqual(sorted(results), ['foo.service', 'foo.tmp.service'])
# ensure we don't try to create a symlink to itself
self.assertNotIn('itself', err)
diff --git a/tmpfiles.d/systemd.conf.m4 b/tmpfiles.d/systemd.conf.m4
index 276bc6b1ba..150dab1e5b 100644
--- a/tmpfiles.d/systemd.conf.m4
+++ b/tmpfiles.d/systemd.conf.m4
@@ -26,32 +26,45 @@ d /run/log 0755 root root -
z /run/log/journal 2755 root systemd-journal - -
Z /run/log/journal/%m ~2750 root systemd-journal - -
-m4_ifdef(`HAVE_ACL',
+m4_ifdef(`HAVE_ACL',`m4_dnl
+m4_ifdef(`ENABLE_ADM_GROUP',`m4_dnl
m4_ifdef(`ENABLE_WHEEL_GROUP',``
a+ /run/log/journal/%m - - - - d:group:adm:r-x,d:group:wheel:r-x
A+ /run/log/journal/%m - - - - group:adm:r-x,group:wheel:r-x
'',``
a+ /run/log/journal/%m - - - - d:group:adm:r-x
A+ /run/log/journal/%m - - - - group:adm:r-x
-''))m4_dnl
+'')',`m4_dnl
+m4_ifdef(`ENABLE_WHEEL_GROUP',``
+a+ /run/log/journal/%m - - - - d:group:wheel:r-x
+A+ /run/log/journal/%m - - - - group:wheel:r-x
+'')')')m4_dnl
z /var/log/journal 2755 root systemd-journal - -
z /var/log/journal/%m 2755 root systemd-journal - -
z /var/log/journal/%m/system.journal 0640 root systemd-journal - -
-m4_ifdef(`HAVE_ACL',
+m4_ifdef(`HAVE_ACL',`m4_dnl
+m4_ifdef(`ENABLE_ADM_GROUP',`m4_dnl
m4_ifdef(`ENABLE_WHEEL_GROUP',``
a+ /var/log/journal - - - - d:group:adm:r-x,d:group:wheel:r-x
a+ /var/log/journal - - - - group:adm:r-x,group:wheel:r-x
a+ /var/log/journal/%m - - - - d:group:adm:r-x,d:group:wheel:r-x
a+ /var/log/journal/%m - - - - group:adm:r-x,group:wheel:r-x
a+ /var/log/journal/%m/system.journal - - - - group:adm:r--,group:wheel:r--
-'',``
+'', ``
a+ /var/log/journal - - - - d:group:adm:r-x
a+ /var/log/journal - - - - group:adm:r-x
a+ /var/log/journal/%m - - - - d:group:adm:r-x
a+ /var/log/journal/%m - - - - group:adm:r-x
a+ /var/log/journal/%m/system.journal - - - - group:adm:r--
-''))m4_dnl
+'')',`m4_dnl
+m4_ifdef(`ENABLE_WHEEL_GROUP',``
+a+ /var/log/journal - - - - d:group:wheel:r-x
+a+ /var/log/journal - - - - group:wheel:r-x
+a+ /var/log/journal/%m - - - - d:group:wheel:r-x
+a+ /var/log/journal/%m - - - - group:wheel:r-x
+a+ /var/log/journal/%m/system.journal - - - - group:wheel:r--
+'')')')m4_dnl
d /var/lib/systemd 0755 root root -
d /var/lib/systemd/coredump 0755 root root 3d