package Guardian::Daemon;
use strict;
use warnings;
use POSIX;

use Exporter qw(import);

our @EXPORT_OK = qw(Daemonize IsRunning GetPID WritePID RemovePIDFile);

# The file and path where the pidfile which contains the PID (process id)
# of guardian when running in daemon mode will be written.
my $pidfile = "/run/guardian/guardian.pid";
my $pid_path = "/run/guardian";

#
## The main function to daemonize guardian.
#
## When this function is called, the running guardian process will be forked
## into the background and become a daemon.
#
sub Daemonize {
	# Setting the session identifier to the current process.
	&POSIX::setsid or die "Could not set session identifer (setsid): $!";

	# Fork into the background.
	my $pid = fork ();

	# Check if we forked successfully.
	if ($pid < 0) {
		die "Could not fork into background: $!";

	# Clean exit the parent process.
	} elsif ($pid) {
		exit 0;
	}

	# Change working directory.
	chdir "/";

	# Set file umask.
	umask 022;

	# Set max number of "open" descriptors to system default, if not set
	# use 1024.
	foreach (0 .. (POSIX::sysconf (&POSIX::_SC_OPEN_MAX) || 1024))

	# This function does not require any input, so close it.
	{ POSIX::close $_ }

	# Open new I/O streams.
	open (STDIN, "</dev/null");
	open (STDOUT, ">/dev/null");
	open (STDERR, ">&STDOUT");

	# Call sub to write out the process id.
	&WritePID();
}

#
## Function WritePID.
#
## This function will write the current process id to guardians PID file. If the path to
## does not exist yet, it automatically will be created.
#
sub WritePID () {
	# Create directory for storing the pidfile if it does not exist yet.
	unless (-d "$pid_path") {
		mkdir($pid_path);
	}
	
	# Create pidfile.
	open(PIDFILE, ">$pidfile") or die "Could not write $pidfile. $!\n";

	# Write process-id to the pidfile.
	print PIDFILE "$$";

	# Close pidfile.
	close(PIDFILE);
}

#
## Function GetPID.
#
## This subfunction provides an easy to use mechanism to the the process id (PID)
## from the pidfile of guardian.
#
sub GetPID () {
	# Check if the pidfile exists.
	unless (-r "$pidfile") {
		return undef;
	}

	# Open the pidfile.
	open(PIDFILE, "<$pidfile") or die "Could not open $pidfile: $!\n";

	# Read the process id.
	my $pid = <PIDFILE>;

	# Close the file afterwards.
	close(PIDFILE);

	# Check if we got a valid process id.
	unless ($pid =~ /^(\d+)$/ ) {
		return undef;
	}

	# Return the process id.
	return $pid;
}

#
## Function IsRunning.
#
## A subfunction to check if a process by a given process id (PID) is running or not.
#
sub IsRunning () {
	# Grab process id
	my $pid = &GetPID();

	# If we got no process id, no instance of guardian is running yet.
	unless ($pid) {
		return undef;
	}

	# Check if the process exists or not by sending a test signal to the process id.
	my $is_running = kill(0, $pid);

	# Return true if the process is running.
	if ($is_running) {
		return "True";
	}

	# If we got here, there is not process running which uses the given id or something
	# went wrong. Return undef (False) in this case.
	return undef;
}

#
## RemovePIDFile function.
#
## This very tiny function just removes an existing PID file.
#
sub RemovePIDFile () {
	# Check if a socketfile exists.
	if (-e $pidfile) {
		# Delete the pid file.
		unlink($pidfile);
	}
}

1;
