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