#/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 () { if ($_ eq $last) { $repeat = 1; while () { 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";