Giacomo Montagner > Script-Daemonizer-0.93.04 > Script::Daemonizer

Download:
Script-Daemonizer-0.93.04.tar.gz

Dependencies

Annotate this POD

CPAN RT

Open  1
View/Report Bugs
Module Version: 0.93.04   Source   Latest Release: Script-Daemonizer-0.93.05

NAME ^

Script::Daemonizer - Turns your script into a UNIX daemon process (the easy way).

VERSION ^

Version 0.93.04

Interface changed from procedural to OO across 0.92-0.93 transition. 0.93.x is quite experimental.

SYNOPSIS ^

Please consider using Daemon::Control instead of Script::Daemonizer

    # Want a quickstart? Do this: 

    use Script::Daemonizer;
    ...
    Script::Daemonizer->new()->daemonize();

ABSTRACT ^

This module turns your script into a UNIX daemon by requiring as little modification as possible, thus letting you concentrate on solving your problem, rather than on writing a daemon. Just get your job done, then turn your script into a daemon by calling daemonize().

It tries to redirect all messages to syslog by default, using Tie::Syslog.

DESCRIPTION ^

daemonize() is the main routine of this module. What it does, out-of-the-box, is:

1.* it sets umask() to 0. You must then set explicitly file and directory permissions upon creating them, restore umask() after initialization, or specify umask option (see "ADVANCED USAGE" for details).
2.* it calls fork(), then the parent exits;
3. it calls POSIX::setsid() (see POSIX::setsid()), so the process becomes session leader;
4.* it calls fork() again, then the parent exits;
5.* it changes its working directory to "/";
6.* NO LONGER IMPLEMENTED (since 0.93.00) - closing file descriptors. It's practically impossible, so this step has been removed.
7.* it ties STDOUT and STDERR to Syslog using Tie::Syslog (if available, otherwise it reopens them on /dev/null) so that all output is logged to syslog (see Tie::Syslog); open STDIN on /dev/null.

Steps marked by * are configurable; some additional steps are also available if explicitly requested; see "ADVANCED USAGE" for details.

ADVANCED USAGE ^

I strive to make this module support "standard" daemon features out-of-the-box (for some definition of "standard"). Some of these features can be configured, and some other are enabled only if configured.

ADVANCED SYNOPSYS

Advanced configuration syntax is the following:

    use Script::Daemonizer;

    my $daemon = new Script::Daemonizer (
        name            => "My wonderful new daemon",  # tag for logging
        umask           => $my_umask,                  # set umask to $my_umask
        working_dir     => "/var/ftp",                 # try to chdir here
        drop_privileges => {                           # call drop_privileges()
            uid  => $to_uid,
            gid  => $to_gid,
        },
        fork            => 2,                          # for # number of times (0, 1 or 2)
        pidfile         => '/var/run/mydaemon.pid',    # write and lock this pidfile
        output_file     => '/var/log/mydaemon.log',    # redirect stdout/stderr here
    );

    # To make stdout/stderr go to different places, use these: 
    my $daemon = new Script::Daemonizer (
        ...
        stdout_file     => '/log/mydaemon.log',
        stderr_file     => '/log/mydaemon.err',
    );


    # setup SIGHUP as a restart:
    $SIG{HUP} = sub {
        $daemon->restart();
    };

    # if you did not specify drop_privileges in configuration, you can still 
    # do it afterwards: 
    $daemon->drop_privileges(
        uid  => $to_uid,
        gid  => $to_gid,
    );

    # If you used a different signal to restart, remembre to unmask it: 
    $SIG{USR1} = sub {
        $daemon->restart();
    }
    $daemon->sigunmask( qw/USR1/ );

    ###########################################################################

    # IMPORT TAGS

    # Will skip chdir(), unless you pass 'working_dir' to new()
    use Script::Daemonizer qw(:NOCHDIR);

    # Will skip umask(), unless you pass 'umask' to new()
    use Script::Daemonizer qw(:NOUMASK);

OPTIONAL ACTIONS

Some options have no default and thus corresponding actions are skipped if not configured. These are:

IMPORT TAGS

Starting from 0.93.4, you can suppress some default actions by importing Script::Daemonizer with the corresponding tag:

:NOCHDIR
:NOUMASK

METHODS ^

new()

Creates a new instance of a Script::Daemonizer object. If you just want to start with defaults, just call it with no args:

    # A new daemon
    my $daemon = new Script::Daemonizer ();

    # or, if you prefer:
    my $daemon = Script::Daemonizer->new();

To customize your daemon see "ADVANCED USAGE".

daemonize()

It runs through all the steps required to send your program to background as a daemon. Its behavior varies depending on options specified to "new".

drop_privileges()

    # Just drop effective user/group id:
    $daemon->drop_privileges(
        euid => $to_euid,
        egid => $to_egid,
    );

    # Drop both effective and real ids: 
    $daemon->drop_privileges(
        uid  => $to_uid,
        gid  => $to_gid,
    );

Tries to drop privileges to given EUID/EGID or UID/GID (single (e)uid/(e)gid allowed). See "perldoc perlvar" for details on IDs.

daemonize() will automatically call drop_privileges() if configured to do so (guess what? See "ADVANCED USAGE" for details) but this will happen before anything else (think of this as step 0). If you need to drop privileges at a later moment, use drop_privileges(), otherwise it's probably safer to do so while daemonize()-ing.

restart()

restart() is there to let you restart completely the daemon. A simple way to handle SIGHUP might be restarting, for example (see perlipc for details).

    # Restart upon sighup - use a closure to call restart()
    $SIG{HUP} = sub {
        $daemon->restart;
    }; 

pidfile (see "ADVANCED USAGE" for details) is kept open upon restart (if configured), but on some platforms (see "Concerning locks" for details) the lock is not preserved, so a race condition may still happen.

You can pass command line args to restart() to modify command line on-the-fly:

    use Script::Daemonizer;
    ...
    unless( some_condition_on(@ARGV) ) {
        # Do some mangling on @ARGV
        ...
        $daemon->restart(@my_modified_argv);
    }

The defaul is to use a copy of @ARGV taken at compile-time (before any command-line-parsing modifies @ARGV, for example).

sigunmask()

    $daemon->sigunmask( @signals );

Strictly related to restart(), sigunmask() is there to let you unmask signals without pain. See http://docstore.mik.ua/orelly/perl4/cook/ch17_19.htm for details on why you should unmask signals. In short: inside a signal handler the signal that triggered the handler is blocked. If inside a signal handler you re-exec() yourself, the new process inherits the blocked signal. That is why you could want to unmask that signal after a new start.

SGIHUP is unmasked by default, just by saying use Script::Daemonizer.

If you use restart() with other signals, remember to unmask them:

    # Restart on SIGHUP, SIGQUIT and SIGUSR1
    for my $nal in (qw/HUP QUIT USR1/) {
        $SIG{$nal} = sub {
            $daemon->restart;
        }
    }

    # Just in case we came from another instance of ourselves via an exec()
    # (no need to bother for SIGHUP since we unmask it by default, anyway
    # listing it here it's harmless): 

    $daemon->sigunmask(qw{QUIT USR1});

ADVANCED OPTIONS ^

Advanced options are the following:

chdir

The only accepted value is SKIP. If set, this causes the chdir() step to be skipped (and working_dir will be ignored).

    ...
        chdir => 'SKIP'     # Skip chdir()
    ...

name

Sets the name of the daemon. This is used for logging.

default: script name, got from $0, split on system path separator;

fork

How many times do you want to fork?

0 - perform no fork()
1 - do it just once
2 - fork twice
* any other value will result in a fork()-twice

default: fork() twice.

output_file

Redirect both STDOUT and STDERR on the file specified (appending by default). '/dev/null' will be converted to File::Spec->devnull (see File::Spec); Tie::Syslog will not be skipped completely.

    output_file => '/dev/null',

will result in complete discard of output.

pidfile

This will try to:

- open named pidfile, creating it if non-existent;
- lock it (exclusively);

If this operation fails, daemonize() will croak(). Otherwise, PID of the process will be written to the named pidfile after the last fork() is done.

    Script::Daemonizer::daemonize(
        name    => 'A new daemon',
        pidfile => '/var/run/anewdaemon.pid',
    );

This lock mechanism provides the following advantages:

setsid

The only accepted value is SKIP. Set this to skip setsid().

stdout_file

Redirect STDOUT on the file specified (appending by default). '/dev/null' will be converted to File::Spec->devnull (see File::Spec); Tie::Syslog will not be used for STDOUT.

stderr_file

Redirect STDERR on the file specified (appending by default). '/dev/null' will be converted to File::Spec->devnull (see File::Spec); Tie::Syslog will not be used for STDERR.

umask

Set the specified umask. Set this to SKIP to skip this step:

    ...
        umask => 'SKIP',        # Skip setting umask
    ...

default: 0

working_dir

Try to chdir() to the specified directory. Set chdir to SKIP to skip this step.

    ...
        working_dir => '/var/ftp',
    ...

default: root (/) dir.

LOCKING ^

If you want to be sure no multiple instances of your daemon will be running, just use pidfile advanced option. See "pidfile" for details.

CAVEATS ^

Concerning filehandles

Filehandles cannot really be closed. Following advice from Matt S. Trout I will skip filehandle-closing step completely.

Concerning locks

On some platforms (by now only Solaris is proven to be affected, but other platforms may be) the lock on the pidfile is not preserved across fork(), so from 0.91 to 0.92 I added a second flock() after the last fork(). This allows a race condition between the first and the second flock(), but it should not be a problem, since the lock could be as well tried just after the last fork(). The reason I left the first attempt in place is that if we have to fail anyway, it's better to do it as early as possible. The real race condition may happen, instead, when the process is restarted using restart() (or by any other mean), because if lock on pidfile is not preserved, someone could take the lock on it before we're able to complete restart, thus causing the process to exit.

FAQ ^

Q: Why is there no built-in start/stop/* method?

A: Because to start/stop/* a daemon you usually don't call the daemon itself, instead you rely on system tools that allow process control (if you need an "init script" then write one) and interact with processes through signals. Lack of start/stop/* methods is regarded as a feature. Try Daemon::Control if you're searching for such an interface (it cal also generate init scripts).

Q: Why is Tie::Syslog not listed as prerequisites?

A: Because you may want to skip Syslog support and not install that module. Script::Daemonizer module will work nonetheless, without using Tie::Syslog them (and without the features it provides, of course).

TODO ^

Some ideas:

AUTHOR ^

Giacomo Montagner, <gmork at entirelyunlike.net >, <gmork.gmork at gmail.com >

BUGS ^

Please report any bugs or feature requests to bug-script-daemonizer at rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Script-Daemonizer. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.

SUPPORT ^

You can find documentation for this module with the perldoc command.

    perldoc Script::Daemonizer

You can also look for information at:

ACKNOWLEDGEMENTS ^

LICENSE AND COPYRIGHT ^

Copyright (C) 2012 Giacomo Montagner, all rights reserved.

This program is free software; you can redistribute it and/or modify it under the terms of either: the GNU General Public License as published by the Free Software Foundation; or the Artistic License.

See http://dev.perl.org/licenses/ for more information.

AVAILABILITY ^

Latest sources are available from https://github.com/kromg/Script-Daemonizer

syntax highlighting: