cs00chs@unccvax.uncc.edu (charles spell) (10/16/90)
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----cut here---- /****************************************************************************** * This program is freely distributable as long as there has been no changes * applied to this file.Bugs, comments, suggestions:uunet!mcnc!unccvax!cs00chs * If you find this program useful in part or in whole, please send a * contribution to John J. Ribera, Jr.If there is enough monetary interest, * fixes and upgrades will be available (see address below). */ #include <signal.h> #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <utmp.h> #include <time.h> /****************************************************************************** * NAME * watch(1-att) - watch for mail, time, and users logging in (SystemV) * * SYNOPSIS * att watch [users...] [ttylines...] [&] * * DESCRIPTION * watch will notify the you if there is mail, when new mail arrives, * display the current time, and notify you of any user logging on or off * the system. On dual universe machines this program must be compiled and * run in the att universe. The terminal this is run on must have the tsl= * and fsl= capabilities to work properly. It helps if ws# is in terminfo * also. tsl= is the sequence to go to the status line, fsl= is the * sequence to return from status line (cursor position should be restored * by this sequence). ws# should be the maximum number of characters that * can be displayed on the status line. See your terminal reference manual * for these values (and TERMINFO(5) on how to apply them). * * If there are users and/or ttylines specified on the command line, only * those users and/or lines will be checked for logins/logouts, otherwise * ANY login/logout will be displayed. * To disable watch and clear the status line, use: * kill <pid> * where <pid> is the process id of the watch program. Do not kill * watch(1-att) with a -9 value, i.e., the status line will not be cleared. * * EXAMPLES * watch & * - this watches for all users logging in or out of the system. * * watch jjr smith tty01 tty03 & * - this will watch for users with 'jjr' and 'smith' as well as those * logging in tty01 and tty03. * * WARNINGS * Be sure to run watch(1) with an att preceeding the watch command on dual * universe systems. Be careful not to run watch in the backround more than * once. To compile type: cc watch.c -o watch -ltermlib (the att universe * on dual universe machines). * * BUGS * Most of the time you will want to execute watch in the backround. The * logout seems to be closing the tty faster than the clear status line * sequence can be sent in some cases. * Try putting this in your .logout: sleep 2 * * AUTHOR * * clt2!jjr * John J. Ribera Jr. * 9505-J University Terrace Drive * Charlotte, NC 28262 * Voice: (704) 549-5571 * * If you find this program useful in part or in whole, please send a * contribution to John J. Ribera, Jr. If there is enough monetary interest, * fixes and upgrades will be available. */ #define MAX_PORT 512 #define UTMP "/etc/utmp" #define ST_MAIL 0 #define ST_DATE 9 #define ST_LOGIN 26 #define ST_WIDTH 37 #define MAIL_DIR "/usr/spool/mail" #define MAIL " MAIL" #define NEW_MAIL "NEW MAIL" #define CLR_MAIL " " char watchfor[2048]; char St_line[256]; char Termb[1024]; char Ts[80]; char Fs[80]; short Ws; main(argc, argv) int argc; char **argv; { struct utmp curr[MAX_PORT + 1]; struct utmp last[MAX_PORT + 1]; struct stat statb, save_mail; long last_mtime; long last_time; char mailfile[256]; char *login; char *strcpy(); char *getenv(); char *getlogin(); char *ctime(); char *memcpy(); char *strstr(); char **getpwuid(); short i, j, k, l; short watchcnt; short read_utmp(); int memcmp(); void disp_utmp(); void disp_chng(); void done(); signal(SIGINT, done); signal(SIGQUIT, done); signal(SIGTERM, done); signal(SIGHUP, done); for (watchfor[0] = '\0', watchcnt = --argc; argc; --argc) strcat(strcat(watchfor, *++argv), " "); /* Initialize termcaps for going to/from status line and intensity */ if (tgetent(Termb, getenv("TERM")) != 1) fprintf(stderr, "\nUnable to find terminfo data"), exit(1); if (!*strcpy(Ts, gettstr("tsl")) || !*strcpy(Fs, gettstr("fsl"))) fprintf(stderr, "\nNeed status line caps - tsl=, and fsl=."), exit(1); if ((Ws = tgetnum("ws")) == -1 && (Ws = tgetnum("co")) == -1) Ws = 80; /* Initialize everything for loop below...get current utmp entries */ sprintf(St_line, "%-*.*s", Ws, Ws, ""); last_time = time((long *) 0); memcpy(&St_line[ST_DATE], ctime(&last_time), 16); disp_stat(St_line); if ((login = getenv("LOGNAME")) == NULL && (login = getenv("USER")) == NULL && (login = getlogin()) == NULL && !*(login = *getpwuid(getuid()))) fprintf(stderr, "\nUnable to find you"), exit(1); sprintf(mailfile, "%s/%s", MAIL_DIR, login); l = read_utmp(last); if (stat(UTMP, &statb) < 0) fprintf(stderr, "\nUnable to stat utmp file."), exit(1); for (last_mtime = statb.st_mtime; stat(UTMP, &statb) == 0; sleep(1)) { if (statb.st_mtime > last_mtime) { last_mtime = statb.st_mtime; for (i = k = read_utmp(curr); i; i--) for (j = l; j; j--) if (!watchcnt || (strstr(watchfor, curr[i-1].ut_line) || strstr(watchfor, curr[i-1].ut_user) || strstr(watchfor, last[j-1].ut_line) || strstr(watchfor, last[j-1].ut_user))) if (!strcmp(curr[i-1].ut_line, last[j-1].ut_line)) if (last[j-1].ut_type != curr[i-1].ut_type) disp_chng(&last[j-1], &curr[j-1]); memcpy(&last, &curr, sizeof(curr)); l = k; } if ((last_time / 60) != (time((long *) 0) / 60)) { if (!((last_time = time((long *) 0)) % 3600)) putchar('\007'); memcpy(&St_line[ST_DATE], ctime(&last_time), 16); disp_stat(St_line); } if (stat(mailfile, &statb) != 0) fprintf(stderr, "Unable to stat %s", mailfile), exit(1); if (memcmp(&save_mail, &statb, sizeof(statb))) { memcpy(&St_line[ST_MAIL], CLR_MAIL, strlen(CLR_MAIL)); disp_stat(St_line); if (statb.st_mtime >= statb.st_atime && statb.st_size > 1) { memcpy(&St_line[ST_MAIL], NEW_MAIL, strlen(NEW_MAIL)); putchar('\007'); } else if (statb.st_size > 1) memcpy(&St_line[ST_MAIL], MAIL, strlen(MAIL)); disp_stat(St_line); memcpy(&save_mail, &statb, sizeof(statb)); } if (getppid() == 1) done(); } } void disp_chng(last, curr) struct utmp *last; struct utmp *curr; { if (last->ut_type != USER_PROCESS && curr->ut_type == USER_PROCESS) sprintf(&St_line[ST_LOGIN], "%-8.8s on %s", curr->ut_user, curr->ut_line); if (last->ut_type == USER_PROCESS && curr->ut_type != USER_PROCESS) sprintf(&St_line[ST_LOGIN], "%-8.8s off %s", last->ut_user, last->ut_line); memcpy(last, curr, sizeof(*last)); disp_stat(St_line); } void disp_stat(stat_line) char *stat_line; { int outc(); char hold[256]; tputs(Ts, 1, outc); strcpy(hold, stat_line); sprintf(stat_line, "%-*.*s", Ws-1, Ws-1, hold); fwrite(stat_line, strlen(stat_line), 1, stdout); tputs(Fs, 1, outc); fflush(stdout); } short read_utmp(utmps) struct utmp *utmps; { FILE *fp; short i; if ((fp = fopen(UTMP, "r")) == (FILE *) NULL) fprintf(stderr, "\nUnable to read utmp file."), (void)exit(1); i = (short) fread(utmps, sizeof(*utmps), MAX_PORT, fp); fclose(fp); return(i); } /****************************************************************************** * strstr - returns pointer in _str_ that contains start of _sub_ (NULL if _sub_ * not in _str_). * Note: I have seen lots of complex code to do the same thing - this is * pretty efficient (speedwise). */ char * strstr(str, sub) /* some SysV machines do not have this */ char *str; /* string to search */ char *sub; /* sub-string for which to search */ { register char *tstr; /* register to speed it up */ register char *tsub=sub; /* exists only for speed */ while (*str && str && tsub) /* if NULL ptrs skip loop! */ for (tstr = str++; *tsub == *tstr++; tsub++) if (!*tsub) return(--str); return(NULL); } done() { disp_stat(""); exit(0); } char * gettstr(id) char *id; { static char tstr[256]; char *ptr; ptr = tstr; strcpy(tstr, tgetstr(id, &ptr)); if (ptr == tstr) *tstr = '\0'; return(tstr); } int outc(c) char c; { fwrite(&c, 1, 1, stdout); } ---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