#/usr/bin/perl

$> && die "Not running as root\n";

@INC = $INC[$#INC - 1]; # Use only the perl library.
die "Perl library is writable by world!!!\n"
    if $< && -W $INC[0];
die "getopts.pl is writable by world!!!\n"
    if $< && -W "$INC[0]/getopts.pl";
require "getopts.pl";
&Getopts('cst');

$wall = !opt_s;

$_ = "$0 @ARGV";        # To allow "ln START STARTxyz"

$ENV{'IFS'} = '' if $ENV{'IFS'};        # plug sh security hole
$ENV{'PATH'} = '/appl/bin:/bin:/usr/bin:/usr/local/bin';

# Which daemon to start?

if (/abc/) {
    $sys = 'abc';
    $task = 'abcdaemon';
    if (-f '/local/tmp/NO_ABC') {
	die "Can't start abcdaemon while NO_ABC exists\n";
    }
}

elsif (/def/) {
    $sys = 'def';
    $task = 'def';
    if (-f '/local/tmp/NO_DEF') {
	die "Can't start def while NO_DEF exists\n";
    }
}
elsif (/xyz/) {
    $sys = 'xyz';
    $task = 'xyzzy';    # Forks plugh and plover.
    if (-f '/local/tmp/NO_XYZ') {
	die "Can't start lm while NO_XYZ exists\n";
    }
}
elsif (/appl/ || !@ARGV) {
    system $0, 'abc';
    system $0, 'def';
    system $0, 'xyz';
    exit 0;
}
else {
    die "Usage: START subsystem\n";
}

# Get info for logging.

chop($whoami = `who am i`);
$whoami =~ s/[ \t]+/ /g;

chop($tty = `tty`);
$tty = '' if $tty !~ m|/dev/|;

# Set real uid to effective uid so core dumps will happen.

$< = $>;

# Move to directory for core dumps.

chdir '/local/tmp' || die "Can't chdir to /local/tmp";

# See if they should have run KILL.

chop($oldpid = `/bin/cat .pid$sys 2>&1`);
if ($oldpid > 0 && kill 0, $oldpid) {
    die "$sys appears to be running already!\n"
      if `/bin/ps -p$oldpid` =~ /START/;
}

print "Any core dump of $task will be put into /local/tmp.\n";

# Redirect output to log file.

open(STDERR,">/local/tmp/${sys}_err_log")
    || (print STDOUT "Can't open log file\n");
open(STDOUT,">&STDERR");

# Log the startup.

chop($date = `date`);
$date =~ s/ [A-Z][DS]T 19[89][0-9]//;
open(KILLLOG,">>/local/tmp/${sys}_kill_log");
print KILLLOG $date, ' ', $whoami, " $sys started\n";
close(KILLLOG);
if ($tty) {
    open(KILLLOG,">$tty");
    print KILLLOG $date, ' ', $whoami, " $sys started\n";
    close(KILLLOG);
}

if ($pid = fork) {         # Run the rest in background.
    open(PID,">.pid$sys"); # Remember pid for quick check above
    print PID "$pid\n";    # (pid of START, not of $task).
    close(PID);
    sleep(3);              # Give each daemon a chance to start
    exit 0;
}
defined $pid || die "Can't fork: $!\n";

$SIG{'TERM'} = 'IGNORE';

setpgrp(0,$$);  # Prevent kills from infecting other daemons.

# Finally, run the poor daemon and collect its status.

if ($opt_t) {
    $st = (system "/usr/bin/trace /appl/bin/$task");
}
else {
    $st = (system "/appl/bin/$task");
}

# Now get info necessary for logging.

chop($date = `date`);
$date =~ s/ [A-Z][DS]T 19[89][0-9]//;

# Rename any core dump to a unique name.

if ($st & 128) {
    $tm = join('',unpack("x8 a2 x a2 x a2", $date));
    $tm =~ s/ /0/g;
    rename("/local/tmp/core", "/local/tmp/core.$sys$tm");
}

sleep(2);

# Log it everywhere that makes sense.

$entry = "$date $whoami $sys exit " . ($st >> 8) . ", sig " .
    ($st & 127) . ($st & 128 ? ", core dump\n" : "\n");
open(KILLLOG,">>/local/tmp/${sys}_kill_log");
print KILLLOG $entry;
close(KILLLOG);

close(STDERR);
close(STDOUT);
open(STDOUT,">&STDIN");
open(ERR,"/local/tmp/${sys}_err_log");
open(CONSOLE,"/dev/console") if $opt_c;
$tty = '' unless -t;
while (<ERR>) {
    if ($_ eq $last) {
	$repeat = 1;
	while (<ERR>) {
	    if ($_ eq $last) {
		++$repeat;
	    }
	    else {
		$last = "Last message repeated $repeat time" .
		    ($repeat == 1 ? "" : "s") . ".\n";
		print CONSOLE $last if $opt_c;
		print STDOUT $last if $tty;
	    }
	}
    }
    print CONSOLE $_ if $opt_c;
    print STDOUT $_ if $tty;
    $last = $_;
}

if ($wall) {
    open(KILLLOG,"| wall"); # Might as well share the good news
    print KILLLOG $entry;
    close(KILLLOG);
}

unlink "/local/tmp/.pid$sys";