xref: /original-bsd/usr.bin/finger/finger.c (revision 3f73ce2f)
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.20 (Berkeley) 06/01/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 #include "pathnames.h"
39 
40 time_t now;
41 int lflag, sflag, mflag, pplan;
42 char tbuf[1024];
43 
44 main(argc, argv)
45 	int argc;
46 	char **argv;
47 {
48 	extern int optind;
49 	int ch;
50 	time_t time();
51 
52 	while ((ch = getopt(argc, argv, "lmps")) != EOF)
53 		switch(ch) {
54 		case 'l':
55 			lflag = 1;		/* long format */
56 			break;
57 		case 'm':
58 			mflag = 1;		/* force exact match of names */
59 			break;
60 		case 'p':
61 			pplan = 1;		/* don't show .plan/.project */
62 			break;
63 		case 's':
64 			sflag = 1;		/* short format */
65 			break;
66 		case '?':
67 		default:
68 			(void)fprintf(stderr,
69 			    "usage: finger [-lmps] [login ...]\n");
70 			exit(1);
71 		}
72 	argc -= optind;
73 	argv += optind;
74 
75 	(void)time(&now);
76 	setpassent(1);
77 	if (!*argv) {
78 		/*
79 		 * Assign explicit "small" format if no names given and -l
80 		 * not selected.  Force the -s BEFORE we get names so proper
81 		 * screening will be done.
82 		 */
83 		if (!lflag)
84 			sflag = 1;	/* if -l not explicit, force -s */
85 		loginlist();
86 		if (entries == 0)
87 			(void)printf("No one logged on.\n");
88 	} else {
89 		userlist(argc, argv);
90 		/*
91 		 * Assign explicit "large" format if names given and -s not
92 		 * explicitly stated.  Force the -l AFTER we get names so any
93 		 * remote finger attempts specified won't be mishandled.
94 		 */
95 		if (!sflag)
96 			lflag = 1;	/* if -s not explicit, force -l */
97 	}
98 	if (entries != 0) {
99 		if (lflag)
100 			lflag_print();
101 		else
102 			sflag_print();
103 	}
104 	exit(0);
105 }
106 
107 loginlist()
108 {
109 	register PERSON *pn;
110 	struct passwd *pw;
111 	struct utmp user;
112 	char name[UT_NAMESIZE + 1];
113 
114 	if (!freopen(_PATH_UTMP, "r", stdin)) {
115 		(void)fprintf(stderr, "finger: can't read %s.\n", _PATH_UTMP);
116 		exit(2);
117 	}
118 	name[UT_NAMESIZE] = NULL;
119 	while (fread((char *)&user, sizeof(user), 1, stdin) == 1) {
120 		if (!user.ut_name[0])
121 			continue;
122 		if ((pn = find_person(user.ut_name)) == NULL) {
123 			bcopy(user.ut_name, name, UT_NAMESIZE);
124 			if ((pw = getpwnam(name)) == NULL)
125 				continue;
126 			pn = enter_person(pw);
127 		}
128 		enter_where(&user, pn);
129 	}
130 	for (pn = phead; lflag && pn != NULL; pn = pn->next)
131 		enter_lastlog(pn);
132 }
133 
134 userlist(argc, argv)
135 	register argc;
136 	register char **argv;
137 {
138 	register i;
139 	register PERSON *pn;
140 	PERSON *nethead;
141 	struct utmp user;
142 	struct passwd *pw;
143 	int dolocal, *used;
144 	char *index();
145 
146 	if (!(used = (int *)calloc((u_int)argc, (u_int)sizeof(int)))) {
147 		(void)fprintf(stderr, "finger: out of space.\n");
148 		exit(1);
149 	}
150 
151 	/* pull out all network requests */
152 	for (i = 0, dolocal = 0, nethead = NULL; i < argc; i++) {
153 		if (!index(argv[i], '@')) {
154 			dolocal = 1;
155 			continue;
156 		}
157 		pn = palloc();
158 		pn->next = nethead;
159 		nethead = pn;
160 		pn->name = argv[i];
161 		used[i] = -1;
162 	}
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