]> Zhao Yanbai Git Server - minix.git/commitdiff
Importing usr.bin/finger
authorThomas Cort <tcort@minix3.org>
Sat, 1 Jun 2013 14:20:33 +0000 (14:20 +0000)
committerLionel Sambuc <lionel@minix3.org>
Sun, 2 Jun 2013 07:52:40 +0000 (09:52 +0200)
16 files changed:
commands/Makefile
commands/finger/Makefile [deleted file]
commands/finger/finger.c [deleted file]
man/man1/Makefile
man/man1/finger.1 [deleted file]
releasetools/nbsd_ports
usr.bin/Makefile
usr.bin/finger/Makefile [new file with mode: 0644]
usr.bin/finger/extern.h [new file with mode: 0644]
usr.bin/finger/finger.1 [new file with mode: 0644]
usr.bin/finger/finger.c [new file with mode: 0644]
usr.bin/finger/finger.h [new file with mode: 0644]
usr.bin/finger/lprint.c [new file with mode: 0644]
usr.bin/finger/net.c [new file with mode: 0644]
usr.bin/finger/sprint.c [new file with mode: 0644]
usr.bin/finger/util.c [new file with mode: 0644]

index ae8b4bcca9df882329a09891bfd54e747fe6b67b..f731122f18c7a3a5eb1bb8f0f79b8d9bee3e2764 100644 (file)
@@ -9,7 +9,7 @@ SUBDIR= add_route arp ash at backup basename btrace \
        dd decomp16 DESCRIBE devmand devsize df dhcpd \
        dhrystone diff dirname diskctl dumpcore \
        eject env expand factor fbdctl \
-       find finger fingerd fix fold format fortune fsck.mfs \
+       find fingerd fix fold format fortune fsck.mfs \
        gcore gcov-pull getty grep hexdump host \
        hostaddr id ifconfig ifdef \
        intr ipcrm ipcs irdpd isoread last \
diff --git a/commands/finger/Makefile b/commands/finger/Makefile
deleted file mode 100644 (file)
index 34e9f8c..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-PROG=  finger
-MAN=
-
-.include <bsd.prog.mk>
diff --git a/commands/finger/finger.c b/commands/finger/finger.c
deleted file mode 100644 (file)
index 0682ec3..0000000
+++ /dev/null
@@ -1,1092 +0,0 @@
-/*
- * Copyright (c) 1980 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)finger.c 1.1 87/12/21 SMI"; /* from 5.8 3/13/86 */
-#endif /* not lint */
-
-/*
- * This is a finger program.  It prints out useful information about users
- * by digging it up from various system files.
- *
- * 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 location.  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.
- *
- * 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.
- */
-
-#include <sys/types.h>
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <pwd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-#include <utmp.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <net/gen/in.h>
-#include <net/gen/inet.h>
-#include <net/gen/netdb.h>
-#include <net/gen/socket.h>
-#include <net/gen/tcp.h>
-#include <net/gen/tcp_hdr.h>
-#include <net/gen/tcp_io.h>
-#include <net/hton.h>
-#include <net/netlib.h>
-
-#define NONOTHING      1               /* don't say "No plan", or "No mail" */
-
-#define NONET  0
-
-#define ASTERISK       '*'             /* ignore this in real name */
-#define COMMA          ','             /* separator in pw_gecos field */
-#define COMMAND                '-'             /* command line flag char */
-#define SAMENAME       '&'             /* repeat login name in real name */
-#define TALKABLE       0220            /* tty is writable if this mode */
-
-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 */
-       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 *where;                    /* terminal location */
-       char hostt[HMAX+1];             /* login host */
-};
-
-#include <paths.h>
-
-char LASTLOG[] = _PATH_LASTLOG;        /* last login info */
-char USERLOG[] = _PATH_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 */
-
-#if !defined(__minix)
-char *strcpy();
-char *ctime();
-#endif
-
-char *prog_name;
-
-/* Already defined in stdio.h */
-#undef fwopen
-#define fwopen finger_fwopen
-
-int main (int argc, char *argv[]);
-static void doall(void);
-static void donames(char **args);
-static void print(void);
-static void fwopen(void);
-static void decode(struct person *pers);
-static void fwclose(void);
-static int netfinger (char *name);
-static int matchcmp (char *gname, char *login, char *given);
-static void quickprint (struct person *pers);
-static void shortprint (struct person *pers);
-static void personprint (struct person *pers);
-static int AlreadyPrinted(int uid);
-static int AnyMail (char *name);
-static struct passwd *pwdcopy(struct passwd *pfrom);
-static void findidle (struct person *pers);
-static int ltimeprint (char *dt, long *before, char *after);
-static void stimeprint (long *dt);
-static void findwhen (struct person *pers);
-static int namecmp (char *name1, char *name2);
-
-main(argc, argv)
-       int argc;
-       register char **argv;
-{
-       register char *s;
-
-       prog_name= argv[0];
-
-       /* 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();
-       exit(0);
-}
-
-static void doall()
-{
-       register struct person *p;
-       register struct passwd *pw;
-       int uf;
-       char name[NMAX + 1];
-
-       unshort = large;
-       if ((uf = open(USERLOG, 0)) < 0) {
-               fprintf(stderr, "finger: error opening %s\n", USERLOG);
-               exit(2);
-       }
-       if (unquick) {
-               setpwent();
-               fwopen();
-       }
-       while (read(uf, (char *)&user, sizeof user) == sizeof user) {
-               if (user.ut_name[0] == 0)
-                       continue;
-               if (person1 == 0)
-                       p = person1 = (struct person *) malloc(sizeof *p);
-               else {
-                       p->link = (struct person *) malloc(sizeof *p);
-                       p = p->link;
-               }
-               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;
-               p->where = NULL;
-               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;
-       }
-       p->link = 0;
-}
-
-static void donames(argv)
-       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) {
-                       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)
-                       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;
-                       }
-               }
-       }
-       close(uf);
-       if (unquick) {
-               fwopen();
-               for (p = person1; p != 0; p = p->link)
-                       decode(p);
-               fwclose();
-       }
-}
-
-static void print()
-{
-       register FILE *fp;
-       register struct person *p;
-       register char *s;
-       register c;
-
-       /*
-        * print out what we got
-        */
-       if (header) {
-               if (unquick) {
-                       if (!unshort)
-                               if (wide)
-                                       printf("Login       Name              TTY Idle    When            Where\n");
-                               else
-                                       printf("Login    TTY Idle    When            Where\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 && !AlreadyPrinted(p->pwd->pw_uid)) {
-                       AnyMail(p->pwd->pw_name);
-                       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;
-                                               if (isprint(c) || isspace(c))
-                                                       putchar(c);
-                                               else
-                                                       putchar(c ^ 100);
-                                       }
-                                       fclose(fp);
-                                       putchar('\n');
-                               }
-                               free(s);
-                       }
-                       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) {
-                                       if (!NONOTHING) printf("No Plan.\n");
-                               } else {
-                                       printf("Plan:\n");
-                                       while ((c = getc(fp)) != EOF)
-                                               if (isprint(c) || isspace(c))
-                                                       putchar(c);
-                                               else
-                                                       putchar(c ^ 100);
-                                       fclose(fp);
-                               }
-                               free(s);
-                       }
-               }
-               if (p->link != 0)
-                       putchar('\n');
-       }
-}
-
-/*
- * Duplicate a pwd entry.
- * Note: Only the useful things (what the program currently uses) are copied.
- */
-static 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.
- */
-static void 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, and host.
- */
-static void 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 >= 180L * 24 * 60 * 60)
-               printf(" <%-6.6s, %-4.4s>", p + 4, p + 20);
-       else
-               printf(" <%-12.12s>", p + 4);
-       if (pers->host[0])
-               printf(" %-20.20s", pers->host);
-       putchar('\n');
-}
-
-
-/*
- * print out a person in long format giving all possible information.
- * directory and shell are inhibited if unbrief is clear.
- */
-static void
-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 (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) {
-               if (lf >= 0) printf("\nNever logged in.");
-       } else if (tloc - pers->loginat > 180L * 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');
-}
-
-
-/*
- * decode the information in the gecos field of /etc/passwd
- */
-static void
-decode(pers)
-       register struct person *pers;
-{
-       char buffer[256];
-       register char *bp, *gp, *lp;
-       int len;
-
-       pers->realname = 0;
-       if (pers->pwd == 0)
-               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 (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)
- */
-
-static void
-fwopen()
-{
-       if ((lf = open(LASTLOG, 0)) < 0) {
-               if (errno == ENOENT) return;
-               fprintf(stderr, "finger: %s open error\n", LASTLOG);
-       }
-}
-
-static void
-findwhen(pers)
-       register struct person *pers;
-{
-       struct utmp ll;
-#define ll_line ut_line
-#define ll_host ut_host
-#define ll_time ut_time
-
-       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;
-       }
-}
-
-static void 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.
- */
-static void
-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.
- */
-static void
-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.
- */
-static int
-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);
-}
-
-static int
-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*/
-}
-
-static int
-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);
-}
-
-#if NONET
-static int
-netfinger(name)
-char *name;
-{
-       return 0;
-}
-#else
-static int
-netfinger(name)
-       char *name;
-{
-       char *host;
-       struct hostent *hp;
-       int s, result;
-#if !defined(__minix)
-       char *rindex();
-#endif
-       register FILE *f;
-       register int c;
-       register int lastc;
-       nwio_tcpconf_t tcpconf;
-       nwio_tcpcl_t tcpconnopt;
-       char *tcp_device;
-
-       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 ipaddr_t defaddr;
-               static char namebuf[128];
-
-               defaddr = inet_addr(host);
-               if (defaddr == -1) {
-                       printf("unknown host: %s\n", host);
-                       return (1);
-               }
-               strcpy(namebuf, host);
-               def.h_name = namebuf;
-               def.h_addr = (char *)&defaddr;
-               def.h_length = sizeof (ipaddr_t);
-               def.h_addrtype = AF_INET;
-               def.h_aliases = 0;
-               hp = &def;
-       }
-       printf("[%s] ", hp->h_name);
-       fflush(stdout);
-
-       tcp_device= getenv("TCP_DEVICE");
-       if (tcp_device == NULL)
-               tcp_device= TCP_DEVICE;
-       s= open (tcp_device, O_RDWR);
-       if (s == -1)
-       {
-               fprintf(stderr, "%s: unable to open %s (%s)\n",
-                       prog_name, tcp_device, strerror(errno));
-               exit(1);
-       }
-       tcpconf.nwtc_flags= NWTC_LP_SEL | NWTC_SET_RA | NWTC_SET_RP;
-       tcpconf.nwtc_remaddr= *(ipaddr_t *)hp->h_addr;
-       tcpconf.nwtc_remport= htons(TCPPORT_FINGER);
-
-       result= ioctl (s, NWIOSTCPCONF, &tcpconf);
-       if (result<0)
-       {
-               fprintf(stderr, "%s\n", strerror(errno));
-               exit(1);
-       }
-
-       tcpconnopt.nwtcl_flags= 0;
-
-       do
-       {
-               result= ioctl (s, NWIOTCPCONN, &tcpconnopt);
-               if (result<0 && errno== EAGAIN)
-               {
-                       fprintf(stderr, "got EAGAIN error, sleeping 2s\n");
-                       sleep(2);
-               }
-       } while (result<0 && errno == EAGAIN);
-       if (result<0)
-       {
-               fprintf(stderr, "%s\n", strerror(errno));
-               exit(1);
-       }
-       printf("\r\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;
-               }
-*/
-               c &= ~0200;
-               if (c == '\r')
-               {
-                       c= getc(f) & ~0200;
-                       if (c == '\012')
-                       {
-                               lastc= c;
-                               putchar('\n');
-                               continue;
-                       }
-                       else
-                               putchar('\r');
-               }
-               lastc = c;
-               if (isprint(c) || isspace(c))
-                       putchar(c);
-               else
-                       putchar(c ^ 100);
-       }
-       if (lastc != '\n')
-               putchar('\n');
-       (void)fclose(f);
-       return (1);
-}
-#endif
-
-/*
- *     AnyMail - takes a username (string pointer thereto), and
- *     prints on standard output whether there is any unread mail,
- *     and if so, how old it is.       (JCM@Shasta 15 March 80)
- */
-#define preamble "/usr/spool/mail/"    /* mailboxes are there */
-static int
-AnyMail(name)
-char *name;
-{
-       struct stat buf;                /* space for file status buffer */
-       char *mbxdir = preamble;        /* string with path preamble */
-       char *mbxpath;                  /* space for entire pathname */
-
-#if !defined(__minix)
-       char *ctime();                  /* convert longword time to ascii */
-#endif
-       char *timestr;
-
-       mbxpath = malloc(strlen(name) + strlen(preamble) + 1);
-
-       strcpy(mbxpath, mbxdir);        /* copy preamble into path name */
-       strcat(mbxpath, name);          /* concatenate user name to path */
-
-       if (stat(mbxpath, &buf) == -1 || buf.st_size == 0) {
-           /* Mailbox is empty or nonexistent */
-           if (!NONOTHING) printf("No unread mail\n");
-        } else {
-           if (buf.st_mtime == buf.st_atime) {
-               /* There is something in the mailbox, but we can't really
-                *   be sure whether it is mail held there by the user
-                *   or a (single) new message that was placed in a newly
-                *   recreated mailbox, so we punt and call it "unread mail."
-                */
-               printf("Unread mail since ");
-               printf(ctime(&buf.st_mtime));
-           } else {
-               /* New mail has definitely arrived since the last time
-                *   mail was read.  mtime is the time the most recent
-                *   message arrived; atime is either the time the oldest
-                *   unread message arrived, or the last time the mail
-                *   was read.
-                */
-               printf("New mail received ");
-               timestr = ctime(&buf.st_mtime); /* time last modified */
-               timestr[24] = '\0';             /* suppress newline (ugh) */
-               printf(timestr);
-               printf(";\n  unread since ");
-               printf(ctime(&buf.st_atime));   /* time last accessed */
-           }
-       }
-       
-       free(mbxpath);
-}
-
-/*
- * return true iff we've already printed project/plan for this uid;
- * if not, enter this uid into table (so this function has a side-effect.)
- */
-#define        PPMAX   200             /* assume no more than 200 logged-in users */
-int    PlanPrinted[PPMAX+1];
-int    PPIndex = 0;            /* index of next unused table entry */
-
-static int
-AlreadyPrinted(uid)
-int uid;
-{
-       int i = 0;
-       
-       while (i++ < PPIndex) {
-           if (PlanPrinted[i] == uid)
-               return(1);
-       }
-       if (i < PPMAX) {
-           PlanPrinted[i] = uid;
-           PPIndex++;
-       }
-       return(0);
-}
index 09021134267759fab4b7fb01e96afc10205dca18..d966dcc809dcf162239e0d73d49a4be41fb72f1f 100644 (file)
@@ -5,7 +5,7 @@ MAN=    ash.1 at.1 basename.1 \
        df.1 dhrystone.1 dosdir.1 dosread.1 doswrite.1 \
        dumpcore.1 eject.1 \
        env.1 expand.1 factor.1 \
-       finger.1 flexdoc.1 fold.1 format.1 fortune.1 \
+       flexdoc.1 fold.1 format.1 fortune.1 \
        fsck.mfs.1 host.1 hostaddr.1 ifdef.1 \
        isodir.1 isoinfo.1 isoread.1 \
        last.1 loadfont.1 loadkeys.1 logger.1 \
diff --git a/man/man1/finger.1 b/man/man1/finger.1
deleted file mode 100644 (file)
index fe64472..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-.\" Copyright (c) 1980 Regents of the University of California.
-.\" All rights reserved.  The Berkeley software License Agreement
-.\" specifies the terms and conditions for redistribution.
-.\"
-.\"    @(#)finger.1    6.4 (Berkeley) 5/10/86
-.\"
-.TH FINGER 1 "May 10, 1986"
-.UC 4
-.SH NAME
-finger \- user information lookup program
-.SH SYNOPSIS
-.B finger
-[
-options
-] name ...
-.SH DESCRIPTION
-By default
-.B finger
-lists the login name, full name, terminal name and write status
-(as a `*' before the terminal name if write permission is denied),
-idle time, login time, and office location and phone number
-(if they are known) for each current UNIX user.
-(Idle time is minutes if it is a single integer, hours and minutes if a ':'
-is present, or days and hours if a 'd' is present.)
-.PP
-A longer format also exists and is used by
-.B finger
-whenever a list of people's names is given.  (Account names as well as
-first and last names of users are accepted.)
-This format is multi-line, and includes all the information described above
-as well as the user's home
-directory and login shell, any plan which the person has placed in the file
-.B \&.plan
-in their home
-directory, and the project on which they are working from the file
-.B \&.project
-also in the home directory.
-.PP
-.B Finger
-may be used to lookup users on a remote machine.  The format is to specify
-the user as ``user@host.''  If the user name is left off, the
-standard format listing is provided on the remote machine.
-.PP
-.B Finger
-options include:
-.TP
-.B \-m
-Match arguments only on user name.
-.TP
-.B \-l
-Force long output format.
-.TP
-.B \-p
-Suppress printing of the
-.B \&.plan
-files
-.TP
-.B \-s
-Force short output format.
-.SH FILES
-.ta 2i
-/etc/utmp      who file
-.br
-/etc/passwd    for users names, offices, ...
-.br
-/usr/adm/lastlog       last login times
-.br
-~/.plan        plans
-.br
-~/.project     projects
-.SH "SEE ALSO"
-.BR chfn (1),
-.BR w (1),
-.BR who (1).
-.SH AUTHOR
-Earl T. Cohen
-.SH BUGS
-Only the first line of the
-.B .project
-file is printed.
-.PP
-There is no way to pass arguments to the remote machine as
-.B finger
-uses an internet standard port.
index 3f4b7378fe16a234b526e92722e523b12359eb8b..23300f91a776bfbb18fb2146019026b6ba53fa9f 100644 (file)
 2012/10/17 12:00:00,usr.bin/col
 2012/10/17 12:00:00,usr.bin/ctags
 2011/09/01 13:37:33,usr.bin/du
+2013/05/31 12:00:00,usr.bin/finger
 2013/03/22 12:00:00,usr.bin/from
 2013/04/05 12:00:00,usr.bin/ftp
 2013/03/18 12:00:00,usr.bin/head
index a719ec5fd2b0e02102e3b5d10d7fb1afa0d9c146..c8bf4dc81c17a1aef18a4e4ca0275d877ae335cb 100644 (file)
@@ -9,7 +9,7 @@ SUBDIR= \
        cal chpass cksum \
        col ctags \
        du \
-       \
+       finger \
        from ftp \
        genassym getopt head \
        indent infocmp join \
diff --git a/usr.bin/finger/Makefile b/usr.bin/finger/Makefile
new file mode 100644 (file)
index 0000000..d51dee1
--- /dev/null
@@ -0,0 +1,18 @@
+#      $NetBSD: Makefile,v 1.11 2007/05/28 12:06:26 tls Exp $
+#      from: @(#)Makefile      8.1 (Berkeley) 6/6/93
+
+.include <bsd.own.mk>
+
+USE_FORT?= yes # network client
+
+PROG=  finger
+SRCS=  finger.c lprint.c net.c sprint.c util.c utmpentry.c
+
+.PATH.c: ${NETBSDSRCDIR}/usr.bin/who
+CPPFLAGS+=-I${NETBSDSRCDIR}/usr.bin/who -DSUPPORT_UTMPX -DSUPPORT_UTMP
+
+.if (${USE_INET6} != "no")
+CPPFLAGS+=-DINET6
+.endif
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/finger/extern.h b/usr.bin/finger/extern.h
new file mode 100644 (file)
index 0000000..e55cd61
--- /dev/null
@@ -0,0 +1,57 @@
+/*     $NetBSD: extern.h,v 1.10 2006/01/04 01:17:54 perry Exp $        */
+
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)extern.h    8.2 (Berkeley) 4/28/95
+ */
+
+extern time_t now;                     /* Current time. */
+extern char tbuf[1024];                        /* Temp buffer for anybody. */
+extern int entries;                    /* Number of people. */
+extern DB *db;                         /* Database. */
+extern int lflag;
+extern int oflag;
+extern int gflag;
+extern int eightflag;
+extern int pplan;
+
+void    enter_lastlog(PERSON *);
+PERSON *enter_person(struct passwd *);
+void    enter_where(struct utmpentry *, PERSON *);
+void    expandusername(const char *, const char *, char *, int);
+PERSON *find_person(char *);
+int     hash(char *);
+void    lflag_print(void);
+int     match(struct passwd *, char *);
+void    netfinger(char *);
+PERSON *palloc(void);
+char   *prphone(char *);
+int     psort(const void *, const void *);
+void    sflag_print(void);
+PERSON **sort(void);
diff --git a/usr.bin/finger/finger.1 b/usr.bin/finger/finger.1
new file mode 100644 (file)
index 0000000..f241990
--- /dev/null
@@ -0,0 +1,213 @@
+.\"    $NetBSD: finger.1,v 1.16 2012/06/10 17:45:59 dholland Exp $
+.\"
+.\" Copyright (c) 1989, 1990, 1993, 1994
+.\"    The Regents of the University of California.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"    from: @(#)finger.1      8.3 (Berkeley) 5/5/94
+.\"
+.Dd June 10, 2012
+.Dt FINGER 1
+.Os
+.Sh NAME
+.Nm finger
+.Nd user information lookup program
+.Sh SYNOPSIS
+.Nm
+.Op Fl 8ghlmops
+.Op Ar user ...
+.Op Ar user@host ...
+.Sh DESCRIPTION
+The
+.Nm
+displays information about the system users.
+.Pp
+Options are:
+.Bl -tag -width flag
+.It Fl 8
+Pass through 8-bit data.
+This option is intended for enabling 8-bit
+data output in the
+.Xr fingerd 8
+service.
+Using this from the command line is
+.Em dangerous ,
+as the output data may include control characters for your terminal.
+.It Fl g
+This option restricts the gecos output to only the users' real names.
+.It Fl h
+When used in conjunction with the
+.Fl s
+option, the name of the remote host is displayed instead of the office
+location and office phone.
+.It Fl l
+Produces a multi-line format displaying all of the information
+described for the
+.Fl s
+option as well as the user's home directory, home phone number, login
+shell, mail status, and the contents of the files
+.Dq Pa .forward ,
+.Dq Pa .plan
+and
+.Dq Pa .project
+from the user's home directory.
+.Pp
+If idle time is at least a minute and less than a day, it is
+presented in the form
+.Dq hh:mm .
+Idle times greater than a day are presented as
+.Dq d day[s]hh:mm .
+.Pp
+Phone numbers specified as eleven digits are printed as
+.Dq +N-NNN-NNN-NNNN .
+Numbers specified as ten or seven digits are printed as the appropriate
+subset of that string.
+Numbers specified as five digits are printed as
+.Dq xN-NNNN .
+Numbers specified as four digits are printed as
+.Dq xNNNN .
+.Pp
+If write permission is denied to the device, the phrase
+.Dq (messages off)
+is appended to the line containing the device name.
+One entry per user is displayed with the
+.Fl l
+option; if a user is logged on multiple times, terminal information
+is repeated once per login.
+.Pp
+Mail status is shown as
+.Dq \&No Mail.
+if there is no mail at all, ``Mail last read DDD MMM ## HH:MM YYYY (TZ)''
+if the person has looked at their
+mailbox since new mail arriving, or
+.Dq New mail received ... ,
+.Dq Unread since \&...
+if they have new mail.
+.It Fl m
+Prevent matching of
+.Ar user
+names.
+.Ar User
+is usually a login name; however, matching will also be done on the
+users' real names, unless the
+.Fl m
+option is supplied.
+All name matching performed by
+.Nm
+is case insensitive.
+.It Fl o
+When used in conjunction with the
+.Fl s
+option, the office location and office phone information is displayed.
+This is the default.
+.It Fl p
+Prevents
+the
+.Fl l
+option of
+.Nm
+from displaying the contents of the
+.Dq Pa .forward ,
+.Dq Pa .plan
+and
+.Dq Pa .project
+files.
+.It Fl s
+.Nm
+displays the user's login name, real name, terminal name and write
+status (as a
+.Dq *
+after the terminal name if write permission is denied), idle time,
+login time, and either office location and office phone number,
+or the remote host.
+If
+.Fl h
+is given, the remote is printed.
+If
+.Fl o
+is given, the office location and phone number is printed instead
+(the default).
+.Pp
+Idle time is in minutes if it is a single integer, hours and minutes
+if a
+.Dq \&:
+is present, or days if a
+.Dq d
+is present.
+Login time is displayed as the dayname if less than six days,
+else month, day, hours and minutes, unless
+more than six months ago, in which case the year is displayed rather
+than the hours and minutes.
+.Pp
+Unknown devices as well as nonexistent idle and login times are
+displayed as single asterisks.
+.El
+.Pp
+If no options are specified,
+.Nm
+defaults to the
+.Fl l
+style output if operands are provided, otherwise to the
+.Fl s
+style.
+Note that some fields may be missing, in either format, if information
+is not available for them.
+.Pp
+If no arguments are specified,
+.Nm
+will print an entry for each user currently logged into the system.
+.Pp
+.Nm
+may be used to look up users on a remote machine.
+The format is to specify a
+.Ar user
+as
+.Dq Li user@host ,
+or
+.Dq Li @host ,
+where the default output
+format for the former is the
+.Fl l
+style, and the default output format for the latter is the
+.Fl s
+style.
+The
+.Fl l
+option is the only option that may be passed to a remote machine.
+.Sh FILES
+.Bl -tag -width /var/log/lastlog -compact
+.It Pa /var/log/lastlog
+last login data base
+.El
+.Sh SEE ALSO
+.Xr chpass 1 ,
+.Xr w 1 ,
+.Xr who 1
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 3.0 .
diff --git a/usr.bin/finger/finger.c b/usr.bin/finger/finger.c
new file mode 100644 (file)
index 0000000..e61f905
--- /dev/null
@@ -0,0 +1,301 @@
+/*     $NetBSD: finger.c,v 1.29 2009/04/12 06:18:54 lukem Exp $        */
+
+/*
+ * Copyright (c) 1989, 1993
+ *     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, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Luke Mewburn <lukem@NetBSD.org> added the following on 961121:
+ *    - mail status ("No Mail", "Mail read:...", or "New Mail ...,
+ *     Unread since ...".)
+ *    - 4 digit phone extensions (3210 is printed as x3210.)
+ *    - host/office toggling in short format with -h & -o.
+ *    - short day names (`Tue' printed instead of `Jun 21' if the
+ *     login time is < 6 days.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1989, 1993\
+ The Regents of the University of California.  All rights reserved.");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)finger.c   8.5 (Berkeley) 5/4/95";
+#else
+__RCSID("$NetBSD: finger.c,v 1.29 2009/04/12 06:18:54 lukem Exp $");
+#endif
+#endif /* not lint */
+
+/*
+ * 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.
+ *
+ * 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 either remote host information (default) or office location/phone
+ * number, depending on if -h or -o is used respectively.
+ * 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/param.h>
+
+#include <db.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <locale.h>
+#include <langinfo.h>
+
+#include "utmpentry.h"
+
+#include "finger.h"
+#include "extern.h"
+
+DB *db;
+time_t now;
+int entries, gflag, lflag, mflag, oflag, sflag, eightflag, pplan;
+char tbuf[1024];
+struct utmpentry *ehead;
+
+static void loginlist(void);
+static void userlist(int, char **);
+int main(int, char **);
+
+int
+main(int argc, char **argv)
+{
+       int ch;
+
+       /* Allow user's locale settings to affect character output. */
+       setlocale(LC_CTYPE, "");
+
+       /*
+        * Reset back to the C locale, unless we are using a known
+        * single-byte 8-bit locale.
+        */
+       if (strncmp(nl_langinfo(CODESET), "ISO8859-", 8))
+               setlocale(LC_CTYPE, "C");
+
+       oflag = 1;              /* default to old "office" behavior */
+
+       while ((ch = getopt(argc, argv, "lmpshog8")) != -1)
+               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 'h':
+                       oflag = 0;              /* remote host info */
+                       break;
+               case 'o':
+                       oflag = 1;              /* office info */
+                       break;
+               case 'g':
+                       gflag = 1;              /* no gecos info, besides name */
+                       break;
+               case '8':
+                       eightflag = 1;          /* 8-bit pass-through */
+                       break;
+               case '?':
+               default:
+                       (void)fprintf(stderr,
+                           "usage: finger [-lmpshog8] [login ...]\n");
+                       exit(1);
+               }
+       argc -= optind;
+       argv += optind;
+
+       (void)time(&now);
+       setpassent(1);
+       entries = getutentries(NULL, &ehead);
+       if (argc == 0) {
+               /*
+                * 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) {
+               if (lflag)
+                       lflag_print();
+               else
+                       sflag_print();
+       }
+       return (0);
+}
+
+static void
+loginlist(void)
+{
+       PERSON *pn;
+       DBT data, key;
+       struct passwd *pw;
+       int r, seqflag;
+       struct utmpentry *ep;
+
+       for (ep = ehead; ep; ep = ep->next) {
+               if ((pn = find_person(ep->name)) == NULL) {
+                       if ((pw = getpwnam(ep->name)) == NULL)
+                               continue;
+                       pn = enter_person(pw);
+               }
+               enter_where(ep, pn);
+       }
+       if (db && lflag)
+               for (seqflag = R_FIRST;; seqflag = R_NEXT) {
+                       PERSON *tmp;
+
+                       r = (*db->seq)(db, &key, &data, seqflag);
+                       if (r == -1)
+                               err(1, "db seq");
+                       if (r == 1)
+                               break;
+                       memmove(&tmp, data.data, sizeof tmp);
+                       enter_lastlog(tmp);
+               }
+}
+
+static void
+userlist(int argc, char **argv)
+{
+       PERSON *pn;
+       DBT data, key;
+       struct passwd *pw;
+       int r, seqflag, *used, *ip;
+       char **ap, **nargv, **np, **p;
+       struct utmpentry *ep;
+
+       if ((nargv = malloc((argc+1) * sizeof(char *))) == NULL ||
+           (used = calloc(argc, sizeof(int))) == NULL)
+               err(1, NULL);
+
+       /* Pull out all network requests. */
+       for (ap = p = argv, np = nargv; *p; ++p)
+               if (strchr(*p, '@'))
+                       *np++ = *p;
+               else
+                       *ap++ = *p;
+
+       *np++ = NULL;
+       *ap++ = NULL;
+
+       if (!*argv)
+               goto net;
+
+       /*
+        * Traverse the list of possible login names and check the login name
+        * and real name against the name specified by the user.
+        */
+       if (mflag) {
+               for (p = argv; *p; ++p)
+                       if ((pw = getpwnam(*p)) != NULL)
+                               enter_person(pw);
+                       else
+                               warnx("%s: no such user", *p);
+       } else {
+               while ((pw = getpwent()) != NULL)
+                       for (p = argv, ip = used; *p; ++p, ++ip)
+                               if (match(pw, *p)) {
+                                       enter_person(pw);
+                                       *ip = 1;
+                               }
+               for (p = argv, ip = used; *p; ++p, ++ip)
+                       if (!*ip)
+                               warnx("%s: no such user", *p);
+       }
+
+       /* Handle network requests. */
+net:
+       for (p = nargv; *p;)
+               netfinger(*p++);
+
+       if (entries == 0)
+               goto done;
+
+       /*
+        * Scan thru the list of users currently logged in, saving
+        * appropriate data whenever a match occurs.
+        */
+       for (ep = ehead; ep; ep = ep->next) {
+               if ((pn = find_person(ep->name)) == NULL)
+                       continue;
+               enter_where(ep, pn);
+       }
+       if (db != NULL)
+               for (seqflag = R_FIRST;; seqflag = R_NEXT) {
+                       PERSON *tmp;
+
+                       r = (*db->seq)(db, &key, &data, seqflag);
+                       if (r == -1)
+                               err(1, "db seq");
+                       if (r == 1)
+                               break;
+                       memmove(&tmp, data.data, sizeof tmp);
+                       enter_lastlog(tmp);
+               }
+done:
+       free(nargv);
+       free(used);
+}
diff --git a/usr.bin/finger/finger.h b/usr.bin/finger/finger.h
new file mode 100644 (file)
index 0000000..e310ff2
--- /dev/null
@@ -0,0 +1,67 @@
+/*     $NetBSD: finger.h,v 1.10 2007/05/05 16:55:17 christos Exp $     */
+
+/*
+ * Copyright (c) 1989, 1993
+ *     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, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     from: @(#)finger.h      8.1 (Berkeley) 6/6/93
+ */
+
+
+/*
+ * All unique persons are linked in a list headed by "head" and linkd
+ * by the "next" field, as well as kept in a hash table.
+ */
+
+typedef struct person {
+       uid_t uid;                      /* user id */
+       char *dir;                      /* user's home directory */
+       char *homephone;                /* pointer to home phone no. */
+       char *name;                     /* login name */
+       char *office;                   /* pointer to office name */
+       char *officephone;              /* pointer to office phone no. */
+       char *realname;                 /* pointer to full name */
+       char *shell;                    /* user's shell */
+       time_t mailread;                /* last time mail was read */
+       time_t mailrecv;                /* last time mail was read */
+       struct where *whead, *wtail;    /* list of where user is or has been */
+} PERSON;
+
+enum status { LASTLOG, LOGGEDIN };
+
+typedef struct where {
+       struct where *next;             /* next place user is or has been */
+       enum status info;               /* type/status of request */
+       short writable;                 /* tty is writable */
+       time_t loginat;                 /* time of (last) login */
+       time_t idletime;                /* how long idle (if logged in) */
+       char *tty;                      /* tty line */
+       char *host;                     /* remote host name */
+} WHERE;
diff --git a/usr.bin/finger/lprint.c b/usr.bin/finger/lprint.c
new file mode 100644 (file)
index 0000000..2495332
--- /dev/null
@@ -0,0 +1,389 @@
+/*     $NetBSD: lprint.c,v 1.23 2013/01/18 22:10:31 christos Exp $     */
+
+/*
+ * Copyright (c) 1989, 1993
+ *     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, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)lprint.c   8.3 (Berkeley) 4/28/95";
+#else
+__RCSID( "$NetBSD: lprint.c,v 1.23 2013/01/18 22:10:31 christos Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <tzfile.h>
+#include <db.h>
+#include <err.h>
+#include <pwd.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <ctype.h>
+#include <paths.h>
+#include <vis.h>
+
+#include "utmpentry.h"
+#include "finger.h"
+#include "extern.h"
+
+#define        LINE_LEN        80
+#define        TAB_LEN         8               /* 8 spaces between tabs */
+#define        _PATH_FORWARD   ".forward"
+#define        _PATH_PLAN      ".plan"
+#define        _PATH_PROJECT   ".project"
+
+static int     demi_print(const char *, int);
+static void    lprint(PERSON *);
+static int     show_text(const char *, const char *, const char *);
+static void    vputc(int);
+
+#ifdef __SVR4
+#define TIMEZONE(a)    tzname[0]
+#else
+#define TIMEZONE(a)    (a)->tm_zone
+#endif
+
+void
+lflag_print(void)
+{
+       PERSON *pn;
+       int sflag, r;
+       PERSON *tmp;
+       DBT data, key;
+
+       if (db == NULL)
+               return;
+
+       for (sflag = R_FIRST;; sflag = R_NEXT) {
+               r = (*db->seq)(db, &key, &data, sflag);
+               if (r == -1)
+                       err(1, "db seq");
+               if (r == 1)
+                       break;
+               memmove(&tmp, data.data, sizeof tmp);
+               pn = tmp;
+               if (sflag != R_FIRST)
+                       putchar('\n');
+               lprint(pn);
+               if (!pplan) {
+                       (void)show_text(pn->dir,
+                           _PATH_FORWARD, "Mail forwarded to");
+                       (void)show_text(pn->dir, _PATH_PROJECT, "Project");
+                       if (!show_text(pn->dir, _PATH_PLAN, "Plan"))
+                               (void)printf("No Plan.\n");
+               }
+       }
+}
+
+static size_t
+visify(char *buf, size_t blen, const char *str)
+{
+       int len = strnvisx(buf, blen, str, strlen(str), VIS_WHITE|VIS_CSTYLE);
+       if (len == -1) {
+               buf[0] = '\0';
+               return 0;
+       }
+       return len;
+}
+
+static void
+fmt_time(char *buf, size_t blen, time_t ti, time_t n)
+{
+       struct tm *tp = localtime(&ti);
+       if (tp != NULL) {
+               char *t = asctime(tp);
+               char *tzn = TIMEZONE(tp);
+               if (n == (time_t)-1 ||
+                   n - ti > SECSPERDAY * DAYSPERNYEAR / 2)
+                       snprintf(buf, blen, "%.16s %.4s (%s)", t, t + 20, tzn);
+               else
+                       snprintf(buf, blen, "%.16s (%s)", t, tzn);
+       } else
+               snprintf(buf, blen, "[*bad time 0x%llx*]", (long long)ti);
+}
+
+/*
+ * idle time is tough; if have one, print a comma,
+ * then spaces to pad out the device name, then the
+ * idle time.  Follow with a comma if a remote login.
+ */
+static int
+print_idle(time_t t, int maxlen, size_t hostlen, size_t ttylen) {
+
+       int cpr;
+       struct tm *delta = gmtime(&t);
+
+       if (delta == NULL)
+               return printf("Bad idle 0x%llx", (long long)t);
+
+       if (delta->tm_yday == 0 && delta->tm_hour == 0 && delta->tm_min == 0)
+               return 0;
+
+       cpr = printf("%-*s idle ", (int)(maxlen - ttylen + 1), ",");
+       if (delta->tm_yday > 0) {
+               cpr += printf("%d day%s ", delta->tm_yday,
+                  delta->tm_yday == 1 ? "" : "s");
+       }
+       cpr += printf("%d:%02d", delta->tm_hour, delta->tm_min);
+       if (hostlen) {
+               putchar(',');
+               ++cpr;
+       }
+       return cpr;
+}
+
+static void
+lprint(PERSON *pn)
+{
+       WHERE *w;
+       int cpr, len, maxlen;
+       int oddfield;
+       char timebuf[128], ttybuf[64], hostbuf[512];
+       size_t ttylen, hostlen;
+
+       cpr = 0;
+       /*
+        * long format --
+        *      login name
+        *      real name
+        *      home directory
+        *      shell
+        *      office, office phone, home phone if available
+        *      mail status
+        */
+       (void)printf("Login: %-15s\t\t\tName: %s\nDirectory: %-25s",
+           pn->name, pn->realname, pn->dir);
+       (void)printf("\tShell: %-s\n", *pn->shell ? pn->shell : _PATH_BSHELL);
+
+       if (gflag)
+               goto no_gecos;
+       /*
+        * try and print office, office phone, and home phone on one line;
+        * if that fails, do line filling so it looks nice.
+        */
+#define        OFFICE_TAG              "Office"
+#define        OFFICE_PHONE_TAG        "Office Phone"
+       oddfield = 0;
+       if (pn->office && pn->officephone &&
+           strlen(pn->office) + strlen(pn->officephone) +
+           sizeof(OFFICE_TAG) + 2 <= 5 * TAB_LEN) {
+               (void)snprintf(timebuf, sizeof(timebuf), "%s: %s, %s",
+                   OFFICE_TAG, pn->office, prphone(pn->officephone));
+               oddfield = demi_print(timebuf, oddfield);
+       } else {
+               if (pn->office) {
+                       (void)snprintf(timebuf, sizeof(timebuf), "%s: %s",
+                           OFFICE_TAG, pn->office);
+                       oddfield = demi_print(timebuf, oddfield);
+               }
+               if (pn->officephone) {
+                       (void)snprintf(timebuf, sizeof(timebuf), "%s: %s",
+                           OFFICE_PHONE_TAG, prphone(pn->officephone));
+                       oddfield = demi_print(timebuf, oddfield);
+               }
+       }
+       if (pn->homephone) {
+               (void)snprintf(timebuf, sizeof(timebuf), "%s: %s", "Home Phone",
+                   prphone(pn->homephone));
+               oddfield = demi_print(timebuf, oddfield);
+       }
+       if (oddfield)
+               putchar('\n');
+
+no_gecos:
+       /*
+        * long format con't:
+        * if logged in
+        *      terminal
+        *      idle time
+        *      if messages allowed
+        *      where logged in from
+        * if not logged in
+        *      when last logged in
+        */
+       /* find out longest device name for this user for formatting */
+       for (w = pn->whead, maxlen = -1; w != NULL; w = w->next) {
+               visify(ttybuf, sizeof(ttybuf), w->tty);
+               if ((len = strlen(ttybuf)) > maxlen)
+                       maxlen = len;
+       }
+       /* find rest of entries for user */
+       for (w = pn->whead; w != NULL; w = w->next) {
+               ttylen = visify(ttybuf, sizeof(ttybuf), w->tty);
+               hostlen = visify(hostbuf, sizeof(hostbuf), w->host);
+               switch (w->info) {
+               case LOGGEDIN:
+                       fmt_time(timebuf, sizeof(timebuf), w->loginat, -1);
+                       cpr = printf("On since %s on %s", timebuf, ttybuf);
+
+                       cpr += print_idle(w->idletime, maxlen, hostlen,
+                           ttylen);
+
+                       if (!w->writable)
+                               cpr += printf(" (messages off)");
+                       break;
+               case LASTLOG:
+                       if (w->loginat == 0) {
+                               (void)printf("Never logged in.");
+                               break;
+                       }
+                       fmt_time(timebuf, sizeof(timebuf), w->loginat, now);
+                       cpr = printf("Last login %s on %s", timebuf, ttybuf);
+                       break;
+               }
+               if (hostlen) {
+                       if (LINE_LEN < (cpr + 6 + hostlen))
+                               (void)printf("\n   ");
+                       (void)printf(" from %s", hostbuf);
+               }
+               putchar('\n');
+       }
+       if (pn->mailrecv == -1)
+               printf("No Mail.\n");
+       else if (pn->mailrecv > pn->mailread) {
+               fmt_time(timebuf, sizeof(timebuf), pn->mailrecv, -1);
+               printf("New mail received %s\n", timebuf);
+               fmt_time(timebuf, sizeof(timebuf), pn->mailread, -1);
+               printf("     Unread since %s\n", timebuf);
+       } else {
+               fmt_time(timebuf, sizeof(timebuf), pn->mailread, -1);
+               printf("Mail last read %s\n", timebuf);
+       }
+}
+
+static int
+demi_print(const char *str, int oddfield)
+{
+       static int lenlast;
+       int lenthis, maxlen;
+
+       lenthis = strlen(str);
+       if (oddfield) {
+               /*
+                * We left off on an odd number of fields.  If we haven't
+                * crossed the midpoint of the screen, and we have room for
+                * the next field, print it on the same line; otherwise,
+                * print it on a new line.
+                *
+                * Note: we insist on having the right hand fields start
+                * no less than 5 tabs out.
+                */
+               maxlen = 5 * TAB_LEN;
+               if (maxlen < lenlast)
+                       maxlen = lenlast;
+               if (((((maxlen / TAB_LEN) + 1) * TAB_LEN) +
+                   lenthis) <= LINE_LEN) {
+                       while(lenlast < (4 * TAB_LEN)) {
+                               putchar('\t');
+                               lenlast += TAB_LEN;
+                       }
+                       (void)printf("\t%s\n", str);    /* force one tab */
+               } else {
+                       (void)printf("\n%s", str);      /* go to next line */
+                       oddfield = !oddfield;   /* this'll be undone below */
+               }
+       } else
+               (void)printf("%s", str);
+       oddfield = !oddfield;                   /* toggle odd/even marker */
+       lenlast = lenthis;
+       return(oddfield);
+}
+
+static int
+show_text(const char *directory, const char *file_name, const char *header)    
+{
+       struct stat sb;
+       FILE *fp;
+       int ch, cnt, lastc;
+       char *p;
+       int fd, nr;
+
+       lastc = 0;
+       (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", directory, file_name);
+       if ((fd = open(tbuf, O_RDONLY)) < 0 || fstat(fd, &sb) ||
+           sb.st_size == 0)
+               return(0);
+
+       /* If short enough, and no newlines, show it on a single line.*/
+       if (sb.st_size <= (off_t)(LINE_LEN - strlen(header) - 5)) {
+               nr = read(fd, tbuf, sizeof(tbuf));
+               if (nr <= 0) {
+                       (void)close(fd);
+                       return(0);
+               }
+               for (p = tbuf, cnt = nr; cnt--; ++p)
+                       if (*p == '\n')
+                               break;
+               if (cnt <= 1) {
+                       (void)printf("%s: ", header);
+                       for (p = tbuf, cnt = nr; cnt--; ++p)
+                               vputc(lastc = (unsigned char)*p);
+                       if (lastc != '\n')
+                               (void)putchar('\n');
+                       (void)close(fd);
+                       return(1);
+               }
+               else
+                       (void)lseek(fd, 0L, SEEK_SET);
+       }
+       if ((fp = fdopen(fd, "r")) == NULL)
+               return(0);
+       (void)printf("%s:\n", header);
+       while ((ch = getc(fp)) != EOF)
+               vputc(lastc = ch);
+       if (lastc != '\n')
+               (void)putchar('\n');
+       (void)fclose(fp);
+       return(1);
+}
+
+static void
+vputc(int ch)
+{
+       char visout[5], *s2;
+
+       if (eightflag || isprint(ch) || isspace(ch)) {
+           (void)putchar(ch);
+           return;
+       }
+       ch = toascii(ch);
+       vis(visout, ch, VIS_SAFE|VIS_NOSLASH, 0);
+       for (s2 = visout; *s2; s2++)
+               (void)putchar(*s2);
+}
diff --git a/usr.bin/finger/net.c b/usr.bin/finger/net.c
new file mode 100644 (file)
index 0000000..d1db8c2
--- /dev/null
@@ -0,0 +1,159 @@
+/*     $NetBSD: net.c,v 1.23 2009/04/12 06:18:54 lukem Exp $   */
+
+/*
+ * Copyright (c) 1989, 1993
+ *     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, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)net.c      8.4 (Berkeley) 4/28/95";
+#else
+__RCSID("$NetBSD: net.c,v 1.23 2009/04/12 06:18:54 lukem Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+
+#include <arpa/inet.h>
+
+#include <netdb.h>
+#include <time.h>
+#include <db.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <err.h>
+
+#include "utmpentry.h"
+
+#include "finger.h"
+#include "extern.h"
+
+void
+netfinger(char *name)
+{
+       FILE *fp;
+       int c, lastc;
+       int s;
+       char *host;
+       struct addrinfo hints, *res, *res0;
+       int error;
+       const char *emsg = NULL;
+
+       lastc = 0;
+       if (!(host = strrchr(name, '@')))
+               return;
+       *host++ = '\0';
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_family = PF_UNSPEC;
+       hints.ai_socktype = SOCK_STREAM;
+       hints.ai_flags = AI_CANONNAME;
+       error = getaddrinfo(host, "finger", &hints, &res0);
+       if (error) {
+               warnx("%s: %s", gai_strerror(error), host);
+               return;
+       }
+
+       s = -1;
+       for (res = res0; res; res = res->ai_next) {
+               s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+               if (s < 0) {
+                       emsg = "socket";
+                       continue;
+               }
+
+               if (connect(s, res->ai_addr, res->ai_addrlen)) {
+                       close(s);
+                       s = -1;
+                       emsg = "connect";
+                       continue;
+               }
+
+               break;
+       }
+       if (s < 0) {
+               if (emsg != NULL)
+                       warn("%s", emsg);
+               return;
+       }
+
+       /* have network connection; identify the host connected with */
+       (void)printf("[%s]\n", res0->ai_canonname ? res0->ai_canonname : host);
+
+       /* -l flag for remote fingerd  */
+       if (lflag)
+               write(s, "/W ", 3);
+       /* send the name followed by <CR><LF> */
+       (void)write(s, name, strlen(name));
+       (void)write(s, "\r\n", 2);
+
+       /*
+        * Read from the remote system; once we're connected, we assume some
+        * data.  If none arrives, we hang until the user interrupts.
+        *
+        * If we see a <CR> followed by a newline character, only output
+        * one newline.
+        *
+        * If a character isn't printable and it isn't a space, we strip the
+        * 8th bit and set the 7th bit.  Every ASCII character with bit 7 set
+        * is printable.
+        */
+       if ((fp = fdopen(s, "r")) != NULL)
+               while ((c = getc(fp)) != EOF) {
+                       if (c == '\r') {
+                               if (lastc == '\r')      /* ^M^M - skip dupes */
+                                       continue;
+                               c = '\n';
+                               lastc = '\r';
+                       } else {
+                               if (!(eightflag || isprint(c) || isspace(c))) {
+                                       c &= 0x7f;
+                                       c |= 0x40;
+                               }
+                               if (lastc != '\r' || c != '\n')
+                                       lastc = c;
+                               else {
+                                       lastc = '\n';
+                                       continue;
+                               }
+                       }
+                       putchar(c);
+               }
+       if (lastc != '\n')
+               putchar('\n');
+       (void)fclose(fp);
+}
diff --git a/usr.bin/finger/sprint.c b/usr.bin/finger/sprint.c
new file mode 100644 (file)
index 0000000..84102f2
--- /dev/null
@@ -0,0 +1,173 @@
+/*     $NetBSD: sprint.c,v 1.17 2006/01/04 01:17:54 perry Exp $        */
+
+/*
+ * Copyright (c) 1989, 1993
+ *     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, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)sprint.c   8.3 (Berkeley) 4/28/95";
+#else
+__RCSID("$NetBSD: sprint.c,v 1.17 2006/01/04 01:17:54 perry Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+
+#include <time.h>
+#include <tzfile.h>
+#include <db.h>
+#include <err.h>
+#include <pwd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "utmpentry.h"
+
+#include "finger.h"
+#include "extern.h"
+
+static void      stimeprint(WHERE *);
+
+void
+sflag_print(void)
+{
+       PERSON *pn;
+       WHERE *w;
+       int sflag, r;
+       char *p;
+       PERSON *tmp;
+       DBT data, key;
+
+       if (db == NULL)
+               return;
+
+       /*
+        * short format --
+        *      login name
+        *      real name
+        *      terminal name
+        *      if terminal writable (add an '*' to the terminal name
+        *              if not)
+        *      if logged in show idle time and day logged in, else
+        *              show last login date and time.  If > 6 months,
+        *              show year instead of time.  If < 6 days,
+        *              show day name instead of month & day.
+        *      if -h given
+        *              remote host
+        *      else if -o given (overriding -h) (default)
+        *              office location
+        *              office phone
+        */
+#define        MAXREALNAME     18
+       (void)printf("%-*s %-*s %s %s\n", maxname, "Login", MAXREALNAME,
+           "Name", " Tty      Idle  Login Time  ", (gflag) ? "" :
+           (oflag) ? "Office     Office Phone" : "Where");
+
+       for (sflag = R_FIRST;; sflag = R_NEXT) {
+               r = (*db->seq)(db, &key, &data, sflag);
+               if (r == -1)
+                       err(1, "db seq");
+               if (r == 1)
+                       break;
+               memmove(&tmp, data.data, sizeof tmp);
+               pn = tmp;
+
+               for (w = pn->whead; w != NULL; w = w->next) {
+                       (void)printf("%-*.*s %-*.*s ", (int)maxname, 
+                           (int)maxname,
+                           pn->name, MAXREALNAME, MAXREALNAME,
+                           pn->realname ? pn->realname : "");
+                       if (!w->loginat) {
+                               (void)printf("  *     *  No logins   ");
+                               goto office;
+                       }
+                       (void)putchar(w->info == LOGGEDIN && !w->writable ?
+                           '*' : ' ');
+                       if (*w->tty)
+                               (void)printf("%-7.7s ", w->tty);
+                       else
+                               (void)printf("        ");
+                       if (w->info == LOGGEDIN) {
+                               stimeprint(w);
+                               (void)printf("  ");
+                       } else
+                               (void)printf("    *  ");
+                       p = ctime(&w->loginat);
+                       if (now - w->loginat < SECSPERDAY * (DAYSPERWEEK - 1))
+                               (void)printf("%.3s %-8.5s", p, p + 11);
+                       else if (now - w->loginat
+                             < SECSPERDAY * DAYSPERNYEAR / 2)
+                               (void)printf("%.6s %-5.5s", p + 4, p + 11);
+                       else
+                               (void)printf("%.6s %-5.4s", p + 4, p + 20);
+office:
+                       if (gflag)
+                               goto no_gecos;
+                       putchar(' ');
+                       if (oflag) {
+                               if (pn->office)
+                                       (void)printf("%-10.10s", pn->office);
+                               else if (pn->officephone)
+                                       (void)printf("%-10.10s", " ");
+                               if (pn->officephone)
+                                       (void)printf(" %-.15s",
+                                                   prphone(pn->officephone));
+                       } else
+                               (void)printf("%.*s", MAXHOSTNAMELEN, w->host);
+no_gecos:
+                       putchar('\n');
+               }
+       }
+}
+
+static void
+stimeprint(WHERE *w)
+{
+       struct tm *delta;
+
+       delta = gmtime(&w->idletime);
+       if (!delta->tm_yday) {
+               if (!delta->tm_hour) {
+                       if (!delta->tm_min)
+                               (void)printf("    -");
+                       else
+                               (void)printf("%5d", delta->tm_min);
+               } else
+                       (void)printf("%2d:%02d",
+                           delta->tm_hour, delta->tm_min);
+       } else
+               (void)printf("%4dd", delta->tm_yday);
+}
diff --git a/usr.bin/finger/util.c b/usr.bin/finger/util.c
new file mode 100644 (file)
index 0000000..03dd761
--- /dev/null
@@ -0,0 +1,409 @@
+/*     $NetBSD: util.c,v 1.28 2009/04/12 06:18:54 lukem Exp $  */
+
+/*
+ * Copyright (c) 1989, 1993
+ *     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, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Portions Copyright (c) 1983, 1995, 1996 Eric P. Allman
+ *
+ * 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, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)util.c     8.3 (Berkeley) 4/28/95";
+#else
+__RCSID("$NetBSD: util.c,v 1.28 2009/04/12 06:18:54 lukem Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <db.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <utmp.h>
+
+#include "utmpentry.h"
+
+#include "finger.h"
+#include "extern.h"
+
+static void     find_idle_and_ttywrite(WHERE *);
+static void     userinfo(PERSON *, struct passwd *);
+static WHERE   *walloc(PERSON *);
+
+int
+match(struct passwd *pw, char *user)
+{
+       char *p;
+       char *bp, name[1024];
+
+       if (!strcasecmp(pw->pw_name, user))
+               return(1);
+
+       (void)strlcpy(bp = tbuf, pw->pw_gecos, sizeof(tbuf));
+
+       /* Ampersands get replaced by the login name. */
+       if (!(p = strsep(&bp, ",")))
+               return(0);
+
+       expandusername(p, pw->pw_name, name, sizeof(name));
+       bp = name;
+       while ((p = strsep(&bp, "\t ")))
+               if (!strcasecmp(p, user))
+                       return(1);
+       return(0);
+}
+
+/* inspired by usr.sbin/sendmail/util.c::buildfname */
+void
+expandusername(const char *gecos, const char *login, char *buf, int buflen)
+{
+       const char *p;
+       char *bp;
+
+       /* why do we skip asterisks!?!? */
+       if (*gecos == '*')
+               gecos++;
+       bp = buf;
+
+       /* copy gecos, interpolating & to be full name */
+       for (p = gecos; *p != '\0'; p++) {
+               if (bp >= &buf[buflen - 1]) {
+                       /* buffer overflow - just use login name */
+                       snprintf(buf, buflen, "%s", login);
+                       buf[buflen - 1] = '\0';
+                       return;
+               }
+               if (*p == '&') {
+                       /* interpolate full name */
+                       snprintf(bp, buflen - (bp - buf), "%s", login);
+                       *bp = toupper((unsigned char)*bp);
+                       bp += strlen(bp);
+               }
+               else
+                       *bp++ = *p;
+       }
+       *bp = '\0';
+}
+
+void
+enter_lastlog(PERSON *pn)
+{
+       WHERE *w;
+       static int opened, fd;
+       struct lastlog ll;
+       char doit = 0;
+
+       /* some systems may not maintain lastlog, don't report errors. */
+       if (!opened) {
+               fd = open(_PATH_LASTLOG, O_RDONLY, 0);
+               opened = 1;
+       }
+       if (fd == -1 ||
+           lseek(fd, (off_t)pn->uid * sizeof(ll), SEEK_SET) !=
+           (off_t)pn->uid * (off_t)sizeof(ll) ||
+           read(fd, (char *)&ll, sizeof(ll)) != sizeof(ll)) {
+                       /* as if never logged in */
+                       ll.ll_line[0] = ll.ll_host[0] = '\0';
+                       ll.ll_time = 0;
+               }
+       if ((w = pn->whead) == NULL)
+               doit = 1;
+       else if (ll.ll_time != 0) {
+               /* if last login is earlier than some current login */
+               for (; !doit && w != NULL; w = w->next)
+                       if (w->info == LOGGEDIN && w->loginat < ll.ll_time)
+                               doit = 1;
+               /*
+                * and if it's not any of the current logins
+                * can't use time comparison because there may be a small
+                * discrepency since login calls time() twice
+                */
+               for (w = pn->whead; doit && w != NULL; w = w->next)
+                       if (w->info == LOGGEDIN &&
+                           strncmp(w->tty, ll.ll_line, UT_LINESIZE) == 0)
+                               doit = 0;
+       }
+       if (doit) {
+               w = walloc(pn);
+               w->info = LASTLOG;
+               if ((w->tty = malloc(UT_LINESIZE + 1)) == NULL)
+                       err(1, NULL);
+               memcpy(w->tty, ll.ll_line, UT_LINESIZE);
+               w->tty[UT_LINESIZE] = '\0';
+               if ((w->host = malloc(UT_HOSTSIZE + 1)) == NULL)
+                       err(1, NULL);
+               memcpy(w->host, ll.ll_host, UT_HOSTSIZE);
+               w->host[UT_HOSTSIZE] = '\0';
+               w->loginat = ll.ll_time;
+       }
+}
+
+void
+enter_where(struct utmpentry *ep, PERSON *pn)
+{
+       WHERE *w = walloc(pn);
+
+       w->info = LOGGEDIN;
+       w->tty = ep->line;
+       w->host = ep->host;
+       w->loginat = (time_t)ep->tv.tv_sec;
+       find_idle_and_ttywrite(w);
+}
+
+PERSON *
+enter_person(struct passwd *pw)
+{
+       DBT data, key;
+       PERSON *pn;
+
+       if (db == NULL &&
+           (db = dbopen(NULL, O_RDWR, 0, DB_BTREE, NULL)) == NULL)
+               err(1, NULL);
+
+       key.data = (char *)pw->pw_name;
+       key.size = strlen(pw->pw_name);
+
+       switch ((*db->get)(db, &key, &data, 0)) {
+       case 0:
+               memmove(&pn, data.data, sizeof pn);
+               return (pn);
+       default:
+       case -1:
+               err(1, "db get");
+               /* NOTREACHED */
+       case 1:
+               ++entries;
+               pn = palloc();
+               userinfo(pn, pw);
+               pn->whead = NULL;
+
+               data.size = sizeof(PERSON *);
+               data.data = &pn;
+               if ((*db->put)(db, &key, &data, 0))
+                       err(1, "db put");
+               return (pn);
+       }
+}
+
+PERSON *
+find_person(char *name)
+{
+       DBT data, key;
+       PERSON *p;
+
+       if (!db)
+               return(NULL);
+
+       key.data = name;
+       key.size = strlen(name);
+
+       if ((*db->get)(db, &key, &data, 0))
+               return (NULL);
+       memmove(&p, data.data, sizeof p);
+       return (p);
+}
+
+PERSON *
+palloc(void)
+{
+       PERSON *p;
+
+       if ((p = malloc((u_int) sizeof(PERSON))) == NULL)
+               err(1, NULL);
+       return(p);
+}
+
+static WHERE *
+walloc(PERSON *pn)
+{
+       WHERE *w;
+
+       if ((w = malloc((u_int) sizeof(WHERE))) == NULL)
+               err(1, NULL);
+       if (pn->whead == NULL)
+               pn->whead = pn->wtail = w;
+       else {
+               pn->wtail->next = w;
+               pn->wtail = w;
+       }
+       w->next = NULL;
+       return(w);
+}
+
+char *
+prphone(char *num)
+{
+       char *p;
+       int len;
+       static char pbuf[15];
+
+       /* don't touch anything if the user has their own formatting */
+       for (p = num; *p; ++p)
+               if (!isdigit((unsigned char)*p))
+                       return(num);
+       len = p - num;
+       p = pbuf;
+       switch(len) {
+       case 11:                        /* +0-123-456-7890 */
+               *p++ = '+';
+               *p++ = *num++;
+               *p++ = '-';
+               /* FALLTHROUGH */
+       case 10:                        /* 012-345-6789 */
+               *p++ = *num++;
+               *p++ = *num++;
+               *p++ = *num++;
+               *p++ = '-';
+               /* FALLTHROUGH */
+       case 7:                         /* 012-3456 */
+               *p++ = *num++;
+               *p++ = *num++;
+               *p++ = *num++;
+               break;
+       case 5:                         /* x0-1234 */
+       case 4:                         /* x1234 */
+               *p++ = 'x';
+               *p++ = *num++;
+               break;
+       default:
+               return(num);
+       }
+       if (len != 4) {
+               *p++ = '-';
+               *p++ = *num++;
+       }
+       *p++ = *num++;
+       *p++ = *num++;
+       *p++ = *num++;
+       *p = '\0';
+       return(pbuf);
+}
+
+static void
+find_idle_and_ttywrite(WHERE *w)
+{
+       struct stat sb;
+
+       (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_DEV, w->tty);
+       if (stat(tbuf, &sb) < 0) {
+               warn("%s", tbuf);
+               return;
+       }
+       w->idletime = now < sb.st_atime ? 0 : now - sb.st_atime;
+
+#define        TALKABLE        0220            /* tty is writable if 220 mode */
+       w->writable = ((sb.st_mode & TALKABLE) == TALKABLE);
+}
+
+static void
+userinfo(PERSON *pn, struct passwd *pw)
+{
+       char *p;
+       char *bp, name[1024];
+       struct stat sb;
+
+       pn->realname = pn->office = pn->officephone = pn->homephone = NULL;
+
+       pn->uid = pw->pw_uid;
+       pn->name = strdup(pw->pw_name);
+       pn->dir = strdup(pw->pw_dir);
+       pn->shell = strdup(pw->pw_shell);
+
+       (void)strlcpy(bp = tbuf, pw->pw_gecos, sizeof(tbuf));
+
+       /* ampersands get replaced by the login name */
+       if (!(p = strsep(&bp, ",")))
+               return;
+       expandusername(p, pw->pw_name, name, sizeof(name));
+       pn->realname = strdup(name);
+       pn->office = ((p = strsep(&bp, ",")) && *p) ?
+           strdup(p) : NULL;
+       pn->officephone = ((p = strsep(&bp, ",")) && *p) ?
+           strdup(p) : NULL;
+       pn->homephone = ((p = strsep(&bp, ",")) && *p) ?
+           strdup(p) : NULL;
+       (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_MAILDIR,
+           pw->pw_name);
+       pn->mailrecv = -1;              /* -1 == not_valid */
+       if (stat(tbuf, &sb) < 0) {
+               if (errno != ENOENT) {
+                       (void)fprintf(stderr,
+                           "finger: %s: %s\n", tbuf, strerror(errno));
+                       return;
+               }
+       } else if (sb.st_size != 0) {
+               pn->mailrecv = sb.st_mtime;
+               pn->mailread = sb.st_atime;
+       }
+}