environment variable.
[bug introduced in coreutils-8.26]
+ 'timeout' no longer exits abruptly when its parent is the init process, e.g.,
+ when started by the entrypoint of a container.
+ [bug introduced in coreutils-9.10]
+
** New Features
'date --date' now parses dot delimited dd.mm.yy format common in Europe.
'shuf -i' now operates up to two times faster on systems with unlocked stdio
functions.
+ 'timeout' now properly detects when it is reparented by a subreaper process on
+ Linux instead of init, e.g., the 'systemd --user' process.
+
'wc -l' now operates up to four and a half times faster on hosts that support
Neon instructions.
sigset_t orig_set;
block_cleanup_and_chld (term_signal, &orig_set);
+ /* Get the parent process ID so we can check if we are reparented later.
+ Traditionally processes would be reparented to init. On Linux a process
+ can be come a subreaper using PR_SET_CHILD_SUBREAPER to fulfill the role
+ of init for child processes, as is done by systemd(1). */
+ pid_t timeout_pid = getpid ();
+
/* We cannot use posix_spawn here since the child will have an exit status of
127 for any failure. If implemented through fork and exec, posix_spawn
will return successfully and 'timeout' will have no way to determine if it
/* Add protection if the parent dies without signaling child. */
prctl (PR_SET_PDEATHSIG, term_signal);
#endif
- /* If we're already reparented to init, don't proceed. */
- if (getppid () == 1)
+ /* If we're already reparented to init, don't proceed. Be aware that
+ 'timeout' may actually be started by the init process. E.g., when
+ the shell is the entrypoint to a container. */
+ if (getppid () != timeout_pid)
return EXIT_CANCELED;
/* Restore signal mask for child. */
tests/test/test-diag.pl \
tests/test/test-file.sh \
tests/misc/time-style.sh \
+ tests/timeout/init-parent.sh \
tests/timeout/timeout.sh \
tests/timeout/timeout-blocked.pl \
tests/timeout/timeout-group.sh \
--- /dev/null
+#!/bin/sh
+# Test the behavior of 'timeout' with the init process as its parent.
+
+# Copyright (C) 2026 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ timeout
+
+newpids () { unshare --pid --fork --map-root-user "$@"; }
+
+newpids true || skip_ 'unshare --pid --fork --map-root-user is unavailable'
+
+# In coreutils-9.10 'timeout' would exit immediately if its parent was the init
+# process. This was discovered because Docker entrypoints have a process ID
+# of 1.
+newpids timeout .1 sleep 10
+test $? = 124 || fail=1
+
+Exit $fail