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 \
+++ /dev/null
-PROG= finger
-MAN=
-
-.include <bsd.prog.mk>
+++ /dev/null
-/*
- * 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);
-}
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 \
+++ /dev/null
-.\" 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.
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
cal chpass cksum \
col ctags \
du \
- \
+ finger \
from ftp \
genassym getopt head \
indent infocmp join \
--- /dev/null
+# $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>
--- /dev/null
+/* $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);
--- /dev/null
+.\" $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 .
--- /dev/null
+/* $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);
+}
--- /dev/null
+/* $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;
--- /dev/null
+/* $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);
+}
--- /dev/null
+/* $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);
+}
--- /dev/null
+/* $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);
+}
--- /dev/null
+/* $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;
+ }
+}