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 attie@attie.co.uk > ./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 <attie@attie.co.uk>"
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 <attie@attie.co.uk>"
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 attie@attie.co.uk > ./myfile.gpg
$ gpg -qd < ./myfile.gpg > /dev/null
You need a passphrase to unlock the secret key for
user: "Attie Grande <attie@attie.co.uk>"
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 attie@attie.co.uk > ./myfile.gpg
$ gpg -qd < ./myfile.gpg > /dev/null
You need a passphrase to unlock the secret key for
user: "Attie Grande <attie@attie.co.uk>"
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 attie@attie.co.uk > ./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 <attie@attie.co.uk>"
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?