BSD 4_3_Reno release
[unix-history] / usr / src / usr.bin / finger / finger.c
index 2e1c456..7c08c04 100644 (file)
 /*
 /*
- * Copyright (c) 1980 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Tony Nardo of the Johns Hopkins University/Applied Physics Lab.
+ *
+ * Redistribution and use in source and binary forms are permitted provided
+ * that: (1) source distributions retain this entire copyright notice and
+ * comment, and (2) distributions including binaries display the following
+ * acknowledgement:  ``This product includes software developed by the
+ * University of California, Berkeley and its contributors'' in the
+ * documentation or other materials provided with the distribution and in
+ * all advertising materials mentioning features or use of this software.
+ * Neither the name of the University nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  */
 
 #ifndef lint
 char copyright[] =
  */
 
 #ifndef lint
 char copyright[] =
-"@(#) Copyright (c) 1980 Regents of the University of California.\n\
+"@(#) Copyright (c) 1989 The Regents of the University of California.\n\
  All rights reserved.\n";
  All rights reserved.\n";
-#endif not lint
+#endif /* not lint */
 
 #ifndef lint
 
 #ifndef lint
-static char sccsid[] = "@(#)finger.c   5.6 (Berkeley) %G%";
-#endif not lint
+static char sccsid[] = "@(#)finger.c   5.21 (Berkeley) 6/24/90";
+#endif /* not lint */
 
 /*
 
 /*
- * This is a finger program.  It prints out useful information about users
- * by digging it up from various system files.  It is not very portable
- * because the most useful parts of the information (the full user name,
- * office, and phone numbers) are all stored in the VAX-unused gecos field
- * of /etc/passwd, which, unfortunately, other UNIXes use for other things.
- *
- * There are three output formats, all of which give login name, teletype
- * line number, and login time.  The short output format is reminiscent
- * of finger on ITS, and gives one line of information per user containing
- * in addition to the minimum basic requirements (MBR), the full name of
- * the user, his idle time and office location and phone number.  The
- * quick style output is UNIX who-like, giving only name, teletype and
- * login time.  Finally, the long style output give the same information
- * as the short (in more legible format), the home directory and shell
- * of the user, and, if it exits, a copy of the file .plan in the users
- * home directory.  Finger may be called with or without a list of people
- * to finger -- if no list is given, all the people currently logged in
- * are fingered.
+ * Finger prints out information about users.  It is not portable since
+ * certain fields (e.g. the full user name, office, and phone numbers) are
+ * extracted from the gecos field of the passwd file which other UNIXes
+ * may not have or may use for other things.
  *
  *
- * The program is validly called by one of the following:
- *
- *     finger                  {short form list of users}
- *     finger -l               {long form list of users}
- *     finger -b               {briefer long form list of users}
- *     finger -q               {quick list of users}
- *     finger -i               {quick list of users with idle times}
- *     finger namelist         {long format list of specified users}
- *     finger -s namelist      {short format list of specified users}
- *     finger -w namelist      {narrow short format list of specified users}
- *
- * where 'namelist' is a list of users login names.
- * The other options can all be given after one '-', or each can have its
- * own '-'.  The -f option disables the printing of headers for short and
- * quick outputs.  The -b option briefens long format outputs.  The -p
- * option turns off plans for long format outputs.
+ * There are currently two output formats; the short format is one line
+ * per user and displays login name, tty, login time, real name, idle time,
+ * and office location/phone number.  The long format gives the same
+ * information (in a more legible format) as well as home directory, shell,
+ * mail info, and .plan/.project files.
  */
 
  */
 
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <utmp.h>
-#include <sys/signal.h>
-#include <pwd.h>
+#include <sys/param.h>
+#include <sys/file.h>
 #include <stdio.h>
 #include <stdio.h>
-#include <lastlog.h>
-#include <ctype.h>
-#include <sys/time.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netdb.h>
-
-#define ASTERISK       '*'             /* ignore this in real name */
-#define COMMA          ','             /* separator in pw_gecos field */
-#define COMMAND                '-'             /* command line flag char */
-#define CORY           'C'             /* cory hall office */
-#define EVANS          'E'             /* evans hall office */
-#define SAMENAME       '&'             /* repeat login name in real name */
-#define TALKABLE       0222            /* tty is writable if 222 mode */
+#include "finger.h"
 
 
-struct utmp user;
-#define NMAX sizeof(user.ut_name)
-#define LMAX sizeof(user.ut_line)
-#define HMAX sizeof(user.ut_host)
-
-struct person {                        /* one for each person fingered */
-       char *name;                     /* name */
-       char tty[LMAX+1];               /* null terminated tty line */
-       char host[HMAX+1];              /* null terminated remote host name */
-       long loginat;                   /* time of (last) login */
-       long idletime;                  /* how long idle (if logged in) */
-       char *realname;                 /* pointer to full name */
-       char *office;                   /* pointer to office name */
-       char *officephone;              /* pointer to office phone no. */
-       char *homephone;                /* pointer to home phone no. */
-       char *random;                   /* for any random stuff in pw_gecos */
-       struct passwd *pwd;             /* structure of /etc/passwd stuff */
-       char loggedin;                  /* person is logged in */
-       char writable;                  /* tty is writable */
-       char original;                  /* this is not a duplicate entry */
-       struct person *link;            /* link to next person */
-};
-
-char LASTLOG[] = "/usr/adm/lastlog";   /* last login info */
-char USERLOG[] = "/etc/utmp";          /* who is logged in */
-char PLAN[] = "/.plan";                        /* what plan file is */
-char PROJ[] = "/.project";             /* what project file */
-       
-int unbrief = 1;                       /* -b option default */
-int header = 1;                                /* -f option default */
-int hack = 1;                          /* -h option default */
-int idle = 0;                          /* -i option default */
-int large = 0;                         /* -l option default */
-int match = 1;                         /* -m option default */
-int plan = 1;                          /* -p option default */
-int unquick = 1;                       /* -q option default */
-int small = 0;                         /* -s option default */
-int wide = 1;                          /* -w option default */
-
-int unshort;
-int lf;                                        /* LASTLOG file descriptor */
-struct person *person1;                        /* list of people */
-long tloc;                             /* current time */
-
-struct passwd *pwdcopy();
-char *strcpy();
-char *malloc();
-char *ctime();
+time_t now;
+int lflag, sflag, mflag, pplan;
+char tbuf[1024];
 
 main(argc, argv)
        int argc;
 
 main(argc, argv)
        int argc;
-       register char **argv;
+       char **argv;
 {
 {
-       FILE *fp;
-       register char *s;
+       extern int optind;
+       int ch;
+       time_t time();
 
 
-       /* parse command line for (optional) arguments */
-       while (*++argv && **argv == COMMAND)
-               for (s = *argv + 1; *s; s++)
-                       switch (*s) {
-                       case 'b':
-                               unbrief = 0;
-                               break;
-                       case 'f':
-                               header = 0;
-                               break;
-                       case 'h':
-                               hack = 0;
-                               break;
-                       case 'i':
-                               idle = 1;
-                               unquick = 0;
-                               break;
-                       case 'l':
-                               large = 1;
-                               break;
-                       case 'm':
-                               match = 0;
-                               break;
-                       case 'p':
-                               plan = 0;
-                               break;
-                       case 'q':
-                               unquick = 0;
-                               break;
-                       case 's':
-                               small = 1;
-                               break;
-                       case 'w':
-                               wide = 0;
-                               break;
-                       default:
-                               fprintf(stderr, "Usage: finger [-bfhilmpqsw] [login1 [login2 ...] ]\n");
-                               exit(1);
-                       }
-       if (unquick || idle)
-               time(&tloc);
-       /*
-        * *argv == 0 means no names given
-        */
-       if (*argv == 0)
-               doall();
-       else
-               donames(argv);
-       if (person1)
-               print();
+       while ((ch = getopt(argc, argv, "lmps")) != EOF)
+               switch(ch) {
+               case 'l':
+                       lflag = 1;              /* long format */
+                       break;
+               case 'm':
+                       mflag = 1;              /* force exact match of names */
+                       break;
+               case 'p':
+                       pplan = 1;              /* don't show .plan/.project */
+                       break;
+               case 's':
+                       sflag = 1;              /* short format */
+                       break;
+               case '?':
+               default:
+                       (void)fprintf(stderr,
+                           "usage: finger [-lmps] [login ...]\n");
+                       exit(1);
+               }
+       argc -= optind;
+       argv += optind;
+
+       (void)time(&now);
+       setpassent(1);
+       if (!*argv) {
+               /*
+                * Assign explicit "small" format if no names given and -l
+                * not selected.  Force the -s BEFORE we get names so proper
+                * screening will be done.
+                */
+               if (!lflag)
+                       sflag = 1;      /* if -l not explicit, force -s */
+               loginlist();
+               if (entries == 0)
+                       (void)printf("No one logged on.\n");
+       } else {
+               userlist(argc, argv);
+               /*
+                * Assign explicit "large" format if names given and -s not
+                * explicitly stated.  Force the -l AFTER we get names so any
+                * remote finger attempts specified won't be mishandled.
+                */
+               if (!sflag)
+                       lflag = 1;      /* if -s not explicit, force -l */
+       }
+       if (entries != 0) {
+               if (lflag)
+                       lflag_print();
+               else
+                       sflag_print();
+       }
        exit(0);
 }
 
        exit(0);
 }
 
-doall()
+loginlist()
 {
 {
-       register struct person *p;
-       register struct passwd *pw;
-       int uf;
-       char name[NMAX + 1];
+       register PERSON *pn;
+       struct passwd *pw;
+       struct utmp user;
+       char name[UT_NAMESIZE + 1];
 
 
-       unshort = large;
-       if ((uf = open(USERLOG, 0)) < 0) {
-               fprintf(stderr, "finger: error opening %s\n", USERLOG);
+       if (!freopen(_PATH_UTMP, "r", stdin)) {
+               (void)fprintf(stderr, "finger: can't read %s.\n", _PATH_UTMP);
                exit(2);
        }
                exit(2);
        }
-       if (unquick) {
-               extern _pw_stayopen;
-
-               setpwent();
-               _pw_stayopen = 1;
-               fwopen();
-       }
-       while (read(uf, (char *)&user, sizeof user) == sizeof user) {
-               if (user.ut_name[0] == 0)
+       name[UT_NAMESIZE] = NULL;
+       while (fread((char *)&user, sizeof(user), 1, stdin) == 1) {
+               if (!user.ut_name[0])
                        continue;
                        continue;
-               if (person1 == 0)
-                       p = person1 = (struct person *) malloc(sizeof *p);
-               else {
-                       p->link = (struct person *) malloc(sizeof *p);
-                       p = p->link;
+               if ((pn = find_person(user.ut_name)) == NULL) {
+                       bcopy(user.ut_name, name, UT_NAMESIZE);
+                       if ((pw = getpwnam(name)) == NULL)
+                               continue;
+                       pn = enter_person(pw);
                }
                }
-               bcopy(user.ut_name, name, NMAX);
-               name[NMAX] = 0;
-               bcopy(user.ut_line, p->tty, LMAX);
-               p->tty[LMAX] = 0;
-               bcopy(user.ut_host, p->host, HMAX);
-               p->host[HMAX] = 0;
-               p->loginat = user.ut_time;
-               p->pwd = 0;
-               p->loggedin = 1;
-               if (unquick && (pw = getpwnam(name))) {
-                       p->pwd = pwdcopy(pw);
-                       decode(p);
-                       p->name = p->pwd->pw_name;
-               } else
-                       p->name = strcpy(malloc(strlen(name) + 1), name);
-       }
-       if (unquick) {
-               fwclose();
-               endpwent();
-       }
-       close(uf);
-       if (person1 == 0) {
-               printf("No one logged on\n");
-               return;
+               enter_where(&user, pn);
        }
        }
-       p->link = 0;
+       for (pn = phead; lflag && pn != NULL; pn = pn->next)
+               enter_lastlog(pn);
 }
 
 }
 
-donames(argv)
-       char **argv;
+userlist(argc, argv)
+       register argc;
+       register char **argv;
 {
 {
-       register struct person *p;
-       register struct passwd *pw;
-       int uf;
-
-       /*
-        * get names from command line and check to see if they're
-        * logged in
-        */
-       unshort = !small;
-       for (; *argv != 0; argv++) {
-               if (netfinger(*argv))
-                       continue;
-               if (person1 == 0)
-                       p = person1 = (struct person *) malloc(sizeof *p);
-               else {
-                       p->link = (struct person *) malloc(sizeof *p);
-                       p = p->link;
-               }
-               p->name = *argv;
-               p->loggedin = 0;
-               p->original = 1;
-               p->pwd = 0;
-       }
-       if (person1 == 0)
-               return;
-       p->link = 0;
-       /*
-        * if we are doing it, read /etc/passwd for the useful info
-        */
-       if (unquick) {
-               setpwent();
-               if (!match) {
-                       extern _pw_stayopen;
-
-                       _pw_stayopen = 1;
-                       for (p = person1; p != 0; p = p->link)
-                               if (pw = getpwnam(p->name))
-                                       p->pwd = pwdcopy(pw);
-               } else while ((pw = getpwent()) != 0) {
-                       for (p = person1; p != 0; p = p->link) {
-                               if (!p->original)
-                                       continue;
-                               if (strcmp(p->name, pw->pw_name) != 0 &&
-                                   !matchcmp(pw->pw_gecos, pw->pw_name, p->name))
-                                       continue;
-                               if (p->pwd == 0)
-                                       p->pwd = pwdcopy(pw);
-                               else {
-                                       struct person *new;
-                                       /*
-                                        * handle multiple login names, insert
-                                        * new "duplicate" entry behind
-                                        */
-                                       new = (struct person *)
-                                               malloc(sizeof *new);
-                                       new->pwd = pwdcopy(pw);
-                                       new->name = p->name;
-                                       new->original = 1;
-                                       new->loggedin = 0;
-                                       new->link = p->link;
-                                       p->original = 0;
-                                       p->link = new;
-                                       p = new;
-                               }
-                       }
-               }
-               endpwent();
-       }
-       /* Now get login information */
-       if ((uf = open(USERLOG, 0)) < 0) {
-               fprintf(stderr, "finger: error opening %s\n", USERLOG);
-               exit(2);
-       }
-       while (read(uf, (char *)&user, sizeof user) == sizeof user) {
-               if (*user.ut_name == 0)
+       register i;
+       register PERSON *pn;
+       PERSON *nethead;
+       struct utmp user;
+       struct passwd *pw;
+       int dolocal, *used;
+       char *index();
+
+       if (!(used = (int *)calloc((u_int)argc, (u_int)sizeof(int)))) {
+               (void)fprintf(stderr, "finger: out of space.\n");
+               exit(1);
+       }
+
+       /* pull out all network requests */
+       for (i = 0, dolocal = 0, nethead = NULL; i < argc; i++) {
+               if (!index(argv[i], '@')) {
+                       dolocal = 1;
                        continue;
                        continue;
-               for (p = person1; p != 0; p = p->link) {
-                       if (p->loggedin == 2)
-                               continue;
-                       if (strncmp(p->pwd ? p->pwd->pw_name : p->name,
-                                   user.ut_name, NMAX) != 0)
-                               continue;
-                       if (p->loggedin == 0) {
-                               bcopy(user.ut_line, p->tty, LMAX);
-                               p->tty[LMAX] = 0;
-                               bcopy(user.ut_host, p->host, HMAX);
-                               p->host[HMAX] = 0;
-                               p->loginat = user.ut_time;
-                               p->loggedin = 1;
-                       } else {        /* p->loggedin == 1 */
-                               struct person *new;
-                               new = (struct person *) malloc(sizeof *new);
-                               new->name = p->name;
-                               bcopy(user.ut_line, new->tty, LMAX);
-                               new->tty[LMAX] = 0;
-                               bcopy(user.ut_host, new->host, HMAX);
-                               new->host[HMAX] = 0;
-                               new->loginat = user.ut_time;
-                               new->pwd = p->pwd;
-                               new->loggedin = 1;
-                               new->original = 0;
-                               new->link = p->link;
-                               p->loggedin = 2;
-                               p->link = new;
-                               p = new;
-                       }
                }
                }
+               pn = palloc();
+               pn->next = nethead;
+               nethead = pn;
+               pn->name = argv[i];
+               used[i] = -1;
        }
        }
-       close(uf);
-       if (unquick) {
-               fwopen();
-               for (p = person1; p != 0; p = p->link)
-                       decode(p);
-               fwclose();
-       }
-}
 
 
-print()
-{
-       register FILE *fp;
-       register struct person *p;
-       register char *s;
-       register c;
+       if (!dolocal)
+               goto net;
 
        /*
 
        /*
-        * print out what we got
+        * traverse the list of possible login names and check the login name
+        * and real name against the name specified by the user.
         */
         */
-       if (header) {
-               if (unquick) {
-                       if (!unshort)
-                               if (wide)
-                                       printf("Login       Name              TTY Idle    When            Office\n");
-                               else
-                                       printf("Login    TTY Idle    When            Office\n");
-               } else {
-                       printf("Login      TTY            When");
-                       if (idle)
-                               printf("             Idle");
-                       putchar('\n');
-               }
-       }
-       for (p = person1; p != 0; p = p->link) {
-               if (!unquick) {
-                       quickprint(p);
-                       continue;
-               }
-               if (!unshort) {
-                       shortprint(p);
-                       continue;
-               }
-               personprint(p);
-               if (p->pwd != 0) {
-                       if (hack) {
-                               s = malloc(strlen(p->pwd->pw_dir) +
-                                       sizeof PROJ);
-                               strcpy(s, p->pwd->pw_dir);
-                               strcat(s, PROJ);
-                               if ((fp = fopen(s, "r")) != 0) {
-                                       printf("Project: ");
-                                       while ((c = getc(fp)) != EOF) {
-                                               if (c == '\n')
-                                                       break;
-                                               putchar(c);
-                                       }
-                                       fclose(fp);
-                                       putchar('\n');
-                               }
-                               free(s);
+       if (mflag) {
+               for (i = 0; i < argc; i++)
+                       if (used[i] >= 0 && (pw = getpwnam(argv[i]))) {
+                               enter_person(pw);
+                               used[i] = 1;
                        }
                        }
-                       if (plan) {
-                               s = malloc(strlen(p->pwd->pw_dir) +
-                                       sizeof PLAN);
-                               strcpy(s, p->pwd->pw_dir);
-                               strcat(s, PLAN);
-                               if ((fp = fopen(s, "r")) == 0)
-                                       printf("No Plan.\n");
-                               else {
-                                       printf("Plan:\n");
-                                       while ((c = getc(fp)) != EOF)
-                                               putchar(c);
-                                       fclose(fp);
-                               }
-                               free(s);
+       } else while (pw = getpwent())
+               for (i = 0; i < argc; i++)
+                       if (used[i] >= 0 &&
+                           (!strcasecmp(pw->pw_name, argv[i]) ||
+                           match(pw, argv[i]))) {
+                               enter_person(pw);
+                               used[i] = 1;
                        }
                        }
-               }
-               if (p->link != 0)
-                       putchar('\n');
-       }
-}
-
-/*
- * Duplicate a pwd entry.
- * Note: Only the useful things (what the program currently uses) are copied.
- */
-struct passwd *
-pwdcopy(pfrom)
-       register struct passwd *pfrom;
-{
-       register struct passwd *pto;
-
-       pto = (struct passwd *) malloc(sizeof *pto);
-#define savestr(s) strcpy(malloc(strlen(s) + 1), s)
-       pto->pw_name = savestr(pfrom->pw_name);
-       pto->pw_uid = pfrom->pw_uid;
-       pto->pw_gecos = savestr(pfrom->pw_gecos);
-       pto->pw_dir = savestr(pfrom->pw_dir);
-       pto->pw_shell = savestr(pfrom->pw_shell);
-#undef savestr
-       return pto;
-}
-
-/*
- * print out information on quick format giving just name, tty, login time
- * and idle time if idle is set.
- */
-quickprint(pers)
-       register struct person *pers;
-{
-       printf("%-*.*s  ", NMAX, NMAX, pers->name);
-       if (pers->loggedin) {
-               if (idle) {
-                       findidle(pers);
-                       printf("%c%-*s %-16.16s", pers->writable ? ' ' : '*',
-                               LMAX, pers->tty, ctime(&pers->loginat));
-                       ltimeprint("   ", &pers->idletime, "");
-               } else
-                       printf(" %-*s %-16.16s", LMAX,
-                               pers->tty, ctime(&pers->loginat));
-               putchar('\n');
-       } else
-               printf("          Not Logged In\n");
-}
-
-/*
- * print out information in short format, giving login name, full name,
- * tty, idle time, login time, office location and phone.
- */
-shortprint(pers)
-       register struct person *pers;
-{
-       char *p;
-       char dialup;
-
-       if (pers->pwd == 0) {
-               printf("%-15s       ???\n", pers->name);
-               return;
-       }
-       printf("%-*s", NMAX, pers->pwd->pw_name);
-       dialup = 0;
-       if (wide) {
-               if (pers->realname)
-                       printf(" %-20.20s", pers->realname);
-               else
-                       printf("        ???          ");
-       }
-       putchar(' ');
-       if (pers->loggedin && !pers->writable)
-               putchar('*');
-       else
-               putchar(' ');
-       if (*pers->tty) {
-               if (pers->tty[0] == 't' && pers->tty[1] == 't' &&
-                   pers->tty[2] == 'y') {
-                       if (pers->tty[3] == 'd' && pers->loggedin)
-                               dialup = 1;
-                       printf("%-2.2s ", pers->tty + 3);
-               } else
-                       printf("%-2.2s ", pers->tty);
-       } else
-               printf("   ");
-       p = ctime(&pers->loginat);
-       if (pers->loggedin) {
-               stimeprint(&pers->idletime);
-               printf(" %3.3s %-5.5s ", p, p + 11);
-       } else if (pers->loginat == 0)
-               printf(" < .  .  .  . >");
-       else if (tloc - pers->loginat >= 180 * 24 * 60 * 60)
-               printf(" <%-6.6s, %-4.4s>", p + 4, p + 20);
-       else
-               printf(" <%-12.12s>", p + 4);
-       if (dialup && pers->homephone)
-               printf(" %20s", pers->homephone);
-       else {
-               if (pers->office)
-                       printf(" %-11.11s", pers->office);
-               else if (pers->officephone || pers->homephone)
-                       printf("            ");
-               if (pers->officephone)
-                       printf(" %s", pers->officephone);
-               else if (pers->homephone)
-                       printf(" %s", pers->homephone);
-       }
-       putchar('\n');
-}
-
-/*
- * print out a person in long format giving all possible information.
- * directory and shell are inhibited if unbrief is clear.
- */
-personprint(pers)
-       register struct person *pers;
-{
-       if (pers->pwd == 0) {
-               printf("Login name: %-10s\t\t\tIn real life: ???\n",
-                       pers->name);
-               return;
-       }
-       printf("Login name: %-10s", pers->pwd->pw_name);
-       if (pers->loggedin && !pers->writable)
-               printf("        (messages off)  ");
-       else
-               printf("                        ");
-       if (pers->realname)
-               printf("In real life: %s", pers->realname);
-       if (pers->office) {
-               printf("\nOffice: %-.11s", pers->office);
-               if (pers->officephone) {
-                       printf(", %s", pers->officephone);
-                       if (pers->homephone)
-                               printf("\t\tHome phone: %s", pers->homephone);
-                       else if (pers->random)
-                               printf("\t\t%s", pers->random);
-               } else
-                       if (pers->homephone)
-                               printf("\t\t\tHome phone: %s", pers->homephone);
-                       else if (pers->random)
-                               printf("\t\t\t%s", pers->random);
-       } else if (pers->officephone) {
-               printf("\nPhone: %s", pers->officephone);
-               if (pers->homephone)
-                       printf(", %s", pers->homephone);
-               if (pers->random)
-                       printf(", %s", pers->random);
-       } else if (pers->homephone) {
-               printf("\nPhone: %s", pers->homephone);
-               if (pers->random)
-                       printf(", %s", pers->random);
-       } else if (pers->random)
-               printf("\n%s", pers->random);
-       if (unbrief) {
-               printf("\nDirectory: %-25s", pers->pwd->pw_dir);
-               if (*pers->pwd->pw_shell)
-                       printf("\tShell: %-s", pers->pwd->pw_shell);
-       }
-       if (pers->loggedin) {
-               register char *ep = ctime(&pers->loginat);
-               if (*pers->host) {
-                       printf("\nOn since %15.15s on %s from %s",
-                               &ep[4], pers->tty, pers->host);
-                       ltimeprint("\n", &pers->idletime, " Idle Time");
-               } else {
-                       printf("\nOn since %15.15s on %-*s",
-                               &ep[4], LMAX, pers->tty);
-                       ltimeprint("\t", &pers->idletime, " Idle Time");
-               }
-       } else if (pers->loginat == 0)
-               printf("\nNever logged in.");
-       else if (tloc - pers->loginat > 180 * 24 * 60 * 60) {
-               register char *ep = ctime(&pers->loginat);
-               printf("\nLast login %10.10s, %4.4s on %s",
-                       ep, ep+20, pers->tty);
-               if (*pers->host)
-                       printf(" from %s", pers->host);
-       } else {
-               register char *ep = ctime(&pers->loginat);
-               printf("\nLast login %16.16s on %s", ep, pers->tty);
-               if (*pers->host)
-                       printf(" from %s", pers->host);
-       }
-       putchar('\n');
-}
 
 
-/*
- *  very hacky section of code to format phone numbers.  filled with
- *  magic constants like 4, 7 and 10.
- */
-char *
-phone(s, len, alldigits)
-       register char *s;
-       int len;
-       char alldigits;
-{
-       char fonebuf[15];
-       register char *p = fonebuf;
-       register i;
+       /* list errors */
+       for (i = 0; i < argc; i++)
+               if (!used[i])
+                       (void)fprintf(stderr,
+                           "finger: %s: no such user.\n", argv[i]);
 
 
-       if (!alldigits)
-               return (strcpy(malloc(len + 1), s));
-       switch (len) {
-       case 4:
-               *p++ = ' ';
-               *p++ = 'x';
-               *p++ = '2';
-               *p++ = '-';
-               for (i = 0; i < 4; i++)
-                       *p++ = *s++;
-               break;
-       case 5:
-               *p++ = ' ';
-               *p++ = 'x';
-               *p++ = *s++;
-               *p++ = '-';
-               for (i = 0; i < 4; i++)
-                       *p++ = *s++;
-               break;
-       case 7:
-               for (i = 0; i < 3; i++)
-                       *p++ = *s++;
-               *p++ = '-';
-               for (i = 0; i < 4; i++)
-                       *p++ = *s++;
-               break;
-       case 10:
-               for (i = 0; i < 3; i++)
-                       *p++ = *s++;
-               *p++ = '-';
-               for (i = 0; i < 3; i++)
-                       *p++ = *s++;
-               *p++ = '-';
-               for (i = 0; i < 4; i++)
-                       *p++ = *s++;
-               break;
-       case 0:
-               return 0;
-       default:
-               return (strcpy(malloc(len + 1), s));
+       /* handle network requests */
+net:   for (pn = nethead; pn; pn = pn->next) {
+               netfinger(pn->name);
+               if (pn->next || entries)
+                       putchar('\n');
        }
        }
-       *p++ = 0;
-       return (strcpy(malloc(p - fonebuf), fonebuf));
-}
-
-/*
- * decode the information in the gecos field of /etc/passwd
- */
-decode(pers)
-       register struct person *pers;
-{
-       char buffer[256];
-       register char *bp, *gp, *lp;
-       int alldigits;
-       int hasspace;
-       int len;
 
 
-       pers->realname = 0;
-       pers->office = 0;
-       pers->officephone = 0;
-       pers->homephone = 0;
-       pers->random = 0;
-       if (pers->pwd == 0)
+       if (entries == 0)
                return;
                return;
-       gp = pers->pwd->pw_gecos;
-       bp = buffer;
-       if (*gp == ASTERISK)
-               gp++;
-       while (*gp && *gp != COMMA)                     /* name */
-               if (*gp == SAMENAME) {
-                       lp = pers->pwd->pw_name;
-                       if (islower(*lp))
-                               *bp++ = toupper(*lp++);
-                       while (*bp++ = *lp++)
-                               ;
-                       bp--;
-                       gp++;
-               } else
-                       *bp++ = *gp++;
-       *bp++ = 0;
-       if ((len = bp - buffer) > 1)
-               pers->realname = strcpy(malloc(len), buffer);
-       if (*gp == COMMA) {                             /* office */
-               gp++;
-               hasspace = 0;
-               bp = buffer;
-               while (*gp && *gp != COMMA) {
-                       *bp = *gp++;
-                       if (*bp == ' ')
-                               hasspace = 1;
-                       /* leave 5 for Cory and Evans expansion */
-                       if (bp < buffer + sizeof buffer - 6)
-                               bp++;
-               }
-               *bp = 0;
-               len = bp - buffer;
-               bp--;                   /* point to last character */
-               if (hasspace || len == 0)
-                       len++;
-               else if (*bp == CORY) {
-                       strcpy(bp, " Cory");
-                       len += 5;
-               } else if (*bp == EVANS) {
-                       strcpy(bp, " Evans");
-                       len += 6;
-               } else
-                       len++;
-               if (len > 1)
-                       pers->office = strcpy(malloc(len), buffer);
-       }
-       if (*gp == COMMA) {                             /* office phone */
-               gp++;
-               bp = buffer;
-               alldigits = 1;
-               while (*gp && *gp != COMMA) {
-                       *bp = *gp++;
-                       if (!isdigit(*bp))
-                               alldigits = 0;
-                       if (bp < buffer + sizeof buffer - 1)
-                               bp++;
-               }
-               *bp = 0;
-               pers->officephone = phone(buffer, bp - buffer, alldigits);
-       }
-       if (*gp == COMMA) {                             /* home phone */
-               gp++;
-               bp = buffer;
-               alldigits = 1;
-               while (*gp && *gp != COMMA) {
-                       *bp = *gp++;
-                       if (!isdigit(*bp))
-                               alldigits = 0;
-                       if (bp < buffer + sizeof buffer - 1)
-                               bp++;
-               }
-               *bp = 0;
-               pers->homephone = phone(buffer, bp - buffer, alldigits);
-       }
-       if (pers->loggedin)
-               findidle(pers);
-       else
-               findwhen(pers);
-}
-
-/*
- * find the last log in of a user by checking the LASTLOG file.
- * the entry is indexed by the uid, so this can only be done if
- * the uid is known (which it isn't in quick mode)
- */
-
-fwopen()
-{
-       if ((lf = open(LASTLOG, 0)) < 0)
-               fprintf(stderr, "finger: %s open error\n", LASTLOG);
-}
-
-findwhen(pers)
-       register struct person *pers;
-{
-       struct lastlog ll;
-       int i;
-
-       if (lf >= 0) {
-               lseek(lf, (long)pers->pwd->pw_uid * sizeof ll, 0);
-               if ((i = read(lf, (char *)&ll, sizeof ll)) == sizeof ll) {
-                       bcopy(ll.ll_line, pers->tty, LMAX);
-                       pers->tty[LMAX] = 0;
-                       bcopy(ll.ll_host, pers->host, HMAX);
-                       pers->host[HMAX] = 0;
-                       pers->loginat = ll.ll_time;
-               } else {
-                       if (i != 0)
-                               fprintf(stderr, "finger: %s read error\n",
-                                       LASTLOG);
-                       pers->tty[0] = 0;
-                       pers->host[0] = 0;
-                       pers->loginat = 0L;
-               }
-       } else {
-               pers->tty[0] = 0;
-               pers->host[0] = 0;
-               pers->loginat = 0L;
-       }
-}
-
-fwclose()
-{
-       if (lf >= 0)
-               close(lf);
-}
-
-/*
- * find the idle time of a user by doing a stat on /dev/tty??,
- * where tty?? has been gotten from USERLOG, supposedly.
- */
-findidle(pers)
-       register struct person *pers;
-{
-       struct stat ttystatus;
-       static char buffer[20] = "/dev/";
-       long t;
-#define TTYLEN 5
-
-       strcpy(buffer + TTYLEN, pers->tty);
-       buffer[TTYLEN+LMAX] = 0;
-       if (stat(buffer, &ttystatus) < 0) {
-               fprintf(stderr, "finger: Can't stat %s\n", buffer);
-               exit(4);
-       }
-       time(&t);
-       if (t < ttystatus.st_atime)
-               pers->idletime = 0L;
-       else
-               pers->idletime = t - ttystatus.st_atime;
-       pers->writable = (ttystatus.st_mode & TALKABLE) == TALKABLE;
-}
-
-/*
- * print idle time in short format; this program always prints 4 characters;
- * if the idle time is zero, it prints 4 blanks.
- */
-stimeprint(dt)
-       long *dt;
-{
-       register struct tm *delta;
 
 
-       delta = gmtime(dt);
-       if (delta->tm_yday == 0)
-               if (delta->tm_hour == 0)
-                       if (delta->tm_min == 0)
-                               printf("    ");
-                       else
-                               printf("  %2d", delta->tm_min);
-               else
-                       if (delta->tm_hour >= 10)
-                               printf("%3d:", delta->tm_hour);
-                       else
-                               printf("%1d:%02d",
-                                       delta->tm_hour, delta->tm_min);
-       else
-               printf("%3dd", delta->tm_yday);
-}
-
-/*
- * print idle time in long format with care being taken not to pluralize
- * 1 minutes or 1 hours or 1 days.
- * print "prefix" first.
- */
-ltimeprint(before, dt, after)
-       long *dt;
-       char *before, *after;
-{
-       register struct tm *delta;
-
-       delta = gmtime(dt);
-       if (delta->tm_yday == 0 && delta->tm_hour == 0 && delta->tm_min == 0 &&
-           delta->tm_sec <= 10)
-               return (0);
-       printf("%s", before);
-       if (delta->tm_yday >= 10)
-               printf("%d days", delta->tm_yday);
-       else if (delta->tm_yday > 0)
-               printf("%d day%s %d hour%s",
-                       delta->tm_yday, delta->tm_yday == 1 ? "" : "s",
-                       delta->tm_hour, delta->tm_hour == 1 ? "" : "s");
-       else
-               if (delta->tm_hour >= 10)
-                       printf("%d hours", delta->tm_hour);
-               else if (delta->tm_hour > 0)
-                       printf("%d hour%s %d minute%s",
-                               delta->tm_hour, delta->tm_hour == 1 ? "" : "s",
-                               delta->tm_min, delta->tm_min == 1 ? "" : "s");
-               else
-                       if (delta->tm_min >= 10)
-                               printf("%2d minutes", delta->tm_min);
-                       else if (delta->tm_min == 0)
-                               printf("%2d seconds", delta->tm_sec);
-                       else
-                               printf("%d minute%s %d second%s",
-                                       delta->tm_min,
-                                       delta->tm_min == 1 ? "" : "s",
-                                       delta->tm_sec,
-                                       delta->tm_sec == 1 ? "" : "s");
-       printf("%s", after);
-}
-
-matchcmp(gname, login, given)
-       register char *gname;
-       char *login;
-       char *given;
-{
-       char buffer[100];
-       register char *bp, *lp;
-       register c;
-
-       if (*gname == ASTERISK)
-               gname++;
-       lp = 0;
-       bp = buffer;
-       for (;;)
-               switch (c = *gname++) {
-               case SAMENAME:
-                       for (lp = login; bp < buffer + sizeof buffer
-                                        && (*bp++ = *lp++);)
-                               ;
-                       bp--;
-                       break;
-               case ' ':
-               case COMMA:
-               case '\0':
-                       *bp = 0;
-                       if (namecmp(buffer, given))
-                               return (1);
-                       if (c == COMMA || c == 0)
-                               return (0);
-                       bp = buffer;
-                       break;
-               default:
-                       if (bp < buffer + sizeof buffer)
-                               *bp++ = c;
-               }
-       /*NOTREACHED*/
-}
-
-namecmp(name1, name2)
-       register char *name1, *name2;
-{
-       register c1, c2;
-
-       for (;;) {
-               c1 = *name1++;
-               if (islower(c1))
-                       c1 = toupper(c1);
-               c2 = *name2++;
-               if (islower(c2))
-                       c2 = toupper(c2);
-               if (c1 != c2)
-                       break;
-               if (c1 == 0)
-                       return (1);
-       }
-       if (!c1) {
-               for (name2--; isdigit(*name2); name2++)
-                       ;
-               if (*name2 == 0)
-                       return (1);
-       } else if (!c2) {
-               for (name1--; isdigit(*name1); name1++)
-                       ;
-               if (*name2 == 0)
-                       return (1);
-       }
-       return (0);
-}
-
-netfinger(name)
-       char *name;
-{
-       char *host;
-       char fname[100];
-       struct hostent *hp;
-       struct servent *sp;
-       struct sockaddr_in sin;
-       int s;
-       char *rindex();
-       register FILE *f;
-       register int c;
-       register int lastc;
-
-       if (name == NULL)
-               return (0);
-       host = rindex(name, '@');
-       if (host == NULL)
-               return (0);
-       *host++ = 0;
-       hp = gethostbyname(host);
-       if (hp == NULL) {
-               static struct hostent def;
-               static struct in_addr defaddr;
-               static char *alist[1];
-               static char namebuf[128];
-               int inet_addr();
-
-               defaddr.s_addr = inet_addr(host);
-               if (defaddr.s_addr == -1) {
-                       printf("unknown host: %s\n", host);
-                       return (1);
-               }
-               strcpy(namebuf, host);
-               def.h_name = namebuf;
-               def.h_addr_list = alist, def.h_addr = (char *)&defaddr;
-               def.h_length = sizeof (struct in_addr);
-               def.h_addrtype = AF_INET;
-               def.h_aliases = 0;
-               hp = &def;
-       }
-       printf("[%s]", hp->h_name);
-       sp = getservbyname("finger", "tcp");
-       if (sp == 0) {
-               printf("tcp/finger: unknown service\n");
-               return (1);
-       }
-       sin.sin_family = hp->h_addrtype;
-       bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length);
-       sin.sin_port = sp->s_port;
-       s = socket(hp->h_addrtype, SOCK_STREAM, 0);
-       if (s < 0) {
-               fflush(stdout);
-               perror("socket");
-               return (1);
-       }
-       if (connect(s, (char *)&sin, sizeof (sin)) < 0) {
-               fflush(stdout);
-               perror("connect");
-               close(s);
-               return (1);
+       /*
+        * Scan thru the list of users currently logged in, saving
+        * appropriate data whenever a match occurs.
+        */
+       if (!freopen(_PATH_UTMP, "r", stdin)) {
+               (void)fprintf( stderr, "finger: can't read %s.\n", _PATH_UTMP);
+               exit(1);
        }
        }
-       printf("\n");
-       if (large) write(s, "/W ", 3);
-       write(s, name, strlen(name));
-       write(s, "\r\n", 2);
-       f = fdopen(s, "r");
-       while ((c = getc(f)) != EOF) {
-               switch(c) {
-               case 0210:
-               case 0211:
-               case 0212:
-               case 0214:
-                       c -= 0200;
-                       break;
-               case 0215:
-                       c = '\n';
-                       break;
-               }
-               putchar(lastc = c);
+       while (fread((char *)&user, sizeof(user), 1, stdin) == 1) {
+               if (!user.ut_name[0])
+                       continue;
+               if ((pn = find_person(user.ut_name)) == NULL)
+                       continue;
+               enter_where(&user, pn);
        }
        }
-       if (lastc != '\n')
-               putchar('\n');
-       (void)fclose(f);
-       return (1);
+       for (pn = phead; pn != NULL; pn = pn->next)
+               enter_lastlog(pn);
 }
 }