While answering this question, I was unable to fully explain how signals propagate through a pipeline.
Consider the following examples.
Using timeout
as the first element in the pipeline
This causes gpg
to bail out having caught the SIGTERM
that was delivered to cat
, by timeout
, leaving a broken file.
$ timeout 1 cat /dev/urandom | gpg -er [email protected] > ./myfile.gpg
gpg: Terminated caught ... exiting
Terminated
$ gpg -d < ./myfile.gpg > /dev/null
You need a passphrase to unlock the secret key for
user: "Attie Grande <[email protected]>"
4096-bit RSA key, ID C9AEA6AE, created 2016-12-13 (main key ID 7826F053)
gpg: encrypted with 4096-bit RSA key, ID C9AEA6AE, created 2016-12-13
"Attie Grande <[email protected]>"
gpg: block_filter 0x145e790: read error (size=14775,a->size=14775)
gpg: block_filter 0x145f110: read error (size=10710,a->size=10710)
gpg: WARNING: encrypted message has been manipulated!
gpg: block_filter: pending bytes!
gpg: block_filter: pending bytes!
Using timeout
in the middle of the pipeline
This works as expected - gpg
exits cleanly.
$ cat /dev/urandom | timeout 1 cat | gpg -er [email protected] > ./myfile.gpg
$ gpg -qd < ./myfile.gpg > /dev/null
You need a passphrase to unlock the secret key for
user: "Attie Grande <[email protected]>"
4096-bit RSA key, ID C9AEA6AE, created 2016-12-13 (main key ID 7826F053)
Using SIGUSR1
instead of SIGTERM
Again, this works as expected - gpg
exits cleanly. I expect because cat
quits on SIGUSR1
, while gpg
ignores it.
$ timeout -sUSR1 1 cat /dev/urandom | gpg -er [email protected] > ./myfile.gpg
$ gpg -qd < ./myfile.gpg > /dev/null
You need a passphrase to unlock the secret key for
user: "Attie Grande <[email protected]>"
4096-bit RSA key, ID C9AEA6AE, created 2016-12-13 (main key ID 7826F053)
Using process substitution
Again, this works - though I hadn't expected it to.
$ gpg -er [email protected] > ./myfile.gpg < <( timeout 1 cat /dev/urandom )
$ gpg -qd < ./myfile.gpg > /dev/null
You need a passphrase to unlock the secret key for
user: "Attie Grande <[email protected]>"
4096-bit RSA key, ID C9AEA6AE, created 2016-12-13 (main key ID 7826F053)
I can only presume that the signal of the first element in the pipeline is propagated through to the rest of the elements in the pipeline (even separating them with timeout cat | cat | gpg
fails).
I've had a look for documentation, and had a play with set -e
, set -o pipefail
but they didn't act as I was expecting.
- What is actually going on?
- What are the semantics?
- Do we have any control over this?
- Is there a better way than moving the signal-generating-process form the front of the pipeline?