|Keep It Simple, Stupid|
Re^5: A few questions regarding Proc::Daemonby afoken (Monsignor)
|on Nov 09, 2013 at 22:33 UTC||Need Help??|
Ohhh, stupid me! Sorry, I thought you were saying to replace upstart, init, systemd, etc with daemontools.
Yes, this is possible and can be useful, but it is rarely used.
I just figured that the daemon would need to understand stop, status, etc in order to shutdown gracefully, give a status, and so on.
I guess I was wrong in this assumption?
No. The daemon has to receive some kind of message that tells it to shutdown, re-read the configuration, deliver some status, and so on. UNIX systems typically use signals for that purpose:
Tools like daemontools send those signals to your daemon process. On a system with a classic init, your daemon (or its startup script) needs to write a PID file so that you know the PID of your daemon: kill -HUP `cat /var/run/my-daemon.pid`. Daemontools and the other tools know the PID because the daemon runs as a child process of the monitor process (supervise in case of daemontools), and you ask the monitor process to send a signal to your daemon process (svc -h /service/my-daemon). The advantage over PID files is that there is no race condition and no problem with an unclean shutdown.
Daemontools were written by djb, who has some very strange opinions about errno. gcc on Linux will simply not compile his code, because djb insists on declaring errno as extern int. This is plain wrong, so you need to change that to #include <errno.h>. (See the djb way - errno patches) There are patches available for this, and a second patch that adds the signals QUIT, USR1 and USR2 to daemontools, see the djb way - daemontools - installation.
runit works nearly the same, except that the program names are a little bit different (svscanboot is runit, svscan is runsvdir, supervise is runsv, svc is sv, multilog is svlogd). And of course: no trouble with errno.
The point here is that your daemon contains code to handle the signals, but no code to send those signals. This is the job of daemontools, runit, or the start script.
Configuration in the djb way is done by passing environment variables to your daemon. The envdir program reads them from a directory of files, one file per variable. Or, the run script simply sets them. Of course, you can still read your own configuration file and ignore the environment variables.
Dropping privileges is also done outside the daemon, using the setuidgid program.
Running a TCP service on a privileged port (0-1023) without root privileges is possible, using ucspi-tcp. These programs (mainly tcpserver) open a socket as root, and pass the socket though setuidgid to the daemon running without root privileges - simply as STDIN and STDOUT, just like inetd does.
SSL requires no changes to the daemon, just replace tcpserver with sslserver from ucspi-ssl.
Of course, you can do all of this in your daemon code. But daemontools and friends are there to avoid all of that extra work.
Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)