1*21554Sdist /* 2*21554Sdist * Copyright (c) 1980 Regents of the University of California. 3*21554Sdist * All rights reserved. The Berkeley software License Agreement 4*21554Sdist * specifies the terms and conditions for redistribution. 5*21554Sdist */ 6*21554Sdist 713619Ssam #ifndef lint 8*21554Sdist char copyright[] = 9*21554Sdist "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 10*21554Sdist All rights reserved.\n"; 11*21554Sdist #endif not lint 121014Sbill 13*21554Sdist #ifndef lint 14*21554Sdist static char sccsid[] = "@(#)finger.c 5.1 (Berkeley) 05/31/85"; 15*21554Sdist #endif not lint 16*21554Sdist 1718606Sedward /* 1818606Sedward * This is a finger program. It prints out useful information about users 1918606Sedward * by digging it up from various system files. It is not very portable 2018606Sedward * because the most useful parts of the information (the full user name, 2118606Sedward * office, and phone numbers) are all stored in the VAX-unused gecos field 2218606Sedward * of /etc/passwd, which, unfortunately, other UNIXes use for other things. 231014Sbill * 2418606Sedward * There are three output formats, all of which give login name, teletype 2518606Sedward * line number, and login time. The short output format is reminiscent 2618606Sedward * of finger on ITS, and gives one line of information per user containing 2718606Sedward * in addition to the minimum basic requirements (MBR), the full name of 2818606Sedward * the user, his idle time and office location and phone number. The 2918606Sedward * quick style output is UNIX who-like, giving only name, teletype and 3018606Sedward * login time. Finally, the long style output give the same information 3118606Sedward * as the short (in more legible format), the home directory and shell 3218606Sedward * of the user, and, if it exits, a copy of the file .plan in the users 3318606Sedward * home directory. Finger may be called with or without a list of people 3418606Sedward * to finger -- if no list is given, all the people currently logged in 3518606Sedward * are fingered. 361014Sbill * 3718606Sedward * The program is validly called by one of the following: 381014Sbill * 391014Sbill * finger {short form list of users} 401014Sbill * finger -l {long form list of users} 411014Sbill * finger -b {briefer long form list of users} 421014Sbill * finger -q {quick list of users} 431014Sbill * finger -i {quick list of users with idle times} 441014Sbill * finger namelist {long format list of specified users} 451014Sbill * finger -s namelist {short format list of specified users} 461014Sbill * finger -w namelist {narrow short format list of specified users} 471014Sbill * 4818606Sedward * where 'namelist' is a list of users login names. 4918606Sedward * The other options can all be given after one '-', or each can have its 5018606Sedward * own '-'. The -f option disables the printing of headers for short and 5118606Sedward * quick outputs. The -b option briefens long format outputs. The -p 5218606Sedward * option turns off plans for long format outputs. 531014Sbill */ 541014Sbill 5518606Sedward #include <sys/types.h> 5618606Sedward #include <sys/stat.h> 5718606Sedward #include <utmp.h> 5818606Sedward #include <sys/signal.h> 5918606Sedward #include <pwd.h> 6018606Sedward #include <stdio.h> 6118606Sedward #include <lastlog.h> 6218606Sedward #include <ctype.h> 6318606Sedward #include <sys/time.h> 6418606Sedward #include <sys/socket.h> 6518606Sedward #include <netinet/in.h> 6618606Sedward #include <netdb.h> 671014Sbill 6818606Sedward #define ASTERISK '*' /* ignore this in real name */ 6918606Sedward #define COMMA ',' /* separator in pw_gecos field */ 7018606Sedward #define COMMAND '-' /* command line flag char */ 7118606Sedward #define CORY 'C' /* cory hall office */ 7218606Sedward #define EVANS 'E' /* evans hall office */ 7318606Sedward #define SAMENAME '&' /* repeat login name in real name */ 7418606Sedward #define TALKABLE 0222 /* tty is writable if 222 mode */ 751014Sbill 7618606Sedward struct utmp user; 7718606Sedward #define NMAX sizeof(user.ut_name) 7818606Sedward #define LMAX sizeof(user.ut_line) 7918606Sedward #define HMAX sizeof(user.ut_host) 801014Sbill 8118606Sedward struct person { /* one for each person fingered */ 8218606Sedward char *name; /* name */ 8318606Sedward char tty[LMAX+1]; /* null terminated tty line */ 8418606Sedward char host[HMAX+1]; /* null terminated remote host name */ 8518606Sedward long loginat; /* time of (last) login */ 8618606Sedward long idletime; /* how long idle (if logged in) */ 8718606Sedward char *realname; /* pointer to full name */ 8818606Sedward char *office; /* pointer to office name */ 8918606Sedward char *officephone; /* pointer to office phone no. */ 9018606Sedward char *homephone; /* pointer to home phone no. */ 9118606Sedward char *random; /* for any random stuff in pw_gecos */ 9218606Sedward struct passwd *pwd; /* structure of /etc/passwd stuff */ 9318606Sedward char loggedin; /* person is logged in */ 9418606Sedward char writable; /* tty is writable */ 9518606Sedward char original; /* this is not a duplicate entry */ 9618606Sedward struct person *link; /* link to next person */ 971014Sbill }; 981014Sbill 9918606Sedward char LASTLOG[] = "/usr/adm/lastlog"; /* last login info */ 10018606Sedward char USERLOG[] = "/etc/utmp"; /* who is logged in */ 10118606Sedward char PLAN[] = "/.plan"; /* what plan file is */ 10218606Sedward char PROJ[] = "/.project"; /* what project file */ 10318606Sedward 10418606Sedward int unbrief = 1; /* -b option default */ 10518606Sedward int header = 1; /* -f option default */ 10618606Sedward int hack = 1; /* -h option default */ 10718606Sedward int idle = 0; /* -i option default */ 10818606Sedward int large = 0; /* -l option default */ 10918606Sedward int match = 1; /* -m option default */ 11018606Sedward int plan = 1; /* -p option default */ 11118606Sedward int unquick = 1; /* -q option default */ 11218606Sedward int small = 0; /* -s option default */ 11318606Sedward int wide = 1; /* -w option default */ 1141014Sbill 11518606Sedward int unshort; 11618606Sedward int lf; /* LASTLOG file descriptor */ 11718606Sedward struct person *person1; /* list of people */ 11818606Sedward long tloc; /* current time */ 1191014Sbill 12018606Sedward struct passwd *pwdcopy(); 12118606Sedward char *strcpy(); 12218606Sedward char *malloc(); 12318606Sedward char *ctime(); 1241014Sbill 12518606Sedward main(argc, argv) 12618606Sedward int argc; 12718606Sedward register char **argv; 12818606Sedward { 12918606Sedward FILE *fp; 13018606Sedward register char *s; 1311014Sbill 13218606Sedward /* parse command line for (optional) arguments */ 13318606Sedward while (*++argv && **argv == COMMAND) 13418606Sedward for (s = *argv + 1; *s; s++) 13518606Sedward switch (*s) { 13618606Sedward case 'b': 13718606Sedward unbrief = 0; 13818606Sedward break; 13918606Sedward case 'f': 14018606Sedward header = 0; 14118606Sedward break; 14218606Sedward case 'h': 14318606Sedward hack = 0; 14418606Sedward break; 14518606Sedward case 'i': 14618606Sedward idle = 1; 14718606Sedward unquick = 0; 14818606Sedward break; 14918606Sedward case 'l': 15018606Sedward large = 1; 15118606Sedward break; 15218606Sedward case 'm': 15318606Sedward match = 0; 15418606Sedward break; 15518606Sedward case 'p': 15618606Sedward plan = 0; 15718606Sedward break; 15818606Sedward case 'q': 15918606Sedward unquick = 0; 16018606Sedward break; 16118606Sedward case 's': 16218606Sedward small = 1; 16318606Sedward break; 16418606Sedward case 'w': 16518606Sedward wide = 0; 16618606Sedward break; 16718606Sedward default: 16818606Sedward fprintf(stderr, "Usage: finger [-bfhilmpqsw] [login1 [login2 ...] ]\n"); 16918606Sedward exit(1); 17018606Sedward } 17118606Sedward if (unquick || idle) 17218606Sedward time(&tloc); 17318606Sedward /* 17418606Sedward * *argv == 0 means no names given 17518606Sedward */ 17618606Sedward if (*argv == 0) 17718606Sedward doall(); 17818606Sedward else 17918606Sedward donames(argv); 18018606Sedward print(); 18118606Sedward exit(0); 18218606Sedward } 1831014Sbill 18418606Sedward doall() 1851014Sbill { 18618606Sedward register struct person *p; 18718606Sedward register struct passwd *pw; 18818606Sedward int uf; 18918606Sedward char name[NMAX + 1]; 1901014Sbill 19118606Sedward unshort = large; 19218606Sedward if ((uf = open(USERLOG, 0)) < 0) { 19318606Sedward fprintf(stderr, "finger: error opening %s\n", USERLOG); 19418606Sedward exit(2); 1951014Sbill } 19618606Sedward if (unquick) { 19718606Sedward extern _pw_stayopen; 1981014Sbill 1991014Sbill setpwent(); 20018606Sedward _pw_stayopen = 1; 2011014Sbill fwopen(); 20218606Sedward } 20318606Sedward while (read(uf, (char *)&user, sizeof user) == sizeof user) { 20418606Sedward if (user.ut_name[0] == 0) 20518606Sedward continue; 20618606Sedward if (person1 == 0) 20718606Sedward p = person1 = (struct person *) malloc(sizeof *p); 20818606Sedward else { 20918606Sedward p->link = (struct person *) malloc(sizeof *p); 2101014Sbill p = p->link; 2111014Sbill } 21218606Sedward bcopy(user.ut_name, name, NMAX); 21318606Sedward name[NMAX] = 0; 21418606Sedward bcopy(user.ut_line, p->tty, LMAX); 21518606Sedward p->tty[LMAX] = 0; 21618606Sedward bcopy(user.ut_host, p->host, HMAX); 21718606Sedward p->host[HMAX] = 0; 21818606Sedward p->loginat = user.ut_time; 21918606Sedward p->pwd = 0; 22018606Sedward p->loggedin = 1; 22118606Sedward if (unquick && (pw = getpwnam(name))) { 22218606Sedward p->pwd = pwdcopy(pw); 22318606Sedward decode(p); 22418606Sedward p->name = p->pwd->pw_name; 22518606Sedward } else 22618606Sedward p->name = strcpy(malloc(strlen(name) + 1), name); 22718606Sedward } 22818606Sedward if (unquick) { 2291014Sbill fwclose(); 2301014Sbill endpwent(); 2311014Sbill } 23218606Sedward close(uf); 23318606Sedward if (person1 == 0) { 23418606Sedward printf("No one logged on\n"); 23518606Sedward exit(0); 23618606Sedward } 23718606Sedward p->link = 0; 23818606Sedward } 2391014Sbill 24018606Sedward donames(argv) 24118606Sedward char **argv; 24218606Sedward { 24318606Sedward register struct person *p; 24418606Sedward register struct passwd *pw; 24518606Sedward int uf; 2461014Sbill 24718606Sedward /* 24818606Sedward * get names from command line and check to see if they're 24918606Sedward * logged in 25018606Sedward */ 25118606Sedward unshort = !small; 25218606Sedward for (; *argv != 0; argv++) { 25318606Sedward if (netfinger(*argv)) 25418606Sedward continue; 25518606Sedward if (person1 == 0) 25618606Sedward p = person1 = (struct person *) malloc(sizeof *p); 25718606Sedward else { 25818606Sedward p->link = (struct person *) malloc(sizeof *p); 25918606Sedward p = p->link; 26016469Ssam } 26118606Sedward p->name = *argv; 2621014Sbill p->loggedin = 0; 26318606Sedward p->original = 1; 26418606Sedward p->pwd = 0; 26518606Sedward } 26618606Sedward p->link = 0; 26718606Sedward /* 26818606Sedward * if we are doing it, read /etc/passwd for the useful info 26918606Sedward */ 27018606Sedward if (unquick) { 27118606Sedward setpwent(); 27218606Sedward if (!match) { 27318606Sedward extern _pw_stayopen; 2741014Sbill 27518606Sedward _pw_stayopen = 1; 27618606Sedward for (p = person1; p != 0; p = p->link) 27718606Sedward if (pw = getpwnam(p->name)) 27818606Sedward p->pwd = pwdcopy(pw); 27918606Sedward } else while ((pw = getpwent()) != 0) { 28018606Sedward for (p = person1; p != 0; p = p->link) { 28118606Sedward if (!p->original) 28218606Sedward continue; 28318606Sedward if (strcmp(p->name, pw->pw_name) != 0 && 28418606Sedward !matchcmp(pw->pw_gecos, pw->pw_name, p->name)) 28518606Sedward continue; 28618606Sedward if (p->pwd == 0) 28718606Sedward p->pwd = pwdcopy(pw); 28818606Sedward else { 28918606Sedward struct person *new; 29018606Sedward /* 29118606Sedward * handle multiple login names, insert 29218606Sedward * new "duplicate" entry behind 29318606Sedward */ 29418606Sedward new = (struct person *) 29518606Sedward malloc(sizeof *new); 29618606Sedward new->pwd = pwdcopy(pw); 29718606Sedward new->name = p->name; 29818606Sedward new->original = 1; 29918606Sedward new->loggedin = 0; 30018606Sedward new->link = p->link; 30118606Sedward p->original = 0; 30218606Sedward p->link = new; 30318606Sedward p = new; 30418606Sedward } 3051014Sbill } 3061014Sbill } 3071014Sbill endpwent(); 30818606Sedward } 30918606Sedward /* Now get login information */ 31018606Sedward if ((uf = open(USERLOG, 0)) < 0) { 31118606Sedward fprintf(stderr, "finger: error opening %s\n", USERLOG); 31218606Sedward exit(2); 31318606Sedward } 31418606Sedward while (read(uf, (char *)&user, sizeof user) == sizeof user) { 31518606Sedward if (*user.ut_name == 0) 31618606Sedward continue; 31718606Sedward for (p = person1; p != 0; p = p->link) { 31818606Sedward if (p->loggedin == 2) 31918606Sedward continue; 32018606Sedward if (strncmp(p->pwd ? p->pwd->pw_name : p->name, 32118606Sedward user.ut_name, NMAX) != 0) 32218606Sedward continue; 32318606Sedward if (p->loggedin == 0) { 32418606Sedward bcopy(user.ut_line, p->tty, LMAX); 32518606Sedward p->tty[LMAX] = 0; 32618606Sedward bcopy(user.ut_host, p->host, HMAX); 32718606Sedward p->host[HMAX] = 0; 32818606Sedward p->loginat = user.ut_time; 32918606Sedward p->loggedin = 1; 33018606Sedward } else { /* p->loggedin == 1 */ 33118606Sedward struct person *new; 33218606Sedward new = (struct person *) malloc(sizeof *new); 33318606Sedward new->name = p->name; 33418606Sedward bcopy(user.ut_line, new->tty, LMAX); 33518606Sedward new->tty[LMAX] = 0; 33618606Sedward bcopy(user.ut_host, new->host, HMAX); 33718606Sedward new->host[HMAX] = 0; 33818606Sedward new->loginat = user.ut_time; 33918606Sedward new->pwd = p->pwd; 34018606Sedward new->loggedin = 1; 34118606Sedward new->original = 0; 34218606Sedward new->link = p->link; 34318606Sedward p->loggedin = 2; 34418606Sedward p->link = new; 34518606Sedward p = new; 3461014Sbill } 3471014Sbill } 34818606Sedward } 34918606Sedward close(uf); 35018606Sedward if (unquick) { 3511014Sbill fwopen(); 35218606Sedward for (p = person1; p != 0; p = p->link) 35318606Sedward decode(p); 3541014Sbill fwclose(); 3551014Sbill } 35618606Sedward } 3571014Sbill 35818606Sedward print() 35918606Sedward { 36018606Sedward register FILE *fp; 36118606Sedward register struct person *p; 36218606Sedward register char *s; 36318606Sedward register c; 3641014Sbill 36518606Sedward /* 36618606Sedward * print out what we got 36718606Sedward */ 36818606Sedward if (header) { 36918606Sedward if (unquick) { 37018606Sedward if (!unshort) 37118606Sedward if (wide) 37218606Sedward printf("Login Name TTY Idle When Office\n"); 37318606Sedward else 37418606Sedward printf("Login TTY Idle When Office\n"); 37518606Sedward } else { 37618606Sedward printf("Login TTY When"); 37718606Sedward if (idle) 37818606Sedward printf(" Idle"); 37918606Sedward putchar('\n'); 3801014Sbill } 38118606Sedward } 38218606Sedward for (p = person1; p != 0; p = p->link) { 38318606Sedward if (!unquick) { 38418606Sedward quickprint(p); 38518606Sedward continue; 3861014Sbill } 38718606Sedward if (!unshort) { 38818606Sedward shortprint(p); 38918606Sedward continue; 39018606Sedward } 39118606Sedward personprint(p); 39218606Sedward if (p->pwd != 0) { 39318606Sedward if (hack) { 39418606Sedward s = malloc(strlen(p->pwd->pw_dir) + 39518606Sedward sizeof PROJ); 39618606Sedward strcpy(s, p->pwd->pw_dir); 39718606Sedward strcat(s, PROJ); 39818606Sedward if ((fp = fopen(s, "r")) != 0) { 39918606Sedward printf("Project: "); 40018606Sedward while ((c = getc(fp)) != EOF) { 40118606Sedward if (c == '\n') 40218606Sedward break; 40318606Sedward putchar(c); 40418606Sedward } 40518606Sedward fclose(fp); 40618606Sedward putchar('\n'); 4071014Sbill } 40818606Sedward free(s); 4091014Sbill } 41018606Sedward if (plan) { 41118606Sedward s = malloc(strlen(p->pwd->pw_dir) + 41218606Sedward sizeof PLAN); 41318606Sedward strcpy(s, p->pwd->pw_dir); 41418606Sedward strcat(s, PLAN); 41518606Sedward if ((fp = fopen(s, "r")) == 0) 41618606Sedward printf("No Plan.\n"); 41718606Sedward else { 41818606Sedward printf("Plan:\n"); 41918606Sedward while ((c = getc(fp)) != EOF) 42018606Sedward putchar(c); 42118606Sedward fclose(fp); 4221014Sbill } 42318606Sedward free(s); 4241014Sbill } 4251014Sbill } 42618606Sedward if (p->link != 0) 42718606Sedward putchar('\n'); 42818606Sedward } 4291014Sbill } 4301014Sbill 43118606Sedward /* 43218606Sedward * Duplicate a pwd entry. 43318606Sedward * Note: Only the useful things (what the program currently uses) are copied. 4341014Sbill */ 43518606Sedward struct passwd * 43618606Sedward pwdcopy(pfrom) 43718606Sedward register struct passwd *pfrom; 43818606Sedward { 43918606Sedward register struct passwd *pto; 4401014Sbill 44118606Sedward pto = (struct passwd *) malloc(sizeof *pto); 44218606Sedward #define savestr(s) strcpy(malloc(strlen(s) + 1), s) 44318606Sedward pto->pw_name = savestr(pfrom->pw_name); 4441014Sbill pto->pw_uid = pfrom->pw_uid; 44518606Sedward pto->pw_gecos = savestr(pfrom->pw_gecos); 44618606Sedward pto->pw_dir = savestr(pfrom->pw_dir); 44718606Sedward pto->pw_shell = savestr(pfrom->pw_shell); 44818606Sedward #undef savestr 44918606Sedward return pto; 4501014Sbill } 4511014Sbill 45218606Sedward /* 45318606Sedward * print out information on quick format giving just name, tty, login time 45418606Sedward * and idle time if idle is set. 4551014Sbill */ 45618606Sedward quickprint(pers) 45718606Sedward register struct person *pers; 4581014Sbill { 45918606Sedward printf("%-*.*s ", NMAX, NMAX, pers->name); 46018606Sedward if (pers->loggedin) { 46118606Sedward if (idle) { 46218606Sedward findidle(pers); 46318606Sedward printf("%c%-*s %-16.16s", pers->writable ? ' ' : '*', 46418606Sedward LMAX, pers->tty, ctime(&pers->loginat)); 46518606Sedward ltimeprint(" ", &pers->idletime, ""); 46618606Sedward } else 46718606Sedward printf(" %-*s %-16.16s", LMAX, 46818606Sedward pers->tty, ctime(&pers->loginat)); 46918606Sedward putchar('\n'); 47018606Sedward } else 47118606Sedward printf(" Not Logged In\n"); 4721014Sbill } 4731014Sbill 47418606Sedward /* 47518606Sedward * print out information in short format, giving login name, full name, 47618606Sedward * tty, idle time, login time, office location and phone. 4771014Sbill */ 47818606Sedward shortprint(pers) 47918606Sedward register struct person *pers; 4801014Sbill { 48118606Sedward char *p; 48218606Sedward char dialup; 4831014Sbill 48418606Sedward if (pers->pwd == 0) { 48518606Sedward printf("%-15s ???\n", pers->name); 48618606Sedward return; 4871014Sbill } 48818606Sedward printf("%-*s", NMAX, pers->pwd->pw_name); 4891014Sbill dialup = 0; 49018606Sedward if (wide) { 49118606Sedward if (pers->realname) 49218606Sedward printf(" %-20.20s", pers->realname); 49318606Sedward else 49418606Sedward printf(" ??? "); 4951014Sbill } 49618606Sedward putchar(' '); 49718606Sedward if (pers->loggedin && !pers->writable) 49818606Sedward putchar('*'); 49918606Sedward else 50018606Sedward putchar(' '); 50118606Sedward if (*pers->tty) { 50218606Sedward if (pers->tty[0] == 't' && pers->tty[1] == 't' && 50318606Sedward pers->tty[2] == 'y') { 50418606Sedward if (pers->tty[3] == 'd' && pers->loggedin) 50518606Sedward dialup = 1; 50618606Sedward printf("%-2.2s ", pers->tty + 3); 50718606Sedward } else 50818606Sedward printf("%-2.2s ", pers->tty); 50918606Sedward } else 51018606Sedward printf(" "); 51118606Sedward p = ctime(&pers->loginat); 51218606Sedward if (pers->loggedin) { 51318606Sedward stimeprint(&pers->idletime); 51418606Sedward printf(" %3.3s %-5.5s ", p, p + 11); 51518606Sedward } else if (pers->loginat == 0) 51618606Sedward printf(" < . . . . >"); 5178842Smckusick else if (tloc - pers->loginat >= 180 * 24 * 60 * 60) 51818606Sedward printf(" <%-6.6s, %-4.4s>", p + 4, p + 20); 5198842Smckusick else 52018606Sedward printf(" <%-12.12s>", p + 4); 52118606Sedward if (dialup && pers->homephone) 52218606Sedward printf(" %20s", pers->homephone); 52318606Sedward else { 52418606Sedward if (pers->office) 52518606Sedward printf(" %-11.11s", pers->office); 52618606Sedward else if (pers->officephone || pers->homephone) 52718606Sedward printf(" "); 52818606Sedward if (pers->officephone) 52918606Sedward printf(" %s", pers->officephone); 53018606Sedward else if (pers->homephone) 53118606Sedward printf(" %s", pers->homephone); 5321014Sbill } 53318606Sedward putchar('\n'); 5341014Sbill } 5351014Sbill 53618606Sedward /* 53718606Sedward * print out a person in long format giving all possible information. 53818606Sedward * directory and shell are inhibited if unbrief is clear. 5391014Sbill */ 54018606Sedward personprint(pers) 54118606Sedward register struct person *pers; 5421014Sbill { 54318606Sedward if (pers->pwd == 0) { 54418606Sedward printf("Login name: %-10s\t\t\tIn real life: ???\n", 54518606Sedward pers->name); 54618606Sedward return; 5471014Sbill } 54818606Sedward printf("Login name: %-10s", pers->pwd->pw_name); 54918606Sedward if (pers->loggedin && !pers->writable) 55018606Sedward printf(" (messages off) "); 55118606Sedward else 55218606Sedward printf(" "); 55318606Sedward if (pers->realname) 55418606Sedward printf("In real life: %s", pers->realname); 55518606Sedward if (pers->office) { 55618606Sedward printf("\nOffice: %-.11s", pers->office); 55718606Sedward if (pers->officephone) { 55818606Sedward printf(", %s", pers->officephone); 55918606Sedward if (pers->homephone) 56018606Sedward printf("\t\tHome phone: %s", pers->homephone); 56118606Sedward else if (pers->random) 56218606Sedward printf("\t\t%s", pers->random); 56318606Sedward } else 56418606Sedward if (pers->homephone) 56518606Sedward printf("\t\t\tHome phone: %s", pers->homephone); 56618606Sedward else if (pers->random) 56718606Sedward printf("\t\t\t%s", pers->random); 56818606Sedward } else if (pers->officephone) { 56918606Sedward printf("\nPhone: %s", pers->officephone); 57018606Sedward if (pers->homephone) 57118606Sedward printf(", %s", pers->homephone); 57218606Sedward if (pers->random) 57318606Sedward printf(", %s", pers->random); 57418606Sedward } else if (pers->homephone) { 57518606Sedward printf("\nPhone: %s", pers->homephone); 57618606Sedward if (pers->random) 57718606Sedward printf(", %s", pers->random); 57818606Sedward } else if (pers->random) 57918606Sedward printf("\n%s", pers->random); 58018606Sedward if (unbrief) { 58118606Sedward printf("\nDirectory: %-25s", pers->pwd->pw_dir); 58218606Sedward if (*pers->pwd->pw_shell) 58318606Sedward printf("\tShell: %-s", pers->pwd->pw_shell); 5841014Sbill } 58518606Sedward if (pers->loggedin) { 58618606Sedward register char *ep = ctime(&pers->loginat); 58718606Sedward if (*pers->host) { 58818606Sedward printf("\nOn since %15.15s on %s from %s", 58918606Sedward &ep[4], pers->tty, pers->host); 59018606Sedward ltimeprint("\n", &pers->idletime, " Idle Time"); 59118606Sedward } else { 59218606Sedward printf("\nOn since %15.15s on %-*s", 59318606Sedward &ep[4], LMAX, pers->tty); 59418606Sedward ltimeprint("\t", &pers->idletime, " Idle Time"); 5951014Sbill } 59618606Sedward } else if (pers->loginat == 0) 59718606Sedward printf("\nNever logged in."); 5988842Smckusick else if (tloc - pers->loginat > 180 * 24 * 60 * 60) { 59918606Sedward register char *ep = ctime(&pers->loginat); 60018606Sedward printf("\nLast login %10.10s, %4.4s on %s", 60118606Sedward ep, ep+20, pers->tty); 60218606Sedward if (*pers->host) 60318606Sedward printf(" from %s", pers->host); 60418606Sedward } else { 60518606Sedward register char *ep = ctime(&pers->loginat); 60618606Sedward printf("\nLast login %16.16s on %s", ep, pers->tty); 60718606Sedward if (*pers->host) 60818606Sedward printf(" from %s", pers->host); 6098842Smckusick } 61018606Sedward putchar('\n'); 6111014Sbill } 6121014Sbill 6131014Sbill /* 6141014Sbill * very hacky section of code to format phone numbers. filled with 6151014Sbill * magic constants like 4, 7 and 10. 6161014Sbill */ 61718606Sedward char * 61818606Sedward phone(s, len, alldigits) 61918606Sedward register char *s; 62018606Sedward int len; 62118606Sedward char alldigits; 6221014Sbill { 62318606Sedward char fonebuf[15]; 62418606Sedward register char *p = fonebuf; 62518606Sedward register i; 6261014Sbill 62718606Sedward if (!alldigits) 62818606Sedward return (strcpy(malloc(len + 1), s)); 62918606Sedward switch (len) { 63018606Sedward case 4: 63118606Sedward *p++ = ' '; 63218606Sedward *p++ = 'x'; 63318606Sedward *p++ = '2'; 63418606Sedward *p++ = '-'; 63518606Sedward for (i = 0; i < 4; i++) 63618606Sedward *p++ = *s++; 6371014Sbill break; 63818606Sedward case 7: 63918606Sedward for (i = 0; i < 3; i++) 64018606Sedward *p++ = *s++; 64118606Sedward *p++ = '-'; 64218606Sedward for (i = 0; i < 4; i++) 64318606Sedward *p++ = *s++; 6441014Sbill break; 64518606Sedward case 10: 64618606Sedward for (i = 0; i < 3; i++) 64718606Sedward *p++ = *s++; 64818606Sedward *p++ = '-'; 64918606Sedward for (i = 0; i < 3; i++) 65018606Sedward *p++ = *s++; 65118606Sedward *p++ = '-'; 65218606Sedward for (i = 0; i < 4; i++) 65318606Sedward *p++ = *s++; 6541014Sbill break; 65518606Sedward case 0: 65618606Sedward return 0; 65718606Sedward default: 65818606Sedward return (strcpy(malloc(len + 1), s)); 6591014Sbill } 66018606Sedward *p++ = 0; 66118606Sedward return (strcpy(malloc(p - fonebuf), fonebuf)); 6621014Sbill } 6631014Sbill 66418606Sedward /* 66518606Sedward * decode the information in the gecos field of /etc/passwd 6661014Sbill */ 66718606Sedward decode(pers) 66818606Sedward register struct person *pers; 6691014Sbill { 67018606Sedward char buffer[256]; 67118606Sedward register char *bp, *gp, *lp; 67218606Sedward int alldigits; 67318606Sedward int hasspace; 67418606Sedward int len; 6751014Sbill 67618606Sedward pers->realname = 0; 67718606Sedward pers->office = 0; 67818606Sedward pers->officephone = 0; 67918606Sedward pers->homephone = 0; 68018606Sedward pers->random = 0; 68118606Sedward if (pers->pwd == 0) 68218606Sedward return; 68318606Sedward gp = pers->pwd->pw_gecos; 68418606Sedward bp = buffer; 68518606Sedward if (*gp == ASTERISK) 6861014Sbill gp++; 68718606Sedward while (*gp && *gp != COMMA) /* name */ 68818606Sedward if (*gp == SAMENAME) { 68918606Sedward lp = pers->pwd->pw_name; 69018606Sedward if (islower(*lp)) 69118606Sedward *bp++ = toupper(*lp++); 69218606Sedward while (*bp++ = *lp++) 69318606Sedward ; 69418606Sedward bp--; 69518606Sedward gp++; 69618606Sedward } else 69718606Sedward *bp++ = *gp++; 69818606Sedward *bp++ = 0; 69918606Sedward if ((len = bp - buffer) > 1) 70018606Sedward pers->realname = strcpy(malloc(len), buffer); 70118606Sedward if (*gp == COMMA) { /* office */ 70218606Sedward gp++; 70318606Sedward hasspace = 0; 70418606Sedward bp = buffer; 70518606Sedward while (*gp && *gp != COMMA) { 70618606Sedward *bp = *gp++; 70718606Sedward if (*bp == ' ') 70818606Sedward hasspace = 1; 70918606Sedward /* leave 5 for Cory and Evans expansion */ 71018606Sedward if (bp < buffer + sizeof buffer - 6) 71118606Sedward bp++; 7121014Sbill } 71318606Sedward *bp = 0; 71418606Sedward len = bp - buffer; 71518606Sedward bp--; /* point to last character */ 71618606Sedward if (hasspace || len == 0) 71718606Sedward len++; 71818606Sedward else if (*bp == CORY) { 71918606Sedward strcpy(bp, " Cory"); 72018606Sedward len += 5; 72118606Sedward } else if (*bp == EVANS) { 72218606Sedward strcpy(bp, " Evans"); 72318606Sedward len += 6; 72418606Sedward } else 72518606Sedward len++; 72618606Sedward if (len > 1) 72718606Sedward pers->office = strcpy(malloc(len), buffer); 72818606Sedward } 72918606Sedward if (*gp == COMMA) { /* office phone */ 73018606Sedward gp++; 73118606Sedward bp = buffer; 73218606Sedward alldigits = 1; 73318606Sedward while (*gp && *gp != COMMA) { 73418606Sedward *bp = *gp++; 73518606Sedward if (!isdigit(*bp)) 73618606Sedward alldigits = 0; 73718606Sedward if (bp < buffer + sizeof buffer - 1) 73818606Sedward bp++; 7391014Sbill } 74018606Sedward *bp = 0; 74118606Sedward pers->officephone = phone(buffer, bp - buffer, alldigits); 74218606Sedward } 74318606Sedward if (*gp == COMMA) { /* home phone */ 7441014Sbill gp++; 74518606Sedward bp = buffer; 7461014Sbill alldigits = 1; 74718606Sedward while (*gp && *gp != COMMA) { 7481014Sbill *bp = *gp++; 74918606Sedward if (!isdigit(*bp)) 75018606Sedward alldigits = 0; 75118606Sedward if (bp < buffer + sizeof buffer - 1) 7521014Sbill bp++; 7531014Sbill } 75418606Sedward *bp = 0; 75518606Sedward pers->homephone = phone(buffer, bp - buffer, alldigits); 7561014Sbill } 75718606Sedward if (pers->loggedin) 75818606Sedward findidle(pers); 75918606Sedward else 76018606Sedward findwhen(pers); 7611014Sbill } 7621014Sbill 76318606Sedward /* 76418606Sedward * find the last log in of a user by checking the LASTLOG file. 76518606Sedward * the entry is indexed by the uid, so this can only be done if 76618606Sedward * the uid is known (which it isn't in quick mode) 7671014Sbill */ 7681014Sbill 7691014Sbill fwopen() 7701014Sbill { 77118606Sedward if ((lf = open(LASTLOG, 0)) < 0) 77218606Sedward fprintf(stderr, "finger: %s open error\n", LASTLOG); 7731014Sbill } 7741014Sbill 77518606Sedward findwhen(pers) 77618606Sedward register struct person *pers; 7771014Sbill { 77818606Sedward struct lastlog ll; 77918606Sedward int i; 7801014Sbill 78118606Sedward if (lf >= 0) { 78218606Sedward lseek(lf, (long)pers->pwd->pw_uid * sizeof ll, 0); 78318606Sedward if ((i = read(lf, (char *)&ll, sizeof ll)) == sizeof ll) { 78418606Sedward bcopy(ll.ll_line, pers->tty, LMAX); 78518606Sedward pers->tty[LMAX] = 0; 78618606Sedward bcopy(ll.ll_host, pers->host, HMAX); 78718606Sedward pers->host[HMAX] = 0; 78818606Sedward pers->loginat = ll.ll_time; 78918606Sedward } else { 79018606Sedward if (i != 0) 79118606Sedward fprintf(stderr, "finger: %s read error\n", 79218606Sedward LASTLOG); 79318606Sedward pers->tty[0] = 0; 79418606Sedward pers->host[0] = 0; 79518606Sedward pers->loginat = 0L; 79618606Sedward } 79718606Sedward } else { 79818606Sedward pers->tty[0] = 0; 79918606Sedward pers->host[0] = 0; 8001014Sbill pers->loginat = 0L; 8011014Sbill } 8021014Sbill } 8031014Sbill 8041014Sbill fwclose() 8051014Sbill { 80618606Sedward if (lf >= 0) 80718606Sedward close(lf); 8081014Sbill } 8091014Sbill 81018606Sedward /* 81118606Sedward * find the idle time of a user by doing a stat on /dev/tty??, 81218606Sedward * where tty?? has been gotten from USERLOG, supposedly. 8131014Sbill */ 81418606Sedward findidle(pers) 81518606Sedward register struct person *pers; 8161014Sbill { 81718606Sedward struct stat ttystatus; 81818606Sedward static char buffer[20] = "/dev/"; 81918606Sedward long t; 82018606Sedward #define TTYLEN 5 8211014Sbill 82218606Sedward strcpy(buffer + TTYLEN, pers->tty); 82318606Sedward buffer[TTYLEN+LMAX] = 0; 82418606Sedward if (stat(buffer, &ttystatus) < 0) { 82518606Sedward fprintf(stderr, "finger: Can't stat %s\n", buffer); 82618606Sedward exit(4); 82718606Sedward } 82818606Sedward time(&t); 82918606Sedward if (t < ttystatus.st_atime) 8301014Sbill pers->idletime = 0L; 83118606Sedward else 83218606Sedward pers->idletime = t - ttystatus.st_atime; 83318606Sedward pers->writable = (ttystatus.st_mode & TALKABLE) == TALKABLE; 8341014Sbill } 8351014Sbill 83618606Sedward /* 83718606Sedward * print idle time in short format; this program always prints 4 characters; 83818606Sedward * if the idle time is zero, it prints 4 blanks. 8391014Sbill */ 84018606Sedward stimeprint(dt) 84118606Sedward long *dt; 8421014Sbill { 84318606Sedward register struct tm *delta; 8441014Sbill 84518606Sedward delta = gmtime(dt); 84618606Sedward if (delta->tm_yday == 0) 84718606Sedward if (delta->tm_hour == 0) 84818606Sedward if (delta->tm_min == 0) 84918606Sedward printf(" "); 85018606Sedward else 85118606Sedward printf(" %2d", delta->tm_min); 85218606Sedward else 85318606Sedward if (delta->tm_hour >= 10) 85418606Sedward printf("%3d:", delta->tm_hour); 85518606Sedward else 85618606Sedward printf("%1d:%02d", 85718606Sedward delta->tm_hour, delta->tm_min); 85818606Sedward else 85918606Sedward printf("%3dd", delta->tm_yday); 8601014Sbill } 8611014Sbill 86218606Sedward /* 86318606Sedward * print idle time in long format with care being taken not to pluralize 86418606Sedward * 1 minutes or 1 hours or 1 days. 86518606Sedward * print "prefix" first. 8661014Sbill */ 86718606Sedward ltimeprint(before, dt, after) 86818606Sedward long *dt; 86918606Sedward char *before, *after; 8701014Sbill { 87118606Sedward register struct tm *delta; 8721014Sbill 87318606Sedward delta = gmtime(dt); 87418606Sedward if (delta->tm_yday == 0 && delta->tm_hour == 0 && delta->tm_min == 0 && 87518606Sedward delta->tm_sec <= 10) 87618606Sedward return (0); 87718606Sedward printf("%s", before); 87818606Sedward if (delta->tm_yday >= 10) 87918606Sedward printf("%d days", delta->tm_yday); 88018606Sedward else if (delta->tm_yday > 0) 88118606Sedward printf("%d day%s %d hour%s", 88218606Sedward delta->tm_yday, delta->tm_yday == 1 ? "" : "s", 88318606Sedward delta->tm_hour, delta->tm_hour == 1 ? "" : "s"); 88418606Sedward else 88518606Sedward if (delta->tm_hour >= 10) 88618606Sedward printf("%d hours", delta->tm_hour); 88718606Sedward else if (delta->tm_hour > 0) 88818606Sedward printf("%d hour%s %d minute%s", 88918606Sedward delta->tm_hour, delta->tm_hour == 1 ? "" : "s", 89018606Sedward delta->tm_min, delta->tm_min == 1 ? "" : "s"); 89118606Sedward else 89218606Sedward if (delta->tm_min >= 10) 89318606Sedward printf("%2d minutes", delta->tm_min); 89418606Sedward else if (delta->tm_min == 0) 89518606Sedward printf("%2d seconds", delta->tm_sec); 89618606Sedward else 89718606Sedward printf("%d minute%s %d second%s", 89818606Sedward delta->tm_min, 89918606Sedward delta->tm_min == 1 ? "" : "s", 90018606Sedward delta->tm_sec, 90118606Sedward delta->tm_sec == 1 ? "" : "s"); 90218606Sedward printf("%s", after); 9031014Sbill } 9041014Sbill 90518606Sedward matchcmp(gname, login, given) 90618606Sedward register char *gname; 90718606Sedward char *login; 90818606Sedward char *given; 9091014Sbill { 91018606Sedward char buffer[100]; 91118606Sedward register char *bp, *lp; 91218606Sedward register c; 9131014Sbill 91418606Sedward if (*gname == ASTERISK) 91518606Sedward gname++; 91618606Sedward lp = 0; 91718606Sedward bp = buffer; 91818606Sedward for (;;) 91918606Sedward switch (c = *gname++) { 92018606Sedward case SAMENAME: 92118606Sedward for (lp = login; bp < buffer + sizeof buffer 92218606Sedward && (*bp++ = *lp++);) 92318606Sedward ; 92418606Sedward bp--; 92518606Sedward break; 92618606Sedward case ' ': 92718606Sedward case COMMA: 92818606Sedward case '\0': 92918606Sedward *bp = 0; 93018606Sedward if (namecmp(buffer, given)) 93118606Sedward return (1); 93218606Sedward if (c == COMMA || c == 0) 93318606Sedward return (0); 93418606Sedward bp = buffer; 93518606Sedward break; 93618606Sedward default: 93718606Sedward if (bp < buffer + sizeof buffer) 93818606Sedward *bp++ = c; 9391014Sbill } 94018606Sedward /*NOTREACHED*/ 9411014Sbill } 9421014Sbill 94318606Sedward namecmp(name1, name2) 94418606Sedward register char *name1, *name2; 9451014Sbill { 94618606Sedward register c1, c2; 9471014Sbill 94818606Sedward for (;;) { 94918606Sedward c1 = *name1++; 95018606Sedward if (islower(c1)) 95118606Sedward c1 = toupper(c1); 95218606Sedward c2 = *name2++; 95318606Sedward if (islower(c2)) 95418606Sedward c2 = toupper(c2); 95518606Sedward if (c1 != c2) 95618606Sedward break; 95718606Sedward if (c1 == 0) 95818606Sedward return (1); 9591014Sbill } 96018606Sedward if (!c1) { 96118606Sedward for (name2--; isdigit(*name2); name2++) 96218606Sedward ; 96318606Sedward if (*name2 == 0) 96418606Sedward return (1); 96518606Sedward } else if (!c2) { 96618606Sedward for (name1--; isdigit(*name1); name1++) 96718606Sedward ; 96818606Sedward if (*name2 == 0) 96918606Sedward return (1); 9701014Sbill } 97118606Sedward return (0); 9721014Sbill } 9731014Sbill 97416469Ssam netfinger(name) 97518606Sedward char *name; 97616469Ssam { 97716469Ssam char *host; 97816469Ssam char fname[100]; 97916469Ssam struct hostent *hp; 98016469Ssam struct servent *sp; 98118606Sedward struct sockaddr_in sin; 98216469Ssam int s; 98316469Ssam char *rindex(); 98416469Ssam register FILE *f; 98516469Ssam register int c; 98616469Ssam register int lastc; 98716469Ssam 98816469Ssam if (name == NULL) 98918606Sedward return (0); 99016469Ssam host = rindex(name, '@'); 99116469Ssam if (host == NULL) 99218606Sedward return (0); 99316469Ssam *host++ = 0; 99416469Ssam hp = gethostbyname(host); 99516469Ssam if (hp == NULL) { 99616469Ssam static struct hostent def; 99716469Ssam static struct in_addr defaddr; 99816469Ssam static char namebuf[128]; 99916469Ssam int inet_addr(); 100016469Ssam 100116469Ssam defaddr.s_addr = inet_addr(host); 100216469Ssam if (defaddr.s_addr == -1) { 100316469Ssam printf("unknown host: %s\n", host); 100418606Sedward return (1); 100516469Ssam } 100616469Ssam strcpy(namebuf, host); 100716469Ssam def.h_name = namebuf; 100816469Ssam def.h_addr = (char *)&defaddr; 100916469Ssam def.h_length = sizeof (struct in_addr); 101016469Ssam def.h_addrtype = AF_INET; 101116469Ssam def.h_aliases = 0; 101216469Ssam hp = &def; 101316469Ssam } 101416469Ssam printf("[%s]", hp->h_name); 101516469Ssam sp = getservbyname("finger", "tcp"); 101616469Ssam if (sp == 0) { 101716469Ssam printf("tcp/finger: unknown service\n"); 101818606Sedward return (1); 101916469Ssam } 102016469Ssam sin.sin_family = hp->h_addrtype; 102116469Ssam bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length); 102216469Ssam sin.sin_port = sp->s_port; 102316469Ssam s = socket(hp->h_addrtype, SOCK_STREAM, 0); 102416469Ssam if (s < 0) { 102516469Ssam fflush(stdout); 102616469Ssam perror("socket"); 102718606Sedward return (1); 102816469Ssam } 102916469Ssam if (connect(s, (char *)&sin, sizeof (sin)) < 0) { 103016469Ssam fflush(stdout); 103116469Ssam perror("connect"); 103216469Ssam close(s); 103318606Sedward return (1); 103416469Ssam } 103516469Ssam printf("\n"); 103616469Ssam if (large) write(s, "/W ", 3); 103716469Ssam write(s, name, strlen(name)); 103816469Ssam write(s, "\r\n", 2); 103916469Ssam f = fdopen(s, "r"); 104016469Ssam while ((c = getc(f)) != EOF) { 104116469Ssam switch(c) { 104216469Ssam case 0210: 104316469Ssam case 0211: 104416469Ssam case 0212: 104516469Ssam case 0214: 104616469Ssam c -= 0200; 104716469Ssam break; 104816469Ssam case 0215: 104916469Ssam c = '\n'; 105016469Ssam break; 105116469Ssam } 105216469Ssam putchar(lastc = c); 105316469Ssam } 105416469Ssam if (lastc != '\n') 105516469Ssam putchar('\n'); 105618606Sedward return (1); 105716469Ssam } 1058