Repost of phdaemon - version #3

Lee Hounshell tlh at pbhacker.UUCP
Sat Jul 16 12:51:46 AEST 1988


I've had a few requests for a repost of the fixed version of phdaemon..
for those of you not familiar with it, phdaemon will monitor both
incoming and outgoing calls on your Unix PC.

	enjoy.

	Lee Hounshell

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

/************************************************************************\
**									**
** Program name: phdaemon.c (Phone Daemon)				**
** Programmers:	 original version   - Paul J. Condie (UUCP=pcbox!pjc)	**
**		 modified version   - Lenny Tropiano (UUCP=icus!lenny)	**
**		 fixes/enhancements - Lee Hounshell  (UUCP=pbhacker!tlh)**
**		 kernel	access rtns - Michael Ditto (ford at crash.CTS.COM)**
** Date:	 December 13, 1987					**
**									**
**************************************************************************
**									**
** Program use:	 Program is run	as a daemon process from the boot	**
**		 procedure /etc/rc.  It	can be placed in /etc/daemons/	**
**		 and will be started up	apon system boot.  This	program	**
**		 monitors the data line	(defined as /dev/ph1) for	**
**		 any kind of activity (or lack thereof)	and displays	**
**		 the information in the	Phone Managers window. Freeing	**
**		 up any	other windows from being allocated for that use	**
**									**
**		 This program checks for DATA or VOICE,	UUCP logins,	**
**		 User logins, UUCP outgoing, Internal use of outgoing	**
**		 modem.	 This process will terminate if	the /etc/ph	**
**		 process is terminated.					**
**									**
** Enhancements: Bugs in properly detecting incoming calls have	been	**
**		 fixed.	 The program now reports stray lock files in	**
**		 the status window.  Errors are	reported by placing	**
**		 "ERROR" in the	status window.	User logins and	errors	**
**		 are now logged	in the "/usr/adm/phdaemon.log" file.	**
**									**
\************************************************************************/

#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <status.h>
#include <sys/types.h>
#include <sys/window.h>
#include <sys/stat.h>
#include <sys/tune.h>
#include <sys/proc.h>
#include <sys/user.h>
#include <sys/dir.h>
#include <sys/ph.h>
#include <sys/phone.h>
#include <nlist.h>
#include <pwd.h>
#include <utmp.h>
#include <time.h>

#define	SLEEP	15			/* Sleep time (interval	between)*/
#define	SNOOZE	5			/* Short Sleep time (short time)*/
#define	NICE	5			/* Niceness value		*/
#define	LINE	"ph1"			/* /etc/utmp user for DATA2	*/
#define	BEEP	"\07\07"		/* ring	the bell		*/
#define	PHPID	"/usr/lib/ua/phpid"	/* File	has pid	of /etc/ph	*/
#define	LOCKDIR	"/usr/spool/uucp"	/* UUCP	Lock Directory		*/
#define	LOCKFIL	"LCK.."			/* Lock	file prefix		*/
#define	OFFSET	sizeof(struct phdef)	/* kernel offset (0 for	ph0)	*/
#define	LOGFILE	"/usr/adm/phdaemon.log"	/* login tracking file		*/

/* Command to locate window device in use by /etc/ph */
#define	WINDCMD	"ps -p%d | grep	ph | cut -c9-11"

#define	ESC	27
#define	BOLD	1
#define	REV	7
#define	ROW	1
#define	COL	24

#define	ERROR	 ":%c[%dm ERROR  %c[0m"	/* an error was	detected	*/
#define	INCOMING "<%c[%dm%-8.8s%c[0m"	/* Incoming call string		*/
#define	OUTGOING ">%c[%dm%-8.8s%c[0m"	/* Outgoing call string		*/
#define	IDLE	 "%c[0m: IDLE   "	/* Idle	phone device		*/
#define	LOGIN	 "<LOGIN   "		/* Incoming login		*/
#define	BLANK	 ":        "
#define	UUCICO	 "%c[%dm%cUUCICO  %c[0m"/* Incoming undetermined uucico	*/
#define	HOME	 "%c[%d;%dH"		/* Position cursor in a	window	*/

/* Types of calls  */
#define	IN_USER	 1			/* User	login			*/
#define	OUT_USER 2			/* User	use of on board	modem	*/
#define	UUCP	 3			/* UUCP	login or dial out	*/
#define	LPROCESS 4			/* Login login			*/
#define	PPROCESS 5			/* Pending login		*/

int	wfd;				/* Window file descriptor	*/
int	kmemfd;				/* /dev/kmem file descriptor	*/
int	memfd;				/* /dev/mem file descriptor	*/
int	MAXPROC;			/* max processes available	*/

extern	long lseek();			/* lseek(2) function		*/
void	read_kmem();			/* function to read memory	*/
void	read_mem();			/* function to read memory	*/
char	*cur_time();			/* function to return sys time	*/
char	buffer[BUFSIZ];			/* buffer for strings		*/
char	userlogin[12];			/* user	login name		*/
char	lockph[64];			/* currently monitored LCK file	*/
char	windev[10];			/* window device of /etc/ph	*/
struct	proc	proc;			/* Process block read from kmem	*/
int	phpid;				/* Process id of /etc/ph	*/
FILE	*log_file;			/* /usr/adm/phdaemon.log	*/

struct nlist unixsym[] = {		/* /unix name list of symbols	*/
    { "tuhi", },
    { "proc", },
    { "phndef",	},
    { NULL, },
};

/* Program lists for identification */
struct	programs {			/* CUSTOMIZE TO	FIT YOUR NEEDS */
	char	*name;
	int	type;
} prog[] = {
	{ "sh",		IN_USER	},	/* User	program	when logged in */
	{ "ksh",	IN_USER	},	/* User	program	when logged in */
	{ "cu",		OUT_USER },	/* Program used	to dial	out    */
	{ "kermit",	OUT_USER },	/* Program used	to dial	out    */
	{ "async_main",	OUT_USER },	/* Program used	to dial	out    */
	{ "term",	OUT_USER },	/* Program used	to dial	out    */
	{ "uucico",	UUCP },		/* UUCP	program	dial-in/out    */
	{ "uusched",	UUCP },		/* UUCP	program	dial-in/out    */
	{ "login",	LPROCESS },	/* Login process	       */
	{ "getty",	LPROCESS },	/* Login process	       */
	{ "uugetty",	LPROCESS },	/* Login process	       */
	{ "",		PPROCESS },	/* FAILS all cases	       */
};


main(argc,argv)
int	argc;
char	*argv[];
{
	FILE	*fp, *pfp;
	int	terminate();

	if (fork() != 0)  {		/* detach process-daemon */
		exit(0);
	}
	nice(NICE);			/* Be a	little nice	*/
	signal (SIGHUP,	SIG_IGN);
	signal (SIGINT,	SIG_IGN);
	signal (SIGTERM, terminate);
	if ((log_file =	fopen(LOGFILE, "a")) ==	NULL)  {
		exit(1);
	}
	setbuf(log_file, (char *) 0);
	setup();			/* setup /dev/kmem and /unix */

	if (access(PHPID, 0) ==	-1) {
		sprintf(buffer,	"phone manager file %s does not	exist",	PHPID);
		werror(buffer,0);
	}
	if ((fp	= fopen(PHPID,"r")) == NULL) {
		sprintf(buffer,	"can't open file %s", PHPID);
		werror(buffer,0);
	}
	fscanf(fp,"%d",&phpid);		/* read	the process id of /etc/ph */
	fclose(fp);

	if (!findproc(phpid)) {
		errno =	ESRCH;
		werror("phone manager /etc/ph not running",0);
	}

	sprintf(buffer,WINDCMD,phpid);
	if ((pfp = popen(buffer,"r")) == NULL)	{
		werror("can't open pipe	to 'ps'	command",0);
	}
	if (fgets(buffer,3,pfp)	== NULL)  {
		werror("nothing	returned from pipe",1);
	}
	pclose(pfp);
	sprintf(windev,"/dev/%s",buffer);

	setpgrp();
	if ((wfd = open(windev,O_RDWR))	== -1) {
		sprintf(buffer,	"can't open %s", windev);
		werror(buffer,0);
	}
	close(0); dup(wfd);
	close(1); dup(wfd);
	close(2); dup(wfd);

	daemon_process();

	terminate();

}

daemon_process()
{
	int	 lockfd, calltype;
	short	 lockpid;
	char	 idle[20],
		 command[DIRSIZ],	/* Command of program running	*/
		 *findmachine(),
		 *getcommand(),
		 machine[12];
	struct	 phdef	 phblock;
	struct	 passwd	*pwent,
			*getpwnam(),
			*getpwuid();
	struct	utmp	*getutid(),
			*utmp,
			uph1;
	int	dfd;			/* Directory file descriptor	*/
	int	rflag =	1, beep	= 1, fnd_user = 0, wait_a_bit = 0;
	static	struct	direct	dirbuf;	/* Directory entry buffer	*/

	home_cursor();
	sprintf(idle, IDLE, ESC);
	write(0,idle,strlen(idle));
	while (findproc(phpid))	{		/* Process still exists	*/
	    if ((dfd = open(LOCKDIR, O_RDONLY))	== -1)
		werror("can't open lock	directory",0);
	    while (1)  {
		  if (rflag)  {
			if (read(dfd, &dirbuf, sizeof (struct direct))
				!= (sizeof (struct direct))) break;
			if ((dirbuf.d_ino != 0)
			    && (strncmp(dirbuf.d_name, LOCKFIL,	5) == 0)) {
				sprintf(lockph,"%s/%s",LOCKDIR,dirbuf.d_name);
				rflag =	0;
			}
			else continue;
		  }
		  else sleep(SNOOZE);	       /* Take a few ZZzzz... */
		  read_kmem(&phblock,
			   (unixsym[2].n_value + OFFSET),
			   (long)sizeof	(struct	phdef));

		  if (phblock.p_lineparam & DATA) {
			/* Check lock file existence */
			if (access(lockph,0) ==	-1) {
			   home_cursor();
			   write(0,idle,strlen(idle));
			   beep	= rflag	= 1;
			   continue;	       /* no file found	*/
			}

			if ((lockfd = open(lockph, O_RDONLY)) == -1) {
			   sprintf(buffer, "can't open %s", lockph);
			   werror(buffer,0);
			}
			read(lockfd, &lockpid, sizeof(short));
			read(lockfd, &lockpid, sizeof(short));	/* HDB UUCP */
			close(lockfd);

			if (!findproc(lockpid))	{
				char lbuf[20];
				if (strncmp(&dirbuf.d_name[5], "ph0", 3))  {
LCK_ERROR:			    sprintf(lbuf, "%c[%dm?%-8.8s%c[0m",
					ESC, REV, &dirbuf.d_name[5], ESC);
				    home_cursor();
				    write(0,lbuf,strlen(lbuf));
				}
				continue;
			}

			sprintf(command,"%s",getcommand());
			calltype = check_command(command);

			if (calltype ==	PPROCESS)  {
			    if (!strncmp(&dirbuf.d_name[5], "ph0", 3))	{
				rflag =	1;
STILL_THERE:			strcpy (uph1.ut_id, LINE);	/* for getuid */
				uph1.ut_type = LOGIN_PROCESS;
				/* Find	out whats happening with data line */
				utmpname ("/etc/utmp");		/* rewind */
				utmp = getutid (&uph1);
				if (utmp == NULL || strcmp (utmp->ut_id,LINE)) {
					werror("Internal Error:	/etc/utmp",0);
				}
				if (utmp->ut_type == USER_PROCESS)  {
					if (wait_a_bit)  {
						wait_a_bit = 0;
						sleep(SNOOZE);
						continue;
					}
					if (beep)  {
					    sprintf(buffer,INCOMING,
						ESC,REV,utmp->ut_user,ESC);
			   		    home_cursor();
					    write(0,buffer,strlen(buffer));
					    write(0,BEEP,2);
					    beep = 0;
					    fprintf(log_file,
						"USER %s logged IN at %s\n",
						utmp->ut_user, cur_time());
					    fnd_user = 1;
					}
					sleep(SNOOZE);
					goto STILL_THERE;
				}
				if (fnd_user)  {
					fprintf(log_file,
						"USER %s logged OUT at %s\n",
						utmp->ut_user, cur_time());
					wait_a_bit = 1;
					fnd_user = 0;
					continue;
				}
			    }
			    else goto LCK_ERROR;
			}

			wait_a_bit = 1;
			setpwent();	/* rewind /etc/passwd */
			if (calltype ==	OUT_USER) {
				if ((pwent = getpwuid(proc.p_uid)) == NULL) {
				    sprintf(buffer,
					"cannot	locate uid %d in /etc/passwd",
					proc.p_uid);
				    werror(buffer,1);
				}
			}
			else if	(calltype == IN_USER) {
				utmpentry(LINE);
				if (*userlogin == NULL)	{
					write(0, LOGIN,	strlen(LOGIN));
					continue;
				}
				if ((pwent = getpwnam(userlogin)) == NULL) {
				    sprintf(buffer,
					"cannot	locate user %s in /etc/passwd",
					userlogin);
				    werror(buffer,1);
				}
			}
			endpwent();	/* close /etc/passwd */

			home_cursor();
			switch (calltype) {
			   case	OUT_USER:
				if (beep)  {
					sprintf(buffer,OUTGOING,ESC,REV,
						pwent->pw_name,	ESC);
					write(0,buffer,strlen(buffer));
					beep = 0;
				}
				break;
			   case	UUCP:
				sprintf(machine,"%s",(char *)findmachine());
				utmpentry(LINE);
				if (*userlogin == NULL)	{
					if (*machine !=	NULL)  {
						sprintf(buffer,OUTGOING,
							ESC,BOLD,machine,ESC);
					}
					else  {
						sprintf(buffer,UUCICO,ESC,
							BOLD,'>',ESC);
					}
				}
				else {
					if (*machine !=	NULL)  {
						sprintf(buffer,INCOMING,
							ESC,BOLD,machine,ESC);
					}
					else  {
						sprintf(buffer,UUCICO,
							ESC,BOLD,'<',ESC);
					}
				}
				endutent();
				if (beep)  {
					write(0,buffer,strlen(buffer));
					write(0,BEEP,2);
					beep = 0;
				}
				break;
			}
		  }
	    }
	    close(dfd);
	    if (wait_a_bit) sleep(SLEEP);
	}
}

check_command(cmd)			/* Check the list of commands */
char *cmd;
{
	register i;

	i = 0;
	while (*(prog[i].name) != NULL)	{
		if (strcmp(prog[i].name, cmd) == 0)
			return(prog[i].type);
		i++;
	}
	return(PPROCESS);
}

utmpentry(line)
char *line;
{
	struct	utmp   *utent, *getutent();

	setutent();
	while ((utent =	getutent()) != NULL) {
	    if (strncmp(utent->ut_line,line,strlen(line)) == 0 &&
		utent->ut_type == USER_PROCESS)	{
			sprintf(userlogin,"%s",utent->ut_user);
			endutent();
			return;
	    }
	}
	endutent();
	*userlogin = NULL;
}

home_cursor()
{
	sprintf(buffer,HOME,ESC,ROW,COL);
	write(0,buffer,7);
}

int terminate()
{
	home_cursor(1);
	write(0,BLANK,strlen(BLANK));
	close(wfd);
	close(kmemfd);
	close(memfd);
	fclose(log_file);
	exit(0);
}

setup()
{
	struct tunable tune;

	if ((kmemfd=open("/dev/kmem", O_RDWR)) == -1)
	   werror("can't open /dev/kmem",0);

	if ((memfd=open("/dev/mem", O_RDWR)) ==	-1)
	   werror("can't open /dev/mem",0);

	if (nlist("/unix", unixsym))
	   werror("can't nlist /unix",0);

	read_kmem((char	*)&tune, (unixsym[0].n_value), (long) sizeof tune);
	read_kmem((char	*)&(unixsym[1].n_value), (unixsym[1].n_value),
		  (long)sizeof (unixsym[1].n_value));

	MAXPROC	= tune.nproc;

}

void read_kmem(caddr, kaddr, nbytes)
char *caddr;
long kaddr;
long nbytes;
{
	if (lseek(kmemfd, kaddr, 0)<0L ||
	    read(kmemfd, caddr,	(unsigned)nbytes) != nbytes )
		werror("can't read /dev/kmem",0);
}

void read_mem(caddr, paddr, nbytes)
  char *caddr;
  long paddr;
  long nbytes;
{
    if (lseek(memfd, paddr, 0)<0L ||
	read(memfd, caddr, (unsigned)nbytes) !=	nbytes)
	      werror("can't read /dev/mem",0);
}

int findproc(pid)
  int pid;
{
	register i;

	for (i=0 ; i<MAXPROC ; ++i) {
	   read_kmem((char *)&proc,
		  (long)&((struct proc *)(unixsym[1].n_value))[i],
		  (long)sizeof proc);
	   if (proc.p_pid == pid)
		return 1;
	}
	return 0;
}

char *findmachine()
{
	int	dfd;			/* Directory file descriptor	*/
	static	struct	direct	dirbuf;	/* Directory entry buffer	*/

	if ((dfd = open(LOCKDIR, O_RDONLY)) == -1)
	      werror("can't open lock directory",0);

	while (read(dfd, &dirbuf, sizeof (struct direct)) ==
	      (sizeof (struct direct)))	{
	   if ((dirbuf.d_ino !=	0) && (strncmp(dirbuf.d_name,LOCKFIL,5)	== 0)) {
		if ((strncmp((char *)&dirbuf.d_name[5],"ph",2)	!= 0) &&
		    (strncmp((char *)&dirbuf.d_name[5],"tty",3)	!= 0)) {
			close(dfd);
			return((char *)&dirbuf.d_name[5]);
		}
	   }
	}

	close(dfd);
	return(NULL);
}

werror(errstr, mode)
  char *errstr;
  int	mode;
{
	extern	char	*sys_errlist[];

	/* Log message in /usr/adm/phdaemon.log	*/
	if (mode == 0)	{
		fprintf(log_file, "%s: %s - %s AT %s",
			__FILE__, errstr, sys_errlist[errno], cur_time());
	}
	else  {
		fprintf(log_file, "%s: %s AT %s",
			__FILE__, errstr, cur_time());
	}
	/* Warn	user about error */
	home_cursor();
	sprintf(buffer,	ERROR, ESC, BOLD, ESC);
	write(0,buffer,strlen(buffer));
	fclose(log_file);
	exit(1);
}

char *getcommand()
{
    static struct user users;
    long   upage;

    if (!proc.p_stat ||	proc.p_stat == SIDL || proc.p_stat == SZOMB)
	return 0;

    if (!(proc.p_flag &	SLOAD))	{
	sprintf(buffer,"can't handle swapped process %d	(flag=%05x)",
		proc.p_pid, proc.p_flag);
	werror(buffer,1);
    }

    upage = (long)ctob(proc.p_addr[0]);
    read_mem((char *)&users, upage + U_OFFSET, (long) sizeof (struct user));

    return(users.u_comm);
}

char *cur_time()
{
	long tim;
	char *ptr;

	tim = time((long *) 0);
	ptr = ctime(&tim);
	if (strlen(ptr)) ptr[strlen(ptr) - 1] = 0;
	return ptr;
}



More information about the Unix-pc.sources mailing list