##---------------------------------------------------------------------------##
##  File:
##	daemon.pl
##  Author:
##	Earl Hood	ehood@convex.com
##  Description:
##	This package contains the routine "daemon_init" which
##	can be called by a perl program to initialize itself as a
##	daemon.  The routine achieves this by the following:
##
##	    1. Forks a child and exits the parent process.
##	    2. Becomes a seesion leader (which detaches the program from
##	       the controlling terminal).
##	    3. Changes the current working directory to "/".
##	    4. Clears the file creation mask.
##
##	The calling program is responible for closing unnecessary open
##	file handles.
##
##	If an error occurs in daemon_init so it cannot perform the above
##	steps, than it calls "die" with an error message.  One can
##	prevent program termination by using "eval" to capture any
##	error messages.
##
##  Implementation Notes:
##	Perl does not have direct support for the setsid(2) system call.
##	This call is needed to perform step 2 above.  Therefore,
##	syscall() is used to call setsid.  However, there existed a
##	problem with calling setsid.
##
##	I work in a heterogenous environment.  I noticed that the file
##	syscall.ph did not always define the assembly language
##	interface number for setsid (plus, on one of the Sparc 2s,
##	syscall.ph was called syscall.h, BUT it wasn't the C header).
##	Therefore, to avoid the dependency of administrators installing
##	perl correctly, I access the syscall.h file in /usr/include/sys
##	to determine the value I need for syscall().  If for some
##	reason, syscall.h is not /usr/include/sys, you can change the
##	$syscall_h variable.
##---------------------------------------------------------------------------##
##  Copyright (C) 1994  Earl Hood, ehood@convex.com
##
##  This program is free software; you can redistribute it and/or modify
##  it under the terms of the GNU General Public License as published by
##  the Free Software Foundation; either version 2 of the License, or
##  (at your option) any later version.
##  
##  This program is distributed in the hope that it will be useful,
##  but WITHOUT ANY WARRANTY; without even the implied warranty of
##  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
##  GNU General Public License for more details.
##  
##  You should have received a copy of the GNU General Public License
##  along with this program; if not, write to the Free Software
##  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
##---------------------------------------------------------------------------##

package daemon;

$syscall_h = "/usr/include/sys/syscall.h";

sub main'daemon_init {
    ## Fork and exit parent ##
    FORK: {
	if ($pid = fork) { 		## parent process
	    exit 0;
	} elsif (defined $pid) {	## child process
	    last FORK;
	} elsif ($! =~ /No more process/) {
	    sleep 5;
	    redo FORK;
	} else {
	    die "Can't fork: $!\n";
	}
    }
    ## Detach ourselves from the terminal ##
    if (open(SYSCALL_H, "< $syscall_h")) {
	while (<SYSCALL_H>) {
	    next unless /^\s*#define\s+SYS_setsid\s+(\d*)\s+.*$/;
	    $setsid = $1;  last;
	}
	close(SYSCALL_H);
	if ($setsid) { syscall($setsid); }
	else { die "Cannot detach from controlling terminal\n"; }
    }
    else { die "Unable to access $syscall_h\n",
	       "Cannot detach from controlling terminal\n"; }
    
    chdir "/";		## Change working directory
    umask 0;		## Clear file creation mask
}
1;

