tc.who.c revision 232633
11590Srgrimes/* $Header: /p/tcsh/cvsroot/tcsh/tc.who.c,v 3.57 2012/01/17 20:53:38 christos Exp $ */ 21590Srgrimes/* 31590Srgrimes * tc.who.c: Watch logins and logouts... 41590Srgrimes */ 51590Srgrimes/*- 61590Srgrimes * Copyright (c) 1980, 1991 The Regents of the University of California. 71590Srgrimes * All rights reserved. 81590Srgrimes * 91590Srgrimes * Redistribution and use in source and binary forms, with or without 101590Srgrimes * modification, are permitted provided that the following conditions 111590Srgrimes * are met: 121590Srgrimes * 1. Redistributions of source code must retain the above copyright 131590Srgrimes * notice, this list of conditions and the following disclaimer. 141590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 151590Srgrimes * notice, this list of conditions and the following disclaimer in the 161590Srgrimes * documentation and/or other materials provided with the distribution. 171590Srgrimes * 3. Neither the name of the University nor the names of its contributors 181590Srgrimes * may be used to endorse or promote products derived from this software 191590Srgrimes * without specific prior written permission. 201590Srgrimes * 211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311590Srgrimes * SUCH DAMAGE. 321590Srgrimes */ 331590Srgrimes#include "sh.h" 341590Srgrimes 3574769SmikehRCSID("$tcsh: tc.who.c,v 3.57 2012/01/17 20:53:38 christos Exp $") 361590Srgrimes 3774769Smikeh#include "tc.h" 3874769Smikeh 3974769Smikeh#ifndef HAVENOUTMP 401590Srgrimes/* 411590Srgrimes * kfk 26 Jan 1984 - for login watch functions. 421590Srgrimes */ 431590Srgrimes#include <ctype.h> 441590Srgrimes 451590Srgrimes#ifdef HAVE_UTMPX_H 461590Srgrimes# include <utmpx.h> 471590Srgrimes# define UTNAMLEN sizeof(((struct utmpx *) 0)->ut_name) 481590Srgrimes# define UTLINLEN sizeof(((struct utmpx *) 0)->ut_line) 491590Srgrimes# ifdef HAVE_STRUCT_UTMPX_UT_HOST 5088428Smikeh# define UTHOSTLEN sizeof(((struct utmpx *) 0)->ut_host) 511590Srgrimes# endif 521590Srgrimes/* I just redefine a few words here. Changing every occurrence below 531590Srgrimes * seems like too much of work. All UTMP functions have equivalent 541590Srgrimes * UTMPX counterparts, so they can be added all here when needed. 551590Srgrimes * Kimmo Suominen, Oct 14 1991 561590Srgrimes */ 571590Srgrimes# if defined(__UTMPX_FILE) && !defined(UTMPX_FILE) 581590Srgrimes# define TCSH_PATH_UTMP __UTMPX_FILE 591590Srgrimes# elif defined(_PATH_UTMPX) 601590Srgrimes# define TCSH_PATH_UTMP _PATH_UTMPX 611590Srgrimes# elif defined(UTMPX_FILE) 621590Srgrimes# define TCSH_PATH_UTMP UTMPX_FILE 631590Srgrimes# elif __FreeBSD_version >= 900000 641590Srgrimes# /* Why isn't this defined somewhere? */ 651590Srgrimes# define TCSH_PATH_UTMP "/var/run/utx.active" 661590Srgrimes# elif defined(__hpux) 671590Srgrimes# define TCSH_PATH_UTMP "/etc/utmpx" 681590Srgrimes# endif 691590Srgrimes# if defined(TCSH_PATH_UTMP) || !defined(HAVE_UTMP_H) 701590Srgrimes# define utmp utmpx 711590Srgrimes# define TCSH_USE_UTMPX 721590Srgrimes# if defined(HAVE_GETUTENT) || defined(HAVE_GETUTXENT) 731590Srgrimes# define getutent getutxent 741590Srgrimes# define setutent setutxent 751590Srgrimes# define endutent endutxent 761590Srgrimes# endif /* HAVE_GETUTENT || HAVE_GETUTXENT */ 771590Srgrimes# if defined(HAVE_STRUCT_UTMPX_UT_TV) 781590Srgrimes# define ut_time ut_tv.tv_sec 791590Srgrimes# elif defined(HAVE_STRUCT_UTMPX_UT_XTIME) 801590Srgrimes# define ut_time ut_xtime 811590Srgrimes# endif 8277274Smikeh# if defined(HAVE_STRUCT_UTMPX_UT_USER) 8377274Smikeh# define ut_name ut_user 8488150Smikeh# endif 8588150Smikeh# endif /* TCSH_PATH_UTMP || !HAVE_UTMP_H */ 8688150Smikeh#endif /* HAVE_UTMPX_H */ 871590Srgrimes 881590Srgrimes#if !defined(TCSH_USE_UTMPX) && defined(HAVE_UTMP_H) 891590Srgrimes# include <utmp.h> 901590Srgrimes# if defined(HAVE_STRUCT_UTMP_UT_TV) 911590Srgrimes# define ut_time ut_tv.tv_sec 921590Srgrimes# elif defined(HAVE_STRUCT_UTMP_UT_XTIME) 9388150Smikeh# define ut_time ut_xtime 9488150Smikeh# endif 9588150Smikeh# if defined(HAVE_STRUCT_UTMP_UT_USER) 9688150Smikeh# define ut_name ut_user 971590Srgrimes# endif 9877274Smikeh# ifndef BROKEN_CC 991590Srgrimes# define UTNAMLEN sizeof(((struct utmp *) 0)->ut_name) 10077274Smikeh# define UTLINLEN sizeof(((struct utmp *) 0)->ut_line) 1011590Srgrimes# ifdef HAVE_STRUCT_UTMP_UT_HOST 1021590Srgrimes# ifdef _SEQUENT_ 1031590Srgrimes# define UTHOSTLEN 100 1041590Srgrimes# else 10577274Smikeh# define UTHOSTLEN sizeof(((struct utmp *) 0)->ut_host) 1061590Srgrimes# endif 1071590Srgrimes# endif /* HAVE_STRUCT_UTMP_UT_HOST */ 10888150Smikeh# else 1091590Srgrimes/* give poor cc a little help if it needs it */ 1101590Srgrimesstruct utmp __ut; 11177274Smikeh# define UTNAMLEN sizeof(__ut.ut_name) 11277274Smikeh# define UTLINLEN sizeof(__ut.ut_line) 11374769Smikeh# ifdef HAVE_STRUCT_UTMP_UT_HOST 11474769Smikeh# ifdef _SEQUENT_ 11574769Smikeh# define UTHOSTLEN 100 1161590Srgrimes# else 1171590Srgrimes# define UTHOSTLEN sizeof(__ut.ut_host) 11877274Smikeh# endif 1191590Srgrimes# endif /* HAVE_STRUCT_UTMP_UT_HOST */ 1201590Srgrimes# endif /* BROKEN_CC */ 1211590Srgrimes# ifndef TCSH_PATH_UTMP 1221590Srgrimes# ifdef UTMP_FILE 1231590Srgrimes# define TCSH_PATH_UTMP UTMP_FILE 1241590Srgrimes# elif defined(_PATH_UTMP) 1251590Srgrimes# define TCSH_PATH_UTMP _PATH_UTMP 1261590Srgrimes# else 12777274Smikeh# define TCSH_PATH_UTMP "/etc/utmp" 12877274Smikeh# endif /* UTMP_FILE */ 1291590Srgrimes# endif /* TCSH_PATH_UTMP */ 1301590Srgrimes#endif /* !TCSH_USE_UTMPX && HAVE_UTMP_H */ 1311590Srgrimes 13277274Smikeh#ifndef UTNAMLEN 1331590Srgrimes#define UTNAMLEN 64 13477274Smikeh#endif 1351590Srgrimes#ifndef UTLINLEN 1361590Srgrimes#define UTLINLEN 64 1371590Srgrimes#endif 1381590Srgrimes 1391590Srgrimesstruct who { 14088150Smikeh struct who *who_next; 14188150Smikeh struct who *who_prev; 1421590Srgrimes char who_name[UTNAMLEN + 1]; 1431590Srgrimes char who_new[UTNAMLEN + 1]; 1441590Srgrimes char who_tty[UTLINLEN + 1]; 1451590Srgrimes#ifdef UTHOSTLEN 1461590Srgrimes char who_host[UTHOSTLEN + 1]; 1471590Srgrimes#endif /* UTHOSTLEN */ 1481590Srgrimes time_t who_time; 1491590Srgrimes int who_status; 1501590Srgrimes}; 1511590Srgrimes 1521590Srgrimesstatic struct who whohead, whotail; 1531590Srgrimesstatic time_t watch_period = 0; 15477274Smikehstatic time_t stlast = 0; 1551590Srgrimes#ifdef WHODEBUG 1561590Srgrimesstatic void debugwholist (struct who *, struct who *); 1571590Srgrimes#endif 1581590Srgrimesstatic void print_who (struct who *); 15977274Smikeh 1601590Srgrimes 1611590Srgrimes#define ONLINE 01 1621590Srgrimes#define OFFLINE 02 1631590Srgrimes#define CHANGED 04 1641590Srgrimes#define STMASK 07 1651590Srgrimes#define ANNOUNCE 010 1661590Srgrimes#define CLEARED 020 16777274Smikeh 16877274Smikeh/* 1691590Srgrimes * Karl Kleinpaste, 26 Jan 1984. 1701590Srgrimes * Initialize the dummy tty list for login watch. 1711590Srgrimes * This dummy list eliminates boundary conditions 1721590Srgrimes * when doing pointer-chase searches. 1731590Srgrimes */ 17488150Smikehvoid 17588150Smikehinitwatch(void) 1761590Srgrimes{ 1771590Srgrimes whohead.who_next = &whotail; 1781590Srgrimes whotail.who_prev = &whohead; 17988150Smikeh stlast = 1; 18077274Smikeh#ifdef WHODEBUG 1811590Srgrimes debugwholist(NULL, NULL); 18288150Smikeh#endif /* WHODEBUG */ 18388150Smikeh} 18488150Smikeh 1851590Srgrimesvoid 1861590Srgrimesresetwatch(void) 1871590Srgrimes{ 1881590Srgrimes watch_period = 0; 1891590Srgrimes stlast = 0; 1901590Srgrimes} 1911590Srgrimes 1921590Srgrimes/* 1931590Srgrimes * Karl Kleinpaste, 26 Jan 1984. 1941590Srgrimes * Watch /etc/utmp for login/logout changes. 1951590Srgrimes */ 19688150Smikehvoid 1971590Srgrimeswatch_login(int force) 1981590Srgrimes{ 1991590Srgrimes int comp = -1, alldone; 2001590Srgrimes int firsttime = stlast == 1; 2011590Srgrimes#if defined(HAVE_GETUTENT) || defined(HAVE_GETUTXENT) 2021590Srgrimes struct utmp *uptr; 2031590Srgrimes#else 2041590Srgrimes int utmpfd; 2051590Srgrimes#endif 2061590Srgrimes struct utmp utmp; 2071590Srgrimes struct who *wp, *wpnew; 2081590Srgrimes struct varent *v; 2091590Srgrimes Char **vp = NULL; 2101590Srgrimes time_t t, interval = MAILINTVL; 2111590Srgrimes struct stat sta; 2121590Srgrimes#if defined(HAVE_STRUCT_UTMP_UT_HOST) && defined(_SEQUENT_) 2131590Srgrimes char *host, *ut_find_host(); 2141590Srgrimes#endif 2151590Srgrimes#ifdef WINNT_NATIVE 2161590Srgrimes static int ncbs_posted = 0; 21788428Smikeh USE(utmp); 2181590Srgrimes USE(utmpfd); 2191590Srgrimes USE(sta); 2201590Srgrimes USE(wpnew); 2211590Srgrimes#endif /* WINNT_NATIVE */ 2221590Srgrimes 2231590Srgrimes /* stop SIGINT, lest our login list get trashed. */ 2241590Srgrimes pintr_disabled++; 2251590Srgrimes cleanup_push(&pintr_disabled, disabled_cleanup); 2261590Srgrimes 2271590Srgrimes v = adrof(STRwatch); 2281590Srgrimes if ((v == NULL || v->vec == NULL) && !force) { 2291590Srgrimes cleanup_until(&pintr_disabled); 2301590Srgrimes return; /* no names to watch */ 2311590Srgrimes } 2321590Srgrimes if (!force) { 2331590Srgrimes trim(vp = v->vec); 2341590Srgrimes if (blklen(vp) % 2) /* odd # args: 1st == # minutes. */ 2351590Srgrimes interval = (number(*vp)) ? (getn(*vp++) * 60) : MAILINTVL; 23688428Smikeh } 23788428Smikeh else 23888428Smikeh interval = 0; 23988428Smikeh 24088428Smikeh (void) time(&t); 2411590Srgrimes#ifdef WINNT_NATIVE 2421590Srgrimes /* 2431590Srgrimes * Since NCB_ASTATs take time, start em async at least 90 secs 2441590Srgrimes * before we are due -amol 6/5/97 2451590Srgrimes */ 2461590Srgrimes if (!ncbs_posted) { 2471590Srgrimes time_t tdiff = t - watch_period; 2481590Srgrimes if (!watch_period || ((tdiff > 0) && (tdiff > (interval - 90)))) { 2491590Srgrimes start_ncbs(vp); 2501590Srgrimes ncbs_posted = 1; 2511590Srgrimes } 2521590Srgrimes } 2531590Srgrimes#endif /* WINNT_NATIVE */ 2541590Srgrimes if (t - watch_period < interval) { 25532189Sjoerg cleanup_until(&pintr_disabled); 2561590Srgrimes return; /* not long enough yet... */ 2571590Srgrimes } 25888227Sache watch_period = t; 2591590Srgrimes#ifdef WINNT_NATIVE 2601590Srgrimes ncbs_posted = 0; 2611590Srgrimes#else /* !WINNT_NATIVE */ 26232189Sjoerg 26332189Sjoerg /* 26432189Sjoerg * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de> 26532189Sjoerg * Don't open utmp all the time, stat it first... 26632189Sjoerg */ 26788227Sache if (stat(TCSH_PATH_UTMP, &sta)) { 26832189Sjoerg if (!force) 26932189Sjoerg xprintf(CGETS(26, 1, 27032189Sjoerg "cannot stat %s. Please \"unset watch\".\n"), 2711590Srgrimes TCSH_PATH_UTMP); 2721590Srgrimes cleanup_until(&pintr_disabled); 2731590Srgrimes return; 2741590Srgrimes } 2751590Srgrimes if (stlast == sta.st_mtime) { 2761590Srgrimes cleanup_until(&pintr_disabled); 2771590Srgrimes return; 2781590Srgrimes } 27988428Smikeh stlast = sta.st_mtime; 2801590Srgrimes#if defined(HAVE_GETUTENT) || defined(HAVE_GETUTXENT) 2811590Srgrimes setutent(); 2821590Srgrimes#else 28388428Smikeh if ((utmpfd = xopen(TCSH_PATH_UTMP, O_RDONLY|O_LARGEFILE)) < 0) { 28488428Smikeh if (!force) 28588428Smikeh xprintf(CGETS(26, 2, 28688428Smikeh "%s cannot be opened. Please \"unset watch\".\n"), 28788428Smikeh TCSH_PATH_UTMP); 28888428Smikeh cleanup_until(&pintr_disabled); 28988428Smikeh return; 29088428Smikeh } 29188428Smikeh cleanup_push(&utmpfd, open_cleanup); 29288428Smikeh#endif 29388428Smikeh 29488428Smikeh /* 29588428Smikeh * xterm clears the entire utmp entry - mark everyone on the status list 29688428Smikeh * OFFLINE or we won't notice X "logouts" 29788428Smikeh */ 29888428Smikeh for (wp = whohead.who_next; wp->who_next != NULL; wp = wp->who_next) 29988428Smikeh wp->who_status = OFFLINE | CLEARED; 30088428Smikeh 30188428Smikeh /* 30288428Smikeh * Read in the utmp file, sort the entries, and update existing entries or 30388428Smikeh * add new entries to the status list. 30488428Smikeh */ 30588428Smikeh#if defined(HAVE_GETUTENT) || defined(HAVE_GETUTXENT) 30688428Smikeh while ((uptr = getutent()) != NULL) { 30788428Smikeh memcpy(&utmp, uptr, sizeof (utmp)); 30888428Smikeh#else 30988428Smikeh while (xread(utmpfd, &utmp, sizeof utmp) == sizeof utmp) { 31088428Smikeh#endif 31188428Smikeh 3121590Srgrimes# ifdef DEAD_PROCESS 31388428Smikeh# ifndef IRIS4D 31488428Smikeh if (utmp.ut_type != USER_PROCESS) 31588428Smikeh continue; 31688428Smikeh# else 31788428Smikeh /* Why is that? Cause the utmp file is always corrupted??? */ 31874769Smikeh if (utmp.ut_type != USER_PROCESS && utmp.ut_type != DEAD_PROCESS) 31974769Smikeh continue; 32074769Smikeh# endif /* IRIS4D */ 32174769Smikeh# endif /* DEAD_PROCESS */ 32288428Smikeh 3231590Srgrimes if (utmp.ut_name[0] == '\0' && utmp.ut_line[0] == '\0') 32488428Smikeh continue; /* completely void entry */ 3251590Srgrimes# ifdef DEAD_PROCESS 3261590Srgrimes if (utmp.ut_type == DEAD_PROCESS && utmp.ut_line[0] == '\0') 3271590Srgrimes continue; 3281590Srgrimes# endif /* DEAD_PROCESS */ 3291590Srgrimes wp = whohead.who_next; 3301590Srgrimes while (wp->who_next && (comp = strncmp(wp->who_tty, utmp.ut_line, UTLINLEN)) < 0) 33188227Sache wp = wp->who_next;/* find that tty! */ 3321590Srgrimes 3331590Srgrimes if (wp->who_next && comp == 0) { /* found the tty... */ 3341590Srgrimes if (utmp.ut_time < wp->who_time) 3351590Srgrimes continue; 3361590Srgrimes# ifdef DEAD_PROCESS 3371590Srgrimes if (utmp.ut_type == DEAD_PROCESS) { 33877274Smikeh wp->who_time = utmp.ut_time; 3391590Srgrimes wp->who_status = OFFLINE; 34088428Smikeh } 34188428Smikeh else 34288428Smikeh# endif /* DEAD_PROCESS */ 34388428Smikeh if (utmp.ut_name[0] == '\0') { 34488428Smikeh wp->who_time = utmp.ut_time; 34588428Smikeh wp->who_status = OFFLINE; 34688428Smikeh } 34788428Smikeh else if (strncmp(utmp.ut_name, wp->who_name, UTNAMLEN) == 0) { 34888428Smikeh /* someone is logged in */ 34988428Smikeh wp->who_time = utmp.ut_time; 35088428Smikeh wp->who_status = ONLINE | ANNOUNCE; /* same guy */ 35188428Smikeh } 35288428Smikeh else { 35388428Smikeh (void) strncpy(wp->who_new, utmp.ut_name, UTNAMLEN); 35488428Smikeh# ifdef UTHOSTLEN 35588428Smikeh# ifdef _SEQUENT_ 35688428Smikeh host = ut_find_host(wp->who_tty); 35788428Smikeh if (host) 35888428Smikeh (void) strncpy(wp->who_host, host, UTHOSTLEN); 35988428Smikeh else 36088428Smikeh wp->who_host[0] = 0; 36188428Smikeh# else 36288428Smikeh (void) strncpy(wp->who_host, utmp.ut_host, UTHOSTLEN); 36388428Smikeh# endif 36488428Smikeh# endif /* UTHOSTLEN */ 36588428Smikeh wp->who_time = utmp.ut_time; 36688428Smikeh if (wp->who_name[0] == '\0') 36788428Smikeh wp->who_status = ONLINE; 36888428Smikeh else 36988428Smikeh wp->who_status = CHANGED; 37088428Smikeh } 37188428Smikeh } 37288428Smikeh else { /* new tty in utmp */ 37388428Smikeh wpnew = xcalloc(1, sizeof *wpnew); 37488428Smikeh (void) strncpy(wpnew->who_tty, utmp.ut_line, UTLINLEN); 37588428Smikeh# ifdef UTHOSTLEN 37688428Smikeh# ifdef _SEQUENT_ 37788428Smikeh host = ut_find_host(wpnew->who_tty); 37888428Smikeh if (host) 37988428Smikeh (void) strncpy(wpnew->who_host, host, UTHOSTLEN); 38088428Smikeh else 38188428Smikeh wpnew->who_host[0] = 0; 38288428Smikeh# else 38388428Smikeh (void) strncpy(wpnew->who_host, utmp.ut_host, UTHOSTLEN); 38488428Smikeh# endif 38588428Smikeh# endif /* UTHOSTLEN */ 3861590Srgrimes wpnew->who_time = utmp.ut_time; 3871590Srgrimes# ifdef DEAD_PROCESS 38888428Smikeh if (utmp.ut_type == DEAD_PROCESS) 38974769Smikeh wpnew->who_status = OFFLINE; 3901590Srgrimes else 3911590Srgrimes# endif /* DEAD_PROCESS */ 3921590Srgrimes if (utmp.ut_name[0] == '\0') 39377274Smikeh wpnew->who_status = OFFLINE; 3941590Srgrimes else { 3951590Srgrimes (void) strncpy(wpnew->who_new, utmp.ut_name, UTNAMLEN); 39688150Smikeh wpnew->who_status = ONLINE; 39788150Smikeh } 39888150Smikeh# ifdef WHODEBUG 39988150Smikeh debugwholist(wpnew, wp); 40088150Smikeh# endif /* WHODEBUG */ 40177274Smikeh 4021590Srgrimes wpnew->who_next = wp; /* link in a new 'who' */ 4031590Srgrimes wpnew->who_prev = wp->who_prev; 4041590Srgrimes wpnew->who_prev->who_next = wpnew; 4051590Srgrimes wp->who_prev = wpnew; /* linked in now */ 40677274Smikeh } 4071590Srgrimes } 4081590Srgrimes#if defined(HAVE_GETUTENT) || defined(HAVE_GETUTXENT) 4091590Srgrimes endutent(); 4101590Srgrimes#else 4111590Srgrimes cleanup_until(&utmpfd); 4121590Srgrimes#endif 4131590Srgrimes#endif /* !WINNT_NATIVE */ 4141590Srgrimes 4151590Srgrimes if (force || vp == NULL) { 4161590Srgrimes cleanup_until(&pintr_disabled); 4171590Srgrimes return; 4181590Srgrimes } 4191590Srgrimes 42077274Smikeh /* 4211590Srgrimes * The state of all logins is now known, so we can search the user's list 4221590Srgrimes * of watchables to print the interesting ones. 4231590Srgrimes */ 4241590Srgrimes for (alldone = 0; !alldone && *vp != NULL && **vp != '\0' && 4251590Srgrimes *(vp + 1) != NULL && **(vp + 1) != '\0'; 4261590Srgrimes vp += 2) { /* args used in pairs... */ 4271590Srgrimes 4281590Srgrimes if (eq(*vp, STRany) && eq(*(vp + 1), STRany)) 4291590Srgrimes alldone = 1; 4301590Srgrimes 4311590Srgrimes for (wp = whohead.who_next; wp->who_next != NULL; wp = wp->who_next) { 4321590Srgrimes if (wp->who_status & ANNOUNCE || 4331590Srgrimes (!eq(STRany, vp[0]) && 4341590Srgrimes !Gmatch(str2short(wp->who_name), vp[0]) && 43574769Smikeh !Gmatch(str2short(wp->who_new), vp[0])) || 4361590Srgrimes (!Gmatch(str2short(wp->who_tty), vp[1]) && 4371590Srgrimes !eq(STRany, vp[1]))) 4381590Srgrimes continue; /* entry doesn't qualify */ 4391590Srgrimes /* already printed or not right one to print */ 44074769Smikeh 4411590Srgrimes 4421590Srgrimes if (wp->who_status & CLEARED) {/* utmp entry was cleared */ 4431590Srgrimes wp->who_time = watch_period; 44477274Smikeh wp->who_status &= ~CLEARED; 44577274Smikeh } 4461590Srgrimes 4471590Srgrimes if ((wp->who_status & OFFLINE) && 4481590Srgrimes (wp->who_name[0] != '\0')) { 4491590Srgrimes if (!firsttime) 4501590Srgrimes print_who(wp); 4511590Srgrimes wp->who_name[0] = '\0'; 4521590Srgrimes wp->who_status |= ANNOUNCE; 4531590Srgrimes continue; 4541590Srgrimes } 4551590Srgrimes if (wp->who_status & ONLINE) { 45677274Smikeh if (!firsttime) 4571590Srgrimes print_who(wp); 4581590Srgrimes (void) strcpy(wp->who_name, wp->who_new); 4591590Srgrimes wp->who_status |= ANNOUNCE; 4601590Srgrimes continue; 4611590Srgrimes } 4621590Srgrimes if (wp->who_status & CHANGED) { 4631590Srgrimes if (!firsttime) 4641590Srgrimes print_who(wp); 4651590Srgrimes (void) strcpy(wp->who_name, wp->who_new); 4661590Srgrimes wp->who_status |= ANNOUNCE; 4671590Srgrimes continue; 4681590Srgrimes } 4691590Srgrimes } 4701590Srgrimes } 4711590Srgrimes cleanup_until(&pintr_disabled); 4721590Srgrimes} 4731590Srgrimes 4741590Srgrimes#ifdef WHODEBUG 4751590Srgrimesstatic void 4761590Srgrimesdebugwholist(struct who *new, struct who *wp) 4771590Srgrimes{ 4781590Srgrimes struct who *a; 4791590Srgrimes 4801590Srgrimes a = whohead.who_next; 48177274Smikeh while (a->who_next != NULL) { 4821590Srgrimes xprintf("%s/%s -> ", a->who_name, a->who_tty); 4831590Srgrimes a = a->who_next; 4841590Srgrimes } 4851590Srgrimes xprintf("TAIL\n"); 4861590Srgrimes if (a != &whotail) { 4871590Srgrimes xprintf(CGETS(26, 3, "BUG! last element is not whotail!\n")); 48888150Smikeh abort(); 48977274Smikeh } 49077274Smikeh a = whotail.who_prev; 49177274Smikeh xprintf(CGETS(26, 4, "backward: ")); 49277274Smikeh while (a->who_prev != NULL) { 49377274Smikeh xprintf("%s/%s -> ", a->who_name, a->who_tty); 49488150Smikeh a = a->who_prev; 49577274Smikeh } 4961590Srgrimes xprintf("HEAD\n"); 4971590Srgrimes if (a != &whohead) { 4981590Srgrimes xprintf(CGETS(26, 5, "BUG! first element is not whohead!\n")); 4991590Srgrimes abort(); 5001590Srgrimes } 5011590Srgrimes if (new) 5021590Srgrimes xprintf(CGETS(26, 6, "new: %s/%s\n"), new->who_name, new->who_tty); 5031590Srgrimes if (wp) 5041590Srgrimes xprintf("wp: %s/%s\n", wp->who_name, wp->who_tty); 5051590Srgrimes} 5061590Srgrimes#endif /* WHODEBUG */ 50777274Smikeh 50877274Smikeh 5091590Srgrimesstatic void 5101590Srgrimesprint_who(struct who *wp) 5111590Srgrimes{ 5121590Srgrimes#ifdef UTHOSTLEN 5131590Srgrimes Char *cp = str2short(CGETS(26, 7, "%n has %a %l from %m.")); 51477274Smikeh#else 5151590Srgrimes Char *cp = str2short(CGETS(26, 8, "%n has %a %l.")); 51674769Smikeh#endif /* UTHOSTLEN */ 5171590Srgrimes struct varent *vp = adrof(STRwho); 5181590Srgrimes Char *str; 5191590Srgrimes 52077274Smikeh if (vp && vp->vec && vp->vec[0]) 5211590Srgrimes cp = vp->vec[0]; 5221590Srgrimes 52377274Smikeh str = tprintf(FMT_WHO, cp, NULL, wp->who_time, wp); 52477274Smikeh cleanup_push(str, xfree); 5251590Srgrimes for (cp = str; *cp;) 5261590Srgrimes xputwchar(*cp++); 5271590Srgrimes cleanup_until(str); 5281590Srgrimes xputchar('\n'); 5291590Srgrimes} /* end print_who */ 5301590Srgrimes 5311590Srgrimes 53277274Smikehchar * 5331590Srgrimeswho_info(ptr_t ptr, int c) 53474769Smikeh{ 53577274Smikeh struct who *wp = ptr; 53677274Smikeh char *wbuf; 5371590Srgrimes#ifdef UTHOSTLEN 5381590Srgrimes char *wb; 53977274Smikeh int flg; 5401590Srgrimes char *pb; 54177274Smikeh#endif /* UTHOSTLEN */ 54277274Smikeh 5431590Srgrimes switch (c) { 5441590Srgrimes case 'n': /* user name */ 5451590Srgrimes switch (wp->who_status & STMASK) { 5461590Srgrimes case ONLINE: 5471590Srgrimes case CHANGED: 5481590Srgrimes return strsave(wp->who_new); 5491590Srgrimes case OFFLINE: 5501590Srgrimes return strsave(wp->who_name); 5511590Srgrimes default: 5521590Srgrimes break; 5531590Srgrimes } 5541590Srgrimes break; 5551590Srgrimes 5561590Srgrimes case 'a': 5571590Srgrimes switch (wp->who_status & STMASK) { 55882793Sache case ONLINE: 5591590Srgrimes return strsave(CGETS(26, 9, "logged on")); 56077274Smikeh case OFFLINE: 5611590Srgrimes return strsave(CGETS(26, 10, "logged off")); 56277274Smikeh case CHANGED: 5631590Srgrimes return xasprintf(CGETS(26, 11, "replaced %s on"), wp->who_name); 5641590Srgrimes default: 5651590Srgrimes break; 5661590Srgrimes } 5671590Srgrimes break; 5681590Srgrimes 5691590Srgrimes#ifdef UTHOSTLEN 5701590Srgrimes case 'm': 5711590Srgrimes if (wp->who_host[0] == '\0') 5721590Srgrimes return strsave(CGETS(26, 12, "local")); 5731590Srgrimes else { 5741590Srgrimes pb = wp->who_host; 5751590Srgrimes wbuf = xmalloc(strlen(pb) + 1); 5761590Srgrimes wb = wbuf; 57774769Smikeh /* the ':' stuff is for <host>:<display>.<screen> */ 5781590Srgrimes for (flg = isdigit((unsigned char)*pb) ? '\0' : '.'; 57977274Smikeh *pb != '\0' && (*pb != flg || ((pb = strchr(pb, ':')) != 0)); 5801590Srgrimes pb++) { 58177274Smikeh if (*pb == ':') 58277274Smikeh flg = '\0'; 58374769Smikeh *wb++ = isupper((unsigned char)*pb) ? 58474769Smikeh tolower((unsigned char)*pb) : *pb; 58574769Smikeh } 5861590Srgrimes *wb = '\0'; 5871590Srgrimes return wbuf; 58877274Smikeh } 5891590Srgrimes 5901590Srgrimes case 'M': 5911590Srgrimes if (wp->who_host[0] == '\0') 5921590Srgrimes return strsave(CGETS(26, 12, "local")); 59377274Smikeh else { 59477274Smikeh pb = wp->who_host; 59577274Smikeh wbuf = xmalloc(strlen(pb) + 1); 59677274Smikeh wb = wbuf; 59777274Smikeh for (; *pb != '\0'; pb++) 5981590Srgrimes *wb++ = isupper((unsigned char)*pb) ? 5991590Srgrimes tolower((unsigned char)*pb) : *pb; 6001590Srgrimes *wb = '\0'; 6011590Srgrimes return wbuf; 60277274Smikeh } 6031590Srgrimes#endif /* UTHOSTLEN */ 6041590Srgrimes 6051590Srgrimes case 'l': 6061590Srgrimes return strsave(wp->who_tty); 6071590Srgrimes 60882793Sache default: 6091590Srgrimes wbuf = xmalloc(3); 61077274Smikeh wbuf[0] = '%'; 6111590Srgrimes wbuf[1] = (char) c; 61277274Smikeh wbuf[2] = '\0'; 6131590Srgrimes return wbuf; 6141590Srgrimes } 6151590Srgrimes return NULL; 6161590Srgrimes} 6171590Srgrimes 6181590Srgrimesvoid 6191590Srgrimes/*ARGSUSED*/ 6201590Srgrimesdolog(Char **v, struct command *c) 6211590Srgrimes{ 6221590Srgrimes struct who *wp; 6231590Srgrimes struct varent *vp; 62474769Smikeh 6251590Srgrimes USE(v); 6261590Srgrimes USE(c); 62774769Smikeh vp = adrof(STRwatch); /* lint insists vp isn't used unless we */ 6281590Srgrimes if (vp == NULL) /* unless we assign it outside the if */ 6291590Srgrimes stderror(ERR_NOWATCH); 63077274Smikeh resetwatch(); 6311590Srgrimes wp = whohead.who_next; 6321590Srgrimes while (wp->who_next != NULL) { 6331590Srgrimes wp->who_name[0] = '\0'; 63477274Smikeh wp = wp->who_next; 63577274Smikeh } 63677274Smikeh} 6371590Srgrimes 63877274Smikeh# ifdef UTHOSTLEN 6391590Srgrimessize_t 6401590Srgrimesutmphostsize(void) 64129574Sphk{ 6421590Srgrimes return UTHOSTLEN; 64377274Smikeh} 6441590Srgrimes 64529574Sphkchar * 6461590Srgrimesutmphost(void) 6471590Srgrimes{ 64877274Smikeh char *tty = short2str(varval(STRtty)); 64977274Smikeh struct who *wp; 6501590Srgrimes char *host = NULL; 65188227Sache 6521590Srgrimes watch_login(1); 6531590Srgrimes 6541590Srgrimes for (wp = whohead.who_next; wp->who_next != NULL; wp = wp->who_next) { 6551590Srgrimes if (strcmp(tty, wp->who_tty) == 0) 6561590Srgrimes host = wp->who_host; 6571590Srgrimes wp->who_name[0] = '\0'; 65874769Smikeh } 65974769Smikeh resetwatch(); 66077274Smikeh return host; 6611590Srgrimes} 6621590Srgrimes# endif /* UTHOSTLEN */ 6631590Srgrimes 66477274Smikeh#ifdef WINNT_NATIVE 6651590Srgrimesvoid 6661590Srgrimesadd_to_who_list(char *name, char *mach_nm) 6671590Srgrimes{ 6681590Srgrimes 6691590Srgrimes struct who *wp, *wpnew; 6701590Srgrimes int comp = -1; 6711590Srgrimes 6721590Srgrimes wp = whohead.who_next; 6731590Srgrimes while (wp->who_next && (comp = strncmp(wp->who_tty,mach_nm,UTLINLEN)) < 0) 6741590Srgrimes wp = wp->who_next;/* find that tty! */ 6751590Srgrimes 67688150Smikeh if (wp->who_next && comp == 0) { /* found the tty... */ 6771590Srgrimes 67888150Smikeh if (*name == '\0') { 67988150Smikeh wp->who_time = 0; 68088150Smikeh wp->who_status = OFFLINE; 68177274Smikeh } 68288150Smikeh else if (strncmp(name, wp->who_name, UTNAMLEN) == 0) { 68377274Smikeh /* someone is logged in */ 6841590Srgrimes wp->who_time = 0; 6851590Srgrimes wp->who_status = 0; /* same guy */ 6861590Srgrimes } 6871590Srgrimes else { 6881590Srgrimes (void) strncpy(wp->who_new, name, UTNAMLEN); 6891590Srgrimes wp->who_time = 0; 6901590Srgrimes if (wp->who_name[0] == '\0') 6911590Srgrimes wp->who_status = ONLINE; 6921590Srgrimes else 6931590Srgrimes wp->who_status = CHANGED; 6941590Srgrimes } 6951590Srgrimes } 6961590Srgrimes else { 6971590Srgrimes wpnew = xcalloc(1, sizeof *wpnew); 6981590Srgrimes (void) strncpy(wpnew->who_tty, mach_nm, UTLINLEN); 6991590Srgrimes wpnew->who_time = 0; 7001590Srgrimes if (*name == '\0') 7011590Srgrimes wpnew->who_status = OFFLINE; 7021590Srgrimes else { 7031590Srgrimes (void) strncpy(wpnew->who_new, name, UTNAMLEN); 70477274Smikeh wpnew->who_status = ONLINE; 70577274Smikeh } 70677274Smikeh#ifdef WHODEBUG 7071590Srgrimes debugwholist(wpnew, wp); 7081590Srgrimes#endif /* WHODEBUG */ 7091590Srgrimes 7101590Srgrimes wpnew->who_next = wp; /* link in a new 'who' */ 7111590Srgrimes wpnew->who_prev = wp->who_prev; 7121590Srgrimes wpnew->who_prev->who_next = wpnew; 7131590Srgrimes wp->who_prev = wpnew; /* linked in now */ 71477274Smikeh } 7151590Srgrimes} 7161590Srgrimes#endif /* WINNT_NATIVE */ 7171590Srgrimes#endif /* HAVENOUTMP */ 7181590Srgrimes