GNU bug report logs -
#76282
Signal handling (like SIGINT) and guix shell --container: PID 1
Previous Next
To reply to this bug, email your comments to 76282 AT debbugs.gnu.org.
Toggle the display of automated, internal messages from the tracker.
Report forwarded
to
bug-guix <at> gnu.org
:
bug#76282
; Package
guix
.
(Fri, 14 Feb 2025 09:59:01 GMT)
Full text and
rfc822 format available.
Acknowledgement sent
to
ingar <at> onionmail.info
:
New bug report received and forwarded. Copy sent to
bug-guix <at> gnu.org
.
(Fri, 14 Feb 2025 09:59:01 GMT)
Full text and
rfc822 format available.
Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):
# Bug and reproducer
There is a discrepancy between (expected) signal handling of programs when running them directly,
vs. using `guix shell --container -- program`.
An example program can be used to illustrate:
```
; test.scm
; Test guix shell to catch ctrl-C signal
(while #t
(display "In infinite loop...\n")
(sleep 1))
```
It uses guile, since bash does some extra funky signal-related things, which not every program does.
My usecase is `typst watch`, a program which only exits on ctrl-C, else it loops.
1) Run as `guile test.scm` and use ctrl-C
It terminates as expected.
Same when using `guix shell --container guile` and then `guile test.scm` inside the container shell.
2) Run `guix shell --container guile -- guile test.scm` and use ctrl-C
It doesn't terminate as expected. Only method is to get the PID and use SIGKILL (`kill -KILL <pid>`)
# Reason (as far as I know):
`guix shell --container -- program` starts the program with PID 1 in it's dedicated namespace.
However, PID 1 is handled specially by the kernel when it comes to signal handlers.
Only explicitly registered handlers are used and the default handlers
are not executed for PID 1 (except SIGKILL & SIGSTOP).
You can use `cat /proc/<PID in parent namespace>/status | grep ^NStgid`
to verify the PID seen by the process (rightmost number).
# Sources:
- https://lwn.net/Articles/532748/ ("Signals and the init process")
- In docker: https://ddanilov.me/how-signals-are-handled-in-a-docker-container
- Docker '--init' flag: https://docs.docker.com/reference/cli/docker/container/run/#init
- bash doing funky things: https://colinxy.github.io/computer-science/2017/01/27/bash-handles-signals.html
- Check namespace PID: https://unix.stackexchange.com/questions/625520/is-it-possible-to-check-the-process-id-of-child-in-different-pid-namespace
# Possible fixes:
- Document the behaviour (and nothing more?)
This is the minimum, and I'll see if I can send a patch.
This lengthy bugreport is due to undocumented & unexpected behaviour, leading down a rabbit hole ;)
- Add an `--init` argument, like in docker?
This adds some minimal init process to forward signals and reap processes...
Not sure how minimal the shepherd is?
- Do this by default, and add a --no-init argument?
- ...
# Workaround:
Add "tini" or "catatonit" as a minimal PID 1 process.
- guix shell --container guile tini -- tini guile test.scm
- guix shell --container guile catatonit -- catatonit guile test.scm
Best regards,
Ingar
Information forwarded
to
bug-guix <at> gnu.org
:
bug#76282
; Package
guix
.
(Sat, 31 May 2025 14:51:02 GMT)
Full text and
rfc822 format available.
Message #8 received at 76282 <at> debbugs.gnu.org (full text, mbox):
Hi,
ingar <at> onionmail.info writes:
> # Bug and reproducer
> There is a discrepancy between (expected) signal handling of programs when running them directly,
> vs. using `guix shell --container -- program`.
>
> An example program can be used to illustrate:
> ```
> ; test.scm
> ; Test guix shell to catch ctrl-C signal
>
> (while #t
> (display "In infinite loop...\n")
> (sleep 1))
> ```
>
> It uses guile, since bash does some extra funky signal-related things, which not every program does.
> My usecase is `typst watch`, a program which only exits on ctrl-C, else it loops.
>
> 1) Run as `guile test.scm` and use ctrl-C
> It terminates as expected.
> Same when using `guix shell --container guile` and then `guile test.scm` inside the container shell.
> 2) Run `guix shell --container guile -- guile test.scm` and use ctrl-C
> It doesn't terminate as expected. Only method is to get the PID and use SIGKILL (`kill -KILL <pid>`)
[...]
Thank you for the detailed investigation! I just encountered this
behavior attempting to build forgejo in a containerized environment,
using the following manifest.scm file:
```
(specifications->manifest
(list "coreutils"
"findutils"
"gcc-toolchain"
"git-minimal"
"go"
"grep"
"make"
"node"
"nss-certs"
"sed"))
```
The problem curiously only occurs when '--' is used to launch the
application; otherwise it works normally, e.g.:
--8<---------------cut here---------------start------------->8---
$ guix shell -CNF -m manifest.scm
[env]$ env GOPATH=/tmp TAGS="bindata timetzdata sqlite sqlite_unlock_notify" make build
go: downloading go1.24.3 (linux/amd64)
^C
[env]$ # aborted correctly
--8<---------------cut here---------------end--------------->8---
Your analysis appears correct; the above 'make' runs with PID 3.
--8<---------------cut here---------------start------------->8---
maxim <at> terra ~/src/forgejo$ guix shell -CNF -m manifest.scm -- env GOPATH=/tmp TAGS="bindata timetzdata sqlite sqlite_unlock_notify" make build
go: downloading go1.24.3 (linux/amd64)
^Cgo: downloading go1.24.3 (linux/amd64)
^Cgo: downloading go1.24.3 (linux/amd64)
^Cgo: downloading go1.24.3 (linux/amd64)
^Cgo: downloading go1.24.3 (linux/amd64)
^CForgejo requires Go 1.24 or greater to build. You can get it at https://go.dev/dl/
make: *** [Makefile:297: go-check] Error 1
^C^C^C^C^C^C^C^C^C
# doesn't abort, need kill -9 $pid
--8<---------------cut here---------------end--------------->8---
This doesn't handle signals as expected because it runs as PID 1. I
agree this needs be documented or better, handled with --init ala
docker.
--
Thanks,
Maxim
Information forwarded
to
bug-guix <at> gnu.org
:
bug#76282
; Package
guix
.
(Sun, 01 Jun 2025 22:13:02 GMT)
Full text and
rfc822 format available.
Message #11 received at 76282 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
Hello,
Maxim Cournoyer <maxim.cournoyer <at> gmail.com> writes:
> Your analysis appears correct; the above 'make' runs with PID 3.
>
> --8<---------------cut here---------------start------------->8---
> maxim <at> terra ~/src/forgejo$ guix shell -CNF -m manifest.scm -- env GOPATH=/tmp TAGS="bindata timetzdata sqlite sqlite_unlock_notify" make build
> go: downloading go1.24.3 (linux/amd64)
> ^Cgo: downloading go1.24.3 (linux/amd64)
> ^Cgo: downloading go1.24.3 (linux/amd64)
> ^Cgo: downloading go1.24.3 (linux/amd64)
> ^Cgo: downloading go1.24.3 (linux/amd64)
> ^CForgejo requires Go 1.24 or greater to build. You can get it at https://go.dev/dl/
> make: *** [Makefile:297: go-check] Error 1
> ^C^C^C^C^C^C^C^C^C
> # doesn't abort, need kill -9 $pid
> --8<---------------cut here---------------end--------------->8---
>
> This doesn't handle signals as expected because it runs as PID 1. I
> agree this needs be documented or better, handled with --init ala
> docker.
I didn’t follow closely but how about this:
[Message part 2 (text/x-patch, inline)]
diff --git a/guix/scripts/environment.scm b/guix/scripts/environment.scm
index 1c2d222c748..43cfffbd9cb 100644
--- a/guix/scripts/environment.scm
+++ b/guix/scripts/environment.scm
@@ -980,6 +980,11 @@ (define* (launch-environment/container #:key command bash user user-mappings
;; Call an additional setup procedure, if provided.
(when setup-hook
(setup-hook profile)))
+
+ ;; Do not run the shell as PID 1 since that prevents proper signal
+ ;; handling (?).
+ #:child-is-pid1? #f
+
#:guest-uid uid
#:guest-gid gid
#:writable-root? writable-root?
[Message part 3 (text/plain, inline)]
Thanks,
Ludo’.
Information forwarded
to
bug-guix <at> gnu.org
:
bug#76282
; Package
guix
.
(Mon, 02 Jun 2025 19:25:02 GMT)
Full text and
rfc822 format available.
Message #14 received at 76282 <at> debbugs.gnu.org (full text, mbox):
Ludovic Courtès <ludo <at> gnu.org> writes:
> I didn’t follow closely but how about this:
>
> diff --git a/guix/scripts/environment.scm b/guix/scripts/environment.scm
> index 1c2d222c748..43cfffbd9cb 100644
> --- a/guix/scripts/environment.scm
> +++ b/guix/scripts/environment.scm
> @@ -980,6 +980,11 @@ (define* (launch-environment/container #:key command bash user user-mappings
> ;; Call an additional setup procedure, if provided.
> (when setup-hook
> (setup-hook profile)))
> +
> + ;; Do not run the shell as PID 1 since that prevents proper signal
> + ;; handling (?).
> + #:child-is-pid1? #f
> +
> #:guest-uid uid
> #:guest-gid gid
> #:writable-root? writable-root?
Seems to fix the issue for me, nice.
Reviewed-by: Tomas Volf <~@wolfsden.cz>
Tomas
--
There are only two hard things in Computer Science:
cache invalidation, naming things and off-by-one errors.
This bug report was last modified 3 days ago.
Previous Next
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.