finger.c revision 1590
11590Srgrimes/*
21590Srgrimes * Copyright (c) 1989, 1993
31590Srgrimes *	The Regents of the University of California.  All rights reserved.
41590Srgrimes *
51590Srgrimes * This code is derived from software contributed to Berkeley by
61590Srgrimes * Tony Nardo of the Johns Hopkins University/Applied Physics Lab.
71590Srgrimes *
81590Srgrimes * Redistribution and use in source and binary forms, with or without
91590Srgrimes * modification, are permitted provided that the following conditions
101590Srgrimes * are met:
111590Srgrimes * 1. Redistributions of source code must retain the above copyright
121590Srgrimes *    notice, this list of conditions and the following disclaimer.
131590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141590Srgrimes *    notice, this list of conditions and the following disclaimer in the
151590Srgrimes *    documentation and/or other materials provided with the distribution.
161590Srgrimes * 3. All advertising materials mentioning features or use of this software
171590Srgrimes *    must display the following acknowledgement:
181590Srgrimes *	This product includes software developed by the University of
191590Srgrimes *	California, Berkeley and its contributors.
201590Srgrimes * 4. Neither the name of the University nor the names of its contributors
211590Srgrimes *    may be used to endorse or promote products derived from this software
221590Srgrimes *    without specific prior written permission.
231590Srgrimes *
241590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
251590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
261590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
271590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
281590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
291590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
301590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
311590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
321590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
331590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
341590Srgrimes * SUCH DAMAGE.
351590Srgrimes */
361590Srgrimes
371590Srgrimes#ifndef lint
381590Srgrimesstatic char copyright[] =
391590Srgrimes"@(#) Copyright (c) 1989, 1993\n\
401590Srgrimes	The Regents of the University of California.  All rights reserved.\n";
411590Srgrimes#endif /* not lint */
421590Srgrimes
431590Srgrimes#ifndef lint
441590Srgrimesstatic char sccsid[] = "@(#)finger.c	8.2 (Berkeley) 9/30/93";
451590Srgrimes#endif /* not lint */
461590Srgrimes
471590Srgrimes/*
481590Srgrimes * Finger prints out information about users.  It is not portable since
491590Srgrimes * certain fields (e.g. the full user name, office, and phone numbers) are
501590Srgrimes * extracted from the gecos field of the passwd file which other UNIXes
511590Srgrimes * may not have or may use for other things.
521590Srgrimes *
531590Srgrimes * There are currently two output formats; the short format is one line
541590Srgrimes * per user and displays login name, tty, login time, real name, idle time,
551590Srgrimes * and office location/phone number.  The long format gives the same
561590Srgrimes * information (in a more legible format) as well as home directory, shell,
571590Srgrimes * mail info, and .plan/.project files.
581590Srgrimes */
591590Srgrimes
601590Srgrimes#include <sys/param.h>
611590Srgrimes#include <fcntl.h>
621590Srgrimes#include <time.h>
631590Srgrimes#include <pwd.h>
641590Srgrimes#include <utmp.h>
651590Srgrimes#include <errno.h>
661590Srgrimes#include <stdio.h>
671590Srgrimes#include <stdlib.h>
681590Srgrimes#include <string.h>
691590Srgrimes#include <db.h>
701590Srgrimes#include "finger.h"
711590Srgrimes
721590SrgrimesDB *db;
731590Srgrimestime_t now;
741590Srgrimesint entries, lflag, mflag, pplan, sflag;
751590Srgrimeschar tbuf[1024];
761590Srgrimes
771590Srgrimesstatic void loginlist __P((void));
781590Srgrimesstatic void userlist __P((int, char **));
791590Srgrimes
801590Srgrimesmain(argc, argv)
811590Srgrimes	int argc;
821590Srgrimes	char **argv;
831590Srgrimes{
841590Srgrimes	int ch;
851590Srgrimes
861590Srgrimes	while ((ch = getopt(argc, argv, "lmps")) != EOF)
871590Srgrimes		switch(ch) {
881590Srgrimes		case 'l':
891590Srgrimes			lflag = 1;		/* long format */
901590Srgrimes			break;
911590Srgrimes		case 'm':
921590Srgrimes			mflag = 1;		/* force exact match of names */
931590Srgrimes			break;
941590Srgrimes		case 'p':
951590Srgrimes			pplan = 1;		/* don't show .plan/.project */
961590Srgrimes			break;
971590Srgrimes		case 's':
981590Srgrimes			sflag = 1;		/* short format */
991590Srgrimes			break;
1001590Srgrimes		case '?':
1011590Srgrimes		default:
1021590Srgrimes			(void)fprintf(stderr,
1031590Srgrimes			    "usage: finger [-lmps] [login ...]\n");
1041590Srgrimes			exit(1);
1051590Srgrimes		}
1061590Srgrimes	argc -= optind;
1071590Srgrimes	argv += optind;
1081590Srgrimes
1091590Srgrimes	(void)time(&now);
1101590Srgrimes	setpassent(1);
1111590Srgrimes	if (!*argv) {
1121590Srgrimes		/*
1131590Srgrimes		 * Assign explicit "small" format if no names given and -l
1141590Srgrimes		 * not selected.  Force the -s BEFORE we get names so proper
1151590Srgrimes		 * screening will be done.
1161590Srgrimes		 */
1171590Srgrimes		if (!lflag)
1181590Srgrimes			sflag = 1;	/* if -l not explicit, force -s */
1191590Srgrimes		loginlist();
1201590Srgrimes		if (entries == 0)
1211590Srgrimes			(void)printf("No one logged on.\n");
1221590Srgrimes	} else {
1231590Srgrimes		userlist(argc, argv);
1241590Srgrimes		/*
1251590Srgrimes		 * Assign explicit "large" format if names given and -s not
1261590Srgrimes		 * explicitly stated.  Force the -l AFTER we get names so any
1271590Srgrimes		 * remote finger attempts specified won't be mishandled.
1281590Srgrimes		 */
1291590Srgrimes		if (!sflag)
1301590Srgrimes			lflag = 1;	/* if -s not explicit, force -l */
1311590Srgrimes	}
1321590Srgrimes	if (entries)
1331590Srgrimes		if (lflag)
1341590Srgrimes			lflag_print();
1351590Srgrimes		else
1361590Srgrimes			sflag_print();
1371590Srgrimes	exit(0);
1381590Srgrimes}
1391590Srgrimes
1401590Srgrimesstatic void
1411590Srgrimesloginlist()
1421590Srgrimes{
1431590Srgrimes	register PERSON *pn;
1441590Srgrimes	DBT data, key;
1451590Srgrimes	struct passwd *pw;
1461590Srgrimes	struct utmp user;
1471590Srgrimes	int r, sflag;
1481590Srgrimes	char name[UT_NAMESIZE + 1];
1491590Srgrimes
1501590Srgrimes	if (!freopen(_PATH_UTMP, "r", stdin))
1511590Srgrimes		err("%s: %s", _PATH_UTMP, strerror(errno));
1521590Srgrimes	name[UT_NAMESIZE] = NULL;
1531590Srgrimes	while (fread((char *)&user, sizeof(user), 1, stdin) == 1) {
1541590Srgrimes		if (!user.ut_name[0])
1551590Srgrimes			continue;
1561590Srgrimes		if ((pn = find_person(user.ut_name)) == NULL) {
1571590Srgrimes			bcopy(user.ut_name, name, UT_NAMESIZE);
1581590Srgrimes			if ((pw = getpwnam(name)) == NULL)
1591590Srgrimes				continue;
1601590Srgrimes			pn = enter_person(pw);
1611590Srgrimes		}
1621590Srgrimes		enter_where(&user, pn);
1631590Srgrimes	}
1641590Srgrimes	if (db && lflag)
1651590Srgrimes		for (sflag = R_FIRST;; sflag = R_NEXT) {
1661590Srgrimes			r = (*db->seq)(db, &key, &data, sflag);
1671590Srgrimes			if (r == -1)
1681590Srgrimes				err("db seq: %s", strerror(errno));
1691590Srgrimes			if (r == 1)
1701590Srgrimes				break;
1711590Srgrimes			enter_lastlog(*(PERSON **)data.data);
1721590Srgrimes		}
1731590Srgrimes}
1741590Srgrimes
1751590Srgrimesstatic void
1761590Srgrimesuserlist(argc, argv)
1771590Srgrimes	register int argc;
1781590Srgrimes	register char **argv;
1791590Srgrimes{
1801590Srgrimes	register PERSON *pn;
1811590Srgrimes	DBT data, key;
1821590Srgrimes	struct utmp user;
1831590Srgrimes	struct passwd *pw;
1841590Srgrimes	int r, sflag, *used, *ip;
1851590Srgrimes	char **ap, **nargv, **np, **p;
1861590Srgrimes
1871590Srgrimes	if ((nargv = malloc((argc+1) * sizeof(char *))) == NULL ||
1881590Srgrimes	    (used = calloc(argc, sizeof(int))) == NULL)
1891590Srgrimes		err("%s", strerror(errno));
1901590Srgrimes
1911590Srgrimes	/* Pull out all network requests. */
1921590Srgrimes	for (ap = p = argv, np = nargv; *p; ++p)
1931590Srgrimes		if (index(*p, '@'))
1941590Srgrimes			*np++ = *p;
1951590Srgrimes		else
1961590Srgrimes			*ap++ = *p;
1971590Srgrimes
1981590Srgrimes	*np++ = NULL;
1991590Srgrimes	*ap++ = NULL;
2001590Srgrimes
2011590Srgrimes	if (!*argv)
2021590Srgrimes		goto net;
2031590Srgrimes
2041590Srgrimes	/*
2051590Srgrimes	 * Traverse the list of possible login names and check the login name
2061590Srgrimes	 * and real name against the name specified by the user.
2071590Srgrimes	 */
2081590Srgrimes	if (mflag)
2091590Srgrimes		for (p = argv; *p; ++p)
2101590Srgrimes			if (pw = getpwnam(*p))
2111590Srgrimes				enter_person(pw);
2121590Srgrimes			else
2131590Srgrimes				(void)fprintf(stderr,
2141590Srgrimes				    "finger: %s: no such user\n", *p);
2151590Srgrimes	else {
2161590Srgrimes		while (pw = getpwent())
2171590Srgrimes			for (p = argv, ip = used; *p; ++p, ++ip)
2181590Srgrimes				if (match(pw, *p)) {
2191590Srgrimes					enter_person(pw);
2201590Srgrimes					*ip = 1;
2211590Srgrimes				}
2221590Srgrimes		for (p = argv, ip = used; *p; ++p, ++ip)
2231590Srgrimes			if (!*ip)
2241590Srgrimes				(void)fprintf(stderr,
2251590Srgrimes				    "finger: %s: no such user\n", *p);
2261590Srgrimes	}
2271590Srgrimes
2281590Srgrimes	/* Handle network requests. */
2291590Srgrimesnet:	for (p = nargv; *p;)
2301590Srgrimes		netfinger(*p++);
2311590Srgrimes
2321590Srgrimes	if (entries == 0)
2331590Srgrimes		return;
2341590Srgrimes
2351590Srgrimes	/*
2361590Srgrimes	 * Scan thru the list of users currently logged in, saving
2371590Srgrimes	 * appropriate data whenever a match occurs.
2381590Srgrimes	 */
2391590Srgrimes	if (!freopen(_PATH_UTMP, "r", stdin))
2401590Srgrimes		err("%s: %s", _PATH_UTMP, strerror(errno));
2411590Srgrimes	while (fread((char *)&user, sizeof(user), 1, stdin) == 1) {
2421590Srgrimes		if (!user.ut_name[0])
2431590Srgrimes			continue;
2441590Srgrimes		if ((pn = find_person(user.ut_name)) == NULL)
2451590Srgrimes			continue;
2461590Srgrimes		enter_where(&user, pn);
2471590Srgrimes	}
2481590Srgrimes	if (db)
2491590Srgrimes		for (sflag = R_FIRST;; sflag = R_NEXT) {
2501590Srgrimes			r = (*db->seq)(db, &key, &data, sflag);
2511590Srgrimes			if (r == -1)
2521590Srgrimes				err("db seq: %s", strerror(errno));
2531590Srgrimes			if (r == 1)
2541590Srgrimes				break;
2551590Srgrimes			enter_lastlog(*(PERSON **)data.data);
2561590Srgrimes		}
2571590Srgrimes}
258