xref: /original-bsd/usr.bin/finger/finger.c (revision 54e6d6c7)
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.15 (Berkeley) 05/08/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 userlist(argv)
145 	char **argv;
146 {
147 	register char **ap;
148 	register PERSON *pn;
149 	PERSON *nethead;
150 	struct utmp user;
151 	struct passwd *pw;
152 	int fd, dolocal, *index();
153 
154 	/* pull out all network requests */
155 	for (ap = argv, dolocal = 0, nethead = NULL; *ap != NULL; ap++) {
156 		if (!index(*ap, '@')) {
157 			dolocal = 1;
158 			continue;
159 		}
160 		pn = palloc();
161 		pn->next = nethead;
162 		nethead = pn;
163 		pn->name = *ap;
164 		*ap = ARGIGNORE;
165 	}
166 
167 	if (!dolocal)
168 		goto net;
169 
170 	/*
171 	 * traverse the list of possible login names and check the login name
172 	 * and real name against the name specified by the user.
173 	 */
174 	if (mflag)
175 		for (ap = argv; *ap != NULL; ap++) {
176 			if (*ap == ARGIGNORE)
177 				continue;
178 			if ((pw = getpwnam(*ap)) == NULL)
179 				continue;
180 			enter_person(pw);
181 			*ap = ARGIGNORE;
182 		}
183 	else while (pw = getpwent())
184 		for (ap = argv; *ap != NULL; ap++) {
185 			if (*ap == ARGIGNORE)
186 				continue;
187 			if (strcasecmp(pw->pw_name, *ap) && !match(pw, *ap))
188 				continue;
189 			enter_person(pw);
190 			*ap = ARGIGNORE;
191 			/* don't break, may be listed multiple times */
192 		}
193 
194 	/* list errors */
195 	for (ap = argv; *ap != NULL; ap++)
196 		if (*ap != ARGIGNORE)
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