X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/9b6a83a9cfde77dc51911934799fdfb1bbf16e60..f15db44997a25eaa5c7c6a3f8fdf294e67dc5557:/usr/src/usr.bin/finger/finger.c diff --git a/usr/src/usr.bin/finger/finger.c b/usr/src/usr.bin/finger/finger.c index 45fc1bfb95..170e05fab5 100644 --- a/usr/src/usr.bin/finger/finger.c +++ b/usr/src/usr.bin/finger/finger.c @@ -1,1375 +1,216 @@ -#ifndef lint -static char *sccsid = "@(#)finger.c 4.5 (Berkeley) %G%"; -#endif - -/* This is a finger program. It prints out useful information about users - * by digging it up from various system files. It is not very portable - * because the most useful parts of the information (the full user name, - * office, and phone numbers) are all stored in the VAX-unused gecos field - * of /etc/passwd, which, unfortunately, other UNIXes use for other things. - * - * There are three output formats, all of which give login name, teletype - * line number, and login time. The short output format is reminiscent - * of finger on ITS, and gives one line of information per user containing - * in addition to the minimum basic requirements (MBR), the full name of - * the user, his idle time and office location and phone number. The - * quick style output is UNIX who-like, giving only name, teletype and - * login time. Finally, the long style output give the same information - * as the short (in more legible format), the home directory and shell - * of the user, and, if it exits, a copy of the file .plan in the users - * home directory. Finger may be called with or without a list of people - * to finger -- if no list is given, all the people currently logged in - * are fingered. - * - * The program is validly called by one of the following: - * - * finger {short form list of users} - * finger -l {long form list of users} - * finger -b {briefer long form list of users} - * finger -q {quick list of users} - * finger -i {quick list of users with idle times} - * finger namelist {long format list of specified users} - * finger -s namelist {short format list of specified users} - * finger -w namelist {narrow short format list of specified users} +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. * - * where 'namelist' is a list of users login names. - * The other options can all be given after one '-', or each can have its - * own '-'. The -f option disables the printing of headers for short and - * quick outputs. The -b option briefens long format outputs. The -p - * option turns off plans for long format outputs. + * %sccs.include.redist.c% */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct utmp utmp; /* for sizeof */ -#define NMAX sizeof(utmp.ut_name) -#define LMAX sizeof(utmp.ut_line) - -#define ASTERISK '*' /* ignore this in real name */ -#define BLANK ' ' /* blank character (i.e. space) */ -#define CAPITALIZE 0137& /* capitalize character macro */ -#define COMMA ',' /* separator in pw_gecos field */ -#define COMMAND '-' /* command line flag char */ -#define CORY 'C' /* cory hall office */ -#define EVANS 'E' /* evans hall office */ -#define LINEBREAK 012 /* line feed */ -#define NULLSTR "" /* the null string, opposed to NULL */ -#define SAMENAME '&' /* repeat login name in real name */ -#define TALKABLE 0222 /* tty is writeable if 222 mode */ - -struct person { /* one for each person fingered */ - char name[NMAX+1]; /* login name */ - char tty[LMAX+1]; /* NULL terminated tty line */ - long loginat; /* time of login (possibly last) */ - long idletime; /* how long idle (if logged in) */ - short int loggedin; /* flag for being logged in */ - short int writeable; /* flag for tty being writeable */ - char *realname; /* pointer to full name */ - char *office; /* pointer to office name */ - char *officephone; /* pointer to office phone no. */ - char *homephone; /* pointer to home phone no. */ - char *random; /* for any random stuff in pw_gecos */ - struct passwd *pwd; /* structure of /etc/passwd stuff */ - struct person *link; /* link to next person */ -}; - -struct passwd *NILPWD = 0; -struct person *NILPERS = 0; - -int persize = sizeof( struct person ); -int pwdsize = sizeof( struct passwd ); - -char LASTLOG[] = "/usr/adm/lastlog"; /* last login info */ -char USERLOG[] = "/etc/utmp"; /* who is logged in */ -char outbuf[BUFSIZ]; /* output buffer */ -char *ctime(); - -int unbrief = 1; /* -b option default */ -int header = 1; /* -f option default */ -int hack = 1; /* -h option default */ -int idle = 0; /* -i option default */ -int large = 0; /* -l option default */ -int match = 1; /* -m option default */ -int plan = 1; /* -p option default */ -int unquick = 1; /* -q option default */ -int small = 0; /* -s option default */ -int wide = 1; /* -w option default */ - -int lf; -int llopenerr; - -long tloc; /* current time */ - - - -main( argc, argv ) - - int argc; - char *argv[]; - -{ - FILE *fp, *fopen(); /* for plans */ - struct passwd *getpwent(); /* read /etc/passwd */ - struct person *person1, *p, *pend; /* people */ - struct passwd *pw; /* temporary */ - struct utmp user; /* ditto */ - char *malloc(); - char *s, *pn, *ln; - char c; - char *PLAN = "/.plan"; /* what plan file is */ - char *PROJ = "/.project"; /* what project file */ - int PLANLEN = strlen( PLAN ); - int PROJLEN = strlen( PROJ ); - int numnames = 0; - int orgnumnames; - int uf; - int usize = sizeof user; - int unshort; - int i, j; - int fngrlogin; - - setbuf( stdout, outbuf ); /* buffer output */ - - /* parse command line for (optional) arguments */ - - i = 1; - if( strcmp( *argv, "sh" ) ) { - fngrlogin = 0; - while( i++ < argc && (*++argv)[0] == COMMAND ) { - for( s = argv[0] + 1; *s != NULL; s++ ) { - switch (*s) { - - case 'b': - unbrief = 0; - break; - - case 'f': - header = 0; - break; - - case 'h': - hack = 0; - break; - - case 'i': - idle = 1; - unquick = 0; - break; - - case 'l': - large = 1; - break; - - case 'm': - match = 0; - break; - - case 'p': - plan = 0; - break; - - case 'q': - unquick = 0; - break; - - case 's': - small = 1; - break; - - case 'w': - wide = 0; - break; - - default: - fprintf( stderr, "finger: Usage -- 'finger [-bfhilmpqsw] [login1 [login2 ...] ]'\n" ); - exit( 1 ); - } - } - } - } - else { - fngrlogin = 1; - } - if( unquick ) { - time( &tloc ); - } - else { - if( idle ) { - time( &tloc ); - } - } - - /* i > argc means no login names given so get them by reading USERLOG */ - - if( (i > argc) || fngrlogin ) { - unshort = large; - if( ( uf = open(USERLOG, 0) ) >= 0 ) { - user.ut_name[0] = NULL; - while( user.ut_name[0] == NULL ) { - if( read( uf, (char *) &user, usize ) != usize ) { - printf( "\nNo one logged on\n" ); - exit( 0 ); - } - } - person1 = (struct person *) malloc( persize ); - for( j = 0; j < NMAX; j++ ) { - person1->tty[j] = user.ut_line[j]; - person1->name[j] = user.ut_name[j]; - } - person1->name[NMAX] = NULL; - person1->tty[NMAX] = NULL; - person1->loginat = user.ut_time; - person1->pwd = NILPWD; - person1->loggedin = 1; - numnames++; - p = person1; - while( read( uf, (char *) &user, usize ) == usize ) { - if( user.ut_name[0] == NULL ) continue; - p->link = (struct person *) malloc( persize ); - p = p->link; - for( j = 0; j < NMAX; j++ ) { - p->tty[j] = user.ut_line[j]; - p->name[j] = user.ut_name[j]; - } - p->name[NMAX] = NULL; - p->tty[NMAX] = NULL; - p->loginat = user.ut_time; - p->pwd = NILPWD; - p->loggedin = 1; - numnames++; - } - p->link = NILPERS; - close( uf ); - } - else { - fprintf( stderr, "finger: error opening %s\n", USERLOG ); - exit( 2 ); - } - - /* if we are doing it, read /etc/passwd for the useful info */ - - if( unquick ) { - setpwent(); - fwopen(); - i = numnames; - while( ( (pw = getpwent()) != NILPWD ) && ( i > 0 ) ) { - p = person1; - do { - if( p->pwd == NILPWD ) { - if( strcmp( p->name, pw->pw_name ) == 0 ) { - p->pwd = (struct passwd *) malloc( pwdsize ); - pwdcopy( p->pwd, pw ); - decode( p ); - i--; - } - } - p = p->link; - } while( p != NILPERS ); - } - fwclose(); - endpwent(); - } - } - - /* get names from command line and check to see if they're logged in */ - - else { - unshort = ( small == 1 ? 0 : 1 ); - i++; - person1 = (struct person *) malloc( persize ); - strcpy( person1->name, (argv++)[ 0 ] ); - person1->loggedin = 0; - person1->pwd = NILPWD; - numnames++; - p = person1; - while( i++ <= argc ) { - p->link = (struct person *) malloc( persize ); - p = p->link; - strcpy( p->name, (argv++)[ 0 ] ); - p->loggedin = 0; - p->pwd = NILPWD; - numnames++; - } - p->link = NILPERS; - pend = p; - - /* if we are doing it, read /etc/passwd for the useful info */ - - orgnumnames = numnames; - if( unquick ) { - setpwent(); - while( ( pw = getpwent() ) != NILPWD ) { - p = person1; - i = 0; - do { - if( strcmp( p->name, pw->pw_name ) == 0 || - matchcmp( pw->pw_gecos, pw->pw_name, p->name ) ) { - if( p->pwd == NILPWD ) { - p->pwd = (struct passwd *) malloc( pwdsize ); - pwdcopy( p->pwd, pw ); - } - else { /* handle multiple logins -- append new - "duplicate" entry to end of list */ - pend->link = (struct person *) malloc(persize); - pend = pend->link; - pend->link = NILPERS; - strcpy( pend->name, p->name ); - pend->pwd = (struct passwd *) malloc(pwdsize); - pwdcopy( pend->pwd, pw ); - numnames++; - } - } - p = p->link; - } while( ++i < orgnumnames ); - } - endpwent(); - } - - /* Now get login information */ - - if( ( uf = open(USERLOG, 0) ) >= 0 ) { - while( read( uf, (char *) &user, usize ) == usize ) { - if( user.ut_name[0] == NULL ) continue; - p = person1; - do { - pw = p->pwd; - if( pw == NILPWD ) { - i = ( strcmp( p->name, user.ut_name ) ? 0 : NMAX ); - } - else { - i = 0; - while( (i < NMAX) && - ( pw->pw_name[i] == user.ut_name[i]) ) { - if( pw->pw_name[i] == NULL ) { - i = NMAX; - break; - } - i++; - } - } - if( i == NMAX ) { - if( p->loggedin == 1 ) { - pend->link = (struct person *) malloc(persize); - pend = pend->link; - pend->link = NILPERS; - strcpy( pend->name, p->name ); - for( j = 0; j < NMAX; j++ ) { - pend->tty[j] = user.ut_line[j]; - } - pend->tty[ NMAX ] = NULL; - pend->loginat = user.ut_time; - pend->loggedin = 2; - if( pw == NILPWD ) { - pend ->pwd = NILPWD; - } - else { - pend->pwd = (struct passwd *) malloc(pwdsize); - pwdcopy( pend->pwd, pw ); - } - numnames++; - } - else { - if( p->loggedin != 2 ) { - for( j = 0; j < NMAX; j++ ) { - p->tty[j] = user.ut_line[j]; - } - p->tty[ NMAX ] = NULL; - p->loginat = user.ut_time; - p->loggedin = 1; - } - } - } - p = p->link; - } while( p != NILPERS ); - } - fwopen(); - p = person1; - while( p != NILPERS ) { - if( p->loggedin == 2 ) { - p->loggedin = 1; - } - decode( p ); - p = p->link; - } - fwclose(); - close( uf ); - } - else { - fprintf( stderr, "finger: error opening %s\n", USERLOG ); - exit( 2 ); - } - } - - /* print out what we got */ - - if( header ) { - if( unquick ) { - if( !unshort ) { - if( wide ) { - printf( -"Login Name TTY Idle When Office\n" ); - } - else { - printf( -"Login TTY Idle When Office\n" ); - } - } - } - else { - printf( "Login TTY When" ); - if( idle ) { - printf( " Idle" ); - } - printf( "\n" ); - } - } - p = person1; - do { - if( unquick ) { - if( unshort ) { - personprint( p ); - if( p->pwd != NILPWD ) { - if( hack ) { - s = malloc(strlen((p->pwd)->pw_dir) + PROJLEN + 1 ); - strcpy( s, (p->pwd)->pw_dir ); - strcat( s, PROJ ); - if( ( fp = fopen( s, "r") ) != NULL ) { - printf( "Project: " ); - while( ( c = getc(fp) ) != EOF ) { - if( c == LINEBREAK ) { - break; - } - putc( c, stdout ); - } - fclose( fp ); - printf( "\n" ); - } - } - if( plan ) { - s = malloc( strlen( (p->pwd)->pw_dir ) + PLANLEN + 1 ); - strcpy( s, (p->pwd)->pw_dir ); - strcat( s, PLAN ); - if( ( fp = fopen( s, "r") ) == NULL ) { - printf( "No Plan.\n" ); - } - else { - printf( "Plan:\n" ); - while( ( c = getc(fp) ) != EOF ) { - putc( c, stdout ); - } - fclose( fp ); - } - } - } - if( p->link != NILPERS ) { - printf( "\n" ); - } - } - else { - shortprint( p ); - } - } - else { - quickprint( p ); - } - p = p->link; - } while( p != NILPERS ); - exit(0); -} - - -/* given a pointer to a pwd (pfrom) copy it to another one, allocating - * space for all the stuff in it. Note: Only the useful (what the - * program currently uses) things are copied. - */ - -pwdcopy( pto, pfrom ) /* copy relevant fields only */ - - struct passwd *pto, *pfrom; -{ - pto->pw_name = malloc( strlen( pfrom->pw_name ) + 1 ); - strcpy( pto->pw_name, pfrom->pw_name ); - pto->pw_uid = pfrom->pw_uid; - pto->pw_gecos = malloc( strlen( pfrom->pw_gecos ) + 1 ); - strcpy( pto->pw_gecos, pfrom->pw_gecos ); - pto->pw_dir = malloc( strlen( pfrom->pw_dir ) + 1 ); - strcpy( pto->pw_dir, pfrom->pw_dir ); - pto->pw_shell = malloc( strlen( pfrom->pw_shell ) + 1 ); - strcpy( pto->pw_shell, pfrom->pw_shell ); -} - - -/* print out information on quick format giving just name, tty, login time - * and idle time if idle is set. - */ - -quickprint( pers ) - - struct person *pers; -{ - int idleprinted; - - printf( "%-*.*s", NMAX, NMAX, pers->name ); - printf( " " ); - if( pers->loggedin ) { - if( idle ) { - findidle( pers ); - if( pers->writeable ) { - printf( " %-*.*s %-16.16s", LMAX, LMAX, - pers->tty, ctime( &pers->loginat ) ); - } - else { - printf( "*%-*.*s %-16.16s", LMAX, LMAX, - pers->tty, ctime( &pers->loginat ) ); - } - printf( " " ); - idleprinted = ltimeprint( &pers->idletime ); - } - else { - printf( " %-*.*s %-16.16s", LMAX, LMAX, - pers->tty, ctime( &pers->loginat ) ); - } - } - else { - printf( " Not Logged In" ); - } - printf( "\n" ); -} - - -/* print out information in short format, giving login name, full name, - * tty, idle time, login time, office location and phone. - */ - -shortprint( pers ) - - struct person *pers; - -{ - struct passwd *pwdt = pers->pwd; - char buf[ 26 ]; - int i, len, offset, dialup; - - if( pwdt == NILPWD ) { - printf( "%-*.*s", NMAX, NMAX, pers->name ); - printf( " ???\n" ); - return; - } - printf( "%-*.*s", NMAX, NMAX, pwdt->pw_name ); - dialup = 0; - if( wide ) { - if( strlen( pers->realname ) > 0 ) { - printf( " %-20.20s", pers->realname ); - } - else { - printf( " ??? " ); - } - } - if( pers->loggedin ) { - if( pers->writeable ) { - printf( " " ); - } - else { - printf( " *" ); - } - } - else { - printf( " " ); - } - if( strlen( pers->tty ) > 0 ) { - strcpy( buf, pers->tty ); - if( (buf[0] == 't') && (buf[1] == 't') && (buf[2] == 'y') ) { - offset = 3; - for( i = 0; i < 2; i++ ) { - buf[i] = buf[i + offset]; - } - } - if( (buf[0] == 'd') && pers->loggedin ) { - dialup = 1; - } - printf( "%-2.2s ", buf ); - } - else { - printf( " " ); - } - strcpy(buf, ctime(&pers->loginat)); - if( pers->loggedin ) { - stimeprint( &pers->idletime ); - offset = 7; - for( i = 4; i < 19; i++ ) { - buf[i] = buf[i + offset]; - } - printf( " %-9.9s ", buf ); - } - else if (pers->loginat == 0) - printf(" < . . . . >"); - else if (tloc - pers->loginat >= 180 * 24 * 60 * 60) - printf( " <%-6.6s, %-4.4s>", buf+4, buf+20 ); - else - printf(" <%-12.12s>", buf+4); - len = strlen( pers->homephone ); - if( dialup && (len > 0) ) { - if( len == 8 ) { - printf( " " ); - } - else { - if( len == 12 ) { - printf( " " ); - } - else { - for( i = 1; i <= 21 - len; i++ ) { - printf( " " ); - } - } - } - printf( "%s", pers->homephone ); - } - else { - if( strlen( pers->office ) > 0 ) { - printf( " %-11.11s", pers->office ); - if( strlen( pers->officephone ) > 0 ) { - printf( " %8.8s", pers->officephone ); - } - else { - if( len == 8 ) { - printf( " %8.8s", pers->homephone ); - } - } - } - else { - if( strlen( pers->officephone ) > 0 ) { - printf( " %8.8s", pers->officephone ); - } - else { - if( len == 8 ) { - printf( " %8.8s", pers->homephone ); - } - else { - if( len == 12 ) { - printf( " %12.12s", pers->homephone ); - } - } - } - } - } - printf( "\n" ); -} - - -/* print out a person in long format giving all possible information. - * directory and shell are inhibited if unbrief is clear. - */ - -personprint( pers ) - - struct person *pers; -{ - struct passwd *pwdt = pers->pwd; - int idleprinted; - - if( pwdt == NILPWD ) { - printf( "Login name: %-10s", pers->name ); - printf( " " ); - printf( "In real life: ???\n"); - return; - } - printf( "Login name: %-10s", pwdt->pw_name ); - if( pers->loggedin ) { - if( pers->writeable ) { - printf( " " ); - } - else { - printf( " (messages off) " ); - } - } - else { - printf( " " ); - } - if( strlen( pers->realname ) > 0 ) { - printf( "In real life: %-s", pers->realname ); - } - if( strlen( pers->office ) > 0 ) { - printf( "\nOffice: %-.11s", pers->office ); - if( strlen( pers->officephone ) > 0 ) { - printf( ", %s", pers->officephone ); - if( strlen( pers->homephone ) > 0 ) { - printf( " Home phone: %s", pers->homephone ); - } - else { - if( strlen( pers->random ) > 0 ) { - printf( " %s", pers->random ); - } - } - } - else { - if( strlen( pers->homephone ) > 0 ) { - printf(" Home phone: %s",pers->homephone); - } - if( strlen( pers->random ) > 0 ) { - printf( " %s", pers->random ); - } - } - } - else { - if( strlen( pers->officephone ) > 0 ) { - printf( "\nPhone: %s", pers->officephone ); - if( strlen( pers->homephone ) > 0 ) { - printf( "\n, %s", pers->homephone ); - if( strlen( pers->random ) > 0 ) { - printf( ", %s", pers->random ); - } - } - else { - if( strlen( pers->random ) > 0 ) { - printf( "\n, %s", pers->random ); - } - } - } - else { - if( strlen( pers->homephone ) > 0 ) { - printf( "\nPhone: %s", pers->homephone ); - if( strlen( pers->random ) > 0 ) { - printf( ", %s", pers->random ); - } - } - else { - if( strlen( pers->random ) > 0 ) { - printf( "\n%s", pers->random ); - } - } - } - } - if( unbrief ) { - printf( "\n" ); - printf( "Directory: %-25s", pwdt->pw_dir ); - if( strlen( pwdt->pw_shell ) > 0 ) { - printf( " Shell: %-s", pwdt->pw_shell ); - } - } - if( pers->loggedin ) { - register char *ep = ctime( &pers->loginat ); - printf("\nOn since %15.15s on %-*.*s ", &ep[4], LMAX, LMAX, pers->tty ); - idleprinted = ltimeprint( &pers->idletime ); - if( idleprinted ) { - printf( " Idle Time" ); - } - } - else if (pers->loginat == 0) - printf("\nNever logged in."); - else if (tloc - pers->loginat > 180 * 24 * 60 * 60) { - register char *ep = ctime( &pers->loginat ); - printf("\nLast login %10.10s, %4.4s on %.*s", ep, ep+20, LMAX, pers->tty); - } - else { - register char *ep = ctime( &pers->loginat ); - printf("\nLast login %16.16s on %.*s", ep, LMAX, pers->tty ); - } - printf( "\n" ); -} +#ifndef lint +char copyright[] = +"@(#) Copyright (c) 1989 The Regents of the University of California.\n\ + All rights reserved.\n"; +#endif /* not lint */ +#ifndef lint +static char sccsid[] = "@(#)finger.c 5.20 (Berkeley) %G%"; +#endif /* not lint */ /* - * very hacky section of code to format phone numbers. filled with - * magic constants like 4, 7 and 10. - */ - -char *phone( s, len ) - - char *s; - int len; -{ - char *strsave(); - char fonebuf[ 15 ]; - int i; - - switch( len ) { - - case 4: - fonebuf[ 0 ] = ' '; - fonebuf[ 1 ] = 'x'; - fonebuf[ 2 ] = '2'; - fonebuf[ 3 ] = '-'; - for( i = 0; i <= 3; i++ ) { - fonebuf[ 4 + i ] = *s++; - } - fonebuf[ 8 ] = NULL; - return( strsave( &fonebuf[0] ) ); - break; - - case 7: - for( i = 0; i <= 2; i++ ) { - fonebuf[ i ] = *s++; - } - fonebuf[ 3 ] = '-'; - for( i = 0; i <= 3; i++ ) { - fonebuf[ 4 + i ] = *s++; - } - fonebuf[ 8 ] = NULL; - return( strsave( &fonebuf[0] ) ); - break; - - case 10: - for( i = 0; i <= 2; i++ ) { - fonebuf[ i ] = *s++; - } - fonebuf[ 3 ] = '-'; - for( i = 0; i <= 2; i++ ) { - fonebuf[ 4 + i ] = *s++; - } - fonebuf[ 7 ] = '-'; - for( i = 0; i <= 3; i++ ) { - fonebuf[ 8 + i ] = *s++; - } - fonebuf[ 12 ] = NULL; - return( strsave( &fonebuf[0] ) ); - break; - - default: - fprintf( stderr, "finger: error in phone numbering\n" ); - return( strsave(s) ); - break; - } -} - - -/* decode the information in the gecos field of /etc/passwd - * another hacky section of code, but given the format the stuff is in... - */ - -decode( pers ) - - struct person *pers; - -{ - struct passwd *pwdt = pers->pwd; - char buffer[ 256 ], *bp, *gp, *lp; - char *phone(); - int alldigits; - int len; - int i; - - pers->realname = NULLSTR; - pers->office = NULLSTR; - pers->officephone = NULLSTR; - pers->homephone = NULLSTR; - pers->random = NULLSTR; - if( pwdt != NILPWD ) { - gp = pwdt->pw_gecos; - bp = &buffer[ 0 ]; - if( *gp == ASTERISK ) { - gp++; - } - while( (*gp != NULL) && (*gp != COMMA) ) { /* name */ - if( *gp == SAMENAME ) { - lp = pwdt->pw_name; - *bp++ = CAPITALIZE(*lp++); - while( *lp != NULL ) { - *bp++ = *lp++; - } - } - else { - *bp++ = *gp; - } - gp++; - } - *bp = NULL; - pers->realname = malloc( strlen( &buffer[0] ) + 1 ); - strcpy( pers->realname, &buffer[0] ); - if( *gp++ == COMMA ) { /* office, supposedly */ - alldigits = 1; - bp = &buffer[ 0 ]; - while( (*gp != NULL) && (*gp != COMMA) ) { - *bp = *gp++; - alldigits = alldigits && ('0' <= *bp) && (*bp <= '9'); - bp++; - } - *bp = NULL; - len = strlen( &buffer[0] ); - if( buffer[ len - 1 ] == CORY ) { - strcpy( &buffer[ len - 1 ], " Cory" ); - pers->office = malloc( len + 5 ); - strcpy( pers->office, &buffer[0] ); - } - else { - if( buffer[ len - 1 ] == EVANS ) { - strcpy( &buffer[ len - 1 ], " Evans" ); - pers->office = malloc( len + 6 ); - strcpy( pers->office, &buffer[0] ); - } - else { - if( buffer[ len - 1 ] == 'L' ) { - strcpy( &buffer[ len - 1 ], " LBL" ); - pers->office = malloc( len + 4 ); - strcpy( pers->office, &buffer[0] ); - } - else { - if( alldigits ) { - if( len == 4 ) { - pers->officephone = phone(&buffer[0], len); - } - else { - if( (len == 7) || (len == 10) ) { - pers->homephone = phone(&buffer[0],len); - } - } - } - else { - pers->random = malloc( len + 1 ); - strcpy( pers->random, &buffer[0] ); - } - } - } - } - if( *gp++ == COMMA ) { /* office phone, theoretically */ - bp = &buffer[ 0 ]; - alldigits = 1; - while( (*gp != NULL) && (*gp != COMMA) ) { - *bp = *gp++; - alldigits = alldigits && ('0' <= *bp) && (*bp <= '9'); - bp++; - } - *bp = NULL; - len = strlen( &buffer[0] ); - if( alldigits ) { - if( len != 4 ) { - if( (len == 7) || (len == 10) ) { - pers->homephone = phone( &buffer[0], len ); - } - else { - pers->random = malloc( len + 1 ); - strcpy( pers->random, &buffer[0] ); - } - } - else { - pers->officephone = phone( &buffer[0], len ); - } - } - else { - pers->random = malloc( len + 1 ); - strcpy( pers->random, &buffer[0] ); - } - if( *gp++ == COMMA ) { /* home phone?? */ - bp = &buffer[ 0 ]; - alldigits = 1; - while( (*gp != NULL) && (*gp != COMMA) ) { - *bp = *gp++; - alldigits = alldigits && ('0' <= *bp) && - (*bp <= '9'); - bp++; - } - *bp = NULL; - len = strlen( &buffer[0] ); - if( alldigits && ( (len == 7) || (len == 10) ) ) { - if( *pers->homephone != NULL ) { - pers->officephone = pers->homephone; - } - pers->homephone = phone( &buffer[0], len ); - } - else { - pers->random = malloc( strlen( &buffer[0] ) + 1 ); - strcpy( pers->random, &buffer[0] ); - } - } - } - } - if( pers->loggedin == 0 ) { - findwhen( pers ); - } - else { - findidle( pers ); - } - } -} - - -/* find the last log in of a user by checking the LASTLOG file. - * the entry is indexed by the uid, so this can only be done if - * the uid is known (which it isn't in quick mode) - */ - -fwopen() -{ - if( ( lf = open(LASTLOG, 0) ) >= 0 ) { - llopenerr = 0; - } - else { - fprintf( stderr, "finger: lastlog open error\n" ); - llopenerr = 1; - } -} - - -findwhen( pers ) - - struct person *pers; -{ - struct passwd *pwdt = pers->pwd; - struct lastlog ll; - int llsize = sizeof ll; - int i; - - if( !llopenerr ) { - lseek( lf, pwdt->pw_uid*llsize, 0 ); - if ((i = read( lf, (char *) &ll, llsize )) == llsize) { - for( i = 0; i < LMAX; i++ ) { - pers->tty[ i ] = ll.ll_line[ i ]; - } - pers->tty[ LMAX ] = NULL; - pers->loginat = ll.ll_time; - } - else { - if (i != 0) - fprintf(stderr, "finger: lastlog read error\n"); - pers->tty[ 0 ] = NULL; - pers->loginat = 0L; - } - } - else { - pers->tty[ 0 ] = NULL; - pers->loginat = 0L; - } -} - - -fwclose() -{ - if( !llopenerr ) { - close( lf ); - } -} - - -/* find the idle time of a user by doing a stat on /dev/histty, - * where histty has been gotten from USERLOG, supposedly. - */ - -findidle( pers ) - - struct person *pers; -{ - struct stat ttystatus; - struct passwd *pwdt = pers->pwd; - char buffer[ 20 ]; - char *TTY = "/dev/"; - int TTYLEN = strlen( TTY ); - int i; - - strcpy( &buffer[0], TTY ); - i = 0; - do { - buffer[ TTYLEN + i ] = pers->tty[ i ]; - } while( ++i <= LMAX ); - if( stat( &buffer[0], &ttystatus ) >= 0 ) { - time( &tloc ); - if( tloc < ttystatus.st_atime ) { - pers->idletime = 0L; - } - else { - pers->idletime = tloc - ttystatus.st_atime; - } - if( (ttystatus.st_mode & TALKABLE) == TALKABLE ) { - pers->writeable = 1; - } - else { - pers->writeable = 0; - } - } - else { - fprintf( stderr, "finger: error STATing %s\n", &buffer[0] ); - exit( 4 ); - } -} - - -/* print idle time in short format; this program always prints 4 characters; - * if the idle time is zero, it prints 4 blanks. - */ - -stimeprint( dt ) - - long *dt; -{ - struct tm *gmtime(); - struct tm *delta; - - delta = gmtime( dt ); - if( delta->tm_yday == 0 ) { - if( delta->tm_hour == 0 ) { - if( delta->tm_min >= 10 ) { - printf( " %2.2d ", delta->tm_min ); - } - else { - if( delta->tm_min == 0 ) { - printf( " " ); - } - else { - printf( " %1.1d ", delta->tm_min ); - } - } - } - else { - if( delta->tm_hour >= 10 ) { - printf( "%3.3d:", delta->tm_hour ); - } - else { - printf( "%1.1d:%02.2d", delta->tm_hour, delta->tm_min ); - } - } - } - else { - printf( "%3dd", delta->tm_yday ); - } -} - - -/* print idle time in long format with care being taken not to pluralize - * 1 minutes or 1 hours or 1 days. + * Finger prints out information about users. It is not portable since + * certain fields (e.g. the full user name, office, and phone numbers) are + * extracted from the gecos field of the passwd file which other UNIXes + * may not have or may use for other things. + * + * There are currently two output formats; the short format is one line + * per user and displays login name, tty, login time, real name, idle time, + * and office location/phone number. The long format gives the same + * information (in a more legible format) as well as home directory, shell, + * mail info, and .plan/.project files. */ -ltimeprint( dt ) - - long *dt; -{ - struct tm *gmtime(); - struct tm *delta; - int printed = 1; - - delta = gmtime( dt ); - if( delta->tm_yday == 0 ) { - if( delta->tm_hour == 0 ) { - if( delta->tm_min >= 10 ) { - printf( "%2d minutes", delta->tm_min ); - } - else { - if( delta->tm_min == 0 ) { - if( delta->tm_sec > 10 ) { - printf( "%2d seconds", delta->tm_sec ); - } - else { - printed = 0; - } - } - else { - if( delta->tm_min == 1 ) { - if( delta->tm_sec == 1 ) { - printf( "%1d minute %1d second", - delta->tm_min, delta->tm_sec ); - } - else { - printf( "%1d minute %d seconds", - delta->tm_min, delta->tm_sec ); - } - } - else { - if( delta->tm_sec == 1 ) { - printf( "%1d minutes %1d second", - delta->tm_min, delta->tm_sec ); - } - else { - printf( "%1d minutes %d seconds", - delta->tm_min, delta->tm_sec ); - } - } - } - } - } - else { - if( delta->tm_hour >= 10 ) { - printf( "%2d hours", delta->tm_hour ); - } - else { - if( delta->tm_hour == 1 ) { - if( delta->tm_min == 1 ) { - printf( "%1d hour %1d minute", - delta->tm_hour, delta->tm_min ); - } - else { - printf( "%1d hour %2d minutes", - delta->tm_hour, delta->tm_min ); - } - } - else { - if( delta->tm_min == 1 ) { - printf( "%1d hours %1d minute", - delta->tm_hour, delta->tm_min ); - } - else { - printf( "%1d hours %2d minutes", - delta->tm_hour, delta->tm_min ); - } - } - } - } - } - else { - if( delta->tm_yday >= 10 ) { - printf( "%2d days", delta->tm_yday ); - } - else { - if( delta->tm_yday == 1 ) { - if( delta->tm_hour == 1 ) { - printf( "%1d day %1d hour", - delta->tm_yday, delta->tm_hour ); - } - else { - printf( "%1d day %2d hours", - delta->tm_yday, delta->tm_hour ); - } - } - else { - if( delta->tm_hour == 1 ) { - printf( "%1d days %1d hour", - delta->tm_yday, delta->tm_hour ); - } - else { - printf( "%1d days %2d hours", - delta->tm_yday, delta->tm_hour ); - } - } - } +#include +#include +#include +#include "finger.h" +#include "pathnames.h" + +time_t now; +int lflag, sflag, mflag, pplan; +char tbuf[1024]; + +main(argc, argv) + int argc; + char **argv; +{ + extern int optind; + int ch; + time_t time(); + + while ((ch = getopt(argc, argv, "lmps")) != EOF) + switch(ch) { + case 'l': + lflag = 1; /* long format */ + break; + case 'm': + mflag = 1; /* force exact match of names */ + break; + case 'p': + pplan = 1; /* don't show .plan/.project */ + break; + case 's': + sflag = 1; /* short format */ + break; + case '?': + default: + (void)fprintf(stderr, + "usage: finger [-lmps] [login ...]\n"); + exit(1); + } + argc -= optind; + argv += optind; + + (void)time(&now); + setpassent(1); + if (!*argv) { + /* + * Assign explicit "small" format if no names given and -l + * not selected. Force the -s BEFORE we get names so proper + * screening will be done. + */ + if (!lflag) + sflag = 1; /* if -l not explicit, force -s */ + loginlist(); + if (entries == 0) + (void)printf("No one logged on.\n"); + } else { + userlist(argc, argv); + /* + * Assign explicit "large" format if names given and -s not + * explicitly stated. Force the -l AFTER we get names so any + * remote finger attempts specified won't be mishandled. + */ + if (!sflag) + lflag = 1; /* if -s not explicit, force -l */ + } + if (entries != 0) { + if (lflag) + lflag_print(); + else + sflag_print(); } - return( printed ); + exit(0); } - -matchcmp( gname, login, given ) - - char *gname; - char *login; - char *given; +loginlist() { - char buffer[ 20 ]; - char c; - int flag, i, unfound; + register PERSON *pn; + struct passwd *pw; + struct utmp user; + char name[UT_NAMESIZE + 1]; - if( !match ) { - return( 0 ); + if (!freopen(_PATH_UTMP, "r", stdin)) { + (void)fprintf(stderr, "finger: can't read %s.\n", _PATH_UTMP); + exit(2); } - else { - if( namecmp( login, given ) ) { - return( 1 ); - } - else if (*gname == '\0') - return (0); - else { - if( *gname == ASTERISK ) { - gname++; - } - flag = 1; - i = 0; - unfound = 1; - while( unfound ) { - if( flag ) { - c = *gname++; - if( c == SAMENAME ) { - flag = 0; - c = *login++; - } - else { - unfound = (*gname != COMMA) && (*gname != NULL); - } - } - else { - c = *login++; - if( c == NULL ) { - if( (*gname == COMMA) || (*gname == NULL) ) { - break; - } - else { - flag = 1; + name[UT_NAMESIZE] = NULL; + while (fread((char *)&user, sizeof(user), 1, stdin) == 1) { + if (!user.ut_name[0]) + continue; + if ((pn = find_person(user.ut_name)) == NULL) { + bcopy(user.ut_name, name, UT_NAMESIZE); + if ((pw = getpwnam(name)) == NULL) continue; - } - } - } - if( c == BLANK ) { - buffer[i++] = NULL; - if( namecmp( buffer, given ) ) { - return( 1 ); - } - i = 0; - flag = 1; - } - else { - buffer[ i++ ] = c; - } - } - buffer[i++] = NULL; - if( namecmp( buffer, given ) ) { - return( 1 ); - } - else { - return( 0 ); - } - } - } -} - - -namecmp( name1, name2 ) - - char *name1; - char *name2; -{ - char c1, c2; - - c1 = *name1; - if( (('A' <= c1) && (c1 <= 'Z')) || (('a' <= c1) && (c1 <= 'z')) ) { - c1 = CAPITALIZE( c1 ); - } - c2 = *name2; - if( (('A' <= c2) && (c2 <= 'Z')) || (('a' <= c2) && (c2 <= 'z')) ) { - c2 = CAPITALIZE( c2 ); - } - while( c1 == c2 ) { - if( c1 == NULL ) { - return( 1 ); - } - c1 = *++name1; - if( (('A'<=c1) && (c1<='Z')) || (('a'<=c1) && (c1<='z')) ) { - c1 = CAPITALIZE( c1 ); - } - c2 = *++name2; - if( (('A'<=c2) && (c2<='Z')) || (('a'<=c2) && (c2<='z')) ) { - c2 = CAPITALIZE( c2 ); - } - } - if( *name1 == NULL ) { - while( ('0' <= *name2) && (*name2 <= '9') ) { - name2++; - } - if( *name2 == NULL ) { - return( 1 ); - } - } - else { - if( *name2 == NULL ) { - while( ('0' <= *name1) && (*name1 <= '9') ) { - name1++; - } - if( *name1 == NULL ) { - return( 1 ); - } - } - } - return( 0 ); -} - - -char *strsave( s ) - - char *s; -{ - char *malloc(); - char *p; - - p = malloc( strlen( s ) + 1 ); - strcpy( p, s ); + pn = enter_person(pw); + } + enter_where(&user, pn); + } + for (pn = phead; lflag && pn != NULL; pn = pn->next) + enter_lastlog(pn); +} + +userlist(argc, argv) + register argc; + register char **argv; +{ + register i; + register PERSON *pn; + PERSON *nethead; + struct utmp user; + struct passwd *pw; + int dolocal, *used; + char *index(); + + if (!(used = (int *)calloc((u_int)argc, (u_int)sizeof(int)))) { + (void)fprintf(stderr, "finger: out of space.\n"); + exit(1); + } + + /* pull out all network requests */ + for (i = 0, dolocal = 0, nethead = NULL; i < argc; i++) { + if (!index(argv[i], '@')) { + dolocal = 1; + continue; + } + pn = palloc(); + pn->next = nethead; + nethead = pn; + pn->name = argv[i]; + used[i] = -1; + } + + if (!dolocal) + goto net; + + /* + * traverse the list of possible login names and check the login name + * and real name against the name specified by the user. + */ + if (mflag) { + for (i = 0; i < argc; i++) + if (used[i] >= 0 && (pw = getpwnam(argv[i]))) { + enter_person(pw); + used[i] = 1; + } + } else while (pw = getpwent()) + for (i = 0; i < argc; i++) + if (used[i] >= 0 && + (!strcasecmp(pw->pw_name, argv[i]) || + match(pw, argv[i]))) { + enter_person(pw); + used[i] = 1; + } + + /* list errors */ + for (i = 0; i < argc; i++) + if (!used[i]) + (void)fprintf(stderr, + "finger: %s: no such user.\n", argv[i]); + + /* handle network requests */ +net: for (pn = nethead; pn; pn = pn->next) { + netfinger(pn->name); + if (pn->next || entries) + putchar('\n'); + } + + if (entries == 0) + return; + + /* + * Scan thru the list of users currently logged in, saving + * appropriate data whenever a match occurs. + */ + if (!freopen(_PATH_UTMP, "r", stdin)) { + (void)fprintf( stderr, "finger: can't read %s.\n", _PATH_UTMP); + exit(1); + } + while (fread((char *)&user, sizeof(user), 1, stdin) == 1) { + if (!user.ut_name[0]) + continue; + if ((pn = find_person(user.ut_name)) == NULL) + continue; + enter_where(&user, pn); + } + for (pn = phead; pn != NULL; pn = pn->next) + enter_lastlog(pn); }