1 #ifndef lint 2 static char sccsid[] = "@(#)finger.c 4.9 (Berkeley) 04/09/85"; 3 #endif 4 5 /* 6 * This is a finger program. It prints out useful information about users 7 * by digging it up from various system files. It is not very portable 8 * because the most useful parts of the information (the full user name, 9 * office, and phone numbers) are all stored in the VAX-unused gecos field 10 * of /etc/passwd, which, unfortunately, other UNIXes use for other things. 11 * 12 * There are three output formats, all of which give login name, teletype 13 * line number, and login time. The short output format is reminiscent 14 * of finger on ITS, and gives one line of information per user containing 15 * in addition to the minimum basic requirements (MBR), the full name of 16 * the user, his idle time and office location and phone number. The 17 * quick style output is UNIX who-like, giving only name, teletype and 18 * login time. Finally, the long style output give the same information 19 * as the short (in more legible format), the home directory and shell 20 * of the user, and, if it exits, a copy of the file .plan in the users 21 * home directory. Finger may be called with or without a list of people 22 * to finger -- if no list is given, all the people currently logged in 23 * are fingered. 24 * 25 * The program is validly called by one of the following: 26 * 27 * finger {short form list of users} 28 * finger -l {long form list of users} 29 * finger -b {briefer long form list of users} 30 * finger -q {quick list of users} 31 * finger -i {quick list of users with idle times} 32 * finger namelist {long format list of specified users} 33 * finger -s namelist {short format list of specified users} 34 * finger -w namelist {narrow short format list of specified users} 35 * 36 * where 'namelist' is a list of users login names. 37 * The other options can all be given after one '-', or each can have its 38 * own '-'. The -f option disables the printing of headers for short and 39 * quick outputs. The -b option briefens long format outputs. The -p 40 * option turns off plans for long format outputs. 41 */ 42 43 #include <sys/types.h> 44 #include <sys/stat.h> 45 #include <utmp.h> 46 #include <sys/signal.h> 47 #include <pwd.h> 48 #include <stdio.h> 49 #include <lastlog.h> 50 #include <ctype.h> 51 #include <sys/time.h> 52 #include <sys/socket.h> 53 #include <netinet/in.h> 54 #include <netdb.h> 55 56 #define ASTERISK '*' /* ignore this in real name */ 57 #define COMMA ',' /* separator in pw_gecos field */ 58 #define COMMAND '-' /* command line flag char */ 59 #define CORY 'C' /* cory hall office */ 60 #define EVANS 'E' /* evans hall office */ 61 #define SAMENAME '&' /* repeat login name in real name */ 62 #define TALKABLE 0222 /* tty is writable if 222 mode */ 63 64 struct utmp user; 65 #define NMAX sizeof(user.ut_name) 66 #define LMAX sizeof(user.ut_line) 67 #define HMAX sizeof(user.ut_host) 68 69 struct person { /* one for each person fingered */ 70 char *name; /* name */ 71 char tty[LMAX+1]; /* null terminated tty line */ 72 char host[HMAX+1]; /* null terminated remote host name */ 73 long loginat; /* time of (last) login */ 74 long idletime; /* how long idle (if logged in) */ 75 char *realname; /* pointer to full name */ 76 char *office; /* pointer to office name */ 77 char *officephone; /* pointer to office phone no. */ 78 char *homephone; /* pointer to home phone no. */ 79 char *random; /* for any random stuff in pw_gecos */ 80 struct passwd *pwd; /* structure of /etc/passwd stuff */ 81 char loggedin; /* person is logged in */ 82 char writable; /* tty is writable */ 83 char original; /* this is not a duplicate entry */ 84 struct person *link; /* link to next person */ 85 }; 86 87 char LASTLOG[] = "/usr/adm/lastlog"; /* last login info */ 88 char USERLOG[] = "/etc/utmp"; /* who is logged in */ 89 char PLAN[] = "/.plan"; /* what plan file is */ 90 char PROJ[] = "/.project"; /* what project file */ 91 92 int unbrief = 1; /* -b option default */ 93 int header = 1; /* -f option default */ 94 int hack = 1; /* -h option default */ 95 int idle = 0; /* -i option default */ 96 int large = 0; /* -l option default */ 97 int match = 1; /* -m option default */ 98 int plan = 1; /* -p option default */ 99 int unquick = 1; /* -q option default */ 100 int small = 0; /* -s option default */ 101 int wide = 1; /* -w option default */ 102 103 int unshort; 104 int lf; /* LASTLOG file descriptor */ 105 struct person *person1; /* list of people */ 106 long tloc; /* current time */ 107 108 struct passwd *pwdcopy(); 109 char *strcpy(); 110 char *malloc(); 111 char *ctime(); 112 113 main(argc, argv) 114 int argc; 115 register char **argv; 116 { 117 FILE *fp; 118 register char *s; 119 120 /* parse command line for (optional) arguments */ 121 while (*++argv && **argv == COMMAND) 122 for (s = *argv + 1; *s; s++) 123 switch (*s) { 124 case 'b': 125 unbrief = 0; 126 break; 127 case 'f': 128 header = 0; 129 break; 130 case 'h': 131 hack = 0; 132 break; 133 case 'i': 134 idle = 1; 135 unquick = 0; 136 break; 137 case 'l': 138 large = 1; 139 break; 140 case 'm': 141 match = 0; 142 break; 143 case 'p': 144 plan = 0; 145 break; 146 case 'q': 147 unquick = 0; 148 break; 149 case 's': 150 small = 1; 151 break; 152 case 'w': 153 wide = 0; 154 break; 155 default: 156 fprintf(stderr, "Usage: finger [-bfhilmpqsw] [login1 [login2 ...] ]\n"); 157 exit(1); 158 } 159 if (unquick || idle) 160 time(&tloc); 161 /* 162 * *argv == 0 means no names given 163 */ 164 if (*argv == 0) 165 doall(); 166 else 167 donames(argv); 168 print(); 169 exit(0); 170 } 171 172 doall() 173 { 174 register struct person *p; 175 register struct passwd *pw; 176 int uf; 177 char name[NMAX + 1]; 178 179 unshort = large; 180 if ((uf = open(USERLOG, 0)) < 0) { 181 fprintf(stderr, "finger: error opening %s\n", USERLOG); 182 exit(2); 183 } 184 if (unquick) { 185 extern _pw_stayopen; 186 187 setpwent(); 188 _pw_stayopen = 1; 189 fwopen(); 190 } 191 while (read(uf, (char *)&user, sizeof user) == sizeof user) { 192 if (user.ut_name[0] == 0) 193 continue; 194 if (person1 == 0) 195 p = person1 = (struct person *) malloc(sizeof *p); 196 else { 197 p->link = (struct person *) malloc(sizeof *p); 198 p = p->link; 199 } 200 bcopy(user.ut_name, name, NMAX); 201 name[NMAX] = 0; 202 bcopy(user.ut_line, p->tty, LMAX); 203 p->tty[LMAX] = 0; 204 bcopy(user.ut_host, p->host, HMAX); 205 p->host[HMAX] = 0; 206 p->loginat = user.ut_time; 207 p->pwd = 0; 208 p->loggedin = 1; 209 if (unquick && (pw = getpwnam(name))) { 210 p->pwd = pwdcopy(pw); 211 decode(p); 212 p->name = p->pwd->pw_name; 213 } else 214 p->name = strcpy(malloc(strlen(name) + 1), name); 215 } 216 if (unquick) { 217 fwclose(); 218 endpwent(); 219 } 220 close(uf); 221 if (person1 == 0) { 222 printf("No one logged on\n"); 223 exit(0); 224 } 225 p->link = 0; 226 } 227 228 donames(argv) 229 char **argv; 230 { 231 register struct person *p; 232 register struct passwd *pw; 233 int uf; 234 235 /* 236 * get names from command line and check to see if they're 237 * logged in 238 */ 239 unshort = !small; 240 for (; *argv != 0; argv++) { 241 if (netfinger(*argv)) 242 continue; 243 if (person1 == 0) 244 p = person1 = (struct person *) malloc(sizeof *p); 245 else { 246 p->link = (struct person *) malloc(sizeof *p); 247 p = p->link; 248 } 249 p->name = *argv; 250 p->loggedin = 0; 251 p->original = 1; 252 p->pwd = 0; 253 } 254 p->link = 0; 255 /* 256 * if we are doing it, read /etc/passwd for the useful info 257 */ 258 if (unquick) { 259 setpwent(); 260 if (!match) { 261 extern _pw_stayopen; 262 263 _pw_stayopen = 1; 264 for (p = person1; p != 0; p = p->link) 265 if (pw = getpwnam(p->name)) 266 p->pwd = pwdcopy(pw); 267 } else while ((pw = getpwent()) != 0) { 268 for (p = person1; p != 0; p = p->link) { 269 if (!p->original) 270 continue; 271 if (strcmp(p->name, pw->pw_name) != 0 && 272 !matchcmp(pw->pw_gecos, pw->pw_name, p->name)) 273 continue; 274 if (p->pwd == 0) 275 p->pwd = pwdcopy(pw); 276 else { 277 struct person *new; 278 /* 279 * handle multiple login names, insert 280 * new "duplicate" entry behind 281 */ 282 new = (struct person *) 283 malloc(sizeof *new); 284 new->pwd = pwdcopy(pw); 285 new->name = p->name; 286 new->original = 1; 287 new->loggedin = 0; 288 new->link = p->link; 289 p->original = 0; 290 p->link = new; 291 p = new; 292 } 293 } 294 } 295 endpwent(); 296 } 297 /* Now get login information */ 298 if ((uf = open(USERLOG, 0)) < 0) { 299 fprintf(stderr, "finger: error opening %s\n", USERLOG); 300 exit(2); 301 } 302 while (read(uf, (char *)&user, sizeof user) == sizeof user) { 303 if (*user.ut_name == 0) 304 continue; 305 for (p = person1; p != 0; p = p->link) { 306 if (p->loggedin == 2) 307 continue; 308 if (strncmp(p->pwd ? p->pwd->pw_name : p->name, 309 user.ut_name, NMAX) != 0) 310 continue; 311 if (p->loggedin == 0) { 312 bcopy(user.ut_line, p->tty, LMAX); 313 p->tty[LMAX] = 0; 314 bcopy(user.ut_host, p->host, HMAX); 315 p->host[HMAX] = 0; 316 p->loginat = user.ut_time; 317 p->loggedin = 1; 318 } else { /* p->loggedin == 1 */ 319 struct person *new; 320 new = (struct person *) malloc(sizeof *new); 321 new->name = p->name; 322 bcopy(user.ut_line, new->tty, LMAX); 323 new->tty[LMAX] = 0; 324 bcopy(user.ut_host, new->host, HMAX); 325 new->host[HMAX] = 0; 326 new->loginat = user.ut_time; 327 new->pwd = p->pwd; 328 new->loggedin = 1; 329 new->original = 0; 330 new->link = p->link; 331 p->loggedin = 2; 332 p->link = new; 333 p = new; 334 } 335 } 336 } 337 close(uf); 338 if (unquick) { 339 fwopen(); 340 for (p = person1; p != 0; p = p->link) 341 decode(p); 342 fwclose(); 343 } 344 } 345 346 print() 347 { 348 register FILE *fp; 349 register struct person *p; 350 register char *s; 351 register c; 352 353 /* 354 * print out what we got 355 */ 356 if (header) { 357 if (unquick) { 358 if (!unshort) 359 if (wide) 360 printf("Login Name TTY Idle When Office\n"); 361 else 362 printf("Login TTY Idle When Office\n"); 363 } else { 364 printf("Login TTY When"); 365 if (idle) 366 printf(" Idle"); 367 putchar('\n'); 368 } 369 } 370 for (p = person1; p != 0; p = p->link) { 371 if (!unquick) { 372 quickprint(p); 373 continue; 374 } 375 if (!unshort) { 376 shortprint(p); 377 continue; 378 } 379 personprint(p); 380 if (p->pwd != 0) { 381 if (hack) { 382 s = malloc(strlen(p->pwd->pw_dir) + 383 sizeof PROJ); 384 strcpy(s, p->pwd->pw_dir); 385 strcat(s, PROJ); 386 if ((fp = fopen(s, "r")) != 0) { 387 printf("Project: "); 388 while ((c = getc(fp)) != EOF) { 389 if (c == '\n') 390 break; 391 putchar(c); 392 } 393 fclose(fp); 394 putchar('\n'); 395 } 396 free(s); 397 } 398 if (plan) { 399 s = malloc(strlen(p->pwd->pw_dir) + 400 sizeof PLAN); 401 strcpy(s, p->pwd->pw_dir); 402 strcat(s, PLAN); 403 if ((fp = fopen(s, "r")) == 0) 404 printf("No Plan.\n"); 405 else { 406 printf("Plan:\n"); 407 while ((c = getc(fp)) != EOF) 408 putchar(c); 409 fclose(fp); 410 } 411 free(s); 412 } 413 } 414 if (p->link != 0) 415 putchar('\n'); 416 } 417 } 418 419 /* 420 * Duplicate a pwd entry. 421 * Note: Only the useful things (what the program currently uses) are copied. 422 */ 423 struct passwd * 424 pwdcopy(pfrom) 425 register struct passwd *pfrom; 426 { 427 register struct passwd *pto; 428 429 pto = (struct passwd *) malloc(sizeof *pto); 430 #define savestr(s) strcpy(malloc(strlen(s) + 1), s) 431 pto->pw_name = savestr(pfrom->pw_name); 432 pto->pw_uid = pfrom->pw_uid; 433 pto->pw_gecos = savestr(pfrom->pw_gecos); 434 pto->pw_dir = savestr(pfrom->pw_dir); 435 pto->pw_shell = savestr(pfrom->pw_shell); 436 #undef savestr 437 return pto; 438 } 439 440 /* 441 * print out information on quick format giving just name, tty, login time 442 * and idle time if idle is set. 443 */ 444 quickprint(pers) 445 register struct person *pers; 446 { 447 printf("%-*.*s ", NMAX, NMAX, pers->name); 448 if (pers->loggedin) { 449 if (idle) { 450 findidle(pers); 451 printf("%c%-*s %-16.16s", pers->writable ? ' ' : '*', 452 LMAX, pers->tty, ctime(&pers->loginat)); 453 ltimeprint(" ", &pers->idletime, ""); 454 } else 455 printf(" %-*s %-16.16s", LMAX, 456 pers->tty, ctime(&pers->loginat)); 457 putchar('\n'); 458 } else 459 printf(" Not Logged In\n"); 460 } 461 462 /* 463 * print out information in short format, giving login name, full name, 464 * tty, idle time, login time, office location and phone. 465 */ 466 shortprint(pers) 467 register struct person *pers; 468 { 469 char *p; 470 char dialup; 471 472 if (pers->pwd == 0) { 473 printf("%-15s ???\n", pers->name); 474 return; 475 } 476 printf("%-*s", NMAX, pers->pwd->pw_name); 477 dialup = 0; 478 if (wide) { 479 if (pers->realname) 480 printf(" %-20.20s", pers->realname); 481 else 482 printf(" ??? "); 483 } 484 putchar(' '); 485 if (pers->loggedin && !pers->writable) 486 putchar('*'); 487 else 488 putchar(' '); 489 if (*pers->tty) { 490 if (pers->tty[0] == 't' && pers->tty[1] == 't' && 491 pers->tty[2] == 'y') { 492 if (pers->tty[3] == 'd' && pers->loggedin) 493 dialup = 1; 494 printf("%-2.2s ", pers->tty + 3); 495 } else 496 printf("%-2.2s ", pers->tty); 497 } else 498 printf(" "); 499 p = ctime(&pers->loginat); 500 if (pers->loggedin) { 501 stimeprint(&pers->idletime); 502 printf(" %3.3s %-5.5s ", p, p + 11); 503 } else if (pers->loginat == 0) 504 printf(" < . . . . >"); 505 else if (tloc - pers->loginat >= 180 * 24 * 60 * 60) 506 printf(" <%-6.6s, %-4.4s>", p + 4, p + 20); 507 else 508 printf(" <%-12.12s>", p + 4); 509 if (dialup && pers->homephone) 510 printf(" %20s", pers->homephone); 511 else { 512 if (pers->office) 513 printf(" %-11.11s", pers->office); 514 else if (pers->officephone || pers->homephone) 515 printf(" "); 516 if (pers->officephone) 517 printf(" %s", pers->officephone); 518 else if (pers->homephone) 519 printf(" %s", pers->homephone); 520 } 521 putchar('\n'); 522 } 523 524 /* 525 * print out a person in long format giving all possible information. 526 * directory and shell are inhibited if unbrief is clear. 527 */ 528 personprint(pers) 529 register struct person *pers; 530 { 531 if (pers->pwd == 0) { 532 printf("Login name: %-10s\t\t\tIn real life: ???\n", 533 pers->name); 534 return; 535 } 536 printf("Login name: %-10s", pers->pwd->pw_name); 537 if (pers->loggedin && !pers->writable) 538 printf(" (messages off) "); 539 else 540 printf(" "); 541 if (pers->realname) 542 printf("In real life: %s", pers->realname); 543 if (pers->office) { 544 printf("\nOffice: %-.11s", pers->office); 545 if (pers->officephone) { 546 printf(", %s", pers->officephone); 547 if (pers->homephone) 548 printf("\t\tHome phone: %s", pers->homephone); 549 else if (pers->random) 550 printf("\t\t%s", pers->random); 551 } else 552 if (pers->homephone) 553 printf("\t\t\tHome phone: %s", pers->homephone); 554 else if (pers->random) 555 printf("\t\t\t%s", pers->random); 556 } else if (pers->officephone) { 557 printf("\nPhone: %s", pers->officephone); 558 if (pers->homephone) 559 printf(", %s", pers->homephone); 560 if (pers->random) 561 printf(", %s", pers->random); 562 } else if (pers->homephone) { 563 printf("\nPhone: %s", pers->homephone); 564 if (pers->random) 565 printf(", %s", pers->random); 566 } else if (pers->random) 567 printf("\n%s", pers->random); 568 if (unbrief) { 569 printf("\nDirectory: %-25s", pers->pwd->pw_dir); 570 if (*pers->pwd->pw_shell) 571 printf("\tShell: %-s", pers->pwd->pw_shell); 572 } 573 if (pers->loggedin) { 574 register char *ep = ctime(&pers->loginat); 575 if (*pers->host) { 576 printf("\nOn since %15.15s on %s from %s", 577 &ep[4], pers->tty, pers->host); 578 ltimeprint("\n", &pers->idletime, " Idle Time"); 579 } else { 580 printf("\nOn since %15.15s on %-*s", 581 &ep[4], LMAX, pers->tty); 582 ltimeprint("\t", &pers->idletime, " Idle Time"); 583 } 584 } else if (pers->loginat == 0) 585 printf("\nNever logged in."); 586 else if (tloc - pers->loginat > 180 * 24 * 60 * 60) { 587 register char *ep = ctime(&pers->loginat); 588 printf("\nLast login %10.10s, %4.4s on %s", 589 ep, ep+20, pers->tty); 590 if (*pers->host) 591 printf(" from %s", pers->host); 592 } else { 593 register char *ep = ctime(&pers->loginat); 594 printf("\nLast login %16.16s on %s", ep, pers->tty); 595 if (*pers->host) 596 printf(" from %s", pers->host); 597 } 598 putchar('\n'); 599 } 600 601 /* 602 * very hacky section of code to format phone numbers. filled with 603 * magic constants like 4, 7 and 10. 604 */ 605 char * 606 phone(s, len, alldigits) 607 register char *s; 608 int len; 609 char alldigits; 610 { 611 char fonebuf[15]; 612 register char *p = fonebuf; 613 register i; 614 615 if (!alldigits) 616 return (strcpy(malloc(len + 1), s)); 617 switch (len) { 618 case 4: 619 *p++ = ' '; 620 *p++ = 'x'; 621 *p++ = '2'; 622 *p++ = '-'; 623 for (i = 0; i < 4; i++) 624 *p++ = *s++; 625 break; 626 case 7: 627 for (i = 0; i < 3; i++) 628 *p++ = *s++; 629 *p++ = '-'; 630 for (i = 0; i < 4; i++) 631 *p++ = *s++; 632 break; 633 case 10: 634 for (i = 0; i < 3; i++) 635 *p++ = *s++; 636 *p++ = '-'; 637 for (i = 0; i < 3; i++) 638 *p++ = *s++; 639 *p++ = '-'; 640 for (i = 0; i < 4; i++) 641 *p++ = *s++; 642 break; 643 case 0: 644 return 0; 645 default: 646 return (strcpy(malloc(len + 1), s)); 647 } 648 *p++ = 0; 649 return (strcpy(malloc(p - fonebuf), fonebuf)); 650 } 651 652 /* 653 * decode the information in the gecos field of /etc/passwd 654 */ 655 decode(pers) 656 register struct person *pers; 657 { 658 char buffer[256]; 659 register char *bp, *gp, *lp; 660 int alldigits; 661 int hasspace; 662 int len; 663 664 pers->realname = 0; 665 pers->office = 0; 666 pers->officephone = 0; 667 pers->homephone = 0; 668 pers->random = 0; 669 if (pers->pwd == 0) 670 return; 671 gp = pers->pwd->pw_gecos; 672 bp = buffer; 673 if (*gp == ASTERISK) 674 gp++; 675 while (*gp && *gp != COMMA) /* name */ 676 if (*gp == SAMENAME) { 677 lp = pers->pwd->pw_name; 678 if (islower(*lp)) 679 *bp++ = toupper(*lp++); 680 while (*bp++ = *lp++) 681 ; 682 bp--; 683 gp++; 684 } else 685 *bp++ = *gp++; 686 *bp++ = 0; 687 if ((len = bp - buffer) > 1) 688 pers->realname = strcpy(malloc(len), buffer); 689 if (*gp == COMMA) { /* office */ 690 gp++; 691 hasspace = 0; 692 bp = buffer; 693 while (*gp && *gp != COMMA) { 694 *bp = *gp++; 695 if (*bp == ' ') 696 hasspace = 1; 697 /* leave 5 for Cory and Evans expansion */ 698 if (bp < buffer + sizeof buffer - 6) 699 bp++; 700 } 701 *bp = 0; 702 len = bp - buffer; 703 bp--; /* point to last character */ 704 if (hasspace || len == 0) 705 len++; 706 else if (*bp == CORY) { 707 strcpy(bp, " Cory"); 708 len += 5; 709 } else if (*bp == EVANS) { 710 strcpy(bp, " Evans"); 711 len += 6; 712 } else 713 len++; 714 if (len > 1) 715 pers->office = strcpy(malloc(len), buffer); 716 } 717 if (*gp == COMMA) { /* office phone */ 718 gp++; 719 bp = buffer; 720 alldigits = 1; 721 while (*gp && *gp != COMMA) { 722 *bp = *gp++; 723 if (!isdigit(*bp)) 724 alldigits = 0; 725 if (bp < buffer + sizeof buffer - 1) 726 bp++; 727 } 728 *bp = 0; 729 pers->officephone = phone(buffer, bp - buffer, alldigits); 730 } 731 if (*gp == COMMA) { /* home phone */ 732 gp++; 733 bp = buffer; 734 alldigits = 1; 735 while (*gp && *gp != COMMA) { 736 *bp = *gp++; 737 if (!isdigit(*bp)) 738 alldigits = 0; 739 if (bp < buffer + sizeof buffer - 1) 740 bp++; 741 } 742 *bp = 0; 743 pers->homephone = phone(buffer, bp - buffer, alldigits); 744 } 745 if (pers->loggedin) 746 findidle(pers); 747 else 748 findwhen(pers); 749 } 750 751 /* 752 * find the last log in of a user by checking the LASTLOG file. 753 * the entry is indexed by the uid, so this can only be done if 754 * the uid is known (which it isn't in quick mode) 755 */ 756 757 fwopen() 758 { 759 if ((lf = open(LASTLOG, 0)) < 0) 760 fprintf(stderr, "finger: %s open error\n", LASTLOG); 761 } 762 763 findwhen(pers) 764 register struct person *pers; 765 { 766 struct lastlog ll; 767 int i; 768 769 if (lf >= 0) { 770 lseek(lf, (long)pers->pwd->pw_uid * sizeof ll, 0); 771 if ((i = read(lf, (char *)&ll, sizeof ll)) == sizeof ll) { 772 bcopy(ll.ll_line, pers->tty, LMAX); 773 pers->tty[LMAX] = 0; 774 bcopy(ll.ll_host, pers->host, HMAX); 775 pers->host[HMAX] = 0; 776 pers->loginat = ll.ll_time; 777 } else { 778 if (i != 0) 779 fprintf(stderr, "finger: %s read error\n", 780 LASTLOG); 781 pers->tty[0] = 0; 782 pers->host[0] = 0; 783 pers->loginat = 0L; 784 } 785 } else { 786 pers->tty[0] = 0; 787 pers->host[0] = 0; 788 pers->loginat = 0L; 789 } 790 } 791 792 fwclose() 793 { 794 if (lf >= 0) 795 close(lf); 796 } 797 798 /* 799 * find the idle time of a user by doing a stat on /dev/tty??, 800 * where tty?? has been gotten from USERLOG, supposedly. 801 */ 802 findidle(pers) 803 register struct person *pers; 804 { 805 struct stat ttystatus; 806 static char buffer[20] = "/dev/"; 807 long t; 808 #define TTYLEN 5 809 810 strcpy(buffer + TTYLEN, pers->tty); 811 buffer[TTYLEN+LMAX] = 0; 812 if (stat(buffer, &ttystatus) < 0) { 813 fprintf(stderr, "finger: Can't stat %s\n", buffer); 814 exit(4); 815 } 816 time(&t); 817 if (t < ttystatus.st_atime) 818 pers->idletime = 0L; 819 else 820 pers->idletime = t - ttystatus.st_atime; 821 pers->writable = (ttystatus.st_mode & TALKABLE) == TALKABLE; 822 } 823 824 /* 825 * print idle time in short format; this program always prints 4 characters; 826 * if the idle time is zero, it prints 4 blanks. 827 */ 828 stimeprint(dt) 829 long *dt; 830 { 831 register struct tm *delta; 832 833 delta = gmtime(dt); 834 if (delta->tm_yday == 0) 835 if (delta->tm_hour == 0) 836 if (delta->tm_min == 0) 837 printf(" "); 838 else 839 printf(" %2d", delta->tm_min); 840 else 841 if (delta->tm_hour >= 10) 842 printf("%3d:", delta->tm_hour); 843 else 844 printf("%1d:%02d", 845 delta->tm_hour, delta->tm_min); 846 else 847 printf("%3dd", delta->tm_yday); 848 } 849 850 /* 851 * print idle time in long format with care being taken not to pluralize 852 * 1 minutes or 1 hours or 1 days. 853 * print "prefix" first. 854 */ 855 ltimeprint(before, dt, after) 856 long *dt; 857 char *before, *after; 858 { 859 register struct tm *delta; 860 861 delta = gmtime(dt); 862 if (delta->tm_yday == 0 && delta->tm_hour == 0 && delta->tm_min == 0 && 863 delta->tm_sec <= 10) 864 return (0); 865 printf("%s", before); 866 if (delta->tm_yday >= 10) 867 printf("%d days", delta->tm_yday); 868 else if (delta->tm_yday > 0) 869 printf("%d day%s %d hour%s", 870 delta->tm_yday, delta->tm_yday == 1 ? "" : "s", 871 delta->tm_hour, delta->tm_hour == 1 ? "" : "s"); 872 else 873 if (delta->tm_hour >= 10) 874 printf("%d hours", delta->tm_hour); 875 else if (delta->tm_hour > 0) 876 printf("%d hour%s %d minute%s", 877 delta->tm_hour, delta->tm_hour == 1 ? "" : "s", 878 delta->tm_min, delta->tm_min == 1 ? "" : "s"); 879 else 880 if (delta->tm_min >= 10) 881 printf("%2d minutes", delta->tm_min); 882 else if (delta->tm_min == 0) 883 printf("%2d seconds", delta->tm_sec); 884 else 885 printf("%d minute%s %d second%s", 886 delta->tm_min, 887 delta->tm_min == 1 ? "" : "s", 888 delta->tm_sec, 889 delta->tm_sec == 1 ? "" : "s"); 890 printf("%s", after); 891 } 892 893 matchcmp(gname, login, given) 894 register char *gname; 895 char *login; 896 char *given; 897 { 898 char buffer[100]; 899 register char *bp, *lp; 900 register c; 901 902 if (*gname == ASTERISK) 903 gname++; 904 lp = 0; 905 bp = buffer; 906 for (;;) 907 switch (c = *gname++) { 908 case SAMENAME: 909 for (lp = login; bp < buffer + sizeof buffer 910 && (*bp++ = *lp++);) 911 ; 912 bp--; 913 break; 914 case ' ': 915 case COMMA: 916 case '\0': 917 *bp = 0; 918 if (namecmp(buffer, given)) 919 return (1); 920 if (c == COMMA || c == 0) 921 return (0); 922 bp = buffer; 923 break; 924 default: 925 if (bp < buffer + sizeof buffer) 926 *bp++ = c; 927 } 928 /*NOTREACHED*/ 929 } 930 931 namecmp(name1, name2) 932 register char *name1, *name2; 933 { 934 register c1, c2; 935 936 for (;;) { 937 c1 = *name1++; 938 if (islower(c1)) 939 c1 = toupper(c1); 940 c2 = *name2++; 941 if (islower(c2)) 942 c2 = toupper(c2); 943 if (c1 != c2) 944 break; 945 if (c1 == 0) 946 return (1); 947 } 948 if (!c1) { 949 for (name2--; isdigit(*name2); name2++) 950 ; 951 if (*name2 == 0) 952 return (1); 953 } else if (!c2) { 954 for (name1--; isdigit(*name1); name1++) 955 ; 956 if (*name2 == 0) 957 return (1); 958 } 959 return (0); 960 } 961 962 netfinger(name) 963 char *name; 964 { 965 char *host; 966 char fname[100]; 967 struct hostent *hp; 968 struct servent *sp; 969 struct sockaddr_in sin; 970 int s; 971 char *rindex(); 972 register FILE *f; 973 register int c; 974 register int lastc; 975 976 if (name == NULL) 977 return (0); 978 host = rindex(name, '@'); 979 if (host == NULL) 980 return (0); 981 *host++ = 0; 982 hp = gethostbyname(host); 983 if (hp == NULL) { 984 static struct hostent def; 985 static struct in_addr defaddr; 986 static char namebuf[128]; 987 int inet_addr(); 988 989 defaddr.s_addr = inet_addr(host); 990 if (defaddr.s_addr == -1) { 991 printf("unknown host: %s\n", host); 992 return (1); 993 } 994 strcpy(namebuf, host); 995 def.h_name = namebuf; 996 def.h_addr = (char *)&defaddr; 997 def.h_length = sizeof (struct in_addr); 998 def.h_addrtype = AF_INET; 999 def.h_aliases = 0; 1000 hp = &def; 1001 } 1002 printf("[%s]", hp->h_name); 1003 sp = getservbyname("finger", "tcp"); 1004 if (sp == 0) { 1005 printf("tcp/finger: unknown service\n"); 1006 return (1); 1007 } 1008 sin.sin_family = hp->h_addrtype; 1009 bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length); 1010 sin.sin_port = sp->s_port; 1011 s = socket(hp->h_addrtype, SOCK_STREAM, 0); 1012 if (s < 0) { 1013 fflush(stdout); 1014 perror("socket"); 1015 return (1); 1016 } 1017 if (connect(s, (char *)&sin, sizeof (sin)) < 0) { 1018 fflush(stdout); 1019 perror("connect"); 1020 close(s); 1021 return (1); 1022 } 1023 printf("\n"); 1024 if (large) write(s, "/W ", 3); 1025 write(s, name, strlen(name)); 1026 write(s, "\r\n", 2); 1027 f = fdopen(s, "r"); 1028 while ((c = getc(f)) != EOF) { 1029 switch(c) { 1030 case 0210: 1031 case 0211: 1032 case 0212: 1033 case 0214: 1034 c -= 0200; 1035 break; 1036 case 0215: 1037 c = '\n'; 1038 break; 1039 } 1040 putchar(lastc = c); 1041 } 1042 if (lastc != '\n') 1043 putchar('\n'); 1044 return (1); 1045 } 1046