morgon has asked for the wisdom of the Perl Monks concerning the following question:

Hi

I have a Raspberry Pi where I set the time via a perl-script from a tv-stick.

The script run as an init-script via Daemon::Control and looks like this:

use strict; use Daemon::Control; use Sys::Syslog; exit Daemon::Control->new( name => "Time from DVB", lsb_start => '$syslog $remote_fs', program => \&time_from_dvb, pid_file => "/tmp/dvb-perl.pid", )->run; sub time_from_dvb { openlog("perl-mh"); # set the time from dvb syslog("time set"); }
Now the thing is that while it works (time is set, log message appears in syslog), the pid-file does not get deleted, even though the script has done it's thing and has exited.

I would have assumed that Daemon::Control would see to the pid-file being deleted once the program (in my case a subroutine) has finished.

Is that a wrong understanding of how Daemon::Control works or is there anything else I have to do for the pid-file to get removed?

Many thanks!

Replies are listed 'Best First'.
Re: Daemon::Control pid-files
by ikegami (Patriarch) on Apr 17, 2016 at 03:46 UTC

    If you stop the daemon normally (i.e. using the control script), then the control script *does* delete the PID file.

    If the daemon stops prematurely (e.g. on its own or killed by a signal), then the control script can't possibly delete the PID file because it's not running.


    By the way, why do you pass the value returned by run to exit? run doesn't ever return!

Re: Daemon::Control pid-files
by afoken (Chancellor) on Apr 17, 2016 at 11:30 UTC
      Do you really need PID files?
      I don't need them at all and I may be using the wrong tool.

      What I do is not a daemon as such but simply a perl-script (active for a fraction of a second) that runs at boot time to set the time on my pi (which does not have a rtc).

      I thought Daemon::Control would be a convenient tool as it can also generate the init-script.

      Now Daemon::Control complains if you don't set a pid-file, that's where it comes from.

      I don't need it and I don't really care if it does not get deleted, I was simply wondering...

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

        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):


        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". ;-)
Re: Daemon::Control pid-files
by haukex (Archbishop) on Apr 17, 2016 at 21:21 UTC

    Hi morgon,

    ikegami already said it, but in the module's source you can see that do_stop is the only place unlink is called on the PID file.

    Taking a step back though: I understand that your process is something that just runs once briefly and then exits. Aside from the question as to whether you need a PID file in the first place (is your script called multiple times?) and whether you need to delete the PID file at all, I wouldn't really see the task you describe as a continually-running daemon - instead I might just set that up via cron.

    Is this something like "dvbdate" (1, 2)? If so, that can be set up to run regularly in the crontab - which by the way also has a @reboot directive for running things once on startup (haven't used that myself but it sounds pretty simple).

    If you really want to use an init script (which has the advantage that it can be run immediately on boot and you can control the prerequisites), you could use Daemon::Control's ability to generate an init script for you, and then adapt that to suit your needs. For example, if I use the get_init_file command on your script, I get something like this (edited for brevity):

    #!/bin/sh ### BEGIN INIT INFO # Provides: Time from DVB # Required-Start: $syslog $remote_fs # Required-Stop: # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 ### END INIT INFO` if [ -x /tmp/timeset_daemon.pl ]; then /tmp/timeset_daemon.pl $1 else echo "Required program /tmp/timeset_daemon.pl not found!" exit 1; fi

    Then, just replace /tmp/timeset_daemon.pl by whatever command sets the time from the DVB stick, and it'll be run once on boot (and on shutdown, but that shouldn't matter here). Another sample init script is shown in this article, it also shows the usage of the update-rc.d command. You could also teach that script to respect the start|stop|status commands, but since your script isn't really a continually-running daemon, Daemon::Control might not be the optimal way to do that. Or, you can slap a while (1) { my_code_here; sleep($interval) } around your code and you've basically got a daemon.

    I just recently started working with chrony to replace ntpd and provide accurate time via a GPS receiver on a Raspberry Pi, and it really was much easier to set up than ntpd. If you're looking into giving your RPi accurate time, then somehow feeding the DVB stick's time into chrony might be something worth investigating.

    Hope this helps,
    -- Hauke D

      Hi

      thanks for replying.

      As I explained in another post I wanted to use a sysv-init script so I can specify when to run it via LSB-entries.

      Daemon::Control is handy has it can generate init-scripts but requires a pid-file even though I don't really need one, but the fact that it is not deleted does not really bother me.

      And for my purposes it is quite enough to extract the time-information from the dvb-c signal and set the time once.

      I also have ntpd running on my Pi (I don't quite understand how chrony could be easier as that was rather trivial) for those times when it is connected to the internet, but most of the time my pi is not.

        Hi morgon,

        In that case I'd suggest to just write your own init script based on one of the templates I mentioned, or maybe the extensive /etc/init.d/skeleton if your system has it. Since an init script is just a shell script, you can do all your work there - in fact I even wrote an init script in Perl once - or you can write a simple init script whose start action simply runs the Perl script that sets the time. Since your task is just a one-off thing, you don't need all the complexities of a "real" init script, including Daemon::Control (for example you likely don't need the double-fork, PID file, etc.).

        My understanding is that ntpd works best for systems that are continually on the network, talking to multiple time servers, while chrony was designed with systems with intermittent or no internet access at all in mind. Telling ntpd which Internet NTP servers to sync to is easy; but I was having lots of trouble getting ntpd to sync to gpsd and a "Pulse Per Second" (PPS) signal, with chrony it was much easier to configure and it basically worked right away.

        Regards,
        -- Hauke D

Re: Daemon::Control pid-files
by stevieb (Canon) on Apr 17, 2016 at 01:26 UTC

    After a *very* quick peruse of the documentation of Daemon::Control, I don't see anything stating it'll delete the PID file. Do you need to delete it?

    END { unlink "/tmp/dvb-perl.pid" or die $!; }
      That'll delete the PID file when the control tool exits, not the daemon.