xref: /netbsd/usr.bin/finger/finger.c (revision c4a72b64)
1 /*	$NetBSD: finger.c,v 1.21 2002/09/12 01:31:41 kim Exp $	*/
2 
3 /*
4  * Copyright (c) 1989, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Tony Nardo of the Johns Hopkins University/Applied Physics Lab.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the University of
21  *	California, Berkeley and its contributors.
22  * 4. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  */
38 
39 /*
40  * Luke Mewburn <lukem@netbsd.org> added the following on 961121:
41  *    - mail status ("No Mail", "Mail read:...", or "New Mail ...,
42  *	Unread since ...".)
43  *    - 4 digit phone extensions (3210 is printed as x3210.)
44  *    - host/office toggling in short format with -h & -o.
45  *    - short day names (`Tue' printed instead of `Jun 21' if the
46  *	login time is < 6 days.
47  */
48 
49 #include <sys/cdefs.h>
50 #ifndef lint
51 __COPYRIGHT("@(#) Copyright (c) 1989, 1993\n\
52 	The Regents of the University of California.  All rights reserved.\n");
53 #endif /* not lint */
54 
55 #ifndef lint
56 #if 0
57 static char sccsid[] = "@(#)finger.c	8.5 (Berkeley) 5/4/95";
58 #else
59 __RCSID("$NetBSD: finger.c,v 1.21 2002/09/12 01:31:41 kim Exp $");
60 #endif
61 #endif /* not lint */
62 
63 /*
64  * Finger prints out information about users.  It is not portable since
65  * certain fields (e.g. the full user name, office, and phone numbers) are
66  * extracted from the gecos field of the passwd file which other UNIXes
67  * may not have or may use for other things.
68  *
69  * There are currently two output formats; the short format is one line
70  * per user and displays login name, tty, login time, real name, idle time,
71  * and either remote host information (default) or office location/phone
72  * number, depending on if -h or -o is used respectively.
73  * The long format gives the same information (in a more legible format) as
74  * well as home directory, shell, mail info, and .plan/.project files.
75  */
76 
77 #include <sys/param.h>
78 
79 #include <db.h>
80 #include <err.h>
81 #include <errno.h>
82 #include <fcntl.h>
83 #include <pwd.h>
84 #include <stdio.h>
85 #include <stdlib.h>
86 #include <string.h>
87 #include <time.h>
88 #include <unistd.h>
89 
90 #include <locale.h>
91 #include <langinfo.h>
92 
93 #include "utmpentry.h"
94 
95 #include "finger.h"
96 #include "extern.h"
97 
98 DB *db;
99 time_t now;
100 int entries, gflag, lflag, mflag, oflag, sflag, eightflag, pplan;
101 char tbuf[1024];
102 struct utmpentry *ehead;
103 
104 static void loginlist __P((void));
105 static void userlist __P((int, char **));
106 int main __P((int, char **));
107 
108 int
109 main(argc, argv)
110 	int argc;
111 	char **argv;
112 {
113 	int ch;
114 
115 	/* Allow user's locale settings to affect character output. */
116 	(void *) setlocale(LC_CTYPE, "");
117 
118 	/*
119 	 * Reset back to the C locale, unless we are using a known
120 	 * single-byte 8-bit locale.
121 	 */
122 	if (strncmp(nl_langinfo(CODESET), "ISO8859-", 8))
123 	    (void *) setlocale(LC_CTYPE, "C");
124 
125 	oflag = 1;		/* default to old "office" behavior */
126 
127 	while ((ch = getopt(argc, argv, "lmpshog8")) != -1)
128 		switch(ch) {
129 		case 'l':
130 			lflag = 1;		/* long format */
131 			break;
132 		case 'm':
133 			mflag = 1;		/* force exact match of names */
134 			break;
135 		case 'p':
136 			pplan = 1;		/* don't show .plan/.project */
137 			break;
138 		case 's':
139 			sflag = 1;		/* short format */
140 			break;
141 		case 'h':
142 			oflag = 0;		/* remote host info */
143 			break;
144 		case 'o':
145 			oflag = 1;		/* office info */
146 			break;
147 		case 'g':
148 			gflag = 1;		/* no gecos info, besides name */
149 			break;
150 		case '8':
151 			eightflag = 1;		/* 8-bit pass-through */
152 			break;
153 		case '?':
154 		default:
155 			(void)fprintf(stderr,
156 			    "usage: finger [-lmpshog8] [login ...]\n");
157 			exit(1);
158 		}
159 	argc -= optind;
160 	argv += optind;
161 
162 	(void)time(&now);
163 	setpassent(1);
164 	entries = getutentries(NULL, &ehead);
165 	if (argc == 0) {
166 		/*
167 		 * Assign explicit "small" format if no names given and -l
168 		 * not selected.  Force the -s BEFORE we get names so proper
169 		 * screening will be done.
170 		 */
171 		if (!lflag)
172 			sflag = 1;	/* if -l not explicit, force -s */
173 		loginlist();
174 		if (entries == 0)
175 			(void)printf("No one logged on.\n");
176 	} else {
177 		userlist(argc, argv);
178 		/*
179 		 * Assign explicit "large" format if names given and -s not
180 		 * explicitly stated.  Force the -l AFTER we get names so any
181 		 * remote finger attempts specified won't be mishandled.
182 		 */
183 		if (!sflag)
184 			lflag = 1;	/* if -s not explicit, force -l */
185 	}
186 	if (entries) {
187 		if (lflag)
188 			lflag_print();
189 		else
190 			sflag_print();
191 	}
192 	return (0);
193 }
194 
195 static void
196 loginlist()
197 {
198 	PERSON *pn;
199 	DBT data, key;
200 	struct passwd *pw;
201 	int r, sflag;
202 	struct utmpentry *ep;
203 
204 	for (ep = ehead; ep; ep = ep->next) {
205 		if ((pn = find_person(ep->name)) == NULL) {
206 			if ((pw = getpwnam(ep->name)) == NULL)
207 				continue;
208 			pn = enter_person(pw);
209 		}
210 		enter_where(ep, pn);
211 	}
212 	if (db && lflag)
213 		for (sflag = R_FIRST;; sflag = R_NEXT) {
214 			PERSON *tmp;
215 
216 			r = (*db->seq)(db, &key, &data, sflag);
217 			if (r == -1)
218 				err(1, "db seq");
219 			if (r == 1)
220 				break;
221 			memmove(&tmp, data.data, sizeof tmp);
222 			enter_lastlog(tmp);
223 		}
224 }
225 
226 static void
227 userlist(argc, argv)
228 	int argc;
229 	char **argv;
230 {
231 	register PERSON *pn;
232 	DBT data, key;
233 	struct passwd *pw;
234 	int r, sflag, *used, *ip;
235 	char **ap, **nargv, **np, **p;
236 	struct utmpentry *ep;
237 
238 	if ((nargv = malloc((argc+1) * sizeof(char *))) == NULL ||
239 	    (used = calloc(argc, sizeof(int))) == NULL)
240 		err(1, NULL);
241 
242 	/* Pull out all network requests. */
243 	for (ap = p = argv, np = nargv; *p; ++p)
244 		if (strchr(*p, '@'))
245 			*np++ = *p;
246 		else
247 			*ap++ = *p;
248 
249 	*np++ = NULL;
250 	*ap++ = NULL;
251 
252 	if (!*argv)
253 		goto net;
254 
255 	/*
256 	 * Traverse the list of possible login names and check the login name
257 	 * and real name against the name specified by the user.
258 	 */
259 	if (mflag) {
260 		for (p = argv; *p; ++p)
261 			if ((pw = getpwnam(*p)) != NULL)
262 				enter_person(pw);
263 			else
264 				(void)fprintf(stderr,
265 				    "finger: %s: no such user\n", *p);
266 	} else {
267 		while ((pw = getpwent()) != NULL)
268 			for (p = argv, ip = used; *p; ++p, ++ip)
269 				if (match(pw, *p)) {
270 					enter_person(pw);
271 					*ip = 1;
272 				}
273 		for (p = argv, ip = used; *p; ++p, ++ip)
274 			if (!*ip)
275 				(void)fprintf(stderr,
276 				    "finger: %s: no such user\n", *p);
277 	}
278 
279 	/* Handle network requests. */
280 net:
281 	for (p = nargv; *p;)
282 		netfinger(*p++);
283 
284 	if (entries == 0)
285 		return;
286 
287 	/*
288 	 * Scan thru the list of users currently logged in, saving
289 	 * appropriate data whenever a match occurs.
290 	 */
291 	for (ep = ehead; ep; ep = ep->next) {
292 		if ((pn = find_person(ep->name)) == NULL)
293 			continue;
294 		enter_where(ep, pn);
295 	}
296 	if (db != NULL)
297 		for (sflag = R_FIRST;; sflag = R_NEXT) {
298 			PERSON *tmp;
299 
300 			r = (*db->seq)(db, &key, &data, sflag);
301 			if (r == -1)
302 				err(1, "db seq");
303 			if (r == 1)
304 				break;
305 			memmove(&tmp, data.data, sizeof tmp);
306 			enter_lastlog(tmp);
307 		}
308 }
309 
310