Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change

Fake daemon

by hagus (Monk)
on May 30, 2002 at 02:31 UTC ( #170284=sourcecode: print w/replies, xml ) Need Help??
Category: utility scripts
Author/Contact Info hagus
Description: A script I dug out of my archives. I submit it here in the hope that someone might find some useful sample techniques, despite its hurried appearance. I wrote it awhile ago with the following goals:

  • To make a non-daemon process run as if it were a daemon (ie. give it a controlling terminal).
  • To collect the stderr and stdout streams from that process uninterleaved (is that a word?).
  • To restart the process at a particular time each day.
  • To restart the process should it die unexpectantly.

    Things needing fixing that I can see:

  • Signal handling is below par. I don't understand it very well, as I seldom have to handle signals in perl.
  • Restart time is hardcoded - it really should take either a maximum run-time argument, or a date string which is parsed.
  • Command line arguments, anyone?
  • Handling infinite loops when restarting the process. Ie. if restart occurs more than x times in y seconds, sleep for z or exit.
  • Other stylistic or design problems people might see?

  • use warnings;
    use strict;
    use IO::Pty;
    use IO::Select;
    use POSIX ":sys_wait_h";
    if (@ARGV < 2)
        die "Arguments: logfile executable ...";
    exit if (fork);
    my $logfile;
    POSIX::setsid() or die "Can't start a new session: $!\n";
    sub signal_handler
        my $signame = shift;
        logMsg($logfile, "ERROR: caught signal $signame, exiting.");
    $SIG{INT} = $SIG{TERM} = $SIG{HUP} = \&signal_handler;
    sub terminate
        my $pid = shift;
        my $signal = shift;
        kill $signal, $pid;
        my ($r, $starttime);
        $starttime = time;
            $r = waitpid($pid, &WNOHANG);
        until ($r == $pid || (time - $starttime > 5));
        if ($r == $pid)
            return 1;
            return undef;
    sub logMsg
        my $fh = shift;
        my $msg = shift;
        my $t = scalar localtime;
        my $oldfh = select($fh);
        print $fh "$t [$$]: $msg\n";
    my $logfileName = shift @ARGV;
    $logfile = new IO::File ">>$logfileName" || die "Unable to open logfil
    +e $logfileName";
    while (1)
        my $pty = new IO::Pty;
        my ($readerr, $writeerr);
        pipe($readerr, $writeerr) || die "pipe $!\n";
        if (my $pid = fork)
            my $select = new IO::Select;
            my $run = 1;
            my $runtime = time;
            while ($run)
                foreach my $fh ($select->can_read(0.25))
                    my $buf;
                    if (sysread($fh, $buf, 4096))
                        logMsg($logfile, "child reports \"$buf\"");
                my $r = waitpid($pid, &WNOHANG);
                if ($r == $pid)
                    logMsg($logfile, "Warning: $pid died unexpectedly, res
                    $run = 0;
                    my @times = localtime(time);
                    if ($times[2] == 7 && $times[1] == 0 && ($times[0] > 0
    + && $times[0] < 05))
                        sleep 5;
                        unless (terminate($pid, 15))
                            unless (terminate($pid, 9))
                                die "Unable to kill process $pid with SIGT
    +ERM or SIGKILL!";
                                logMsg($logfile, "Warning: had to resort t
    +o SIGKILL to remove $pid.\n");
                            logMsg($logfile, "Info: killed $pid with SIGTE
                        $run = 0;
            logMsg($logfile, "Info: starting " . join(" ", @ARGV));
            my $slave = $pty->slave();
            close $pty;
            open(STDOUT, ">&" . $slave->fileno);
            open(STDERR, ">&" . $writeerr->fileno);
            exec(@ARGV) || die "exec: $!\n";
    Replies are listed 'Best First'.
    Re: Fake daemon
    by RedDog (Pilgrim) on May 30, 2002 at 04:29 UTC
      You might want to have a look at the Proc::Daemon or Proc::Application modules for some additional ideas.

      ...We will have peace, when you and all your works have perished -- and the works of your dark master to whom you would deliver us. You are a liar, Saruman, and a corrupter of men's hearts. -- Theoden in The Two Towers --
    Log In?

    What's my password?
    Create A New User
    Node Status?
    node history
    Node Type: sourcecode [id://170284]
    and all is quiet...

    How do I use this? | Other CB clients
    Other Users?
    Others scrutinizing the Monastery: (6)
    As of 2018-06-24 10:20 GMT
    Find Nodes?
      Voting Booth?
      Should cpanminus be part of the standard Perl release?

      Results (126 votes). Check out past polls.