4.3 finger diffs for A/UX (SystemV + BSD networking)
Paul Traina
pst at anise.acc.com
Thu Jul 6 10:37:14 AEST 1989
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 at 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 at 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 at 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
More information about the Alt.sources
mailing list