Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Path: utzoo!mnetor!uunet!seismo!sundc!hqda-ai!icus!lenny
From: lenny@icus.UUCP (Lenny Tropiano)
Newsgroups: unix-pc.sources,comp.sys.att
Subject: phdaemon.c (Phone Daemon source) - Monitor Phone calls
Message-ID: <161@icus.UUCP>
Date: Sun, 6-Dec-87 11:46:31 EST
Article-I.D.: icus.161
Posted: Sun Dec 6 11:46:31 1987
Date-Received: Sat, 12-Dec-87 04:04:42 EST
Organization: ICUS Computer Group, Islip, NY
Lines: 707
Keywords: phone, ph1, DATA, source, daemons
Xref: mnetor comp.sys.att:1992
I finally got around to posting my version of the phone daemon program
that was on the net about a month ago. Enjoy the program!
--- cut here --- --- cut here --- --- cut here --- --- cut here ---
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh README <<'END_OF_README'
XThe phone daemon program was written to keep all those people who jump
Xto login when they hear the relay click on the UNIX pc. The program
Xwas first written by Paul Condie (pcbox!pjc) for this exact reason!
X
XI give thanks to Paul and Michael Ditto (ford@crash.CTS.COM) for his
Xexpertise in the internals of the AT&T UNIX pc kernel.
X
XAfter unpacking the shar file, "su" and become root. Then type:
X
X # make install
X
XThis will create the phdaemon executable and copy it into /etc/daemons/.
XThis directory is looked at by /etc/rc apon boot-up to start all system
Xdaemons. If the directory doesn't exist, it will be created. Make sure
Xthe following code is in /etc/rc somewhere:
X
X
Xif [ -d /etc/daemons ]
Xthen
X DAEMONS=`ls /etc/daemons/*`
X if [ $? != 0 ] ; then DAEMONS=""; fi
X for i in $DAEMONS
X do
X if [ -x $i ]
X then nohup $i > /dev/null 2>&1 &
X fi
X done
Xfi
X
XThings to know about the Phone Daemon. This program is configured
Xfor a multi-line system, where ph0 is the VOICE only line, and ph1 is
Xthe DATA/VOICE line. The program will need a few revisions to allow
Xto work with a ONE line system. If someone cares to do this, please
Xmail me the context diffs.
X
XThe program will display:
X
X DATA 2:IDLE - obviously when the line is idle.
X DATA 2:PENDING - A process is going out, not sure what it is.
X DATA 2:user - When a user locks the modem for outgoing calls
X DATA 2:ph1 - When a user locks (not sure what user) going out
X (Generally happens when the user uses the async_main
X program to dial out) -- The lock file doesn't reflect
X the pid of the locking process. -- POSSIBLE BUG?
X
X The following "machine" is in BOLD video.
X
X DATA 2:machine - When a uucico process locks modem going out.
X DATA 2:icus!lenny
X"Usenet the final frontier" ...{cmcl2!phri, hoptoad}!dasys1!/
END_OF_README
if test 4692 -ne `wc -c Makefile <<'END_OF_Makefile'
X#
X# Makefile to compile phdaemon.c (Phone Daemon)
X# By Lenny Tropiano
X# (c)1987 ICUS Computer Group UUCP: ...icus!lenny
X#
XCFLAGS=-v -O
XLDFLAGS=-s
XLIBS=/lib/crt0s.o /lib/shlib.ifile
XDEST=/etc/daemons/
X#
Xphdaemon.o:
X $(CC) $(CFLAGS) -c phdaemon.c
X#
Xphdaemon: phdaemon.o
X @echo "Loading ..."
X $(LD) $(LDFLAGS) $(LIBS) phdaemon.o -o phdaemon
X#
X# You need to be super-user to do this.
X#
X/etc/daemons:
X mkdir /etc/daemons
X chmod 755 /etc/daemons
X#
Xinstall: phdaemon /etc/daemons
X cp phdaemon /etc/daemons/
X chown root /etc/daemons/phdaemon
X chgrp bin /etc/daemons/phdaemon
X chmod 4750 /etc/daemons/phdaemon
X @echo "Phone Daemon started."
X /etc/daemons/phdaemon
END_OF_Makefile
if test 663 -ne `wc -c phdaemon.c <<'END_OF_phdaemon'
X/************************************************************************\
X** **
X** Program name: phdaemon.c (Phone Daemon) **
X** Programmer: Lenny Tropiano UUCP: ...icus!lenny **
X** Organization: ICUS Computer Group **
X** Date: November 8, 1987 **
X** **
X**************************************************************************
X** **
X** Credits: Thanks to Michael Ditto (ford@crash.CTS.COM) for his **
X** Programs fuser and renice which aided me to write the **
X** Kernel accessing routines. **
X** **
X** Again I want to *THANK* Mike Ditto for his infinite **
X** wisdom when it came to the "internals" of the UNIXPC **
X** **
X** Thanks to Paul J. Condie (pcbox!pjc) for his original **
X** idea of the phdaemon program and some tips on writing **
X** my own. **
X** **
X**************************************************************************
X** **
X** Program use: Program is run as a daemon process from the boot **
X** procedure /etc/rc. It can be placed in /etc/daemons/ **
X** and will be started up apon system boot. This program **
X** monitors the data line (defined as /dev/ph1) for **
X** any kind of activity (or lack thereof) and displays **
X** the information in the Phone Managers window. Freeing **
X** up any other windows from being allocated for that use **
X** **
X** This program checks for DATA or VOICE, UUCP logins, **
X** User logins, UUCP outgoing, Internal use of outgoing **
X** modem. This process will terminate if the /etc/ph **
X** process is terminated. **
X** **
X\************************************************************************/
X
X#include
X#include
X#include
X#include
X#include
X#include
X#include
X#include
X#include
X#include
X#include
X#include
X#include
X#include
X#include
X#include
X#include
X
X#define SLEEP 15 /* Sleep time (interval between)*/
X#define SNOOZE 5 /* Short Sleep time (short time)*/
X#define NICE 5 /* Niceness value */
X#define PHPID "/usr/lib/ua/phpid" /* File has pid of /etc/ph */
X#define DEVICE "/dev/ph1" /* Phone line do checking on */
X#define LINE "ph1" /* Phone line yet another way */
X /* Lock file for modem */
X#define LOCKPH "/usr/spool/uucp/LCK..ph1"
X#define LOCKDIR "/usr/spool/uucp" /* UUCP Lock Directory */
X#define LOCKFIL "LCK.." /* Lock file prefix */
X#define OFFSET sizeof(struct phdef) /* kernel offset (0 for ph0) */
X
X /* Command to locate window device in use by /etc/ph */
X
X#define WINDCMD "ps -p%d | grep ph | cut -c9-11"
X
X#define ESC 27
X#define BOLD 1
X#define REV 7
X#define ROW 1
X#define COL 24
X#define WINSIZE 9
X#define ATTSIZE 8
X
X#define INCOMING "<%c[%dm%-8.8s%c[0m" /* Incoming call string */
X#define OUTGOING ">%c[%dm%-8.8s%c[0m" /* Outgoing call string */
X#define IDLE ":IDLE " /* Idle phone device */
X#define PENDING ":PENDING " /* Incoming/Outgoing pending */
X#define BLANK ": "
X#define LOGIN "ph1 " /* Locked outgoing no process */
X#define HOME "%c[%d;%dH" /* Position cursor in a window */
X
X /* Types of calls */
X#define IN_USER 1 /* User login */
X#define OUT_USER 2 /* User use of on board modem */
X#define UUCP 3 /* UUCP login or dial out */
X#define LPROCESS 4 /* Login login */
X#define PPROCESS 5 /* Pending login */
X
Xint wfd; /* Window file descriptor */
Xint phfd; /* Phone line file descriptor */
Xint kmemfd; /* /dev/kmem file descriptor */
Xint memfd; /* /dev/mem file descriptor */
Xint MAXPROC; /* max processes available */
X
Xextern long lseek(); /* lseek(2) function */
Xvoid read_kmem(); /* function to read memory */
Xvoid read_mem(); /* function to read memory */
Xchar *progname; /* program name */
Xchar buffer[BUFSIZ]; /* buffer for strings */
Xchar userlogin[12]; /* user login name */
Xchar windev[10]; /* window device of /etc/ph */
Xstruct proc proc; /* Process block read from kmem */
Xint phpid; /* Process id of /etc/ph */
X
Xstruct nlist unixsym[] = { /* /unix name list of symbols */
X { "tuhi", },
X { "proc", },
X { "phndef", },
X { NULL, },
X};
X
X /* Program lists for identification */
X
Xstruct programs { /* CUSTOMIZE TO FIT YOUR NEEDS */
X char *name;
X int type;
X} prog[] = {
X { "sh", IN_USER }, /* User program when logged in */
X { "ksh", IN_USER }, /* User program when logged in */
X { "cu", OUT_USER }, /* Program used to dial out */
X { "kermit", OUT_USER }, /* Program used to dial out */
X { "async_main", OUT_USER }, /* Program used to dial out */
X { "term", OUT_USER }, /* Program used to dial out */
X { "uucico", UUCP }, /* UUCP program dial-in/out */
X { "uusched", UUCP }, /* UUCP program dial-in/out */
X { "login", LPROCESS }, /* Login process */
X { "getty", LPROCESS }, /* Login process */
X { "uugetty", LPROCESS }, /* Login process */
X { "", PPROCESS }, /* FAILS all cases: PENDING */
X};
X
X
X/************************************************************************/
X
Xmain(argc,argv)
Xint argc;
Xchar *argv[];
X{
X FILE *fp, *pfp;
X int terminate();
X
X if (fork() != 0) /* detach process-daemon */
X exit(0);
X
X nice(NICE); /* Be a little nice */
X signal (SIGHUP, SIG_IGN);
X signal (SIGINT, SIG_IGN);
X signal (SIGTERM, terminate);
X
X progname = *argv;
X
X setup(); /* setup /dev/kmem and /unix */
X
X if (access(PHPID, 0) == -1) {
X sprintf(buffer, "phone manager file %s does not exist", PHPID);
X werror(buffer,0);
X }
X if ((fp = fopen(PHPID,"r")) == NULL) {
X sprintf(buffer, "can't open file %s", PHPID);
X werror(buffer,0);
X }
X fscanf(fp,"%d",&phpid); /* read the process id of /etc/ph */
X fclose(fp);
X
X if (!findproc(phpid)) {
X errno = ESRCH;
X werror("phone manager /etc/ph not running",0);
X }
X
X sprintf(buffer,WINDCMD,phpid);
X if ((pfp = popen(buffer,"r")) == NULL)
X werror("can't open pipe to 'ps' command",0);
X
X if (fgets(buffer,3,pfp) == NULL)
X werror("nothing returned from pipe",1);
X
X pclose(pfp);
X sprintf(windev,"/dev/%s",buffer);
X
X setpgrp();
X if ((wfd = open(windev,O_RDWR)) == -1) {
X sprintf(buffer, "can't open %s", windev);
X werror(buffer,0);
X }
X close(0); dup(wfd);
X close(1); dup(wfd);
X close(2); dup(wfd);
X
X daemon_process();
X
X terminate();
X
X}
X
Xdaemon_process()
X{
X register i;
X int lockfd, calltype;
X short lockpid;
X char command[DIRSIZ], /* Command of program running */
X *findmachine(),
X *getcommand(),
X machine[12];
X struct phdef phblock;
X struct passwd *pwent,
X *getpwnam(),
X *getpwuid();
X
X while (findproc(phpid)) { /* Process still exists */
X read_kmem(&phblock,
X (unixsym[2].n_value + OFFSET),
X (long)sizeof (struct phdef));
X
X if (phblock.p_lineparam & DATA) {
X /* Check lock file existence */
X if (access(LOCKPH,0) == -1) {
X home_cursor();
X write(0,IDLE,WINSIZE);
X sleep(SLEEP);
X continue; /* no file found */
X }
X
X if ((lockfd = open(LOCKPH, O_RDONLY)) == -1) {
X sprintf(buffer, "can't open %s", LOCKPH);
X werror(buffer,0);
X }
X read(lockfd,&lockpid,sizeof(short));
X read(lockfd,&lockpid,sizeof(short)); /* HDB UUCP */
X close(lockfd);
X
X if (!findproc(lockpid)) {
X home_cursor();
X write(0,LOCKED,WINSIZE);
X sleep(SLEEP);
X close(lockfd);
X continue;
X }
X
X sprintf(command,"%s",getcommand());
X calltype = check_command(command);
X
X if (calltype == LPROCESS || calltype == PPROCESS) {
X home_cursor();
X write(0,(calltype == LPROCESS) ? LOGIN : PENDING,
X WINSIZE);
X sleep(SNOOZE);
X continue;
X }
X
X setpwent(); /* rewind /etc/passwd */
X if (calltype == OUT_USER) {
X if ((pwent = getpwuid(proc.p_uid)) == NULL) {
X sprintf(buffer,
X "cannot locate uid %d in /etc/passwd",
X proc.p_uid);
X werror(buffer,1);
X }
X } else if (calltype == IN_USER) {
X utmpentry(LINE);
X if (*userlogin == NULL) {
X write(0, LOGIN, WINSIZE);
X sleep(SNOOZE);
X continue;
X }
X if ((pwent = getpwnam(userlogin)) == NULL) {
X sprintf(buffer,
X "cannot locate user %s in /etc/passwd",
X userlogin);
X werror(buffer,1);
X }
X }
X endpwent(); /* close /etc/passwd */
X
X home_cursor();
X switch (calltype) {
X case IN_USER:
X sprintf(buffer,INCOMING,ESC,REV,pwent->pw_name,
X ESC);
X write(0,buffer,WINSIZE+ATTSIZE);
X break;
X case OUT_USER:
X sprintf(buffer,OUTGOING,ESC,REV,pwent->pw_name,
X ESC);
X write(0,buffer,WINSIZE+ATTSIZE);
X break;
X case UUCP:
X sprintf(machine,"%s",(char *)findmachine());
X utmpentry(LINE);
X if (*userlogin == NULL) {
X if (*machine != NULL)
X sprintf(buffer,OUTGOING,ESC,BOLD,machine,
X ESC);
X else
X sprintf(buffer,UUCICO,ESC,BOLD,'>',ESC);
X } else {
X if (*machine != NULL)
X sprintf(buffer,INCOMING,ESC,BOLD,machine,
X ESC);
X else
X sprintf(buffer,UUCICO,ESC,BOLD,'<',ESC);
X }
X endutent();
X write(0,buffer,WINSIZE+ATTSIZE);
X break;
X case LPROCESS:
X write(0,LOGIN,WINSIZE);
X break;
X default:
X sprintf(buffer,"calltype is incorrect = %d",
X calltype);
X werror(buffer, 1);
X break;
X }
X }
X if (calltype == UUCP && *machine == NULL)
X sleep(SNOOZE); /* Take a few short ZZzzz... */
X else
X sleep(SLEEP); /* Take a few ZZzzz... */
X }
X}
X
Xcheck_command(cmd) /* Check the list of commands */
Xchar *cmd;
X{
X register i;
X
X i = 0;
X while (*(prog[i].name) != NULL) {
X if (strcmp(prog[i].name, cmd) == 0)
X return(prog[i].type);
X i++;
X }
X return(PPROCESS);
X}
X
Xutmpentry(line)
Xchar *line;
X{
X struct utmp *utent, *getutent();
X
X setutent();
X while ((utent = getutent()) != NULL) {
X if (strncmp(utent->ut_line,line,strlen(line)) == 0 &&
X utent->ut_type == USER_PROCESS) {
X sprintf(userlogin,"%s",utent->ut_user);
X endutent();
X return;
X }
X }
X endutent();
X *userlogin = NULL;
X}
X
Xhome_cursor()
X{
X sprintf(buffer,HOME,ESC,ROW,COL);
X write(0,buffer,7);
X}
X
Xint terminate()
X{
X home_cursor();
X write(0,BLANK,WINSIZE);
X close(wfd);
X close(kmemfd);
X close(memfd);
X exit(0);
X}
X
Xsetup()
X{
X struct tunable tune;
X
X if ((kmemfd=open("/dev/kmem", O_RDWR)) == -1)
X werror("can't open /dev/kmem",0);
X
X if ((memfd=open("/dev/mem", O_RDWR)) == -1)
X werror("can't open /dev/mem",0);
X
X if (nlist("/unix", unixsym))
X werror("can't nlist /unix",0);
X
X read_kmem((char *)&tune, (unixsym[0].n_value), (long) sizeof tune);
X read_kmem((char *)&(unixsym[1].n_value), (unixsym[1].n_value),
X (long)sizeof (unixsym[1].n_value));
X
X MAXPROC = tune.nproc;
X
X}
X
Xvoid read_kmem(caddr, kaddr, nbytes)
Xchar *caddr;
Xlong kaddr;
Xlong nbytes;
X{
X if (lseek(kmemfd, kaddr, 0)<0L ||
X read(kmemfd, caddr, (unsigned)nbytes) != nbytes )
X werror("can't read /dev/kmem",0);
X}
X
Xvoid read_mem(caddr, paddr, nbytes)
Xchar *caddr;
Xlong paddr;
Xlong nbytes;
X{
X if (lseek(memfd, paddr, 0)<0L ||
X read(memfd, caddr, (unsigned)nbytes) != nbytes)
X werror("can't read /dev/mem",0);
X}
X
Xint findproc(pid)
Xint pid;
X{
X register i;
X
X for (i=0 ; iicus!lenny
"Usenet the final frontier" ...{cmcl2!phri, hoptoad}!dasys1!/