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