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