1 static char *sccsid = "@(#)finger.c 4.1 (Berkeley) 10/01/80"; 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 { 612 printf( " " ); 613 offset = 4; 614 for( i = 0; i <22; i++ ) { 615 buf[i] = buf[i + offset]; 616 } 617 printf( "<%-12.12s>", buf ); 618 } 619 len = strlen( pers->homephone ); 620 if( dialup && (len > 0) ) { 621 if( len == 8 ) { 622 printf( " " ); 623 } 624 else { 625 if( len == 12 ) { 626 printf( " " ); 627 } 628 else { 629 for( i = 1; i <= 21 - len; i++ ) { 630 printf( " " ); 631 } 632 } 633 } 634 printf( "%s", pers->homephone ); 635 } 636 else { 637 if( strlen( pers->office ) > 0 ) { 638 printf( " %-11.11s", pers->office ); 639 if( strlen( pers->officephone ) > 0 ) { 640 printf( " %8.8s", pers->officephone ); 641 } 642 else { 643 if( len == 8 ) { 644 printf( " %8.8s", pers->homephone ); 645 } 646 } 647 } 648 else { 649 if( strlen( pers->officephone ) > 0 ) { 650 printf( " %8.8s", pers->officephone ); 651 } 652 else { 653 if( len == 8 ) { 654 printf( " %8.8s", pers->homephone ); 655 } 656 else { 657 if( len == 12 ) { 658 printf( " %12.12s", pers->homephone ); 659 } 660 } 661 } 662 } 663 } 664 printf( "\n" ); 665 } 666 667 668 /* print out a person in long format giving all possible information. 669 * directory and shell are inhibited if unbrief is clear. 670 */ 671 672 personprint( pers ) 673 674 struct person *pers; 675 { 676 struct passwd *pwdt = pers->pwd; 677 int idleprinted; 678 679 if( pwdt == NILPWD ) { 680 printf( "Login name: %-10s", pers->name ); 681 printf( " " ); 682 printf( "In real life: ???\n"); 683 return; 684 } 685 printf( "Login name: %-10s", pwdt->pw_name ); 686 if( pers->loggedin ) { 687 if( pers->writeable ) { 688 printf( " " ); 689 } 690 else { 691 printf( " (messages off) " ); 692 } 693 } 694 else { 695 printf( " " ); 696 } 697 if( strlen( pers->realname ) > 0 ) { 698 printf( "In real life: %-s", pers->realname ); 699 } 700 if( strlen( pers->office ) > 0 ) { 701 printf( "\nOffice: %-.11s", pers->office ); 702 if( strlen( pers->officephone ) > 0 ) { 703 printf( ", %s", pers->officephone ); 704 if( strlen( pers->homephone ) > 0 ) { 705 printf( " Home phone: %s", pers->homephone ); 706 } 707 else { 708 if( strlen( pers->random ) > 0 ) { 709 printf( " %s", pers->random ); 710 } 711 } 712 } 713 else { 714 if( strlen( pers->homephone ) > 0 ) { 715 printf(" Home phone: %s",pers->homephone); 716 } 717 if( strlen( pers->random ) > 0 ) { 718 printf( " %s", pers->random ); 719 } 720 } 721 } 722 else { 723 if( strlen( pers->officephone ) > 0 ) { 724 printf( "\nPhone: %s", pers->officephone ); 725 if( strlen( pers->homephone ) > 0 ) { 726 printf( "\n, %s", pers->homephone ); 727 if( strlen( pers->random ) > 0 ) { 728 printf( ", %s", pers->random ); 729 } 730 } 731 else { 732 if( strlen( pers->random ) > 0 ) { 733 printf( "\n, %s", pers->random ); 734 } 735 } 736 } 737 else { 738 if( strlen( pers->homephone ) > 0 ) { 739 printf( "\nPhone: %s", pers->homephone ); 740 if( strlen( pers->random ) > 0 ) { 741 printf( ", %s", pers->random ); 742 } 743 } 744 else { 745 if( strlen( pers->random ) > 0 ) { 746 printf( "\n%s", pers->random ); 747 } 748 } 749 } 750 } 751 if( unbrief ) { 752 printf( "\n" ); 753 printf( "Directory: %-25s", pwdt->pw_dir ); 754 if( strlen( pwdt->pw_shell ) > 0 ) { 755 printf( " Shell: %-s", pwdt->pw_shell ); 756 } 757 } 758 if( pers->loggedin ) { 759 register char *ep = ctime( &pers->loginat ); 760 printf("\nOn since %15.15s on %-*.*s ", &ep[4], LMAX, LMAX, pers->tty ); 761 idleprinted = ltimeprint( &pers->idletime ); 762 if( idleprinted ) { 763 printf( " Idle Time" ); 764 } 765 } 766 else { 767 register char *ep = ctime( &pers->loginat ); 768 printf("\nLast login %16.16s on %.*s", ep, LMAX, pers->tty ); 769 } 770 printf( "\n" ); 771 } 772 773 774 /* 775 * very hacky section of code to format phone numbers. filled with 776 * magic constants like 4, 7 and 10. 777 */ 778 779 char *phone( s, len ) 780 781 char *s; 782 int len; 783 { 784 char *strsave(); 785 char fonebuf[ 15 ]; 786 int i; 787 788 switch( len ) { 789 790 case 4: 791 fonebuf[ 0 ] = ' '; 792 fonebuf[ 1 ] = 'x'; 793 fonebuf[ 2 ] = '2'; 794 fonebuf[ 3 ] = '-'; 795 for( i = 0; i <= 3; i++ ) { 796 fonebuf[ 4 + i ] = *s++; 797 } 798 fonebuf[ 8 ] = NULL; 799 return( strsave( &fonebuf[0] ) ); 800 break; 801 802 case 7: 803 for( i = 0; i <= 2; i++ ) { 804 fonebuf[ i ] = *s++; 805 } 806 fonebuf[ 3 ] = '-'; 807 for( i = 0; i <= 3; i++ ) { 808 fonebuf[ 4 + i ] = *s++; 809 } 810 fonebuf[ 8 ] = NULL; 811 return( strsave( &fonebuf[0] ) ); 812 break; 813 814 case 10: 815 for( i = 0; i <= 2; i++ ) { 816 fonebuf[ i ] = *s++; 817 } 818 fonebuf[ 3 ] = '-'; 819 for( i = 0; i <= 2; i++ ) { 820 fonebuf[ 4 + i ] = *s++; 821 } 822 fonebuf[ 7 ] = '-'; 823 for( i = 0; i <= 3; i++ ) { 824 fonebuf[ 8 + i ] = *s++; 825 } 826 fonebuf[ 12 ] = NULL; 827 return( strsave( &fonebuf[0] ) ); 828 break; 829 830 default: 831 fprintf( stderr, "finger: error in phone numbering\n" ); 832 return( strsave(s) ); 833 break; 834 } 835 } 836 837 838 /* decode the information in the gecos field of /etc/passwd 839 * another hacky section of code, but given the format the stuff is in... 840 */ 841 842 decode( pers ) 843 844 struct person *pers; 845 846 { 847 struct passwd *pwdt = pers->pwd; 848 char buffer[ 40 ], *bp, *gp, *lp; 849 char *phone(); 850 int alldigits; 851 int len; 852 int i; 853 854 pers->realname = NULLSTR; 855 pers->office = NULLSTR; 856 pers->officephone = NULLSTR; 857 pers->homephone = NULLSTR; 858 pers->random = NULLSTR; 859 if( pwdt != NILPWD ) { 860 gp = pwdt->pw_gecos; 861 bp = &buffer[ 0 ]; 862 if( *gp == ASTERISK ) { 863 gp++; 864 } 865 while( (*gp != NULL) && (*gp != COMMA) ) { /* name */ 866 if( *gp == SAMENAME ) { 867 lp = pwdt->pw_name; 868 *bp++ = CAPITALIZE(*lp++); 869 while( *lp != NULL ) { 870 *bp++ = *lp++; 871 } 872 } 873 else { 874 *bp++ = *gp; 875 } 876 gp++; 877 } 878 *bp = NULL; 879 pers->realname = malloc( strlen( &buffer[0] ) + 1 ); 880 strcpy( pers->realname, &buffer[0] ); 881 if( *gp++ == COMMA ) { /* office, supposedly */ 882 alldigits = 1; 883 bp = &buffer[ 0 ]; 884 while( (*gp != NULL) && (*gp != COMMA) ) { 885 *bp = *gp++; 886 alldigits = alldigits && ('0' <= *bp) && (*bp <= '9'); 887 bp++; 888 } 889 *bp = NULL; 890 len = strlen( &buffer[0] ); 891 if( buffer[ len - 1 ] == CORY ) { 892 strcpy( &buffer[ len - 1 ], " Cory" ); 893 pers->office = malloc( len + 5 ); 894 strcpy( pers->office, &buffer[0] ); 895 } 896 else { 897 if( buffer[ len - 1 ] == EVANS ) { 898 strcpy( &buffer[ len - 1 ], " Evans" ); 899 pers->office = malloc( len + 6 ); 900 strcpy( pers->office, &buffer[0] ); 901 } 902 else { 903 if( buffer[ len - 1 ] == 'L' ) { 904 strcpy( &buffer[ len - 1 ], " LBL" ); 905 pers->office = malloc( len + 4 ); 906 strcpy( pers->office, &buffer[0] ); 907 } 908 else { 909 if( alldigits ) { 910 if( len == 4 ) { 911 pers->officephone = phone(&buffer[0], len); 912 } 913 else { 914 if( (len == 7) || (len == 10) ) { 915 pers->homephone = phone(&buffer[0],len); 916 } 917 } 918 } 919 else { 920 pers->random = malloc( len + 1 ); 921 strcpy( pers->random, &buffer[0] ); 922 } 923 } 924 } 925 } 926 if( *gp++ == COMMA ) { /* office phone, theoretically */ 927 bp = &buffer[ 0 ]; 928 alldigits = 1; 929 while( (*gp != NULL) && (*gp != COMMA) ) { 930 *bp = *gp++; 931 alldigits = alldigits && ('0' <= *bp) && (*bp <= '9'); 932 bp++; 933 } 934 *bp = NULL; 935 len = strlen( &buffer[0] ); 936 if( alldigits ) { 937 if( len != 4 ) { 938 if( (len == 7) || (len == 10) ) { 939 pers->homephone = phone( &buffer[0], len ); 940 } 941 else { 942 pers->random = malloc( len + 1 ); 943 strcpy( pers->random, &buffer[0] ); 944 } 945 } 946 else { 947 pers->officephone = phone( &buffer[0], len ); 948 } 949 } 950 else { 951 pers->random = malloc( len + 1 ); 952 strcpy( pers->random, &buffer[0] ); 953 } 954 if( *gp++ == COMMA ) { /* home phone?? */ 955 bp = &buffer[ 0 ]; 956 alldigits = 1; 957 while( (*gp != NULL) && (*gp != COMMA) ) { 958 *bp = *gp++; 959 alldigits = alldigits && ('0' <= *bp) && 960 (*bp <= '9'); 961 bp++; 962 } 963 *bp = NULL; 964 len = strlen( &buffer[0] ); 965 if( alldigits && ( (len == 7) || (len == 10) ) ) { 966 if( *pers->homephone != NULL ) { 967 pers->officephone = pers->homephone; 968 } 969 pers->homephone = phone( &buffer[0], len ); 970 } 971 else { 972 pers->random = malloc( strlen( &buffer[0] ) + 1 ); 973 strcpy( pers->random, &buffer[0] ); 974 } 975 } 976 } 977 } 978 if( pers->loggedin == 0 ) { 979 findwhen( pers ); 980 } 981 else { 982 findidle( pers ); 983 } 984 } 985 } 986 987 988 /* find the last log in of a user by checking the LASTLOG file. 989 * the entry is indexed by the uid, so this can only be done if 990 * the uid is known (which it isn't in quick mode) 991 */ 992 993 fwopen() 994 { 995 if( ( lf = open(LASTLOG, 0) ) >= 0 ) { 996 llopenerr = 0; 997 } 998 else { 999 fprintf( stderr, "finger: lastlog open error\n" ); 1000 llopenerr = 1; 1001 } 1002 } 1003 1004 1005 findwhen( pers ) 1006 1007 struct person *pers; 1008 { 1009 struct passwd *pwdt = pers->pwd; 1010 struct lastlog ll; 1011 int llsize = sizeof ll; 1012 int i; 1013 1014 if( !llopenerr ) { 1015 lseek( lf, pwdt->pw_uid*llsize, 0 ); 1016 if( read( lf, (char *) &ll, llsize ) == llsize ) { 1017 for( i = 0; i < LMAX; i++ ) { 1018 pers->tty[ i ] = ll.ll_line[ i ]; 1019 } 1020 pers->tty[ LMAX ] = NULL; 1021 pers->loginat = ll.ll_time; 1022 } 1023 else { 1024 fprintf( stderr, "finger: lastlog read error\n" ); 1025 pers->tty[ 0 ] = NULL; 1026 pers->loginat = 0L; 1027 } 1028 } 1029 else { 1030 pers->tty[ 0 ] = NULL; 1031 pers->loginat = 0L; 1032 } 1033 } 1034 1035 1036 fwclose() 1037 { 1038 if( !llopenerr ) { 1039 close( lf ); 1040 } 1041 } 1042 1043 1044 /* find the idle time of a user by doing a stat on /dev/histty, 1045 * where histty has been gotten from USERLOG, supposedly. 1046 */ 1047 1048 findidle( pers ) 1049 1050 struct person *pers; 1051 { 1052 struct stat ttystatus; 1053 struct passwd *pwdt = pers->pwd; 1054 char buffer[ 20 ]; 1055 char *TTY = "/dev/"; 1056 int TTYLEN = strlen( TTY ); 1057 int i; 1058 1059 strcpy( &buffer[0], TTY ); 1060 i = 0; 1061 do { 1062 buffer[ TTYLEN + i ] = pers->tty[ i ]; 1063 } while( ++i <= LMAX ); 1064 if( stat( &buffer[0], &ttystatus ) >= 0 ) { 1065 time( &tloc ); 1066 if( tloc < ttystatus.st_atime ) { 1067 pers->idletime = 0L; 1068 } 1069 else { 1070 pers->idletime = tloc - ttystatus.st_atime; 1071 } 1072 if( (ttystatus.st_mode & TALKABLE) == TALKABLE ) { 1073 pers->writeable = 1; 1074 } 1075 else { 1076 pers->writeable = 0; 1077 } 1078 } 1079 else { 1080 fprintf( stderr, "finger: error STATing %s\n", &buffer[0] ); 1081 exit( 4 ); 1082 } 1083 } 1084 1085 1086 /* print idle time in short format; this program always prints 4 characters; 1087 * if the idle time is zero, it prints 4 blanks. 1088 */ 1089 1090 stimeprint( dt ) 1091 1092 long *dt; 1093 { 1094 struct tm *gmtime(); 1095 struct tm *delta; 1096 1097 delta = gmtime( dt ); 1098 if( delta->tm_yday == 0 ) { 1099 if( delta->tm_hour == 0 ) { 1100 if( delta->tm_min >= 10 ) { 1101 printf( " %2.2d ", delta->tm_min ); 1102 } 1103 else { 1104 if( delta->tm_min == 0 ) { 1105 printf( " " ); 1106 } 1107 else { 1108 printf( " %1.1d ", delta->tm_min ); 1109 } 1110 } 1111 } 1112 else { 1113 if( delta->tm_hour >= 10 ) { 1114 printf( "%3.3d:", delta->tm_hour ); 1115 } 1116 else { 1117 printf( "%1.1d:%02.2d", delta->tm_hour, delta->tm_min ); 1118 } 1119 } 1120 } 1121 else { 1122 printf( "%3dd", delta->tm_yday ); 1123 } 1124 } 1125 1126 1127 /* print idle time in long format with care being taken not to pluralize 1128 * 1 minutes or 1 hours or 1 days. 1129 */ 1130 1131 ltimeprint( dt ) 1132 1133 long *dt; 1134 { 1135 struct tm *gmtime(); 1136 struct tm *delta; 1137 int printed = 1; 1138 1139 delta = gmtime( dt ); 1140 if( delta->tm_yday == 0 ) { 1141 if( delta->tm_hour == 0 ) { 1142 if( delta->tm_min >= 10 ) { 1143 printf( "%2d minutes", delta->tm_min ); 1144 } 1145 else { 1146 if( delta->tm_min == 0 ) { 1147 if( delta->tm_sec > 10 ) { 1148 printf( "%2d seconds", delta->tm_sec ); 1149 } 1150 else { 1151 printed = 0; 1152 } 1153 } 1154 else { 1155 if( delta->tm_min == 1 ) { 1156 if( delta->tm_sec == 1 ) { 1157 printf( "%1d minute %1d second", 1158 delta->tm_min, delta->tm_sec ); 1159 } 1160 else { 1161 printf( "%1d minute %d seconds", 1162 delta->tm_min, delta->tm_sec ); 1163 } 1164 } 1165 else { 1166 if( delta->tm_sec == 1 ) { 1167 printf( "%1d minutes %1d second", 1168 delta->tm_min, delta->tm_sec ); 1169 } 1170 else { 1171 printf( "%1d minutes %d seconds", 1172 delta->tm_min, delta->tm_sec ); 1173 } 1174 } 1175 } 1176 } 1177 } 1178 else { 1179 if( delta->tm_hour >= 10 ) { 1180 printf( "%2d hours", delta->tm_hour ); 1181 } 1182 else { 1183 if( delta->tm_hour == 1 ) { 1184 if( delta->tm_min == 1 ) { 1185 printf( "%1d hour %1d minute", 1186 delta->tm_hour, delta->tm_min ); 1187 } 1188 else { 1189 printf( "%1d hour %2d minutes", 1190 delta->tm_hour, delta->tm_min ); 1191 } 1192 } 1193 else { 1194 if( delta->tm_min == 1 ) { 1195 printf( "%1d hours %1d minute", 1196 delta->tm_hour, delta->tm_min ); 1197 } 1198 else { 1199 printf( "%1d hours %2d minutes", 1200 delta->tm_hour, delta->tm_min ); 1201 } 1202 } 1203 } 1204 } 1205 } 1206 else { 1207 if( delta->tm_yday >= 10 ) { 1208 printf( "%2d days", delta->tm_yday ); 1209 } 1210 else { 1211 if( delta->tm_yday == 1 ) { 1212 if( delta->tm_hour == 1 ) { 1213 printf( "%1d day %1d hour", 1214 delta->tm_yday, delta->tm_hour ); 1215 } 1216 else { 1217 printf( "%1d day %2d hours", 1218 delta->tm_yday, delta->tm_hour ); 1219 } 1220 } 1221 else { 1222 if( delta->tm_hour == 1 ) { 1223 printf( "%1d days %1d hour", 1224 delta->tm_yday, delta->tm_hour ); 1225 } 1226 else { 1227 printf( "%1d days %2d hours", 1228 delta->tm_yday, delta->tm_hour ); 1229 } 1230 } 1231 } 1232 } 1233 return( printed ); 1234 } 1235 1236 1237 matchcmp( gname, login, given ) 1238 1239 char *gname; 1240 char *login; 1241 char *given; 1242 { 1243 char buffer[ 20 ]; 1244 char c; 1245 int flag, i, unfound; 1246 1247 if( !match ) { 1248 return( 0 ); 1249 } 1250 else { 1251 if( namecmp( login, given ) ) { 1252 return( 1 ); 1253 } 1254 else { 1255 if( *gname == ASTERISK ) { 1256 gname++; 1257 } 1258 flag = 1; 1259 i = 0; 1260 unfound = 1; 1261 while( unfound ) { 1262 if( flag ) { 1263 c = *gname++; 1264 if( c == SAMENAME ) { 1265 flag = 0; 1266 c = *login++; 1267 } 1268 else { 1269 unfound = (*gname != COMMA) && (*gname != NULL); 1270 } 1271 } 1272 else { 1273 c = *login++; 1274 if( c == NULL ) { 1275 if( (*gname == COMMA) || (*gname == NULL) ) { 1276 break; 1277 } 1278 else { 1279 flag = 1; 1280 continue; 1281 } 1282 } 1283 } 1284 if( c == BLANK ) { 1285 buffer[i++] = NULL; 1286 if( namecmp( buffer, given ) ) { 1287 return( 1 ); 1288 } 1289 i = 0; 1290 flag = 1; 1291 } 1292 else { 1293 buffer[ i++ ] = c; 1294 } 1295 } 1296 buffer[i++] = NULL; 1297 if( namecmp( buffer, given ) ) { 1298 return( 1 ); 1299 } 1300 else { 1301 return( 0 ); 1302 } 1303 } 1304 } 1305 } 1306 1307 1308 namecmp( name1, name2 ) 1309 1310 char *name1; 1311 char *name2; 1312 { 1313 char c1, c2; 1314 1315 c1 = *name1; 1316 if( (('A' <= c1) && (c1 <= 'Z')) || (('a' <= c1) && (c1 <= 'z')) ) { 1317 c1 = CAPITALIZE( c1 ); 1318 } 1319 c2 = *name2; 1320 if( (('A' <= c2) && (c2 <= 'Z')) || (('a' <= c2) && (c2 <= 'z')) ) { 1321 c2 = CAPITALIZE( c2 ); 1322 } 1323 while( c1 == c2 ) { 1324 if( c1 == NULL ) { 1325 return( 1 ); 1326 } 1327 c1 = *++name1; 1328 if( (('A'<=c1) && (c1<='Z')) || (('a'<=c1) && (c1<='z')) ) { 1329 c1 = CAPITALIZE( c1 ); 1330 } 1331 c2 = *++name2; 1332 if( (('A'<=c2) && (c2<='Z')) || (('a'<=c2) && (c2<='z')) ) { 1333 c2 = CAPITALIZE( c2 ); 1334 } 1335 } 1336 if( *name1 == NULL ) { 1337 while( ('0' <= *name2) && (*name2 <= '9') ) { 1338 name2++; 1339 } 1340 if( *name2 == NULL ) { 1341 return( 1 ); 1342 } 1343 } 1344 else { 1345 if( *name2 == NULL ) { 1346 while( ('0' <= *name1) && (*name1 <= '9') ) { 1347 name1++; 1348 } 1349 if( *name1 == NULL ) { 1350 return( 1 ); 1351 } 1352 } 1353 } 1354 return( 0 ); 1355 } 1356 1357 1358 char *strsave( s ) 1359 1360 char *s; 1361 { 1362 char *malloc(); 1363 char *p; 1364 1365 p = malloc( strlen( s ) + 1 ); 1366 strcpy( p, s ); 1367 } 1368