1 static char *sccsid = "@(#)finger.c 4.3 (Berkeley) 12/13/82"; 2 3 /* This is a finger program. It prints out useful information about users 4 * by digging it up from various system files. It is not very portable 5 * because the most useful parts of the information (the full user name, 6 * office, and phone numbers) are all stored in the VAX-unused gecos field 7 * of /etc/passwd, which, unfortunately, other UNIXes use for other things. 8 * 9 * There are three output formats, all of which give login name, teletype 10 * line number, and login time. The short output format is reminiscent 11 * of finger on ITS, and gives one line of information per user containing 12 * in addition to the minimum basic requirements (MBR), the full name of 13 * the user, his idle time and office location and phone number. The 14 * quick style output is UNIX who-like, giving only name, teletype and 15 * login time. Finally, the long style output give the same information 16 * as the short (in more legible format), the home directory and shell 17 * of the user, and, if it exits, a copy of the file .plan in the users 18 * home directory. Finger may be called with or without a list of people 19 * to finger -- if no list is given, all the people currently logged in 20 * are fingered. 21 * 22 * The program is validly called by one of the following: 23 * 24 * finger {short form list of users} 25 * finger -l {long form list of users} 26 * finger -b {briefer long form list of users} 27 * finger -q {quick list of users} 28 * finger -i {quick list of users with idle times} 29 * finger namelist {long format list of specified users} 30 * finger -s namelist {short format list of specified users} 31 * finger -w namelist {narrow short format list of specified users} 32 * 33 * where 'namelist' is a list of users login names. 34 * The other options can all be given after one '-', or each can have its 35 * own '-'. The -f option disables the printing of headers for short and 36 * quick outputs. The -b option briefens long format outputs. The -p 37 * option turns off plans for long format outputs. 38 */ 39 40 #include <sys/types.h> 41 #include <sys/stat.h> 42 #include <sgtty.h> 43 #include <utmp.h> 44 #include <signal.h> 45 #include <pwd.h> 46 #include <stdio.h> 47 #include <sccs.h> 48 #include <lastlog.h> 49 #include <time.h> 50 51 struct utmp utmp; /* for sizeof */ 52 #define NMAX sizeof(utmp.ut_name) 53 #define LMAX sizeof(utmp.ut_line) 54 55 #define ASTERISK '*' /* ignore this in real name */ 56 #define BLANK ' ' /* blank character (i.e. space) */ 57 #define CAPITALIZE 0137& /* capitalize character macro */ 58 #define COMMA ',' /* separator in pw_gecos field */ 59 #define COMMAND '-' /* command line flag char */ 60 #define CORY 'C' /* cory hall office */ 61 #define EVANS 'E' /* evans hall office */ 62 #define LINEBREAK 012 /* line feed */ 63 #define NULLSTR "" /* the null string, opposed to NULL */ 64 #define SAMENAME '&' /* repeat login name in real name */ 65 #define TALKABLE 0222 /* tty is writeable if 222 mode */ 66 67 struct person { /* one for each person fingered */ 68 char name[NMAX+1]; /* login name */ 69 char tty[LMAX+1]; /* NULL terminated tty line */ 70 long loginat; /* time of login (possibly last) */ 71 long idletime; /* how long idle (if logged in) */ 72 short int loggedin; /* flag for being logged in */ 73 short int writeable; /* flag for tty being writeable */ 74 char *realname; /* pointer to full name */ 75 char *office; /* pointer to office name */ 76 char *officephone; /* pointer to office phone no. */ 77 char *homephone; /* pointer to home phone no. */ 78 char *random; /* for any random stuff in pw_gecos */ 79 struct passwd *pwd; /* structure of /etc/passwd stuff */ 80 struct person *link; /* link to next person */ 81 }; 82 83 struct passwd *NILPWD = 0; 84 struct person *NILPERS = 0; 85 86 int persize = sizeof( struct person ); 87 int pwdsize = sizeof( struct passwd ); 88 89 char LASTLOG[] = "/usr/adm/lastlog"; /* last login info */ 90 char USERLOG[] = "/etc/utmp"; /* who is logged in */ 91 char outbuf[BUFSIZ]; /* output buffer */ 92 char *ctime(); 93 94 int unbrief = 1; /* -b option default */ 95 int header = 1; /* -f option default */ 96 int hack = 1; /* -h option default */ 97 int idle = 0; /* -i option default */ 98 int large = 0; /* -l option default */ 99 int match = 1; /* -m option default */ 100 int plan = 1; /* -p option default */ 101 int unquick = 1; /* -q option default */ 102 int small = 0; /* -s option default */ 103 int wide = 1; /* -w option default */ 104 105 int lf; 106 int llopenerr; 107 108 long tloc; /* current time */ 109 110 111 112 main( argc, argv ) 113 114 int argc; 115 char *argv[]; 116 117 { 118 FILE *fp, *fopen(); /* for plans */ 119 struct passwd *getpwent(); /* read /etc/passwd */ 120 struct person *person1, *p, *pend; /* people */ 121 struct passwd *pw; /* temporary */ 122 struct utmp user; /* ditto */ 123 char *malloc(); 124 char *s, *pn, *ln; 125 char c; 126 char *PLAN = "/.plan"; /* what plan file is */ 127 char *PROJ = "/.project"; /* what project file */ 128 int PLANLEN = strlen( PLAN ); 129 int PROJLEN = strlen( PROJ ); 130 int numnames = 0; 131 int orgnumnames; 132 int uf; 133 int usize = sizeof user; 134 int unshort; 135 int i, j; 136 int fngrlogin; 137 138 setbuf( stdout, outbuf ); /* buffer output */ 139 140 /* parse command line for (optional) arguments */ 141 142 i = 1; 143 if( strcmp( *argv, "sh" ) ) { 144 fngrlogin = 0; 145 while( i++ < argc && (*++argv)[0] == COMMAND ) { 146 for( s = argv[0] + 1; *s != NULL; s++ ) { 147 switch (*s) { 148 149 case 'b': 150 unbrief = 0; 151 break; 152 153 case 'f': 154 header = 0; 155 break; 156 157 case 'h': 158 hack = 0; 159 break; 160 161 case 'i': 162 idle = 1; 163 unquick = 0; 164 break; 165 166 case 'l': 167 large = 1; 168 break; 169 170 case 'm': 171 match = 0; 172 break; 173 174 case 'p': 175 plan = 0; 176 break; 177 178 case 'q': 179 unquick = 0; 180 break; 181 182 case 's': 183 small = 1; 184 break; 185 186 case 'w': 187 wide = 0; 188 break; 189 190 default: 191 fprintf( stderr, "finger: Usage -- 'finger [-bfhilmpqsw] [login1 [login2 ...] ]'\n" ); 192 exit( 1 ); 193 } 194 } 195 } 196 } 197 else { 198 fngrlogin = 1; 199 } 200 if( unquick ) { 201 time( &tloc ); 202 } 203 else { 204 if( idle ) { 205 time( &tloc ); 206 } 207 } 208 209 /* i > argc means no login names given so get them by reading USERLOG */ 210 211 if( (i > argc) || fngrlogin ) { 212 unshort = large; 213 if( ( uf = open(USERLOG, 0) ) >= 0 ) { 214 user.ut_name[0] = NULL; 215 while( user.ut_name[0] == NULL ) { 216 if( read( uf, (char *) &user, usize ) != usize ) { 217 printf( "\nNo one logged on\n" ); 218 exit( 0 ); 219 } 220 } 221 person1 = (struct person *) malloc( persize ); 222 for( j = 0; j < NMAX; j++ ) { 223 person1->tty[j] = user.ut_line[j]; 224 person1->name[j] = user.ut_name[j]; 225 } 226 person1->name[NMAX] = NULL; 227 person1->tty[NMAX] = NULL; 228 person1->loginat = user.ut_time; 229 person1->pwd = NILPWD; 230 person1->loggedin = 1; 231 numnames++; 232 p = person1; 233 while( read( uf, (char *) &user, usize ) == usize ) { 234 if( user.ut_name[0] == NULL ) continue; 235 p->link = (struct person *) malloc( persize ); 236 p = p->link; 237 for( j = 0; j < NMAX; j++ ) { 238 p->tty[j] = user.ut_line[j]; 239 p->name[j] = user.ut_name[j]; 240 } 241 p->name[NMAX] = NULL; 242 p->tty[NMAX] = NULL; 243 p->loginat = user.ut_time; 244 p->pwd = NILPWD; 245 p->loggedin = 1; 246 numnames++; 247 } 248 p->link = NILPERS; 249 close( uf ); 250 } 251 else { 252 fprintf( stderr, "finger: error opening %s\n", USERLOG ); 253 exit( 2 ); 254 } 255 256 /* if we are doing it, read /etc/passwd for the useful info */ 257 258 if( unquick ) { 259 setpwent(); 260 fwopen(); 261 i = numnames; 262 while( ( (pw = getpwent()) != NILPWD ) && ( i > 0 ) ) { 263 p = person1; 264 do { 265 if( p->pwd == NILPWD ) { 266 if( strcmp( p->name, pw->pw_name ) == 0 ) { 267 p->pwd = (struct passwd *) malloc( pwdsize ); 268 pwdcopy( p->pwd, pw ); 269 decode( p ); 270 i--; 271 } 272 } 273 p = p->link; 274 } while( p != NILPERS ); 275 } 276 fwclose(); 277 endpwent(); 278 } 279 } 280 281 /* get names from command line and check to see if they're logged in */ 282 283 else { 284 unshort = ( small == 1 ? 0 : 1 ); 285 i++; 286 person1 = (struct person *) malloc( persize ); 287 strcpy( person1->name, (argv++)[ 0 ] ); 288 person1->loggedin = 0; 289 person1->pwd = NILPWD; 290 numnames++; 291 p = person1; 292 while( i++ <= argc ) { 293 p->link = (struct person *) malloc( persize ); 294 p = p->link; 295 strcpy( p->name, (argv++)[ 0 ] ); 296 p->loggedin = 0; 297 p->pwd = NILPWD; 298 numnames++; 299 } 300 p->link = NILPERS; 301 pend = p; 302 303 /* if we are doing it, read /etc/passwd for the useful info */ 304 305 orgnumnames = numnames; 306 if( unquick ) { 307 setpwent(); 308 while( ( pw = getpwent() ) != NILPWD ) { 309 p = person1; 310 i = 0; 311 do { 312 if( strcmp( p->name, pw->pw_name ) == 0 || 313 matchcmp( pw->pw_gecos, pw->pw_name, p->name ) ) { 314 if( p->pwd == NILPWD ) { 315 p->pwd = (struct passwd *) malloc( pwdsize ); 316 pwdcopy( p->pwd, pw ); 317 } 318 else { /* handle multiple logins -- append new 319 "duplicate" entry to end of list */ 320 pend->link = (struct person *) malloc(persize); 321 pend = pend->link; 322 pend->link = NILPERS; 323 strcpy( pend->name, p->name ); 324 pend->pwd = (struct passwd *) malloc(pwdsize); 325 pwdcopy( pend->pwd, pw ); 326 numnames++; 327 } 328 } 329 p = p->link; 330 } while( ++i < orgnumnames ); 331 } 332 endpwent(); 333 } 334 335 /* Now get login information */ 336 337 if( ( uf = open(USERLOG, 0) ) >= 0 ) { 338 while( read( uf, (char *) &user, usize ) == usize ) { 339 if( user.ut_name[0] == NULL ) continue; 340 p = person1; 341 do { 342 pw = p->pwd; 343 if( pw == NILPWD ) { 344 i = ( strcmp( p->name, user.ut_name ) ? 0 : NMAX ); 345 } 346 else { 347 i = 0; 348 while( (i < NMAX) && 349 ( pw->pw_name[i] == user.ut_name[i]) ) { 350 if( pw->pw_name[i] == NULL ) { 351 i = NMAX; 352 break; 353 } 354 i++; 355 } 356 } 357 if( i == NMAX ) { 358 if( p->loggedin == 1 ) { 359 pend->link = (struct person *) malloc(persize); 360 pend = pend->link; 361 pend->link = NILPERS; 362 strcpy( pend->name, p->name ); 363 for( j = 0; j < NMAX; j++ ) { 364 pend->tty[j] = user.ut_line[j]; 365 } 366 pend->tty[ NMAX ] = NULL; 367 pend->loginat = user.ut_time; 368 pend->loggedin = 2; 369 if( pw == NILPWD ) { 370 pend ->pwd = NILPWD; 371 } 372 else { 373 pend->pwd = (struct passwd *) malloc(pwdsize); 374 pwdcopy( pend->pwd, pw ); 375 } 376 numnames++; 377 } 378 else { 379 if( p->loggedin != 2 ) { 380 for( j = 0; j < NMAX; j++ ) { 381 p->tty[j] = user.ut_line[j]; 382 } 383 p->tty[ NMAX ] = NULL; 384 p->loginat = user.ut_time; 385 p->loggedin = 1; 386 } 387 } 388 } 389 p = p->link; 390 } while( p != NILPERS ); 391 } 392 fwopen(); 393 p = person1; 394 while( p != NILPERS ) { 395 if( p->loggedin == 2 ) { 396 p->loggedin = 1; 397 } 398 decode( p ); 399 p = p->link; 400 } 401 fwclose(); 402 close( uf ); 403 } 404 else { 405 fprintf( stderr, "finger: error opening %s\n", USERLOG ); 406 exit( 2 ); 407 } 408 } 409 410 /* print out what we got */ 411 412 if( header ) { 413 if( unquick ) { 414 if( !unshort ) { 415 if( wide ) { 416 printf( 417 "Login Name TTY Idle When Office\n" ); 418 } 419 else { 420 printf( 421 "Login TTY Idle When Office\n" ); 422 } 423 } 424 } 425 else { 426 printf( "Login TTY When" ); 427 if( idle ) { 428 printf( " Idle" ); 429 } 430 printf( "\n" ); 431 } 432 } 433 p = person1; 434 do { 435 if( unquick ) { 436 if( unshort ) { 437 personprint( p ); 438 if( p->pwd != NILPWD ) { 439 if( hack ) { 440 s = malloc(strlen((p->pwd)->pw_dir) + PROJLEN + 1 ); 441 strcpy( s, (p->pwd)->pw_dir ); 442 strcat( s, PROJ ); 443 if( ( fp = fopen( s, "r") ) != NULL ) { 444 printf( "Project: " ); 445 while( ( c = getc(fp) ) != EOF ) { 446 if( c == LINEBREAK ) { 447 break; 448 } 449 putc( c, stdout ); 450 } 451 fclose( fp ); 452 printf( "\n" ); 453 } 454 } 455 if( plan ) { 456 s = malloc( strlen( (p->pwd)->pw_dir ) + PLANLEN + 1 ); 457 strcpy( s, (p->pwd)->pw_dir ); 458 strcat( s, PLAN ); 459 if( ( fp = fopen( s, "r") ) == NULL ) { 460 printf( "No Plan.\n" ); 461 } 462 else { 463 printf( "Plan:\n" ); 464 while( ( c = getc(fp) ) != EOF ) { 465 putc( c, stdout ); 466 } 467 fclose( fp ); 468 } 469 } 470 } 471 if( p->link != NILPERS ) { 472 printf( "\n" ); 473 } 474 } 475 else { 476 shortprint( p ); 477 } 478 } 479 else { 480 quickprint( p ); 481 } 482 p = p->link; 483 } while( p != NILPERS ); 484 exit(0); 485 } 486 487 488 /* given a pointer to a pwd (pfrom) copy it to another one, allocating 489 * space for all the stuff in it. Note: Only the useful (what the 490 * program currently uses) things are copied. 491 */ 492 493 pwdcopy( pto, pfrom ) /* copy relevant fields only */ 494 495 struct passwd *pto, *pfrom; 496 { 497 pto->pw_name = malloc( strlen( pfrom->pw_name ) + 1 ); 498 strcpy( pto->pw_name, pfrom->pw_name ); 499 pto->pw_uid = pfrom->pw_uid; 500 pto->pw_gecos = malloc( strlen( pfrom->pw_gecos ) + 1 ); 501 strcpy( pto->pw_gecos, pfrom->pw_gecos ); 502 pto->pw_dir = malloc( strlen( pfrom->pw_dir ) + 1 ); 503 strcpy( pto->pw_dir, pfrom->pw_dir ); 504 pto->pw_shell = malloc( strlen( pfrom->pw_shell ) + 1 ); 505 strcpy( pto->pw_shell, pfrom->pw_shell ); 506 } 507 508 509 /* print out information on quick format giving just name, tty, login time 510 * and idle time if idle is set. 511 */ 512 513 quickprint( pers ) 514 515 struct person *pers; 516 { 517 int idleprinted; 518 519 printf( "%-*.*s", NMAX, NMAX, pers->name ); 520 printf( " " ); 521 if( pers->loggedin ) { 522 if( idle ) { 523 findidle( pers ); 524 if( pers->writeable ) { 525 printf( " %-*.*s %-16.16s", LMAX, LMAX, 526 pers->tty, ctime( &pers->loginat ) ); 527 } 528 else { 529 printf( "*%-*.*s %-16.16s", LMAX, LMAX, 530 pers->tty, ctime( &pers->loginat ) ); 531 } 532 printf( " " ); 533 idleprinted = ltimeprint( &pers->idletime ); 534 } 535 else { 536 printf( " %-*.*s %-16.16s", LMAX, LMAX, 537 pers->tty, ctime( &pers->loginat ) ); 538 } 539 } 540 else { 541 printf( " Not Logged In" ); 542 } 543 printf( "\n" ); 544 } 545 546 547 /* print out information in short format, giving login name, full name, 548 * tty, idle time, login time, office location and phone. 549 */ 550 551 shortprint( pers ) 552 553 struct person *pers; 554 555 { 556 struct passwd *pwdt = pers->pwd; 557 char buf[ 26 ]; 558 int i, len, offset, dialup; 559 560 if( pwdt == NILPWD ) { 561 printf( "%-*.*s", NMAX, NMAX, pers->name ); 562 printf( " ???\n" ); 563 return; 564 } 565 printf( "%-*.*s", NMAX, NMAX, pwdt->pw_name ); 566 dialup = 0; 567 if( wide ) { 568 if( strlen( pers->realname ) > 0 ) { 569 printf( " %-20.20s", pers->realname ); 570 } 571 else { 572 printf( " ??? " ); 573 } 574 } 575 if( pers->loggedin ) { 576 if( pers->writeable ) { 577 printf( " " ); 578 } 579 else { 580 printf( " *" ); 581 } 582 } 583 else { 584 printf( " " ); 585 } 586 if( strlen( pers->tty ) > 0 ) { 587 strcpy( buf, pers->tty ); 588 if( (buf[0] == 't') && (buf[1] == 't') && (buf[2] == 'y') ) { 589 offset = 3; 590 for( i = 0; i < 2; i++ ) { 591 buf[i] = buf[i + offset]; 592 } 593 } 594 if( (buf[0] == 'd') && pers->loggedin ) { 595 dialup = 1; 596 } 597 printf( "%-2.2s ", buf ); 598 } 599 else { 600 printf( " " ); 601 } 602 strcpy(buf, ctime(&pers->loginat)); 603 if( pers->loggedin ) { 604 stimeprint( &pers->idletime ); 605 offset = 7; 606 for( i = 4; i < 19; i++ ) { 607 buf[i] = buf[i + offset]; 608 } 609 printf( " %-9.9s ", buf ); 610 } 611 else if (pers->loginat == 0) 612 printf(" < . . . . >"); 613 else if (tloc - pers->loginat >= 180 * 24 * 60 * 60) 614 printf( " <%-6.6s, %-4.4s>", buf+4, buf+20 ); 615 else 616 printf(" <%-12.12s>", buf+4); 617 len = strlen( pers->homephone ); 618 if( dialup && (len > 0) ) { 619 if( len == 8 ) { 620 printf( " " ); 621 } 622 else { 623 if( len == 12 ) { 624 printf( " " ); 625 } 626 else { 627 for( i = 1; i <= 21 - len; i++ ) { 628 printf( " " ); 629 } 630 } 631 } 632 printf( "%s", pers->homephone ); 633 } 634 else { 635 if( strlen( pers->office ) > 0 ) { 636 printf( " %-11.11s", pers->office ); 637 if( strlen( pers->officephone ) > 0 ) { 638 printf( " %8.8s", pers->officephone ); 639 } 640 else { 641 if( len == 8 ) { 642 printf( " %8.8s", pers->homephone ); 643 } 644 } 645 } 646 else { 647 if( strlen( pers->officephone ) > 0 ) { 648 printf( " %8.8s", pers->officephone ); 649 } 650 else { 651 if( len == 8 ) { 652 printf( " %8.8s", pers->homephone ); 653 } 654 else { 655 if( len == 12 ) { 656 printf( " %12.12s", pers->homephone ); 657 } 658 } 659 } 660 } 661 } 662 printf( "\n" ); 663 } 664 665 666 /* print out a person in long format giving all possible information. 667 * directory and shell are inhibited if unbrief is clear. 668 */ 669 670 personprint( pers ) 671 672 struct person *pers; 673 { 674 struct passwd *pwdt = pers->pwd; 675 int idleprinted; 676 677 if( pwdt == NILPWD ) { 678 printf( "Login name: %-10s", pers->name ); 679 printf( " " ); 680 printf( "In real life: ???\n"); 681 return; 682 } 683 printf( "Login name: %-10s", pwdt->pw_name ); 684 if( pers->loggedin ) { 685 if( pers->writeable ) { 686 printf( " " ); 687 } 688 else { 689 printf( " (messages off) " ); 690 } 691 } 692 else { 693 printf( " " ); 694 } 695 if( strlen( pers->realname ) > 0 ) { 696 printf( "In real life: %-s", pers->realname ); 697 } 698 if( strlen( pers->office ) > 0 ) { 699 printf( "\nOffice: %-.11s", pers->office ); 700 if( strlen( pers->officephone ) > 0 ) { 701 printf( ", %s", pers->officephone ); 702 if( strlen( pers->homephone ) > 0 ) { 703 printf( " Home phone: %s", pers->homephone ); 704 } 705 else { 706 if( strlen( pers->random ) > 0 ) { 707 printf( " %s", pers->random ); 708 } 709 } 710 } 711 else { 712 if( strlen( pers->homephone ) > 0 ) { 713 printf(" Home phone: %s",pers->homephone); 714 } 715 if( strlen( pers->random ) > 0 ) { 716 printf( " %s", pers->random ); 717 } 718 } 719 } 720 else { 721 if( strlen( pers->officephone ) > 0 ) { 722 printf( "\nPhone: %s", pers->officephone ); 723 if( strlen( pers->homephone ) > 0 ) { 724 printf( "\n, %s", pers->homephone ); 725 if( strlen( pers->random ) > 0 ) { 726 printf( ", %s", pers->random ); 727 } 728 } 729 else { 730 if( strlen( pers->random ) > 0 ) { 731 printf( "\n, %s", pers->random ); 732 } 733 } 734 } 735 else { 736 if( strlen( pers->homephone ) > 0 ) { 737 printf( "\nPhone: %s", pers->homephone ); 738 if( strlen( pers->random ) > 0 ) { 739 printf( ", %s", pers->random ); 740 } 741 } 742 else { 743 if( strlen( pers->random ) > 0 ) { 744 printf( "\n%s", pers->random ); 745 } 746 } 747 } 748 } 749 if( unbrief ) { 750 printf( "\n" ); 751 printf( "Directory: %-25s", pwdt->pw_dir ); 752 if( strlen( pwdt->pw_shell ) > 0 ) { 753 printf( " Shell: %-s", pwdt->pw_shell ); 754 } 755 } 756 if( pers->loggedin ) { 757 register char *ep = ctime( &pers->loginat ); 758 printf("\nOn since %15.15s on %-*.*s ", &ep[4], LMAX, LMAX, pers->tty ); 759 idleprinted = ltimeprint( &pers->idletime ); 760 if( idleprinted ) { 761 printf( " Idle Time" ); 762 } 763 } 764 else if (pers->loginat == 0) 765 printf("\nNever logged in."); 766 else if (tloc - pers->loginat > 180 * 24 * 60 * 60) { 767 register char *ep = ctime( &pers->loginat ); 768 printf("\nLast login %10.10s, %4.4s on %.*s", ep, ep+20, LMAX, pers->tty); 769 } 770 else { 771 register char *ep = ctime( &pers->loginat ); 772 printf("\nLast login %16.16s on %.*s", ep, LMAX, pers->tty ); 773 } 774 printf( "\n" ); 775 } 776 777 778 /* 779 * very hacky section of code to format phone numbers. filled with 780 * magic constants like 4, 7 and 10. 781 */ 782 783 char *phone( s, len ) 784 785 char *s; 786 int len; 787 { 788 char *strsave(); 789 char fonebuf[ 15 ]; 790 int i; 791 792 switch( len ) { 793 794 case 4: 795 fonebuf[ 0 ] = ' '; 796 fonebuf[ 1 ] = 'x'; 797 fonebuf[ 2 ] = '2'; 798 fonebuf[ 3 ] = '-'; 799 for( i = 0; i <= 3; i++ ) { 800 fonebuf[ 4 + i ] = *s++; 801 } 802 fonebuf[ 8 ] = NULL; 803 return( strsave( &fonebuf[0] ) ); 804 break; 805 806 case 7: 807 for( i = 0; i <= 2; i++ ) { 808 fonebuf[ i ] = *s++; 809 } 810 fonebuf[ 3 ] = '-'; 811 for( i = 0; i <= 3; i++ ) { 812 fonebuf[ 4 + i ] = *s++; 813 } 814 fonebuf[ 8 ] = NULL; 815 return( strsave( &fonebuf[0] ) ); 816 break; 817 818 case 10: 819 for( i = 0; i <= 2; i++ ) { 820 fonebuf[ i ] = *s++; 821 } 822 fonebuf[ 3 ] = '-'; 823 for( i = 0; i <= 2; i++ ) { 824 fonebuf[ 4 + i ] = *s++; 825 } 826 fonebuf[ 7 ] = '-'; 827 for( i = 0; i <= 3; i++ ) { 828 fonebuf[ 8 + i ] = *s++; 829 } 830 fonebuf[ 12 ] = NULL; 831 return( strsave( &fonebuf[0] ) ); 832 break; 833 834 default: 835 fprintf( stderr, "finger: error in phone numbering\n" ); 836 return( strsave(s) ); 837 break; 838 } 839 } 840 841 842 /* decode the information in the gecos field of /etc/passwd 843 * another hacky section of code, but given the format the stuff is in... 844 */ 845 846 decode( pers ) 847 848 struct person *pers; 849 850 { 851 struct passwd *pwdt = pers->pwd; 852 char buffer[ 40 ], *bp, *gp, *lp; 853 char *phone(); 854 int alldigits; 855 int len; 856 int i; 857 858 pers->realname = NULLSTR; 859 pers->office = NULLSTR; 860 pers->officephone = NULLSTR; 861 pers->homephone = NULLSTR; 862 pers->random = NULLSTR; 863 if( pwdt != NILPWD ) { 864 gp = pwdt->pw_gecos; 865 bp = &buffer[ 0 ]; 866 if( *gp == ASTERISK ) { 867 gp++; 868 } 869 while( (*gp != NULL) && (*gp != COMMA) ) { /* name */ 870 if( *gp == SAMENAME ) { 871 lp = pwdt->pw_name; 872 *bp++ = CAPITALIZE(*lp++); 873 while( *lp != NULL ) { 874 *bp++ = *lp++; 875 } 876 } 877 else { 878 *bp++ = *gp; 879 } 880 gp++; 881 } 882 *bp = NULL; 883 pers->realname = malloc( strlen( &buffer[0] ) + 1 ); 884 strcpy( pers->realname, &buffer[0] ); 885 if( *gp++ == COMMA ) { /* office, supposedly */ 886 alldigits = 1; 887 bp = &buffer[ 0 ]; 888 while( (*gp != NULL) && (*gp != COMMA) ) { 889 *bp = *gp++; 890 alldigits = alldigits && ('0' <= *bp) && (*bp <= '9'); 891 bp++; 892 } 893 *bp = NULL; 894 len = strlen( &buffer[0] ); 895 if( buffer[ len - 1 ] == CORY ) { 896 strcpy( &buffer[ len - 1 ], " Cory" ); 897 pers->office = malloc( len + 5 ); 898 strcpy( pers->office, &buffer[0] ); 899 } 900 else { 901 if( buffer[ len - 1 ] == EVANS ) { 902 strcpy( &buffer[ len - 1 ], " Evans" ); 903 pers->office = malloc( len + 6 ); 904 strcpy( pers->office, &buffer[0] ); 905 } 906 else { 907 if( buffer[ len - 1 ] == 'L' ) { 908 strcpy( &buffer[ len - 1 ], " LBL" ); 909 pers->office = malloc( len + 4 ); 910 strcpy( pers->office, &buffer[0] ); 911 } 912 else { 913 if( alldigits ) { 914 if( len == 4 ) { 915 pers->officephone = phone(&buffer[0], len); 916 } 917 else { 918 if( (len == 7) || (len == 10) ) { 919 pers->homephone = phone(&buffer[0],len); 920 } 921 } 922 } 923 else { 924 pers->random = malloc( len + 1 ); 925 strcpy( pers->random, &buffer[0] ); 926 } 927 } 928 } 929 } 930 if( *gp++ == COMMA ) { /* office phone, theoretically */ 931 bp = &buffer[ 0 ]; 932 alldigits = 1; 933 while( (*gp != NULL) && (*gp != COMMA) ) { 934 *bp = *gp++; 935 alldigits = alldigits && ('0' <= *bp) && (*bp <= '9'); 936 bp++; 937 } 938 *bp = NULL; 939 len = strlen( &buffer[0] ); 940 if( alldigits ) { 941 if( len != 4 ) { 942 if( (len == 7) || (len == 10) ) { 943 pers->homephone = phone( &buffer[0], len ); 944 } 945 else { 946 pers->random = malloc( len + 1 ); 947 strcpy( pers->random, &buffer[0] ); 948 } 949 } 950 else { 951 pers->officephone = phone( &buffer[0], len ); 952 } 953 } 954 else { 955 pers->random = malloc( len + 1 ); 956 strcpy( pers->random, &buffer[0] ); 957 } 958 if( *gp++ == COMMA ) { /* home phone?? */ 959 bp = &buffer[ 0 ]; 960 alldigits = 1; 961 while( (*gp != NULL) && (*gp != COMMA) ) { 962 *bp = *gp++; 963 alldigits = alldigits && ('0' <= *bp) && 964 (*bp <= '9'); 965 bp++; 966 } 967 *bp = NULL; 968 len = strlen( &buffer[0] ); 969 if( alldigits && ( (len == 7) || (len == 10) ) ) { 970 if( *pers->homephone != NULL ) { 971 pers->officephone = pers->homephone; 972 } 973 pers->homephone = phone( &buffer[0], len ); 974 } 975 else { 976 pers->random = malloc( strlen( &buffer[0] ) + 1 ); 977 strcpy( pers->random, &buffer[0] ); 978 } 979 } 980 } 981 } 982 if( pers->loggedin == 0 ) { 983 findwhen( pers ); 984 } 985 else { 986 findidle( pers ); 987 } 988 } 989 } 990 991 992 /* find the last log in of a user by checking the LASTLOG file. 993 * the entry is indexed by the uid, so this can only be done if 994 * the uid is known (which it isn't in quick mode) 995 */ 996 997 fwopen() 998 { 999 if( ( lf = open(LASTLOG, 0) ) >= 0 ) { 1000 llopenerr = 0; 1001 } 1002 else { 1003 fprintf( stderr, "finger: lastlog open error\n" ); 1004 llopenerr = 1; 1005 } 1006 } 1007 1008 1009 findwhen( pers ) 1010 1011 struct person *pers; 1012 { 1013 struct passwd *pwdt = pers->pwd; 1014 struct lastlog ll; 1015 int llsize = sizeof ll; 1016 int i; 1017 1018 if( !llopenerr ) { 1019 lseek( lf, pwdt->pw_uid*llsize, 0 ); 1020 if ((i = read( lf, (char *) &ll, llsize )) == llsize) { 1021 for( i = 0; i < LMAX; i++ ) { 1022 pers->tty[ i ] = ll.ll_line[ i ]; 1023 } 1024 pers->tty[ LMAX ] = NULL; 1025 pers->loginat = ll.ll_time; 1026 } 1027 else { 1028 if (i != 0) 1029 fprintf(stderr, "finger: lastlog read error\n"); 1030 pers->tty[ 0 ] = NULL; 1031 pers->loginat = 0L; 1032 } 1033 } 1034 else { 1035 pers->tty[ 0 ] = NULL; 1036 pers->loginat = 0L; 1037 } 1038 } 1039 1040 1041 fwclose() 1042 { 1043 if( !llopenerr ) { 1044 close( lf ); 1045 } 1046 } 1047 1048 1049 /* find the idle time of a user by doing a stat on /dev/histty, 1050 * where histty has been gotten from USERLOG, supposedly. 1051 */ 1052 1053 findidle( pers ) 1054 1055 struct person *pers; 1056 { 1057 struct stat ttystatus; 1058 struct passwd *pwdt = pers->pwd; 1059 char buffer[ 20 ]; 1060 char *TTY = "/dev/"; 1061 int TTYLEN = strlen( TTY ); 1062 int i; 1063 1064 strcpy( &buffer[0], TTY ); 1065 i = 0; 1066 do { 1067 buffer[ TTYLEN + i ] = pers->tty[ i ]; 1068 } while( ++i <= LMAX ); 1069 if( stat( &buffer[0], &ttystatus ) >= 0 ) { 1070 time( &tloc ); 1071 if( tloc < ttystatus.st_atime ) { 1072 pers->idletime = 0L; 1073 } 1074 else { 1075 pers->idletime = tloc - ttystatus.st_atime; 1076 } 1077 if( (ttystatus.st_mode & TALKABLE) == TALKABLE ) { 1078 pers->writeable = 1; 1079 } 1080 else { 1081 pers->writeable = 0; 1082 } 1083 } 1084 else { 1085 fprintf( stderr, "finger: error STATing %s\n", &buffer[0] ); 1086 exit( 4 ); 1087 } 1088 } 1089 1090 1091 /* print idle time in short format; this program always prints 4 characters; 1092 * if the idle time is zero, it prints 4 blanks. 1093 */ 1094 1095 stimeprint( dt ) 1096 1097 long *dt; 1098 { 1099 struct tm *gmtime(); 1100 struct tm *delta; 1101 1102 delta = gmtime( dt ); 1103 if( delta->tm_yday == 0 ) { 1104 if( delta->tm_hour == 0 ) { 1105 if( delta->tm_min >= 10 ) { 1106 printf( " %2.2d ", delta->tm_min ); 1107 } 1108 else { 1109 if( delta->tm_min == 0 ) { 1110 printf( " " ); 1111 } 1112 else { 1113 printf( " %1.1d ", delta->tm_min ); 1114 } 1115 } 1116 } 1117 else { 1118 if( delta->tm_hour >= 10 ) { 1119 printf( "%3.3d:", delta->tm_hour ); 1120 } 1121 else { 1122 printf( "%1.1d:%02.2d", delta->tm_hour, delta->tm_min ); 1123 } 1124 } 1125 } 1126 else { 1127 printf( "%3dd", delta->tm_yday ); 1128 } 1129 } 1130 1131 1132 /* print idle time in long format with care being taken not to pluralize 1133 * 1 minutes or 1 hours or 1 days. 1134 */ 1135 1136 ltimeprint( dt ) 1137 1138 long *dt; 1139 { 1140 struct tm *gmtime(); 1141 struct tm *delta; 1142 int printed = 1; 1143 1144 delta = gmtime( dt ); 1145 if( delta->tm_yday == 0 ) { 1146 if( delta->tm_hour == 0 ) { 1147 if( delta->tm_min >= 10 ) { 1148 printf( "%2d minutes", delta->tm_min ); 1149 } 1150 else { 1151 if( delta->tm_min == 0 ) { 1152 if( delta->tm_sec > 10 ) { 1153 printf( "%2d seconds", delta->tm_sec ); 1154 } 1155 else { 1156 printed = 0; 1157 } 1158 } 1159 else { 1160 if( delta->tm_min == 1 ) { 1161 if( delta->tm_sec == 1 ) { 1162 printf( "%1d minute %1d second", 1163 delta->tm_min, delta->tm_sec ); 1164 } 1165 else { 1166 printf( "%1d minute %d seconds", 1167 delta->tm_min, delta->tm_sec ); 1168 } 1169 } 1170 else { 1171 if( delta->tm_sec == 1 ) { 1172 printf( "%1d minutes %1d second", 1173 delta->tm_min, delta->tm_sec ); 1174 } 1175 else { 1176 printf( "%1d minutes %d seconds", 1177 delta->tm_min, delta->tm_sec ); 1178 } 1179 } 1180 } 1181 } 1182 } 1183 else { 1184 if( delta->tm_hour >= 10 ) { 1185 printf( "%2d hours", delta->tm_hour ); 1186 } 1187 else { 1188 if( delta->tm_hour == 1 ) { 1189 if( delta->tm_min == 1 ) { 1190 printf( "%1d hour %1d minute", 1191 delta->tm_hour, delta->tm_min ); 1192 } 1193 else { 1194 printf( "%1d hour %2d minutes", 1195 delta->tm_hour, delta->tm_min ); 1196 } 1197 } 1198 else { 1199 if( delta->tm_min == 1 ) { 1200 printf( "%1d hours %1d minute", 1201 delta->tm_hour, delta->tm_min ); 1202 } 1203 else { 1204 printf( "%1d hours %2d minutes", 1205 delta->tm_hour, delta->tm_min ); 1206 } 1207 } 1208 } 1209 } 1210 } 1211 else { 1212 if( delta->tm_yday >= 10 ) { 1213 printf( "%2d days", delta->tm_yday ); 1214 } 1215 else { 1216 if( delta->tm_yday == 1 ) { 1217 if( delta->tm_hour == 1 ) { 1218 printf( "%1d day %1d hour", 1219 delta->tm_yday, delta->tm_hour ); 1220 } 1221 else { 1222 printf( "%1d day %2d hours", 1223 delta->tm_yday, delta->tm_hour ); 1224 } 1225 } 1226 else { 1227 if( delta->tm_hour == 1 ) { 1228 printf( "%1d days %1d hour", 1229 delta->tm_yday, delta->tm_hour ); 1230 } 1231 else { 1232 printf( "%1d days %2d hours", 1233 delta->tm_yday, delta->tm_hour ); 1234 } 1235 } 1236 } 1237 } 1238 return( printed ); 1239 } 1240 1241 1242 matchcmp( gname, login, given ) 1243 1244 char *gname; 1245 char *login; 1246 char *given; 1247 { 1248 char buffer[ 20 ]; 1249 char c; 1250 int flag, i, unfound; 1251 1252 if( !match ) { 1253 return( 0 ); 1254 } 1255 else { 1256 if( namecmp( login, given ) ) { 1257 return( 1 ); 1258 } 1259 else if (*gname == '\0') 1260 return (0); 1261 else { 1262 if( *gname == ASTERISK ) { 1263 gname++; 1264 } 1265 flag = 1; 1266 i = 0; 1267 unfound = 1; 1268 while( unfound ) { 1269 if( flag ) { 1270 c = *gname++; 1271 if( c == SAMENAME ) { 1272 flag = 0; 1273 c = *login++; 1274 } 1275 else { 1276 unfound = (*gname != COMMA) && (*gname != NULL); 1277 } 1278 } 1279 else { 1280 c = *login++; 1281 if( c == NULL ) { 1282 if( (*gname == COMMA) || (*gname == NULL) ) { 1283 break; 1284 } 1285 else { 1286 flag = 1; 1287 continue; 1288 } 1289 } 1290 } 1291 if( c == BLANK ) { 1292 buffer[i++] = NULL; 1293 if( namecmp( buffer, given ) ) { 1294 return( 1 ); 1295 } 1296 i = 0; 1297 flag = 1; 1298 } 1299 else { 1300 buffer[ i++ ] = c; 1301 } 1302 } 1303 buffer[i++] = NULL; 1304 if( namecmp( buffer, given ) ) { 1305 return( 1 ); 1306 } 1307 else { 1308 return( 0 ); 1309 } 1310 } 1311 } 1312 } 1313 1314 1315 namecmp( name1, name2 ) 1316 1317 char *name1; 1318 char *name2; 1319 { 1320 char c1, c2; 1321 1322 c1 = *name1; 1323 if( (('A' <= c1) && (c1 <= 'Z')) || (('a' <= c1) && (c1 <= 'z')) ) { 1324 c1 = CAPITALIZE( c1 ); 1325 } 1326 c2 = *name2; 1327 if( (('A' <= c2) && (c2 <= 'Z')) || (('a' <= c2) && (c2 <= 'z')) ) { 1328 c2 = CAPITALIZE( c2 ); 1329 } 1330 while( c1 == c2 ) { 1331 if( c1 == NULL ) { 1332 return( 1 ); 1333 } 1334 c1 = *++name1; 1335 if( (('A'<=c1) && (c1<='Z')) || (('a'<=c1) && (c1<='z')) ) { 1336 c1 = CAPITALIZE( c1 ); 1337 } 1338 c2 = *++name2; 1339 if( (('A'<=c2) && (c2<='Z')) || (('a'<=c2) && (c2<='z')) ) { 1340 c2 = CAPITALIZE( c2 ); 1341 } 1342 } 1343 if( *name1 == NULL ) { 1344 while( ('0' <= *name2) && (*name2 <= '9') ) { 1345 name2++; 1346 } 1347 if( *name2 == NULL ) { 1348 return( 1 ); 1349 } 1350 } 1351 else { 1352 if( *name2 == NULL ) { 1353 while( ('0' <= *name1) && (*name1 <= '9') ) { 1354 name1++; 1355 } 1356 if( *name1 == NULL ) { 1357 return( 1 ); 1358 } 1359 } 1360 } 1361 return( 0 ); 1362 } 1363 1364 1365 char *strsave( s ) 1366 1367 char *s; 1368 { 1369 char *malloc(); 1370 char *p; 1371 1372 p = malloc( strlen( s ) + 1 ); 1373 strcpy( p, s ); 1374 } 1375