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