📄 finger.c
字号:
/* * 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 lintstatic 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 */};char LASTLOG[] = "/usr/adm/lastlog"; /* last login info */char USERLOG[] = "/etc/utmp"; /* who is logged in */char PLAN[] = "/.plan"; /* what plan file is */char PROJ[] = "/.project"; /* what project file */ int unbrief = 1; /* -b option default */int header = 1; /* -f option default */int hack = 1; /* -h option default */int idle = 0; /* -i option default */int large = 0; /* -l option default */int match = 1; /* -m option default */int plan = 1; /* -p option default */int unquick = 1; /* -q option default */int small = 0; /* -s option default */int wide = 1; /* -w option default */int unshort;int lf; /* LASTLOG file descriptor */struct person *person1; /* list of people */long tloc; /* current time */#if !_MINIXchar *strcpy();char *ctime();#endifchar *prog_name;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;{ FILE *fp; 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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -