finger.c revision 11759
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 <locale.h> 82#include "finger.h" 83 84DB *db; 85time_t now; 86int entries, lflag, mflag, pplan, sflag, oflag; 87char tbuf[1024]; 88 89static void loginlist __P((void)); 90static void userlist __P((int, char **)); 91 92int 93option(argc, argv) 94 int argc; 95 char **argv; 96{ 97 int ch; 98 99 optind = 1; /* reset getopt */ 100 101 while ((ch = getopt(argc, argv, "lmpsho")) != EOF) 102 switch(ch) { 103 case 'l': 104 lflag = 1; /* long format */ 105 break; 106 case 'm': 107 mflag = 1; /* force exact match of names */ 108 break; 109 case 'p': 110 pplan = 1; /* don't show .plan/.project */ 111 break; 112 case 's': 113 sflag = 1; /* short format */ 114 break; 115 case 'h': 116 oflag = 0; /* remote host info */ 117 break; 118 case 'o': 119 oflag = 1; /* office info */ 120 break; 121 case '?': 122 default: 123 (void)fprintf(stderr, 124 "usage: finger [-lmpsho] [login ...]\n"); 125 exit(1); 126 } 127 128 return optind; 129} 130 131main(argc, argv) 132 int argc; 133 char **argv; 134{ 135 int ch, envargc, argcnt; 136 char *envargv[3]; 137 138 (void) setlocale(LC_TIME|LC_CTYPE, ""); 139 140 /* remove this line to get remote host */ 141 oflag = 1; /* default to old "office" behavior */ 142 143 /* 144 * Process environment variables followed by command line arguments. 145 */ 146 if ((envargv[1] = getenv("FINGER"))) { 147 envargc = 2; 148 envargv[0] = "finger"; 149 envargv[2] = NULL; 150 (void) option(envargc, envargv); 151 } 152 153 argcnt = option(argc, argv); 154 argc -= argcnt; 155 argv += argcnt; 156 157 (void)time(&now); 158 setpassent(1); 159 if (!*argv) { 160 /* 161 * Assign explicit "small" format if no names given and -l 162 * not selected. Force the -s BEFORE we get names so proper 163 * screening will be done. 164 */ 165 if (!lflag) 166 sflag = 1; /* if -l not explicit, force -s */ 167 loginlist(); 168 if (entries == 0) 169 (void)printf("No one logged on.\n"); 170 } else { 171 userlist(argc, argv); 172 /* 173 * Assign explicit "large" format if names given and -s not 174 * explicitly stated. Force the -l AFTER we get names so any 175 * remote finger attempts specified won't be mishandled. 176 */ 177 if (!sflag) 178 lflag = 1; /* if -s not explicit, force -l */ 179 } 180 if (entries) 181 if (lflag) 182 lflag_print(); 183 else 184 sflag_print(); 185 exit(0); 186} 187 188static void 189loginlist() 190{ 191 register PERSON *pn; 192 DBT data, key; 193 struct passwd *pw; 194 struct utmp user; 195 int r, sflag; 196 char name[UT_NAMESIZE + 1]; 197 198 if (!freopen(_PATH_UTMP, "r", stdin)) 199 err("%s: %s", _PATH_UTMP, strerror(errno)); 200 name[UT_NAMESIZE] = NULL; 201 while (fread((char *)&user, sizeof(user), 1, stdin) == 1) { 202 if (!user.ut_name[0]) 203 continue; 204 if ((pn = find_person(user.ut_name)) == NULL) { 205 bcopy(user.ut_name, name, UT_NAMESIZE); 206 if ((pw = getpwnam(name)) == NULL) 207 continue; 208 if (hide(pw)) 209 continue; 210 pn = enter_person(pw); 211 } 212 enter_where(&user, pn); 213 } 214 if (db && lflag) 215 for (sflag = R_FIRST;; sflag = R_NEXT) { 216 r = (*db->seq)(db, &key, &data, sflag); 217 if (r == -1) 218 err("db seq: %s", strerror(errno)); 219 if (r == 1) 220 break; 221 enter_lastlog(*(PERSON **)data.data); 222 } 223} 224 225static void 226userlist(argc, argv) 227 register int argc; 228 register char **argv; 229{ 230 register PERSON *pn; 231 DBT data, key; 232 struct utmp user; 233 struct passwd *pw; 234 int r, sflag, *used, *ip; 235 char **ap, **nargv, **np, **p; 236 237 if ((nargv = malloc((argc+1) * sizeof(char *))) == NULL || 238 (used = calloc(argc, sizeof(int))) == NULL) 239 err("%s", strerror(errno)); 240 241 /* Pull out all network requests. */ 242 for (ap = p = argv, np = nargv; *p; ++p) 243 if (index(*p, '@')) 244 *np++ = *p; 245 else 246 *ap++ = *p; 247 248 *np++ = NULL; 249 *ap++ = NULL; 250 251 if (!*argv) 252 goto net; 253 254 /* 255 * Traverse the list of possible login names and check the login name 256 * and real name against the name specified by the user. 257 */ 258 if (mflag) 259 for (p = argv; *p; ++p) 260 if ((pw = getpwnam(*p)) && !hide(pw)) 261 enter_person(pw); 262 else 263 (void)fprintf(stderr, 264 "finger: %s: no such user\n", *p); 265 else { 266 while (pw = getpwent()) { 267 for (p = argv, ip = used; *p; ++p, ++ip) 268 if (match(pw, *p) && !hide(pw)) { 269 enter_person(pw); 270 *ip = 1; 271 } 272 } 273 for (p = argv, ip = used; *p; ++p, ++ip) 274 if (!*ip) 275 (void)fprintf(stderr, 276 "finger: %s: no such user\n", *p); 277 } 278 279 /* Handle network requests. */ 280net: for (p = nargv; *p;) { 281 netfinger(*p++); 282 if (*p || entries) 283 printf("\n"); 284 } 285 286 if (entries == 0) 287 return; 288 289 /* 290 * Scan thru the list of users currently logged in, saving 291 * appropriate data whenever a match occurs. 292 */ 293 if (!freopen(_PATH_UTMP, "r", stdin)) 294 err("%s: %s", _PATH_UTMP, strerror(errno)); 295 while (fread((char *)&user, sizeof(user), 1, stdin) == 1) { 296 if (!user.ut_name[0]) 297 continue; 298 if ((pn = find_person(user.ut_name)) == NULL) 299 continue; 300 enter_where(&user, pn); 301 } 302 if (db) 303 for (sflag = R_FIRST;; sflag = R_NEXT) { 304 r = (*db->seq)(db, &key, &data, sflag); 305 if (r == -1) 306 err("db seq: %s", strerror(errno)); 307 if (r == 1) 308 break; 309 enter_lastlog(*(PERSON **)data.data); 310 } 311} 312