[comp.sources.d] autologout

hans@let.vu.nl (Hans Varkevisser) (01/13/89)

I have changed the w.c program (BSD 4.3 w.c version 5.3) to a programm
with the following options:

I have renamed w.c to autologout.c.

autologout -k 		kill all users with only one proces and 30 min
			idle
			Kill all users who are 120 minutes idle without
			looking to the proces

autologout		The same as w

I don't send the complete file, I only send the diff file because of
the copywrite of w.c.

You can change the program to an other idle time etc.
I have added some explanation in the file, because I needed the program
very badly there is a bug in it. This bug must be solved but I don't
have the time for it.

The bug is: if the idle time > 120 the user is logout, but not always
by killing the shell with the hangup signal. Sometimes child processes
are killed with hangup instead and finaly the shell is killed.
This is because I look at the lowest proces-id and not to the
number of the shell pid.
the diff file follows.

cut here -------------------- cut here ---------------- cut here

7,14c7,11
< /* This programm is adapted from the programm w.c.
<  * There some changes and some features are deleted
<  * I add the autologout feature, the programm looks at the
<  * idle time and the number of processes. If the idle time is > 30
<  * and the number of processes = 1 the the user is logout by kill signal
<  * Hans Varkevisser, Fac of Literature Free University the Netherlands
<  * let.vu.nl!hans or hans@let.vu.nl   (UUCP)
<  */
---
> #ifndef lint
> char copyright[] =
> "@(#) Copyright (c) 1980 Regents of the University of California.\n\
>  All rights reserved.\n";
> #endif not lint
17c14
< static char sccsid[] = "@(#)autologout.c	1.0 (Free University) 1/11/89";
---
> static char sccsid[] = "@(#)w.c	5.3 (Berkeley) 2/23/86";
19a17,22
> /*
>  * w - print system status (who and what)
>  *
>  * This program is similar to the systat command on Tenex/Tops 10/20
>  * It needs read permission on /dev/mem, /dev/kmem, and /dev/drum.
>  */
104,119d106
< /* new variables for autologout */
< 
< #define KILL_SIGNAL	"-1"	/* use this for kill, -1 = hangup */
< 
< int 	tmp_pid = 0;		/* temporary proces id */
< int 	tmp_uid = 0;		/* temporary user id */
< int	max_idle = 30;		/* max idle time in minutes */
< int	max_limit = 120;	/* max limit time in minutes */
< int 	kill_on = 0;		/* true if -k flag, kill idle process */
< int 	tot_proc = 0;		/* total of processes */
< char	tmp_itoa[10];		/* tmp var to convert int to string */
< char	command[512];		/* command string for systemcall */
< int	min_number = 100;	/* user number less than min_number
< 				 * won't be affected
< 				*/
< 
159,162d145
< 				case 'k':
< 					kill_on++;
< 					break;
< 
213a197,199
> 	if (header) {
> 		/* Print time of day */
> 		prtat(&now);
214a201,206
> 		/*
> 		 * Print how long system has been up.
> 		 * (Found by looking for "boottime" in kernel)
> 		 */
> 		lseek(kmem, (long)nl[X_BOOTTIME].n_value, 0);
> 		read(kmem, &boottime, sizeof (boottime));
215a208,260
> 		uptime = now - boottime.tv_sec;
> 		uptime += 30;
> 		days = uptime / (60*60*24);
> 		uptime %= (60*60*24);
> 		hrs = uptime / (60*60);
> 		uptime %= (60*60);
> 		mins = uptime / 60;
> 
> 		printf("  up");
> 		if (days > 0)
> 			printf(" %d day%s,", days, days>1?"s":"");
> 		if (hrs > 0 && mins > 0) {
> 			printf(" %2d:%02d,", hrs, mins);
> 		} else {
> 			if (hrs > 0)
> 				printf(" %d hr%s,", hrs, hrs>1?"s":"");
> 			if (mins > 0)
> 				printf(" %d min%s,", mins, mins>1?"s":"");
> 		}
> 
> 		/* Print number of users logged in to system */
> 		while (fread(&utmp, sizeof(utmp), 1, ut)) {
> 			if (utmp.ut_name[0] != '\0')
> 				nusers++;
> 		}
> 		rewind(ut);
> 		printf("  %d user%s", nusers, nusers>1?"s":"");
> 
> 		/*
> 		 * Print 1, 5, and 15 minute load averages.
> 		 * (Found by looking in kernel for avenrun).
> 		 */
> 		printf(",  load average:");
> 		lseek(kmem, (long)nl[X_AVENRUN].n_value, 0);
> 		read(kmem, avenrun, sizeof(avenrun));
> 		for (i = 0; i < (sizeof(avenrun)/sizeof(avenrun[0])); i++) {
> 			if (i > 0)
> 				printf(",");
> 			printf(" %.2f", avenrun[i]);
> 		}
> 		printf("\n");
> 		if (firstchar == 'u')
> 			exit(0);
> 
> 		/* Headers for rest of output */
> 		if (lflag)
> 			printf("User     tty       login@  idle   JCPU   PCPU  what\n");
> 		else
> 			printf("User    tty  idle  what\n");
> 		fflush(stdout);
> 	}
> 
> 
233d277
< 		tot_proc=0;
239,244c283,299
< 			tot_proc++;
< 			 
< 			if (tmp_pid == 0)
< 				tmp_pid=pr[i].w_pid;
< 			tmp_uid=pr[i].w_uid;
< 
---
> 			/* 
> 			 * Meaning of debug fields following proc name is:
> 			 * & by itself: ignoring both SIGINT and QUIT.
> 			 *		(==> this proc is not a candidate.)
> 			 * & <i> <q>:   i is SIGINT status, q is quit.
> 			 *		0 == DFL, 1 == IGN, 2 == caught.
> 			 * *:		proc pgrp == tty pgrp.
> 			 */
> 			 if (debug) {
> 				printf("\t\t%d\t%s", pr[i].w_pid, pr[i].w_args);
> 				if ((j=pr[i].w_igintr) > 0)
> 					if (j==IGINT)
> 						printf(" &");
> 					else
> 						printf(" & %d %d", j%3, j/3);
> 				printf("\n");
> 			}
248a304,314
> 			if(pr[i].w_pid>curpid && (pr[i].w_igintr!=IGINT || empty)){
> 				curpid = pr[i].w_pid;
> 				strcpy(doing, lflag ? pr[i].w_args : pr[i].w_comm);
> #ifdef notdef
> 				if (doing[0]==0 || doing[0]=='-' && doing[1]<=' ' || doing[0] == '?') {
> 					strcat(doing, " (");
> 					strcat(doing, pr[i].w_comm);
> 					strcat(doing, ")");
> 				}
> #endif
> 			}
250,275d315
< 
< 	/* -k flag log users out who are idle > 30 minutes */
< 	if (kill_on == 1) {
< 	
< 		/* convert int pid to string */
< 		itoa(tmp_pid,tmp_itoa);		
< 
< 		/* put command in command string */
< 		strcpy(command,"kill ");
< 		strcat(command, KILL_SIGNAL);
< 		strcat(command, " ");
< 
< 		/* append pid to commandstring */
< 		strcat(command,tmp_itoa);
< 	/* kill user for idle > 120 minutes  don't look at processes*/
< 
< 		if ((tmp_uid > min_number) && ( idle >= max_limit)){
< 	/* execute a kill -1 on pid */
< 	system(command);	
< 		}
< 	/* kill user for idle > 30 minutes and only one process running */
< 		if ((tmp_uid > min_number) && ( idle >= max_idle) && (tot_proc == 1)){
< 	/* execute a kill -1 on pid */
< 	system( command);	
< 		}
< 	} else {
277,278d316
< 	}	
< 		tmp_pid=0;
302c340
< 		
---
> 
304,305c342
< 	printf("%d\t%d\t%-*.*s ", tmp_uid, tmp_pid, NMAX, NMAX, utmp.ut_name); 
< 		printf("%3d idle \n", idle );
---
> 	printf("%-*.*s ", NMAX, NMAX, utmp.ut_name);
306a344,374
> 	/* print tty user is on */
> 	if (lflag)
> 		/* long form: all (up to) LMAX chars */
> 		printf("%-*.*s", LMAX, LMAX, utmp.ut_line);
> 	else {
> 		/* short form: 2 chars, skipping 'tty' if there */
> 		if (utmp.ut_line[0]=='t' && utmp.ut_line[1]=='t' && utmp.ut_line[2]=='y')
> 			printf("%-2.2s", &utmp.ut_line[3]);
> 		else
> 			printf("%-2.2s", utmp.ut_line);
> 	}
> 
> 	if (lflag)
> 		/* print when the user logged in */
> 		prtat(&utmp.ut_time);
> 
> 	/* print idle time */
> 	if (idle >= 36 * 60)
> 		printf("%2ddays ", (idle + 12 * 60) / (24 * 60));
> 	else
> 		prttime(idle," ");
> 
> 	if (lflag) {
> 		/* print CPU time for all processes & children */
> 		prttime(jobtime," ");
> 		/* print cpu time for interesting process */
> 		prttime(proctime," ");
> 	}
> 
> 	/* what user is doing, either command tail or args */
> 	printf(" %-.32s\n",doing);
606,633d673
< }
< itoa(n,s)
< char s[];
< int n;
< {
< 	int i, sign;
< 	
< 	if ((sign = n) < 0)
< 		n = -n;
< 	i = 0;
< 	do {
< 		s[i++] = n % 10 + '0';
< 	} while (( n /= 10 ) > 0 );
< 	if (sign < 0)
< 		s[i++] = '-';
< 	s[i] = '\0';
< 	reverse(s);
< }
< reverse (s)
< char s[];
< {
< 	int c, i, j;
< 
< 	for (i = 0, j = strlen(s)-1; i < j; i++, j--) {
< 		c = s[i];
< 		s[i] = s[j];
< 		s[j] = c;
< 	}

hans@let.vu.nl (Hans Varkevisser) (01/18/89)

This only is for users of BSD 4.3 with w.c version 5.3

I have made changes to the program w.c and changed the name to
autologout.c.
I use the program autologout to logout users who are idle for a given time
You set the time in the source file.
There are two var for time, max_idle and max_limit. 
max_idle is used to logout a user who is idle for > max_idle and 
who only has the shellproces running (number of processes =1).
max_limit is used to logout a user who is idle for > max_limit and can
have more processes running, only the shellproces is killed.
I use the kill -1, pid because -1 is the hangup signal .
I find this the best way to do, of course you can use other signals.
I use the var min_number to test for uid > given number, this is used by
us to leave staff users logged in.
I put an entry in crontab that start every 5 minutes autologout -k.

Because of the copyright I only have send the diff between w.c and autologout.c.
The next vars I used for the program, see the diff file at the end.


 #define KILL_SIGNAL	"-1"	/* use this for kill, -1 = hangup */

int 	tmp_pid = 0;		/* temporary proces id */
int 	tmp_uid = 0;		/* temporary user id */
int	max_idle = 30;		/* max idle time in minutes */
int	max_limit = 60;		/* max limit time in minutes */
int 	kill_on = 0;		/* true if -k flag, kill idle process */
int 	tot_proc = 0;		/* total of processes */
char	tmp_itoa[10];		/* tmp var to convert int to string */
char	command[512];		/* command string for systemcall */
int	min_number = 100;	/* user number less than min_number


The text is the result of diff -e w.c autologout.c
-------- cut here ------------- cut here ----------------
673a
}
itoa(n,s)
char s[];
int n;
{
	int i, sign;
	
	if ((sign = n) < 0)
		n = -n;
	i = 0;
	do {
		s[i++] = n % 10 + '0';
	} while (( n /= 10 ) > 0 );
	if (sign < 0)
		s[i++] = '-';
	s[i] = '\0';
	reverse(s);
}
reverse (s)
char s[];
{
	int c, i, j;

	for (i = 0, j = strlen(s)-1; i < j; i++, j--) {
		c = s[i];
		s[i] = s[j];
		s[j] = c;
	}
}
kill_shell()
{	
	/* convert int pid to string */
	itoa(tmp_pid,tmp_itoa);		

	/* put command in command string */
	strcpy(command,"kill ");

	/* KILL_SIGNAL can be user defined */
	strcat(command, KILL_SIGNAL);
	strcat(command, " ");

	/* append pid to commandstring */
	strcat(command,tmp_itoa);

/* kill user for idle > 60 minutes  don't look at number of processes*/
	
	if ((tmp_uid > min_number) && ( idle >= max_limit)){
		/* execute a kill -1 on pid */
		system(command);
	
	}
	/* kill user for idle > 30 minutes and only one process running */
	if ((tmp_uid > min_number) && ( idle >= max_idle) && (tot_proc == 1)){
	/* execute a kill -1 on pid */
		system(command);
	}
.
535a
		pr[np].w_pgrp = mproc.p_pgrp;
.
344,374d
342c
	printf("pid %5d\t%-*.*s ",  tmp_pid, NMAX, NMAX, utmp.ut_name); 
		printf("%3d idle \t%-.32s\n", idle,doing );
.
340c
		
.
318a
}
.
317a
	strcpy(tmp_doing, lflag ? pr[i].w_args : pr[i].w_comm);
	if ((doing[0] == '-' || doing[0] == 0) && (tmp_pid == 0))
		tmp_pid=pr[i].w_pid;
	if ((tmp_doing[0] == '-' || tmp_doing[0] == 0) && (tmp_pid == 0))
		tmp_pid=pr[i].w_pid;
	
	}	
	/* -k flag log users out who are idle > 30 minutes */
	if ((kill_on == 1) && ( tmp_pid >= 10)) 
		kill_shell();	
	else 
		putline();
.
304,316c

	if(pr[i].w_pid>curpid && (pr[i].w_igintr!=IGINT || empty)){
		curpid = pr[i].w_pid;
		strcpy(doing, lflag ? pr[i].w_args : pr[i].w_comm);
.
283,297c
			tot_proc++;
	
			tmp_uid=pr[i].w_uid;

			if (debug) {
				printf("\t%5d\t%s",pr[i].w_pid,pr[i].w_args);
.
277a
		tot_proc=0;
		tmp_pid=0;
.
208,260d
201,206d
197,199d
163c
				case 'a':
.
145a
				case 'k':
					kill_on++;
					break;

.
106a
/* new variables for autologout */

#define KILL_SIGNAL	"-1"	/* use this for kill, -1 = hangup */

int 	tmp_pid = 0;		/* temporary proces id */
int 	tmp_uid = 0;		/* temporary user id */
int	max_idle = 30;		/* max idle time in minutes */
int	max_limit = 60;		/* max limit time in minutes */
int 	kill_on = 0;		/* true if -k flag, kill idle process */
int 	tot_proc = 0;		/* total of processes */
char	tmp_itoa[10];		/* tmp var to convert int to string */
char	command[512];		/* command string for systemcall */
int	min_number = 100;	/* user number less than min_number
				 * won't be affected
				*/
char	tmp_doing[520];		/* process attached to terminal */

.
41a
	short	w_pgrp;			/* proc.p_pgrp */
.
17,22d
14c
static char sccsid[] = "@(#)autologout.c	1.0 (Free University) 1/11/89";
.
7,11c
/* This programm is adapted from the programm w.c.
 * There some changes and some features are deleted
 * I add the autologout feature, the programm looks at the
 * idle time and the number of processes. If the idle time is > 30
 * and the number of processes = 1 the the user is logout by kill signal
 * For safety there is a check on the uid, on our computer we only kill
 * the user if the uid > 100.
 * Hans Varkevisser, Fac of Literature Free University the Netherlands
 * let.vu.nl!hans or hans@let.vu.nl   (UUCP)
 */
.
----------- end -----------------

-- 
Organisation:	Free University, Faculty of Literature
                Amsterdam, the Netherlands           
Name:		Hans Varkevisser (system administrator) 
                hans@let.vu.nl  or let.vu.nl!hans     UUCP