[comp.sys.next] ghostbuster--a program to log out orphaned ptys

eps@toaster.SFSU.EDU (Eric P. Scott) (01/22/90)

I finally got tired of the ptys not-cleaned-up-after by Terminal
et al., and killing off scores of comsats and ntalkds that glom
on to them.  Yes, it's another one of my infamous quick-and-dirty
hacks!

Ghostbuster scans utmp for logged-in ptys with no controlling
process, and logs them out properly.  It will message syslogd
if it catches anything, so you can tell it's been working.

What do you do with it?  To be honest, I don't really know (could
have something to do with the late hour :-) )--it could be run
out of cron, or as a LogoutHook, or whatever.

Anyway, enjoy.
					-=EPS=-
K&R C, BSD conventions, depends on int==32 bits, runs as root.
-------
/*
 * ghostbuster - log out orphaned ptys
 * Eric P. Scott, San Francisco State University, January 1990
 *
 * cc -o ghostbuster -s -O -bsd ghostbuster.c -lsys_s
 * chown root.tty ghostbuster
 * chmod 4755 ghostbuster
 */
#include <stdio.h>
#include <grp.h>
#include <utmp.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/syslog.h>

main(argc, argv)
int argc;
char *argv[];
{
	char *malloc();
	time_t time();
	register struct utmp *ut;
	register char *ubuf;
	register struct group *gr;
	register int s;
	int u, w, p;
	struct stat st;
	char devname[12];

	s=3; do close(s); while (++s<20);
	openlog("ghostbuster", LOG_PID, LOG_AUTH);
	if ((u=open("/etc/utmp", O_RDWR))<0) {
		syslog(LOG_ERR, "/etc/utmp: %m");
		exit(1);
	}
	gr=getgrnam("tty"); endgrent();
	(void)fstat(u, &st);
	if ((st.st_size%sizeof (struct utmp))!=0) {
		syslog(LOG_ALERT, "utmp corrupt");
		exit(1);
	}
	if (!(ubuf=malloc(st.st_size))) abort();
	if ((s=read(u, ubuf, st.st_size))!=st.st_size) {
		if (s<0) syslog(LOG_ERR, "read error: %m");
		else syslog(LOG_ERR, "read expected %d, got %d\n",
			st.st_size, s);
		exit(1);
	}
	s/=sizeof (struct utmp);
	for (ut=(struct utmp *)ubuf;s>0;--s,ut++) {
		if (ut->ut_line[0]!='t'||ut->ut_line[1]!='t'||
			ut->ut_line[2]!='y'|| ut->ut_line[3]<'p'||
			ut->ut_line[3]>'s'||!ut->ut_name[0]) continue;
		sprintf(devname, "/dev/pty%.5s", &ut->ut_line[3]);
		if ((p=open(devname, O_RDWR))<0) continue;
		devname[5]='t';
		bzero(ut->ut_name, sizeof ut->ut_name);
		bzero(ut->ut_host, sizeof ut->ut_host);
		(void)time(&ut->ut_time);
	 	if ((w=open("/usr/adm/wtmp", O_WRONLY|O_APPEND))>=0) {
			(void)write(w, (char *)ut, sizeof (struct utmp));
			(void)close(w);
		}
		(void)lseek(u, (long)((char *)ut-ubuf), L_SET);
		(void)write(u, (char *)ut, sizeof (struct utmp));
		(void)chmod(devname, 0666);
		(void)chown(devname, 0, gr ? gr->gr_gid : 0);
		(void)close(p);
		syslog(LOG_NOTICE, "%s logged out", ut->ut_line);
	}
	(void)close(u);
	exit(0);
}