###
###  Copyright 2000-2007 University of Illinois Board of Trustees
###  All rights reserved. 
###
###  PSGConf::Action::RestartDaemon - Send defined signal to a given daemon
###
###  Campus Information Technologies and Educational Services
###  University of Illinois at Urbana-Champaign
###


package PSGConf::Action::RestartDaemon;

use strict;

use File::stat;

use PSGConf::Action;

use PSGConf::Util;

our @ISA = qw (PSGConf::Action);


###############################################################################
###  constructor
###############################################################################
     
my %defaults = (
     signal => 'HUP',
	check_func => \&_check_file
);

sub new
{
     my ($class, %opts) = @_;
	my ($self) = \%opts;

     map {
          $self->{$_} = $defaults{$_}
               if (!exists($self->{$_}));
     } keys %defaults;

     return PSGConf::Action::new($class, %$self);
}


###############################################################################
###  check method
###############################################################################

sub _check_file
{
     my ($self, $psgconf) = @_;
     my ($action, $file);

	foreach $file ( @{$self->{filename}} ) {
     	$action = $psgconf->get_action($file);

     	return 1
			if (defined($action) && $action->changed());
	}

	return 0;
} 

sub check
{
     my ($self, $psgconf) = @_;
     my ($ret);

     $ret = (exists($self->{check_func})
          ? $self->{check_func}->($self, $psgconf)
          : 1);

     return $ret
          if ($ret != 1);
     
     $self->{changed} = 1;
     return 1;
}


###############################################################################
###  diff method
###############################################################################

sub diff
{
     my ($self) = @_;

     print "###############################################################################\n"; 
     print "### DIFF FOR $self->{name}\n";
     print "###############################################################################\n";
     print "+ RESTART: $self->{name}\n\n";
}         


###############################################################################
###  do method
###############################################################################

sub do
{
	my ($self, $psgconf) = @_;
	my ($proc, $pid, $rcscript);

	return 0
		if (! $psgconf->{restart_daemons});
          
	print $0 . ": restarting $self->{name}\n";
               
     ### do special AIX stuff
     if ( -x '/usr/bin/refresh' 
         && $self->{signal} eq 'HUP'
         && (grep /^$self->{name}$/, @{$psgconf->data_obj('refresh_daemons')->get()}))
     {
		return ( PSGConf::Util::RunCommand (
					"/usr/bin/refresh -s $self->{name} > /dev/null 2>&1"
					) ? -1 : 1 );
     }

     ### use pidfile if specified
     if (defined($self->{pidfile}))
     {
          return 0
               if (! -f $self->{pidfile});

          if (!open(PIDFILE, "<$self->{pidfile}"))
          {
               warn "\t!!! open('<$self->{pidfile}'): $!\n";
               return -1;
          }
          $pid = <PIDFILE>;
          close(PIDFILE);

          chomp($pid);
          if (! kill($self->{signal}, $pid))
          {    
               warn "\t!!! can't send signal SIG$self->{signal} to "
                         . "$self->{name} (pid=$pid): $!\n";
               return -1;
          }
          return 1;
     }
     
     ### use the rcscript to bounce the daemon
     elsif (defined($self->{rcscript}) && -f $self->{rcscript})
     {
		$rcscript = ( -x $self->{rcscript} )? 
			$self->{rcscript} : 'sh ' . $self->{rcscript};

		if ( defined $self->{use_restart} ) {
			return ( PSGConf::Util::RunCommand (
					"$rcscript restart > /dev/null 2>&1"
					) ? -1 : 1 );
		} else {
			if ( PSGConf::Util::RunCommand (
				"$rcscript stop > /dev/null 2>&1")) {
				return -1;
			} else {
				sleep $self->{delay}
					if ( defined $self->{delay} );
				return ( PSGConf::Util::RunCommand (
						"$rcscript start > /dev/null 2>&1"
						) ? -1 : 1 );
			}
		}
	}

     ### if all else fails, check for running processes
     foreach $proc (@{$psgconf->{ps}->table})
     {
          next
               if ($proc->pid == $$
                   || $proc->ppid != 1
                   || (eval { $proc->cmndline; }
                    && $proc->cmndline !~ m/$self->{name}/));

          if (!kill($self->{signal}, $proc->pid))
          {
               warn "\t!!! can't send SIG$self->{signal} to $self->{name} "
                         . "(pid=" . $proc->pid . "): $!\n";
               return -1;
          }
     }    
                         
     return 1; 
}        


###############################################################################
###  documentation
###############################################################################

1;

__END__

=head1 NAME

PSGConf::Action::RestartDaemon - Send defined signal to a given daemon

=head1 SYNOPSIS

  use PSGConf::Action::RestartDaemon;

  $psgconf->register_actions(
		PSGConf::Action::RestartDaemon->new(
			'name'		=> daemon,
			'filename'	=> [ '/path/file1', ... ],
			'check_func'	=> \&_subref,
			'signal'		=> HUP,
			'pidfile'		=> '/path/to/file.pid'
			'rcscript'	=> '/etc/init.d/script' # Takes stop/start args
			'use_restart'	=> true 		# the rcscript has a restart arg
			'delay'		=> 10 		# Number of seconds to sleep
									# between stop & start of rc script
			...
		),
		...
	);

=head1 DESCRIPTION

The B<PSGConf::Action::RestartDaemon> module provides a B<PSGConf> 
action class for signaling a daemon to restart.  The arguments are 
the name of the daemon to restart, the file to watch for a change,
the signal to send to the daemon, and (optionally) the absolute 
path of the daemon's pidfile.

The B<PSGConf::Action::RestartDaemon> class is derived from the
B<PSGConf::Action> class, but it defines/overrides the
following methods:

=over 4

=item check()

Checks to see if there is any action(s) pending on I<filename>.

=item diff() 

Prints a message indicating that the daemon will be restarted.

=item do()

Actually restarts the daemon.

=back

In addition to the attributes supported by the B<PSGConf::Action>
class, the B<PSGConf::Action::RestartCommand> class supports the following
attributes:

=over 4

=item I<name>

The name of the daemon to restart.

=item I<filename>

The file(s) to watch to check() to restart.

=item I<check_func>

A reference to the subroutine that determines whether the command needs
to be executed.  The subroutine will be passed a reference to the
B<PSGConf::Action::RestartDaemon> object and a reference to the B<PSGConf>
object.  It can return anything that the check() method can return.

=item I<signal>

The signal to send to the daemon, defaults to I<HUP>.

=item I<pidfile>

The file that stores the pid of I<name> daemon.

=item I<rcscript>

Use this I<rcscript> with the I<stop> and I<start> options to bounce
this daemon. 

=item I<use_restart>

The I<rcscript> supports the I<restart> argument.

=item I<delay>

Sleep I<delay> seconds between running I<rcscript stop> and 
I<rcscript start>.

=back

=head1 SEE ALSO

L<perl>

L<PSGConf>

L<PSGConf::Action>

L<PSGConf::Util>

=cut



syntax highlighted by Code2HTML, v. 0.9.1