diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-06 02:25:50 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-06 02:25:50 +0000 |
commit | 19f4f86bfed21c5326ed2acebe1163f3a83e832b (patch) | |
tree | d59b9989ce55ed23693e80974d94c856f1c2c8b1 /test/TEST-22-TMPFILES | |
parent | Initial commit. (diff) | |
download | systemd-19f4f86bfed21c5326ed2acebe1163f3a83e832b.tar.xz systemd-19f4f86bfed21c5326ed2acebe1163f3a83e832b.zip |
Adding upstream version 241.upstream/241upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
l--------- | test/TEST-22-TMPFILES/Makefile | 1 | ||||
-rwxr-xr-x | test/TEST-22-TMPFILES/run-tmpfiles-tests.sh | 13 | ||||
-rwxr-xr-x | test/TEST-22-TMPFILES/test-01.sh | 13 | ||||
-rwxr-xr-x | test/TEST-22-TMPFILES/test-02.sh | 122 | ||||
-rwxr-xr-x | test/TEST-22-TMPFILES/test-03.sh | 236 | ||||
-rwxr-xr-x | test/TEST-22-TMPFILES/test-04.sh | 44 | ||||
-rwxr-xr-x | test/TEST-22-TMPFILES/test-05.sh | 45 | ||||
-rwxr-xr-x | test/TEST-22-TMPFILES/test-06.sh | 38 | ||||
-rwxr-xr-x | test/TEST-22-TMPFILES/test-07.sh | 31 | ||||
-rwxr-xr-x | test/TEST-22-TMPFILES/test.sh | 40 | ||||
-rw-r--r-- | test/TEST-22-TMPFILES/testsuite.service | 10 |
11 files changed, 593 insertions, 0 deletions
diff --git a/test/TEST-22-TMPFILES/Makefile b/test/TEST-22-TMPFILES/Makefile new file mode 120000 index 0000000..e9f93b1 --- /dev/null +++ b/test/TEST-22-TMPFILES/Makefile @@ -0,0 +1 @@ +../TEST-01-BASIC/Makefile
\ No newline at end of file diff --git a/test/TEST-22-TMPFILES/run-tmpfiles-tests.sh b/test/TEST-22-TMPFILES/run-tmpfiles-tests.sh new file mode 100755 index 0000000..3ad652f --- /dev/null +++ b/test/TEST-22-TMPFILES/run-tmpfiles-tests.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +set -x +set -e + +>/failed + +for t in test-*.sh; do + echo "Running $t"; ./$t +done + +touch /testok +rm /failed diff --git a/test/TEST-22-TMPFILES/test-01.sh b/test/TEST-22-TMPFILES/test-01.sh new file mode 100755 index 0000000..d233e37 --- /dev/null +++ b/test/TEST-22-TMPFILES/test-01.sh @@ -0,0 +1,13 @@ +#! /bin/bash +# +# With "e" don't attempt to set permissions when file doesn't exist, see +# https://github.com/systemd/systemd/pull/6682. +# + +set -e + +rm -fr /tmp/test + +echo "e /tmp/test - root root 1d" | systemd-tmpfiles --create - + +! test -e /tmp/test diff --git a/test/TEST-22-TMPFILES/test-02.sh b/test/TEST-22-TMPFILES/test-02.sh new file mode 100755 index 0000000..d1bf1ea --- /dev/null +++ b/test/TEST-22-TMPFILES/test-02.sh @@ -0,0 +1,122 @@ +#! /bin/bash +# +# Basic tests for types creating directories +# + +set -e +set -x + +rm -fr /tmp/{C,d,D,e} +mkdir /tmp/{C,d,D,e} + +# +# 'd' +# +mkdir /tmp/d/2 +chmod 777 /tmp/d/2 + +systemd-tmpfiles --create - <<EOF +d /tmp/d/1 0755 daemon daemon - - +d /tmp/d/2 0755 daemon daemon - - +EOF + +test -d /tmp/d/1 +test $(stat -c %U:%G:%a /tmp/d/1) = "daemon:daemon:755" + +test -d /tmp/d/2 +test $(stat -c %U:%G:%a /tmp/d/2) = "daemon:daemon:755" + +# +# 'D' +# +mkdir /tmp/D/2 +chmod 777 /tmp/D/2 +touch /tmp/D/2/foo + +systemd-tmpfiles --create - <<EOF +D /tmp/D/1 0755 daemon daemon - - +D /tmp/D/2 0755 daemon daemon - - +EOF + +test -d /tmp/D/1 +test $(stat -c %U:%G:%a /tmp/D/1) = "daemon:daemon:755" + +test -d /tmp/D/2 +test $(stat -c %U:%G:%a /tmp/D/2) = "daemon:daemon:755" + +systemd-tmpfiles --remove - <<EOF +D /tmp/D/2 0755 daemon daemon - - +EOF + +# the content of '2' should be removed +test "$(echo /tmp/D/2/*)" = "/tmp/D/2/*" + +# +# 'e' +# +mkdir -p /tmp/e/2/{d1,d2} +chmod 777 /tmp/e/2 +chmod 777 /tmp/e/2/d* + +systemd-tmpfiles --create - <<EOF +e /tmp/e/1 0755 daemon daemon - - +e /tmp/e/2/* 0755 daemon daemon - - +EOF + +! test -d /tmp/e/1 + +test -d /tmp/e/2 +test $(stat -c %U:%G:%a /tmp/e/2) = "root:root:777" + +test -d /tmp/e/2/d1 +test $(stat -c %U:%G:%a /tmp/e/2/d1) = "daemon:daemon:755" +test -d /tmp/e/2/d2 +test $(stat -c %U:%G:%a /tmp/e/2/d2) = "daemon:daemon:755" + +# 'e' operates on directories only +mkdir -p /tmp/e/3/{d1,d2} +chmod 777 /tmp/e/3 +chmod 777 /tmp/e/3/d* +touch /tmp/e/3/f1 +chmod 644 /tmp/e/3/f1 + +! systemd-tmpfiles --create - <<EOF +e /tmp/e/3/* 0755 daemon daemon - - +EOF + +# the directories should have been processed although systemd-tmpfiles failed +# previously due to the presence of a file. +test -d /tmp/e/3/d1 +test $(stat -c %U:%G:%a /tmp/e/3/d1) = "daemon:daemon:755" +test -d /tmp/e/3/d2 +test $(stat -c %U:%G:%a /tmp/e/3/d2) = "daemon:daemon:755" + +test -f /tmp/e/3/f1 +test $(stat -c %U:%G:%a /tmp/e/3/f1) = "root:root:644" + +# +# 'C' +# + +mkdir /tmp/C/{1,2,3}-origin +touch /tmp/C/{1,2,3}-origin/f1 +chmod 755 /tmp/C/{1,2,3}-origin/f1 + +mkdir /tmp/C/{2,3} +touch /tmp/C/3/f1 + +systemd-tmpfiles --create - <<EOF +C /tmp/C/1 0755 daemon daemon - /tmp/C/1-origin +C /tmp/C/2 0755 daemon daemon - /tmp/C/2-origin +EOF + +test -d /tmp/C/1 +test $(stat -c %U:%G:%a /tmp/C/1/f1) = "daemon:daemon:755" +test -d /tmp/C/2 +test $(stat -c %U:%G:%a /tmp/C/2/f1) = "daemon:daemon:755" + +! systemd-tmpfiles --create - <<EOF +C /tmp/C/3 0755 daemon daemon - /tmp/C/3-origin +EOF + +test $(stat -c %U:%G:%a /tmp/C/3/f1) = "root:root:644" diff --git a/test/TEST-22-TMPFILES/test-03.sh b/test/TEST-22-TMPFILES/test-03.sh new file mode 100755 index 0000000..39a4bad --- /dev/null +++ b/test/TEST-22-TMPFILES/test-03.sh @@ -0,0 +1,236 @@ +#! /bin/bash +# +# Basic tests for types creating/writing files +# + +set -e +set -x + +rm -fr /tmp/{f,F,w} +mkdir /tmp/{f,F,w} +touch /tmp/file-owned-by-root + +# +# 'f' +# +systemd-tmpfiles --create - <<EOF +f /tmp/f/1 0644 - - - - +f /tmp/f/2 0644 - - - This string should be written +EOF + +### '1' should exist and be empty +test -f /tmp/f/1; ! test -s /tmp/f/1 +test $(stat -c %U:%G:%a /tmp/f/1) = "root:root:644" + +test $(stat -c %U:%G:%a /tmp/f/2) = "root:root:644" +test "$(< /tmp/f/2)" = "This string should be written" + +### The perms are supposed to be updated even if the file already exists. +systemd-tmpfiles --create - <<EOF +f /tmp/f/1 0666 daemon daemon - This string should not be written +EOF + +# file should be empty +! test -s /tmp/f/1 +test $(stat -c %U:%G:%a /tmp/f/1) = "daemon:daemon:666" + +### But we shouldn't try to set perms on an existing file which is not a +### regular one. +mkfifo /tmp/f/fifo +chmod 644 /tmp/f/fifo + +! systemd-tmpfiles --create - <<EOF +f /tmp/f/fifo 0666 daemon daemon - This string should not be written +EOF + +test -p /tmp/f/fifo +test $(stat -c %U:%G:%a /tmp/f/fifo) = "root:root:644" + +### 'f' should not follow symlinks. +ln -s missing /tmp/f/dangling +ln -s /tmp/file-owned-by-root /tmp/f/symlink + +! systemd-tmpfiles --create - <<EOF +f /tmp/f/dangling 0644 daemon daemon - - +f /tmp/f/symlink 0644 daemon daemon - - +EOF +! test -e /tmp/f/missing +test $(stat -c %U:%G:%a /tmp/file-owned-by-root) = "root:root:644" + +### Handle read-only filesystem gracefully: we shouldn't fail if the target +### already exists and have the correct perms. +mkdir /tmp/f/rw-fs +mkdir /tmp/f/ro-fs + +touch /tmp/f/rw-fs/foo +chmod 644 /tmp/f/rw-fs/foo + +mount -o bind,ro /tmp/f/rw-fs /tmp/f/ro-fs + +systemd-tmpfiles --create - <<EOF +f /tmp/f/ro-fs/foo 0644 - - - - This string should not be written +EOF +test -f /tmp/f/ro-fs/foo; ! test -s /tmp/f/ro-fs/foo + +! systemd-tmpfiles --create - <<EOF +f /tmp/f/ro-fs/foo 0666 - - - - +EOF +test $(stat -c %U:%G:%a /tmp/f/fifo) = "root:root:644" + +! systemd-tmpfiles --create - <<EOF +f /tmp/f/ro-fs/bar 0644 - - - - +EOF +! test -e /tmp/f/ro-fs/bar + +### 'f' shouldn't follow unsafe paths. +mkdir /tmp/f/daemon +ln -s /root /tmp/f/daemon/unsafe-symlink +chown -R --no-dereference daemon:daemon /tmp/f/daemon + +! systemd-tmpfiles --create - <<EOF +f /tmp/f/daemon/unsafe-symlink/exploit 0644 daemon daemon - - +EOF +! test -e /tmp/f/daemon/unsafe-symlink/exploit + +# +# 'F' +# +echo "This should be truncated" >/tmp/F/truncated +echo "This should be truncated" >/tmp/F/truncated-with-content + +systemd-tmpfiles --create - <<EOF +F /tmp/F/created 0644 - - - - +F /tmp/F/created-with-content 0644 - - - new content +F /tmp/F/truncated 0666 daemon daemon - - +F /tmp/F/truncated-with-content 0666 daemon daemon - new content +EOF + +test -f /tmp/F/created; ! test -s /tmp/F/created +test -f /tmp/F/created-with-content +test "$(< /tmp/F/created-with-content)" = "new content" +test -f /tmp/F/truncated; ! test -s /tmp/F/truncated +test $(stat -c %U:%G:%a /tmp/F/truncated) = "daemon:daemon:666" +test -s /tmp/F/truncated-with-content +test $(stat -c %U:%G:%a /tmp/F/truncated-with-content) = "daemon:daemon:666" + +### We shouldn't try to truncate anything but regular files since the behavior is +### unspecified in the other cases. +mkfifo /tmp/F/fifo + +! systemd-tmpfiles --create - <<EOF +F /tmp/F/fifo 0644 - - - - +EOF + +test -p /tmp/F/fifo + +### 'F' should not follow symlinks. +ln -s missing /tmp/F/dangling +ln -s /tmp/file-owned-by-root /tmp/F/symlink + +! systemd-tmpfiles --create - <<EOF +f /tmp/F/dangling 0644 daemon daemon - - +f /tmp/F/symlink 0644 daemon daemon - - +EOF +! test -e /tmp/F/missing +test $(stat -c %U:%G:%a /tmp/file-owned-by-root) = "root:root:644" + +### Handle read-only filesystem gracefully: we shouldn't fail if the target +### already exists and is empty. +mkdir /tmp/F/rw-fs +mkdir /tmp/F/ro-fs + +touch /tmp/F/rw-fs/foo +chmod 644 /tmp/F/rw-fs/foo + +mount -o bind,ro /tmp/F/rw-fs /tmp/F/ro-fs + +systemd-tmpfiles --create - <<EOF +F /tmp/F/ro-fs/foo 0644 - - - - +EOF +test -f /tmp/F/ro-fs/foo; ! test -s /tmp/F/ro-fs/foo + +echo "truncating is not allowed anymore" >/tmp/F/rw-fs/foo +! systemd-tmpfiles --create - <<EOF +F /tmp/F/ro-fs/foo 0644 - - - - +EOF + +! systemd-tmpfiles --create - <<EOF +F /tmp/F/ro-fs/foo 0644 - - - - This string should not be written +EOF +test -f /tmp/F/ro-fs/foo; ! test -s /tmp/F/ro-fs/foo + +# Trying to change the perms should fail. +>/tmp/F/rw-fs/foo +! systemd-tmpfiles --create - <<EOF +F /tmp/F/ro-fs/foo 0666 - - - - +EOF +test $(stat -c %U:%G:%a /tmp/F/ro-fs/foo) = "root:root:644" + +### Try to create a new file. +! systemd-tmpfiles --create - <<EOF +F /tmp/F/ro-fs/bar 0644 - - - - +EOF +! test -e /tmp/F/ro-fs/bar + +### 'F' shouldn't follow unsafe paths. +mkdir /tmp/F/daemon +ln -s /root /tmp/F/daemon/unsafe-symlink +chown -R --no-dereference daemon:daemon /tmp/F/daemon + +! systemd-tmpfiles --create - <<EOF +F /tmp/F/daemon/unsafe-symlink/exploit 0644 daemon daemon - - +EOF +! test -e /tmp/F/daemon/unsafe-symlink/exploit + +# +# 'w' +# +touch /tmp/w/overwritten + +### nop if the target does not exist. +systemd-tmpfiles --create - <<EOF +w /tmp/w/unexistent 0644 - - - new content +EOF +! test -e /tmp/w/unexistent + +### no argument given -> fails. +! systemd-tmpfiles --create - <<EOF +w /tmp/w/unexistent 0644 - - - - +EOF + +### write into an empty file. +systemd-tmpfiles --create - <<EOF +w /tmp/w/overwritten 0644 - - - old content +EOF +test -f /tmp/w/overwritten +test "$(< /tmp/w/overwritten)" = "old content" + +### new content is overwritten +systemd-tmpfiles --create - <<EOF +w /tmp/w/overwritten 0644 - - - new content +EOF +test -f /tmp/w/overwritten +test "$(< /tmp/w/overwritten)" = "new content" + +### writing into an 'exotic' file sould be allowed. +systemd-tmpfiles --create - <<EOF +w /dev/null - - - - new content +EOF + +### 'w' follows symlinks +ln -s ./overwritten /tmp/w/symlink +systemd-tmpfiles --create - <<EOF +w /tmp/w/symlink - - - - $(readlink -e /tmp/w/symlink) +EOF +readlink -e /tmp/w/symlink +test "$(< /tmp/w/overwritten)" = "/tmp/w/overwritten" + +### 'w' shouldn't follow unsafe paths. +mkdir /tmp/w/daemon +ln -s /root /tmp/w/daemon/unsafe-symlink +chown -R --no-dereference daemon:daemon /tmp/w/daemon + +! systemd-tmpfiles --create - <<EOF +f /tmp/w/daemon/unsafe-symlink/exploit 0644 daemon daemon - - +EOF +! test -e /tmp/w/daemon/unsafe-symlink/exploit diff --git a/test/TEST-22-TMPFILES/test-04.sh b/test/TEST-22-TMPFILES/test-04.sh new file mode 100755 index 0000000..f916086 --- /dev/null +++ b/test/TEST-22-TMPFILES/test-04.sh @@ -0,0 +1,44 @@ +#! /bin/bash +# +# Basic tests for types creating fifos +# + +set -e +set -x + +rm -fr /tmp/p +mkdir /tmp/p +touch /tmp/p/f1 + +systemd-tmpfiles --create - <<EOF +p /tmp/p/fifo1 0666 - - - - +EOF + +test -p /tmp/p/fifo1 +test $(stat -c %U:%G:%a /tmp/p/fifo1) = "root:root:666" + +# it should refuse to overwrite an existing file +! systemd-tmpfiles --create - <<EOF +p /tmp/p/f1 0666 - - - - +EOF + +test -f /tmp/p/f1 + +# unless '+' prefix is used +systemd-tmpfiles --create - <<EOF +p+ /tmp/p/f1 0666 - - - - +EOF + +test -p /tmp/p/f1 +test $(stat -c %U:%G:%a /tmp/p/f1) = "root:root:666" + +# +# Must be fixed +# +# mkdir /tmp/p/daemon +# #ln -s /root /tmp/F/daemon/unsafe-symlink +# chown -R --no-dereference daemon:daemon /tmp/p/daemon +# +# systemd-tmpfiles --create - <<EOF +# p /tmp/p/daemon/fifo2 0666 daemon daemon - - +# EOF diff --git a/test/TEST-22-TMPFILES/test-05.sh b/test/TEST-22-TMPFILES/test-05.sh new file mode 100755 index 0000000..13c4ac8 --- /dev/null +++ b/test/TEST-22-TMPFILES/test-05.sh @@ -0,0 +1,45 @@ +#! /bin/bash + +set -e +set -x + +rm -fr /tmp/{z,Z} +mkdir /tmp/{z,Z} + +# +# 'z' +# +mkdir /tmp/z/d{1,2} +touch /tmp/z/f1 /tmp/z/d1/f11 /tmp/z/d2/f21 + +systemd-tmpfiles --create - <<EOF +z /tmp/z/f1 0755 daemon daemon - - +z /tmp/z/d1 0755 daemon daemon - - +EOF + +test $(stat -c %U:%G /tmp/z/f1) = "daemon:daemon" +test $(stat -c %U:%G /tmp/z/d1) = "daemon:daemon" +test $(stat -c %U:%G /tmp/z/d1/f11) = "root:root" + +systemd-tmpfiles --create - <<EOF +z /tmp/z/d2/* 0755 daemon daemon - - +EOF + +test $(stat -c %U:%G /tmp/z/d2/f21) = "daemon:daemon" + +# +# 'Z' +# +mkdir /tmp/Z/d1 /tmp/Z/d1/d11 +touch /tmp/Z/f1 /tmp/Z/d1/f11 /tmp/Z/d1/d11/f111 + +systemd-tmpfiles --create - <<EOF +Z /tmp/Z/f1 0755 daemon daemon - - +Z /tmp/Z/d1 0755 daemon daemon - - +EOF + +test $(stat -c %U:%G /tmp/Z/f1) = "daemon:daemon" +test $(stat -c %U:%G /tmp/Z/d1) = "daemon:daemon" +test $(stat -c %U:%G /tmp/Z/d1/d11) = "daemon:daemon" +test $(stat -c %U:%G /tmp/Z/d1/f11) = "daemon:daemon" +test $(stat -c %U:%G /tmp/Z/d1/d11/f111) = "daemon:daemon" diff --git a/test/TEST-22-TMPFILES/test-06.sh b/test/TEST-22-TMPFILES/test-06.sh new file mode 100755 index 0000000..cd65ba6 --- /dev/null +++ b/test/TEST-22-TMPFILES/test-06.sh @@ -0,0 +1,38 @@ +#! /bin/bash +# +# Inspired by https://github.com/systemd/systemd/issues/9508 +# + +set -e + +test_snippet() { + systemd-tmpfiles "$@" - <<EOF +d /var/tmp/foobar-test-06 +d /var/tmp/foobar-test-06/important +R /var/tmp/foobar-test-06 +EOF +} + +test_snippet --create --remove +test -d /var/tmp/foobar-test-06 +test -d /var/tmp/foobar-test-06/important + +test_snippet --remove +! test -f /var/tmp/foobar-test-06 +! test -f /var/tmp/foobar-test-06/important + +test_snippet --create +test -d /var/tmp/foobar-test-06 +test -d /var/tmp/foobar-test-06/important + +touch /var/tmp/foobar-test-06/something-else + +test_snippet --create +test -d /var/tmp/foobar-test-06 +test -d /var/tmp/foobar-test-06/important +test -f /var/tmp/foobar-test-06/something-else + +test_snippet --create --remove +test -d /var/tmp/foobar-test-06 +test -d /var/tmp/foobar-test-06/important +! test -f /var/tmp/foobar-test-06/something-else diff --git a/test/TEST-22-TMPFILES/test-07.sh b/test/TEST-22-TMPFILES/test-07.sh new file mode 100755 index 0000000..39c04b9 --- /dev/null +++ b/test/TEST-22-TMPFILES/test-07.sh @@ -0,0 +1,31 @@ +#! /bin/bash +# +# Verifies the issues described by https://github.com/systemd/systemd/issues/10191 +# + +set -e +set -x + +rm -rf /tmp/test-prefix + +mkdir /tmp/test-prefix +touch /tmp/test-prefix/file + +systemd-tmpfiles --remove - <<EOF +r /tmp/test-prefix +r /tmp/test-prefix/file +EOF + +! test -f /tmp/test-prefix/file +! test -f /tmp/test-prefix + +mkdir /tmp/test-prefix +touch /tmp/test-prefix/file + +systemd-tmpfiles --remove - <<EOF +r /tmp/test-prefix/file +r /tmp/test-prefix +EOF + +! test -f /tmp/test-prefix/file +! test -f /tmp/test-prefix diff --git a/test/TEST-22-TMPFILES/test.sh b/test/TEST-22-TMPFILES/test.sh new file mode 100755 index 0000000..13e191b --- /dev/null +++ b/test/TEST-22-TMPFILES/test.sh @@ -0,0 +1,40 @@ +#!/bin/bash +# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +# ex: ts=8 sw=4 sts=4 et filetype=sh +set -e +TEST_DESCRIPTION="Tmpfiles related tests" +TEST_NO_QEMU=1 + +. $TEST_BASE_DIR/test-functions + +test_setup() { + # create the basic filesystem layout + setup_basic_environment + inst_binary mv + inst_binary stat + inst_binary seq + inst_binary xargs + inst_binary mkfifo + inst_binary readlink + + # mask some services that we do not want to run in these tests + ln -fs /dev/null $initdir/etc/systemd/system/systemd-hwdb-update.service + ln -fs /dev/null $initdir/etc/systemd/system/systemd-journal-catalog-update.service + ln -fs /dev/null $initdir/etc/systemd/system/systemd-networkd.service + ln -fs /dev/null $initdir/etc/systemd/system/systemd-networkd.socket + ln -fs /dev/null $initdir/etc/systemd/system/systemd-resolved.service + ln -fs /dev/null $initdir/etc/systemd/system/systemd-machined.service + + # setup the testsuite service + cp testsuite.service $initdir/etc/systemd/system/ + setup_testsuite + + mkdir -p $initdir/testsuite + cp run-tmpfiles-tests.sh $initdir/testsuite/ + cp test-*.sh $initdir/testsuite/ + + # create dedicated rootfs for nspawn (located in $TESTDIR/nspawn-root) + setup_nspawn_root +} + +do_test "$@" diff --git a/test/TEST-22-TMPFILES/testsuite.service b/test/TEST-22-TMPFILES/testsuite.service new file mode 100644 index 0000000..a19174e --- /dev/null +++ b/test/TEST-22-TMPFILES/testsuite.service @@ -0,0 +1,10 @@ +[Unit] +Description=Testsuite service +After=systemd-tmpfiles-setup.service + +[Service] +WorkingDirectory=/testsuite +ExecStart=/testsuite/run-tmpfiles-tests.sh +Type=oneshot +StandardOutput=tty +StandardError=tty |