[net.sources] Program to watch for a user to become active.

mikel@bmcg.UUCP (11/20/84)

Enclosed is the source and manual page for a program running under 4.1BSD.  It
is designed to watch for a particular user and give a message on your terminal
when the user is active.  It creates a background process that, at low priorty,
polls the logged on user file for the name you've requested, calculates a
the terminals idle time, and if it was active within the last 2 minutes outputs
a bell and a message to your terminal and dies.  This program may be a kluge
and can be implemented with 6 dozen options, but what can you expect for my
first unix program?  Use and enjoy!

Mike Lesher
Burroughs ASG, San Diego, CA.
(..!bmcg!mikel)
--------------- Cut Here ---------------
#! /bin/sh
# The rest of this file is a shell script which will extract:
# watchfor.man watchfor.c
echo x - watchfor.man
cat >watchfor.man <<'!Funky!Stuff!'
.TH WATCHFOR LOCAL 7/30/84
.SH NAME
watchfor \- tell the user when a specified user is active
.SH SYNOPSIS
.B watchfor
.I USERNAME
.SH DESCRIPTION
.PP
.B Watchfor
takes the name of the user you are looking for and informs you when he is
active on the system.
.PP
For example:
.br
.in 1i
.B "watchfor mr-frog"
.br
.B "watchfor rwt"
.br
.in -1i
.PP
When
.I watchfor
finds that the user you are looking for is logged in and has been active
within the last 2 minutes, it will display the message:
.PP
REAL_USER_NAME is active on ttynd!!!
.PP
If it cannot find the user, it will look every minute for him until he is
found. Since
.I watchfor
creates a low priorty background process to do it's checking, the message will
be output to your terminal, no matter what you are doing and your terminal will
be available for continued processing.
.SH AUTHOR
Mike Lesher
.SH FILES
/dev/tty* \- tty of the user your looking for.
.br
/etc/utmp \- list of the logged on users.
.br
/etc/passwd \- the users real name.
.SH DIAGNOSTICS
Exit code is 1 given for unsupplied user name, error
code 2 if undefined user and error code 3 if it cannot open /etc/utmp.
.SH BUGS
.I Watchfor
may only be specified with one user name at a time. Several names should be
able to be specified.
.PP
The amount of time to wait should be able to be modified with a -X switch.
.PP
The output may be intermixed with the output of other programs, even other
watchfors.
!Funky!Stuff!
echo x - watchfor.c
cat >watchfor.c <<'!Funky!Stuff!'
/*
 *				*Watchfor*
 *
 * This program is designed to watch for activity on a users terminal.
 * This is done by checking for a valid user, then forking a process that
 * will, every WAIT_TIME, look for the user to be logged on and him being
 * active on the terminal. When these conditions are true, a message that
 * this person is active is output to your terminal no matter what program
 * you are running if any.
 *
 */

#define WAIT_TIME 60			/* Background jobs wait time */
#define IDLE_LIMIT 120			/* Max idle for non-report */
#define TTY_FILE "/u/fred/vax/term_map"	/* contains tty locations */
#define LMAX sizeof(utmp.ut_line)

#include <sys/param.h>
#include <stdio.h>
#include <ctype.h>
#include <utmp.h>
#include <time.h>
#include <sys/stat.h>
#include <pwd.h>

struct utmp utmp;
struct passwd *pwd, *getpwnam();
char oldlogin[20], newlogin[20];

main(argc, argv)
int argc;
char *argv[];
{
	FILE *fi;
	long idletime();

	/* error if not two arguments */
	if (argc != 2) {
		fprintf(stderr, "watchfor: user name not supplied\n");
		fprintf(stderr, "usage - watchfor <user_name>\n");
		exit(1);
	}

	/* find out if it's a valid user name */
	if ((pwd = getpwnam(argv[1])) == NULL) {
		fprintf(stderr, "watchfor: not a defined user\n");
		exit(2);
	}

	/* get a copy of the current login */
	strcpy(oldlogin, getlogin());

	/* open the user logged in file */
	if ((fi = fopen("/etc/utmp", "r")) == NULL) {
		fprintf(stderr, "watchfor: cannot open utmp\n");
		exit(3);
	}

	/*fork and exit if not the background process */
	if (fork() != 0) exit(0);
	/* give it a low priorty */
	nice(40);

loop:	/* if the login code has changed, the parent died so exit. */
	strcpy(newlogin, getlogin());
	if (strcmp(newlogin, oldlogin) != 0)
		exit(0);

	/* read from beginning of file */
	rewind(fi);
	/* read in each record of user logged in file */
	while (fread((char *)&utmp, sizeof(utmp), 1, fi) != NULL) {
		/* end of file? */
		if(utmp.ut_name[0] != '\0') {
			/* is it the requested name? */
			if (strcmp(argv[1], utmp.ut_name) == 0) {
				/* is the idle time within the limit? */
				if (idletime() < IDLE_LIMIT) {
					/* by jove I think we got him! */
					/* back to high gear */
					nice(-40);
					print_user_name();
					fprintf(stderr,
						" is active on %s!!\7\n",
						utmp.ut_line);
					exit(0);
				}
			}
		}
	}
	/* sleep some so we don't take up all the CPU time */
	sleep(WAIT_TIME);
	/* try again */
	goto loop;
}

/* find & return number of seconds current tty has been idle */
idletime()
{
	struct stat stbuf;
	time_t	now;			/* the current time of day */
	long diff;
	char ttyname[20];

	strcpy(ttyname, "/dev/");
	strcatn(ttyname, utmp.ut_line, LMAX);
	stat(ttyname, &stbuf);
	time(&now);
	diff = now - stbuf.st_atime;
	if (diff < 0) diff = 0;
	return(diff);
}

print_user_name()
{
	int i = 0;

	while (isalnum(pwd->pw_gecos[i]) || isspace(pwd->pw_gecos[i]))
		fprintf(stderr, "%c", pwd->pw_gecos[i++]);
}
!Funky!Stuff!