Ever since I switched my system to systemd, makewhatis (which is ran by default by a daily cron job) gives several errors like the following: bzcat: I/O or other error, bailing out. Possible reason follows. bzcat: Broken pipe Input file = /usr/share/man/man1/./curl.1.bz2, output file = (stdout) This only happens the first time makewhatis is ran after a package was installed (curl in this case). If I remove the -u switch from /etc/cron.daily/makewhatis then it happens every time (that's because the removal of this switch forces makewhatis to scan all man pages, not just the new ones). This does not happen when I manually execute makewhatis myself and it does not happen when makewhatis is executed by vixie-cron when run under openrc. Thus I conclude that it has to do with systemd.
Forgot to mention that I also get the errors when I run makewhatis using a systemd unit file like this: [Service] ExecStart=/usr/sbin/makewhatis that is, bypassing vixie-cron completely. This makes me rule out the possibility that it is vixie-cron's fault.
Ok, I found the culprit, it's systemd as I suspected. What happens is that makewhatis calls bzcat in order to uncompress the compressed man pages and after it reads the first few lines it closes the pipe. Under systemd, this causes the bzcat process to receive a SIGPIPE signal and its handler then produces the above error message. When makewhatis is ran directly in a terminal or under openrc this does not happen.
Ok, so systemd offers an option for the [Service] section called IgnoreSIGPIPE. Setting it to "no" (the default is yes) in the vixie-cron unit file fixes the issue. What's the best solution here?
Do I understand correctly that you are concerned of it happening when vixie-cron is spawned by systemd, correct?
(In reply to Michał Górny from comment #4) > Do I understand correctly that you are concerned of it happening when > vixie-cron is spawned by systemd, correct? Yes. It is a systemd bug, not a sys-apps/man bug.
If it's a bug, then what is the fix?
Maybe sysvinit or start-stop-daemon calls signal(SIGPIPE, SIG_IGN) at some point, and this gets inherited by cron?
Here's a more technical explanation of what happens: makewhatis scans all files in /usr/share/man/ and it reads the first few lines from each of them. Because they are compressed, it uses (bz|z|xz)cat to do that. Sort of like this: bzcat /usr/share/man/man1/emerge.1.bz2 | head Now if you run the above command in a terminal, it will not produce any error/warning. But if you run the following: perl -e '$SIG{PIPE}="IGNORE"; system "bzcat /usr/share/man/man1/emerge.1.bz2 | head"' you will get the following error: bzcat: I/O or other error, bailing out. Possible reason follows. bzcat: Broken pipe Input file = /usr/share/man/man1/emerge.1.bz2, output file = (stdout) That's exactly what happens with systemd; it ignores SIGPIPE by default [1]. So when systemd executes vixie-cron then vixie-cron inherits this behavior. Then vixie-cron in turn executes makewhatit which executes bzcat. [1] http://cgit.freedesktop.org/systemd/systemd/commit/?id=353e12c2f4a9e96a47eb80b80d2ffb7bc1d44a1b
(In reply to Mike Gilbert from comment #7) > Maybe sysvinit or start-stop-daemon calls signal(SIGPIPE, SIG_IGN) at some > point, and this gets inherited by cron? Oops, I didn't see that comment before I posted my previous comment. Yes, someone does call signal(SIGPIPE, SIG_IGN) and that someone is systemd. It seems that bzcat behaves in the opposite way I would naively expect: If SIGPIPE is being ignored by its caller then it complains. If the signal handler of SIGPIPE is set to SIG_DFL then it does not complain at all. You can verify that by trying the following two commands: perl -e '$SIG{PIPE}="IGNORE"; system "bzcat /usr/share/man/man1/emerge.1.bz2 | head"' perl -e '$SIG{PIPE}="DEFAULT"; system "bzcat /usr/share/man/man1/emerge.1.bz2 | head"'
(In reply to redneb from comment #9) Ah, I had it reversed. Yeah, you have it nailed. So, either vixie-cron needs to reset the SIGPIPE handler to SIG_DFL, or we should update the unit to set IgnoreSIGPIPE=no.
FWIW, Fedora's fork of vixie-cron (sys-process/cronie) resets SIGPIPE for child processes. https://git.fedorahosted.org/cgit/cronie.git/commit/?id=ee4cbe7659ede3f61db18cc922ee0e27268a8579
Reassigning to vixie-cron maintainers.
But shouldn't makewhatis be ready to run with whatever signal handlers are installed on its parent? IMO if it relies on given behavior, it should set signal handlers itself.
(In reply to Michał Górny from comment #13) Hmm... I suppose it technically should. However, since cron daemons invoke random shell commands which often involve pipelines, it seems like it a more sensible default would be a good idea.
Sure but I think we should fix it in all the places.
I did some digging. makewhatis is a shell script, so I think the only way it can set signal handlers is using the trap built-in. POSIX says this: http://pubs.opengroup.org/onlinepubs/009695399/utilities/trap.html "Signals that were ignored on entry to a non-interactive shell cannot be trapped or reset, although no error need be reported when attempting to do so." So, to reset the SIGPIPE handler, makewhatis would need to be rewritten in a more complete programming language, or it would have to invoke some helper utility to reset the signal and start the pipelined processes.
Hmm, so everything that spawns shell should reset ignored signals to defaults for consistency, correct?
Yeah, that seems to be the case.
(In reply to Mike Gilbert from comment #16) that's the old POSIX spec. here's the new link: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#trap you should update your bookmarks accordingly as there's lots of goodies in the newer one (not that it matters for this specific bug).
+ 24 Apr 2015; Mike Gilbert <floppym@gentoo.org> files/vixie-cron.service: + Set IgnoreSIGPIPE=false, bug 482758. I'm not sure this is worth a revbump.