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 35RCSID("$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 */ 110struct 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 139struct 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 152static struct who whohead, whotail; 153static time_t watch_period = 0; 154static time_t stlast = 0; 155#ifdef WHODEBUG 156static void debugwholist (struct who *, struct who *); 157#endif 158static 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 */ 174void 175initwatch(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 185void 186resetwatch(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 */ 196void 197watch_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 475static void 476debugwholist(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 509static void 510print_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 532char * 533who_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 618void 619/*ARGSUSED*/ 620dolog(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 639size_t 640utmphostsize(void) 641{ 642 return UTHOSTLEN; 643} 644 645char * 646utmphost(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 665void 666add_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