Path: utzoo!utgpu!news-server.csri.toronto.edu!rutgers!cs.utexas.edu!uunet!allbery From: unccvax.uncc.edu!cs00chs@unccvax.uncc.edu (charles spell) Newsgroups: comp.sources.misc Subject: v15i099: watch.c - a SysV mail notifier, date/time, and user log on/off Keywords: For SysV - uses status line. BUDPAK enhanced! Message-ID: <114658@uunet.UU.NET> Date: 16 Dec 90 21:20:20 GMT Sender: allbery@uunet.UU.NET Organization: University of NC at Charlotte Lines: 308 Approved: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) Posting-number: Volume 15, Issue 99 Submitted-by: charles spell 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 X#include X#include X#include X#include X#include 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 X* where 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