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