summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CODING_STYLE14
-rw-r--r--Makefile.am2
-rw-r--r--TODO8
-rw-r--r--man/systemd-detect-virt.xml76
-rw-r--r--man/systemd.exec.xml86
-rw-r--r--man/systemd.timer.xml2
-rw-r--r--src/basic/calendarspec.c4
-rw-r--r--src/basic/def.h24
-rw-r--r--src/basic/extract-word.c141
-rw-r--r--src/basic/parse-util.c100
-rw-r--r--src/basic/time-util.c33
-rw-r--r--src/basic/time-util.h1
-rw-r--r--src/basic/virt.c2
-rw-r--r--src/binfmt/binfmt.c2
-rw-r--r--src/bootchart/bootchart.c6
-rw-r--r--src/cgls/cgls.c5
-rw-r--r--src/core/load-fragment-gperf.gperf.m44
-rw-r--r--src/core/load-fragment.c240
-rw-r--r--src/core/load-fragment.h2
-rw-r--r--src/core/main.c10
-rw-r--r--src/core/manager.c1
-rw-r--r--src/journal-remote/journal-remote.c2
-rw-r--r--src/journal-remote/journal-upload.c2
-rw-r--r--src/journal/coredump.c4
-rw-r--r--src/journal/journald-server.c16
-rw-r--r--src/login/logind.c4
-rw-r--r--src/modules-load/modules-load.c2
-rw-r--r--src/resolve/resolved-conf.c4
-rw-r--r--src/shared/sleep-config.c2
-rw-r--r--src/sysctl/sysctl.c2
-rw-r--r--src/sysusers/sysusers.c2
-rw-r--r--src/test/test-time.c23
-rw-r--r--src/test/test-unit-file.c61
-rw-r--r--src/timesync/timesyncd-conf.c4
-rw-r--r--src/tmpfiles/tmpfiles.c2
-rwxr-xr-xtest/TEST-01-BASIC/test.sh2
-rwxr-xr-xtest/TEST-02-CRYPTSETUP/test.sh2
-rw-r--r--test/end.service10
-rw-r--r--test/end.service.in6
-rw-r--r--test/test-execute/exec-capabilityboundingset-invert.service3
-rw-r--r--test/test-execute/exec-capabilityboundingset-merge.service3
-rw-r--r--test/test-execute/exec-capabilityboundingset-reset.service3
-rw-r--r--test/test-execute/exec-capabilityboundingset-simple.service3
-rw-r--r--test/test-execute/exec-environment-empty.service3
-rw-r--r--test/test-execute/exec-environment-multiple.service3
-rw-r--r--test/test-execute/exec-environment.service3
-rw-r--r--test/test-execute/exec-environmentfile.service2
-rw-r--r--test/test-execute/exec-group.service3
-rw-r--r--test/test-execute/exec-ignoresigpipe-no.service2
-rw-r--r--test/test-execute/exec-ignoresigpipe-yes.service2
-rw-r--r--test/test-execute/exec-ioschedulingclass-best-effort.service2
-rw-r--r--test/test-execute/exec-ioschedulingclass-idle.service2
-rw-r--r--test/test-execute/exec-ioschedulingclass-none.service2
-rw-r--r--test/test-execute/exec-ioschedulingclass-realtime.service2
-rw-r--r--test/test-execute/exec-oomscoreadjust-negative.service4
-rw-r--r--test/test-execute/exec-oomscoreadjust-positive.service4
-rw-r--r--test/test-execute/exec-personality-s390.service2
-rw-r--r--test/test-execute/exec-personality-x86-64.service2
-rw-r--r--test/test-execute/exec-personality-x86.service2
-rw-r--r--test/test-execute/exec-privatedevices-no.service2
-rw-r--r--test/test-execute/exec-privatedevices-yes.service2
-rw-r--r--test/test-execute/exec-privatenetwork-yes.service3
-rw-r--r--test/test-execute/exec-privatetmp-no.service2
-rw-r--r--test/test-execute/exec-privatetmp-yes.service2
-rw-r--r--test/test-execute/exec-runtimedirectory-mode.service2
-rw-r--r--test/test-execute/exec-runtimedirectory-owner.service2
-rw-r--r--test/test-execute/exec-runtimedirectory.service2
-rw-r--r--test/test-execute/exec-systemcallerrornumber.service3
-rw-r--r--test/test-execute/exec-systemcallfilter-failing.service1
-rw-r--r--test/test-execute/exec-systemcallfilter-failing2.service1
-rw-r--r--test/test-execute/exec-systemcallfilter-not-failing.service1
-rw-r--r--test/test-execute/exec-systemcallfilter-not-failing2.service1
-rw-r--r--test/test-execute/exec-umask-0177.service3
-rw-r--r--test/test-execute/exec-umask-default.service3
-rw-r--r--test/test-execute/exec-user.service3
-rw-r--r--test/test-execute/exec-workingdirectory.service2
-rw-r--r--test/test-functions2
77 files changed, 671 insertions, 331 deletions
diff --git a/CODING_STYLE b/CODING_STYLE
index 8b945cd3c1..0064303203 100644
--- a/CODING_STYLE
+++ b/CODING_STYLE
@@ -145,11 +145,15 @@
- Think about the types you use. If a value cannot sensibly be
negative, do not use "int", but use "unsigned".
-- Do not use types like "short". They *never* make sense. Use ints,
- longs, long longs, all in unsigned+signed fashion, and the fixed
- size types uint32_t and so on, as well as size_t, but nothing
- else. Do not use kernel types like u32 and so on, leave that to the
- kernel.
+- Use "char" only for actual characters. Use "uint8_t" or "int8_t"
+ when you actually mean a byte-sized signed or unsigned
+ integers. When referring to a generic byte, we generally prefer the
+ unsigned variant "uint8_t". Do not use types based on "short". They
+ *never* make sense. Use ints, longs, long longs, all in
+ unsigned+signed fashion, and the fixed size types
+ uint8_t/uint16_t/uint32_t/uint64_t/int8_t/int16_t/int32_t and so on,
+ as well as size_t, but nothing else. Do not use kernel types like
+ u32 and so on, leave that to the kernel.
- Public API calls (i.e. functions exported by our shared libraries)
must be marked "_public_" and need to be prefixed with "sd_". No
diff --git a/Makefile.am b/Makefile.am
index 51548bb289..cec07fac27 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1506,7 +1506,7 @@ EXTRA_DIST += \
test/c.service \
test/daughter.service \
test/d.service \
- test/end.service.in \
+ test/end.service \
test/e.service \
test/f.service \
test/grandchild.service \
diff --git a/TODO b/TODO
index 42534989a6..25900c70b8 100644
--- a/TODO
+++ b/TODO
@@ -33,6 +33,12 @@ Janitorial Clean-ups:
Features:
+* add an explicit parser for LimitNICE= and 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.
+
* do something about "/control" subcgroups in the unified cgroup hierarchy
* when we detect that there are waiting jobs but no running jobs, do something
@@ -912,8 +918,6 @@ External:
* dbus: in fedora, make /var/lib/dbus/machine-id a symlink to /etc/machine-id
-* add "# export SYSTEMD_PAGER=" to bash login
-
* /usr/bin/service should actually show the new command line
* fedora: suggest auto-restart on failure, but not on success and not on coredump. also, ask people to think about changing the start limit logic. Also point people to RestartPreventExitStatus=, SuccessExitStatus=
diff --git a/man/systemd-detect-virt.xml b/man/systemd-detect-virt.xml
index 3997e10c43..5d19322cdc 100644
--- a/man/systemd-detect-virt.xml
+++ b/man/systemd-detect-virt.xml
@@ -22,7 +22,7 @@
-->
<refentry id="systemd-detect-virt"
- xmlns:xi="http://www.w3.org/2001/XInclude">
+ xmlns:xi="http://www.w3.org/2001/XInclude">
<refentryinfo>
<title>systemd-detect-virt</title>
@@ -81,92 +81,92 @@
<colspec colname="product" />
<thead>
<row>
- <entry>Type</entry>
- <entry>ID</entry>
- <entry>Product</entry>
+ <entry>Type</entry>
+ <entry>ID</entry>
+ <entry>Product</entry>
</row>
</thead>
<tbody>
<row>
- <entry morerows="9">VM</entry>
- <entry><varname>qemu</varname></entry>
- <entry>QEMU software virtualization</entry>
+ <entry morerows="9">VM</entry>
+ <entry><varname>qemu</varname></entry>
+ <entry>QEMU software virtualization</entry>
</row>
<row>
- <entry><varname>kvm</varname></entry>
- <entry>Linux KVM kernel virtual machine</entry>
+ <entry><varname>kvm</varname></entry>
+ <entry>Linux KVM kernel virtual machine</entry>
</row>
<row>
- <entry><varname>zvm</varname></entry>
- <entry>s390 z/VM</entry>
+ <entry><varname>zvm</varname></entry>
+ <entry>s390 z/VM</entry>
</row>
<row>
- <entry><varname>vmware</varname></entry>
- <entry>VMware Workstation or Server, and related products</entry>
+ <entry><varname>vmware</varname></entry>
+ <entry>VMware Workstation or Server, and related products</entry>
</row>
<row>
- <entry><varname>microsoft</varname></entry>
- <entry>Hyper-V, also known as Viridian or Windows Server Virtualization</entry>
+ <entry><varname>microsoft</varname></entry>
+ <entry>Hyper-V, also known as Viridian or Windows Server Virtualization</entry>
</row>
<row>
- <entry><varname>oracle</varname></entry>
- <entry>Oracle VM VirtualBox (historically marketed by innotek and Sun Microsystems)</entry>
+ <entry><varname>oracle</varname></entry>
+ <entry>Oracle VM VirtualBox (historically marketed by innotek and Sun Microsystems)</entry>
</row>
<row>
- <entry><varname>xen</varname></entry>
- <entry>Xen hypervisor (only domU, not dom0)</entry>
+ <entry><varname>xen</varname></entry>
+ <entry>Xen hypervisor (only domU, not dom0)</entry>
</row>
<row>
- <entry><varname>bochs</varname></entry>
- <entry>Bochs Emulator</entry>
+ <entry><varname>bochs</varname></entry>
+ <entry>Bochs Emulator</entry>
</row>
<row>
- <entry><varname>uml</varname></entry>
- <entry>User-mode Linux</entry>
+ <entry><varname>uml</varname></entry>
+ <entry>User-mode Linux</entry>
</row>
<row>
- <entry><varname>parallels</varname></entry>
- <entry>Parallels Desktop, Parallels Server</entry>
+ <entry><varname>parallels</varname></entry>
+ <entry>Parallels Desktop, Parallels Server</entry>
</row>
<row>
- <entry morerows="5">Container</entry>
- <entry><varname>openvz</varname></entry>
- <entry>OpenVZ/Virtuozzo</entry>
+ <entry morerows="5">Container</entry>
+ <entry><varname>openvz</varname></entry>
+ <entry>OpenVZ/Virtuozzo</entry>
</row>
<row>
- <entry><varname>lxc</varname></entry>
- <entry>Linux container implementation by LXC</entry>
+ <entry><varname>lxc</varname></entry>
+ <entry>Linux container implementation by LXC</entry>
</row>
<row>
- <entry><varname>lxc-libvirt</varname></entry>
- <entry>Linux container implementation by libvirt</entry>
+ <entry><varname>lxc-libvirt</varname></entry>
+ <entry>Linux container implementation by libvirt</entry>
</row>
<row>
- <entry><varname>systemd-nspawn</varname></entry>
- <entry>systemd's minimal container implementation, see <citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry></entry>
+ <entry><varname>systemd-nspawn</varname></entry>
+ <entry>systemd's minimal container implementation, see <citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry></entry>
</row>
<row>
- <entry><varname>docker</varname></entry>
- <entry>Docker container manager</entry>
+ <entry><varname>docker</varname></entry>
+ <entry>Docker container manager</entry>
</row>
<row>
- <entry><varname>rkt</varname></entry>
- <entry>rkt app container runtime</entry>
+ <entry><varname>rkt</varname></entry>
+ <entry>rkt app container runtime</entry>
</row>
</tbody>
</tgroup>
diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
index 96298f11ed..2b090871ff 100644
--- a/man/systemd.exec.xml
+++ b/man/systemd.exec.xml
@@ -568,90 +568,133 @@
of various resources for executed processes. See
<citerefentry><refentrytitle>setrlimit</refentrytitle><manvolnum>2</manvolnum></citerefentry>
for details. 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).</para></listitem>
+ 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>
+
+ <para>Note that most process resource limits configured with
+ these options are per-process, and processes may fork in order
+ to acquire a new set of resources that are accounted
+ independently of the original process, and may thus escape
+ limits set. Also note that <varname>LimitRSS=</varname> is not
+ implemented on Linux, and setting it has no effect. Often it
+ is advisable to prefer the resource controls listed in
+ <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ over these per-process limits, as they apply to services as a
+ whole, may be altered dynamically at runtime, and are
+ generally more expressive. For example,
+ <varname>MemoryLimit=</varname> is a more powerful (and
+ working) replacement for <varname>LimitRSS=</varname>.</para>
<table>
<title>Limit directives and their equivalent with ulimit</title>
- <tgroup cols='2'>
+ <tgroup cols='3'>
<colspec colname='directive' />
<colspec colname='equivalent' />
+ <colspec colname='unit' />
<thead>
<row>
<entry>Directive</entry>
<entry>ulimit equivalent</entry>
+ <entry>Unit</entry>
</row>
</thead>
<tbody>
<row>
- <entry>LimitCPU</entry>
+ <entry>LimitCPU=</entry>
<entry>ulimit -t</entry>
+ <entry>Seconds</entry>
</row>
<row>
- <entry>LimitFSIZE</entry>
+ <entry>LimitFSIZE=</entry>
<entry>ulimit -f</entry>
+ <entry>Bytes</entry>
</row>
<row>
- <entry>LimitDATA</entry>
+ <entry>LimitDATA=</entry>
<entry>ulimit -d</entry>
+ <entry>Bytes</entry>
</row>
<row>
- <entry>LimitSTACK</entry>
+ <entry>LimitSTACK=</entry>
<entry>ulimit -s</entry>
+ <entry>Bytes</entry>
</row>
<row>
- <entry>LimitCORE</entry>
+ <entry>LimitCORE=</entry>
<entry>ulimit -c</entry>
+ <entry>Bytes</entry>
</row>
<row>
- <entry>LimitRSS</entry>
+ <entry>LimitRSS=</entry>
<entry>ulimit -m</entry>
+ <entry>Bytes</entry>
</row>
<row>
- <entry>LimitNOFILE</entry>
+ <entry>LimitNOFILE=</entry>
<entry>ulimit -n</entry>
+ <entry>Number of File Descriptors</entry>
</row>
<row>
- <entry>LimitAS</entry>
+ <entry>LimitAS=</entry>
<entry>ulimit -v</entry>
+ <entry>Bytes</entry>
</row>
<row>
- <entry>LimitNPROC</entry>
+ <entry>LimitNPROC=</entry>
<entry>ulimit -u</entry>
+ <entry>Number of Processes</entry>
</row>
<row>
- <entry>LimitMEMLOCK</entry>
+ <entry>LimitMEMLOCK=</entry>
<entry>ulimit -l</entry>
+ <entry>Bytes</entry>
</row>
<row>
- <entry>LimitLOCKS</entry>
+ <entry>LimitLOCKS=</entry>
<entry>ulimit -x</entry>
+ <entry>Number of Locks</entry>
</row>
<row>
- <entry>LimitSIGPENDING</entry>
+ <entry>LimitSIGPENDING=</entry>
<entry>ulimit -i</entry>
+ <entry>Number of Queued Signals</entry>
</row>
<row>
- <entry>LimitMSGQUEUE</entry>
+ <entry>LimitMSGQUEUE=</entry>
<entry>ulimit -q</entry>
+ <entry>Bytes</entry>
</row>
<row>
- <entry>LimitNICE</entry>
+ <entry>LimitNICE=</entry>
<entry>ulimit -e</entry>
+ <entry>Nice Level</entry>
</row>
<row>
- <entry>LimitRTPRIO</entry>
+ <entry>LimitRTPRIO=</entry>
<entry>ulimit -r</entry>
+ <entry>Realtime Priority</entry>
</row>
<row>
- <entry>LimitRTTIME</entry>
+ <entry>LimitRTTIME=</entry>
<entry>No equivalent</entry>
+ <entry>Microseconds</entry>
</row>
</tbody>
</tgroup>
- </table>
+ </table></listitem>
</varlistentry>
<varlistentry>
@@ -1320,6 +1363,7 @@
<citerefentry><refentrytitle>systemd.mount</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.kill</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.directives</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
<citerefentry><refentrytitle>tmpfiles.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry project='man-pages'><refentrytitle>exec</refentrytitle><manvolnum>3</manvolnum></citerefentry>
diff --git a/man/systemd.timer.xml b/man/systemd.timer.xml
index 20890f2270..c98258a0d7 100644
--- a/man/systemd.timer.xml
+++ b/man/systemd.timer.xml
@@ -127,7 +127,7 @@
boot-up. The argument may also include time units. Example:
"OnBootSec=5h 30min" means 5 hours and 30 minutes after
boot-up. For details about the syntax of time spans, see
- <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
+ <citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para>
<para>If a timer configured with <varname>OnBootSec=</varname>
or <varname>OnStartupSec=</varname> is already in the past
diff --git a/src/basic/calendarspec.c b/src/basic/calendarspec.c
index a6a906f453..7151fc3d0c 100644
--- a/src/basic/calendarspec.c
+++ b/src/basic/calendarspec.c
@@ -562,7 +562,7 @@ static int parse_date(const char **p, CalendarSpec *c) {
return -EINVAL;
}
-static int parse_time(const char **p, CalendarSpec *c) {
+static int parse_calendar_time(const char **p, CalendarSpec *c) {
CalendarComponent *h = NULL, *m = NULL, *s = NULL;
const char *t;
int r;
@@ -802,7 +802,7 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) {
if (r < 0)
goto fail;
- r = parse_time(&p, c);
+ r = parse_calendar_time(&p, c);
if (r < 0)
goto fail;
diff --git a/src/basic/def.h b/src/basic/def.h
index 950f693899..0657ac7367 100644
--- a/src/basic/def.h
+++ b/src/basic/def.h
@@ -76,17 +76,19 @@
#define NOTIFY_FD_MAX 768
#define NOTIFY_BUFFER_MAX PIPE_BUF
-/* Return a nulstr for a standard cascade of configuration directories,
- * suitable to pass to conf_files_list_nulstr or config_parse_many. */
-#define CONF_DIRS_NULSTR(n) \
- "/etc/" n ".d\0" \
- "/run/" n ".d\0" \
- "/usr/local/lib/" n ".d\0" \
- "/usr/lib/" n ".d\0" \
- CONF_DIR_SPLIT_USR(n)
-
#ifdef HAVE_SPLIT_USR
-#define CONF_DIR_SPLIT_USR(n) "/lib/" n ".d\0"
+#define _CONF_PATHS_SPLIT_USR(n) "/lib/" n "\0"
#else
-#define CONF_DIR_SPLIT_USR(n)
+#define _CONF_PATHS_SPLIT_USR(n)
#endif
+
+/* Return a nulstr for a standard cascade of configuration paths,
+ * suitable to pass to conf_files_list_nulstr() or config_parse_many()
+ * to implement drop-in directories for extending configuration
+ * files. */
+#define CONF_PATHS_NULSTR(n) \
+ "/etc/" n "\0" \
+ "/run/" n "\0" \
+ "/usr/local/lib/" n "\0" \
+ "/usr/lib/" n "\0" \
+ _CONF_PATHS_SPLIT_USR(n)
diff --git a/src/basic/extract-word.c b/src/basic/extract-word.c
index 6721b85c0a..ff6d211ef4 100644
--- a/src/basic/extract-word.c
+++ b/src/basic/extract-word.c
@@ -29,54 +29,51 @@
int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags) {
_cleanup_free_ char *s = NULL;
size_t allocated = 0, sz = 0;
+ char c;
int r;
char quote = 0; /* 0 or ' or " */
bool backslash = false; /* whether we've just seen a backslash */
- bool separator = false; /* whether we've just seen a separator */
- bool start = true; /* false means we're looking at a value */
assert(p);
assert(ret);
- if (!separators)
- separators = WHITESPACE;
-
/* Bail early if called after last value or with no input */
if (!*p)
goto finish_force_terminate;
+ c = **p;
+
+ if (!separators)
+ separators = WHITESPACE;
/* Parses the first word of a string, and returns it in
* *ret. Removes all quotes in the process. When parsing fails
* (because of an uneven number of quotes or similar), leaves
* the pointer *p at the first invalid character. */
- for (;;) {
- char c = **p;
-
- if (start) {
- if (flags & EXTRACT_DONT_COALESCE_SEPARATORS)
- if (!GREEDY_REALLOC(s, allocated, sz+1))
- return -ENOMEM;
+ if (flags & EXTRACT_DONT_COALESCE_SEPARATORS)
+ if (!GREEDY_REALLOC(s, allocated, sz+1))
+ return -ENOMEM;
- if (c == 0)
- goto finish_force_terminate;
- else if (strchr(separators, c)) {
+ for (;; (*p) ++, c = **p) {
+ if (c == 0)
+ goto finish_force_terminate;
+ else if (strchr(separators, c)) {
+ if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) {
(*p) ++;
- if (flags & EXTRACT_DONT_COALESCE_SEPARATORS)
- goto finish_force_next;
- continue;
+ goto finish_force_next;
}
-
+ } else {
/* We found a non-blank character, so we will always
* want to return a string (even if it is empty),
* allocate it here. */
if (!GREEDY_REALLOC(s, allocated, sz+1))
return -ENOMEM;
-
- start = false;
+ break;
}
+ }
+ for (;; (*p) ++, c = **p) {
if (backslash) {
if (!GREEDY_REALLOC(s, allocated, sz+7))
return -ENOMEM;
@@ -107,67 +104,73 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra
if (flags & EXTRACT_CUNESCAPE_RELAX) {
s[sz++] = '\\';
s[sz++] = c;
- goto end_escape;
- }
- return -EINVAL;
+ } else
+ return -EINVAL;
+ } else {
+ (*p) += r - 1;
+
+ if (c != 0)
+ s[sz++] = c; /* normal explicit char */
+ else
+ sz += utf8_encode_unichar(s + sz, u); /* unicode chars we'll encode as utf8 */
}
-
- (*p) += r - 1;
-
- if (c != 0)
- s[sz++] = c; /* normal explicit char */
- else
- sz += utf8_encode_unichar(s + sz, u); /* unicode chars we'll encode as utf8 */
} else
s[sz++] = c;
-end_escape:
backslash = false;
} else if (quote) { /* inside either single or double quotes */
- if (c == 0) {
- if (flags & EXTRACT_RELAX)
- goto finish_force_terminate;
- return -EINVAL;
- } else if (c == quote) /* found the end quote */
- quote = 0;
- else if (c == '\\')
- backslash = true;
- else {
- if (!GREEDY_REALLOC(s, allocated, sz+2))
- return -ENOMEM;
-
- s[sz++] = c;
+ for (;; (*p) ++, c = **p) {
+ if (c == 0) {
+ if (flags & EXTRACT_RELAX)
+ goto finish_force_terminate;
+ return -EINVAL;
+ } else if (c == quote) { /* found the end quote */
+ quote = 0;
+ break;
+ } else if (c == '\\') {
+ backslash = true;
+ break;
+ } else {
+ if (!GREEDY_REALLOC(s, allocated, sz+2))
+ return -ENOMEM;
+
+ s[sz++] = c;
+ }
}
- } else if (separator) {
- if (c == 0)
- goto finish_force_terminate;
- if (!strchr(separators, c))
- goto finish;
-
} else {
- if (c == 0)
- goto finish_force_terminate;
- else if ((c == '\'' || c == '"') && (flags & EXTRACT_QUOTES))
- quote = c;
- else if (c == '\\')
- backslash = true;
- else if (strchr(separators, c)) {
- if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) {
- (*p) ++;
- goto finish_force_next;
- }
- separator = true;
- } else {
- if (!GREEDY_REALLOC(s, allocated, sz+2))
- return -ENOMEM;
+ for (;; (*p) ++, c = **p) {
+ if (c == 0)
+ goto finish_force_terminate;
+ else if ((c == '\'' || c == '"') && (flags & EXTRACT_QUOTES)) {
+ quote = c;
+ break;
+ } else if (c == '\\') {
+ backslash = true;
+ break;
+ } else if (strchr(separators, c)) {
+ if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) {
+ (*p) ++;
+ goto finish_force_next;
+ }
+ /* Skip additional coalesced separators. */
+ for (;; (*p) ++, c = **p) {
+ if (c == 0)
+ goto finish_force_terminate;
+ if (!strchr(separators, c))
+ break;
+ }
+ goto finish;
- s[sz++] = c;
+ } else {
+ if (!GREEDY_REALLOC(s, allocated, sz+2))
+ return -ENOMEM;
+
+ s[sz++] = c;
+ }
}
}
-
- (*p) ++;
}
finish_force_terminate:
diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c
index b6358c459a..151067e916 100644
--- a/src/basic/parse-util.c
+++ b/src/basic/parse-util.c
@@ -67,11 +67,14 @@ int parse_mode(const char *s, mode_t *ret) {
assert(s);
assert(ret);
+ s += strspn(s, WHITESPACE);
+ if (s[0] == '-')
+ return -ERANGE;
+
errno = 0;
l = strtol(s, &x, 8);
if (errno != 0)
return -errno;
-
if (!x || x == s || *x)
return -EINVAL;
if (l < 0 || l > 07777)
@@ -162,15 +165,15 @@ int parse_size(const char *t, uint64_t base, uint64_t *size) {
unsigned i;
p += strspn(p, WHITESPACE);
- if (*p == '-')
- return -ERANGE;
errno = 0;
l = strtoull(p, &e, 10);
- if (errno > 0)
+ if (errno != 0)
return -errno;
if (e == p)
return -EINVAL;
+ if (*p == '-')
+ return -ERANGE;
if (*e == '.') {
e++;
@@ -181,7 +184,7 @@ int parse_size(const char *t, uint64_t base, uint64_t *size) {
char *e2;
l2 = strtoull(e, &e2, 10);
- if (errno > 0)
+ if (errno != 0)
return -errno;
/* Ignore failure. E.g. 10.M is valid */
@@ -307,12 +310,24 @@ int safe_atou(const char *s, unsigned *ret_u) {
assert(s);
assert(ret_u);
- errno = 0;
- l = strtoul(s, &x, 0);
+ /* strtoul() is happy to parse negative values, and silently
+ * converts them to unsigned values without generating an
+ * error. We want a clean error, hence let's look for the "-"
+ * prefix on our own, and generate an error. But let's do so
+ * only after strtoul() validated that the string is clean
+ * otherwise, so that we return EINVAL preferably over
+ * ERANGE. */
- if (!x || x == s || *x || errno)
- return errno > 0 ? -errno : -EINVAL;
+ s += strspn(s, WHITESPACE);
+ errno = 0;
+ l = strtoul(s, &x, 0);
+ if (errno != 0)
+ return -errno;
+ if (!x || x == s || *x)
+ return -EINVAL;
+ if (s[0] == '-')
+ return -ERANGE;
if ((unsigned long) (unsigned) l != l)
return -ERANGE;
@@ -329,10 +344,10 @@ int safe_atoi(const char *s, int *ret_i) {
errno = 0;
l = strtol(s, &x, 0);
-
- if (!x || x == s || *x || errno)
- return errno > 0 ? -errno : -EINVAL;
-
+ if (errno != 0)
+ return -errno;
+ if (!x || x == s || *x)
+ return -EINVAL;
if ((long) (int) l != l)
return -ERANGE;
@@ -347,11 +362,16 @@ int safe_atollu(const char *s, long long unsigned *ret_llu) {
assert(s);
assert(ret_llu);
+ s += strspn(s, WHITESPACE);
+
errno = 0;
l = strtoull(s, &x, 0);
-
- if (!x || x == s || *x || errno)
- return errno ? -errno : -EINVAL;
+ if (errno != 0)
+ return -errno;
+ if (!x || x == s || *x)
+ return -EINVAL;
+ if (*s == '-')
+ return -ERANGE;
*ret_llu = l;
return 0;
@@ -366,9 +386,10 @@ int safe_atolli(const char *s, long long int *ret_lli) {
errno = 0;
l = strtoll(s, &x, 0);
-
- if (!x || x == s || *x || errno)
- return errno ? -errno : -EINVAL;
+ if (errno != 0)
+ return -errno;
+ if (!x || x == s || *x)
+ return -EINVAL;
*ret_lli = l;
return 0;
@@ -381,12 +402,16 @@ int safe_atou8(const char *s, uint8_t *ret) {
assert(s);
assert(ret);
+ s += strspn(s, WHITESPACE);
+
errno = 0;
l = strtoul(s, &x, 0);
-
- if (!x || x == s || *x || errno)
- return errno > 0 ? -errno : -EINVAL;
-
+ if (errno != 0)
+ return -errno;
+ if (!x || x == s || *x)
+ return -EINVAL;
+ if (s[0] == '-')
+ return -ERANGE;
if ((unsigned long) (uint8_t) l != l)
return -ERANGE;
@@ -401,12 +426,16 @@ int safe_atou16(const char *s, uint16_t *ret) {
assert(s);
assert(ret);
+ s += strspn(s, WHITESPACE);
+
errno = 0;
l = strtoul(s, &x, 0);
-
- if (!x || x == s || *x || errno)
- return errno > 0 ? -errno : -EINVAL;
-
+ if (errno != 0)
+ return -errno;
+ if (!x || x == s || *x)
+ return -EINVAL;
+ if (s[0] == '-')
+ return -ERANGE;
if ((unsigned long) (uint16_t) l != l)
return -ERANGE;
@@ -423,10 +452,10 @@ int safe_atoi16(const char *s, int16_t *ret) {
errno = 0;
l = strtol(s, &x, 0);
-
- if (!x || x == s || *x || errno)
- return errno > 0 ? -errno : -EINVAL;
-
+ if (errno != 0)
+ return -errno;
+ if (!x || x == s || *x)
+ return -EINVAL;
if ((long) (int16_t) l != l)
return -ERANGE;
@@ -448,10 +477,13 @@ int safe_atod(const char *s, double *ret_d) {
errno = 0;
d = strtod_l(s, &x, loc);
-
- if (!x || x == s || *x || errno) {
+ if (errno != 0) {
freelocale(loc);
- return errno ? -errno : -EINVAL;
+ return -errno;
+ }
+ if (!x || x == s || *x) {
+ freelocale(loc);
+ return -EINVAL;
}
freelocale(loc);
diff --git a/src/basic/time-util.c b/src/basic/time-util.c
index e629d91cb2..b36fbe4f09 100644
--- a/src/basic/time-util.c
+++ b/src/basic/time-util.c
@@ -705,7 +705,8 @@ finish:
return 0;
}
-int parse_sec(const char *t, usec_t *usec) {
+int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
+
static const struct {
const char *suffix;
usec_t usec;
@@ -737,7 +738,6 @@ int parse_sec(const char *t, usec_t *usec) {
{ "y", USEC_PER_YEAR },
{ "usec", 1ULL },
{ "us", 1ULL },
- { "", USEC_PER_SEC }, /* default is sec */
};
const char *p, *s;
@@ -746,6 +746,7 @@ int parse_sec(const char *t, usec_t *usec) {
assert(t);
assert(usec);
+ assert(default_unit > 0);
p = t;
@@ -764,6 +765,7 @@ int parse_sec(const char *t, usec_t *usec) {
long long l, z = 0;
char *e;
unsigned i, n = 0;
+ usec_t multiplier, k;
p += strspn(p, WHITESPACE);
@@ -806,21 +808,24 @@ int parse_sec(const char *t, usec_t *usec) {
for (i = 0; i < ELEMENTSOF(table); i++)
if (startswith(e, table[i].suffix)) {
- usec_t k = (usec_t) z * table[i].usec;
-
- for (; n > 0; n--)
- k /= 10;
-
- r += (usec_t) l * table[i].usec + k;
+ multiplier = table[i].usec;
p = e + strlen(table[i].suffix);
-
- something = true;
break;
}
- if (i >= ELEMENTSOF(table))
- return -EINVAL;
+ if (i >= ELEMENTSOF(table)) {
+ multiplier = default_unit;
+ p = e;
+ }
+
+ something = true;
+
+ k = (usec_t) z * multiplier;
+ for (; n > 0; n--)
+ k /= 10;
+
+ r += (usec_t) l * multiplier + k;
}
*usec = r;
@@ -828,6 +833,10 @@ int parse_sec(const char *t, usec_t *usec) {
return 0;
}
+int parse_sec(const char *t, usec_t *usec) {
+ return parse_time(t, usec, USEC_PER_SEC);
+}
+
int parse_nsec(const char *t, nsec_t *nsec) {
static const struct {
const char *suffix;
diff --git a/src/basic/time-util.h b/src/basic/time-util.h
index 925bf18eb2..0417c29cdd 100644
--- a/src/basic/time-util.h
+++ b/src/basic/time-util.h
@@ -104,6 +104,7 @@ int dual_timestamp_deserialize(const char *value, dual_timestamp *t);
int parse_timestamp(const char *t, usec_t *usec);
int parse_sec(const char *t, usec_t *usec);
+int parse_time(const char *t, usec_t *usec, usec_t default_unit);
int parse_nsec(const char *t, nsec_t *nsec);
bool ntp_synced(void);
diff --git a/src/basic/virt.c b/src/basic/virt.c
index ff006e96c6..d088b7a804 100644
--- a/src/basic/virt.c
+++ b/src/basic/virt.c
@@ -400,7 +400,7 @@ int detect_container(void) {
goto finish;
}
- r = VIRTUALIZATION_NONE;
+ r = VIRTUALIZATION_CONTAINER_OTHER;
finish:
cached_found = r;
diff --git a/src/binfmt/binfmt.c b/src/binfmt/binfmt.c
index 42ad0adb02..03fb413fe5 100644
--- a/src/binfmt/binfmt.c
+++ b/src/binfmt/binfmt.c
@@ -37,7 +37,7 @@
#include "strv.h"
#include "util.h"
-static const char conf_file_dirs[] = CONF_DIRS_NULSTR("binfmt");
+static const char conf_file_dirs[] = CONF_PATHS_NULSTR("binfmt.d");
static int delete_rule(const char *rule) {
_cleanup_free_ char *x = NULL, *fn = NULL;
diff --git a/src/bootchart/bootchart.c b/src/bootchart/bootchart.c
index 852febb225..6a0e1d6b14 100644
--- a/src/bootchart/bootchart.c
+++ b/src/bootchart/bootchart.c
@@ -95,8 +95,6 @@ static void signal_handler(int sig) {
exiting = 1;
}
-#define BOOTCHART_CONF "/etc/systemd/bootchart.conf"
-
#define BOOTCHART_MAX (16*1024*1024)
static void parse_conf(void) {
@@ -117,8 +115,8 @@ static void parse_conf(void) {
{ NULL, NULL, NULL, 0, NULL }
};
- config_parse_many(BOOTCHART_CONF,
- CONF_DIRS_NULSTR("systemd/bootchart.conf"),
+ config_parse_many(PKGSYSCONFDIR "/bootchart.conf",
+ CONF_PATHS_NULSTR("systemd/bootchart.conf.d"),
NULL, config_item_table_lookup, items, true, NULL);
if (init != NULL)
diff --git a/src/cgls/cgls.c b/src/cgls/cgls.c
index 4e9a76a100..22efc58ac9 100644
--- a/src/cgls/cgls.c
+++ b/src/cgls/cgls.c
@@ -165,8 +165,10 @@ static int get_cgroup_root(char **ret) {
}
static void show_cg_info(const char *controller, const char *path) {
- if (cg_unified() <= 0)
+
+ if (cg_unified() <= 0 && controller && !streq(controller, SYSTEMD_CGROUP_CONTROLLER))
printf("Controller %s; ", controller);
+
printf("Control group %s:\n", isempty(path) ? "/" : path);
fflush(stdout);
}
@@ -270,6 +272,7 @@ int main(int argc, char *argv[]) {
show_cg_info(SYSTEMD_CGROUP_CONTROLLER, root);
+ printf("-.slice\n");
r = show_cgroup(SYSTEMD_CGROUP_CONTROLLER, root, NULL, 0, arg_kernel_threads, output_flags);
}
}
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index 5b7954dbf9..75388659e3 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -58,7 +58,7 @@ $1.RestrictAddressFamilies, config_parse_address_families, 0,
$1.SystemCallArchitectures, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
$1.SystemCallErrorNumber, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
$1.RestrictAddressFamilies, config_parse_warn_compat, DISABLED_CONFIGURATION, 0')
-$1.LimitCPU, config_parse_limit, RLIMIT_CPU, offsetof($1, exec_context.rlimit)
+$1.LimitCPU, config_parse_sec_limit, RLIMIT_CPU, offsetof($1, exec_context.rlimit)
$1.LimitFSIZE, config_parse_bytes_limit, RLIMIT_FSIZE, offsetof($1, exec_context.rlimit)
$1.LimitDATA, config_parse_bytes_limit, RLIMIT_DATA, offsetof($1, exec_context.rlimit)
$1.LimitSTACK, config_parse_bytes_limit, RLIMIT_STACK, offsetof($1, exec_context.rlimit)
@@ -73,7 +73,7 @@ $1.LimitSIGPENDING, config_parse_limit, RLIMIT_SIGP
$1.LimitMSGQUEUE, config_parse_bytes_limit, RLIMIT_MSGQUEUE, offsetof($1, exec_context.rlimit)
$1.LimitNICE, config_parse_limit, RLIMIT_NICE, offsetof($1, exec_context.rlimit)
$1.LimitRTPRIO, config_parse_limit, RLIMIT_RTPRIO, offsetof($1, exec_context.rlimit)
-$1.LimitRTTIME, config_parse_limit, RLIMIT_RTTIME, offsetof($1, exec_context.rlimit)
+$1.LimitRTTIME, config_parse_usec_limit, RLIMIT_RTTIME, offsetof($1, exec_context.rlimit)
$1.ReadWriteDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_write_dirs)
$1.ReadOnlyDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_only_dirs)
$1.InaccessibleDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.inaccessible_dirs)
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index 7f12f26b08..79cabd26e7 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -111,22 +111,28 @@ int config_parse_unit_deps(const char *unit,
UnitDependency d = ltype;
Unit *u = userdata;
- const char *word, *state;
- size_t l;
+ const char *p;
assert(filename);
assert(lvalue);
assert(rvalue);
- FOREACH_WORD_QUOTED(word, l, rvalue, state) {
- _cleanup_free_ char *t = NULL, *k = NULL;
+ p = rvalue;
+ for(;;) {
+ _cleanup_free_ char *word = NULL, *k = NULL;
int r;
- t = strndup(word, l);
- if (!t)
+ r = extract_first_word(&p, &word, NULL, 0);
+ if (r == 0)
+ break;
+ if (r == -ENOMEM)
return log_oom();
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
+ break;
+ }
- r = unit_name_printf(u, t, &k);
+ r = unit_name_printf(u, word, &k);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
continue;
@@ -136,8 +142,6 @@ int config_parse_unit_deps(const char *unit,
if (r < 0)
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
}
- if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid syntax, ignoring.");
return 0;
}
@@ -970,23 +974,22 @@ int config_parse_exec_secure_bits(const char *unit,
return 0;
}
-int config_parse_bounding_set(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
+int config_parse_bounding_set(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
uint64_t *capability_bounding_set_drop = data;
- uint64_t capability_bounding_set;
+ uint64_t capability_bounding_set, sum = 0;
bool invert = false;
- uint64_t sum = 0;
- const char *prev;
- const char *cur;
+ const char *p;
assert(filename);
assert(lvalue);
@@ -1003,35 +1006,32 @@ int config_parse_bounding_set(const char *unit,
* non-inverted everywhere to have a fully normalized
* interface. */
- prev = cur = rvalue;
+ p = rvalue;
for (;;) {
_cleanup_free_ char *word = NULL;
- int cap;
- int r;
+ int cap, r;
- r = extract_first_word(&cur, &word, NULL, EXTRACT_QUOTES);
+ r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
if (r == 0)
break;
if (r == -ENOMEM)
return log_oom();
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Trailing garbage in bounding set, ignoring: %s", prev);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse word, ignoring: %s", rvalue);
break;
}
cap = capability_from_name(word);
if (cap < 0) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse capability in bounding set, ignoring: %s", word);
- prev = cur;
continue;
}
- sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
- prev = cur;
+ sum |= ((uint64_t) UINT64_C(1)) << (uint64_t) cap;
}
capability_bounding_set = invert ? ~sum : sum;
- if (*capability_bounding_set_drop && capability_bounding_set)
+ if (*capability_bounding_set_drop != 0 && capability_bounding_set != 0)
*capability_bounding_set_drop = ~(~*capability_bounding_set_drop | capability_bounding_set);
else
*capability_bounding_set_drop = ~capability_bounding_set;
@@ -1039,19 +1039,21 @@ int config_parse_bounding_set(const char *unit,
return 0;
}
-int config_parse_limit(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
+int config_parse_limit(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
struct rlimit **rl = data;
- unsigned long long u;
+ rlim_t v;
+ int r;
assert(filename);
assert(lvalue);
@@ -1061,15 +1063,22 @@ int config_parse_limit(const char *unit,
rl += ltype;
if (streq(rvalue, "infinity"))
- u = (unsigned long long) RLIM_INFINITY;
+ v = RLIM_INFINITY;
else {
- int r;
+ uint64_t u;
- r = safe_atollu(rvalue, &u);
+ /* setrlimit(2) suggests rlim_t is always 64bit on Linux. */
+ assert_cc(sizeof(rlim_t) == sizeof(uint64_t));
+
+ r = safe_atou64(rvalue, &u);
+ if (r >= 0 && u >= (uint64_t) RLIM_INFINITY)
+ r = -ERANGE;
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
return 0;
}
+
+ v = (rlim_t) u;
}
if (!*rl) {
@@ -1078,23 +1087,25 @@ int config_parse_limit(const char *unit,
return log_oom();
}
- (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
+ (*rl)->rlim_cur = (*rl)->rlim_max = v;
return 0;
}
-int config_parse_bytes_limit(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
+int config_parse_bytes_limit(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
struct rlimit **rl = data;
- uint64_t bytes;
+ rlim_t bytes;
+ int r;
assert(filename);
assert(lvalue);
@@ -1104,15 +1115,120 @@ int config_parse_bytes_limit(const char *unit,
rl += ltype;
if (streq(rvalue, "infinity"))
- bytes = (uint64_t) RLIM_INFINITY;
+ bytes = RLIM_INFINITY;
else {
- int r;
+ uint64_t u;
+
+ r = parse_size(rvalue, 1024, &u);
+ if (r >= 0 && u >= (uint64_t) RLIM_INFINITY)
+ r = -ERANGE;
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ bytes = (rlim_t) u;
+ }
+
+ if (!*rl) {
+ *rl = new(struct rlimit, 1);
+ if (!*rl)
+ return log_oom();
+ }
+
+ (*rl)->rlim_cur = (*rl)->rlim_max = bytes;
+ return 0;
+}
+
+int config_parse_sec_limit(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
- r = parse_size(rvalue, 1024, &bytes);
+ struct rlimit **rl = data;
+ rlim_t seconds;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ rl += ltype;
+
+ if (streq(rvalue, "infinity"))
+ seconds = RLIM_INFINITY;
+ else {
+ usec_t t;
+
+ r = parse_sec(rvalue, &t);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
return 0;
}
+
+ if (t == USEC_INFINITY)
+ seconds = RLIM_INFINITY;
+ else
+ seconds = (rlim_t) (DIV_ROUND_UP(t, USEC_PER_SEC));
+ }
+
+ if (!*rl) {
+ *rl = new(struct rlimit, 1);
+ if (!*rl)
+ return log_oom();
+ }
+
+ (*rl)->rlim_cur = (*rl)->rlim_max = seconds;
+ return 0;
+}
+
+
+int config_parse_usec_limit(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ struct rlimit **rl = data;
+ rlim_t useconds;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ rl += ltype;
+
+ if (streq(rvalue, "infinity"))
+ useconds = RLIM_INFINITY;
+ else {
+ usec_t t;
+
+ r = parse_time(rvalue, &t, 1);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ if (t == USEC_INFINITY)
+ useconds = RLIM_INFINITY;
+ else
+ useconds = (rlim_t) t;
}
if (!*rl) {
@@ -1121,7 +1237,7 @@ int config_parse_bytes_limit(const char *unit,
return log_oom();
}
- (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) bytes;
+ (*rl)->rlim_cur = (*rl)->rlim_max = useconds;
return 0;
}
diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h
index 029775bb46..0cf821289c 100644
--- a/src/core/load-fragment.h
+++ b/src/core/load-fragment.h
@@ -57,6 +57,8 @@ int config_parse_exec_secure_bits(const char *unit, const char *filename, unsign
int config_parse_bounding_set(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_bytes_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_sec_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_usec_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_sysv_priority(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_kill_signal(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_exec_mount_flags(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
diff --git a/src/core/main.c b/src/core/main.c
index 950315e857..a86080642d 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -682,8 +682,14 @@ static int parse_config_file(void) {
const char *fn, *conf_dirs_nulstr;
- fn = arg_running_as == MANAGER_SYSTEM ? PKGSYSCONFDIR "/system.conf" : PKGSYSCONFDIR "/user.conf";
- conf_dirs_nulstr = arg_running_as == MANAGER_SYSTEM ? CONF_DIRS_NULSTR("systemd/system.conf") : CONF_DIRS_NULSTR("systemd/user.conf");
+ fn = arg_running_as == MANAGER_SYSTEM ?
+ PKGSYSCONFDIR "/system.conf" :
+ PKGSYSCONFDIR "/user.conf";
+
+ conf_dirs_nulstr = arg_running_as == MANAGER_SYSTEM ?
+ CONF_PATHS_NULSTR("systemd/system.conf.d") :
+ CONF_PATHS_NULSTR("systemd/user.conf.d");
+
config_parse_many(fn, conf_dirs_nulstr, "Manager\0",
config_item_table_lookup, items, false, NULL);
diff --git a/src/core/manager.c b/src/core/manager.c
index b13663e702..7c3a020c4a 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -2024,7 +2024,6 @@ int manager_loop(Manager *m) {
/* Yay, something is going seriously wrong, pause a little */
log_warning("Looping too fast. Throttling execution a little.");
sleep(1);
- continue;
}
if (manager_dispatch_load_queue(m) > 0)
diff --git a/src/journal-remote/journal-remote.c b/src/journal-remote/journal-remote.c
index 6eb0ee9d9e..b2f5fbf6b4 100644
--- a/src/journal-remote/journal-remote.c
+++ b/src/journal-remote/journal-remote.c
@@ -1188,7 +1188,7 @@ static int parse_config(void) {
{}};
return config_parse_many(PKGSYSCONFDIR "/journal-remote.conf",
- CONF_DIRS_NULSTR("systemd/journal-remote.conf"),
+ CONF_PATHS_NULSTR("systemd/journal-remote.conf.d"),
"Remote\0", config_item_table_lookup, items,
false, NULL);
}
diff --git a/src/journal-remote/journal-upload.c b/src/journal-remote/journal-upload.c
index 42d14dc7c4..6302266ccb 100644
--- a/src/journal-remote/journal-upload.c
+++ b/src/journal-remote/journal-upload.c
@@ -542,7 +542,7 @@ static int parse_config(void) {
{}};
return config_parse_many(PKGSYSCONFDIR "/journal-upload.conf",
- CONF_DIRS_NULSTR("systemd/journal-upload.conf"),
+ CONF_PATHS_NULSTR("systemd/journal-upload.conf.d"),
"Upload\0", config_item_table_lookup, items,
false, NULL);
}
diff --git a/src/journal/coredump.c b/src/journal/coredump.c
index 4c83e311db..f750ddfcbd 100644
--- a/src/journal/coredump.c
+++ b/src/journal/coredump.c
@@ -126,8 +126,8 @@ static int parse_config(void) {
{}
};
- return config_parse_many("/etc/systemd/coredump.conf",
- CONF_DIRS_NULSTR("systemd/coredump.conf"),
+ return config_parse_many(PKGSYSCONFDIR "/coredump.conf",
+ CONF_PATHS_NULSTR("systemd/coredump.conf.d"),
"Coredump\0",
config_item_table_lookup, items,
false, NULL);
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
index 7a70dcbc57..36fe739073 100644
--- a/src/journal/journald-server.c
+++ b/src/journal/journald-server.c
@@ -1296,10 +1296,22 @@ static int setup_signals(Server *s) {
if (r < 0)
return r;
+ /* Let's process SIGTERM late, so that we flush all queued
+ * messages to disk before we exit */
+ r = sd_event_source_set_priority(s->sigterm_event_source, SD_EVENT_PRIORITY_NORMAL+20);
+ if (r < 0)
+ return r;
+
+ /* When journald is invoked on the terminal (when debugging),
+ * it's useful if C-c is handled equivalent to SIGTERM. */
r = sd_event_add_signal(s->event, &s->sigint_event_source, SIGINT, dispatch_sigterm, s);
if (r < 0)
return r;
+ r = sd_event_source_set_priority(s->sigint_event_source, SD_EVENT_PRIORITY_NORMAL+20);
+ if (r < 0)
+ return r;
+
return 0;
}
@@ -1360,8 +1372,8 @@ static int server_parse_proc_cmdline(Server *s) {
static int server_parse_config_file(Server *s) {
assert(s);
- return config_parse_many("/etc/systemd/journald.conf",
- CONF_DIRS_NULSTR("systemd/journald.conf"),
+ return config_parse_many(PKGSYSCONFDIR "/journald.conf",
+ CONF_PATHS_NULSTR("systemd/journald.conf.d"),
"Journal\0",
config_item_perf_lookup, journald_gperf_lookup,
false, s);
diff --git a/src/login/logind.c b/src/login/logind.c
index 83896ea627..be6bbe5b5c 100644
--- a/src/login/logind.c
+++ b/src/login/logind.c
@@ -1102,8 +1102,8 @@ static int manager_run(Manager *m) {
static int manager_parse_config_file(Manager *m) {
assert(m);
- return config_parse_many("/etc/systemd/logind.conf",
- CONF_DIRS_NULSTR("systemd/logind.conf"),
+ return config_parse_many(PKGSYSCONFDIR "/logind.conf",
+ CONF_PATHS_NULSTR("systemd/logind.conf.d"),
"Login\0",
config_item_perf_lookup, logind_gperf_lookup,
false, m);
diff --git a/src/modules-load/modules-load.c b/src/modules-load/modules-load.c
index 13784763f1..a7fdcb09cf 100644
--- a/src/modules-load/modules-load.c
+++ b/src/modules-load/modules-load.c
@@ -38,7 +38,7 @@
static char **arg_proc_cmdline_modules = NULL;
-static const char conf_file_dirs[] = CONF_DIRS_NULSTR("modules-load");
+static const char conf_file_dirs[] = CONF_PATHS_NULSTR("modules-load.d");
static void systemd_kmod_log(void *data, int priority, const char *file, int line,
const char *fn, const char *format, va_list args) {
diff --git a/src/resolve/resolved-conf.c b/src/resolve/resolved-conf.c
index de1bd26174..9207719551 100644
--- a/src/resolve/resolved-conf.c
+++ b/src/resolve/resolved-conf.c
@@ -150,8 +150,8 @@ int config_parse_support(
int manager_parse_config_file(Manager *m) {
assert(m);
- return config_parse_many("/etc/systemd/resolved.conf",
- CONF_DIRS_NULSTR("systemd/resolved.conf"),
+ return config_parse_many(PKGSYSCONFDIR "/resolved.conf",
+ CONF_PATHS_NULSTR("systemd/resolved.conf.d"),
"Resolve\0",
config_item_perf_lookup, resolved_gperf_lookup,
false, m);
diff --git a/src/shared/sleep-config.c b/src/shared/sleep-config.c
index 102c5cc992..39b836d053 100644
--- a/src/shared/sleep-config.c
+++ b/src/shared/sleep-config.c
@@ -54,7 +54,7 @@ int parse_sleep_config(const char *verb, char ***_modes, char ***_states) {
};
config_parse_many(PKGSYSCONFDIR "/sleep.conf",
- CONF_DIRS_NULSTR("systemd/sleep.conf"),
+ CONF_PATHS_NULSTR("systemd/sleep.conf.d"),
"Sleep\0", config_item_table_lookup, items,
false, NULL);
diff --git a/src/sysctl/sysctl.c b/src/sysctl/sysctl.c
index 152c98b348..25b5ff52ea 100644
--- a/src/sysctl/sysctl.c
+++ b/src/sysctl/sysctl.c
@@ -41,7 +41,7 @@
static char **arg_prefixes = NULL;
-static const char conf_file_dirs[] = CONF_DIRS_NULSTR("sysctl");
+static const char conf_file_dirs[] = CONF_PATHS_NULSTR("sysctl.d");
static int apply_all(Hashmap *sysctl_options) {
char *property, *value;
diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c
index 008b1bde24..675f94906b 100644
--- a/src/sysusers/sysusers.c
+++ b/src/sysusers/sysusers.c
@@ -72,7 +72,7 @@ typedef struct Item {
static char *arg_root = NULL;
-static const char conf_file_dirs[] = CONF_DIRS_NULSTR("sysusers");
+static const char conf_file_dirs[] = CONF_PATHS_NULSTR("sysusers.d");
static Hashmap *users = NULL, *groups = NULL;
static Hashmap *todo_uids = NULL, *todo_gids = NULL;
diff --git a/src/test/test-time.c b/src/test/test-time.c
index 3840fff061..820e4aaee2 100644
--- a/src/test/test-time.c
+++ b/src/test/test-time.c
@@ -57,6 +57,28 @@ static void test_parse_sec(void) {
assert_se(parse_sec(".3 infinity", &u) < 0);
}
+static void test_parse_time(void) {
+ usec_t u;
+
+ assert_se(parse_time("5", &u, 1) >= 0);
+ assert_se(u == 5);
+
+ assert_se(parse_time("5", &u, USEC_PER_MSEC) >= 0);
+ assert_se(u == 5 * USEC_PER_MSEC);
+
+ assert_se(parse_time("5", &u, USEC_PER_SEC) >= 0);
+ assert_se(u == 5 * USEC_PER_SEC);
+
+ assert_se(parse_time("5s", &u, 1) >= 0);
+ assert_se(u == 5 * USEC_PER_SEC);
+
+ assert_se(parse_time("5s", &u, USEC_PER_SEC) >= 0);
+ assert_se(u == 5 * USEC_PER_SEC);
+
+ assert_se(parse_time("5s", &u, USEC_PER_MSEC) >= 0);
+ assert_se(u == 5 * USEC_PER_SEC);
+}
+
static void test_parse_nsec(void) {
nsec_t u;
@@ -161,6 +183,7 @@ static void test_get_timezones(void) {
int main(int argc, char *argv[]) {
test_parse_sec();
+ test_parse_time();
test_parse_nsec();
test_format_timespan(1);
test_format_timespan(USEC_PER_MSEC);
diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c
index f9107e0d0d..3648ec9c58 100644
--- a/src/test/test-unit-file.c
+++ b/src/test/test-unit-file.c
@@ -681,6 +681,66 @@ static void test_config_parse_bounding_set(void) {
assert_se(capability_bounding_set_drop == ~(make_cap(CAP_NET_RAW) | make_cap(CAP_NET_ADMIN)));
}
+static void test_config_parse_rlimit(void) {
+ struct rlimit * rl[_RLIMIT_MAX] = {};
+
+ assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "55", rl, NULL) >= 0);
+ assert_se(rl[RLIMIT_NOFILE]);
+ assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 55);
+ assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max);
+
+ assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "infinity", rl, NULL) >= 0);
+ assert_se(rl[RLIMIT_NOFILE]);
+ assert_se(rl[RLIMIT_NOFILE]->rlim_cur == RLIM_INFINITY);
+ assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max);
+
+ rl[RLIMIT_NOFILE] = mfree(rl[RLIMIT_NOFILE]);
+
+ assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "56", rl, NULL) >= 0);
+ assert_se(rl[RLIMIT_CPU]);
+ assert_se(rl[RLIMIT_CPU]->rlim_cur == 56);
+ assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max);
+
+ assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "57s", rl, NULL) >= 0);
+ assert_se(rl[RLIMIT_CPU]);
+ assert_se(rl[RLIMIT_CPU]->rlim_cur == 57);
+ assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max);
+
+ assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "infinity", rl, NULL) >= 0);
+ assert_se(rl[RLIMIT_CPU]);
+ assert_se(rl[RLIMIT_CPU]->rlim_cur == RLIM_INFINITY);
+ assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max);
+
+ assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "1234ms", rl, NULL) >= 0);
+ assert_se(rl[RLIMIT_CPU]);
+ assert_se(rl[RLIMIT_CPU]->rlim_cur == 2);
+ assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max);
+
+ rl[RLIMIT_CPU] = mfree(rl[RLIMIT_CPU]);
+
+ assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "58", rl, NULL) >= 0);
+ assert_se(rl[RLIMIT_RTTIME]);
+ assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 58);
+ assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max);
+
+ assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "59s", rl, NULL) >= 0);
+ assert_se(rl[RLIMIT_RTTIME]);
+ assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 59 * USEC_PER_SEC);
+ assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max);
+
+ assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "infinity", rl, NULL) >= 0);
+ assert_se(rl[RLIMIT_RTTIME]);
+ assert_se(rl[RLIMIT_RTTIME]->rlim_cur == RLIM_INFINITY);
+ assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max);
+
+ assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "2345ms", rl, NULL) >= 0);
+ assert_se(rl[RLIMIT_RTTIME]);
+ assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 2345 * USEC_PER_MSEC);
+ assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max);
+
+ rl[RLIMIT_RTTIME] = mfree(rl[RLIMIT_RTTIME]);
+}
+
int main(int argc, char *argv[]) {
int r;
@@ -690,6 +750,7 @@ int main(int argc, char *argv[]) {
r = test_unit_file_get_set();
test_config_parse_exec();
test_config_parse_bounding_set();
+ test_config_parse_rlimit();
test_load_env_file_1();
test_load_env_file_2();
test_load_env_file_3();
diff --git a/src/timesync/timesyncd-conf.c b/src/timesync/timesyncd-conf.c
index 001a0f4d41..5881bc0c45 100644
--- a/src/timesync/timesyncd-conf.c
+++ b/src/timesync/timesyncd-conf.c
@@ -100,8 +100,8 @@ int config_parse_servers(
int manager_parse_config_file(Manager *m) {
assert(m);
- return config_parse_many("/etc/systemd/timesyncd.conf",
- CONF_DIRS_NULSTR("systemd/timesyncd.conf"),
+ return config_parse_many(PKGSYSCONFDIR "/timesyncd.conf",
+ CONF_PATHS_NULSTR("systemd/timesyncd.conf.d"),
"Time\0",
config_item_perf_lookup, timesyncd_gperf_lookup,
false, m);
diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
index ffae91a3ca..64f0c9396c 100644
--- a/src/tmpfiles/tmpfiles.c
+++ b/src/tmpfiles/tmpfiles.c
@@ -159,7 +159,7 @@ static char **arg_include_prefixes = NULL;
static char **arg_exclude_prefixes = NULL;
static char *arg_root = NULL;
-static const char conf_file_dirs[] = CONF_DIRS_NULSTR("tmpfiles");
+static const char conf_file_dirs[] = CONF_PATHS_NULSTR("tmpfiles.d");
#define MAX_DEPTH 256
diff --git a/test/TEST-01-BASIC/test.sh b/test/TEST-01-BASIC/test.sh
index d97fbe24d4..b6b474393d 100755
--- a/test/TEST-01-BASIC/test.sh
+++ b/test/TEST-01-BASIC/test.sh
@@ -53,7 +53,7 @@ Description=Testsuite service
After=multi-user.target
[Service]
-ExecStart=/bin/bash -c 'set -x; systemctl --failed --no-legend --no-pager > /failed ; echo OK > /testok; while : ;do echo "testsuite service waiting for journal to move to /var/log/journal" > /dev/console ; for i in /var/log/journal/*;do [ -d "\$i" ] && echo "\$i" && break 2; done; sleep 1; done; sleep 1; exit 0;'
+ExecStart=/bin/sh -x -c 'systemctl --failed --no-legend --no-pager > /failed ; echo OK > /testok'
Type=oneshot
EOF
diff --git a/test/TEST-02-CRYPTSETUP/test.sh b/test/TEST-02-CRYPTSETUP/test.sh
index 4be2365e2f..2997da06ff 100755
--- a/test/TEST-02-CRYPTSETUP/test.sh
+++ b/test/TEST-02-CRYPTSETUP/test.sh
@@ -59,7 +59,7 @@ Description=Testsuite service
After=multi-user.target
[Service]
-ExecStart=/bin/bash -c 'set -x; systemctl --failed --no-legend --no-pager > /failed ; echo OK > /testok; while : ;do systemd-cat echo "testsuite service waiting for /var/log/journal" ; echo "testsuite service waiting for journal to move to /var/log/journal" > /dev/console ; for i in /var/log/journal/*;do [ -d "\$i" ] && echo "\$i" && break 2; done; sleep 1; done; sleep 1; exit 0;'
+ExecStart=/bin/sh -x -c 'systemctl --failed --no-legend --no-pager > /failed ; echo OK > /testok'
Type=oneshot
EOF
diff --git a/test/end.service b/test/end.service
new file mode 100644
index 0000000000..6e1996fd02
--- /dev/null
+++ b/test/end.service
@@ -0,0 +1,10 @@
+[Unit]
+Description=End the test
+After=testsuite.service
+OnFailure=poweroff.target
+OnFailureJobMode=replace-irreversibly
+
+[Service]
+Type=oneshot
+ExecStart=/bin/sh -x -c 'systemctl poweroff --no-block'
+TimeoutStartSec=5m
diff --git a/test/end.service.in b/test/end.service.in
deleted file mode 100644
index 4857ffe02b..0000000000
--- a/test/end.service.in
+++ /dev/null
@@ -1,6 +0,0 @@
-[Unit]
-Description=End the test
-After=testsuite.service
-
-[Service]
-ExecStart=@SYSTEMCTL@ poweroff --no-block
diff --git a/test/test-execute/exec-capabilityboundingset-invert.service b/test/test-execute/exec-capabilityboundingset-invert.service
index e2b09e1550..fd5d248702 100644
--- a/test/test-execute/exec-capabilityboundingset-invert.service
+++ b/test/test-execute/exec-capabilityboundingset-invert.service
@@ -2,5 +2,6 @@
Description=Test for CapabilityBoundingSet
[Service]
-ExecStart=/bin/sh -c 'c=$(capsh --print | grep "Bounding set " | grep "cap_chown"); echo $c; exit $(test -z $c)'
+ExecStart=/bin/sh -x -c 'c=$$(capsh --print | grep "^Bounding set .*cap_chown"); test -z "$$c"'
+Type=oneshot
CapabilityBoundingSet=~CAP_CHOWN
diff --git a/test/test-execute/exec-capabilityboundingset-merge.service b/test/test-execute/exec-capabilityboundingset-merge.service
index b0f4732529..5c7fcaf437 100644
--- a/test/test-execute/exec-capabilityboundingset-merge.service
+++ b/test/test-execute/exec-capabilityboundingset-merge.service
@@ -2,6 +2,7 @@
Description=Test for CapabilityBoundingSet
[Service]
-ExecStart=/bin/sh -c 'c=$(capsh --print | grep "Bounding set " | cut -f 2 -d "="); echo $c; exit $(test $c = "cap_chown,cap_fowner,cap_kill")'
+ExecStart=/bin/sh -x -c 'c=$$(capsh --print | grep "Bounding set "); test "$$c" = "Bounding set =cap_chown,cap_fowner,cap_kill"'
+Type=oneshot
CapabilityBoundingSet=CAP_FOWNER
CapabilityBoundingSet=CAP_KILL CAP_CHOWN
diff --git a/test/test-execute/exec-capabilityboundingset-reset.service b/test/test-execute/exec-capabilityboundingset-reset.service
index 51092ab0d5..d7d3320204 100644
--- a/test/test-execute/exec-capabilityboundingset-reset.service
+++ b/test/test-execute/exec-capabilityboundingset-reset.service
@@ -2,6 +2,7 @@
Description=Test for CapabilityBoundingSet
[Service]
-ExecStart=/bin/sh -c 'c=$(capsh --print | grep "Bounding set " | cut -f 2 -d "="); echo $c; exit $(test -z $c)'
+ExecStart=/bin/sh -x -c 'c=$$(capsh --print | grep "Bounding set "); test "$$c" = "Bounding set ="'
+Type=oneshot
CapabilityBoundingSet=CAP_FOWNER CAP_KILL
CapabilityBoundingSet=
diff --git a/test/test-execute/exec-capabilityboundingset-simple.service b/test/test-execute/exec-capabilityboundingset-simple.service
index b9037a0ddf..bf1a7f575a 100644
--- a/test/test-execute/exec-capabilityboundingset-simple.service
+++ b/test/test-execute/exec-capabilityboundingset-simple.service
@@ -2,5 +2,6 @@
Description=Test for CapabilityBoundingSet
[Service]
-ExecStart=/bin/sh -c 'c=$(capsh --print | grep "Bounding set " | cut -f 2 -d "="); echo $c; exit $(test $c = "cap_fowner,cap_kill")'
+ExecStart=/bin/sh -x -c 'c=$$(capsh --print | grep "Bounding set "); test "$$c" = "Bounding set =cap_fowner,cap_kill"'
+Type=oneshot
CapabilityBoundingSet=CAP_FOWNER CAP_KILL
diff --git a/test/test-execute/exec-environment-empty.service b/test/test-execute/exec-environment-empty.service
index 0219ca4fd7..9c92d4bc81 100644
--- a/test/test-execute/exec-environment-empty.service
+++ b/test/test-execute/exec-environment-empty.service
@@ -2,6 +2,7 @@
Description=Test for Environment
[Service]
-ExecStart=/bin/sh -c 'exit $(test ! "$VAR1" = "word1 word2") && $(test ! "$VAR2" = word3) && $(test ! "$VAR3" = \'$word 5 6\')'
+ExecStart=/bin/sh -x -c 'test "$${VAR1-unset}" = "unset" && test "$${VAR2-unset}" = "unset" && test "$${VAR3-unset}" = "unset"'
+Type=oneshot
Environment="VAR1=word1 word2" VAR2=word3 "VAR3=$word 5 6"
Environment=
diff --git a/test/test-execute/exec-environment-multiple.service b/test/test-execute/exec-environment-multiple.service
index 479005a5d8..b9bc225635 100644
--- a/test/test-execute/exec-environment-multiple.service
+++ b/test/test-execute/exec-environment-multiple.service
@@ -2,6 +2,7 @@
Description=Test for Environment
[Service]
-ExecStart=/bin/sh -c 'exit $(test "$VAR1" = "word1 word2") && $(test "$VAR2" = word3) && $(test "$VAR3" = foobar)'
+ExecStart=/bin/sh -x -c 'test "$$VAR1" = "word1 word2" && test "$$VAR2" = word3 && test "$$VAR3" = foobar'
+Type=oneshot
Environment="VAR1=word1 word2" VAR2=word3 "VAR3=$word 5 6"
Environment="VAR3=foobar"
diff --git a/test/test-execute/exec-environment.service b/test/test-execute/exec-environment.service
index 4586b4c4a9..06e77af220 100644
--- a/test/test-execute/exec-environment.service
+++ b/test/test-execute/exec-environment.service
@@ -2,5 +2,6 @@
Description=Test for Environment
[Service]
-ExecStart=/bin/sh -c 'exit $(test "$VAR1" = "word1 word2") && $(test "$VAR2" = word3) && $(test "$VAR3" = \'$word 5 6\')'
+ExecStart=/bin/sh -x -c 'test "$$VAR1" = "word1 word2" && test "$$VAR2" = word3 && test "$$VAR3" = "\\$$word 5 6"'
+Type=oneshot
Environment="VAR1=word1 word2" VAR2=word3 "VAR3=$word 5 6"
diff --git a/test/test-execute/exec-environmentfile.service b/test/test-execute/exec-environmentfile.service
index 848f2a120c..f6b8462719 100644
--- a/test/test-execute/exec-environmentfile.service
+++ b/test/test-execute/exec-environmentfile.service
@@ -2,6 +2,6 @@
Description=Test for EnvironmentFile
[Service]
-ExecStart=/bin/sh -c 'exit $(test "$VAR1" = "word1 word2") && $(test "$VAR2" = word3) && $(test "$VAR3" = \'$word 5 6\')'
+ExecStart=/bin/sh -x -c 'test "$$VAR1" = "word1 word2" && test "$$VAR2" = word3 && test "$$VAR3" = "\\$$word 5 6"'
Type=oneshot
EnvironmentFile=/tmp/test-exec_environmentfile.conf
diff --git a/test/test-execute/exec-group.service b/test/test-execute/exec-group.service
index 1aa04b5bd2..be7c796912 100644
--- a/test/test-execute/exec-group.service
+++ b/test/test-execute/exec-group.service
@@ -2,5 +2,6 @@
Description=Test for Group
[Service]
-ExecStart=/bin/sh -c 'exit $(test $(id -n -g) = nobody)'
+ExecStart=/bin/sh -x -c 'test "$$(id -n -g)" = "nobody"'
+Type=oneshot
Group=nobody
diff --git a/test/test-execute/exec-ignoresigpipe-no.service b/test/test-execute/exec-ignoresigpipe-no.service
index 69b2e9d8a8..73addf5f05 100644
--- a/test/test-execute/exec-ignoresigpipe-no.service
+++ b/test/test-execute/exec-ignoresigpipe-no.service
@@ -2,6 +2,6 @@
Description=Test for IgnoreSIGPIPE=no
[Service]
-ExecStart=/bin/sh -c 'kill -PIPE 0'
+ExecStart=/bin/sh -x -c 'kill -PIPE 0'
Type=oneshot
IgnoreSIGPIPE=no
diff --git a/test/test-execute/exec-ignoresigpipe-yes.service b/test/test-execute/exec-ignoresigpipe-yes.service
index 877ec8aed0..f81c01719e 100644
--- a/test/test-execute/exec-ignoresigpipe-yes.service
+++ b/test/test-execute/exec-ignoresigpipe-yes.service
@@ -2,6 +2,6 @@
Description=Test for IgnoreSIGPIPE=yes
[Service]
-ExecStart=/bin/sh -c 'kill -PIPE 0'
+ExecStart=/bin/sh -x -c 'kill -PIPE 0'
Type=oneshot
IgnoreSIGPIPE=yes
diff --git a/test/test-execute/exec-ioschedulingclass-best-effort.service b/test/test-execute/exec-ioschedulingclass-best-effort.service
index 56e2718505..29bb8510b4 100644
--- a/test/test-execute/exec-ioschedulingclass-best-effort.service
+++ b/test/test-execute/exec-ioschedulingclass-best-effort.service
@@ -2,6 +2,6 @@
Description=Test for IOSchedulingClass=best-effort
[Service]
-ExecStart=/bin/bash -c 'c=$(ionice); echo $c; [[ "$c" == best-effort* ]]'
+ExecStart=/bin/sh -x -c 'c=$$(LC_ALL=C ionice); test "$${c%%:*}" = "best-effort"'
Type=oneshot
IOSchedulingClass=best-effort
diff --git a/test/test-execute/exec-ioschedulingclass-idle.service b/test/test-execute/exec-ioschedulingclass-idle.service
index b45795cab7..87dbed14c1 100644
--- a/test/test-execute/exec-ioschedulingclass-idle.service
+++ b/test/test-execute/exec-ioschedulingclass-idle.service
@@ -2,6 +2,6 @@
Description=Test for IOSchedulingClass=idle
[Service]
-ExecStart=/bin/bash -c 'c=$(ionice); echo $c; [[ "$c" == idle* ]]'
+ExecStart=/bin/sh -x -c 'c=$$(LC_ALL=C ionice); test "$${c%%:*}" = "idle"'
Type=oneshot
IOSchedulingClass=idle
diff --git a/test/test-execute/exec-ioschedulingclass-none.service b/test/test-execute/exec-ioschedulingclass-none.service
index 36b546ca01..b6af122a1e 100644
--- a/test/test-execute/exec-ioschedulingclass-none.service
+++ b/test/test-execute/exec-ioschedulingclass-none.service
@@ -2,6 +2,6 @@
Description=Test for IOSchedulingClass=none
[Service]
-ExecStart=/bin/bash -c 'c=$(ionice); echo $c; [[ "$c" == none* ]]'
+ExecStart=/bin/sh -x -c 'c=$$(LC_ALL=C ionice); test "$${c%%:*}" = "none"'
Type=oneshot
IOSchedulingClass=none
diff --git a/test/test-execute/exec-ioschedulingclass-realtime.service b/test/test-execute/exec-ioschedulingclass-realtime.service
index 74936d8079..d920d5c687 100644
--- a/test/test-execute/exec-ioschedulingclass-realtime.service
+++ b/test/test-execute/exec-ioschedulingclass-realtime.service
@@ -2,6 +2,6 @@
Description=Test for IOSchedulingClass=realtime
[Service]
-ExecStart=/bin/bash -c 'c=$(ionice); echo $c; [[ "$c" == realtime* ]]'
+ExecStart=/bin/sh -x -c 'c=$$(LC_ALL=C ionice); test "$${c%%:*}" = "realtime"'
Type=oneshot
IOSchedulingClass=realtime
diff --git a/test/test-execute/exec-oomscoreadjust-negative.service b/test/test-execute/exec-oomscoreadjust-negative.service
index 63ab501c63..2234c53c3f 100644
--- a/test/test-execute/exec-oomscoreadjust-negative.service
+++ b/test/test-execute/exec-oomscoreadjust-negative.service
@@ -2,6 +2,6 @@
Description=Test for OOMScoreAdjust
[Service]
-ExecStart=/bin/bash -c 'c=$(cat /proc/self/oom_score_adj); echo $c; exit $(test $c -eq -100)'
-OOMScoreAdjust=-100
+ExecStart=/bin/sh -x -c 'c=$$(cat /proc/self/oom_score_adj); test "$$c" -eq -100'
Type=oneshot
+OOMScoreAdjust=-100
diff --git a/test/test-execute/exec-oomscoreadjust-positive.service b/test/test-execute/exec-oomscoreadjust-positive.service
index e47a4f1392..456a8f80cf 100644
--- a/test/test-execute/exec-oomscoreadjust-positive.service
+++ b/test/test-execute/exec-oomscoreadjust-positive.service
@@ -2,6 +2,6 @@
Description=Test for OOMScoreAdjust
[Service]
-ExecStart=/bin/bash -c 'c=$(cat /proc/self/oom_score_adj); echo $c; exit $(test $c -eq 100)'
-OOMScoreAdjust=100
+ExecStart=/bin/sh -x -c 'c=$$(cat /proc/self/oom_score_adj); test "$$c" -eq 100'
Type=oneshot
+OOMScoreAdjust=100
diff --git a/test/test-execute/exec-personality-s390.service b/test/test-execute/exec-personality-s390.service
index f3c3b03e3d..89f7de89d0 100644
--- a/test/test-execute/exec-personality-s390.service
+++ b/test/test-execute/exec-personality-s390.service
@@ -2,6 +2,6 @@
Description=Test for Personality=s390
[Service]
-ExecStart=/bin/sh -c 'echo $(uname -m); exit $(test $(uname -m) = "s390")'
+ExecStart=/bin/sh -x -c 'c=$$(uname -m); test "$$c" = "s390"'
Type=oneshot
Personality=s390
diff --git a/test/test-execute/exec-personality-x86-64.service b/test/test-execute/exec-personality-x86-64.service
index 5bb5d910d0..433e69a6d1 100644
--- a/test/test-execute/exec-personality-x86-64.service
+++ b/test/test-execute/exec-personality-x86-64.service
@@ -2,6 +2,6 @@
Description=Test for Personality=x86-64
[Service]
-ExecStart=/bin/sh -c 'echo $(uname -m); exit $(test $(uname -m) = "x86_64")'
+ExecStart=/bin/sh -x -c 'c=$$(uname -m); test "$$c" = "x86_64"'
Type=oneshot
Personality=x86-64
diff --git a/test/test-execute/exec-personality-x86.service b/test/test-execute/exec-personality-x86.service
index 0b370a6480..a623a08cbe 100644
--- a/test/test-execute/exec-personality-x86.service
+++ b/test/test-execute/exec-personality-x86.service
@@ -2,6 +2,6 @@
Description=Test for Personality=x86
[Service]
-ExecStart=/bin/sh -c 'echo $(uname -m); exit $(test $(uname -m) = "i686")'
+ExecStart=/bin/sh -x -c 'c=$$(uname -m); test "$$c" = "i686"'
Type=oneshot
Personality=x86
diff --git a/test/test-execute/exec-privatedevices-no.service b/test/test-execute/exec-privatedevices-no.service
index cf4f275fb6..77aeb951b5 100644
--- a/test/test-execute/exec-privatedevices-no.service
+++ b/test/test-execute/exec-privatedevices-no.service
@@ -2,6 +2,6 @@
Description=Test for PrivateDev=no
[Service]
-ExecStart=/bin/sh -c 'exit $(test -c /dev/mem)'
+ExecStart=/bin/sh -x -c 'test -c /dev/mem'
Type=oneshot
PrivateDevices=no
diff --git a/test/test-execute/exec-privatedevices-yes.service b/test/test-execute/exec-privatedevices-yes.service
index 85b3f4f981..ab958b646e 100644
--- a/test/test-execute/exec-privatedevices-yes.service
+++ b/test/test-execute/exec-privatedevices-yes.service
@@ -2,6 +2,6 @@
Description=Test for PrivateDev=yes
[Service]
-ExecStart=/bin/sh -c 'exit $(test ! -c /dev/mem)'
+ExecStart=/bin/sh -c 'test ! -c /dev/mem'
Type=oneshot
PrivateDevices=yes
diff --git a/test/test-execute/exec-privatenetwork-yes.service b/test/test-execute/exec-privatenetwork-yes.service
index 494712e6a7..3df543ec93 100644
--- a/test/test-execute/exec-privatenetwork-yes.service
+++ b/test/test-execute/exec-privatenetwork-yes.service
@@ -2,5 +2,6 @@
Description=Test for PrivateNetwork
[Service]
-ExecStart=/bin/sh -c 'i=$(ip link | grep ": " | grep -v lo); echo $i; exit $(test -z $i)'
+ExecStart=/bin/sh -x -c 'i=$$(ip link | grep ": " | grep -v ": lo:"); test -z "$$i"'
+Type=oneshot
PrivateNetwork=yes
diff --git a/test/test-execute/exec-privatetmp-no.service b/test/test-execute/exec-privatetmp-no.service
index d69e552a63..59f60f4755 100644
--- a/test/test-execute/exec-privatetmp-no.service
+++ b/test/test-execute/exec-privatetmp-no.service
@@ -2,6 +2,6 @@
Description=Test for PrivateTmp=no
[Service]
-ExecStart=/bin/sh -c 'exit $(test -f /tmp/test-exec_privatetmp)'
+ExecStart=/bin/sh -x -c 'test -f /tmp/test-exec_privatetmp'
Type=oneshot
PrivateTmp=no
diff --git a/test/test-execute/exec-privatetmp-yes.service b/test/test-execute/exec-privatetmp-yes.service
index 881a040b87..907c291b81 100644
--- a/test/test-execute/exec-privatetmp-yes.service
+++ b/test/test-execute/exec-privatetmp-yes.service
@@ -2,6 +2,6 @@
Description=Test for PrivateTmp=yes
[Service]
-ExecStart=/bin/sh -c 'exit $(test ! -f /tmp/test-exec_privatetmp)'
+ExecStart=/bin/sh -x -c 'test ! -f /tmp/test-exec_privatetmp'
Type=oneshot
PrivateTmp=yes
diff --git a/test/test-execute/exec-runtimedirectory-mode.service b/test/test-execute/exec-runtimedirectory-mode.service
index ba6d7ee39f..842721d5c2 100644
--- a/test/test-execute/exec-runtimedirectory-mode.service
+++ b/test/test-execute/exec-runtimedirectory-mode.service
@@ -2,7 +2,7 @@
Description=Test for RuntimeDirectoryMode
[Service]
-ExecStart=/bin/sh -c 's=$(stat -c %a /tmp/test-exec_runtimedirectory-mode); echo $s; exit $(test $s = "750")'
+ExecStart=/bin/sh -x -c 'mode=$$(stat -c %%a /tmp/test-exec_runtimedirectory-mode); test "$$mode" = "750"'
Type=oneshot
RuntimeDirectory=test-exec_runtimedirectory-mode
RuntimeDirectoryMode=0750
diff --git a/test/test-execute/exec-runtimedirectory-owner.service b/test/test-execute/exec-runtimedirectory-owner.service
index 077e08d1c5..1f438c182e 100644
--- a/test/test-execute/exec-runtimedirectory-owner.service
+++ b/test/test-execute/exec-runtimedirectory-owner.service
@@ -2,7 +2,7 @@
Description=Test for RuntimeDirectory owner (must not be the default group of the user if Group is set)
[Service]
-ExecStart=/bin/sh -c 'f=/tmp/test-exec_runtimedirectory-owner;g=$(stat -c %G $f); echo "$g"; exit $(test $g = "nobody")'
+ExecStart=/bin/sh -x -c 'group=$$(stat -c %%G /tmp/test-exec_runtimedirectory-owner); test "$$group" = "nobody"'
Type=oneshot
Group=nobody
User=root
diff --git a/test/test-execute/exec-runtimedirectory.service b/test/test-execute/exec-runtimedirectory.service
index c12a6c63d6..ec46c9d49b 100644
--- a/test/test-execute/exec-runtimedirectory.service
+++ b/test/test-execute/exec-runtimedirectory.service
@@ -2,6 +2,6 @@
Description=Test for RuntimeDirectory
[Service]
-ExecStart=/bin/sh -c 'exit $(test -d /tmp/test-exec_runtimedirectory)'
+ExecStart=/bin/sh -x -c 'test -d /tmp/test-exec_runtimedirectory'
Type=oneshot
RuntimeDirectory=test-exec_runtimedirectory
diff --git a/test/test-execute/exec-systemcallerrornumber.service b/test/test-execute/exec-systemcallerrornumber.service
index b11a952bd6..ff7da3c1a4 100644
--- a/test/test-execute/exec-systemcallerrornumber.service
+++ b/test/test-execute/exec-systemcallerrornumber.service
@@ -2,6 +2,7 @@
Description=Test for SystemCallErrorNumber
[Service]
-ExecStart=/bin/sh -c 'uname -a'
+ExecStart=/bin/sh -x -c 'uname -a'
+Type=oneshot
SystemCallFilter=~uname
SystemCallErrorNumber=EACCES
diff --git a/test/test-execute/exec-systemcallfilter-failing.service b/test/test-execute/exec-systemcallfilter-failing.service
index c6ce9368c9..5c6422f0fd 100644
--- a/test/test-execute/exec-systemcallfilter-failing.service
+++ b/test/test-execute/exec-systemcallfilter-failing.service
@@ -3,6 +3,7 @@ Description=Test for SystemCallFilter
[Service]
ExecStart=/bin/echo "This should not be seen"
+Type=oneshot
SystemCallFilter=ioperm
SystemCallFilter=~ioperm
SystemCallFilter=ioperm
diff --git a/test/test-execute/exec-systemcallfilter-failing2.service b/test/test-execute/exec-systemcallfilter-failing2.service
index b7f7c2aff9..3516078e1f 100644
--- a/test/test-execute/exec-systemcallfilter-failing2.service
+++ b/test/test-execute/exec-systemcallfilter-failing2.service
@@ -3,4 +3,5 @@ Description=Test for SystemCallFilter
[Service]
ExecStart=/bin/echo "This should not be seen"
+Type=oneshot
SystemCallFilter=~write open execve exit_group close mmap munmap fstat DONOTEXIST
diff --git a/test/test-execute/exec-systemcallfilter-not-failing.service b/test/test-execute/exec-systemcallfilter-not-failing.service
index feb206ab6d..c794b67edd 100644
--- a/test/test-execute/exec-systemcallfilter-not-failing.service
+++ b/test/test-execute/exec-systemcallfilter-not-failing.service
@@ -3,6 +3,7 @@ Description=Test for SystemCallFilter
[Service]
ExecStart=/bin/echo "Foo bar"
+Type=oneshot
SystemCallFilter=~read write open execve ioperm
SystemCallFilter=ioctl
SystemCallFilter=read write open execve
diff --git a/test/test-execute/exec-systemcallfilter-not-failing2.service b/test/test-execute/exec-systemcallfilter-not-failing2.service
index cca469aa3d..a62c81bd48 100644
--- a/test/test-execute/exec-systemcallfilter-not-failing2.service
+++ b/test/test-execute/exec-systemcallfilter-not-failing2.service
@@ -3,4 +3,5 @@ Description=Test for SystemCallFilter
[Service]
ExecStart=/bin/echo "Foo bar"
+Type=oneshot
SystemCallFilter=
diff --git a/test/test-execute/exec-umask-0177.service b/test/test-execute/exec-umask-0177.service
index af9295888e..a5e8fc4dbc 100644
--- a/test/test-execute/exec-umask-0177.service
+++ b/test/test-execute/exec-umask-0177.service
@@ -2,6 +2,7 @@
Description=Test for UMask
[Service]
-ExecStart=/bin/sh -c 'touch /tmp/test-exec-umask; s=$(stat -c %a /tmp/test-exec-umask); echo $s; exit $(test $s = "600")'
+ExecStart=/bin/sh -x -c 'touch /tmp/test-exec-umask; mode=$$(stat -c %%a /tmp/test-exec-umask); test "$$mode" = "600"'
+Type=oneshot
UMask=0177
PrivateTmp=yes
diff --git a/test/test-execute/exec-umask-default.service b/test/test-execute/exec-umask-default.service
index 41e20a60a1..487f5e9b94 100644
--- a/test/test-execute/exec-umask-default.service
+++ b/test/test-execute/exec-umask-default.service
@@ -2,5 +2,6 @@
Description=Test for UMask default
[Service]
-ExecStart=/bin/sh -c 'touch /tmp/test-exec-umask; s=$(stat -c %a /tmp/test-exec-umask); echo $s; exit $(test $s = "644")'
+ExecStart=/bin/sh -x -c 'touch /tmp/test-exec-umask; mode=$$(stat -c %%a /tmp/test-exec-umask); test "$$mode" = "644"'
+Type=oneshot
PrivateTmp=yes
diff --git a/test/test-execute/exec-user.service b/test/test-execute/exec-user.service
index 2ca08ebb42..0a00c1abc4 100644
--- a/test/test-execute/exec-user.service
+++ b/test/test-execute/exec-user.service
@@ -2,5 +2,6 @@
Description=Test for User
[Service]
-ExecStart=/bin/sh -c 'exit $(test "$USER" = nobody)'
+ExecStart=/bin/sh -x -c 'test "$$USER" = "nobody"'
+Type=oneshot
User=nobody
diff --git a/test/test-execute/exec-workingdirectory.service b/test/test-execute/exec-workingdirectory.service
index 10855d682a..fe3c420d2d 100644
--- a/test/test-execute/exec-workingdirectory.service
+++ b/test/test-execute/exec-workingdirectory.service
@@ -2,6 +2,6 @@
Description=Test for WorkingDirectory
[Service]
-ExecStart=/bin/sh -c 'echo $PWD; exit $(test $PWD = "/tmp/test-exec_workingdirectory")'
+ExecStart=/bin/sh -x -c 'test "$$PWD" = "/tmp/test-exec_workingdirectory"'
Type=oneshot
WorkingDirectory=/tmp/test-exec_workingdirectory
diff --git a/test/test-functions b/test/test-functions
index ab77576573..2f5ec9b93f 100644
--- a/test/test-functions
+++ b/test/test-functions
@@ -305,7 +305,7 @@ install_terminfo() {
setup_testsuite() {
cp $TEST_BASE_DIR/testsuite.target $initdir/etc/systemd/system/
- sed "s#@SYSTEMCTL@#$(type -P systemctl)#g" $TEST_BASE_DIR/end.service.in > $initdir/etc/systemd/system/end.service
+ cp $TEST_BASE_DIR/end.service $initdir/etc/systemd/system/
mkdir -p $initdir/etc/systemd/system/testsuite.target.wants
ln -fs $TEST_BASE_DIR/testsuite.service $initdir/etc/systemd/system/testsuite.target.wants/testsuite.service