lenny@icus.UUCP (Lenny Tropiano) (12/06/87)
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 <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: README Makefile phdaemon.c # Wrapped by lenny@icus.UUCP on Sun Dec 6 21:12:58 EST 1987 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f README -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"README\" else echo shar: Extracting \"README\" \(4692 characters\) sed "s/^X//" >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:<LOGIN - Login process (don't know who or what it is yet) X X DATA 2:>PENDING - A process is going out, not sure what it is. X DATA 2:<PENDING - A process is coming in, not sure what it is. X X The following "user" is in INVERSE video. X X DATA 2:>user - When a user locks the modem for outgoing calls X DATA 2:<user - When a user locks the modem when coming in. 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:<UUCICO - It is a uucico process but don't know what machine X as of yet. (coming in) X DATA 2:>machine - When a uucico process locks modem going out. X DATA 2:<machine - When a uucico process locks modem coming in. X X---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- X XThe program doesn't allocate another window, it just uses the window Xallocated to the /etc/ph process. This will not waste another window. X XThe following parameters can be changed to your liking: 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 XThe program is set to a nice value of 25, and it sleeps for 15 seconds Xbetween checks. This will keep the process from bogging down the CPU with Xwasted cycles. When there is a "LOGIN or UUCICO" process that is still Xundetermined, the program will only SNOOZE for 5 seconds, to try to catch Xwho or what is logging in before they logout. X X XThe following is a table of the programs to determine what kind of process Xis going using the modem. The following are my choices, more can be added Xto match what you system requires. Each program must have a type for either X X IN_USER - user login X OUT_USER - user dialing out X UUCP - uucp process X LPROCESS - login process X 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 XNote: term is a program I wrote that acts as a terminal program, I left Xit there for example purposes. X XPlease report any bugs, suggestions and problems to me: X X============================ US MAIL: Lenny Tropiano, ICUS Computer Group X IIIII CCC U U SSSS PO Box 1 X I C C U U S Islip Terrace, New York 11752 X I C U U SSS PHONE: (516) 968-8576 [H] (516) 582-5525 [W] X I C C U U S AT&T MAIL: ...attmail!icus!lenny TELEX: 154232428 X IIIII CCC UUU SSSS UUCP: X============================ ...{uunet!godfre, harvard!talcott}!\ X ...{ihnp4, boulder, mtune, skeeve, ptsfa}! >icus!lenny X"Usenet the final frontier" ...{cmcl2!phri, hoptoad}!dasys1!/ END_OF_README if test 4692 -ne `wc -c <README`; then echo shar: \"README\" unpacked with wrong size! fi # end of overwriting check fi if test -f Makefile -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"Makefile\" else echo shar: Extracting \"Makefile\" \(663 characters\) sed "s/^X//" >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 <Makefile`; then echo shar: \"Makefile\" unpacked with wrong size! fi # end of overwriting check fi if test -f phdaemon.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"phdaemon.c\" else echo shar: Extracting \"phdaemon.c\" \(14239 characters\) sed "s/^X//" >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 <stdio.h> X#include <fcntl.h> X#include <errno.h> X#include <signal.h> X#include <status.h> X#include <sys/types.h> X#include <sys/window.h> X#include <sys/stat.h> X#include <sys/tune.h> X#include <sys/proc.h> X#include <sys/user.h> X#include <sys/dir.h> X#include <sys/ph.h> X#include <sys/phone.h> X#include <nlist.h> X#include <pwd.h> X#include <utmp.h> 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 "<LOGIN " /* Incoming login */ X#define UUCICO "%c[%dm%cUUCICO %c[0m"/* Incoming undetermined uucico */ X#define LOCKED ">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 ; i<MAXPROC ; ++i) { X read_kmem((char *)&proc, X (long)&((struct proc *)(unixsym[1].n_value))[i], X (long)sizeof proc); X if (proc.p_pid == pid) X return 1; X } X return 0; X} X Xchar *findmachine() X{ X int dfd; /* Directory file descriptor */ X static struct direct dirbuf; /* Directory entry buffer */ X X if ((dfd = open(LOCKDIR, O_RDONLY)) == -1) X werror("can't open lock directory",0); X X while (read(dfd, &dirbuf, sizeof (struct direct)) == X (sizeof (struct direct))) { X if ((dirbuf.d_ino != 0) && (strncmp(dirbuf.d_name,LOCKFIL,5) == 0)) { X if ((strncmp((char *)&dirbuf.d_name[5],"ph",2) != 0) && X (strncmp((char *)&dirbuf.d_name[5],"tty",3) != 0)) { X close(dfd); X return((char *)&dirbuf.d_name[5]); X } X } X } X X close(dfd); X return(NULL); X} X Xwerror(errstr,mode) Xchar *errstr; Xint mode; X{ X extern char *sys_errlist[]; X X /* Warn user about error */ X X if (mode == 0) X eprintf(ST_SYS, ST_DISPLAY, NULL, "%s: %s: %s", X progname, errstr, sys_errlist[errno]); X else X eprintf(ST_SYS, ST_DISPLAY, NULL, "%s: %s", X progname, errstr); X X /* Log message in /usr/adm/logfile */ X X if (mode == 0) X eprintf(ST_LOG, ST_DISPLAY, NULL, "logfile %s: %s: %s", X progname, errstr, sys_errlist[errno]); X else X eprintf(ST_LOG, ST_DISPLAY, NULL, "logfile %s: %s", X progname, errstr); X X home_cursor(); X write(0,BLANK,WINSIZE); X exit(1); X} X Xchar *getcommand() X{ X static struct user users; X long upage; X X if (!proc.p_stat || proc.p_stat == SIDL || proc.p_stat == SZOMB) X return 0; X X if (!(proc.p_flag & SLOAD)) { X sprintf(buffer,"can't handle swapped process %d (flag=%05x)", X proc.p_pid, proc.p_flag); X werror(buffer,1); X } X X upage = (long)ctob(proc.p_addr[0]); X read_mem((char *)&users, upage + U_OFFSET, (long) sizeof (struct user)); X X return(users.u_comm); X} END_OF_phdaemon fi if test 14239 -ne `wc -c <phdaemon.c`; then echo shar: \"phdaemon.c\" unpacked with wrong size! fi # end of overwriting check echo shar: End of shell archive. exit 0 --- cut here too --- --- cut here too --- --- cut here too --- --- cut here too -- ============================ US MAIL: Lenny Tropiano, ICUS Computer Group IIIII CCC U U SSSS PO Box 1 I C C U U S Islip Terrace, New York 11752 I C U U SSS PHONE: (516) 968-8576 [H] (516) 582-5525 [W] I C C U U S AT&T MAIL: ...attmail!icus!lenny TELEX: 154232428 IIIII CCC UUU SSSS UUCP: ============================ ...{uunet!godfre, harvard!talcott}!\ ...{ihnp4, boulder, mtune, skeeve, ptsfa}! >icus!lenny "Usenet the final frontier" ...{cmcl2!phri, hoptoad}!dasys1!/