xref: /original-bsd/usr.bin/finger/finger.c (revision 4aa23bb2)
1 /*
2  * Copyright (c) 1989 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 
18 #ifndef lint
19 char copyright[] =
20 "@(#) Copyright (c) 1989 The Regents of the University of California.\n\
21  All rights reserved.\n";
22 #endif /* not lint */
23 
24 #ifndef lint
25 static char sccsid[] = "@(#)finger.c	5.16 (Berkeley) 05/11/89";
26 #endif /* not lint */
27 
28 /*
29  * Finger prints out information about users.  It is not portable since
30  * certain fields (e.g. the full user name, office, and phone numbers) are
31  * extracted from the gecos field of the passwd file which other UNIXes
32  * may not have or may use for other things.
33  *
34  * There are currently two output formats; the short format is one line
35  * per user and displays login name, tty, login time, real name, idle time,
36  * and office location/phone number.  The long format gives the same
37  * information (in a more legible format) as well as home directory, shell,
38  * mail info, and .plan/.project files.
39  */
40 
41 #include <sys/param.h>
42 #include <sys/file.h>
43 #include <stdio.h>
44 #include "finger.h"
45 #include "pathnames.h"
46 
47 time_t now;
48 int lflag, sflag, mflag, pplan;
49 char tbuf[1024];
50 
51 main(argc, argv)
52 	int argc;
53 	char **argv;
54 {
55 	extern int optind;
56 	int ch;
57 	time_t time();
58 
59 	while ((ch = getopt(argc, argv, "lmps")) != EOF)
60 		switch(ch) {
61 		case 'l':
62 			lflag = 1;		/* long format */
63 			break;
64 		case 'm':
65 			mflag = 1;		/* force exact match of names */
66 			break;
67 		case 'p':
68 			pplan = 1;		/* don't show .plan/.project */
69 			break;
70 		case 's':
71 			sflag = 1;		/* short format */
72 			break;
73 		case '?':
74 		default:
75 			(void)fprintf(stderr,
76 			    "usage: finger [-lmps] [login ...]\n");
77 			exit(1);
78 		}
79 	argc -= optind;
80 	argv += optind;
81 
82 	(void)time(&now);
83 	setpassent(1);
84 	if (!*argv) {
85 		/*
86 		 * Assign explicit "small" format if no names given and -l
87 		 * not selected.  Force the -s BEFORE we get names so proper
88 		 * screening will be done.
89 		 */
90 		if (!lflag)
91 			sflag = 1;	/* if -l not explicit, force -s */
92 		loginlist();
93 		if (entries == 0)
94 			(void)printf("No one logged on.\n");
95 	} else {
96 		userlist(argv);
97 		/*
98 		 * Assign explicit "large" format if names given and -s not
99 		 * explicitly stated.  Force the -l AFTER we get names so any
100 		 * remote finger attempts specified won't be mishandled.
101 		 */
102 		if (!sflag)
103 			lflag = 1;	/* if -s not explicit, force -l */
104 	}
105 	if (entries != 0) {
106 		if (lflag)
107 			lflag_print();
108 		else
109 			sflag_print();
110 	}
111 	exit(0);
112 }
113 
114 loginlist()
115 {
116 	register PERSON *pn;
117 	register int fd;
118 	struct passwd *pw;
119 	struct utmp user;
120 	char name[UT_NAMESIZE + 1];
121 
122 	if ((fd = open(_PATH_UTMP, O_RDONLY, 0)) < 0) {
123 		(void)fprintf(stderr, "finger: can't read %s.\n", _PATH_UTMP);
124 		exit(2);
125 	}
126 	name[UT_NAMESIZE] = NULL;
127 	while (read(fd, (char *)&user, sizeof(user)) == sizeof(user)) {
128 		if (!user.ut_name[0])
129 			continue;
130 		if ((pn = find_person(user.ut_name)) == NULL) {
131 			bcopy(user.ut_name, name, UT_NAMESIZE);
132 			if ((pw = getpwnam(name)) == NULL)
133 				continue;
134 			pn = enter_person(pw);
135 		}
136 		enter_where(&user, pn);
137 	}
138 	(void)close(fd);
139 	for (pn = phead; lflag && pn != NULL; pn = pn->next)
140 		enter_lastlog(pn);
141 }
142 
143 #define	ARGIGNORE	(char *)0x01
144 
145 userlist(argv)
146 	char **argv;
147 {
148 	register char **ap;
149 	register PERSON *pn;
150 	PERSON *nethead;
151 	struct utmp user;
152 	struct passwd *pw;
153 	int fd, dolocal, *used, *index();
154 
155 	/* pull out all network requests */
156 	for (ap = argv, dolocal = 0, nethead = NULL; *ap; ap++) {
157 		if (!index(*ap, '@')) {
158 			dolocal = 1;
159 			continue;
160 		}
161 		pn = palloc();
162 		pn->next = nethead;
163 		nethead = pn;
164 		pn->name = *ap;
165 		*ap = ARGIGNORE;
166 	}
167 
168 	if (!dolocal)
169 		goto net;
170 
171 	if (!(used = (int *)calloc((u_int)(ap - argv), (u_int)sizeof(int)))) {
172 		(void)fprintf(stderr, "finger: out of space.\n");
173 		exit(1);
174 	}
175 
176 	/*
177 	 * traverse the list of possible login names and check the login name
178 	 * and real name against the name specified by the user.
179 	 */
180 	if (mflag) {
181 		for (ap = argv; *ap; ap++)
182 			if (*ap != ARGIGNORE && (pw = getpwnam(*ap))) {
183 				enter_person(pw);
184 				used[ap - argv] = 1;
185 			}
186 	} else while (pw = getpwent())
187 		for (ap = argv; *ap; ap++)
188 			if (*ap != ARGIGNORE &&
189 			    (!strcasecmp(pw->pw_name, *ap) || match(pw, *ap))) {
190 				enter_person(pw);
191 				used[ap - argv] = 1;
192 			}
193 
194 	/* list errors */
195 	for (ap = argv; *ap; ap++)
196 		if (*ap != ARGIGNORE && !used[ap - argv])
197 			(void)fprintf(stderr,
198 			    "finger: %s: no such user.\n", *ap);
199 
200 	/* handle network requests */
201 net:	for (pn = nethead; pn; pn = pn->next) {
202 		netfinger(pn->name);
203 		if (pn->next || entries)
204 			putchar('\n');
205 	}
206 
207 	if (entries == 0)
208 		return;
209 
210 	/*
211 	 * Scan thru the list of users currently logged in, saving
212 	 * appropriate data whenever a match occurs.
213 	 */
214 	if ((fd = open(_PATH_UTMP, O_RDONLY, 0)) < 0) {
215 		(void)fprintf( stderr, "finger: can't read %s.\n", _PATH_UTMP);
216 		exit(1);
217 	}
218 	while (read(fd, (char *)&user, sizeof(user)) == sizeof(user)) {
219 		if (!user.ut_name[0])
220 			continue;
221 		if ((pn = find_person(user.ut_name)) == NULL)
222 			continue;
223 		enter_where(&user, pn);
224 	}
225 	(void)close(fd);
226 	for (pn = phead; pn != NULL; pn = pn->next)
227 		enter_lastlog(pn);
228 }
229