cs00chs@unccvax.uncc.edu (charles spell) (12/17/90)
Posting-number: Volume 15, Issue 99
Submitted-by: charles spell <unccvax.uncc.edu!cs00chs@unccvax.uncc.edu>
Archive-name: jjrsl/part01
Here is a program for SystemV machines to display mail, new mail, the time
and date and users logging on/off the system on the status line. You must
put the tsl= and fsl= capabilities into the terminfo database if they do not
already exist. A future enhancement will use sc= and rc= to put the info
anywhere on the screen...
Enjoy...
--- cut here ---
#! /bin/sh
# This file was wrapped with "dummyshar". "sh" this file to extract.
# Contents: jjrsl.c
echo extracting 'jjrsl.c'
if test -f 'jjrsl.c' -a -z "$1"; then echo Not overwriting 'jjrsl.c'; else
sed 's/^X//' << \EOF > 'jjrsl.c'
X/******************************************************************************
X* This program is freely distributable as long as there has been no changes
X* applied to this file.Bugs, comments, suggestions:uunet!mcnc!unccvax!cs00chs
X* If you find this program useful in part or in whole, please send a
X* contribution to John J. Ribera, Jr.If there is enough monetary interest,
X* fixes and upgrades will be available (see address below).
X*/
X#include <signal.h>
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <utmp.h>
X#include <time.h>
X/******************************************************************************
X* NAME
X* watch(1-att) - watch for mail, time, and users logging in (SystemV)
X*
X* SYNOPSIS
X* att watch [users...] [ttylines...] [&]
X*
X* DESCRIPTION
X* watch will notify the you if there is mail, when new mail arrives,
X* display the current time, and notify you of any user logging on or off
X* the system. On dual universe machines this program must be compiled and
X* run in the att universe. The terminal this is run on must have the tsl=
X* and fsl= capabilities to work properly. It helps if ws# is in terminfo
X* also. tsl= is the sequence to go to the status line, fsl= is the
X* sequence to return from status line (cursor position should be restored
X* by this sequence). ws# should be the maximum number of characters that
X* can be displayed on the status line. See your terminal reference manual
X* for these values (and TERMINFO(5) on how to apply them).
X*
X* If there are users and/or ttylines specified on the command line, only
X* those users and/or lines will be checked for logins/logouts, otherwise
X* ANY login/logout will be displayed.
X* To disable watch and clear the status line, use:
X* kill <pid>
X* where <pid> is the process id of the watch program. Do not kill
X* watch(1-att) with a -9 value, i.e., the status line will not be cleared.
X*
X* EXAMPLES
X* watch &
X* - this watches for all users logging in or out of the system.
X*
X* watch jjr smith tty01 tty03 &
X* - this will watch for users with 'jjr' and 'smith' as well as those
X* logging in tty01 and tty03.
X*
X* WARNINGS
X* Be sure to run watch(1) with an att preceeding the watch command on dual
X* universe systems. Be careful not to run watch in the backround more than
X* once. To compile type: cc watch.c -o watch -ltermlib (the att universe
X* on dual universe machines).
X*
X* BUGS
X* Most of the time you will want to execute watch in the backround. The
X* logout seems to be closing the tty faster than the clear status line
X* sequence can be sent in some cases.
X* Try putting this in your .logout: sleep 2
X*
X* AUTHOR
X*
X* clt2!jjr
X* John J. Ribera Jr.
X* 9505-J University Terrace Drive
X* Charlotte, NC 28262
X* Voice: (704) 549-5571
X*
X* If you find this program useful in part or in whole, please send a
X* contribution to John J. Ribera, Jr. If there is enough monetary interest,
X* fixes and upgrades will be available.
X*/
X
X#define MAX_PORT 512
X#define UTMP "/etc/utmp"
X#define ST_MAIL 0
X#define ST_DATE 9
X#define ST_LOGIN 26
X#define ST_WIDTH 37
X#define MAIL_DIR "/usr/spool/mail"
X
X#define MAIL " MAIL"
X#define NEW_MAIL "NEW MAIL"
X#define CLR_MAIL " "
X
Xchar watchfor[2048];
Xchar St_line[256];
Xchar Termb[1024];
Xchar Ts[80];
Xchar Fs[80];
Xshort Ws;
X
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
Xstruct utmp curr[MAX_PORT + 1];
Xstruct utmp last[MAX_PORT + 1];
Xstruct stat statb, save_mail;
X long last_mtime;
X long last_time;
X char mailfile[256];
X char *login;
X char *strcpy();
X char *getenv();
X char *getlogin();
X char *ctime();
X char *memcpy();
X char *strstr();
X char **getpwuid();
X short i, j, k, l;
X short watchcnt;
X short read_utmp();
X int memcmp();
X void disp_utmp();
X void disp_chng();
X void done();
X
Xsignal(SIGINT, done);
Xsignal(SIGQUIT, done);
Xsignal(SIGTERM, done);
Xsignal(SIGHUP, done);
Xfor (watchfor[0] = '\0', watchcnt = --argc; argc; --argc)
X strcat(strcat(watchfor, *++argv), " ");
X/* Initialize termcaps for going to/from status line and intensity */
Xif (tgetent(Termb, getenv("TERM")) != 1)
X fprintf(stderr, "\nUnable to find terminfo data"), exit(1);
Xif (!*strcpy(Ts, gettstr("tsl")) || !*strcpy(Fs, gettstr("fsl")))
X fprintf(stderr, "\nNeed status line caps - tsl=, and fsl=."), exit(1);
Xif ((Ws = tgetnum("ws")) == -1 && (Ws = tgetnum("co")) == -1)
X Ws = 80;
X/* Initialize everything for loop below...get current utmp entries */
Xsprintf(St_line, "%-*.*s", Ws, Ws, "");
Xlast_time = time((long *) 0);
Xmemcpy(&St_line[ST_DATE], ctime(&last_time), 16);
Xdisp_stat(St_line);
Xif ((login = getenv("LOGNAME")) == NULL && (login = getenv("USER")) == NULL &&
X (login = getlogin()) == NULL && !*(login = *getpwuid(getuid())))
X fprintf(stderr, "\nUnable to find you"), exit(1);
Xsprintf(mailfile, "%s/%s", MAIL_DIR, login);
Xl = read_utmp(last);
Xif (stat(UTMP, &statb) < 0)
X fprintf(stderr, "\nUnable to stat utmp file."), exit(1);
X
Xfor (last_mtime = statb.st_mtime; stat(UTMP, &statb) == 0; sleep(1))
X {
X if (statb.st_mtime > last_mtime)
X {
X last_mtime = statb.st_mtime;
X for (i = k = read_utmp(curr); i; i--)
X for (j = l; j; j--)
X if (!watchcnt ||
X (strstr(watchfor, curr[i-1].ut_line) ||
X strstr(watchfor, curr[i-1].ut_user) ||
X strstr(watchfor, last[j-1].ut_line) ||
X strstr(watchfor, last[j-1].ut_user)))
X if (!strcmp(curr[i-1].ut_line, last[j-1].ut_line))
X if (last[j-1].ut_type != curr[i-1].ut_type)
X disp_chng(&last[j-1], &curr[j-1]);
X memcpy(&last, &curr, sizeof(curr));
X l = k;
X }
X if ((last_time / 60) != (time((long *) 0) / 60))
X {
X if (!((last_time = time((long *) 0)) % 3600))
X putchar('\007');
X memcpy(&St_line[ST_DATE], ctime(&last_time), 16);
X disp_stat(St_line);
X }
X if (stat(mailfile, &statb) != 0)
X fprintf(stderr, "Unable to stat %s", mailfile), exit(1);
X if (memcmp(&save_mail, &statb, sizeof(statb)))
X {
X memcpy(&St_line[ST_MAIL], CLR_MAIL, strlen(CLR_MAIL));
X disp_stat(St_line);
X if (statb.st_mtime >= statb.st_atime && statb.st_size > 1)
X {
X memcpy(&St_line[ST_MAIL], NEW_MAIL, strlen(NEW_MAIL));
X putchar('\007');
X }
X else if (statb.st_size > 1)
X memcpy(&St_line[ST_MAIL], MAIL, strlen(MAIL));
X disp_stat(St_line);
X memcpy(&save_mail, &statb, sizeof(statb));
X }
X if (getppid() == 1)
X done();
X }
X}
X
Xvoid
Xdisp_chng(last, curr)
Xstruct utmp *last;
Xstruct utmp *curr;
X{
Xif (last->ut_type != USER_PROCESS && curr->ut_type == USER_PROCESS)
X sprintf(&St_line[ST_LOGIN], "%-8.8s on %s", curr->ut_user, curr->ut_line);
Xif (last->ut_type == USER_PROCESS && curr->ut_type != USER_PROCESS)
X sprintf(&St_line[ST_LOGIN], "%-8.8s off %s", last->ut_user, last->ut_line);
Xmemcpy(last, curr, sizeof(*last));
Xdisp_stat(St_line);
X}
X
Xvoid
Xdisp_stat(stat_line)
Xchar *stat_line;
X{
X int outc();
X char hold[256];
X
Xtputs(Ts, 1, outc);
Xstrcpy(hold, stat_line);
Xsprintf(stat_line, "%-*.*s", Ws-1, Ws-1, hold);
Xfwrite(stat_line, strlen(stat_line), 1, stdout);
Xtputs(Fs, 1, outc);
Xfflush(stdout);
X}
X
Xshort
Xread_utmp(utmps)
Xstruct utmp *utmps;
X{
X FILE *fp;
X short i;
X
Xif ((fp = fopen(UTMP, "r")) == (FILE *) NULL)
X fprintf(stderr, "\nUnable to read utmp file."), (void)exit(1);
Xi = (short) fread(utmps, sizeof(*utmps), MAX_PORT, fp);
Xfclose(fp);
Xreturn(i);
X}
X/******************************************************************************
X* strstr - returns pointer in _str_ that contains start of _sub_ (NULL if _sub_
X* not in _str_).
X* Note: I have seen lots of complex code to do the same thing - this is
X* pretty efficient (speedwise).
X*/
Xchar *
Xstrstr(str, sub) /* some SysV machines do not have this */
Xchar *str; /* string to search */
Xchar *sub; /* sub-string for which to search */
X{
Xregister char *tstr; /* register to speed it up */
Xregister char *tsub=sub; /* exists only for speed */
X
Xwhile (*str && str && tsub) /* if NULL ptrs skip loop! */
X for (tstr = str++; *tsub == *tstr++; tsub++)
X if (!*tsub)
X return(--str);
Xreturn(NULL);
X}
X
Xdone()
X{
Xdisp_stat("");
Xexit(0);
X}
X
Xchar *
Xgettstr(id)
Xchar *id;
X{
Xstatic char tstr[256];
X char *ptr;
X
Xptr = tstr;
Xstrcpy(tstr, tgetstr(id, &ptr));
Xif (ptr == tstr)
X *tstr = '\0';
Xreturn(tstr);
X}
X
Xint
Xoutc(c)
Xchar c;
X{
Xfwrite(&c, 1, 1, stdout);
X}
EOF
chars=`wc -c < 'jjrsl.c'`
if test $chars != 8338; then echo 'jjrsl.c' is $chars characters, should be 8338 characters!; fi
fi
exit 0
---cut here----cut here----
--
.--------------------------. ... |On the border of your mind lies a place
|uunet!mcnc!unccvax!cs00chs| (") |where dreams and reality are one...I will
`--------------------------'-w-U-w-|take you there, for I am the subject...
\%\%\%\%\%\%\%\%\%\%\%\%\%\%\%\%\%\|the subject of your imagination. -Aldo Nova