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