tc.who.c revision 316958
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 35RCSID("$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 */ 112struct 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 141struct 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 154static struct who whohead, whotail; 155static time_t watch_period = 0; 156static time_t stlast = 0; 157#ifdef WHODEBUG 158static void debugwholist (struct who *, struct who *); 159#endif 160static 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 */ 176void 177initwatch(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 187void 188resetwatch(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 */ 198void 199watch_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 477static void 478debugwholist(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 511static void 512print_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 534char * 535who_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 620void 621/*ARGSUSED*/ 622dolog(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 641size_t 642utmphostsize(void) 643{ 644 return UTHOSTLEN; 645} 646 647char * 648utmphost(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 667void 668add_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