Tag Archives: daemon

Creating a Perl Daemon in Ubuntu

If you have a process that need to run in the background, creating a daemon is the key. Some examples of what your can do:

  • Wait for video files to be dropped via FTP and then process them
  • Check for a recurring problem and report it to admin
  • Monitor system load and report to the admin at a certain threshold

In this post we’ll take a look at how to create a Perl daemon script and how to get it to run as a daemon whenever the system is started. For the Perl script, a template will be created and for control of the daemon process, standard Debian facilities will be used.

What will be covered:

  • Create the start/stop script in /etc/init.d
  • Create the Perl daemon script in /usr/bin/
  • Create the log file in /var/log/
  • Get the daemon to start automatically when the system boots
  • How to manage your daemon

The start/stop script starts and stops the daemon. It is also used by the system to start your daemon when the system starts.

The Perl daemon script contains your custom Perl code to run in the background. It executes your code every x number of seconds.

Create the Start/stop Script

Happily, Debian and therefore Ubuntu, supplies a template that uses the Debian start-stop-daemon command to start and stop daemons. It is only necessary to copy this template to a new file of the correct name and modify it for the purpose.

These scripts reside in the /etc/init.d/ directory. The script you create will have the exact same filename as the Perl daemon script you will create and the name cannot have a file extension – just the bare name.

Substitute your daemon’s name for “mydaemon” in the examples.

sudo cp /etc/init.d/skeleton /etc/init.d/mydaemon
sudo chmod +x /etc/init.d/mydaemon
sudo vi /etc/init.d/mydaemon

Make changes to your start/stop script. Locate the header in the script:

PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="Description of the service"
NAME=daemonexecutablename
DAEMON=/usr/bin/$NAME
DAEMON_ARGS="--options args"
PIDFILE=/var/run/$NAME.pid
SCRIPTNAME=/etc/init.d/$NAME
  • Change the content of DESC to a meaningful description of your daemon.
  • Change the content for NAME to the exact name of your daemon.
  • Create the Perl Daemon Script

    Use the Perl Daemon Script Template located at the end of this post. In the following, the script template is copied to /usr/bin/where executables specific to this system are located. Actually, you would copy the template to your home directory, make the changes and then copy the daemon script to /usr/bin/.

    sudo cp daemon_template.pl /usr/bin/mydaemon
    sudo vi /usr/bin/mydaemon
    sudo chmod +x /usr/bin/mydaemon
    

    The script template is commented with the changes that are needed. In particular, change the value of $daemonName to the exact name of your new daemon. Ten, add your custom code where # do something appears.

    Prerequisites

    The script uses File::Pid and POSIX from CPAN, so you’ll need to install that module:

    sudo aptitude install cpan
    sudo cpan POSIX
    sudo cpan File::Pid
    

    Create the Log File

    We’ll create the log file so it has the correct ownership and permissions. The log fie has the daemon name appended with “.log”. It is located in the /var/log/ directory.

    sudo touch /var/log/mydaemon.log
    sudo chmod 640 /var/log/mydaemon.log
    sudo chown root:adm /var/log/mydaemon.log
    

    The permissions and ownership change allow adm group members to read the log, per convention. Add yourself to adm group to view logs.

    Run your Daemon

    As you have created a standard start/stop script for your daemon, you can start it the standard way:

    sudo /etc/init.d/mydaemon start
    

    Stop your Daemon

    Similarly, your daemon is easy to stop and restart:

    sudo /etc/init.d/mydaemon stop
    
    sudo /etc/init.d/mydaemon restart
    

    Automatically Start your Daemon

    This command tells your system to start your daemon automatically when the system starts:

    update-rc.d mydaemon defaults 99
    

    To keep your daemon from starting, if needed:

    update-rc.d -f mydaemon remove
    

    Managing Daemons

    List running daemons

    Well-behaved daemons generally create a PID file in /var/run/. List that directory and your have a fair list of running daemons.

    sudo ls /var/run/
    

    Get PID for a particular daemon

    If you know the name of a daemon and want to see if it is running and get its PID, use pgrep.

    pgrep mydaemon
    

    Also useful is the ps command, which list processes.

    ps aux
    

    The aux switch limits output to processes not associated with a terminal.

    Show programs running as daemons

    This line attempts to show programs that are running as daemons.

    which `ps aux | cut -c 66- | cut -d\  -f 1` | sort | uniq
    

    The Perl Daemon Script Template

    #!/usr/bin/perl -w
    #
    # mydaemon.pl by Andrew Ault, www.andrewault.net
    #
    # Free software. Use this as you wish.
    #
    # Throughout this template "mydaemon" is used where the name of your daemon should
    # be, replace occurrences of "mydaemon" with the name of your daemon.
    #
    # This name will also be the exact name to give this file (WITHOUT a ".pl" extension).
    #
    # It is also the exact name to give the start-stop script that will go into the
    # /etc/init.d/ directory.
    #
    # It is also the name of the log file in the /var/log/ directory WITH a ".log"
    # file extension.
    #
    # Replace "# do something" with your super useful code.
    #
    # Use "# logEntry("log something");" to log whatever your need to see in the log.
    #
    use strict;
    use warnings;
    use POSIX;
    use File::Pid;
     
    # make "mydaemon.log" file in /var/log/ with "chown root:adm mydaemon"
     
    # TODO: change "mydaemon" to the exact name of your daemon.
    my $daemonName    = "mydaemon";
    #
    my $dieNow        = 0;                                     # used for "infinte loop" construct - allows daemon mode to gracefully exit
    my $sleepMainLoop = 120;                                    # number of seconds to wait between "do something" execution after queue is clear
    my $logging       = 1;                                     # 1= logging is on
    my $logFilePath   = "/var/log/";                           # log file path
    my $logFile       = $logFilePath . $daemonName . ".log";
    my $pidFilePath   = "/var/run/";                           # PID file path
    my $pidFile       = $pidFilePath . $daemonName . ".pid";
     
    # daemonize
    use POSIX qw(setsid);
    chdir '/';
    umask 0;
    open STDIN,  '/dev/null'   or die "Can't read /dev/null: $!";
    open STDOUT, '>>/dev/null' or die "Can't write to /dev/null: $!";
    open STDERR, '>>/dev/null' or die "Can't write to /dev/null: $!";
    defined( my $pid = fork ) or die "Can't fork: $!";
    exit if $pid;
     
    # dissociate this process from the controlling terminal that started it and stop being part
    # of whatever process group this process was a part of.
    POSIX::setsid() or die "Can't start a new session.";
     
    # callback signal handler for signals.
    $SIG{INT} = $SIG{TERM} = $SIG{HUP} = \&signalHandler;
    $SIG{PIPE} = 'ignore';
     
    # create pid file in /var/run/
    my $pidfile = File::Pid->new( { file => $pidFile, } );
     
    $pidfile->write or die "Can't write PID file, /dev/null: $!";
     
    # turn on logging
    if ($logging) {
    	open LOG, ">>$logFile";
    	select((select(LOG), $|=1)[0]); # make the log file "hot" - turn off buffering
    }
     
    # "infinite" loop where some useful process happens
    until ($dieNow) {
    	sleep($sleepMainLoop);
     
    	# TODO: put your custom code here!
    	# do something
     
    	# logEntry("log something"); # use this to log whatever you need to
    }
     
    # add a line to the log file
    sub logEntry {
    	my ($logText) = @_;
    	my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) = localtime(time);
    	my $dateTime = sprintf "%4d-%02d-%02d %02d:%02d:%02d", $year + 1900, $mon + 1, $mday, $hour, $min, $sec;
    	if ($logging) {
    		print LOG "$dateTime $logText\n";
    	}
    }
     
    # catch signals and end the program if one is caught.
    sub signalHandler {
    	$dieNow = 1;    # this will cause the "infinite loop" to exit
    }
     
    # do this stuff when exit() is called.
    END {
    	if ($logging) { close LOG }
    	$pidfile->remove if defined $pidfile;
    }
    

    UPDATE:

    Looks like there’s a page in French about this post: http://www.duncane.net/2011/02/25/perl-daemon/. Merci Duncane!