#!/usr/bin/perl -w
# killbgproc.pl -- Kill background processes on OpenBSD
# William Marquette - billm@danger.ms
#
use POSIX; # Need this for daemonize code
use Sys::Syslog;

#
# Initialize variables
#
sub init {
  $ourname = "killbgproc"; # Name to use in syslog
  $logopt = "pid"; # Logging options, you probably don't want to change this
  $facility = "daemon"; # Logging facility - lowercase nonLOG_ versions from syslog(3)
  $LLEV = "info"; # Logging level - lowercase nonLOG_ versions from syslog(3)
  $mingooduser = 1000; # Lowest numbered UID that is allowed to run BG processes
  $sleeptime = 10;  # Time to sleep between runs - in seconds
}

#
# C code from figure 12.4 of Stevens Unix Network Programming vol. 1 perlized
# (and probably quite bastardized)
#
sub daemonize {
  if (($daemonpid = fork) != 0) { exit; } # Parent exits

  # First child continues
  setsid; # Become session leader
  
  # signal(SIGHUP, SIG_IGN); # note sure how to implement this in perl yet

  if (($daemonpid = fork) != 0) { exit; } # 1st child exits

  $daemonpid = getpid; # Get our current PID
  chdir("/"); # Change working directory

  umask(0); # Clear our file mode creation mask

  # Not sure how to close all file descriptors in perl 

  openlog($ourname, $logopt, $facility);
  Sys::Syslog::setlogsock("unix");

}

#
# The meat of the program
#
sub work {
  open(PS, "ps -ajx 2>&1 |") || die "Can't run ps";
  while (<PS>) { 
    chomp;
    next unless (m/(\w+)\s+(\d+)\s+(\d+)\s+\d+\s+\w+\s+\d+\s+[A-Za-z+]+\s+\?\?+\s+[0-9:.]+\s+(.*)/);
   # next unless (m/(\w+)\s+(\d+)\s+\d+\.\d+\s+\d+\.\d+\s+\d+\s+\d+\s+\?\?\s+\w+\s+\w+\s+[0-9:.]+\s+(.*)/);
    local ($user, $pid, $ppid, $command) = ($1, $2, $3, $4);
    
    local $uid = getpwnam $user;
    if (($uid > $mingooduser) && ($pid != $daemonpid) && ($ppid != $daemonpid)) {
      kill "KILL", $pid;
      syslog($LLEV, "killed $pid owned by $uid running: $command");
    }
  }
  close PS;
}

#
# Closing down
#
sub closedown {
  closelog;
}

init;
daemonize;
while(1) {
  work;
  sleep $sleeptime;
}
closedown;
