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