in reply to Re^2: Daemon::Control pid-files
in thread Daemon::Control pid-files

Suggestions on simpler ways to make a perl-script run at boot time are welcome.

Well, click on any but the first link in the posting you replied to. I suggest to start with the djb way. Yes, that text does not mention perl at all, the example is a stupid daemon written as a shell script, in just 12 lines of code.

But that does not matter at all. You write your "daemon" not to fork to background, and to write warnings and errors to STDERR (just use warn and die). STDIN and STDOUT may be used for other purposes, or you ignore STDIN and don't write to STDOUT. You may also write debug messages to STDOUT, and decide in the starting script (the run script) if you want to merge STDOUT and STDERR (during debugging) or if you want to discard STDOUT (i.e. redirect to /dev/null, for production use).

Daemontools take care of reliable logging and automatic log rotation (via svscan, supervise, multilog; just copy and paste log/run from "the djb way"), restarting (implicit in supervise), sending signals to your program (svc via supervise), starting and stopping your program (svc via supervise, down flag file).

Daemontools have a little learning curve, in that they chain several programs together in an unusual way. Each program does only one thing, removes its arguments from the command line, and execs the next program on the command line. Don't worry, it looks a little bit strange, but it works very nice.


This is a working example from my server to start the fetchmail service (file /service/fetchmail/run):

#!/bin/sh exec 2>&1 echo "*** Starting fetchmail service ...***" if [ "$(pidof exim)" = "" ] ; then echo "exim not running, exiting" exit 1 fi exec \ env FETCHMAILHOME="./pid" \ setuidgid fetchmail \ fetchmail -f ./fetchmail.conf --nodetach

STDOUT and STDERR are merged, a log line is written, if exim (my mail server) is not running, the run script just exits. supervise will restart it after a second, at that time, exim is hopefully running.

Now the chaining part. Note that everything after exec is essentially one long command line:

The shell interpreting the run script sees this: exec env FETCHMAILHOME="./pid" setuidgid fetchmail fetchmail -f ./fetchmail.conf --nodetach
Tell the shell to replace this script with the env(1) program, passing everything after env as parameters.
env sees this: FETCHMAILHOME="./pid" setuidgid fetchmail fetchmail -f ./fetchmail.conf --nodetach
Set the environment variable FETCHMAILHOME to ./pid, then exec setuidgid with all arguments following it.
setuidgid sees this: fetchmail fetchmail -f ./fetchmail.conf --nodetach
Set user id to uid of user "fetchmail", group id to main group of that user, then exec fetchmail with all arguments following it.
fetchmail sees this: -f ./fetchmail.conf --nodetach
Read configuration from ./fetchmail.conf, don't fork to background

In short: set $ENV{FETCHMAILHOME}, become the fetchmail user, run the fetchmail program as that user. All using the same process ID, and always under control of supervise.

The logging script /service/fetchmail/log/run is even shorter:

#!/bin/sh exec \ setuidgid nobody \ multilog t s1000000 /var/multilog/fetchmail

Yes, just four lines that could be stuffed into two lines. Become "nobody", then run the multilog program. Multilog creates logfiles in /var/multilog/fetchmail, prefixes timestamps to the log lines (t), rotates the logfiles after 1_000_000 bytes.


Now, how to you send signals to your daemon if there is no PID file?

supervise always knows the current PID of your daemon, and it will send the signal for you. It will also start or stop your daemon on command.

So, how do you talk to supervise? There are many supervise processes around when you use daemontools. Which one is the right one?

supervise uses a pipe below the service directory. There is exactly one pipe per running process, and it's always the one below the service directory. You don't have to know which supervise you want to talk to, you just use the pipe below the service directory.

What's the name of the pipe? What to write there?

You don't have to know that. There is a tool named svc that talks to supervise. Just tell svc which signal to send, and it will take care of everything. Note that svc and supervise from djb do not send the signals QUIT, USR1, and USR2, but if you follow the djb way, you will find a patch that adds support for those three signals.

So, to send a USR1 signal to your service, just execute svc -1 /service/yourservice. That's all. No PID files needed, as I promised.

The options for the other signals are -p for STOP, -C for CONT, -h for HUP, -a for ALRM, -i for INT, -t for TERM, -k for KILL. With the patch, -1 sends USR1, -2 sends USR2, -q sends QUIT.

Other commands are sent like signals: To start your service, and to restart it when it exits, execute svc -u /service/yourservice. To stop it, execute svc -d /service/yourservice. To run your service only once, execute svc -o /service/yourservice. To prevent your service from automatically starting during boot, create a file named /service/yourservice/down. To make your service start during boot, delete /service/yourservice/down. To completely remove a service, execute svc -dx /service/yourservice /service/yourservice/log, then remove the /service/yourservice directory.

Is your service running?

svstat and svok answer that question, for humans and scripts. (You might notice that my /service/fetchmail/run script does not use svok, neiter does it use svstat. It uses pidof. It's an old script, from a time when exim was not under control of daemontools, that's why. It should really use svok /service/exim instead.)

Alexander

--
Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)

Replies are listed 'Best First'.
Re^4: Daemon::Control pid-files
by morgon (Priest) on Apr 17, 2016 at 21:28 UTC
    Hi,

    many thanks for your reply - it is very interesting.

    However my requirement is a little different (I probably should have mentioned that earlier).

    My Pi runs with an older (still system v init) based version of raspbian.

    What I want is to set the time at boot time from a dvb-c signal (a one-off event) - but I want to do that not at some random time but at a time after syslog is available but before certain other services start start.

    By using a sysv init script I can express this order via LSB-entries which makes it pretty simple.

    This has led me to Daemon::Control which in turn requires the use of a pid file (that I don't really care about).

    And while this may be a topic for another forum: Do you think daemontools still have an ecological niche on Debian-based systems now that systemd is taking over?

      What I want is to set the time at boot time from a dvb-c signal (a one-off event) - but I want to do that not at some random time but at a time after syslog is available but before certain other services start start.

      By using a sysv init script I can express this order via LSB-entries which makes it pretty simple.

      In that case, you don't need a daemon at all. LSB-ordering makes sure that your init script runs at the right time. In the init script, you simply run a program to read the time signal, blocking. No need for a daemon.

      Do you think daemontools still have an ecological niche on Debian-based systems now that systemd is taking over?

      Systemd is IMHO an ugly monster, stuffing everything and the kitchen sink into one fat binary (or two) on which the entire system depends. Just the opposite of what made Unix great: Little programs that can be combined like LEGO to build things that nobody did think of when they were written. Daemontools follow the Unix spirit of little programs that do one thing, and do that right.

      Using daemontools does not mean that you have to remove SysV init, BSD init or Systemd. You could do so, and use a very tiny init that just starts a script to make sure the system is ready to start deamontools, and then passes control to daemontools. But svscanboot can be started like any other service from some init script, or directly from init. This is also the way I use daemontools: I added sv:2345:respawn:/command/svscanboot to /etc/inittab.

      Alexander

      --
      Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)