diff options
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 += \ @@ -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 |