#!/bin/sh #-*-Perl-*- exec perl -w -x $0 "$@" #!perl ############################################################################## # # jabberd - perl wrapper script to manage launching and controlling the various # binaries that make up the 2.0 version of the jabberd server. # ############################################################################## use strict; use Getopt::Std; use FileHandle; use IPC::Open3; use IO::Select; use POSIX; use POSIX qw(setsid); #----------------------------------------------------------------------------- # Define some initial variables and default them as needed. #----------------------------------------------------------------------------- my $Bin = "@bindir@"; my $VERSION = "@VERSION@"; my $config_dir = "@sysconfdir@"; my $config = "jabberd.cfg"; my $debug = 0; my $daemon = 0; my $select = IO::Select->new(); my ($exe) = ($0 =~ /([^\/]+)$/); my %jobs; my %fhs; my @programs; #----------------------------------------------------------------------------- # Process the command line arguments #----------------------------------------------------------------------------- my %opts; getopts("c:d:Dhb",\%opts); &usage if exists($opts{h}); if (exists($opts{c})) { $config = $opts{c} if (defined($opts{c}) && ($opts{c} ne "")); &usage() if (!defined($opts{c}) || ($opts{c} eq "")); } if (exists($opts{d})) { $config_dir = $opts{d} if (defined($opts{d}) && ($opts{d} ne "")); &usage() if (!defined($opts{d}) || ($opts{d} eq "")); } $config = $config_dir.'/'.$config if ($config !~ /^\//); $config = "internal" unless (-e $config); $debug = 1 if exists($opts{D}); $daemon = 1 if exists($opts{b}); #----------------------------------------------------------------------------- # Catch some signals so that we can handle them later. #----------------------------------------------------------------------------- $SIG{HUP} = \&Signal; $SIG{TERM} = \&Signal; $SIG{INT} = \&Signal; $SIG{CHLD} = "IGNORE"; #----------------------------------------------------------------------------- # Setup the jobs: router, resolver, sm, c2s, s2s #----------------------------------------------------------------------------- $jobs{jabberd}->{prefix} = "JBRD"; $jobs{router}->{cmd} = "$Bin/router"; $jobs{router}->{config} = "$config_dir/router.xml"; $jobs{router}->{prefix} = "ROUT"; $jobs{resolver}->{cmd} = "$Bin/resolver"; $jobs{resolver}->{config} = "$config_dir/resolver.xml"; $jobs{resolver}->{prefix} = "RSLV"; $jobs{sm}->{cmd} = "$Bin/sm"; $jobs{sm}->{config} = "$config_dir/sm.xml"; $jobs{sm}->{prefix} = "SM"; $jobs{c2s}->{cmd} = "$Bin/c2s"; $jobs{c2s}->{config} = "$config_dir/c2s.xml"; $jobs{c2s}->{prefix} = "C2S"; $jobs{s2s}->{cmd} = "$Bin/s2s"; $jobs{s2s}->{config} = "$config_dir/s2s.xml"; $jobs{s2s}->{prefix} = "S2S"; if ($config eq "internal") { $programs[0] = ["router"]; $programs[1] = ["resolver"]; $programs[2] = ["sm"]; $programs[3] = ["c2s"]; $programs[4] = ["s2s"]; } else { if (!(-f $config)) { print "ERROR: config file does not exist: $config\n"; exit(1); } open(CFG,$config); while() { next if /^\#/; next if /^\s*$/; my ($job,$config) = /^\s*(\S+)\s*(\S*)\s*$/; push(@programs,[$job,$config]); } close(CFG); } if ($debug) { &debug("jabberd","stdout","debug on\n"); &debug("jabberd","stdout","version($VERSION)\n"); &debug("jabberd","stdout","config_dir($config_dir)\n"); &debug("jabberd","stdout","config($config)\n"); } #----------------------------------------------------------------------------- # Launch all of the jobs. #----------------------------------------------------------------------------- if ($#programs == -1) { print "ERROR: No jobs to launch.\n"; exit(1); } foreach my $job (@programs) { &LaunchJob($job->[0],$job->[1]); } unless (!$daemon || $debug) { # Fork and become a daemon. Exit if we are the parent process. defined(my $pid = fork()) || die "Could not fork: $!"; POSIX:_exit(0) if $pid; # If we are the child process, continue (but act like a daemon). setsid or die "Could not start a new POSIX Session: $!"; chdir "/" or die "Could not chdir to /: $!"; umask 0; open STDIN, "/dev/null" or die "Could not set STDIN to /dev/null: $!"; open STDOUT, "/dev/null" or die "Could not set STDOUT to /dev/null: $!"; open STDERR, "/dev/null" or die "Could not set STDERR to /dev/null: $!"; } #----------------------------------------------------------------------------- # Run the main loop. Read the output from the jobs, watch for dead jobs and # restart them, make sure that the debug output is clearly marked. #----------------------------------------------------------------------------- while (1) { my @ready = $select->can_read(0); foreach my $fh (@ready) { my $line = <$fh>; if (defined($line)) { &debug($fhs{$fh}->{job},$fhs{$fh}->{std},$line); } else { print "ERROR: $fhs{$fh}->{job} died. Shutting down server.\n"; &Signal("TERM"); } } select(undef,undef,undef,.01); } ############################################################################## # # LaunchJob - Do all of the necessary steps to monitor the job and launch it. # ############################################################################## sub LaunchJob { my $job = shift; my $config = shift; my $cmd = $jobs{$job}->{cmd}; if (defined($config)) { $cmd .= " -c ".$config; } else { $cmd .= " -c ".$jobs{$job}->{config}; } $cmd .= " -D" if $debug; &debug("jabberd","stdout","LaunchJob: $job -> $cmd\n"); &CloseJob($job) if exists($jobs{$job}->{launched}); $jobs{$job}->{stdout} = new FileHandle(); $jobs{$job}->{stderr} = new FileHandle(); $jobs{$job}->{stdout}->autoflush(1); $jobs{$job}->{stderr}->autoflush(1); my $stdin = new FileHandle(); $jobs{$job}->{pid} = open3($stdin, $jobs{$job}->{stdout}, $jobs{$job}->{stderr}, $cmd); print $stdin "\n"; $stdin->close(); $select->add($jobs{$job}->{stdout}); $select->add($jobs{$job}->{stderr}); $jobs{$job}->{launched} = 1; $fhs{$jobs{$job}->{stdout}}->{job} = $job; $fhs{$jobs{$job}->{stdout}}->{std} = "stdout"; $fhs{$jobs{$job}->{stderr}}->{job} = $job; $fhs{$jobs{$job}->{stderr}}->{std} = "stderr"; } ############################################################################## # # CloseJob - Do all of the necessary steps to clean up after a job. # ############################################################################## sub CloseJob { my $job = shift; $select->remove($jobs{$job}->{stdout}, $jobs{$job}->{stderr}); $jobs{$job}->{stdout}->close(); $jobs{$job}->{stderr}->close(); delete($jobs{$job}->{launched}); } ############################################################################## # # Signal - when we get a signal... we need to do something about it. # ############################################################################## sub Signal { my $sig = shift; &debug("jabberd","stdout","Got a signal... pass it on.\n"); foreach my $job (keys(%jobs)) { next unless exists($jobs{$job}->{launched}); kill $sig => $jobs{$job}->{pid}; } if (($sig eq "INT") || ($sig eq "TERM")) { &debug("jabberd","stdout","It was a $sig. Shut it all down!\n"); exit(0); } } ############################################################################## # # debug - print out a message for debug. Making sure that the prefix is the # program that generated the debug. # ############################################################################## sub debug { return unless $debug; my $job = shift; my $std = shift; #my $flag = " "; #$flag = "*" if ($std eq "stderr"); #printf("%s%-4s: ",$flag,$jobs{$job}->{prefix}); my $prefix = $jobs{$job}->{prefix}; $prefix = $job if ! defined($prefix); printf("%-4s: ",$prefix); print join("",@_); } ############################################################################## # # usage - print out the help and exit # ############################################################################## sub usage { print "$exe - jabberd wrapper script ($VERSION)\n"; print "Usage: $exe \n"; print "Options are:\n"; print " -c config file to use [default: $config]\n"; print " -D Show debug output\n"; print " -b Push into background\n"; print " -h Show this help\n"; exit(0); }