xref: /original-bsd/usr.bin/finger/finger.c (revision f72a1a16)
1 /*
2  * Copyright (c) 1989 The Regents of the University of California.
3  * 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 char copyright[] =
13 "@(#) Copyright (c) 1989 The Regents of the University of California.\n\
14  All rights reserved.\n";
15 #endif /* not lint */
16 
17 #ifndef lint
18 static char sccsid[] = "@(#)finger.c	5.22 (Berkeley) 06/29/90";
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 #include <sys/file.h>
36 #include <stdio.h>
37 #include "finger.h"
38 
39 time_t now;
40 int lflag, sflag, mflag, pplan;
41 char tbuf[1024];
42 
43 main(argc, argv)
44 	int argc;
45 	char **argv;
46 {
47 	extern int optind;
48 	int ch;
49 	time_t time();
50 
51 	while ((ch = getopt(argc, argv, "lmps")) != EOF)
52 		switch(ch) {
53 		case 'l':
54 			lflag = 1;		/* long format */
55 			break;
56 		case 'm':
57 			mflag = 1;		/* force exact match of names */
58 			break;
59 		case 'p':
60 			pplan = 1;		/* don't show .plan/.project */
61 			break;
62 		case 's':
63 			sflag = 1;		/* short format */
64 			break;
65 		case '?':
66 		default:
67 			(void)fprintf(stderr,
68 			    "usage: finger [-lmps] [login ...]\n");
69 			exit(1);
70 		}
71 	argc -= optind;
72 	argv += optind;
73 
74 	(void)time(&now);
75 	setpassent(1);
76 	if (!*argv) {
77 		/*
78 		 * Assign explicit "small" format if no names given and -l
79 		 * not selected.  Force the -s BEFORE we get names so proper
80 		 * screening will be done.
81 		 */
82 		if (!lflag)
83 			sflag = 1;	/* if -l not explicit, force -s */
84 		loginlist();
85 		if (entries == 0)
86 			(void)printf("No one logged on.\n");
87 	} else {
88 		userlist(argc, argv);
89 		/*
90 		 * Assign explicit "large" format if names given and -s not
91 		 * explicitly stated.  Force the -l AFTER we get names so any
92 		 * remote finger attempts specified won't be mishandled.
93 		 */
94 		if (!sflag)
95 			lflag = 1;	/* if -s not explicit, force -l */
96 	}
97 	if (entries != 0) {
98 		if (lflag)
99 			lflag_print();
100 		else
101 			sflag_print();
102 	}
103 	exit(0);
104 }
105 
106 loginlist()
107 {
108 	register PERSON *pn;
109 	struct passwd *pw;
110 	struct utmp user;
111 	char name[UT_NAMESIZE + 1];
112 
113 	if (!freopen(_PATH_UTMP, "r", stdin)) {
114 		(void)fprintf(stderr, "finger: can't read %s.\n", _PATH_UTMP);
115 		exit(2);
116 	}
117 	name[UT_NAMESIZE] = NULL;
118 	while (fread((char *)&user, sizeof(user), 1, stdin) == 1) {
119 		if (!user.ut_name[0])
120 			continue;
121 		if ((pn = find_person(user.ut_name)) == NULL) {
122 			bcopy(user.ut_name, name, UT_NAMESIZE);
123 			if ((pw = getpwnam(name)) == NULL)
124 				continue;
125 			pn = enter_person(pw);
126 		}
127 		enter_where(&user, pn);
128 	}
129 	for (pn = phead; lflag && pn != NULL; pn = pn->next)
130 		enter_lastlog(pn);
131 }
132 
133 userlist(argc, argv)
134 	register argc;
135 	register char **argv;
136 {
137 	register i;
138 	register PERSON *pn;
139 	PERSON *nethead, **nettail;
140 	struct utmp user;
141 	struct passwd *pw;
142 	int dolocal, *used;
143 	char *index();
144 
145 	if (!(used = (int *)calloc((u_int)argc, (u_int)sizeof(int)))) {
146 		(void)fprintf(stderr, "finger: out of space.\n");
147 		exit(1);
148 	}
149 
150 	/* pull out all network requests */
151 	for (i = 0, dolocal = 0, nettail = &nethead; i < argc; i++) {
152 		if (!index(argv[i], '@')) {
153 			dolocal = 1;
154 			continue;
155 		}
156 		pn = palloc();
157 		*nettail = pn;
158 		nettail = &pn->next;
159 		pn->name = argv[i];
160 		used[i] = -1;
161 	}
162 	*nettail = NULL;
163 
164 	if (!dolocal)
165 		goto net;
166 
167 	/*
168 	 * traverse the list of possible login names and check the login name
169 	 * and real name against the name specified by the user.
170 	 */
171 	if (mflag) {
172 		for (i = 0; i < argc; i++)
173 			if (used[i] >= 0 && (pw = getpwnam(argv[i]))) {
174 				enter_person(pw);
175 				used[i] = 1;
176 			}
177 	} else while (pw = getpwent())
178 		for (i = 0; i < argc; i++)
179 			if (used[i] >= 0 &&
180 			    (!strcasecmp(pw->pw_name, argv[i]) ||
181 			    match(pw, argv[i]))) {
182 				enter_person(pw);
183 				used[i] = 1;
184 			}
185 
186 	/* list errors */
187 	for (i = 0; i < argc; i++)
188 		if (!used[i])
189 			(void)fprintf(stderr,
190 			    "finger: %s: no such user.\n", argv[i]);
191 
192 	/* handle network requests */
193 net:	for (pn = nethead; pn; pn = pn->next) {
194 		netfinger(pn->name);
195 		if (pn->next || entries)
196 			putchar('\n');
197 	}
198 
199 	if (entries == 0)
200 		return;
201 
202 	/*
203 	 * Scan thru the list of users currently logged in, saving
204 	 * appropriate data whenever a match occurs.
205 	 */
206 	if (!freopen(_PATH_UTMP, "r", stdin)) {
207 		(void)fprintf( stderr, "finger: can't read %s.\n", _PATH_UTMP);
208 		exit(1);
209 	}
210 	while (fread((char *)&user, sizeof(user), 1, stdin) == 1) {
211 		if (!user.ut_name[0])
212 			continue;
213 		if ((pn = find_person(user.ut_name)) == NULL)
214 			continue;
215 		enter_where(&user, pn);
216 	}
217 	for (pn = phead; pn != NULL; pn = pn->next)
218 		enter_lastlog(pn);
219 }
220