1: /*
2: * Copyright (c) 1980 Regents of the University of California.
3: * All rights reserved. The Berkeley software License Agreement
4: * specifies the terms and conditions for redistribution.
5: */
6:
7: #ifndef lint
8: char copyright[] =
9: "@(#) Copyright (c) 1980 Regents of the University of California.\n\
10: All rights reserved.\n";
11: #endif not lint
12:
13: #ifndef lint
14: static char sccsid[] = "@(#)finger.c 5.8 (Berkeley) 3/13/86";
15: #endif not lint
16:
17: /*
18: * This is a finger program. It prints out useful information about users
19: * by digging it up from various system files. It is not very portable
20: * because the most useful parts of the information (the full user name,
21: * office, and phone numbers) are all stored in the VAX-unused gecos field
22: * of /etc/passwd, which, unfortunately, other UNIXes use for other things.
23: *
24: * There are three output formats, all of which give login name, teletype
25: * line number, and login time. The short output format is reminiscent
26: * of finger on ITS, and gives one line of information per user containing
27: * in addition to the minimum basic requirements (MBR), the full name of
28: * the user, his idle time and office location and phone number. The
29: * quick style output is UNIX who-like, giving only name, teletype and
30: * login time. Finally, the long style output give the same information
31: * as the short (in more legible format), the home directory and shell
32: * of the user, and, if it exits, a copy of the file .plan in the users
33: * home directory. Finger may be called with or without a list of people
34: * to finger -- if no list is given, all the people currently logged in
35: * are fingered.
36: *
37: * The program is validly called by one of the following:
38: *
39: * finger {short form list of users}
40: * finger -l {long form list of users}
41: * finger -b {briefer long form list of users}
42: * finger -q {quick list of users}
43: * finger -i {quick list of users with idle times}
44: * finger namelist {long format list of specified users}
45: * finger -s namelist {short format list of specified users}
46: * finger -w namelist {narrow short format list of specified users}
47: *
48: * where 'namelist' is a list of users login names.
49: * The other options can all be given after one '-', or each can have its
50: * own '-'. The -f option disables the printing of headers for short and
51: * quick outputs. The -b option briefens long format outputs. The -p
52: * option turns off plans for long format outputs.
53: */
54:
55: #include <sys/types.h>
56: #include <sys/stat.h>
57: #include <utmp.h>
58: #include <sys/signal.h>
59: #include <pwd.h>
60: #include <stdio.h>
61: #include <lastlog.h>
62: #include <ctype.h>
63: #include <sys/time.h>
64: #include <sys/socket.h>
65: #include <netinet/in.h>
66: #include <netdb.h>
67:
68: #define ASTERISK '*' /* ignore this in real name */
69: #define COMMA ',' /* separator in pw_gecos field */
70: #define COMMAND '-' /* command line flag char */
71: #define CORY 'C' /* cory hall office */
72: #define EVANS 'E' /* evans hall office */
73: #define SAMENAME '&' /* repeat login name in real name */
74: #define TALKABLE 0220 /* tty is writable if 220 mode */
75:
76: struct utmp user;
77: #define NMAX sizeof(user.ut_name)
78: #define LMAX sizeof(user.ut_line)
79: #define HMAX sizeof(user.ut_host)
80:
81: struct person { /* one for each person fingered */
82: char *name; /* name */
83: char tty[LMAX+1]; /* null terminated tty line */
84: char host[HMAX+1]; /* null terminated remote host name */
85: long loginat; /* time of (last) login */
86: long idletime; /* how long idle (if logged in) */
87: char *realname; /* pointer to full name */
88: char *office; /* pointer to office name */
89: char *officephone; /* pointer to office phone no. */
90: char *homephone; /* pointer to home phone no. */
91: char *random; /* for any random stuff in pw_gecos */
92: struct passwd *pwd; /* structure of /etc/passwd stuff */
93: char loggedin; /* person is logged in */
94: char writable; /* tty is writable */
95: char original; /* this is not a duplicate entry */
96: struct person *link; /* link to next person */
97: };
98:
99: char LASTLOG[] = "/usr/adm/lastlog"; /* last login info */
100: char USERLOG[] = "/etc/utmp"; /* who is logged in */
101: char PLAN[] = "/.plan"; /* what plan file is */
102: char PROJ[] = "/.project"; /* what project file */
103:
104: int unbrief = 1; /* -b option default */
105: int = 1; /* -f option default */
106: int hack = 1; /* -h option default */
107: int idle = 0; /* -i option default */
108: int large = 0; /* -l option default */
109: int match = 1; /* -m option default */
110: int plan = 1; /* -p option default */
111: int unquick = 1; /* -q option default */
112: int small = 0; /* -s option default */
113: int wide = 1; /* -w option default */
114:
115: int unshort;
116: int lf; /* LASTLOG file descriptor */
117: struct person *person1; /* list of people */
118: long tloc; /* current time */
119:
120: struct passwd *pwdcopy();
121: char *strcpy();
122: char *malloc();
123: char *ctime();
124:
125: main(argc, argv)
126: int argc;
127: register char **argv;
128: {
129: FILE *fp;
130: register char *s;
131:
132: /* parse command line for (optional) arguments */
133: while (*++argv && **argv == COMMAND)
134: for (s = *argv + 1; *s; s++)
135: switch (*s) {
136: case 'b':
137: unbrief = 0;
138: break;
139: case 'f':
140: header = 0;
141: break;
142: case 'h':
143: hack = 0;
144: break;
145: case 'i':
146: idle = 1;
147: unquick = 0;
148: break;
149: case 'l':
150: large = 1;
151: break;
152: case 'm':
153: match = 0;
154: break;
155: case 'p':
156: plan = 0;
157: break;
158: case 'q':
159: unquick = 0;
160: break;
161: case 's':
162: small = 1;
163: break;
164: case 'w':
165: wide = 0;
166: break;
167: default:
168: fprintf(stderr, "Usage: finger [-bfhilmpqsw] [login1 [login2 ...] ]\n");
169: exit(1);
170: }
171: if (unquick || idle)
172: time(&tloc);
173: /*
174: * *argv == 0 means no names given
175: */
176: if (*argv == 0)
177: doall();
178: else
179: donames(argv);
180: if (person1)
181: print();
182: exit(0);
183: }
184:
185: doall()
186: {
187: register struct person *p;
188: register struct passwd *pw;
189: int uf;
190: char name[NMAX + 1];
191:
192: unshort = large;
193: if ((uf = open(USERLOG, 0)) < 0) {
194: fprintf(stderr, "finger: error opening %s\n", USERLOG);
195: exit(2);
196: }
197: if (unquick) {
198: extern _pw_stayopen;
199:
200: setpwent();
201: _pw_stayopen = 1;
202: fwopen();
203: }
204: while (read(uf, (char *)&user, sizeof user) == sizeof user) {
205: if (user.ut_name[0] == 0)
206: continue;
207: if (person1 == 0)
208: p = person1 = (struct person *) malloc(sizeof *p);
209: else {
210: p->link = (struct person *) malloc(sizeof *p);
211: p = p->link;
212: }
213: bcopy(user.ut_name, name, NMAX);
214: name[NMAX] = 0;
215: bcopy(user.ut_line, p->tty, LMAX);
216: p->tty[LMAX] = 0;
217: bcopy(user.ut_host, p->host, HMAX);
218: p->host[HMAX] = 0;
219: p->loginat = user.ut_time;
220: p->pwd = 0;
221: p->loggedin = 1;
222: if (unquick && (pw = getpwnam(name))) {
223: p->pwd = pwdcopy(pw);
224: decode(p);
225: p->name = p->pwd->pw_name;
226: } else
227: p->name = strcpy(malloc(strlen(name) + 1), name);
228: }
229: if (unquick) {
230: fwclose();
231: endpwent();
232: }
233: close(uf);
234: if (person1 == 0) {
235: printf("No one logged on\n");
236: return;
237: }
238: p->link = 0;
239: }
240:
241: donames(argv)
242: char **argv;
243: {
244: register struct person *p;
245: register struct passwd *pw;
246: int uf;
247:
248: /*
249: * get names from command line and check to see if they're
250: * logged in
251: */
252: unshort = !small;
253: for (; *argv != 0; argv++) {
254: if (netfinger(*argv))
255: continue;
256: if (person1 == 0)
257: p = person1 = (struct person *) malloc(sizeof *p);
258: else {
259: p->link = (struct person *) malloc(sizeof *p);
260: p = p->link;
261: }
262: p->name = *argv;
263: p->loggedin = 0;
264: p->original = 1;
265: p->pwd = 0;
266: }
267: if (person1 == 0)
268: return;
269: p->link = 0;
270: /*
271: * if we are doing it, read /etc/passwd for the useful info
272: */
273: if (unquick) {
274: setpwent();
275: if (!match) {
276: extern _pw_stayopen;
277:
278: _pw_stayopen = 1;
279: for (p = person1; p != 0; p = p->link)
280: if (pw = getpwnam(p->name))
281: p->pwd = pwdcopy(pw);
282: } else while ((pw = getpwent()) != 0) {
283: for (p = person1; p != 0; p = p->link) {
284: if (!p->original)
285: continue;
286: if (strcmp(p->name, pw->pw_name) != 0 &&
287: !matchcmp(pw->pw_gecos, pw->pw_name, p->name))
288: continue;
289: if (p->pwd == 0)
290: p->pwd = pwdcopy(pw);
291: else {
292: struct person *new;
293: /*
294: * handle multiple login names, insert
295: * new "duplicate" entry behind
296: */
297: new = (struct person *)
298: malloc(sizeof *new);
299: new->pwd = pwdcopy(pw);
300: new->name = p->name;
301: new->original = 1;
302: new->loggedin = 0;
303: new->link = p->link;
304: p->original = 0;
305: p->link = new;
306: p = new;
307: }
308: }
309: }
310: endpwent();
311: }
312: /* Now get login information */
313: if ((uf = open(USERLOG, 0)) < 0) {
314: fprintf(stderr, "finger: error opening %s\n", USERLOG);
315: exit(2);
316: }
317: while (read(uf, (char *)&user, sizeof user) == sizeof user) {
318: if (*user.ut_name == 0)
319: continue;
320: for (p = person1; p != 0; p = p->link) {
321: if (p->loggedin == 2)
322: continue;
323: if (strncmp(p->pwd ? p->pwd->pw_name : p->name,
324: user.ut_name, NMAX) != 0)
325: continue;
326: if (p->loggedin == 0) {
327: bcopy(user.ut_line, p->tty, LMAX);
328: p->tty[LMAX] = 0;
329: bcopy(user.ut_host, p->host, HMAX);
330: p->host[HMAX] = 0;
331: p->loginat = user.ut_time;
332: p->loggedin = 1;
333: } else { /* p->loggedin == 1 */
334: struct person *new;
335: new = (struct person *) malloc(sizeof *new);
336: new->name = p->name;
337: bcopy(user.ut_line, new->tty, LMAX);
338: new->tty[LMAX] = 0;
339: bcopy(user.ut_host, new->host, HMAX);
340: new->host[HMAX] = 0;
341: new->loginat = user.ut_time;
342: new->pwd = p->pwd;
343: new->loggedin = 1;
344: new->original = 0;
345: new->link = p->link;
346: p->loggedin = 2;
347: p->link = new;
348: p = new;
349: }
350: }
351: }
352: close(uf);
353: if (unquick) {
354: fwopen();
355: for (p = person1; p != 0; p = p->link)
356: decode(p);
357: fwclose();
358: }
359: }
360:
361: print()
362: {
363: register FILE *fp;
364: register struct person *p;
365: register char *s;
366: register c;
367:
368: /*
369: * print out what we got
370: */
371: if (header) {
372: if (unquick) {
373: if (!unshort)
374: if (wide)
375: printf("Login Name TTY Idle When Office\n");
376: else
377: printf("Login TTY Idle When Office\n");
378: } else {
379: printf("Login TTY When");
380: if (idle)
381: printf(" Idle");
382: putchar('\n');
383: }
384: }
385: for (p = person1; p != 0; p = p->link) {
386: if (!unquick) {
387: quickprint(p);
388: continue;
389: }
390: if (!unshort) {
391: shortprint(p);
392: continue;
393: }
394: personprint(p);
395: if (p->pwd != 0) {
396: if (hack) {
397: s = malloc(strlen(p->pwd->pw_dir) +
398: sizeof PROJ);
399: strcpy(s, p->pwd->pw_dir);
400: strcat(s, PROJ);
401: if ((fp = fopen(s, "r")) != 0) {
402: printf("Project: ");
403: while ((c = getc(fp)) != EOF) {
404: if (c == '\n')
405: break;
406: if (isprint(c) || isspace(c))
407: putchar(c);
408: else
409: putchar(c ^ 100);
410: }
411: fclose(fp);
412: putchar('\n');
413: }
414: free(s);
415: }
416: if (plan) {
417: s = malloc(strlen(p->pwd->pw_dir) +
418: sizeof PLAN);
419: strcpy(s, p->pwd->pw_dir);
420: strcat(s, PLAN);
421: if ((fp = fopen(s, "r")) == 0)
422: printf("No Plan.\n");
423: else {
424: printf("Plan:\n");
425: while ((c = getc(fp)) != EOF)
426: if (isprint(c) || isspace(c))
427: putchar(c);
428: else
429: putchar(c ^ 100);
430: fclose(fp);
431: }
432: free(s);
433: }
434: }
435: if (p->link != 0)
436: putchar('\n');
437: }
438: }
439:
440: /*
441: * Duplicate a pwd entry.
442: * Note: Only the useful things (what the program currently uses) are copied.
443: */
444: struct passwd *
445: pwdcopy(pfrom)
446: register struct passwd *pfrom;
447: {
448: register struct passwd *pto;
449:
450: pto = (struct passwd *) malloc(sizeof *pto);
451: #define savestr(s) strcpy(malloc(strlen(s) + 1), s)
452: pto->pw_name = savestr(pfrom->pw_name);
453: pto->pw_uid = pfrom->pw_uid;
454: pto->pw_gecos = savestr(pfrom->pw_gecos);
455: pto->pw_dir = savestr(pfrom->pw_dir);
456: pto->pw_shell = savestr(pfrom->pw_shell);
457: #undef savestr
458: return pto;
459: }
460:
461: /*
462: * print out information on quick format giving just name, tty, login time
463: * and idle time if idle is set.
464: */
465: quickprint(pers)
466: register struct person *pers;
467: {
468: printf("%-*.*s ", NMAX, NMAX, pers->name);
469: if (pers->loggedin) {
470: if (idle) {
471: findidle(pers);
472: printf("%c%-*s %-16.16s", pers->writable ? ' ' : '*',
473: LMAX, pers->tty, ctime(&pers->loginat));
474: ltimeprint(" ", &pers->idletime, "");
475: } else
476: printf(" %-*s %-16.16s", LMAX,
477: pers->tty, ctime(&pers->loginat));
478: putchar('\n');
479: } else
480: printf(" Not Logged In\n");
481: }
482:
483: /*
484: * print out information in short format, giving login name, full name,
485: * tty, idle time, login time, office location and phone.
486: */
487: shortprint(pers)
488: register struct person *pers;
489: {
490: char *p;
491: char dialup;
492:
493: if (pers->pwd == 0) {
494: printf("%-15s ???\n", pers->name);
495: return;
496: }
497: printf("%-*s", NMAX, pers->pwd->pw_name);
498: dialup = 0;
499: if (wide) {
500: if (pers->realname)
501: printf(" %-20.20s", pers->realname);
502: else
503: printf(" ??? ");
504: }
505: putchar(' ');
506: if (pers->loggedin && !pers->writable)
507: putchar('*');
508: else
509: putchar(' ');
510: if (*pers->tty) {
511: if (pers->tty[0] == 't' && pers->tty[1] == 't' &&
512: pers->tty[2] == 'y') {
513: if (pers->tty[3] == 'd' && pers->loggedin)
514: dialup = 1;
515: printf("%-2.2s ", pers->tty + 3);
516: } else
517: printf("%-2.2s ", pers->tty);
518: } else
519: printf(" ");
520: p = ctime(&pers->loginat);
521: if (pers->loggedin) {
522: stimeprint(&pers->idletime);
523: printf(" %3.3s %-5.5s ", p, p + 11);
524: } else if (pers->loginat == 0)
525: printf(" < . . . . >");
526: else if (tloc - pers->loginat >= 180 * 24 * 60 * 60)
527: printf(" <%-6.6s, %-4.4s>", p + 4, p + 20);
528: else
529: printf(" <%-12.12s>", p + 4);
530: if (dialup && pers->homephone)
531: printf(" %20s", pers->homephone);
532: else {
533: if (pers->office)
534: printf(" %-11.11s", pers->office);
535: else if (pers->officephone || pers->homephone)
536: printf(" ");
537: if (pers->officephone)
538: printf(" %s", pers->officephone);
539: else if (pers->homephone)
540: printf(" %s", pers->homephone);
541: }
542: putchar('\n');
543: }
544:
545: /*
546: * print out a person in long format giving all possible information.
547: * directory and shell are inhibited if unbrief is clear.
548: */
549: personprint(pers)
550: register struct person *pers;
551: {
552: if (pers->pwd == 0) {
553: printf("Login name: %-10s\t\t\tIn real life: ???\n",
554: pers->name);
555: return;
556: }
557: printf("Login name: %-10s", pers->pwd->pw_name);
558: if (pers->loggedin && !pers->writable)
559: printf(" (messages off) ");
560: else
561: printf(" ");
562: if (pers->realname)
563: printf("In real life: %s", pers->realname);
564: if (pers->office) {
565: printf("\nOffice: %-.11s", pers->office);
566: if (pers->officephone) {
567: printf(", %s", pers->officephone);
568: if (pers->homephone)
569: printf("\t\tHome phone: %s", pers->homephone);
570: else if (pers->random)
571: printf("\t\t%s", pers->random);
572: } else
573: if (pers->homephone)
574: printf("\t\t\tHome phone: %s", pers->homephone);
575: else if (pers->random)
576: printf("\t\t\t%s", pers->random);
577: } else if (pers->officephone) {
578: printf("\nPhone: %s", pers->officephone);
579: if (pers->homephone)
580: printf(", %s", pers->homephone);
581: if (pers->random)
582: printf(", %s", pers->random);
583: } else if (pers->homephone) {
584: printf("\nPhone: %s", pers->homephone);
585: if (pers->random)
586: printf(", %s", pers->random);
587: } else if (pers->random)
588: printf("\n%s", pers->random);
589: if (unbrief) {
590: printf("\nDirectory: %-25s", pers->pwd->pw_dir);
591: if (*pers->pwd->pw_shell)
592: printf("\tShell: %-s", pers->pwd->pw_shell);
593: }
594: if (pers->loggedin) {
595: register char *ep = ctime(&pers->loginat);
596: if (*pers->host) {
597: printf("\nOn since %15.15s on %s from %s",
598: &ep[4], pers->tty, pers->host);
599: ltimeprint("\n", &pers->idletime, " Idle Time");
600: } else {
601: printf("\nOn since %15.15s on %-*s",
602: &ep[4], LMAX, pers->tty);
603: ltimeprint("\t", &pers->idletime, " Idle Time");
604: }
605: } else if (pers->loginat == 0)
606: printf("\nNever logged in.");
607: else if (tloc - pers->loginat > 180 * 24 * 60 * 60) {
608: register char *ep = ctime(&pers->loginat);
609: printf("\nLast login %10.10s, %4.4s on %s",
610: ep, ep+20, pers->tty);
611: if (*pers->host)
612: printf(" from %s", pers->host);
613: } else {
614: register char *ep = ctime(&pers->loginat);
615: printf("\nLast login %16.16s on %s", ep, pers->tty);
616: if (*pers->host)
617: printf(" from %s", pers->host);
618: }
619: putchar('\n');
620: }
621:
622: /*
623: * very hacky section of code to format phone numbers. filled with
624: * magic constants like 4, 7 and 10.
625: */
626: char *
627: phone(s, len, alldigits)
628: register char *s;
629: int len;
630: char alldigits;
631: {
632: char fonebuf[15];
633: register char *p = fonebuf;
634: register i;
635:
636: if (!alldigits)
637: return (strcpy(malloc(len + 1), s));
638: switch (len) {
639: case 4:
640: *p++ = ' ';
641: *p++ = 'x';
642: *p++ = '2';
643: *p++ = '-';
644: for (i = 0; i < 4; i++)
645: *p++ = *s++;
646: break;
647: case 5:
648: *p++ = ' ';
649: *p++ = 'x';
650: *p++ = *s++;
651: *p++ = '-';
652: for (i = 0; i < 4; i++)
653: *p++ = *s++;
654: break;
655: case 7:
656: for (i = 0; i < 3; i++)
657: *p++ = *s++;
658: *p++ = '-';
659: for (i = 0; i < 4; i++)
660: *p++ = *s++;
661: break;
662: case 10:
663: for (i = 0; i < 3; i++)
664: *p++ = *s++;
665: *p++ = '-';
666: for (i = 0; i < 3; i++)
667: *p++ = *s++;
668: *p++ = '-';
669: for (i = 0; i < 4; i++)
670: *p++ = *s++;
671: break;
672: case 0:
673: return 0;
674: default:
675: return (strcpy(malloc(len + 1), s));
676: }
677: *p++ = 0;
678: return (strcpy(malloc(p - fonebuf), fonebuf));
679: }
680:
681: /*
682: * decode the information in the gecos field of /etc/passwd
683: */
684: decode(pers)
685: register struct person *pers;
686: {
687: char buffer[256];
688: register char *bp, *gp, *lp;
689: int alldigits;
690: int hasspace;
691: int len;
692:
693: pers->realname = 0;
694: pers->office = 0;
695: pers->officephone = 0;
696: pers->homephone = 0;
697: pers->random = 0;
698: if (pers->pwd == 0)
699: return;
700: gp = pers->pwd->pw_gecos;
701: bp = buffer;
702: if (*gp == ASTERISK)
703: gp++;
704: while (*gp && *gp != COMMA) /* name */
705: if (*gp == SAMENAME) {
706: lp = pers->pwd->pw_name;
707: if (islower(*lp))
708: *bp++ = toupper(*lp++);
709: while (*bp++ = *lp++)
710: ;
711: bp--;
712: gp++;
713: } else
714: *bp++ = *gp++;
715: *bp++ = 0;
716: if ((len = bp - buffer) > 1)
717: pers->realname = strcpy(malloc(len), buffer);
718: if (*gp == COMMA) { /* office */
719: gp++;
720: hasspace = 0;
721: bp = buffer;
722: while (*gp && *gp != COMMA) {
723: *bp = *gp++;
724: if (*bp == ' ')
725: hasspace = 1;
726: /* leave 5 for Cory and Evans expansion */
727: if (bp < buffer + sizeof buffer - 6)
728: bp++;
729: }
730: *bp = 0;
731: len = bp - buffer;
732: bp--; /* point to last character */
733: if (hasspace || len == 0)
734: len++;
735: else if (*bp == CORY) {
736: strcpy(bp, " Cory");
737: len += 5;
738: } else if (*bp == EVANS) {
739: strcpy(bp, " Evans");
740: len += 6;
741: } else
742: len++;
743: if (len > 1)
744: pers->office = strcpy(malloc(len), buffer);
745: }
746: if (*gp == COMMA) { /* office phone */
747: gp++;
748: bp = buffer;
749: alldigits = 1;
750: while (*gp && *gp != COMMA) {
751: *bp = *gp++;
752: if (!isdigit(*bp))
753: alldigits = 0;
754: if (bp < buffer + sizeof buffer - 1)
755: bp++;
756: }
757: *bp = 0;
758: pers->officephone = phone(buffer, bp - buffer, alldigits);
759: }
760: if (*gp == COMMA) { /* home phone */
761: gp++;
762: bp = buffer;
763: alldigits = 1;
764: while (*gp && *gp != COMMA) {
765: *bp = *gp++;
766: if (!isdigit(*bp))
767: alldigits = 0;
768: if (bp < buffer + sizeof buffer - 1)
769: bp++;
770: }
771: *bp = 0;
772: pers->homephone = phone(buffer, bp - buffer, alldigits);
773: }
774: if (pers->loggedin)
775: findidle(pers);
776: else
777: findwhen(pers);
778: }
779:
780: /*
781: * find the last log in of a user by checking the LASTLOG file.
782: * the entry is indexed by the uid, so this can only be done if
783: * the uid is known (which it isn't in quick mode)
784: */
785:
786: fwopen()
787: {
788: if ((lf = open(LASTLOG, 0)) < 0)
789: fprintf(stderr, "finger: %s open error\n", LASTLOG);
790: }
791:
792: findwhen(pers)
793: register struct person *pers;
794: {
795: struct lastlog ll;
796: int i;
797:
798: if (lf >= 0) {
799: lseek(lf, (long)pers->pwd->pw_uid * sizeof ll, 0);
800: if ((i = read(lf, (char *)&ll, sizeof ll)) == sizeof ll) {
801: bcopy(ll.ll_line, pers->tty, LMAX);
802: pers->tty[LMAX] = 0;
803: bcopy(ll.ll_host, pers->host, HMAX);
804: pers->host[HMAX] = 0;
805: pers->loginat = ll.ll_time;
806: } else {
807: if (i != 0)
808: fprintf(stderr, "finger: %s read error\n",
809: LASTLOG);
810: pers->tty[0] = 0;
811: pers->host[0] = 0;
812: pers->loginat = 0L;
813: }
814: } else {
815: pers->tty[0] = 0;
816: pers->host[0] = 0;
817: pers->loginat = 0L;
818: }
819: }
820:
821: fwclose()
822: {
823: if (lf >= 0)
824: close(lf);
825: }
826:
827: /*
828: * find the idle time of a user by doing a stat on /dev/tty??,
829: * where tty?? has been gotten from USERLOG, supposedly.
830: */
831: findidle(pers)
832: register struct person *pers;
833: {
834: struct stat ttystatus;
835: static char buffer[20] = "/dev/";
836: long t;
837: #define TTYLEN 5
838:
839: strcpy(buffer + TTYLEN, pers->tty);
840: buffer[TTYLEN+LMAX] = 0;
841: if (stat(buffer, &ttystatus) < 0) {
842: fprintf(stderr, "finger: Can't stat %s\n", buffer);
843: exit(4);
844: }
845: time(&t);
846: if (t < ttystatus.st_atime)
847: pers->idletime = 0L;
848: else
849: pers->idletime = t - ttystatus.st_atime;
850: pers->writable = (ttystatus.st_mode & TALKABLE) == TALKABLE;
851: }
852:
853: /*
854: * print idle time in short format; this program always prints 4 characters;
855: * if the idle time is zero, it prints 4 blanks.
856: */
857: stimeprint(dt)
858: long *dt;
859: {
860: register struct tm *delta;
861:
862: delta = gmtime(dt);
863: if (delta->tm_yday == 0)
864: if (delta->tm_hour == 0)
865: if (delta->tm_min == 0)
866: printf(" ");
867: else
868: printf(" %2d", delta->tm_min);
869: else
870: if (delta->tm_hour >= 10)
871: printf("%3d:", delta->tm_hour);
872: else
873: printf("%1d:%02d",
874: delta->tm_hour, delta->tm_min);
875: else
876: printf("%3dd", delta->tm_yday);
877: }
878:
879: /*
880: * print idle time in long format with care being taken not to pluralize
881: * 1 minutes or 1 hours or 1 days.
882: * print "prefix" first.
883: */
884: ltimeprint(before, dt, after)
885: long *dt;
886: char *before, *after;
887: {
888: register struct tm *delta;
889:
890: delta = gmtime(dt);
891: if (delta->tm_yday == 0 && delta->tm_hour == 0 && delta->tm_min == 0 &&
892: delta->tm_sec <= 10)
893: return (0);
894: printf("%s", before);
895: if (delta->tm_yday >= 10)
896: printf("%d days", delta->tm_yday);
897: else if (delta->tm_yday > 0)
898: printf("%d day%s %d hour%s",
899: delta->tm_yday, delta->tm_yday == 1 ? "" : "s",
900: delta->tm_hour, delta->tm_hour == 1 ? "" : "s");
901: else
902: if (delta->tm_hour >= 10)
903: printf("%d hours", delta->tm_hour);
904: else if (delta->tm_hour > 0)
905: printf("%d hour%s %d minute%s",
906: delta->tm_hour, delta->tm_hour == 1 ? "" : "s",
907: delta->tm_min, delta->tm_min == 1 ? "" : "s");
908: else
909: if (delta->tm_min >= 10)
910: printf("%2d minutes", delta->tm_min);
911: else if (delta->tm_min == 0)
912: printf("%2d seconds", delta->tm_sec);
913: else
914: printf("%d minute%s %d second%s",
915: delta->tm_min,
916: delta->tm_min == 1 ? "" : "s",
917: delta->tm_sec,
918: delta->tm_sec == 1 ? "" : "s");
919: printf("%s", after);
920: }
921:
922: matchcmp(gname, login, given)
923: register char *gname;
924: char *login;
925: char *given;
926: {
927: char buffer[100];
928: register char *bp, *lp;
929: register c;
930:
931: if (*gname == ASTERISK)
932: gname++;
933: lp = 0;
934: bp = buffer;
935: for (;;)
936: switch (c = *gname++) {
937: case SAMENAME:
938: for (lp = login; bp < buffer + sizeof buffer
939: && (*bp++ = *lp++);)
940: ;
941: bp--;
942: break;
943: case ' ':
944: case COMMA:
945: case '\0':
946: *bp = 0;
947: if (namecmp(buffer, given))
948: return (1);
949: if (c == COMMA || c == 0)
950: return (0);
951: bp = buffer;
952: break;
953: default:
954: if (bp < buffer + sizeof buffer)
955: *bp++ = c;
956: }
957: /*NOTREACHED*/
958: }
959:
960: namecmp(name1, name2)
961: register char *name1, *name2;
962: {
963: register c1, c2;
964:
965: for (;;) {
966: c1 = *name1++;
967: if (islower(c1))
968: c1 = toupper(c1);
969: c2 = *name2++;
970: if (islower(c2))
971: c2 = toupper(c2);
972: if (c1 != c2)
973: break;
974: if (c1 == 0)
975: return (1);
976: }
977: if (!c1) {
978: for (name2--; isdigit(*name2); name2++)
979: ;
980: if (*name2 == 0)
981: return (1);
982: } else if (!c2) {
983: for (name1--; isdigit(*name1); name1++)
984: ;
985: if (*name2 == 0)
986: return (1);
987: }
988: return (0);
989: }
990:
991: netfinger(name)
992: char *name;
993: {
994: char *host;
995: char fname[100];
996: struct hostent *hp;
997: struct servent *sp;
998: struct sockaddr_in sin;
999: int s;
1000: char *rindex();
1001: register FILE *f;
1002: register int c;
1003: register int lastc;
1004:
1005: if (name == NULL)
1006: return (0);
1007: host = rindex(name, '@');
1008: if (host == NULL)
1009: return (0);
1010: *host++ = 0;
1011: hp = gethostbyname(host);
1012: if (hp == NULL) {
1013: static struct hostent def;
1014: static struct in_addr defaddr;
1015: static char *alist[1];
1016: static char namebuf[128];
1017: int inet_addr();
1018:
1019: defaddr.s_addr = inet_addr(host);
1020: if (defaddr.s_addr == -1) {
1021: printf("unknown host: %s\n", host);
1022: return (1);
1023: }
1024: strcpy(namebuf, host);
1025: def.h_name = namebuf;
1026: def.h_addr_list = alist, def.h_addr = (char *)&defaddr;
1027: def.h_length = sizeof (struct in_addr);
1028: def.h_addrtype = AF_INET;
1029: def.h_aliases = 0;
1030: hp = &def;
1031: }
1032: printf("[%s]", hp->h_name);
1033: sp = getservbyname("finger", "tcp");
1034: if (sp == 0) {
1035: printf("tcp/finger: unknown service\n");
1036: return (1);
1037: }
1038: sin.sin_family = hp->h_addrtype;
1039: bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length);
1040: sin.sin_port = sp->s_port;
1041: s = socket(hp->h_addrtype, SOCK_STREAM, 0);
1042: if (s < 0) {
1043: fflush(stdout);
1044: perror("socket");
1045: return (1);
1046: }
1047: if (connect(s, (char *)&sin, sizeof (sin)) < 0) {
1048: fflush(stdout);
1049: perror("connect");
1050: close(s);
1051: return (1);
1052: }
1053: printf("\n");
1054: if (large) write(s, "/W ", 3);
1055: write(s, name, strlen(name));
1056: write(s, "\r\n", 2);
1057: f = fdopen(s, "r");
1058: while ((c = getc(f)) != EOF) {
1059: switch(c) {
1060: case 0210:
1061: case 0211:
1062: case 0212:
1063: case 0214:
1064: c -= 0200;
1065: break;
1066: case 0215:
1067: c = '\n';
1068: break;
1069: }
1070: lastc = c;
1071: if (isprint(c) || isspace(c))
1072: putchar(c);
1073: else
1074: putchar(c ^ 100);
1075: }
1076: if (lastc != '\n')
1077: putchar('\n');
1078: (void)fclose(f);
1079: return (1);
1080: }