xref: /original-bsd/usr.bin/finger/finger.c (revision 0f81f0ee)
1 /*
2  * Copyright (c) 1989, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Tony Nardo of the Johns Hopkins University/Applied Physics Lab.
7  *
8  * %sccs.include.redist.c%
9  */
10 
11 #ifndef lint
12 static char copyright[] =
13 "@(#) Copyright (c) 1989, 1993\n\
14 	The Regents of the University of California.  All rights reserved.\n";
15 #endif /* not lint */
16 
17 #ifndef lint
18 static char sccsid[] = "@(#)finger.c	8.5 (Berkeley) 05/04/95";
19 #endif /* not lint */
20 
21 /*
22  * Finger prints out information about users.  It is not portable since
23  * certain fields (e.g. the full user name, office, and phone numbers) are
24  * extracted from the gecos field of the passwd file which other UNIXes
25  * may not have or may use for other things.
26  *
27  * There are currently two output formats; the short format is one line
28  * per user and displays login name, tty, login time, real name, idle time,
29  * and office location/phone number.  The long format gives the same
30  * information (in a more legible format) as well as home directory, shell,
31  * mail info, and .plan/.project files.
32  */
33 
34 #include <sys/param.h>
35 
36 #include <db.h>
37 #include <err.h>
38 #include <errno.h>
39 #include <fcntl.h>
40 #include <pwd.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <time.h>
45 #include <unistd.h>
46 #include <utmp.h>
47 
48 #include "finger.h"
49 
50 DB *db;
51 time_t now;
52 int entries, lflag, mflag, pplan, sflag;
53 char tbuf[1024];
54 
55 static void loginlist __P((void));
56 static void userlist __P((int, char **));
57 
58 int
59 main(argc, argv)
60 	int argc;
61 	char **argv;
62 {
63 	int ch;
64 
65 	while ((ch = getopt(argc, argv, "lmps")) != EOF)
66 		switch(ch) {
67 		case 'l':
68 			lflag = 1;		/* long format */
69 			break;
70 		case 'm':
71 			mflag = 1;		/* force exact match of names */
72 			break;
73 		case 'p':
74 			pplan = 1;		/* don't show .plan/.project */
75 			break;
76 		case 's':
77 			sflag = 1;		/* short format */
78 			break;
79 		case '?':
80 		default:
81 			(void)fprintf(stderr,
82 			    "usage: finger [-lmps] [login ...]\n");
83 			exit(1);
84 		}
85 	argc -= optind;
86 	argv += optind;
87 
88 	(void)time(&now);
89 	setpassent(1);
90 	if (!*argv) {
91 		/*
92 		 * Assign explicit "small" format if no names given and -l
93 		 * not selected.  Force the -s BEFORE we get names so proper
94 		 * screening will be done.
95 		 */
96 		if (!lflag)
97 			sflag = 1;	/* if -l not explicit, force -s */
98 		loginlist();
99 		if (entries == 0)
100 			(void)printf("No one logged on.\n");
101 	} else {
102 		userlist(argc, argv);
103 		/*
104 		 * Assign explicit "large" format if names given and -s not
105 		 * explicitly stated.  Force the -l AFTER we get names so any
106 		 * remote finger attempts specified won't be mishandled.
107 		 */
108 		if (!sflag)
109 			lflag = 1;	/* if -s not explicit, force -l */
110 	}
111 	if (entries)
112 		if (lflag)
113 			lflag_print();
114 		else
115 			sflag_print();
116 	return (0);
117 }
118 
119 static void
120 loginlist()
121 {
122 	register PERSON *pn;
123 	DBT data, key;
124 	struct passwd *pw;
125 	struct utmp user;
126 	int r, sflag;
127 	char name[UT_NAMESIZE + 1];
128 
129 	if (!freopen(_PATH_UTMP, "r", stdin))
130 		err(1, "%s", _PATH_UTMP);
131 	name[UT_NAMESIZE] = NULL;
132 	while (fread((char *)&user, sizeof(user), 1, stdin) == 1) {
133 		if (!user.ut_name[0])
134 			continue;
135 		if ((pn = find_person(user.ut_name)) == NULL) {
136 			bcopy(user.ut_name, name, UT_NAMESIZE);
137 			if ((pw = getpwnam(name)) == NULL)
138 				continue;
139 			pn = enter_person(pw);
140 		}
141 		enter_where(&user, pn);
142 	}
143 	if (db && lflag)
144 		for (sflag = R_FIRST;; sflag = R_NEXT) {
145 			PERSON *tmp;
146 
147 			r = (*db->seq)(db, &key, &data, sflag);
148 			if (r == -1)
149 				err(1, "db seq");
150 			if (r == 1)
151 				break;
152 			memmove(&tmp, data.data, sizeof tmp);
153 			enter_lastlog(tmp);
154 		}
155 }
156 
157 static void
158 userlist(argc, argv)
159 	register int argc;
160 	register char **argv;
161 {
162 	register PERSON *pn;
163 	DBT data, key;
164 	struct utmp user;
165 	struct passwd *pw;
166 	int r, sflag, *used, *ip;
167 	char **ap, **nargv, **np, **p;
168 
169 	if ((nargv = malloc((argc+1) * sizeof(char *))) == NULL ||
170 	    (used = calloc(argc, sizeof(int))) == NULL)
171 		err(1, NULL);
172 
173 	/* Pull out all network requests. */
174 	for (ap = p = argv, np = nargv; *p; ++p)
175 		if (index(*p, '@'))
176 			*np++ = *p;
177 		else
178 			*ap++ = *p;
179 
180 	*np++ = NULL;
181 	*ap++ = NULL;
182 
183 	if (!*argv)
184 		goto net;
185 
186 	/*
187 	 * Traverse the list of possible login names and check the login name
188 	 * and real name against the name specified by the user.
189 	 */
190 	if (mflag)
191 		for (p = argv; *p; ++p)
192 			if ((pw = getpwnam(*p)) != NULL)
193 				enter_person(pw);
194 			else
195 				(void)fprintf(stderr,
196 				    "finger: %s: no such user\n", *p);
197 	else {
198 		while ((pw = getpwent()) != NULL)
199 			for (p = argv, ip = used; *p; ++p, ++ip)
200 				if (match(pw, *p)) {
201 					enter_person(pw);
202 					*ip = 1;
203 				}
204 		for (p = argv, ip = used; *p; ++p, ++ip)
205 			if (!*ip)
206 				(void)fprintf(stderr,
207 				    "finger: %s: no such user\n", *p);
208 	}
209 
210 	/* Handle network requests. */
211 net:	for (p = nargv; *p;)
212 		netfinger(*p++);
213 
214 	if (entries == 0)
215 		return;
216 
217 	/*
218 	 * Scan thru the list of users currently logged in, saving
219 	 * appropriate data whenever a match occurs.
220 	 */
221 	if (!freopen(_PATH_UTMP, "r", stdin))
222 		err(1, "%s", _PATH_UTMP);
223 	while (fread((char *)&user, sizeof(user), 1, stdin) == 1) {
224 		if (!user.ut_name[0])
225 			continue;
226 		if ((pn = find_person(user.ut_name)) == NULL)
227 			continue;
228 		enter_where(&user, pn);
229 	}
230 	if (db)
231 		for (sflag = R_FIRST;; sflag = R_NEXT) {
232 			PERSON *tmp;
233 
234 			r = (*db->seq)(db, &key, &data, sflag);
235 			if (r == -1)
236 				err(1, "db seq");
237 			if (r == 1)
238 				break;
239 			memmove(&tmp, data.data, sizeof tmp);
240 			enter_lastlog(tmp);
241 		}
242 }
243