Subject: Workaround For The Never Ending Connection Problem

From: Jon Forrest <[email-masked]>
Date: Wed, 3 May 1995 10:21:26 -0700

Like nearly everyone else, I'm also bothered with ftp connections that don't
go away. So, I hacked the ftpcount program to check how long each connection
has been going and to kill it if it has been around longer than a certain
amount of time. I run the result manually but you could put it in
a crontab. I use this on a Sparc10 running SunOS 4.1.3.

Here's the context diffs to ftpcount.c and the new function check_proc.

Jon

---------

***************
*** 210,223 ****
  #elif defined(M_UNIX)
                      sprintf(line,"/bin/ps -f -p %d",buf[which]);
  #else
!                     sprintf(line,"/bin/ps -u%d",buf[which]);
  #endif
                      ZeFile = popen(line, "r");
                      rewind(ZeFile);
                      fgets(line, 1024, ZeFile);
                      fgets(line, 1024, ZeFile);
!                     check_proc(line);
!                     /* printf("%s",line); */
                      pclose(ZeFile);
                  }
                  count++;
--- 210,222 ----
  #elif defined(M_UNIX)
                      sprintf(line,"/bin/ps -f -p %d",buf[which]);
  #else
!                     sprintf(line,"/bin/ps %d",buf[which]);
  #endif
                      ZeFile = popen(line, "r");
                      rewind(ZeFile);
                      fgets(line, 1024, ZeFile);
                      fgets(line, 1024, ZeFile);
!                     printf("%s",line);
                      pclose(ZeFile);
                  }
                  count++;
***************

/* Number of hours an ftp connection is allowed to live */
#define TIME_LIMIT    6
check_proc(char *line)
{
      register int i;
      time_t cur_time;
      char *c_ptr;
      char *delim = " \t";
      struct tm *tm_ptr;
      int pid;
      int cur_hour, starting_hour;

      /* This gets the token 'ftp' */
      c_ptr = strtok(line, delim);

      /* This gets the process id */
      c_ptr = strtok(NULL, delim);
      pid = atoi(c_ptr);

      /* Get the current hour in order to compare it to the
      ** starting time of each ftp process. We do this each time
      ** the function is called because we might have added 24 to
      ** the current hour below. Also, there's a chance the hour
      ** has changed from 23 to 0.
      */
      (void) time(&cur_time);
      tm_ptr = localtime(&cur_time);

      /* Go through the rest of the tokens until we get to the
      ** start time.
      */
      for (i = 0; i < 7; i++)
              c_ptr = strtok(NULL, delim);

      cur_hour = tm_ptr->tm_hour;
      starting_hour = atoi(c_ptr);

      /* If the cur_hour is less than the starting hour, then we're
      ** seeing a starting hour from yesterday. This isn't supposed
      ** to happen, according to the 'ps' man page, but it does.
      ** When it does, add 24 hours to cur_hour to make the time
      ** check come out right.
      */
      if (cur_hour < starting_hour)
              cur_hour += 24;

      /* If the first character of the start time isn't a
      ** number then it's a month name, meaning that the starting
      ** time for the process was sometime yesterday so kill it.
      ** If the start time is a number and the number if less than
      ** TIME_LIMIT hours from the current hour then kill it.
      */
      if (!isdigit(*c_ptr) || ((cur_hour - starting_hour) >= TIME_LIMIT))
      {
              printf("killing %d\n", pid);
              kill(pid, SIGKILL);
      }
}

---

From: Lee McLoughlin <[email-masked]>
Date: Wed, 3 May 1995 21:30:12 +0100

On May 3, 10:21am, Jon Forrest wrote:
} Subject: Workaround For The Never Ending Connection Problem
} 
} So, I hacked the ftpcount program to check how long each connection
} has been going and to kill it if it has been around longer than a certain
} amount of time.

That was a good idea.  I wrote a seperate perl program, which uses some
system 5-ism's, to do the same thing.  I then extended to stomp on my
other regular "hangers on".

I also had a problem with processes holding onto files on our 35 Gig metadisk
during shutdown.  This meant the disk had to be fsck'd on reboot.  So I
run my script in the shutdown sequence to kill off anything that might be
doing this.  (BTW it can take about 40 minutes to fsck 35 Gig.)

I run this on sunsite.doc.ic.ac.uk which has no real users on so the
patterns I use to match old jobs with are unlikely to match non-archive
commands.

If anyone wants to use it a copy is below.  But it should be used with
	EXTREME CAUTION
and don't blame me if it all goes horribly wrong!

#!/usr/local/bin/perl -s
# Find and kill old jobs.
# (Uses the fact that /proc files are timestamped with the last active time.)
# Usage: zap-old-jobs [-all] [-s sig] [-m pat]
#   eg: zap-old-jobs -s -m spat mpat
#
#  -m pat = match pat against the process name
#  -all = zap all matching processes reguardless of age
#  -s sig  = send sig to all matching processes
#
# This is called from cron and when the system is about to shutdown.

# exit unless $test;

$sig = 1;
if( $s ){
	$sig = shift;
}

$MIN = 60;
$HOUR = 60 * $MIN;
$DAY = 24 * $HOUR;

@proclimits = (
	'root.*ftpd.new',	12 * $HOUR,
	'root.*in.ftpd',	12 * $HOUR,
	'nobody.*httpd',	30 * $MIN,
	'nobody.*archieplex',	30 * $MIN,
	'nobody.*gofake',	30 * $MIN,
	'root.*gofake',		30 * $MIN,
	'root.*mirror.nightly',	23 * $HOUR,
	'root.*mirror -p',	22 * $HOUR,
);

if( $m ){
	$procpat = shift;
}

$limit = 12 * $HOUR;
if( $l ){
	$limit = $l;
}

# I may be running my special daemonised ftpd.
$ftpdpid = '';
if( open( pidf, "/etc/ftpd.pid" ) ){
	chop( $ftpdpid = <pidf> );
	close( pidf );
}

# I may be running my special daemonised gofake.
$gofpid = '';
if( open( pidf, "/etc/gofake.pid" ) ){
	chop( $gofpid = <pidf> );
	close( pidf );
}

open( ps, "ps -ef |" ) || die "cannot run ps";
while( <ps> ){
	chop;
	@F = split;
	$pid = $F[ 2 ];

	# Don't kill myself, ignore the title line
	next if $pid == $$ || $pid eq 'PID';

	if( $m ){
		next unless /$procpat/;
	}
	else {
		$N = 0;
		$found = 0;
		while( $N < $#proclimits ){
			$procpat = $proclimits[ $N++ ];
			$limit = $proclimits[ $N++ ];
			if( /$procpat/ ){
				$found = 1;
				last;
			}
		}
		next if ! $found;
	}
	$age = &proc_age( $pid );
	next if $age == 0;

	# Don't kill off the master ftpd or gofake unless everthing is being
	# killed
	next if !$all && ($pid == $ftpdpid || $pid == $gofpid);

	if( $all || $age >= $limit ){
		warn "kill: $_ ($age)\n" if $debug;
		push( @pids, $pid );
	}
}
close( ps );
$count = $#pids + 1;
print "[$count] @pids\n" if $debug || $show;
kill $sig, @pids unless $debug;

sub proc_age
{
	local( $pid ) = @_;
	local( $now ) = time;
	local( $dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
	       $atime,$mtime,$ctime,$blksize,$blocks ) = stat( "/proc/$pid" );
	if( $ctime eq '' || $ctime == 0 ){
		# ctime must be invalid, maybe proc has died?
		warn "***** no ctime proc died\n" if $debug;
		return 0;
	}
	return $now - $ctime;
}

-- 
--
Lee McLoughlin.                          Phone: +44 171 594 8388
Dept of Computing, Imperial College,     Fax: +44 171 584 8301
180 Queens Gate, London, SW7 2BZ, UK.    Email: [email-masked]