saltstack / printf IO-error / debianutils / which
After some upgrades, I suddenly noticed unexpected
sh: printf: I/O error
output. Some debugging later, it turns out that
it's the Dash way of informing us of a PIPE error. Apparently salt's
cmd.run
can cause so little output buffering, that the debianutils
which
command can be aborted mid-output.
Not-broken example:
$ which python3 python false | head -n1
/usr/bin/python3
Broken example, through a salt cmd.run
call:
$ salt 'example.com' cmd.run 'which python3 python false | head -n1'
example.com:
/usr/bin/python3
sh: printf: I/O error
It finds and prints /usr/bin/python3
. Then head -n1
is so fast in
closing stdin, that dash notices and reports an I/O error when the
dash builtin printf
tries to write the line /usr/bin/python
to
stdout — which is the stdin that head
closed already.
$ salt 'example.com' cmd.run 'sh -x /bin/which python3 python false | head -n1' 2>&1 | tail -n5
+ [ -f /usr/bin/python ]
+ [ -x /usr/bin/python ]
+ puts /usr/bin/python
+ printf %s\n /usr/bin/python
sh: printf: I/O error
bash reports something similar, but is more pronounced:
$ salt 'example.com' cmd.run 'bash -x /bin/which python3 python false | head -n1' 2>&1 | tail -n5
+ '[' -x /usr/bin/python ']'
/usr/bin/python3
+ puts /usr/bin/python
+ printf '%s\n' /usr/bin/python
/bin/which: line 10: printf: write error: Broken pipe
While I haven't delved into the reason why this happens in these salt
calls only, I think the problem lies with debianutils which
.
Something like this would fix things:
--- /bin/which 2020-04-29 14:40:26.032397533 +0200
+++ /bin/which-fixed 2020-04-29 14:56:11.518941600 +0200
@@ -7,7 +7,7 @@ if test -n "$KSH_VERSION"; then
}
else
puts() {
- printf '%s\n' "$*"
+ printf '%s\n' "$*" 2>/dev/null
}
fi
Trapping the PIPE
signal would not work, as the signal is handled
already — by a handler that prints "write error: Broken pipe".
$ sh -c 'trap exit PIPE; echo foo; sleep 1; echo bar' | true
sh: echo: I/O error
$ bash -c 'trap exit PIPE; echo foo; sleep 1; echo bar' | true
bash: line 0: echo: write error: Broken pipe
Oh well. At least this explains the odd messages.