-#ifndef lint
-static char *sccsid = "@(#)finger.c 4.4 (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 <sys/types.h>
-#include <sys/stat.h>
-#include <sgtty.h>
-#include <utmp.h>
-#include <signal.h>
-#include <pwd.h>
-#include <stdio.h>
-#include <lastlog.h>
-#include <sys/time.h>
-
-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[ 40 ], *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 <sys/param.h>
+#include <sys/file.h>
+#include <stdio.h>
+#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);
}