source: trunk/third/tcsh/tc.who.c @ 12039

Revision 12039, 16.3 KB checked in by danw, 26 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r12038, which included commits to RCS files with non-trunk default branches.
Line 
1/* $Header: /afs/dev.mit.edu/source/repository/third/tcsh/tc.who.c,v 1.1.1.2 1998-10-03 21:10:17 danw Exp $ */
2/*
3 * tc.who.c: Watch logins and logouts...
4 */
5/*-
6 * Copyright (c) 1980, 1991 The Regents of the University of California.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 *    must display the following acknowledgement:
19 *      This product includes software developed by the University of
20 *      California, Berkeley and its contributors.
21 * 4. Neither the name of the University nor the names of its contributors
22 *    may be used to endorse or promote products derived from this software
23 *    without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 */
37#include "sh.h"
38
39RCSID("$Id: tc.who.c,v 1.1.1.2 1998-10-03 21:10:17 danw Exp $")
40
41#include "tc.h"
42
43#ifndef HAVENOUTMP
44/*
45 * kfk 26 Jan 1984 - for login watch functions.
46 */
47#include <ctype.h>
48
49#ifdef HAVEUTMPX
50# include <utmpx.h>
51/* I just redefine a few words here.  Changing every occurrence below
52 * seems like too much of work.  All UTMP functions have equivalent
53 * UTMPX counterparts, so they can be added all here when needed.
54 * Kimmo Suominen, Oct 14 1991
55 */
56# ifndef _PATH_UTMP
57#  define _PATH_UTMP UTMPX_FILE
58# endif /* _PATH_UTMP */
59# define utmp utmpx
60# define ut_time ut_xtime
61#else /* !HAVEUTMPX */
62# ifndef WINNT
63#  include <utmp.h>
64# endif /* WINNT */
65#endif /* HAVEUTMPX */
66
67#ifndef BROKEN_CC
68# define UTNAMLEN       sizeof(((struct utmp *) 0)->ut_name)
69# define UTLINLEN       sizeof(((struct utmp *) 0)->ut_line)
70# ifdef UTHOST
71#  ifdef _SEQUENT_
72#   define UTHOSTLEN    100
73#  else
74#   define UTHOSTLEN    sizeof(((struct utmp *) 0)->ut_host)
75#  endif
76# endif /* UTHOST */
77#else
78/* give poor cc a little help if it needs it */
79struct utmp __ut;
80
81# define UTNAMLEN       sizeof(__ut.ut_name)
82# define UTLINLEN       sizeof(__ut.ut_line)
83# ifdef UTHOST
84#  ifdef _SEQUENT_
85#   define UTHOSTLEN    100
86#  else
87#   define UTHOSTLEN    sizeof(__ut.ut_host)
88#  endif
89# endif /* UTHOST */
90#endif /* BROKEN_CC */
91
92#ifndef _PATH_UTMP
93# ifdef UTMP_FILE
94#  define _PATH_UTMP UTMP_FILE
95# else
96#  define _PATH_UTMP "/etc/utmp"
97# endif /* UTMP_FILE */
98#endif /* _PATH_UTMP */
99
100
101struct who {
102    struct who *who_next;
103    struct who *who_prev;
104    char    who_name[UTNAMLEN + 1];
105    char    who_new[UTNAMLEN + 1];
106    char    who_tty[UTLINLEN + 1];
107#ifdef UTHOST
108    char    who_host[UTHOSTLEN + 1];
109#endif /* UTHOST */
110    time_t  who_time;
111    int     who_status;
112};
113
114static struct who whohead, whotail;
115static time_t watch_period = 0;
116static time_t stlast = 0;
117#ifdef WHODEBUG
118static  void    debugwholist    __P((struct who *, struct who *));
119#endif
120static  void    print_who       __P((struct who *));
121
122
123#define ONLINE          01
124#define OFFLINE         02
125#define CHANGED         04
126#define STMASK          07
127#define ANNOUNCE        010
128
129/*
130 * Karl Kleinpaste, 26 Jan 1984.
131 * Initialize the dummy tty list for login watch.
132 * This dummy list eliminates boundary conditions
133 * when doing pointer-chase searches.
134 */
135void
136initwatch()
137{
138    whohead.who_next = &whotail;
139    whotail.who_prev = &whohead;
140    stlast = 1;
141#ifdef WHODEBUG
142    debugwholist(NULL, NULL);
143#endif /* WHODEBUG */
144}
145
146void
147resetwatch()
148{
149    watch_period = 0;
150    stlast = 0;
151}
152
153/*
154 * Karl Kleinpaste, 26 Jan 1984.
155 * Watch /etc/utmp for login/logout changes.
156 */
157void
158watch_login(force)
159    int force;
160{
161    int     utmpfd, comp = -1, alldone;
162    int     firsttime = stlast == 1;
163#ifdef BSDSIGS
164    sigmask_t omask;
165#endif                          /* BSDSIGS */
166    struct utmp utmp;
167    struct who *wp, *wpnew;
168    struct varent *v;
169    Char  **vp = NULL;
170    time_t  t, interval = MAILINTVL;
171    struct stat sta;
172#if defined(UTHOST) && defined(_SEQUENT_)
173    char   *host, *ut_find_host();
174#endif
175#ifdef WINNT
176    static int ncbs_posted = 0;
177    USE(utmp);
178    USE(utmpfd);
179    USE(sta);
180    USE(wpnew);
181#endif /* WINNT */
182
183    /* stop SIGINT, lest our login list get trashed. */
184#ifdef BSDSIGS
185    omask = sigblock(sigmask(SIGINT));
186#else
187    (void) sighold(SIGINT);
188#endif
189
190    v = adrof(STRwatch);
191    if (v == NULL && !force) {
192#ifdef BSDSIGS
193        (void) sigsetmask(omask);
194#else
195        (void) sigrelse(SIGINT);
196#endif
197        return;                 /* no names to watch */
198    }
199    if (!force) {
200        trim(vp = v->vec);
201        if (blklen(vp) % 2)             /* odd # args: 1st == # minutes. */
202            interval = (number(*vp)) ? (getn(*vp++) * 60) : MAILINTVL;
203    }
204    else
205        interval = 0;
206       
207    (void) time(&t);
208#ifdef WINNT
209        /*
210         * Since NCB_ASTATs take time, start em async at least 90 secs
211         * before we are due -amol 6/5/97
212         */
213        if (!ncbs_posted) {
214            unsigned long tdiff = t - watch_period;
215            if (!watch_period || ((tdiff  > 0) && (tdiff > (interval - 90)))) {
216                start_ncbs(vp);
217                ncbs_posted = 1;
218            }
219        }
220#endif /* WINNT */
221    if (t - watch_period < interval) {
222#ifdef BSDSIGS
223        (void) sigsetmask(omask);
224#else
225        (void) sigrelse(SIGINT);
226#endif
227        return;                 /* not long enough yet... */
228    }
229    watch_period = t;
230#ifdef WINNT
231    ncbs_posted = 0;
232#else /* !WINNT */
233
234    /*
235     * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de>
236     * Don't open utmp all the time, stat it first...
237     */
238    if (stat(_PATH_UTMP, &sta)) {
239        xprintf(CGETS(26, 1, "cannot stat %s.  Please \"unset watch\".\n"),
240                _PATH_UTMP);
241# ifdef BSDSIGS
242        (void) sigsetmask(omask);
243# else
244        (void) sigrelse(SIGINT);
245# endif
246        return;
247    }
248    if (stlast == sta.st_mtime) {
249# ifdef BSDSIGS
250        (void) sigsetmask(omask);
251# else
252        (void) sigrelse(SIGINT);
253# endif
254        return;
255    }
256    stlast = sta.st_mtime;
257    if ((utmpfd = open(_PATH_UTMP, O_RDONLY)) < 0) {
258        xprintf(CGETS(26, 2, "%s cannot be opened.  Please \"unset watch\".\n"),
259                _PATH_UTMP);
260# ifdef BSDSIGS
261        (void) sigsetmask(omask);
262# else
263        (void) sigrelse(SIGINT);
264# endif
265        return;
266    }
267
268    /*
269     * xterm clears the entire utmp entry - mark everyone on the status list
270     * OFFLINE or we won't notice X "logouts"
271     */
272    for (wp = whohead.who_next; wp->who_next != NULL; wp = wp->who_next) {
273        wp->who_status = OFFLINE;
274        wp->who_time = 0;
275    }
276
277    /*
278     * Read in the utmp file, sort the entries, and update existing entries or
279     * add new entries to the status list.
280     */
281    while (read(utmpfd, (char *) &utmp, sizeof utmp) == sizeof utmp) {
282
283# ifdef DEAD_PROCESS
284#  ifndef IRIS4D
285        if (utmp.ut_type != USER_PROCESS)
286            continue;
287#  else
288        /* Why is that? Cause the utmp file is always corrupted??? */
289        if (utmp.ut_type != USER_PROCESS && utmp.ut_type != DEAD_PROCESS)
290            continue;
291#  endif /* IRIS4D */
292# endif /* DEAD_PROCESS */
293
294        if (utmp.ut_name[0] == '\0' && utmp.ut_line[0] == '\0')
295            continue;   /* completely void entry */
296# ifdef DEAD_PROCESS
297        if (utmp.ut_type == DEAD_PROCESS && utmp.ut_line[0] == '\0')
298            continue;
299# endif /* DEAD_PROCESS */
300        wp = whohead.who_next;
301        while (wp->who_next && (comp = strncmp(wp->who_tty, utmp.ut_line, UTLINLEN)) < 0)
302            wp = wp->who_next;/* find that tty! */
303
304        if (wp->who_next && comp == 0) {        /* found the tty... */
305# ifdef DEAD_PROCESS
306            if (utmp.ut_type == DEAD_PROCESS) {
307                wp->who_time = utmp.ut_time;
308                wp->who_status = OFFLINE;
309            }
310            else
311# endif /* DEAD_PROCESS */
312            if (utmp.ut_name[0] == '\0') {
313                wp->who_time = utmp.ut_time;
314                wp->who_status = OFFLINE;
315            }
316            else if (strncmp(utmp.ut_name, wp->who_name, UTNAMLEN) == 0) {
317                /* someone is logged in */
318                wp->who_time = utmp.ut_time;
319                wp->who_status = 0;     /* same guy */
320            }
321            else {
322                (void) strncpy(wp->who_new, utmp.ut_name, UTNAMLEN);
323# ifdef UTHOST
324#  ifdef _SEQUENT_
325                host = ut_find_host(wp->who_tty);
326                if (host)
327                    (void) strncpy(wp->who_host, host, UTHOSTLEN);
328                else
329                    wp->who_host[0] = 0;
330#  else
331                (void) strncpy(wp->who_host, utmp.ut_host, UTHOSTLEN);
332#  endif
333# endif /* UTHOST */
334                wp->who_time = utmp.ut_time;
335                if (wp->who_name[0] == '\0')
336                    wp->who_status = ONLINE;
337                else
338                    wp->who_status = CHANGED;
339            }
340        }
341        else {          /* new tty in utmp */
342            wpnew = (struct who *) xcalloc(1, sizeof *wpnew);
343            (void) strncpy(wpnew->who_tty, utmp.ut_line, UTLINLEN);
344# ifdef UTHOST
345#  ifdef _SEQUENT_
346            host = ut_find_host(wpnew->who_tty);
347            if (host)
348                (void) strncpy(wpnew->who_host, host, UTHOSTLEN);
349            else
350                wpnew->who_host[0] = 0;
351#  else
352            (void) strncpy(wpnew->who_host, utmp.ut_host, UTHOSTLEN);
353#  endif
354# endif /* UTHOST */
355            wpnew->who_time = utmp.ut_time;
356# ifdef DEAD_PROCESS
357            if (utmp.ut_type == DEAD_PROCESS)
358                wpnew->who_status = OFFLINE;
359            else
360# endif /* DEAD_PROCESS */
361            if (utmp.ut_name[0] == '\0')
362                wpnew->who_status = OFFLINE;
363            else {
364                (void) strncpy(wpnew->who_new, utmp.ut_name, UTNAMLEN);
365                wpnew->who_status = ONLINE;
366            }
367# ifdef WHODEBUG
368            debugwholist(wpnew, wp);
369# endif /* WHODEBUG */
370
371            wpnew->who_next = wp;       /* link in a new 'who' */
372            wpnew->who_prev = wp->who_prev;
373            wpnew->who_prev->who_next = wpnew;
374            wp->who_prev = wpnew;       /* linked in now */
375        }
376    }
377    (void) close(utmpfd);
378# if defined(UTHOST) && defined(_SEQUENT_)
379    endutent();
380# endif
381#endif /* !WINNT */
382
383    if (force || vp == NULL)
384        return;
385
386    /*
387     * The state of all logins is now known, so we can search the user's list
388     * of watchables to print the interesting ones.
389     */
390    for (alldone = 0; !alldone && *vp != NULL && **vp != '\0' &&
391         *(vp + 1) != NULL && **(vp + 1) != '\0';
392         vp += 2) {             /* args used in pairs... */
393
394        if (eq(*vp, STRany) && eq(*(vp + 1), STRany))
395            alldone = 1;
396
397        for (wp = whohead.who_next; wp->who_next != NULL; wp = wp->who_next) {
398            if (wp->who_status & ANNOUNCE ||
399                (!eq(STRany, vp[0]) &&
400                 !Gmatch(str2short(wp->who_name), vp[0]) &&
401                 !Gmatch(str2short(wp->who_new),  vp[0])) ||
402                (!Gmatch(str2short(wp->who_tty),  vp[1]) &&
403                 !eq(STRany, vp[1])))
404                continue;       /* entry doesn't qualify */
405            /* already printed or not right one to print */
406
407
408            if (wp->who_time == 0)/* utmp entry was cleared */
409                wp->who_time = watch_period;
410
411            if ((wp->who_status & OFFLINE) &&
412                (wp->who_name[0] != '\0')) {
413                if (!firsttime)
414                    print_who(wp);
415                wp->who_name[0] = '\0';
416                wp->who_status |= ANNOUNCE;
417                continue;
418            }
419            if (wp->who_status & ONLINE) {
420                if (!firsttime)
421                    print_who(wp);
422                (void) strcpy(wp->who_name, wp->who_new);
423                wp->who_status |= ANNOUNCE;
424                continue;
425            }
426            if (wp->who_status & CHANGED) {
427                if (!firsttime)
428                    print_who(wp);
429                (void) strcpy(wp->who_name, wp->who_new);
430                wp->who_status |= ANNOUNCE;
431                continue;
432            }
433        }
434    }
435#ifdef BSDSIGS
436    (void) sigsetmask(omask);
437#else
438    (void) sigrelse(SIGINT);
439#endif
440}
441
442#ifdef WHODEBUG
443static void
444debugwholist(new, wp)
445    register struct who *new, *wp;
446{
447    register struct who *a;
448
449    a = whohead.who_next;
450    while (a->who_next != NULL) {
451        xprintf("%s/%s -> ", a->who_name, a->who_tty);
452        a = a->who_next;
453    }
454    xprintf("TAIL\n");
455    if (a != &whotail) {
456        xprintf(CGETS(26, 3, "BUG! last element is not whotail!\n"));
457        abort();
458    }
459    a = whotail.who_prev;
460    xprintf(CGETS(26, 4, "backward: "));
461    while (a->who_prev != NULL) {
462        xprintf("%s/%s -> ", a->who_name, a->who_tty);
463        a = a->who_prev;
464    }
465    xprintf("HEAD\n");
466    if (a != &whohead) {
467        xprintf(CGETS(26, 5, "BUG! first element is not whohead!\n"));
468        abort();
469    }
470    if (new)
471        xprintf(CGETS(26, 6, "new: %s/%s\n"), new->who_name, new->who_tty);
472    if (wp)
473        xprintf("wp: %s/%s\n", wp->who_name, wp->who_tty);
474}
475#endif /* WHODEBUG */
476
477
478static void
479print_who(wp)
480    struct who *wp;
481{
482#ifdef UTHOST
483    Char   *cp = str2short(CGETS(26, 7, "%n has %a %l from %m."));
484#else
485    Char   *cp = str2short(CGETS(26, 8, "%n has %a %l."));
486#endif /* UTHOST */
487    struct varent *vp = adrof(STRwho);
488    Char buf[BUFSIZE];
489
490    if (vp && vp->vec[0])
491        cp = vp->vec[0];
492
493    tprintf(FMT_WHO, buf, cp, BUFSIZE, NULL, wp->who_time, (ptr_t) wp);
494    for (cp = buf; *cp;)
495        xputchar(*cp++);
496    xputchar('\n');
497} /* end print_who */
498
499
500const char *
501who_info(ptr, c, wbuf, wbufsiz)
502    ptr_t ptr;
503    int c;
504    char *wbuf;
505    size_t wbufsiz;
506{
507    struct who *wp = (struct who *) ptr;
508#ifdef UTHOST
509    char *wb = wbuf;
510    int flg;
511    char *pb;
512#endif /* UTHOST */
513
514    switch (c) {
515    case 'n':           /* user name */
516        switch (wp->who_status & STMASK) {
517        case ONLINE:
518        case CHANGED:
519            return wp->who_new;
520        case OFFLINE:
521            return wp->who_name;
522        default:
523            break;
524        }
525        break;
526
527    case 'a':
528        switch (wp->who_status & STMASK) {
529        case ONLINE:
530            return CGETS(26, 9, "logged on");
531        case OFFLINE:
532            return CGETS(26, 10, "logged off");
533        case CHANGED:
534            xsnprintf(wbuf, wbufsiz, CGETS(26, 11, "replaced %s on"),
535                      wp->who_name);
536            return wbuf;
537        default:
538            break;
539        }
540        break;
541
542#ifdef UTHOST
543    case 'm':
544        if (wp->who_host[0] == '\0')
545            return CGETS(26, 12, "local");
546        else {
547            /* the ':' stuff is for <host>:<display>.<screen> */
548            for (pb = wp->who_host, flg = Isdigit(*pb) ? '\0' : '.';
549                 *pb != '\0' &&
550                 (*pb != flg || ((pb = strchr(pb, ':')) != 0));
551                 pb++) {
552                if (*pb == ':')
553                    flg = '\0';
554                *wb++ = Isupper(*pb) ? Tolower(*pb) : *pb;
555            }
556            *wb = '\0';
557            return wbuf;
558        }
559
560    case 'M':
561        if (wp->who_host[0] == '\0')
562            return CGETS(26, 12, "local");
563        else {
564            for (pb = wp->who_host; *pb != '\0'; pb++)
565                *wb++ = Isupper(*pb) ? Tolower(*pb) : *pb;
566            *wb = '\0';
567            return wbuf;
568        }
569#endif /* UTHOST */
570
571    case 'l':
572        return wp->who_tty;
573
574    default:
575        wbuf[0] = '%';
576        wbuf[1] = (char) c;
577        wbuf[2] = '\0';
578        return wbuf;
579    }
580    return NULL;
581}
582
583void
584/*ARGSUSED*/
585dolog(v, c)
586Char **v;
587struct command *c;
588{
589    struct who *wp;
590    struct varent *vp;
591
592    USE(v);
593    USE(c);
594    vp = adrof(STRwatch);       /* lint insists vp isn't used unless we */
595    if (vp == NULL)             /* unless we assign it outside the if */
596        stderror(ERR_NOWATCH);
597    resetwatch();
598    wp = whohead.who_next;
599    while (wp->who_next != NULL) {
600        wp->who_name[0] = '\0';
601        wp = wp->who_next;
602    }
603}
604
605# ifdef UTHOST
606char *
607utmphost()
608{
609    char *tty = short2str(varval(STRtty));
610    struct who *wp;
611    char *host = NULL;
612
613    watch_login(1);
614   
615    for (wp = whohead.who_next; wp->who_next != NULL; wp = wp->who_next) {
616        if (strcmp(tty, wp->who_tty) == 0)
617            host = wp->who_host;
618        wp->who_name[0] = '\0';
619    }
620    resetwatch();
621    return host;
622}
623# endif /* UTHOST */
624
625#ifdef WINNT
626void add_to_who_list(name, mach_nm)
627    char *name;
628    char *mach_nm;
629{
630
631    struct who *wp, *wpnew;
632    int comp = -1;
633
634    wp = whohead.who_next;
635    while (wp->who_next && (comp = strncmp(wp->who_tty,mach_nm,UTLINLEN)) < 0)
636        wp = wp->who_next;/* find that tty! */
637
638    if (wp->who_next && comp == 0) {    /* found the tty... */
639
640        if (*name == '\0') {
641            wp->who_time = 0;
642            wp->who_status = OFFLINE;
643        }
644        else if (strncmp(name, wp->who_name, UTNAMLEN) == 0) {
645            /* someone is logged in */
646            wp->who_time = 0;
647            wp->who_status = 0; /* same guy */
648        }
649        else {
650            (void) strncpy(wp->who_new, name, UTNAMLEN);
651            wp->who_time = 0;
652            if (wp->who_name[0] == '\0')
653                wp->who_status = ONLINE;
654            else
655                wp->who_status = CHANGED;
656        }
657    }
658    else {
659        wpnew = (struct who *) xcalloc(1, sizeof *wpnew);
660        (void) strncpy(wpnew->who_tty, mach_nm, UTLINLEN);
661        wpnew->who_time = 0;
662        if (*name == '\0')
663            wpnew->who_status = OFFLINE;
664        else {
665            (void) strncpy(wpnew->who_new, name, UTNAMLEN);
666            wpnew->who_status = ONLINE;
667        }
668#ifdef WHODEBUG
669        debugwholist(wpnew, wp);
670#endif /* WHODEBUG */
671
672        wpnew->who_next = wp;   /* link in a new 'who' */
673        wpnew->who_prev = wp->who_prev;
674        wpnew->who_prev->who_next = wpnew;
675        wp->who_prev = wpnew;   /* linked in now */
676    }
677}
678#endif /* WINNT */
679#endif /* HAVENOUTMP */
Note: See TracBrowser for help on using the repository browser.