xref: /csrg-svn/usr.bin/finger/finger.c (revision 37659)
121554Sdist /*
2*37659Sbostic  * Copyright (c) 1989 The Regents of the University of California.
335627Sbostic  * All rights reserved.
435627Sbostic  *
5*37659Sbostic  * This code is derived from software contributed to Berkeley by
6*37659Sbostic  * Tony Nardo of the Johns Hopkins University/Applied Physics Lab.
7*37659Sbostic  *
835627Sbostic  * Redistribution and use in source and binary forms are permitted
935627Sbostic  * provided that the above copyright notice and this paragraph are
1035627Sbostic  * duplicated in all such forms and that any documentation,
1135627Sbostic  * advertising materials, and other materials related to such
1235627Sbostic  * distribution and use acknowledge that the software was developed
1335627Sbostic  * by the University of California, Berkeley.  The name of the
1435627Sbostic  * University may not be used to endorse or promote products derived
1535627Sbostic  * from this software without specific prior written permission.
1635627Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1735627Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18*37659Sbostic  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1921554Sdist  */
2021554Sdist 
2113619Ssam #ifndef lint
2221554Sdist char copyright[] =
23*37659Sbostic "@(#) Copyright (c) 1989 The Regents of the University of California.\n\
2421554Sdist  All rights reserved.\n";
2535627Sbostic #endif /* not lint */
261014Sbill 
2721554Sdist #ifndef lint
28*37659Sbostic static char sccsid[] = "@(#)finger.c	5.13 (Berkeley) 05/06/89";
2935627Sbostic #endif /* not lint */
3021554Sdist 
3118606Sedward /*
32*37659Sbostic  * Finger prints out information about users.  It is not portable since
33*37659Sbostic  * certain fields (e.g. the full user name, office, and phone numbers) are
34*37659Sbostic  * extracted from the gecos field of the passwd file which other UNIXes
35*37659Sbostic  * may not have or may use for other things.
361014Sbill  *
37*37659Sbostic  * There are currently two output formats; the short format is one line
38*37659Sbostic  * per user and displays login name, tty, login time, real name, idle time,
39*37659Sbostic  * and office location/phone number.  The long format gives the same
40*37659Sbostic  * information (in a more legible format) as well as home directory, shell,
41*37659Sbostic  * mail info, and .plan/.project files.
421014Sbill  */
431014Sbill 
44*37659Sbostic #include <sys/param.h>
45*37659Sbostic #include <sys/file.h>
4637629Sbostic #include <stdio.h>
47*37659Sbostic #include "finger.h"
4837629Sbostic #include "pathnames.h"
491014Sbill 
5018606Sedward struct utmp user;
51*37659Sbostic PERSON *head;
52*37659Sbostic time_t now;
53*37659Sbostic int entries, lflag, sflag, mflag, pplan;
54*37659Sbostic char tbuf[1024];
551014Sbill 
5618606Sedward main(argc, argv)
5718606Sedward 	int argc;
58*37659Sbostic 	char **argv;
5918606Sedward {
60*37659Sbostic 	extern int optind;
61*37659Sbostic 	int ch;
62*37659Sbostic 	time_t time();
631014Sbill 
64*37659Sbostic 	while ((ch = getopt(argc, argv, "lmps")) != EOF)
65*37659Sbostic 		switch(ch) {
66*37659Sbostic 		case 'l':
67*37659Sbostic 			lflag = 1;		/* long format */
68*37659Sbostic 			break;
69*37659Sbostic 		case 'm':
70*37659Sbostic 			mflag = 1;		/* force exact match of names */
71*37659Sbostic 			break;
72*37659Sbostic 		case 'p':
73*37659Sbostic 			pplan = 1;		/* don't show .plan/.project */
74*37659Sbostic 			break;
75*37659Sbostic 		case 's':
76*37659Sbostic 			sflag = 1;		/* short format */
77*37659Sbostic 			break;
78*37659Sbostic 		case '?':
79*37659Sbostic 		default:
80*37659Sbostic 			(void)fprintf(stderr,
81*37659Sbostic 			    "usage: finger [-lmps] [login ...]\n");
82*37659Sbostic 			exit(1);
83*37659Sbostic 		}
84*37659Sbostic 	argc -= optind;
85*37659Sbostic 	argv += optind;
86*37659Sbostic 
87*37659Sbostic 	(void)time(&now);
88*37659Sbostic 	setpassent(1);
89*37659Sbostic 	if (!*argv) {
90*37659Sbostic 		/*
91*37659Sbostic 		 * Assign explicit "small" format if no names given and -l
92*37659Sbostic 		 * not selected.  Force the -s BEFORE we get names so proper
93*37659Sbostic 		 * screening will be done.
94*37659Sbostic 		 */
95*37659Sbostic 		if (!lflag)
96*37659Sbostic 			sflag = 1;	/* if -l not explicit, force -s */
97*37659Sbostic 		loginlist();
98*37659Sbostic 		if (!head)
99*37659Sbostic 			(void)printf("No one logged on.\n");
100*37659Sbostic 	} else {
101*37659Sbostic 		userlist(argv);
102*37659Sbostic 		/*
103*37659Sbostic 		 * Assign explicit "large" format if names given and -s not
104*37659Sbostic 		 * explicitly stated.  Force the -l AFTER we get names so any
105*37659Sbostic 		 * remote finger attempts specified won't be mishandled.
106*37659Sbostic 		 */
107*37659Sbostic 		if (!sflag)
108*37659Sbostic 			lflag = 1;	/* if -s not explicit, force -l */
109*37659Sbostic 	}
110*37659Sbostic 	if (head) {
111*37659Sbostic 		if (lflag)
112*37659Sbostic 			lflag_print();
113*37659Sbostic 		else
114*37659Sbostic 			sflag_print();
115*37659Sbostic 	}
11618606Sedward 	exit(0);
11718606Sedward }
1181014Sbill 
119*37659Sbostic loginlist()
1201014Sbill {
121*37659Sbostic 	register PERSON *pn;
122*37659Sbostic 	register int fd;
123*37659Sbostic 	struct passwd *pw;
124*37659Sbostic 	char name[UT_NAMESIZE + 1], *strdup(), *malloc();
1251014Sbill 
126*37659Sbostic 	if ((fd = open(_PATH_UTMP, O_RDONLY, 0)) < 0) {
127*37659Sbostic 		(void)fprintf(stderr, "finger: can't read %s.\n", _PATH_UTMP);
12818606Sedward 		exit(2);
1291014Sbill 	}
130*37659Sbostic 	name[UT_NAMESIZE] = NULL;
131*37659Sbostic 	while(read(fd, (char *)&user, sizeof(user)) == sizeof(user)) {
132*37659Sbostic 		if (!user.ut_name[0])
13318606Sedward 			continue;
134*37659Sbostic 		bcopy(user.ut_name, name, UT_NAMESIZE);
135*37659Sbostic 		if (!(pw = getpwnam(name)))
136*37659Sbostic 			continue;
137*37659Sbostic 		if (!(pn = (PERSON *)malloc((u_int)sizeof(PERSON)))) {
138*37659Sbostic 			(void)fprintf(stderr, "finger: out of space.\n");
139*37659Sbostic 			exit(1);
1401014Sbill 		}
141*37659Sbostic 		++entries;
142*37659Sbostic 		pn->next = head;
143*37659Sbostic 		head = pn;
144*37659Sbostic 		utcopy(&user, pn);
145*37659Sbostic 		userinfo(pn, pw);
146*37659Sbostic 		find_idle_and_ttywrite(pn);
147*37659Sbostic 		pn->info = LOGGEDIN;
14818606Sedward 	}
149*37659Sbostic 	(void)close(fd);
15018606Sedward }
1511014Sbill 
152*37659Sbostic #define	ARGIGNORE	(char *)0x01
153*37659Sbostic userlist(argv)
15418606Sedward 	char **argv;
15518606Sedward {
156*37659Sbostic 	register PERSON *nethead, *p, *pn;
15718606Sedward 	register struct passwd *pw;
158*37659Sbostic 	register char **a1, **a2;
159*37659Sbostic 	int fd, dolocal, nelem;
160*37659Sbostic 	char **sargv, **arglist, *malloc(), *rindex(), *strcpy();
1611014Sbill 
162*37659Sbostic 	/* suppress duplicates while it's still easy */
163*37659Sbostic 	for (a1 = argv; *a1; ++a1)
164*37659Sbostic 		for (a2 = a1 + 1; *a2; ++a2)
165*37659Sbostic 			if (!strcasecmp(*a1, *a2)) {
166*37659Sbostic 				*a1 = ARGIGNORE;
167*37659Sbostic 				break;
168*37659Sbostic 			}
169*37659Sbostic 
170*37659Sbostic 	/* pull out all network requests */
171*37659Sbostic 	for (sargv = argv, dolocal = 0, nethead = NULL; *argv; ++argv) {
172*37659Sbostic 		if (!index(*argv, '@')) {
173*37659Sbostic 			dolocal = 1;
17418606Sedward 			continue;
17516469Ssam 		}
176*37659Sbostic 		if (!(pn = (PERSON *)malloc((u_int)sizeof(PERSON)))) {
177*37659Sbostic 			(void)fprintf(stderr, "finger: out of space.\n");
178*37659Sbostic 			exit(1);
179*37659Sbostic 		}
180*37659Sbostic 		pn->next = nethead;
181*37659Sbostic 		nethead = pn;
182*37659Sbostic 		pn->name = *argv;
183*37659Sbostic 		*argv = ARGIGNORE;
18418606Sedward 	}
185*37659Sbostic 
186*37659Sbostic 	if (!dolocal)
187*37659Sbostic 		goto net;
188*37659Sbostic 
18918606Sedward 	/*
190*37659Sbostic 	 * traverse the list of possible login names and check the login name
191*37659Sbostic 	 * and real name against the name specified by the user.  Possible
192*37659Sbostic 	 * speedup would be to use getpwnam(3) if mflag set -- maybe not
193*37659Sbostic 	 * worthwhile, given that the default is the mflag off.
19418606Sedward 	 */
195*37659Sbostic 	nelem = argv - sargv + 1;
196*37659Sbostic 	if (!(arglist =
197*37659Sbostic 	    (char **)malloc((u_int)(nelem * sizeof(char *))))) {
198*37659Sbostic 		(void)fprintf(stderr, "finger: out of space.\n");
199*37659Sbostic 		exit(1);
20018606Sedward 	}
201*37659Sbostic 	bcopy((char *)sargv, (char *)arglist, nelem * sizeof(char *));
202*37659Sbostic 	while (pw = getpwent()) {
203*37659Sbostic 		for (argv = sargv; *argv; ++argv) {
204*37659Sbostic 			if (*argv == ARGIGNORE)
20518606Sedward 				continue;
206*37659Sbostic 			if (strcasecmp(pw->pw_name, *argv) &&
207*37659Sbostic 			    (mflag || !match(pw, *argv)))
20818606Sedward 				continue;
209*37659Sbostic 			if (!(pn = (PERSON *)malloc((u_int)sizeof(PERSON)))) {
210*37659Sbostic 				(void)fprintf(stderr,
211*37659Sbostic 				    "finger: out of space.\n");
212*37659Sbostic 				exit(1);
2131014Sbill 			}
214*37659Sbostic 			++entries;
215*37659Sbostic 			pn->next = head;
216*37659Sbostic 			head = pn;
217*37659Sbostic 			userinfo(pn, pw);
218*37659Sbostic 			pn->info = FOUND;
219*37659Sbostic 			arglist[argv - sargv] = ARGIGNORE;
220*37659Sbostic 			/* don't break, may be listed multiple times */
2211014Sbill 		}
22218606Sedward 	}
223*37659Sbostic 
224*37659Sbostic 	/* list errors */
225*37659Sbostic 	for (; *arglist; ++arglist)
226*37659Sbostic 		if (*arglist != ARGIGNORE)
227*37659Sbostic 			(void)fprintf(stderr,
228*37659Sbostic 			    "finger: %s: no such user.\n", *arglist);
229*37659Sbostic 
230*37659Sbostic 	/* handle network requests */
231*37659Sbostic net:	for (pn = nethead; pn; pn = pn->next) {
232*37659Sbostic 		netfinger(pn->name);
233*37659Sbostic 		if (pn->next || entries)
234*37659Sbostic 			putchar('\n');
2351014Sbill 	}
2361014Sbill 
237*37659Sbostic 	if (!head)
238*37659Sbostic 		return;
2391014Sbill 
24018606Sedward 	/*
241*37659Sbostic 	 * Scan thru the list of users currently logged in, saving
242*37659Sbostic 	 * appropriate data whenever a match occurs.
24318606Sedward 	 */
244*37659Sbostic 	if ((fd = open(_PATH_UTMP, O_RDONLY, 0)) < 0) {
245*37659Sbostic 		(void)fprintf( stderr, "finger: can't read %s.\n", _PATH_UTMP);
246*37659Sbostic 		exit(1);
24718606Sedward 	}
248*37659Sbostic 	while (read(fd, (char *)&user, sizeof(user)) == sizeof(user)) {
249*37659Sbostic 		if (!user.ut_name[0])
25018606Sedward 			continue;
251*37659Sbostic 		for (pn = head; pn; pn = pn->next) {
252*37659Sbostic 			if (strncasecmp(pn->name, user.ut_name, UT_NAMESIZE))
253*37659Sbostic 				continue;
254*37659Sbostic 			if (pn->info == LOGGEDIN) {
255*37659Sbostic 				if (!(p =
256*37659Sbostic 				    (PERSON *)malloc((u_int)sizeof(PERSON)))) {
257*37659Sbostic 					(void)fprintf(stderr,
258*37659Sbostic 					    "finger: out of space.\n");
259*37659Sbostic 					exit(1);
2601014Sbill 				}
261*37659Sbostic 				++entries;
262*37659Sbostic 				p->name = pn->name;
263*37659Sbostic 				(void)strcpy(p->tty, pn->tty);
264*37659Sbostic 				/* link in so finds `real' entry first! */
265*37659Sbostic 				p->next = pn->next;
266*37659Sbostic 				pn->next = p;
267*37659Sbostic 				pn = p;
2681014Sbill 			}
269*37659Sbostic 			pn->info = LOGGEDIN;
270*37659Sbostic 			utcopy(&user, pn);
271*37659Sbostic 			find_idle_and_ttywrite(pn);
272*37659Sbostic 			/* don't break, may be listed multiple times... */
2731014Sbill 		}
27418606Sedward 	}
275*37659Sbostic 	(void)close(fd);
276*37659Sbostic 	for (pn = head; pn; pn = pn->next)
277*37659Sbostic 		if (pn->info == FOUND)
278*37659Sbostic 			find_when(pn);
2791014Sbill }
280