pst@anise.acc.com (Paul Traina) (07/06/89)
I was sick and tired of the stupid bugs in the Apple/Unisoft port of finger(1) to SystemV, so here is a shar file that contains the diff of the 4.3-tahoe finger.c so that it will compile on a A/UX system. It should work on any Uniplus based SystemV (and perhaps on some others too). finger(1) is untainted by AT&T lawyers and is available on uunet. For those without access to finger.c, I've also included my modified finger.c in toto. Previous bugs now fixed: finger used to report that a user was logged in, even if they were not, if they had ever logged in before. repeat by: login to two or different terminals & then logout do finger your-name@aux-machine finger incorrectly shows that you're there. cause: System V treats the utmp file differently. We needed to check ut_type as well as ut_uid to see which ttys the user was logged in on. finger couldn't deal with last-login-time when user wasn't logged in. repeat by: make sure you're not logged in on aux-host do finger your-name@aux-machine from remote site it says you've never logged in. cause: System V doesn't have /usr/adm/lastlog. It does have /etc/wtmp. We now cruise through wtmp (backwards) looking for last occurance of a user's login & glom the information that way. (Yes, its not as nice as lastlog, but at least it works). As usual, this is "as-is". Have fun (remember to compile with -DUSG). Happy Hacking, the PST #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: finger.diff finger.c # Wrapped by pst@anise.acc.com on Wed Jul 5 17:27:40 1989 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'finger.diff' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'finger.diff'\" else echo shar: Extracting \"'finger.diff'\" \(7315 characters\) sed "s/^X//" >'finger.diff' <<'END_OF_FILE' X*** finger.orig Wed Jul 5 17:21:36 1989 X--- finger.c Wed Jul 5 17:23:41 1989 X*************** X*** 58,64 X #include <sys/signal.h> X #include <pwd.h> X #include <stdio.h> X- #include <lastlog.h> X #include <ctype.h> X #include <sys/time.h> X #include <sys/socket.h> X X--- 58,63 ----- X #include <sys/signal.h> X #include <pwd.h> X #include <stdio.h> X #include <ctype.h> X #ifdef USG X #include <time.h> X*************** X*** 60,65 X #include <stdio.h> X #include <lastlog.h> X #include <ctype.h> X #include <sys/time.h> X #include <sys/socket.h> X #include <netinet/in.h> X X--- 59,68 ----- X #include <pwd.h> X #include <stdio.h> X #include <ctype.h> X+ #ifdef USG X+ #include <time.h> X+ #else X+ #include <lastlog.h> X #include <sys/time.h> X #endif X #include <sys/socket.h> X*************** X*** 61,66 X #include <lastlog.h> X #include <ctype.h> X #include <sys/time.h> X #include <sys/socket.h> X #include <netinet/in.h> X #include <netdb.h> X X--- 64,70 ----- X #else X #include <lastlog.h> X #include <sys/time.h> X+ #endif X #include <sys/socket.h> X #include <netinet/in.h> X #include <netdb.h> X*************** X*** 96,101 X struct person *link; /* link to next person */ X }; X X char LASTLOG[] = "/usr/adm/lastlog"; /* last login info */ X char USERLOG[] = "/etc/utmp"; /* who is logged in */ X char PLAN[] = "/.plan"; /* what plan file is */ X X--- 100,108 ----- X struct person *link; /* link to next person */ X }; X X+ #ifdef USG X+ char LASTLOG[] = "/etc/wtmp"; X+ #else X char LASTLOG[] = "/usr/adm/lastlog"; /* last login info */ X #endif X char USERLOG[] = "/etc/utmp"; /* who is logged in */ X*************** X*** 97,102 X }; X X char LASTLOG[] = "/usr/adm/lastlog"; /* last login info */ X char USERLOG[] = "/etc/utmp"; /* who is logged in */ X char PLAN[] = "/.plan"; /* what plan file is */ X char PROJ[] = "/.project"; /* what project file */ X X--- 104,110 ----- X char LASTLOG[] = "/etc/wtmp"; X #else X char LASTLOG[] = "/usr/adm/lastlog"; /* last login info */ X+ #endif X char USERLOG[] = "/etc/utmp"; /* who is logged in */ X char PLAN[] = "/.plan"; /* what plan file is */ X char PROJ[] = "/.project"; /* what project file */ X*************** X*** 195,200 X exit(2); X } X if (unquick) { X extern _pw_stayopen; X X setpwent(); X X--- 203,209 ----- X exit(2); X } X if (unquick) { X+ #ifndef USG X extern _pw_stayopen; X #endif X setpwent(); X*************** X*** 196,202 X } X if (unquick) { X extern _pw_stayopen; X! X setpwent(); X _pw_stayopen = 1; X fwopen(); X X--- 205,211 ----- X if (unquick) { X #ifndef USG X extern _pw_stayopen; X! #endif X setpwent(); X #ifndef USG X _pw_stayopen = 1; X*************** X*** 198,203 X extern _pw_stayopen; X X setpwent(); X _pw_stayopen = 1; X fwopen(); X } X X--- 207,213 ----- X extern _pw_stayopen; X #endif X setpwent(); X+ #ifndef USG X _pw_stayopen = 1; X #endif X fwopen(); X*************** X*** 199,204 X X setpwent(); X _pw_stayopen = 1; X fwopen(); X } X while (read(uf, (char *)&user, sizeof user) == sizeof user) { X X--- 209,215 ----- X setpwent(); X #ifndef USG X _pw_stayopen = 1; X+ #endif X fwopen(); X } X while (read(uf, (char *)&user, sizeof user) == sizeof user) { X*************** X*** 202,207 X fwopen(); X } X while (read(uf, (char *)&user, sizeof user) == sizeof user) { X if (user.ut_name[0] == 0) X continue; X if (person1 == 0) X X--- 213,221 ----- X fwopen(); X } X while (read(uf, (char *)&user, sizeof user) == sizeof user) { X+ #ifdef USG X+ if (user.ut_name[0] == 0 || user.ut_type != USER_PROCESS) X+ #else X if (user.ut_name[0] == 0) X #endif X continue; X*************** X*** 203,208 X } X while (read(uf, (char *)&user, sizeof user) == sizeof user) { X if (user.ut_name[0] == 0) X continue; X if (person1 == 0) X p = person1 = (struct person *) malloc(sizeof *p); X X--- 217,223 ----- X if (user.ut_name[0] == 0 || user.ut_type != USER_PROCESS) X #else X if (user.ut_name[0] == 0) X+ #endif X continue; X if (person1 == 0) X p = person1 = (struct person *) malloc(sizeof *p); X*************** X*** 273,278 X if (unquick) { X setpwent(); X if (!match) { X extern _pw_stayopen; X X _pw_stayopen = 1; X X--- 288,294 ----- X if (unquick) { X setpwent(); X if (!match) { X+ #ifndef USG X extern _pw_stayopen; X X _pw_stayopen = 1; X*************** X*** 276,281 X extern _pw_stayopen; X X _pw_stayopen = 1; X for (p = person1; p != 0; p = p->link) X if (pw = getpwnam(p->name)) X p->pwd = pwdcopy(pw); X X--- 292,298 ----- X extern _pw_stayopen; X X _pw_stayopen = 1; X+ #endif X for (p = person1; p != 0; p = p->link) X if (pw = getpwnam(p->name)) X p->pwd = pwdcopy(pw); X*************** X*** 315,320 X exit(2); X } X while (read(uf, (char *)&user, sizeof user) == sizeof user) { X if (*user.ut_name == 0) X continue; X for (p = person1; p != 0; p = p->link) { X X--- 332,340 ----- X exit(2); X } X while (read(uf, (char *)&user, sizeof user) == sizeof user) { X+ #ifdef USG X+ if (*user.ut_name == 0 || user.ut_type != USER_PROCESS) X+ #else X if (*user.ut_name == 0) X #endif X continue; X*************** X*** 316,321 X } X while (read(uf, (char *)&user, sizeof user) == sizeof user) { X if (*user.ut_name == 0) X continue; X for (p = person1; p != 0; p = p->link) { X if (p->loggedin == 2) X X--- 336,342 ----- X if (*user.ut_name == 0 || user.ut_type != USER_PROCESS) X #else X if (*user.ut_name == 0) X+ #endif X continue; X for (p = person1; p != 0; p = p->link) { X if (p->loggedin == 2) X*************** X*** 792,797 X findwhen(pers) X register struct person *pers; X { X struct lastlog ll; X int i; X X X--- 813,821 ----- X findwhen(pers) X register struct person *pers; X { X+ #ifdef USG X+ struct utmp ut; X+ #else X struct lastlog ll; X #endif X int i; X*************** X*** 793,798 X register struct person *pers; X { X struct lastlog ll; X int i; X X if (lf >= 0) { X X--- 817,823 ----- X struct utmp ut; X #else X struct lastlog ll; X+ #endif X int i; X X if (lf >= 0) { X*************** X*** 796,801 X int i; X X if (lf >= 0) { X lseek(lf, (long)pers->pwd->pw_uid * sizeof ll, 0); X if ((i = read(lf, (char *)&ll, sizeof ll)) == sizeof ll) { X bcopy(ll.ll_line, pers->tty, LMAX); X X--- 821,845 ----- X int i; X X if (lf >= 0) { X+ #ifdef USG X+ lseek(lf, (long) (sizeof ut), 2); X+ while (lseek(lf, (long) (-2 * sizeof ut), 1) >= 0) { X+ read(lf, (char *)&ut, sizeof ut); X+ if (ut.ut_type == USER_PROCESS && X+ !strncmp(ut.ut_user, pers->name)) { X+ bcopy(ut.ut_line, pers->tty, LMAX); X+ pers->tty[LMAX] = '\0'; X+ bcopy(ut.ut_host, pers->host, HMAX); X+ pers->host[HMAX] = '\0'; X+ pers->loginat = ut.ut_time; X+ return; X+ } else X+ continue; X+ } X+ pers->tty[0] = 0; X+ pers->host[0] = 0; X+ pers->loginat = 0L; X+ #else X lseek(lf, (long)pers->pwd->pw_uid * sizeof ll, 0); X if ((i = read(lf, (char *)&ll, sizeof ll)) == sizeof ll) { X bcopy(ll.ll_line, pers->tty, LMAX); X*************** X*** 811,816 X pers->host[0] = 0; X pers->loginat = 0L; X } X } else { X pers->tty[0] = 0; X pers->host[0] = 0; X X--- 855,861 ----- X pers->host[0] = 0; X pers->loginat = 0L; X } X+ #endif X } else { X pers->tty[0] = 0; X pers->host[0] = 0; END_OF_FILE if test 7315 -ne `wc -c <'finger.diff'`; then echo shar: \"'finger.diff'\" unpacked with wrong size! fi # end of 'finger.diff' fi if test -f 'finger.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'finger.c'\" else echo shar: Extracting \"'finger.c'\" \(25816 characters\) sed "s/^X//" >'finger.c' <<'END_OF_FILE' X/* X * Copyright (c) 1980 Regents of the University of California. X * All rights reserved. The Berkeley software License Agreement X * specifies the terms and conditions for redistribution. X */ X X#ifndef lint Xchar copyright[] = X"@(#) Copyright (c) 1980 Regents of the University of California.\n\ X All rights reserved.\n"; X#endif not lint X X#ifndef lint Xstatic char sccsid[] = "@(#)finger.c 5.10 (Berkeley) 4/26/87"; X#endif not lint X X/* X * This is a finger program. It prints out useful information about users X * by digging it up from various system files. It is not very portable X * because the most useful parts of the information (the full user name, X * office, and phone numbers) are all stored in the VAX-unused gecos field X * of /etc/passwd, which, unfortunately, other UNIXes use for other things. X * X * There are three output formats, all of which give login name, teletype X * line number, and login time. The short output format is reminiscent X * of finger on ITS, and gives one line of information per user containing X * in addition to the minimum basic requirements (MBR), the full name of X * the user, his idle time and office location and phone number. The X * quick style output is UNIX who-like, giving only name, teletype and X * login time. Finally, the long style output give the same information X * as the short (in more legible format), the home directory and shell X * of the user, and, if it exits, a copy of the file .plan in the users X * home directory. Finger may be called with or without a list of people X * to finger -- if no list is given, all the people currently logged in X * are fingered. X * X * The program is validly called by one of the following: X * X * finger {short form list of users} X * finger -l {long form list of users} X * finger -b {briefer long form list of users} X * finger -q {quick list of users} X * finger -i {quick list of users with idle times} X * finger namelist {long format list of specified users} X * finger -s namelist {short format list of specified users} X * finger -w namelist {narrow short format list of specified users} X * X * where 'namelist' is a list of users login names. X * The other options can all be given after one '-', or each can have its X * own '-'. The -f option disables the printing of headers for short and X * quick outputs. The -b option briefens long format outputs. The -p X * option turns off plans for long format outputs. X */ X X#include <sys/types.h> X#include <sys/stat.h> X#include <utmp.h> X#include <sys/signal.h> X#include <pwd.h> X#include <stdio.h> X#include <ctype.h> X#ifdef USG X#include <time.h> X#else X#include <lastlog.h> X#include <sys/time.h> X#endif X#include <sys/socket.h> X#include <netinet/in.h> X#include <netdb.h> X X#define ASTERISK '*' /* ignore this in real name */ X#define COMMA ',' /* separator in pw_gecos field */ X#define COMMAND '-' /* command line flag char */ X#define CORY 'C' /* cory hall office */ X#define EVANS 'E' /* evans hall office */ X#define SAMENAME '&' /* repeat login name in real name */ X#define TALKABLE 0220 /* tty is writable if 220 mode */ X Xstruct utmp user; X#define NMAX sizeof(user.ut_name) X#define LMAX sizeof(user.ut_line) X#define HMAX sizeof(user.ut_host) X Xstruct person { /* one for each person fingered */ X char *name; /* name */ X char tty[LMAX+1]; /* null terminated tty line */ X char host[HMAX+1]; /* null terminated remote host name */ X long loginat; /* time of (last) login */ X long idletime; /* how long idle (if logged in) */ X char *realname; /* pointer to full name */ X char *office; /* pointer to office name */ X char *officephone; /* pointer to office phone no. */ X char *homephone; /* pointer to home phone no. */ X char *random; /* for any random stuff in pw_gecos */ X struct passwd *pwd; /* structure of /etc/passwd stuff */ X char loggedin; /* person is logged in */ X char writable; /* tty is writable */ X char original; /* this is not a duplicate entry */ X struct person *link; /* link to next person */ X}; X X#ifdef USG Xchar LASTLOG[] = "/etc/wtmp"; X#else Xchar LASTLOG[] = "/usr/adm/lastlog"; /* last login info */ X#endif Xchar USERLOG[] = "/etc/utmp"; /* who is logged in */ Xchar PLAN[] = "/.plan"; /* what plan file is */ Xchar PROJ[] = "/.project"; /* what project file */ X Xint unbrief = 1; /* -b option default */ Xint header = 1; /* -f option default */ Xint hack = 1; /* -h option default */ Xint idle = 0; /* -i option default */ Xint large = 0; /* -l option default */ Xint match = 1; /* -m option default */ Xint plan = 1; /* -p option default */ Xint unquick = 1; /* -q option default */ Xint small = 0; /* -s option default */ Xint wide = 1; /* -w option default */ X Xint unshort; Xint lf; /* LASTLOG file descriptor */ Xstruct person *person1; /* list of people */ Xlong tloc; /* current time */ X Xstruct passwd *pwdcopy(); Xchar *strcpy(); Xchar *malloc(); Xchar *ctime(); X Xmain(argc, argv) X int argc; X register char **argv; X{ X FILE *fp; X register char *s; X X /* parse command line for (optional) arguments */ X while (*++argv && **argv == COMMAND) X for (s = *argv + 1; *s; s++) X switch (*s) { X case 'b': X unbrief = 0; X break; X case 'f': X header = 0; X break; X case 'h': X hack = 0; X break; X case 'i': X idle = 1; X unquick = 0; X break; X case 'l': X large = 1; X break; X case 'm': X match = 0; X break; X case 'p': X plan = 0; X break; X case 'q': X unquick = 0; X break; X case 's': X small = 1; X break; X case 'w': X wide = 0; X break; X default: X fprintf(stderr, "Usage: finger [-bfhilmpqsw] [login1 [login2 ...] ]\n"); X exit(1); X } X if (unquick || idle) X time(&tloc); X /* X * *argv == 0 means no names given X */ X if (*argv == 0) X doall(); X else X donames(argv); X if (person1) X print(); X exit(0); X} X Xdoall() X{ X register struct person *p; X register struct passwd *pw; X int uf; X char name[NMAX + 1]; X X unshort = large; X if ((uf = open(USERLOG, 0)) < 0) { X fprintf(stderr, "finger: error opening %s\n", USERLOG); X exit(2); X } X if (unquick) { X#ifndef USG X extern _pw_stayopen; X#endif X setpwent(); X#ifndef USG X _pw_stayopen = 1; X#endif X fwopen(); X } X while (read(uf, (char *)&user, sizeof user) == sizeof user) { X#ifdef USG X if (user.ut_name[0] == 0 || user.ut_type != USER_PROCESS) X#else X if (user.ut_name[0] == 0) X#endif X continue; X if (person1 == 0) X p = person1 = (struct person *) malloc(sizeof *p); X else { X p->link = (struct person *) malloc(sizeof *p); X p = p->link; X } X bcopy(user.ut_name, name, NMAX); X name[NMAX] = 0; X bcopy(user.ut_line, p->tty, LMAX); X p->tty[LMAX] = 0; X bcopy(user.ut_host, p->host, HMAX); X p->host[HMAX] = 0; X p->loginat = user.ut_time; X p->pwd = 0; X p->loggedin = 1; X if (unquick && (pw = getpwnam(name))) { X p->pwd = pwdcopy(pw); X decode(p); X p->name = p->pwd->pw_name; X } else X p->name = strcpy(malloc(strlen(name) + 1), name); X } X if (unquick) { X fwclose(); X endpwent(); X } X close(uf); X if (person1 == 0) { X printf("No one logged on\n"); X return; X } X p->link = 0; X} X Xdonames(argv) X char **argv; X{ X register struct person *p; X register struct passwd *pw; X int uf; X X /* X * get names from command line and check to see if they're X * logged in X */ X unshort = !small; X for (; *argv != 0; argv++) { X if (netfinger(*argv)) X continue; X if (person1 == 0) X p = person1 = (struct person *) malloc(sizeof *p); X else { X p->link = (struct person *) malloc(sizeof *p); X p = p->link; X } X p->name = *argv; X p->loggedin = 0; X p->original = 1; X p->pwd = 0; X } X if (person1 == 0) X return; X p->link = 0; X /* X * if we are doing it, read /etc/passwd for the useful info X */ X if (unquick) { X setpwent(); X if (!match) { X#ifndef USG X extern _pw_stayopen; X X _pw_stayopen = 1; X#endif X for (p = person1; p != 0; p = p->link) X if (pw = getpwnam(p->name)) X p->pwd = pwdcopy(pw); X } else while ((pw = getpwent()) != 0) { X for (p = person1; p != 0; p = p->link) { X if (!p->original) X continue; X if (strcmp(p->name, pw->pw_name) != 0 && X !matchcmp(pw->pw_gecos, pw->pw_name, p->name)) X continue; X if (p->pwd == 0) X p->pwd = pwdcopy(pw); X else { X struct person *new; X /* X * handle multiple login names, insert X * new "duplicate" entry behind X */ X new = (struct person *) X malloc(sizeof *new); X new->pwd = pwdcopy(pw); X new->name = p->name; X new->original = 1; X new->loggedin = 0; X new->link = p->link; X p->original = 0; X p->link = new; X p = new; X } X } X } X endpwent(); X } X /* Now get login information */ X if ((uf = open(USERLOG, 0)) < 0) { X fprintf(stderr, "finger: error opening %s\n", USERLOG); X exit(2); X } X while (read(uf, (char *)&user, sizeof user) == sizeof user) { X#ifdef USG X if (*user.ut_name == 0 || user.ut_type != USER_PROCESS) X#else X if (*user.ut_name == 0) X#endif X continue; X for (p = person1; p != 0; p = p->link) { X if (p->loggedin == 2) X continue; X if (strncmp(p->pwd ? p->pwd->pw_name : p->name, X user.ut_name, NMAX) != 0) X continue; X if (p->loggedin == 0) { X bcopy(user.ut_line, p->tty, LMAX); X p->tty[LMAX] = 0; X bcopy(user.ut_host, p->host, HMAX); X p->host[HMAX] = 0; X p->loginat = user.ut_time; X p->loggedin = 1; X } else { /* p->loggedin == 1 */ X struct person *new; X new = (struct person *) malloc(sizeof *new); X new->name = p->name; X bcopy(user.ut_line, new->tty, LMAX); X new->tty[LMAX] = 0; X bcopy(user.ut_host, new->host, HMAX); X new->host[HMAX] = 0; X new->loginat = user.ut_time; X new->pwd = p->pwd; X new->loggedin = 1; X new->original = 0; X new->link = p->link; X p->loggedin = 2; X p->link = new; X p = new; X } X } X } X close(uf); X if (unquick) { X fwopen(); X for (p = person1; p != 0; p = p->link) X decode(p); X fwclose(); X } X} X Xprint() X{ X register FILE *fp; X register struct person *p; X register char *s; X register c; X X /* X * print out what we got X */ X if (header) { X if (unquick) { X if (!unshort) X if (wide) X printf("Login Name TTY Idle When Office\n"); X else X printf("Login TTY Idle When Office\n"); X } else { X printf("Login TTY When"); X if (idle) X printf(" Idle"); X putchar('\n'); X } X } X for (p = person1; p != 0; p = p->link) { X if (!unquick) { X quickprint(p); X continue; X } X if (!unshort) { X shortprint(p); X continue; X } X personprint(p); X if (p->pwd != 0) { X if (hack) { X s = malloc(strlen(p->pwd->pw_dir) + X sizeof PROJ); X strcpy(s, p->pwd->pw_dir); X strcat(s, PROJ); X if ((fp = fopen(s, "r")) != 0) { X printf("Project: "); X while ((c = getc(fp)) != EOF) { X if (c == '\n') X break; X if (isprint(c) || isspace(c)) X putchar(c); X else X putchar(c ^ 100); X } X fclose(fp); X putchar('\n'); X } X free(s); X } X if (plan) { X s = malloc(strlen(p->pwd->pw_dir) + X sizeof PLAN); X strcpy(s, p->pwd->pw_dir); X strcat(s, PLAN); X if ((fp = fopen(s, "r")) == 0) X printf("No Plan.\n"); X else { X printf("Plan:\n"); X while ((c = getc(fp)) != EOF) X if (isprint(c) || isspace(c)) X putchar(c); X else X putchar(c ^ 100); X fclose(fp); X } X free(s); X } X } X if (p->link != 0) X putchar('\n'); X } X} X X/* X * Duplicate a pwd entry. X * Note: Only the useful things (what the program currently uses) are copied. X */ Xstruct passwd * Xpwdcopy(pfrom) X register struct passwd *pfrom; X{ X register struct passwd *pto; X X pto = (struct passwd *) malloc(sizeof *pto); X#define savestr(s) strcpy(malloc(strlen(s) + 1), s) X pto->pw_name = savestr(pfrom->pw_name); X pto->pw_uid = pfrom->pw_uid; X pto->pw_gecos = savestr(pfrom->pw_gecos); X pto->pw_dir = savestr(pfrom->pw_dir); X pto->pw_shell = savestr(pfrom->pw_shell); X#undef savestr X return pto; X} X X/* X * print out information on quick format giving just name, tty, login time X * and idle time if idle is set. X */ Xquickprint(pers) X register struct person *pers; X{ X printf("%-*.*s ", NMAX, NMAX, pers->name); X if (pers->loggedin) { X if (idle) { X findidle(pers); X printf("%c%-*s %-16.16s", pers->writable ? ' ' : '*', X LMAX, pers->tty, ctime(&pers->loginat)); X ltimeprint(" ", &pers->idletime, ""); X } else X printf(" %-*s %-16.16s", LMAX, X pers->tty, ctime(&pers->loginat)); X putchar('\n'); X } else X printf(" Not Logged In\n"); X} X X/* X * print out information in short format, giving login name, full name, X * tty, idle time, login time, office location and phone. X */ Xshortprint(pers) X register struct person *pers; X{ X char *p; X char dialup; X X if (pers->pwd == 0) { X printf("%-15s ???\n", pers->name); X return; X } X printf("%-*s", NMAX, pers->pwd->pw_name); X dialup = 0; X if (wide) { X if (pers->realname) X printf(" %-20.20s", pers->realname); X else X printf(" ??? "); X } X putchar(' '); X if (pers->loggedin && !pers->writable) X putchar('*'); X else X putchar(' '); X if (*pers->tty) { X if (pers->tty[0] == 't' && pers->tty[1] == 't' && X pers->tty[2] == 'y') { X if (pers->tty[3] == 'd' && pers->loggedin) X dialup = 1; X printf("%-2.2s ", pers->tty + 3); X } else X printf("%-2.2s ", pers->tty); X } else X printf(" "); X p = ctime(&pers->loginat); X if (pers->loggedin) { X stimeprint(&pers->idletime); X printf(" %3.3s %-5.5s ", p, p + 11); X } else if (pers->loginat == 0) X printf(" < . . . . >"); X else if (tloc - pers->loginat >= 180 * 24 * 60 * 60) X printf(" <%-6.6s, %-4.4s>", p + 4, p + 20); X else X printf(" <%-12.12s>", p + 4); X if (dialup && pers->homephone) X printf(" %20s", pers->homephone); X else { X if (pers->office) X printf(" %-11.11s", pers->office); X else if (pers->officephone || pers->homephone) X printf(" "); X if (pers->officephone) X printf(" %s", pers->officephone); X else if (pers->homephone) X printf(" %s", pers->homephone); X } X putchar('\n'); X} X X/* X * print out a person in long format giving all possible information. X * directory and shell are inhibited if unbrief is clear. X */ Xpersonprint(pers) X register struct person *pers; X{ X if (pers->pwd == 0) { X printf("Login name: %-10s\t\t\tIn real life: ???\n", X pers->name); X return; X } X printf("Login name: %-10s", pers->pwd->pw_name); X if (pers->loggedin && !pers->writable) X printf(" (messages off) "); X else X printf(" "); X if (pers->realname) X printf("In real life: %s", pers->realname); X if (pers->office) { X printf("\nOffice: %-.11s", pers->office); X if (pers->officephone) { X printf(", %s", pers->officephone); X if (pers->homephone) X printf("\t\tHome phone: %s", pers->homephone); X else if (pers->random) X printf("\t\t%s", pers->random); X } else X if (pers->homephone) X printf("\t\t\tHome phone: %s", pers->homephone); X else if (pers->random) X printf("\t\t\t%s", pers->random); X } else if (pers->officephone) { X printf("\nPhone: %s", pers->officephone); X if (pers->homephone) X printf(", %s", pers->homephone); X if (pers->random) X printf(", %s", pers->random); X } else if (pers->homephone) { X printf("\nPhone: %s", pers->homephone); X if (pers->random) X printf(", %s", pers->random); X } else if (pers->random) X printf("\n%s", pers->random); X if (unbrief) { X printf("\nDirectory: %-25s", pers->pwd->pw_dir); X if (*pers->pwd->pw_shell) X printf("\tShell: %-s", pers->pwd->pw_shell); X } X if (pers->loggedin) { X register char *ep = ctime(&pers->loginat); X if (*pers->host) { X printf("\nOn since %15.15s on %s from %s", X &ep[4], pers->tty, pers->host); X ltimeprint("\n", &pers->idletime, " Idle Time"); X } else { X printf("\nOn since %15.15s on %-*s", X &ep[4], LMAX, pers->tty); X ltimeprint("\t", &pers->idletime, " Idle Time"); X } X } else if (pers->loginat == 0) X printf("\nNever logged in."); X else if (tloc - pers->loginat > 180 * 24 * 60 * 60) { X register char *ep = ctime(&pers->loginat); X printf("\nLast login %10.10s, %4.4s on %s", X ep, ep+20, pers->tty); X if (*pers->host) X printf(" from %s", pers->host); X } else { X register char *ep = ctime(&pers->loginat); X printf("\nLast login %16.16s on %s", ep, pers->tty); X if (*pers->host) X printf(" from %s", pers->host); X } X putchar('\n'); X} X X/* X * very hacky section of code to format phone numbers. filled with X * magic constants like 4, 7 and 10. X */ Xchar * Xphone(s, len, alldigits) X register char *s; X int len; X char alldigits; X{ X char fonebuf[15]; X register char *p = fonebuf; X register i; X X if (!alldigits) X return (strcpy(malloc(len + 1), s)); X switch (len) { X case 4: X *p++ = ' '; X *p++ = 'x'; X *p++ = '2'; X *p++ = '-'; X for (i = 0; i < 4; i++) X *p++ = *s++; X break; X case 5: X *p++ = ' '; X *p++ = 'x'; X *p++ = *s++; X *p++ = '-'; X for (i = 0; i < 4; i++) X *p++ = *s++; X break; X case 7: X for (i = 0; i < 3; i++) X *p++ = *s++; X *p++ = '-'; X for (i = 0; i < 4; i++) X *p++ = *s++; X break; X case 10: X for (i = 0; i < 3; i++) X *p++ = *s++; X *p++ = '-'; X for (i = 0; i < 3; i++) X *p++ = *s++; X *p++ = '-'; X for (i = 0; i < 4; i++) X *p++ = *s++; X break; X case 0: X return 0; X default: X return (strcpy(malloc(len + 1), s)); X } X *p++ = 0; X return (strcpy(malloc(p - fonebuf), fonebuf)); X} X X/* X * decode the information in the gecos field of /etc/passwd X */ Xdecode(pers) X register struct person *pers; X{ X char buffer[256]; X register char *bp, *gp, *lp; X int alldigits; X int hasspace; X int len; X X pers->realname = 0; X pers->office = 0; X pers->officephone = 0; X pers->homephone = 0; X pers->random = 0; X if (pers->pwd == 0) X return; X gp = pers->pwd->pw_gecos; X bp = buffer; X if (*gp == ASTERISK) X gp++; X while (*gp && *gp != COMMA) /* name */ X if (*gp == SAMENAME) { X lp = pers->pwd->pw_name; X if (islower(*lp)) X *bp++ = toupper(*lp++); X while (*bp++ = *lp++) X ; X bp--; X gp++; X } else X *bp++ = *gp++; X *bp++ = 0; X if ((len = bp - buffer) > 1) X pers->realname = strcpy(malloc(len), buffer); X if (*gp == COMMA) { /* office */ X gp++; X hasspace = 0; X bp = buffer; X while (*gp && *gp != COMMA) { X *bp = *gp++; X if (*bp == ' ') X hasspace = 1; X /* leave 5 for Cory and Evans expansion */ X if (bp < buffer + sizeof buffer - 6) X bp++; X } X *bp = 0; X len = bp - buffer; X bp--; /* point to last character */ X if (hasspace || len == 0) X len++; X else if (*bp == CORY) { X strcpy(bp, " Cory"); X len += 5; X } else if (*bp == EVANS) { X strcpy(bp, " Evans"); X len += 6; X } else X len++; X if (len > 1) X pers->office = strcpy(malloc(len), buffer); X } X if (*gp == COMMA) { /* office phone */ X gp++; X bp = buffer; X alldigits = 1; X while (*gp && *gp != COMMA) { X *bp = *gp++; X if (!isdigit(*bp)) X alldigits = 0; X if (bp < buffer + sizeof buffer - 1) X bp++; X } X *bp = 0; X pers->officephone = phone(buffer, bp - buffer, alldigits); X } X if (*gp == COMMA) { /* home phone */ X gp++; X bp = buffer; X alldigits = 1; X while (*gp && *gp != COMMA) { X *bp = *gp++; X if (!isdigit(*bp)) X alldigits = 0; X if (bp < buffer + sizeof buffer - 1) X bp++; X } X *bp = 0; X pers->homephone = phone(buffer, bp - buffer, alldigits); X } X if (pers->loggedin) X findidle(pers); X else X findwhen(pers); X} X X/* X * find the last log in of a user by checking the LASTLOG file. X * the entry is indexed by the uid, so this can only be done if X * the uid is known (which it isn't in quick mode) X */ X Xfwopen() X{ X if ((lf = open(LASTLOG, 0)) < 0) X fprintf(stderr, "finger: %s open error\n", LASTLOG); X} X Xfindwhen(pers) X register struct person *pers; X{ X#ifdef USG X struct utmp ut; X#else X struct lastlog ll; X#endif X int i; X X if (lf >= 0) { X#ifdef USG X lseek(lf, (long) (sizeof ut), 2); X while (lseek(lf, (long) (-2 * sizeof ut), 1) >= 0) { X read(lf, (char *)&ut, sizeof ut); X if (ut.ut_type == USER_PROCESS && X !strncmp(ut.ut_user, pers->name)) { X bcopy(ut.ut_line, pers->tty, LMAX); X pers->tty[LMAX] = '\0'; X bcopy(ut.ut_host, pers->host, HMAX); X pers->host[HMAX] = '\0'; X pers->loginat = ut.ut_time; X return; X } else X continue; X } X pers->tty[0] = 0; X pers->host[0] = 0; X pers->loginat = 0L; X#else X lseek(lf, (long)pers->pwd->pw_uid * sizeof ll, 0); X if ((i = read(lf, (char *)&ll, sizeof ll)) == sizeof ll) { X bcopy(ll.ll_line, pers->tty, LMAX); X pers->tty[LMAX] = 0; X bcopy(ll.ll_host, pers->host, HMAX); X pers->host[HMAX] = 0; X pers->loginat = ll.ll_time; X } else { X if (i != 0) X fprintf(stderr, "finger: %s read error\n", X LASTLOG); X pers->tty[0] = 0; X pers->host[0] = 0; X pers->loginat = 0L; X } X#endif X } else { X pers->tty[0] = 0; X pers->host[0] = 0; X pers->loginat = 0L; X } X} X Xfwclose() X{ X if (lf >= 0) X close(lf); X} X X/* X * find the idle time of a user by doing a stat on /dev/tty??, X * where tty?? has been gotten from USERLOG, supposedly. X */ Xfindidle(pers) X register struct person *pers; X{ X struct stat ttystatus; X static char buffer[20] = "/dev/"; X long t; X#define TTYLEN 5 X X strcpy(buffer + TTYLEN, pers->tty); X buffer[TTYLEN+LMAX] = 0; X if (stat(buffer, &ttystatus) < 0) { X fprintf(stderr, "finger: Can't stat %s\n", buffer); X exit(4); X } X time(&t); X if (t < ttystatus.st_atime) X pers->idletime = 0L; X else X pers->idletime = t - ttystatus.st_atime; X pers->writable = (ttystatus.st_mode & TALKABLE) == TALKABLE; X} X X/* X * print idle time in short format; this program always prints 4 characters; X * if the idle time is zero, it prints 4 blanks. X */ Xstimeprint(dt) X long *dt; X{ X register struct tm *delta; X X delta = gmtime(dt); X if (delta->tm_yday == 0) X if (delta->tm_hour == 0) X if (delta->tm_min == 0) X printf(" "); X else X printf(" %2d", delta->tm_min); X else X if (delta->tm_hour >= 10) X printf("%3d:", delta->tm_hour); X else X printf("%1d:%02d", X delta->tm_hour, delta->tm_min); X else X printf("%3dd", delta->tm_yday); X} X X/* X * print idle time in long format with care being taken not to pluralize X * 1 minutes or 1 hours or 1 days. X * print "prefix" first. X */ Xltimeprint(before, dt, after) X long *dt; X char *before, *after; X{ X register struct tm *delta; X X delta = gmtime(dt); X if (delta->tm_yday == 0 && delta->tm_hour == 0 && delta->tm_min == 0 && X delta->tm_sec <= 10) X return (0); X printf("%s", before); X if (delta->tm_yday >= 10) X printf("%d days", delta->tm_yday); X else if (delta->tm_yday > 0) X printf("%d day%s %d hour%s", X delta->tm_yday, delta->tm_yday == 1 ? "" : "s", X delta->tm_hour, delta->tm_hour == 1 ? "" : "s"); X else X if (delta->tm_hour >= 10) X printf("%d hours", delta->tm_hour); X else if (delta->tm_hour > 0) X printf("%d hour%s %d minute%s", X delta->tm_hour, delta->tm_hour == 1 ? "" : "s", X delta->tm_min, delta->tm_min == 1 ? "" : "s"); X else X if (delta->tm_min >= 10) X printf("%2d minutes", delta->tm_min); X else if (delta->tm_min == 0) X printf("%2d seconds", delta->tm_sec); X else X printf("%d minute%s %d second%s", X delta->tm_min, X delta->tm_min == 1 ? "" : "s", X delta->tm_sec, X delta->tm_sec == 1 ? "" : "s"); X printf("%s", after); X} X Xmatchcmp(gname, login, given) X register char *gname; X char *login; X char *given; X{ X char buffer[100]; X register char *bp, *lp; X register c; X X if (*gname == ASTERISK) X gname++; X lp = 0; X bp = buffer; X for (;;) X switch (c = *gname++) { X case SAMENAME: X for (lp = login; bp < buffer + sizeof buffer X && (*bp++ = *lp++);) X ; X bp--; X break; X case ' ': X case COMMA: X case '\0': X *bp = 0; X if (namecmp(buffer, given)) X return (1); X if (c == COMMA || c == 0) X return (0); X bp = buffer; X break; X default: X if (bp < buffer + sizeof buffer) X *bp++ = c; X } X /*NOTREACHED*/ X} X Xnamecmp(name1, name2) X register char *name1, *name2; X{ X register c1, c2; X X for (;;) { X c1 = *name1++; X if (islower(c1)) X c1 = toupper(c1); X c2 = *name2++; X if (islower(c2)) X c2 = toupper(c2); X if (c1 != c2) X break; X if (c1 == 0) X return (1); X } X if (!c1) { X for (name2--; isdigit(*name2); name2++) X ; X if (*name2 == 0) X return (1); X } else if (!c2) { X for (name1--; isdigit(*name1); name1++) X ; X if (*name2 == 0) X return (1); X } X return (0); X} X Xnetfinger(name) X char *name; X{ X char *host; X char fname[100]; X struct hostent *hp; X struct servent *sp; X struct sockaddr_in sin; X int s; X char *rindex(); X register FILE *f; X register int c; X register int lastc; X X if (name == NULL) X return (0); X host = rindex(name, '@'); X if (host == NULL) X return (0); X *host++ = 0; X hp = gethostbyname(host); X if (hp == NULL) { X static struct hostent def; X static struct in_addr defaddr; X static char *alist[1]; X static char namebuf[128]; X int inet_addr(); X X defaddr.s_addr = inet_addr(host); X if (defaddr.s_addr == -1) { X printf("unknown host: %s\n", host); X return (1); X } X strcpy(namebuf, host); X def.h_name = namebuf; X def.h_addr_list = alist, def.h_addr = (char *)&defaddr; X def.h_length = sizeof (struct in_addr); X def.h_addrtype = AF_INET; X def.h_aliases = 0; X hp = &def; X } X sp = getservbyname("finger", "tcp"); X if (sp == 0) { X printf("tcp/finger: unknown service\n"); X return (1); X } X sin.sin_family = hp->h_addrtype; X bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length); X sin.sin_port = sp->s_port; X s = socket(hp->h_addrtype, SOCK_STREAM, 0); X if (s < 0) { X perror("socket"); X return (1); X } X printf("[%s]\n", hp->h_name); X fflush(stdout); X if (connect(s, (char *)&sin, sizeof (sin)) < 0) { X perror("connect"); X close(s); X return (1); X } X if (large) write(s, "/W ", 3); X write(s, name, strlen(name)); X write(s, "\r\n", 2); X f = fdopen(s, "r"); X while ((c = getc(f)) != EOF) { X switch(c) { X case 0210: X case 0211: X case 0212: X case 0214: X c -= 0200; X break; X case 0215: X c = '\n'; X break; X } X lastc = c; X if (isprint(c) || isspace(c)) X putchar(c); X else X putchar(c ^ 100); X } X if (lastc != '\n') X putchar('\n'); X (void)fclose(f); X return (1); X} END_OF_FILE if test 25816 -ne `wc -c <'finger.c'`; then echo shar: \"'finger.c'\" unpacked with wrong size! fi # end of 'finger.c' fi echo shar: End of shell archive. exit 0 -- "Do not meddle in the affairs of cats, for they are subtle and will piss on your computer." -- stolen from Brian Gollum