finger.c revision 4991
1/* 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. 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 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37/* 38 * Luke Mewburn <lm@rmit.edu.au> added the following on 940622: 39 * - mail status ("No Mail", "Mail read:...", or "New Mail ..., 40 * Unread since ...".) 41 * - 4 digit phone extensions (3210 is printed as x3210.) 42 * - host/office toggling in short format with -h & -o. 43 * - short day names (`Tue' printed instead of `Jun 21' if the 44 * login time is < 6 days. 45 */ 46 47#ifndef lint 48static char copyright[] = 49"@(#) Copyright (c) 1989, 1993\n\ 50 The Regents of the University of California. All rights reserved.\n"; 51#endif /* not lint */ 52 53#ifndef lint 54static char sccsid[] = "@(#)finger.c 8.2 (Berkeley) 9/30/93"; 55#endif /* not lint */ 56 57/* 58 * Finger prints out information about users. It is not portable since 59 * certain fields (e.g. the full user name, office, and phone numbers) are 60 * extracted from the gecos field of the passwd file which other UNIXes 61 * may not have or may use for other things. 62 * 63 * There are currently two output formats; the short format is one line 64 * per user and displays login name, tty, login time, real name, idle time, 65 * and either remote host information (default) or office location/phone 66 * number, depending on if -h or -o is used respectively. 67 * The long format gives the same information (in a more legible format) as 68 * well as home directory, shell, mail info, and .plan/.project files. 69 */ 70 71#include <sys/param.h> 72#include <fcntl.h> 73#include <time.h> 74#include <pwd.h> 75#include <utmp.h> 76#include <errno.h> 77#include <stdio.h> 78#include <stdlib.h> 79#include <string.h> 80#include <db.h> 81#include "finger.h" 82 83DB *db; 84time_t now; 85int entries, lflag, mflag, pplan, sflag, oflag; 86char tbuf[1024]; 87 88static void loginlist __P((void)); 89static void userlist __P((int, char **)); 90 91int 92option(argc, argv) 93 int argc; 94 char **argv; 95{ 96 int ch; 97 98 optind = 1; /* reset getopt */ 99 100 while ((ch = getopt(argc, argv, "lmpsho")) != EOF) 101 switch(ch) { 102 case 'l': 103 lflag = 1; /* long format */ 104 break; 105 case 'm': 106 mflag = 1; /* force exact match of names */ 107 break; 108 case 'p': 109 pplan = 1; /* don't show .plan/.project */ 110 break; 111 case 's': 112 sflag = 1; /* short format */ 113 break; 114 case 'h': 115 oflag = 0; /* remote host info */ 116 break; 117 case 'o': 118 oflag = 1; /* office info */ 119 break; 120 case '?': 121 default: 122 (void)fprintf(stderr, 123 "usage: finger [-lmpsho] [login ...]\n"); 124 exit(1); 125 } 126 127 return optind; 128} 129 130main(argc, argv) 131 int argc; 132 char **argv; 133{ 134 int ch, envargc, argcnt; 135 char *envargv[3]; 136 137 /* remove this line to get remote host */ 138 oflag = 1; /* default to old "office" behavior */ 139 140 /* 141 * Process environment variables followed by command line arguments. 142 */ 143 if ((envargv[1] = getenv("FINGER"))) { 144 envargc = 2; 145 envargv[0] = "finger"; 146 envargv[2] = NULL; 147 (void) option(envargc, envargv); 148 } 149 150 argcnt = option(argc, argv); 151 argc -= argcnt; 152 argv += argcnt; 153 154 (void)time(&now); 155 setpassent(1); 156 if (!*argv) { 157 /* 158 * Assign explicit "small" format if no names given and -l 159 * not selected. Force the -s BEFORE we get names so proper 160 * screening will be done. 161 */ 162 if (!lflag) 163 sflag = 1; /* if -l not explicit, force -s */ 164 loginlist(); 165 if (entries == 0) 166 (void)printf("No one logged on.\n"); 167 } else { 168 userlist(argc, argv); 169 /* 170 * Assign explicit "large" format if names given and -s not 171 * explicitly stated. Force the -l AFTER we get names so any 172 * remote finger attempts specified won't be mishandled. 173 */ 174 if (!sflag) 175 lflag = 1; /* if -s not explicit, force -l */ 176 } 177 if (entries) 178 if (lflag) 179 lflag_print(); 180 else 181 sflag_print(); 182 exit(0); 183} 184 185static void 186loginlist() 187{ 188 register PERSON *pn; 189 DBT data, key; 190 struct passwd *pw; 191 struct utmp user; 192 int r, sflag; 193 char name[UT_NAMESIZE + 1]; 194 195 if (!freopen(_PATH_UTMP, "r", stdin)) 196 err("%s: %s", _PATH_UTMP, strerror(errno)); 197 name[UT_NAMESIZE] = NULL; 198 while (fread((char *)&user, sizeof(user), 1, stdin) == 1) { 199 if (!user.ut_name[0]) 200 continue; 201 if ((pn = find_person(user.ut_name)) == NULL) { 202 bcopy(user.ut_name, name, UT_NAMESIZE); 203 if ((pw = getpwnam(name)) == NULL) 204 continue; 205 pn = enter_person(pw); 206 } 207 enter_where(&user, pn); 208 } 209 if (db && lflag) 210 for (sflag = R_FIRST;; sflag = R_NEXT) { 211 r = (*db->seq)(db, &key, &data, sflag); 212 if (r == -1) 213 err("db seq: %s", strerror(errno)); 214 if (r == 1) 215 break; 216 enter_lastlog(*(PERSON **)data.data); 217 } 218} 219 220static void 221userlist(argc, argv) 222 register int argc; 223 register char **argv; 224{ 225 register PERSON *pn; 226 DBT data, key; 227 struct utmp user; 228 struct passwd *pw; 229 int r, sflag, *used, *ip; 230 char **ap, **nargv, **np, **p; 231 232 if ((nargv = malloc((argc+1) * sizeof(char *))) == NULL || 233 (used = calloc(argc, sizeof(int))) == NULL) 234 err("%s", strerror(errno)); 235 236 /* Pull out all network requests. */ 237 for (ap = p = argv, np = nargv; *p; ++p) 238 if (index(*p, '@')) 239 *np++ = *p; 240 else 241 *ap++ = *p; 242 243 *np++ = NULL; 244 *ap++ = NULL; 245 246 if (!*argv) 247 goto net; 248 249 /* 250 * Traverse the list of possible login names and check the login name 251 * and real name against the name specified by the user. 252 */ 253 if (mflag) 254 for (p = argv; *p; ++p) 255 if (pw = getpwnam(*p)) 256 enter_person(pw); 257 else 258 (void)fprintf(stderr, 259 "finger: %s: no such user\n", *p); 260 else { 261 while (pw = getpwent()) 262 for (p = argv, ip = used; *p; ++p, ++ip) 263 if (match(pw, *p)) { 264 enter_person(pw); 265 *ip = 1; 266 } 267 for (p = argv, ip = used; *p; ++p, ++ip) 268 if (!*ip) 269 (void)fprintf(stderr, 270 "finger: %s: no such user\n", *p); 271 } 272 273 /* Handle network requests. */ 274net: for (p = nargv; *p;) { 275 netfinger(*p++); 276 if (*p || entries) 277 printf("\n"); 278 } 279 280 if (entries == 0) 281 return; 282 283 /* 284 * Scan thru the list of users currently logged in, saving 285 * appropriate data whenever a match occurs. 286 */ 287 if (!freopen(_PATH_UTMP, "r", stdin)) 288 err("%s: %s", _PATH_UTMP, strerror(errno)); 289 while (fread((char *)&user, sizeof(user), 1, stdin) == 1) { 290 if (!user.ut_name[0]) 291 continue; 292 if ((pn = find_person(user.ut_name)) == NULL) 293 continue; 294 enter_where(&user, pn); 295 } 296 if (db) 297 for (sflag = R_FIRST;; sflag = R_NEXT) { 298 r = (*db->seq)(db, &key, &data, sflag); 299 if (r == -1) 300 err("db seq: %s", strerror(errno)); 301 if (r == 1) 302 break; 303 enter_lastlog(*(PERSON **)data.data); 304 } 305} 306