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 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 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 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