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 * %sccs.include.redist.c% 9 */ 10 11 #ifndef lint 12 static char copyright[] = 13 "@(#) Copyright (c) 1989, 1993\n\ 14 The Regents of the University of California. All rights reserved.\n"; 15 #endif /* not lint */ 16 17 #ifndef lint 18 static char sccsid[] = "@(#)finger.c 8.1 (Berkeley) 06/06/93"; 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 <fcntl.h> 36 #include <time.h> 37 #include <pwd.h> 38 #include <utmp.h> 39 #include <errno.h> 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <db.h> 44 #include "finger.h" 45 46 DB *db; 47 time_t now; 48 int entries, lflag, mflag, pplan, sflag; 49 char tbuf[1024]; 50 51 static void loginlist __P((void)); 52 static void userlist __P((int, char **)); 53 54 main(argc, argv) 55 int argc; 56 char **argv; 57 { 58 int ch; 59 60 while ((ch = getopt(argc, argv, "lmps")) != EOF) 61 switch(ch) { 62 case 'l': 63 lflag = 1; /* long format */ 64 break; 65 case 'm': 66 mflag = 1; /* force exact match of names */ 67 break; 68 case 'p': 69 pplan = 1; /* don't show .plan/.project */ 70 break; 71 case 's': 72 sflag = 1; /* short format */ 73 break; 74 case '?': 75 default: 76 (void)fprintf(stderr, 77 "usage: finger [-lmps] [login ...]\n"); 78 exit(1); 79 } 80 argc -= optind; 81 argv += optind; 82 83 (void)time(&now); 84 setpassent(1); 85 if (!*argv) { 86 /* 87 * Assign explicit "small" format if no names given and -l 88 * not selected. Force the -s BEFORE we get names so proper 89 * screening will be done. 90 */ 91 if (!lflag) 92 sflag = 1; /* if -l not explicit, force -s */ 93 loginlist(); 94 if (entries == 0) 95 (void)printf("No one logged on.\n"); 96 } else { 97 userlist(argc, argv); 98 /* 99 * Assign explicit "large" format if names given and -s not 100 * explicitly stated. Force the -l AFTER we get names so any 101 * remote finger attempts specified won't be mishandled. 102 */ 103 if (!sflag) 104 lflag = 1; /* if -s not explicit, force -l */ 105 } 106 if (entries) 107 if (lflag) 108 lflag_print(); 109 else 110 sflag_print(); 111 exit(0); 112 } 113 114 static void 115 loginlist() 116 { 117 register PERSON *pn; 118 DBT data, key; 119 struct passwd *pw; 120 struct utmp user; 121 int r, sflag; 122 char name[UT_NAMESIZE + 1]; 123 124 if (!freopen(_PATH_UTMP, "r", stdin)) 125 err("%s: %s", _PATH_UTMP, strerror(errno)); 126 name[UT_NAMESIZE] = NULL; 127 while (fread((char *)&user, sizeof(user), 1, stdin) == 1) { 128 if (!user.ut_name[0]) 129 continue; 130 if ((pn = find_person(user.ut_name)) == NULL) { 131 bcopy(user.ut_name, name, UT_NAMESIZE); 132 if ((pw = getpwnam(name)) == NULL) 133 continue; 134 pn = enter_person(pw); 135 } 136 enter_where(&user, pn); 137 } 138 if (db && lflag) 139 for (sflag = R_FIRST;; sflag = R_NEXT) { 140 r = (*db->seq)(db, &key, &data, sflag); 141 if (r == -1) 142 err("db seq: %s", strerror(errno)); 143 if (r == 1) 144 break; 145 enter_lastlog(*(PERSON **)data.data); 146 } 147 } 148 149 static void 150 userlist(argc, argv) 151 register int argc; 152 register char **argv; 153 { 154 register PERSON *pn; 155 DBT data, key; 156 struct utmp user; 157 struct passwd *pw; 158 int r, sflag, *used, *ip; 159 char **ap, **nargv, **np, **p; 160 161 if ((nargv = malloc(argc * sizeof(char *))) == NULL || 162 (used = calloc(argc, sizeof(int))) == NULL) 163 err("%s", strerror(errno)); 164 165 /* Pull out all network requests. */ 166 for (ap = p = argv, np = nargv; *p; ++p) 167 if (index(*p, '@')) 168 *np++ = *p; 169 else 170 *ap++ = *p; 171 172 *np++ = NULL; 173 *ap++ = NULL; 174 175 if (!*argv) 176 goto net; 177 178 /* 179 * Traverse the list of possible login names and check the login name 180 * and real name against the name specified by the user. 181 */ 182 if (mflag) 183 for (p = argv; *p; ++p) 184 if (pw = getpwnam(*p)) 185 enter_person(pw); 186 else 187 (void)fprintf(stderr, 188 "finger: %s: no such user\n", *p); 189 else { 190 while (pw = getpwent()) 191 for (p = argv, ip = used; *p; ++p, ++ip) 192 if (match(pw, *p)) { 193 enter_person(pw); 194 *ip = 1; 195 } 196 for (p = argv, ip = used; *p; ++p, ++ip) 197 if (!*ip) 198 (void)fprintf(stderr, 199 "finger: %s: no such user\n", *p); 200 } 201 202 /* Handle network requests. */ 203 net: for (p = nargv; *p;) 204 netfinger(*p++); 205 206 if (entries == 0) 207 return; 208 209 /* 210 * Scan thru the list of users currently logged in, saving 211 * appropriate data whenever a match occurs. 212 */ 213 if (!freopen(_PATH_UTMP, "r", stdin)) 214 err("%s: %s", _PATH_UTMP, strerror(errno)); 215 while (fread((char *)&user, sizeof(user), 1, stdin) == 1) { 216 if (!user.ut_name[0]) 217 continue; 218 if ((pn = find_person(user.ut_name)) == NULL) 219 continue; 220 enter_where(&user, pn); 221 } 222 if (db) 223 for (sflag = R_FIRST;; sflag = R_NEXT) { 224 r = (*db->seq)(db, &key, &data, sflag); 225 if (r == -1) 226 err("db seq: %s", strerror(errno)); 227 if (r == 1) 228 break; 229 enter_lastlog(*(PERSON **)data.data); 230 } 231 } 232