121554Sdist /* 2*37659Sbostic * Copyright (c) 1989 The Regents of the University of California. 335627Sbostic * All rights reserved. 435627Sbostic * 5*37659Sbostic * This code is derived from software contributed to Berkeley by 6*37659Sbostic * Tony Nardo of the Johns Hopkins University/Applied Physics Lab. 7*37659Sbostic * 835627Sbostic * Redistribution and use in source and binary forms are permitted 935627Sbostic * provided that the above copyright notice and this paragraph are 1035627Sbostic * duplicated in all such forms and that any documentation, 1135627Sbostic * advertising materials, and other materials related to such 1235627Sbostic * distribution and use acknowledge that the software was developed 1335627Sbostic * by the University of California, Berkeley. The name of the 1435627Sbostic * University may not be used to endorse or promote products derived 1535627Sbostic * from this software without specific prior written permission. 1635627Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1735627Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18*37659Sbostic * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1921554Sdist */ 2021554Sdist 2113619Ssam #ifndef lint 2221554Sdist char copyright[] = 23*37659Sbostic "@(#) Copyright (c) 1989 The Regents of the University of California.\n\ 2421554Sdist All rights reserved.\n"; 2535627Sbostic #endif /* not lint */ 261014Sbill 2721554Sdist #ifndef lint 28*37659Sbostic static char sccsid[] = "@(#)finger.c 5.13 (Berkeley) 05/06/89"; 2935627Sbostic #endif /* not lint */ 3021554Sdist 3118606Sedward /* 32*37659Sbostic * Finger prints out information about users. It is not portable since 33*37659Sbostic * certain fields (e.g. the full user name, office, and phone numbers) are 34*37659Sbostic * extracted from the gecos field of the passwd file which other UNIXes 35*37659Sbostic * may not have or may use for other things. 361014Sbill * 37*37659Sbostic * There are currently two output formats; the short format is one line 38*37659Sbostic * per user and displays login name, tty, login time, real name, idle time, 39*37659Sbostic * and office location/phone number. The long format gives the same 40*37659Sbostic * information (in a more legible format) as well as home directory, shell, 41*37659Sbostic * mail info, and .plan/.project files. 421014Sbill */ 431014Sbill 44*37659Sbostic #include <sys/param.h> 45*37659Sbostic #include <sys/file.h> 4637629Sbostic #include <stdio.h> 47*37659Sbostic #include "finger.h" 4837629Sbostic #include "pathnames.h" 491014Sbill 5018606Sedward struct utmp user; 51*37659Sbostic PERSON *head; 52*37659Sbostic time_t now; 53*37659Sbostic int entries, lflag, sflag, mflag, pplan; 54*37659Sbostic char tbuf[1024]; 551014Sbill 5618606Sedward main(argc, argv) 5718606Sedward int argc; 58*37659Sbostic char **argv; 5918606Sedward { 60*37659Sbostic extern int optind; 61*37659Sbostic int ch; 62*37659Sbostic time_t time(); 631014Sbill 64*37659Sbostic while ((ch = getopt(argc, argv, "lmps")) != EOF) 65*37659Sbostic switch(ch) { 66*37659Sbostic case 'l': 67*37659Sbostic lflag = 1; /* long format */ 68*37659Sbostic break; 69*37659Sbostic case 'm': 70*37659Sbostic mflag = 1; /* force exact match of names */ 71*37659Sbostic break; 72*37659Sbostic case 'p': 73*37659Sbostic pplan = 1; /* don't show .plan/.project */ 74*37659Sbostic break; 75*37659Sbostic case 's': 76*37659Sbostic sflag = 1; /* short format */ 77*37659Sbostic break; 78*37659Sbostic case '?': 79*37659Sbostic default: 80*37659Sbostic (void)fprintf(stderr, 81*37659Sbostic "usage: finger [-lmps] [login ...]\n"); 82*37659Sbostic exit(1); 83*37659Sbostic } 84*37659Sbostic argc -= optind; 85*37659Sbostic argv += optind; 86*37659Sbostic 87*37659Sbostic (void)time(&now); 88*37659Sbostic setpassent(1); 89*37659Sbostic if (!*argv) { 90*37659Sbostic /* 91*37659Sbostic * Assign explicit "small" format if no names given and -l 92*37659Sbostic * not selected. Force the -s BEFORE we get names so proper 93*37659Sbostic * screening will be done. 94*37659Sbostic */ 95*37659Sbostic if (!lflag) 96*37659Sbostic sflag = 1; /* if -l not explicit, force -s */ 97*37659Sbostic loginlist(); 98*37659Sbostic if (!head) 99*37659Sbostic (void)printf("No one logged on.\n"); 100*37659Sbostic } else { 101*37659Sbostic userlist(argv); 102*37659Sbostic /* 103*37659Sbostic * Assign explicit "large" format if names given and -s not 104*37659Sbostic * explicitly stated. Force the -l AFTER we get names so any 105*37659Sbostic * remote finger attempts specified won't be mishandled. 106*37659Sbostic */ 107*37659Sbostic if (!sflag) 108*37659Sbostic lflag = 1; /* if -s not explicit, force -l */ 109*37659Sbostic } 110*37659Sbostic if (head) { 111*37659Sbostic if (lflag) 112*37659Sbostic lflag_print(); 113*37659Sbostic else 114*37659Sbostic sflag_print(); 115*37659Sbostic } 11618606Sedward exit(0); 11718606Sedward } 1181014Sbill 119*37659Sbostic loginlist() 1201014Sbill { 121*37659Sbostic register PERSON *pn; 122*37659Sbostic register int fd; 123*37659Sbostic struct passwd *pw; 124*37659Sbostic char name[UT_NAMESIZE + 1], *strdup(), *malloc(); 1251014Sbill 126*37659Sbostic if ((fd = open(_PATH_UTMP, O_RDONLY, 0)) < 0) { 127*37659Sbostic (void)fprintf(stderr, "finger: can't read %s.\n", _PATH_UTMP); 12818606Sedward exit(2); 1291014Sbill } 130*37659Sbostic name[UT_NAMESIZE] = NULL; 131*37659Sbostic while(read(fd, (char *)&user, sizeof(user)) == sizeof(user)) { 132*37659Sbostic if (!user.ut_name[0]) 13318606Sedward continue; 134*37659Sbostic bcopy(user.ut_name, name, UT_NAMESIZE); 135*37659Sbostic if (!(pw = getpwnam(name))) 136*37659Sbostic continue; 137*37659Sbostic if (!(pn = (PERSON *)malloc((u_int)sizeof(PERSON)))) { 138*37659Sbostic (void)fprintf(stderr, "finger: out of space.\n"); 139*37659Sbostic exit(1); 1401014Sbill } 141*37659Sbostic ++entries; 142*37659Sbostic pn->next = head; 143*37659Sbostic head = pn; 144*37659Sbostic utcopy(&user, pn); 145*37659Sbostic userinfo(pn, pw); 146*37659Sbostic find_idle_and_ttywrite(pn); 147*37659Sbostic pn->info = LOGGEDIN; 14818606Sedward } 149*37659Sbostic (void)close(fd); 15018606Sedward } 1511014Sbill 152*37659Sbostic #define ARGIGNORE (char *)0x01 153*37659Sbostic userlist(argv) 15418606Sedward char **argv; 15518606Sedward { 156*37659Sbostic register PERSON *nethead, *p, *pn; 15718606Sedward register struct passwd *pw; 158*37659Sbostic register char **a1, **a2; 159*37659Sbostic int fd, dolocal, nelem; 160*37659Sbostic char **sargv, **arglist, *malloc(), *rindex(), *strcpy(); 1611014Sbill 162*37659Sbostic /* suppress duplicates while it's still easy */ 163*37659Sbostic for (a1 = argv; *a1; ++a1) 164*37659Sbostic for (a2 = a1 + 1; *a2; ++a2) 165*37659Sbostic if (!strcasecmp(*a1, *a2)) { 166*37659Sbostic *a1 = ARGIGNORE; 167*37659Sbostic break; 168*37659Sbostic } 169*37659Sbostic 170*37659Sbostic /* pull out all network requests */ 171*37659Sbostic for (sargv = argv, dolocal = 0, nethead = NULL; *argv; ++argv) { 172*37659Sbostic if (!index(*argv, '@')) { 173*37659Sbostic dolocal = 1; 17418606Sedward continue; 17516469Ssam } 176*37659Sbostic if (!(pn = (PERSON *)malloc((u_int)sizeof(PERSON)))) { 177*37659Sbostic (void)fprintf(stderr, "finger: out of space.\n"); 178*37659Sbostic exit(1); 179*37659Sbostic } 180*37659Sbostic pn->next = nethead; 181*37659Sbostic nethead = pn; 182*37659Sbostic pn->name = *argv; 183*37659Sbostic *argv = ARGIGNORE; 18418606Sedward } 185*37659Sbostic 186*37659Sbostic if (!dolocal) 187*37659Sbostic goto net; 188*37659Sbostic 18918606Sedward /* 190*37659Sbostic * traverse the list of possible login names and check the login name 191*37659Sbostic * and real name against the name specified by the user. Possible 192*37659Sbostic * speedup would be to use getpwnam(3) if mflag set -- maybe not 193*37659Sbostic * worthwhile, given that the default is the mflag off. 19418606Sedward */ 195*37659Sbostic nelem = argv - sargv + 1; 196*37659Sbostic if (!(arglist = 197*37659Sbostic (char **)malloc((u_int)(nelem * sizeof(char *))))) { 198*37659Sbostic (void)fprintf(stderr, "finger: out of space.\n"); 199*37659Sbostic exit(1); 20018606Sedward } 201*37659Sbostic bcopy((char *)sargv, (char *)arglist, nelem * sizeof(char *)); 202*37659Sbostic while (pw = getpwent()) { 203*37659Sbostic for (argv = sargv; *argv; ++argv) { 204*37659Sbostic if (*argv == ARGIGNORE) 20518606Sedward continue; 206*37659Sbostic if (strcasecmp(pw->pw_name, *argv) && 207*37659Sbostic (mflag || !match(pw, *argv))) 20818606Sedward continue; 209*37659Sbostic if (!(pn = (PERSON *)malloc((u_int)sizeof(PERSON)))) { 210*37659Sbostic (void)fprintf(stderr, 211*37659Sbostic "finger: out of space.\n"); 212*37659Sbostic exit(1); 2131014Sbill } 214*37659Sbostic ++entries; 215*37659Sbostic pn->next = head; 216*37659Sbostic head = pn; 217*37659Sbostic userinfo(pn, pw); 218*37659Sbostic pn->info = FOUND; 219*37659Sbostic arglist[argv - sargv] = ARGIGNORE; 220*37659Sbostic /* don't break, may be listed multiple times */ 2211014Sbill } 22218606Sedward } 223*37659Sbostic 224*37659Sbostic /* list errors */ 225*37659Sbostic for (; *arglist; ++arglist) 226*37659Sbostic if (*arglist != ARGIGNORE) 227*37659Sbostic (void)fprintf(stderr, 228*37659Sbostic "finger: %s: no such user.\n", *arglist); 229*37659Sbostic 230*37659Sbostic /* handle network requests */ 231*37659Sbostic net: for (pn = nethead; pn; pn = pn->next) { 232*37659Sbostic netfinger(pn->name); 233*37659Sbostic if (pn->next || entries) 234*37659Sbostic putchar('\n'); 2351014Sbill } 2361014Sbill 237*37659Sbostic if (!head) 238*37659Sbostic return; 2391014Sbill 24018606Sedward /* 241*37659Sbostic * Scan thru the list of users currently logged in, saving 242*37659Sbostic * appropriate data whenever a match occurs. 24318606Sedward */ 244*37659Sbostic if ((fd = open(_PATH_UTMP, O_RDONLY, 0)) < 0) { 245*37659Sbostic (void)fprintf( stderr, "finger: can't read %s.\n", _PATH_UTMP); 246*37659Sbostic exit(1); 24718606Sedward } 248*37659Sbostic while (read(fd, (char *)&user, sizeof(user)) == sizeof(user)) { 249*37659Sbostic if (!user.ut_name[0]) 25018606Sedward continue; 251*37659Sbostic for (pn = head; pn; pn = pn->next) { 252*37659Sbostic if (strncasecmp(pn->name, user.ut_name, UT_NAMESIZE)) 253*37659Sbostic continue; 254*37659Sbostic if (pn->info == LOGGEDIN) { 255*37659Sbostic if (!(p = 256*37659Sbostic (PERSON *)malloc((u_int)sizeof(PERSON)))) { 257*37659Sbostic (void)fprintf(stderr, 258*37659Sbostic "finger: out of space.\n"); 259*37659Sbostic exit(1); 2601014Sbill } 261*37659Sbostic ++entries; 262*37659Sbostic p->name = pn->name; 263*37659Sbostic (void)strcpy(p->tty, pn->tty); 264*37659Sbostic /* link in so finds `real' entry first! */ 265*37659Sbostic p->next = pn->next; 266*37659Sbostic pn->next = p; 267*37659Sbostic pn = p; 2681014Sbill } 269*37659Sbostic pn->info = LOGGEDIN; 270*37659Sbostic utcopy(&user, pn); 271*37659Sbostic find_idle_and_ttywrite(pn); 272*37659Sbostic /* don't break, may be listed multiple times... */ 2731014Sbill } 27418606Sedward } 275*37659Sbostic (void)close(fd); 276*37659Sbostic for (pn = head; pn; pn = pn->next) 277*37659Sbostic if (pn->info == FOUND) 278*37659Sbostic find_when(pn); 2791014Sbill } 280