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