I recently came across daemon(1), a neat little GPL utility that will turn any program into a proper daemon. Doing this usually requires a series of calls to semi-obscure POSIX API functions. This is not hard, but only fun the first few times you do it.
Say I have random Perl script
foo.pl that I want to run in the background as a daemon. This can be done with a simple command like:
Presuming, of course, that
foo.pl is in my
fork(), become a session leader,
chdir() to /, and do a bunch of other stuff that is well described in Chapter 13 of Advanced Programming in the Unix Environment.
daemon then runs
foo.pl and waits for it to terminate.
Things now get interesting because I can do:
Which will exit immediately with an exit status of 0 if
foo.pl is running and 1 if it’s not. Once
foo.pl has served my nefarious purposes, it can be easily stopped:
daemon can do many other useful things that are well described in the man page.
daemon so much I thought I’d use it to run a daemon on a remote host from a Perl script. Doing this requires a bit of Perl that looks something like:
`ssh remotehost daemon –pidfile $dir/foo.pid
–name foo-daemon $dir/foo.pl`;
The only problem with this is that it doesn’t work.
daemon decides that it’s not going to
fork(), so my Perl script waits for
foo.pl to exit rather than running it in the background. A bit of rumaging around the source soon revealed the reason why.
daemon plays nice with
inetd(8), and it knows not to become a daemon if started by either of these programs- essentially because such things will have already been taken care of.
The check to see if
daemon has been started by
inetd(8) is actually done in
libslack and is implemented by the following function:
size_t optlen = sizeof(int);
return (getsockopt(STDIN_FILENO, SOL_SOCKET,
SO_TYPE, &optval, (void *)&optlen) == 0);
So if standard input is a socket which is apparently the case when daemon has been run by
sshd(8), daemon assumes it has been started from
inetd(8) and doesn’t do its whole daemonization routine. Annoying. I tested this by modifying
daemon_started_by_inetd() so that it always returns 0, and sure enough things worked fine.
Personally I think this is a perfect excuse for a new option for
daemon. I’ll have to ask if they will accept a patch. I am a little surprised that no-one has run into this before- I doubt that I’m the only guy writing grubby little Perl scripts that need to run stuff on multiple hosts. More likely there are other ways to do it just as well, or better.