Summary: | daemon(8) using -P swallows signals such as SIGHUP instead of propagating them | ||||||
---|---|---|---|---|---|---|---|
Product: | Base System | Reporter: | Dave Cottlehuber <dch> | ||||
Component: | bin | Assignee: | freebsd-bugs (Nobody) <bugs> | ||||
Status: | Open --- | ||||||
Severity: | Affects Some People | CC: | crest, feld, grahamperrin, ihor, mjg, pat, prj | ||||
Priority: | --- | ||||||
Version: | 10.3-RELEASE | ||||||
Hardware: | Any | ||||||
OS: | Any | ||||||
Attachments: |
|
Description
Dave Cottlehuber
2016-09-19 17:11:00 UTC
To elaborate on my general thoughts; The issue with just passing signals through daemon is: what if we want to signal daemon? Whoops. The other possibility is to use uncommonly used signals but then all you've got is SIGUSR1 and SIGUSR2 without violating sanity. Obviously, that is not an acceptable solution either. So my thought is that a user who wishes for daemon(8) to pass signals to the child needs to provide two explicit arguments at runtime. First, the existing child pid argument -p. Second, the flag -s 'signal passing.' This would tell daemon to simply pass through all signals verbatim to the PID contained within -p. (-s would conflict with -r as well.) This means it's an explicit user-initiated behavior change, rather than function change. Obviously, this then presents the problem: how to signal daemon itself. That I do not have an elegant solution for. My initial thought was to have a socket equivalent to -P where the user could simply echo the desired signal number to. e.g. "echo '9' > /var/run/daemon/234.pid" - which isn't exactly optimal either. However, this might be a more workable solution for child signalling perhaps? Thoughts and feedback definitely appreciated. adding mjg as he is reviewing other daemon related things for me Created attachment 175049 [details] patch to daemon.c v1 Thanks prj@. I'm not sure what usage daemon gets outside ports tree, but I assume hooking it up to rc.d framework services is the major use case. Looking at daemon.c it has a special case to forward SIGTERM, but nothing for SIGHUP so I assume by default SIGHUP does Something like this? see pretty diff https://git.io/vi7j2 BTW I can see the advantages of daemon accepting all signals but then the change becomes more complex - the original issue was allowing the SIGHUP from `service widget reload` to be passed through. Apparently /etc/rc.subr allows passing arbitrary signals through if defined in the widget's script: reload) if [ -z "$rc_pid" ]; then _run_rc_notrunning return 1 fi _run_rc_precmd || return 1 _doit=$(_run_rc_killcmd "${sig_reload:-HUP}") _run_rc_doit "$_doit" || return 1 _run_rc_postcmd ;; viz: japanese/ebnetd/files/ebhttpd.in:sig_reload=SIGHUP japanese/ebnetd/files/ebnetd.in:sig_reload=SIGHUP japanese/ebnetd/files/ndtpd.in:sig_reload=SIGHUP lang/php55/files/php-fpm.in:sig_reload="USR2" lang/php56/files/php-fpm.in:sig_reload="USR2" lang/php70/files/php-fpm.in:sig_reload="USR2" mail/mimedefang/files/patch-examples__init-script.in: sig_reload="INT" mail/opendkim/files/milter-opendkim.in:sig_reload="USR1" mail/rspamd-devel/files/rspamd_redirector.in:sig_reload="USR1" mail/rspamd/files/rspamd.in:sig_reload="HUP" mail/rspamd/files/rspamd_redirector.in:sig_reload="USR1" net-mgmt/icinga-core/files/icinga.in:sig_reload=HUP net-mgmt/icinga2/files/icinga2.in:sig_reload=HUP net-mgmt/nagios/files/nagios.in:sig_reload=HUP net-mgmt/nagios4/files/nagios.in:sig_reload=HUP net-mgmt/nrpe/files/nrpe2.in:sig_reload=HUP net/exabgp/files/exabgp.in:sig_reload="USR1" net/exaddos/files/exaddos.in:sig_reload="USR1" net/vncreflector/files/vncreflector.in:sig_reload=USR2 security/openvpn-devel/files/openvpn.in: sig_reload=USR1 run_rc_command reload security/openvpn/files/openvpn.in: sig_reload=USR1 run_rc_command reload security/openvpn/files/openvpn.in: sig_reload=USR2 sysutils/burp/files/burp.in:sig_reload="HUP" sysutils/sec/files/sec.in:sig_reload=HUP www/kannel-sqlbox/files/kannel_sqlbox.in:sig_reload=SIGUSR1 www/kannel/files/kannel_bearerbox.in:sig_reload=SIGUSR1 www/kannel/files/kannel_smsbox.in:sig_reload=SIGUSR1 www/kannel/files/kannel_wapbox.in:sig_reload=SIGUSR1 www/lighttpd/files/lighttpd.in: sig_reload="INT" www/nghttp2/files/nghttpx.in:sig_reload="USR2" # exec-self reload; Note: future versions have SIGHUP to reload www/nghttp2/files/nghttpx.in: sig_reload="USR1" www/nginx-devel/files/nginx.in: sig_reload="USR2" www/nginx-devel/files/nginx.in: sig_reload="QUIT" www/nginx/files/nginx.in: sig_reload="USR2" www/nginx/files/nginx.in: sig_reload="QUIT" www/ufdbguard/files/ufdbguardd.in: sig_reload=USR1 www/ufdbguard/files/ufdbguardd.in: sig_reload=USR2 www/uwsgi/files/uwsgi.in: sig_reload="TERM" TLDR a generalised solution might be better. Yes; after some discussion with feld@ I actually realized that this issue is the actual root cause of problems I've been having with socat in my own environment. The 'proper' way to terminate socat is SIGKILL, not SIGTERM. Right now it sounds like daemon(8) isn't even working as intended and desired; now we've got cases that are exposing further shortcomings. (And no, I'm not using rc.subr.) What's supposed to happen is that when I issue a SIGKILL to daemon(8) it is supposed to pass that SIGKILL through to the child immediately, then terminate itself. Basically any signal should be passed through verbatim, then handled by daemon(8) itself. That doesn't appear to be what's happening; at least not reliably. So, it seems to be a mix of bug and shortcoming. This definitely warrants some further discussion to see what the preferred resolution to both issues would be. prj@ I agree that the desired behaviour in most cases is likely to be to pass the signal on (possibly referencing some config or masking list) and then handle the signal in daemon as required. # workaround /bin/pkill -HUP -U riemann java works for me. I am working on daemon improvements and this feature is planned to be added once transition to kqueue is finished. After reading all comments I take the side of Phillip R. Jaenke (prj) Different services expect different signals, so creating a mechanism to pass signals to a child leaves a question "how to signal daemon" open. It is obviously a bad design. The ideal solution would be to have a socket that daemon listens for various commands. I need to run this idea by kevans to make sure he has no objections for this work. This might or might not be considered a scope creep. And if it is - I am going to spin off a new supervisor daemon. With sockets, config files, blackjack and hookers :) In the meanwhile It is possible make `service` to send signal to the child. There are 2 ways: 1) In your rc script pidfile=/path/to/child/pid command="/usr/sbin/daemon" command_args="--child-pidfile $pidfile .... rc framework on `service foo reload` should send SIGHUP to the process identified by $pidfile 2) There is a way to add custom commands to the rc script: extra_commands="foobarnate" pidfile=/path/to/child/pid command="/usr/sbin/daemon" command_args="--child-pidfile $pidfile .... myservice_foobarnate() { kill -SIGUSR1 $pidfile } So you can run `service myservice foobarnate` to execute completely custom logic. See /etc/rc.d/ipfilter for a concrete example of custom commands Ok, after talking to kevans@ we are not going to be adding a socket to daemon. So this is a WONTFIX. There are several process supervisors available in ports that could be used instead of daemon. It should be enough to declare a runtime dependency on it and use it instead of daemon in your rc.d script(s). The better ones e.g. s6/runit/daemontools support sending signals to the supervised processes and can capture their stdout/stderr into a pipe connected to a logging process this can be a proxy to syslog (or something better). |