tc.who.c revision 69408
169408Sache/* $Header: /src/pub/tcsh/tc.who.c,v 3.32 2000/11/12 02:18:07 christos Exp $ */ 259243Sobrien/* 359243Sobrien * tc.who.c: Watch logins and logouts... 459243Sobrien */ 559243Sobrien/*- 659243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California. 759243Sobrien * All rights reserved. 859243Sobrien * 959243Sobrien * Redistribution and use in source and binary forms, with or without 1059243Sobrien * modification, are permitted provided that the following conditions 1159243Sobrien * are met: 1259243Sobrien * 1. Redistributions of source code must retain the above copyright 1359243Sobrien * notice, this list of conditions and the following disclaimer. 1459243Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1559243Sobrien * notice, this list of conditions and the following disclaimer in the 1659243Sobrien * documentation and/or other materials provided with the distribution. 1759243Sobrien * 3. All advertising materials mentioning features or use of this software 1859243Sobrien * must display the following acknowledgement: 1959243Sobrien * This product includes software developed by the University of 2059243Sobrien * California, Berkeley and its contributors. 2159243Sobrien * 4. Neither the name of the University nor the names of its contributors 2259243Sobrien * may be used to endorse or promote products derived from this software 2359243Sobrien * without specific prior written permission. 2459243Sobrien * 2559243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2659243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2759243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2859243Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2959243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3059243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3159243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3259243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3359243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3459243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3559243Sobrien * SUCH DAMAGE. 3659243Sobrien */ 3759243Sobrien#include "sh.h" 3859243Sobrien 3969408SacheRCSID("$Id: tc.who.c,v 3.32 2000/11/12 02:18:07 christos Exp $") 4059243Sobrien 4159243Sobrien#include "tc.h" 4259243Sobrien 4359243Sobrien#ifndef HAVENOUTMP 4459243Sobrien/* 4559243Sobrien * kfk 26 Jan 1984 - for login watch functions. 4659243Sobrien */ 4759243Sobrien#include <ctype.h> 4859243Sobrien 4959243Sobrien#ifdef HAVEUTMPX 5059243Sobrien# include <utmpx.h> 5159243Sobrien/* I just redefine a few words here. Changing every occurrence below 5259243Sobrien * seems like too much of work. All UTMP functions have equivalent 5359243Sobrien * UTMPX counterparts, so they can be added all here when needed. 5459243Sobrien * Kimmo Suominen, Oct 14 1991 5559243Sobrien */ 5659243Sobrien# ifndef _PATH_UTMP 5769408Sache# if defined(__UTMPX_FILE) && !defined(UTMPX_FILE) 5869408Sache# define _PATH_UTMP __UTMPX_FILE 5969408Sache# else 6069408Sache# define _PATH_UTMP UTMPX_FILE 6169408Sache# endif /* __UTMPX_FILE && !UTMPX_FILE */ 6259243Sobrien# endif /* _PATH_UTMP */ 6359243Sobrien# define utmp utmpx 6469408Sache# ifdef __MVS__ 6569408Sache# define ut_time ut_tv.tv_sec 6669408Sache# define ut_name ut_user 6769408Sache# else 6869408Sache# define ut_time ut_xtime 6969408Sache# endif /* __MVS__ */ 7059243Sobrien#else /* !HAVEUTMPX */ 7169408Sache# ifndef WINNT_NATIVE 7259243Sobrien# include <utmp.h> 7369408Sache# endif /* WINNT_NATIVE */ 7459243Sobrien#endif /* HAVEUTMPX */ 7559243Sobrien 7659243Sobrien#ifndef BROKEN_CC 7759243Sobrien# define UTNAMLEN sizeof(((struct utmp *) 0)->ut_name) 7859243Sobrien# define UTLINLEN sizeof(((struct utmp *) 0)->ut_line) 7959243Sobrien# ifdef UTHOST 8059243Sobrien# ifdef _SEQUENT_ 8159243Sobrien# define UTHOSTLEN 100 8259243Sobrien# else 8359243Sobrien# define UTHOSTLEN sizeof(((struct utmp *) 0)->ut_host) 8459243Sobrien# endif 8559243Sobrien# endif /* UTHOST */ 8659243Sobrien#else 8759243Sobrien/* give poor cc a little help if it needs it */ 8859243Sobrienstruct utmp __ut; 8959243Sobrien 9059243Sobrien# define UTNAMLEN sizeof(__ut.ut_name) 9159243Sobrien# define UTLINLEN sizeof(__ut.ut_line) 9259243Sobrien# ifdef UTHOST 9359243Sobrien# ifdef _SEQUENT_ 9459243Sobrien# define UTHOSTLEN 100 9559243Sobrien# else 9659243Sobrien# define UTHOSTLEN sizeof(__ut.ut_host) 9759243Sobrien# endif 9859243Sobrien# endif /* UTHOST */ 9959243Sobrien#endif /* BROKEN_CC */ 10059243Sobrien 10159243Sobrien#ifndef _PATH_UTMP 10259243Sobrien# ifdef UTMP_FILE 10359243Sobrien# define _PATH_UTMP UTMP_FILE 10459243Sobrien# else 10559243Sobrien# define _PATH_UTMP "/etc/utmp" 10659243Sobrien# endif /* UTMP_FILE */ 10759243Sobrien#endif /* _PATH_UTMP */ 10859243Sobrien 10959243Sobrien 11059243Sobrienstruct who { 11159243Sobrien struct who *who_next; 11259243Sobrien struct who *who_prev; 11359243Sobrien char who_name[UTNAMLEN + 1]; 11459243Sobrien char who_new[UTNAMLEN + 1]; 11559243Sobrien char who_tty[UTLINLEN + 1]; 11659243Sobrien#ifdef UTHOST 11759243Sobrien char who_host[UTHOSTLEN + 1]; 11859243Sobrien#endif /* UTHOST */ 11959243Sobrien time_t who_time; 12059243Sobrien int who_status; 12159243Sobrien}; 12259243Sobrien 12359243Sobrienstatic struct who whohead, whotail; 12459243Sobrienstatic time_t watch_period = 0; 12559243Sobrienstatic time_t stlast = 0; 12659243Sobrien#ifdef WHODEBUG 12759243Sobrienstatic void debugwholist __P((struct who *, struct who *)); 12859243Sobrien#endif 12959243Sobrienstatic void print_who __P((struct who *)); 13059243Sobrien 13159243Sobrien 13259243Sobrien#define ONLINE 01 13359243Sobrien#define OFFLINE 02 13459243Sobrien#define CHANGED 04 13559243Sobrien#define STMASK 07 13659243Sobrien#define ANNOUNCE 010 13759243Sobrien 13859243Sobrien/* 13959243Sobrien * Karl Kleinpaste, 26 Jan 1984. 14059243Sobrien * Initialize the dummy tty list for login watch. 14159243Sobrien * This dummy list eliminates boundary conditions 14259243Sobrien * when doing pointer-chase searches. 14359243Sobrien */ 14459243Sobrienvoid 14559243Sobrieninitwatch() 14659243Sobrien{ 14759243Sobrien whohead.who_next = &whotail; 14859243Sobrien whotail.who_prev = &whohead; 14959243Sobrien stlast = 1; 15059243Sobrien#ifdef WHODEBUG 15159243Sobrien debugwholist(NULL, NULL); 15259243Sobrien#endif /* WHODEBUG */ 15359243Sobrien} 15459243Sobrien 15559243Sobrienvoid 15659243Sobrienresetwatch() 15759243Sobrien{ 15859243Sobrien watch_period = 0; 15959243Sobrien stlast = 0; 16059243Sobrien} 16159243Sobrien 16259243Sobrien/* 16359243Sobrien * Karl Kleinpaste, 26 Jan 1984. 16459243Sobrien * Watch /etc/utmp for login/logout changes. 16559243Sobrien */ 16659243Sobrienvoid 16759243Sobrienwatch_login(force) 16859243Sobrien int force; 16959243Sobrien{ 17059243Sobrien int utmpfd, comp = -1, alldone; 17159243Sobrien int firsttime = stlast == 1; 17259243Sobrien#ifdef BSDSIGS 17359243Sobrien sigmask_t omask; 17459243Sobrien#endif /* BSDSIGS */ 17559243Sobrien struct utmp utmp; 17659243Sobrien struct who *wp, *wpnew; 17759243Sobrien struct varent *v; 17859243Sobrien Char **vp = NULL; 17959243Sobrien time_t t, interval = MAILINTVL; 18059243Sobrien struct stat sta; 18159243Sobrien#if defined(UTHOST) && defined(_SEQUENT_) 18259243Sobrien char *host, *ut_find_host(); 18359243Sobrien#endif 18469408Sache#ifdef WINNT_NATIVE 18559243Sobrien static int ncbs_posted = 0; 18659243Sobrien USE(utmp); 18759243Sobrien USE(utmpfd); 18859243Sobrien USE(sta); 18959243Sobrien USE(wpnew); 19069408Sache#endif /* WINNT_NATIVE */ 19159243Sobrien 19259243Sobrien /* stop SIGINT, lest our login list get trashed. */ 19359243Sobrien#ifdef BSDSIGS 19459243Sobrien omask = sigblock(sigmask(SIGINT)); 19559243Sobrien#else 19659243Sobrien (void) sighold(SIGINT); 19759243Sobrien#endif 19859243Sobrien 19959243Sobrien v = adrof(STRwatch); 20059243Sobrien if (v == NULL && !force) { 20159243Sobrien#ifdef BSDSIGS 20259243Sobrien (void) sigsetmask(omask); 20359243Sobrien#else 20459243Sobrien (void) sigrelse(SIGINT); 20559243Sobrien#endif 20659243Sobrien return; /* no names to watch */ 20759243Sobrien } 20859243Sobrien if (!force) { 20959243Sobrien trim(vp = v->vec); 21059243Sobrien if (blklen(vp) % 2) /* odd # args: 1st == # minutes. */ 21159243Sobrien interval = (number(*vp)) ? (getn(*vp++) * 60) : MAILINTVL; 21259243Sobrien } 21359243Sobrien else 21459243Sobrien interval = 0; 21559243Sobrien 21659243Sobrien (void) time(&t); 21769408Sache#ifdef WINNT_NATIVE 21859243Sobrien /* 21959243Sobrien * Since NCB_ASTATs take time, start em async at least 90 secs 22059243Sobrien * before we are due -amol 6/5/97 22159243Sobrien */ 22259243Sobrien if (!ncbs_posted) { 22359243Sobrien unsigned long tdiff = t - watch_period; 22459243Sobrien if (!watch_period || ((tdiff > 0) && (tdiff > (interval - 90)))) { 22559243Sobrien start_ncbs(vp); 22659243Sobrien ncbs_posted = 1; 22759243Sobrien } 22859243Sobrien } 22969408Sache#endif /* WINNT_NATIVE */ 23059243Sobrien if (t - watch_period < interval) { 23159243Sobrien#ifdef BSDSIGS 23259243Sobrien (void) sigsetmask(omask); 23359243Sobrien#else 23459243Sobrien (void) sigrelse(SIGINT); 23559243Sobrien#endif 23659243Sobrien return; /* not long enough yet... */ 23759243Sobrien } 23859243Sobrien watch_period = t; 23969408Sache#ifdef WINNT_NATIVE 24059243Sobrien ncbs_posted = 0; 24169408Sache#else /* !WINNT_NATIVE */ 24259243Sobrien 24359243Sobrien /* 24459243Sobrien * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de> 24559243Sobrien * Don't open utmp all the time, stat it first... 24659243Sobrien */ 24759243Sobrien if (stat(_PATH_UTMP, &sta)) { 24861515Sobrien if (!force) 24961515Sobrien xprintf(CGETS(26, 1, 25061515Sobrien "cannot stat %s. Please \"unset watch\".\n"), 25161515Sobrien _PATH_UTMP); 25259243Sobrien# ifdef BSDSIGS 25359243Sobrien (void) sigsetmask(omask); 25459243Sobrien# else 25559243Sobrien (void) sigrelse(SIGINT); 25659243Sobrien# endif 25759243Sobrien return; 25859243Sobrien } 25959243Sobrien if (stlast == sta.st_mtime) { 26059243Sobrien# ifdef BSDSIGS 26159243Sobrien (void) sigsetmask(omask); 26259243Sobrien# else 26359243Sobrien (void) sigrelse(SIGINT); 26459243Sobrien# endif 26559243Sobrien return; 26659243Sobrien } 26759243Sobrien stlast = sta.st_mtime; 26859243Sobrien if ((utmpfd = open(_PATH_UTMP, O_RDONLY)) < 0) { 26961515Sobrien if (!force) 27061515Sobrien xprintf(CGETS(26, 2, 27161515Sobrien "%s cannot be opened. Please \"unset watch\".\n"), 27261515Sobrien _PATH_UTMP); 27359243Sobrien# ifdef BSDSIGS 27459243Sobrien (void) sigsetmask(omask); 27559243Sobrien# else 27659243Sobrien (void) sigrelse(SIGINT); 27759243Sobrien# endif 27859243Sobrien return; 27959243Sobrien } 28059243Sobrien 28159243Sobrien /* 28259243Sobrien * xterm clears the entire utmp entry - mark everyone on the status list 28359243Sobrien * OFFLINE or we won't notice X "logouts" 28459243Sobrien */ 28559243Sobrien for (wp = whohead.who_next; wp->who_next != NULL; wp = wp->who_next) { 28659243Sobrien wp->who_status = OFFLINE; 28759243Sobrien wp->who_time = 0; 28859243Sobrien } 28959243Sobrien 29059243Sobrien /* 29159243Sobrien * Read in the utmp file, sort the entries, and update existing entries or 29259243Sobrien * add new entries to the status list. 29359243Sobrien */ 29459243Sobrien while (read(utmpfd, (char *) &utmp, sizeof utmp) == sizeof utmp) { 29559243Sobrien 29659243Sobrien# ifdef DEAD_PROCESS 29759243Sobrien# ifndef IRIS4D 29859243Sobrien if (utmp.ut_type != USER_PROCESS) 29959243Sobrien continue; 30059243Sobrien# else 30159243Sobrien /* Why is that? Cause the utmp file is always corrupted??? */ 30259243Sobrien if (utmp.ut_type != USER_PROCESS && utmp.ut_type != DEAD_PROCESS) 30359243Sobrien continue; 30459243Sobrien# endif /* IRIS4D */ 30559243Sobrien# endif /* DEAD_PROCESS */ 30659243Sobrien 30759243Sobrien if (utmp.ut_name[0] == '\0' && utmp.ut_line[0] == '\0') 30859243Sobrien continue; /* completely void entry */ 30959243Sobrien# ifdef DEAD_PROCESS 31059243Sobrien if (utmp.ut_type == DEAD_PROCESS && utmp.ut_line[0] == '\0') 31159243Sobrien continue; 31259243Sobrien# endif /* DEAD_PROCESS */ 31359243Sobrien wp = whohead.who_next; 31459243Sobrien while (wp->who_next && (comp = strncmp(wp->who_tty, utmp.ut_line, UTLINLEN)) < 0) 31559243Sobrien wp = wp->who_next;/* find that tty! */ 31659243Sobrien 31759243Sobrien if (wp->who_next && comp == 0) { /* found the tty... */ 31859243Sobrien# ifdef DEAD_PROCESS 31959243Sobrien if (utmp.ut_type == DEAD_PROCESS) { 32059243Sobrien wp->who_time = utmp.ut_time; 32159243Sobrien wp->who_status = OFFLINE; 32259243Sobrien } 32359243Sobrien else 32459243Sobrien# endif /* DEAD_PROCESS */ 32559243Sobrien if (utmp.ut_name[0] == '\0') { 32659243Sobrien wp->who_time = utmp.ut_time; 32759243Sobrien wp->who_status = OFFLINE; 32859243Sobrien } 32959243Sobrien else if (strncmp(utmp.ut_name, wp->who_name, UTNAMLEN) == 0) { 33059243Sobrien /* someone is logged in */ 33159243Sobrien wp->who_time = utmp.ut_time; 33259243Sobrien wp->who_status = 0; /* same guy */ 33359243Sobrien } 33459243Sobrien else { 33559243Sobrien (void) strncpy(wp->who_new, utmp.ut_name, UTNAMLEN); 33659243Sobrien# ifdef UTHOST 33759243Sobrien# ifdef _SEQUENT_ 33859243Sobrien host = ut_find_host(wp->who_tty); 33959243Sobrien if (host) 34059243Sobrien (void) strncpy(wp->who_host, host, UTHOSTLEN); 34159243Sobrien else 34259243Sobrien wp->who_host[0] = 0; 34359243Sobrien# else 34459243Sobrien (void) strncpy(wp->who_host, utmp.ut_host, UTHOSTLEN); 34559243Sobrien# endif 34659243Sobrien# endif /* UTHOST */ 34759243Sobrien wp->who_time = utmp.ut_time; 34859243Sobrien if (wp->who_name[0] == '\0') 34959243Sobrien wp->who_status = ONLINE; 35059243Sobrien else 35159243Sobrien wp->who_status = CHANGED; 35259243Sobrien } 35359243Sobrien } 35459243Sobrien else { /* new tty in utmp */ 35559243Sobrien wpnew = (struct who *) xcalloc(1, sizeof *wpnew); 35659243Sobrien (void) strncpy(wpnew->who_tty, utmp.ut_line, UTLINLEN); 35759243Sobrien# ifdef UTHOST 35859243Sobrien# ifdef _SEQUENT_ 35959243Sobrien host = ut_find_host(wpnew->who_tty); 36059243Sobrien if (host) 36159243Sobrien (void) strncpy(wpnew->who_host, host, UTHOSTLEN); 36259243Sobrien else 36359243Sobrien wpnew->who_host[0] = 0; 36459243Sobrien# else 36559243Sobrien (void) strncpy(wpnew->who_host, utmp.ut_host, UTHOSTLEN); 36659243Sobrien# endif 36759243Sobrien# endif /* UTHOST */ 36859243Sobrien wpnew->who_time = utmp.ut_time; 36959243Sobrien# ifdef DEAD_PROCESS 37059243Sobrien if (utmp.ut_type == DEAD_PROCESS) 37159243Sobrien wpnew->who_status = OFFLINE; 37259243Sobrien else 37359243Sobrien# endif /* DEAD_PROCESS */ 37459243Sobrien if (utmp.ut_name[0] == '\0') 37559243Sobrien wpnew->who_status = OFFLINE; 37659243Sobrien else { 37759243Sobrien (void) strncpy(wpnew->who_new, utmp.ut_name, UTNAMLEN); 37859243Sobrien wpnew->who_status = ONLINE; 37959243Sobrien } 38059243Sobrien# ifdef WHODEBUG 38159243Sobrien debugwholist(wpnew, wp); 38259243Sobrien# endif /* WHODEBUG */ 38359243Sobrien 38459243Sobrien wpnew->who_next = wp; /* link in a new 'who' */ 38559243Sobrien wpnew->who_prev = wp->who_prev; 38659243Sobrien wpnew->who_prev->who_next = wpnew; 38759243Sobrien wp->who_prev = wpnew; /* linked in now */ 38859243Sobrien } 38959243Sobrien } 39059243Sobrien (void) close(utmpfd); 39159243Sobrien# if defined(UTHOST) && defined(_SEQUENT_) 39259243Sobrien endutent(); 39359243Sobrien# endif 39469408Sache#endif /* !WINNT_NATIVE */ 39559243Sobrien 39659243Sobrien if (force || vp == NULL) 39759243Sobrien return; 39859243Sobrien 39959243Sobrien /* 40059243Sobrien * The state of all logins is now known, so we can search the user's list 40159243Sobrien * of watchables to print the interesting ones. 40259243Sobrien */ 40359243Sobrien for (alldone = 0; !alldone && *vp != NULL && **vp != '\0' && 40459243Sobrien *(vp + 1) != NULL && **(vp + 1) != '\0'; 40559243Sobrien vp += 2) { /* args used in pairs... */ 40659243Sobrien 40759243Sobrien if (eq(*vp, STRany) && eq(*(vp + 1), STRany)) 40859243Sobrien alldone = 1; 40959243Sobrien 41059243Sobrien for (wp = whohead.who_next; wp->who_next != NULL; wp = wp->who_next) { 41159243Sobrien if (wp->who_status & ANNOUNCE || 41259243Sobrien (!eq(STRany, vp[0]) && 41359243Sobrien !Gmatch(str2short(wp->who_name), vp[0]) && 41459243Sobrien !Gmatch(str2short(wp->who_new), vp[0])) || 41559243Sobrien (!Gmatch(str2short(wp->who_tty), vp[1]) && 41659243Sobrien !eq(STRany, vp[1]))) 41759243Sobrien continue; /* entry doesn't qualify */ 41859243Sobrien /* already printed or not right one to print */ 41959243Sobrien 42059243Sobrien 42159243Sobrien if (wp->who_time == 0)/* utmp entry was cleared */ 42259243Sobrien wp->who_time = watch_period; 42359243Sobrien 42459243Sobrien if ((wp->who_status & OFFLINE) && 42559243Sobrien (wp->who_name[0] != '\0')) { 42659243Sobrien if (!firsttime) 42759243Sobrien print_who(wp); 42859243Sobrien wp->who_name[0] = '\0'; 42959243Sobrien wp->who_status |= ANNOUNCE; 43059243Sobrien continue; 43159243Sobrien } 43259243Sobrien if (wp->who_status & ONLINE) { 43359243Sobrien if (!firsttime) 43459243Sobrien print_who(wp); 43559243Sobrien (void) strcpy(wp->who_name, wp->who_new); 43659243Sobrien wp->who_status |= ANNOUNCE; 43759243Sobrien continue; 43859243Sobrien } 43959243Sobrien if (wp->who_status & CHANGED) { 44059243Sobrien if (!firsttime) 44159243Sobrien print_who(wp); 44259243Sobrien (void) strcpy(wp->who_name, wp->who_new); 44359243Sobrien wp->who_status |= ANNOUNCE; 44459243Sobrien continue; 44559243Sobrien } 44659243Sobrien } 44759243Sobrien } 44859243Sobrien#ifdef BSDSIGS 44959243Sobrien (void) sigsetmask(omask); 45059243Sobrien#else 45159243Sobrien (void) sigrelse(SIGINT); 45259243Sobrien#endif 45359243Sobrien} 45459243Sobrien 45559243Sobrien#ifdef WHODEBUG 45659243Sobrienstatic void 45759243Sobriendebugwholist(new, wp) 45859243Sobrien register struct who *new, *wp; 45959243Sobrien{ 46059243Sobrien register struct who *a; 46159243Sobrien 46259243Sobrien a = whohead.who_next; 46359243Sobrien while (a->who_next != NULL) { 46459243Sobrien xprintf("%s/%s -> ", a->who_name, a->who_tty); 46559243Sobrien a = a->who_next; 46659243Sobrien } 46759243Sobrien xprintf("TAIL\n"); 46859243Sobrien if (a != &whotail) { 46959243Sobrien xprintf(CGETS(26, 3, "BUG! last element is not whotail!\n")); 47059243Sobrien abort(); 47159243Sobrien } 47259243Sobrien a = whotail.who_prev; 47359243Sobrien xprintf(CGETS(26, 4, "backward: ")); 47459243Sobrien while (a->who_prev != NULL) { 47559243Sobrien xprintf("%s/%s -> ", a->who_name, a->who_tty); 47659243Sobrien a = a->who_prev; 47759243Sobrien } 47859243Sobrien xprintf("HEAD\n"); 47959243Sobrien if (a != &whohead) { 48059243Sobrien xprintf(CGETS(26, 5, "BUG! first element is not whohead!\n")); 48159243Sobrien abort(); 48259243Sobrien } 48359243Sobrien if (new) 48459243Sobrien xprintf(CGETS(26, 6, "new: %s/%s\n"), new->who_name, new->who_tty); 48559243Sobrien if (wp) 48659243Sobrien xprintf("wp: %s/%s\n", wp->who_name, wp->who_tty); 48759243Sobrien} 48859243Sobrien#endif /* WHODEBUG */ 48959243Sobrien 49059243Sobrien 49159243Sobrienstatic void 49259243Sobrienprint_who(wp) 49359243Sobrien struct who *wp; 49459243Sobrien{ 49559243Sobrien#ifdef UTHOST 49659243Sobrien Char *cp = str2short(CGETS(26, 7, "%n has %a %l from %m.")); 49759243Sobrien#else 49859243Sobrien Char *cp = str2short(CGETS(26, 8, "%n has %a %l.")); 49959243Sobrien#endif /* UTHOST */ 50059243Sobrien struct varent *vp = adrof(STRwho); 50159243Sobrien Char buf[BUFSIZE]; 50259243Sobrien 50359243Sobrien if (vp && vp->vec[0]) 50459243Sobrien cp = vp->vec[0]; 50559243Sobrien 50659243Sobrien tprintf(FMT_WHO, buf, cp, BUFSIZE, NULL, wp->who_time, (ptr_t) wp); 50759243Sobrien for (cp = buf; *cp;) 50859243Sobrien xputchar(*cp++); 50959243Sobrien xputchar('\n'); 51059243Sobrien} /* end print_who */ 51159243Sobrien 51259243Sobrien 51359243Sobrienconst char * 51459243Sobrienwho_info(ptr, c, wbuf, wbufsiz) 51559243Sobrien ptr_t ptr; 51659243Sobrien int c; 51759243Sobrien char *wbuf; 51859243Sobrien size_t wbufsiz; 51959243Sobrien{ 52059243Sobrien struct who *wp = (struct who *) ptr; 52159243Sobrien#ifdef UTHOST 52259243Sobrien char *wb = wbuf; 52359243Sobrien int flg; 52459243Sobrien char *pb; 52559243Sobrien#endif /* UTHOST */ 52659243Sobrien 52759243Sobrien switch (c) { 52859243Sobrien case 'n': /* user name */ 52959243Sobrien switch (wp->who_status & STMASK) { 53059243Sobrien case ONLINE: 53159243Sobrien case CHANGED: 53259243Sobrien return wp->who_new; 53359243Sobrien case OFFLINE: 53459243Sobrien return wp->who_name; 53559243Sobrien default: 53659243Sobrien break; 53759243Sobrien } 53859243Sobrien break; 53959243Sobrien 54059243Sobrien case 'a': 54159243Sobrien switch (wp->who_status & STMASK) { 54259243Sobrien case ONLINE: 54359243Sobrien return CGETS(26, 9, "logged on"); 54459243Sobrien case OFFLINE: 54559243Sobrien return CGETS(26, 10, "logged off"); 54659243Sobrien case CHANGED: 54759243Sobrien xsnprintf(wbuf, wbufsiz, CGETS(26, 11, "replaced %s on"), 54859243Sobrien wp->who_name); 54959243Sobrien return wbuf; 55059243Sobrien default: 55159243Sobrien break; 55259243Sobrien } 55359243Sobrien break; 55459243Sobrien 55559243Sobrien#ifdef UTHOST 55659243Sobrien case 'm': 55759243Sobrien if (wp->who_host[0] == '\0') 55859243Sobrien return CGETS(26, 12, "local"); 55959243Sobrien else { 56059243Sobrien /* the ':' stuff is for <host>:<display>.<screen> */ 56159243Sobrien for (pb = wp->who_host, flg = Isdigit(*pb) ? '\0' : '.'; 56259243Sobrien *pb != '\0' && 56359243Sobrien (*pb != flg || ((pb = strchr(pb, ':')) != 0)); 56459243Sobrien pb++) { 56559243Sobrien if (*pb == ':') 56659243Sobrien flg = '\0'; 56759243Sobrien *wb++ = Isupper(*pb) ? Tolower(*pb) : *pb; 56859243Sobrien } 56959243Sobrien *wb = '\0'; 57059243Sobrien return wbuf; 57159243Sobrien } 57259243Sobrien 57359243Sobrien case 'M': 57459243Sobrien if (wp->who_host[0] == '\0') 57559243Sobrien return CGETS(26, 12, "local"); 57659243Sobrien else { 57759243Sobrien for (pb = wp->who_host; *pb != '\0'; pb++) 57859243Sobrien *wb++ = Isupper(*pb) ? Tolower(*pb) : *pb; 57959243Sobrien *wb = '\0'; 58059243Sobrien return wbuf; 58159243Sobrien } 58259243Sobrien#endif /* UTHOST */ 58359243Sobrien 58459243Sobrien case 'l': 58559243Sobrien return wp->who_tty; 58659243Sobrien 58759243Sobrien default: 58859243Sobrien wbuf[0] = '%'; 58959243Sobrien wbuf[1] = (char) c; 59059243Sobrien wbuf[2] = '\0'; 59159243Sobrien return wbuf; 59259243Sobrien } 59359243Sobrien return NULL; 59459243Sobrien} 59559243Sobrien 59659243Sobrienvoid 59759243Sobrien/*ARGSUSED*/ 59859243Sobriendolog(v, c) 59959243SobrienChar **v; 60059243Sobrienstruct command *c; 60159243Sobrien{ 60259243Sobrien struct who *wp; 60359243Sobrien struct varent *vp; 60459243Sobrien 60559243Sobrien USE(v); 60659243Sobrien USE(c); 60759243Sobrien vp = adrof(STRwatch); /* lint insists vp isn't used unless we */ 60859243Sobrien if (vp == NULL) /* unless we assign it outside the if */ 60959243Sobrien stderror(ERR_NOWATCH); 61059243Sobrien resetwatch(); 61159243Sobrien wp = whohead.who_next; 61259243Sobrien while (wp->who_next != NULL) { 61359243Sobrien wp->who_name[0] = '\0'; 61459243Sobrien wp = wp->who_next; 61559243Sobrien } 61659243Sobrien} 61759243Sobrien 61859243Sobrien# ifdef UTHOST 61969408Sachesize_t 62069408Sacheutmphostsize() 62169408Sache{ 62269408Sache return UTHOSTLEN; 62369408Sache} 62469408Sache 62559243Sobrienchar * 62659243Sobrienutmphost() 62759243Sobrien{ 62859243Sobrien char *tty = short2str(varval(STRtty)); 62959243Sobrien struct who *wp; 63059243Sobrien char *host = NULL; 63159243Sobrien 63259243Sobrien watch_login(1); 63359243Sobrien 63459243Sobrien for (wp = whohead.who_next; wp->who_next != NULL; wp = wp->who_next) { 63559243Sobrien if (strcmp(tty, wp->who_tty) == 0) 63659243Sobrien host = wp->who_host; 63759243Sobrien wp->who_name[0] = '\0'; 63859243Sobrien } 63959243Sobrien resetwatch(); 64059243Sobrien return host; 64159243Sobrien} 64259243Sobrien# endif /* UTHOST */ 64359243Sobrien 64469408Sache#ifdef WINNT_NATIVE 64559243Sobrienvoid add_to_who_list(name, mach_nm) 64659243Sobrien char *name; 64759243Sobrien char *mach_nm; 64859243Sobrien{ 64959243Sobrien 65059243Sobrien struct who *wp, *wpnew; 65159243Sobrien int comp = -1; 65259243Sobrien 65359243Sobrien wp = whohead.who_next; 65459243Sobrien while (wp->who_next && (comp = strncmp(wp->who_tty,mach_nm,UTLINLEN)) < 0) 65559243Sobrien wp = wp->who_next;/* find that tty! */ 65659243Sobrien 65759243Sobrien if (wp->who_next && comp == 0) { /* found the tty... */ 65859243Sobrien 65959243Sobrien if (*name == '\0') { 66059243Sobrien wp->who_time = 0; 66159243Sobrien wp->who_status = OFFLINE; 66259243Sobrien } 66359243Sobrien else if (strncmp(name, wp->who_name, UTNAMLEN) == 0) { 66459243Sobrien /* someone is logged in */ 66559243Sobrien wp->who_time = 0; 66659243Sobrien wp->who_status = 0; /* same guy */ 66759243Sobrien } 66859243Sobrien else { 66959243Sobrien (void) strncpy(wp->who_new, name, UTNAMLEN); 67059243Sobrien wp->who_time = 0; 67159243Sobrien if (wp->who_name[0] == '\0') 67259243Sobrien wp->who_status = ONLINE; 67359243Sobrien else 67459243Sobrien wp->who_status = CHANGED; 67559243Sobrien } 67659243Sobrien } 67759243Sobrien else { 67859243Sobrien wpnew = (struct who *) xcalloc(1, sizeof *wpnew); 67959243Sobrien (void) strncpy(wpnew->who_tty, mach_nm, UTLINLEN); 68059243Sobrien wpnew->who_time = 0; 68159243Sobrien if (*name == '\0') 68259243Sobrien wpnew->who_status = OFFLINE; 68359243Sobrien else { 68459243Sobrien (void) strncpy(wpnew->who_new, name, UTNAMLEN); 68559243Sobrien wpnew->who_status = ONLINE; 68659243Sobrien } 68759243Sobrien#ifdef WHODEBUG 68859243Sobrien debugwholist(wpnew, wp); 68959243Sobrien#endif /* WHODEBUG */ 69059243Sobrien 69159243Sobrien wpnew->who_next = wp; /* link in a new 'who' */ 69259243Sobrien wpnew->who_prev = wp->who_prev; 69359243Sobrien wpnew->who_prev->who_next = wpnew; 69459243Sobrien wp->who_prev = wpnew; /* linked in now */ 69559243Sobrien } 69659243Sobrien} 69769408Sache#endif /* WINNT_NATIVE */ 69859243Sobrien#endif /* HAVENOUTMP */ 699