17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 506e1a714Sraf * Common Development and Distribution License (the "License"). 606e1a714Sraf * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 2106e1a714Sraf 227c478bd9Sstevel@tonic-gate /* 237a59e0bfSDavid Edmondson * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 287c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate /* 317c478bd9Sstevel@tonic-gate * Copyright (c) 1982, 1986, 1988 327c478bd9Sstevel@tonic-gate * The Regents of the University of California 337c478bd9Sstevel@tonic-gate * All Rights Reserved 347c478bd9Sstevel@tonic-gate * 357c478bd9Sstevel@tonic-gate * Portions of this document are derived from 367c478bd9Sstevel@tonic-gate * software developed by the University of California, Berkeley, and its 377c478bd9Sstevel@tonic-gate * contributors. 387c478bd9Sstevel@tonic-gate */ 397c478bd9Sstevel@tonic-gate 407c478bd9Sstevel@tonic-gate /* 417c478bd9Sstevel@tonic-gate * This is a finger program. It prints out useful information about users 427c478bd9Sstevel@tonic-gate * by digging it up from various system files. 437c478bd9Sstevel@tonic-gate * 447c478bd9Sstevel@tonic-gate * There are three output formats, all of which give login name, teletype 457c478bd9Sstevel@tonic-gate * line number, and login time. The short output format is reminiscent 467c478bd9Sstevel@tonic-gate * of finger on ITS, and gives one line of information per user containing 477c478bd9Sstevel@tonic-gate * in addition to the minimum basic requirements (MBR), the user's full name, 487c478bd9Sstevel@tonic-gate * idle time and location. 497c478bd9Sstevel@tonic-gate * The quick style output is UNIX who-like, giving only name, teletype and 507c478bd9Sstevel@tonic-gate * login time. Finally, the long style output give the same information 517c478bd9Sstevel@tonic-gate * as the short (in more legible format), the home directory and shell 527c478bd9Sstevel@tonic-gate * of the user, and, if it exits, a copy of the file .plan in the users 537c478bd9Sstevel@tonic-gate * home directory. Finger may be called with or without a list of people 547c478bd9Sstevel@tonic-gate * to finger -- if no list is given, all the people currently logged in 557c478bd9Sstevel@tonic-gate * are fingered. 567c478bd9Sstevel@tonic-gate * 577c478bd9Sstevel@tonic-gate * The program is validly called by one of the following: 587c478bd9Sstevel@tonic-gate * 597c478bd9Sstevel@tonic-gate * finger {short form list of users} 607c478bd9Sstevel@tonic-gate * finger -l {long form list of users} 617c478bd9Sstevel@tonic-gate * finger -b {briefer long form list of users} 627c478bd9Sstevel@tonic-gate * finger -q {quick list of users} 637c478bd9Sstevel@tonic-gate * finger -i {quick list of users with idle times} 647c478bd9Sstevel@tonic-gate * finger -m {matches arguments against only username} 657c478bd9Sstevel@tonic-gate * finger -f {suppress header in non-long form} 667c478bd9Sstevel@tonic-gate * finger -p {suppress printing of .plan file} 677c478bd9Sstevel@tonic-gate * finger -h {suppress printing of .project file} 687c478bd9Sstevel@tonic-gate * finger -i {forces "idle" output format} 697c478bd9Sstevel@tonic-gate * finger namelist {long format list of specified users} 707c478bd9Sstevel@tonic-gate * finger -s namelist {short format list of specified users} 717c478bd9Sstevel@tonic-gate * finger -w namelist {narrow short format list of specified users} 727c478bd9Sstevel@tonic-gate * 737c478bd9Sstevel@tonic-gate * where 'namelist' is a list of users login names. 747c478bd9Sstevel@tonic-gate * The other options can all be given after one '-', or each can have its 757c478bd9Sstevel@tonic-gate * own '-'. The -f option disables the printing of headers for short and 767c478bd9Sstevel@tonic-gate * quick outputs. The -b option briefens long format outputs. The -p 777c478bd9Sstevel@tonic-gate * option turns off plans for long format outputs. 787c478bd9Sstevel@tonic-gate */ 797c478bd9Sstevel@tonic-gate 807c478bd9Sstevel@tonic-gate #include <sys/types.h> 817c478bd9Sstevel@tonic-gate #include <sys/stat.h> 827c478bd9Sstevel@tonic-gate #include <utmpx.h> 837c478bd9Sstevel@tonic-gate #include <sys/signal.h> 847c478bd9Sstevel@tonic-gate #include <pwd.h> 857c478bd9Sstevel@tonic-gate #include <stdio.h> 867c478bd9Sstevel@tonic-gate #include <lastlog.h> 877c478bd9Sstevel@tonic-gate #include <ctype.h> 887c478bd9Sstevel@tonic-gate #include <sys/time.h> 897c478bd9Sstevel@tonic-gate #include <time.h> 907c478bd9Sstevel@tonic-gate #include <sys/socket.h> 917c478bd9Sstevel@tonic-gate #include <netinet/in.h> 927c478bd9Sstevel@tonic-gate #include <netdb.h> 937c478bd9Sstevel@tonic-gate #include <locale.h> 947c478bd9Sstevel@tonic-gate #include <sys/select.h> 957c478bd9Sstevel@tonic-gate #include <stdlib.h> 967c478bd9Sstevel@tonic-gate #include <strings.h> 977c478bd9Sstevel@tonic-gate #include <fcntl.h> 987c478bd9Sstevel@tonic-gate #include <curses.h> 997c478bd9Sstevel@tonic-gate #include <unctrl.h> 1007c478bd9Sstevel@tonic-gate #include <maillock.h> 1017c478bd9Sstevel@tonic-gate #include <deflt.h> 1027c478bd9Sstevel@tonic-gate #include <unistd.h> 1037c478bd9Sstevel@tonic-gate #include <arpa/inet.h> 1047c478bd9Sstevel@tonic-gate #include <macros.h> 1057c478bd9Sstevel@tonic-gate 1067c478bd9Sstevel@tonic-gate static char gecos_ignore_c = '*'; /* ignore this in real name */ 1077c478bd9Sstevel@tonic-gate static char gecos_sep_c = ','; /* separator in pw_gecos field */ 1087c478bd9Sstevel@tonic-gate static char gecos_samename = '&'; /* repeat login name in real name */ 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate #define TALKABLE 0220 /* tty is writable if this mode */ 1117c478bd9Sstevel@tonic-gate 1127c478bd9Sstevel@tonic-gate #define NMAX sizeof (((struct utmpx *)0)->ut_name) 1137c478bd9Sstevel@tonic-gate #define LMAX sizeof (((struct utmpx *)0)->ut_line) 1147c478bd9Sstevel@tonic-gate #define HMAX sizeof (((struct utmpx *)0)->ut_host) 1157c478bd9Sstevel@tonic-gate 1167c478bd9Sstevel@tonic-gate struct person { /* one for each person fingered */ 1177c478bd9Sstevel@tonic-gate char *name; /* name */ 1187c478bd9Sstevel@tonic-gate char tty[LMAX+1]; /* null terminated tty line */ 1197c478bd9Sstevel@tonic-gate char host[HMAX+1]; /* null terminated remote host name */ 1207c478bd9Sstevel@tonic-gate char *ttyloc; /* location of tty line, if any */ 1217c478bd9Sstevel@tonic-gate time_t loginat; /* time of (last) login */ 1227c478bd9Sstevel@tonic-gate time_t idletime; /* how long idle (if logged in) */ 1237c478bd9Sstevel@tonic-gate char *realname; /* pointer to full name */ 1247c478bd9Sstevel@tonic-gate struct passwd *pwd; /* structure of /etc/passwd stuff */ 1257c478bd9Sstevel@tonic-gate char loggedin; /* person is logged in */ 1267c478bd9Sstevel@tonic-gate char writable; /* tty is writable */ 1277c478bd9Sstevel@tonic-gate char original; /* this is not a duplicate entry */ 1287c478bd9Sstevel@tonic-gate struct person *link; /* link to next person */ 1297c478bd9Sstevel@tonic-gate }; 1307c478bd9Sstevel@tonic-gate 131*2de0a7d6SDan McDonald char LASTLOG[] = "/var/adm/lastlog"; /* last login info */ 1327c478bd9Sstevel@tonic-gate char PLAN[] = "/.plan"; /* what plan file is */ 1337c478bd9Sstevel@tonic-gate char PROJ[] = "/.project"; /* what project file */ 1347c478bd9Sstevel@tonic-gate 1357c478bd9Sstevel@tonic-gate int unbrief = 1; /* -b option default */ 1367c478bd9Sstevel@tonic-gate int header = 1; /* -f option default */ 1377c478bd9Sstevel@tonic-gate int hack = 1; /* -h option default */ 1387c478bd9Sstevel@tonic-gate int idle = 0; /* -i option default */ 1397c478bd9Sstevel@tonic-gate int large = 0; /* -l option default */ 1407c478bd9Sstevel@tonic-gate int match = 1; /* -m option default */ 1417c478bd9Sstevel@tonic-gate int plan = 1; /* -p option default */ 1427c478bd9Sstevel@tonic-gate int unquick = 1; /* -q option default */ 1437c478bd9Sstevel@tonic-gate int small = 0; /* -s option default */ 1447c478bd9Sstevel@tonic-gate int wide = 1; /* -w option default */ 1457c478bd9Sstevel@tonic-gate 1467c478bd9Sstevel@tonic-gate /* 1477c478bd9Sstevel@tonic-gate * RFC 1288 says that system administrators should have the option of 1487c478bd9Sstevel@tonic-gate * separately allowing ASCII characters less than 32 or greater than 1497c478bd9Sstevel@tonic-gate * 126. The termpass variable keeps track of this. 1507c478bd9Sstevel@tonic-gate */ 1517c478bd9Sstevel@tonic-gate char defaultfile[] = "/etc/default/finger"; 1527c478bd9Sstevel@tonic-gate char passvar[] = "PASS="; 1537c478bd9Sstevel@tonic-gate int termpass = 0; /* default is ASCII only */ 1547c478bd9Sstevel@tonic-gate char *termopts[] = { 1557c478bd9Sstevel@tonic-gate #define TERM_LOW 0 1567c478bd9Sstevel@tonic-gate "low", 1577c478bd9Sstevel@tonic-gate #define TERM_HIGH 1 1587c478bd9Sstevel@tonic-gate "high", 1597c478bd9Sstevel@tonic-gate (char *)NULL 1607c478bd9Sstevel@tonic-gate }; 1617c478bd9Sstevel@tonic-gate #define TS_LOW (1 << TERM_LOW) /* print characters less than 32 */ 1627c478bd9Sstevel@tonic-gate #define TS_HIGH (1 << TERM_HIGH) /* print characters greater than 126 */ 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate int unshort; 1667c478bd9Sstevel@tonic-gate FILE *lf; /* LASTLOG file pointer */ 1677c478bd9Sstevel@tonic-gate struct person *person1; /* list of people */ 1687a59e0bfSDavid Edmondson size_t nperson; /* number of people */ 1697c478bd9Sstevel@tonic-gate time_t tloc; /* current time */ 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate char usagestr[] = "Usage: " 1727c478bd9Sstevel@tonic-gate "finger [-bfhilmpqsw] [name1 [name2 ...] ]\n"; 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate int AlreadyPrinted(uid_t uid); 1757c478bd9Sstevel@tonic-gate void AnyMail(char *name); 1767c478bd9Sstevel@tonic-gate void catfile(char *s, mode_t mode, int trunc_at_nl); 1777c478bd9Sstevel@tonic-gate void decode(struct person *pers); 1787c478bd9Sstevel@tonic-gate void doall(void); 1797c478bd9Sstevel@tonic-gate void donames(char **argv); 1807c478bd9Sstevel@tonic-gate void findidle(struct person *pers); 1817c478bd9Sstevel@tonic-gate void findwhen(struct person *pers); 1827c478bd9Sstevel@tonic-gate void fwclose(void); 1837c478bd9Sstevel@tonic-gate void fwopen(void); 1847c478bd9Sstevel@tonic-gate void initscreening(void); 1857c478bd9Sstevel@tonic-gate void ltimeprint(char *before, time_t *dt, char *after); 1867c478bd9Sstevel@tonic-gate int matchcmp(char *gname, char *login, char *given); 1877c478bd9Sstevel@tonic-gate int namecmp(char *name1, char *name2); 1887c478bd9Sstevel@tonic-gate int netfinger(char *name); 1897c478bd9Sstevel@tonic-gate void personprint(struct person *pers); 1907c478bd9Sstevel@tonic-gate void print(void); 1917c478bd9Sstevel@tonic-gate struct passwd *pwdcopy(const struct passwd *pfrom); 1927c478bd9Sstevel@tonic-gate void quickprint(struct person *pers); 1937c478bd9Sstevel@tonic-gate void shortprint(struct person *pers); 1947c478bd9Sstevel@tonic-gate void stimeprint(time_t *dt); 1957a59e0bfSDavid Edmondson void sort_by_username(void); 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate int 1997c478bd9Sstevel@tonic-gate main(int argc, char **argv) 2007c478bd9Sstevel@tonic-gate { 2017c478bd9Sstevel@tonic-gate int c; 2027c478bd9Sstevel@tonic-gate 2037c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 2047c478bd9Sstevel@tonic-gate /* parse command line for (optional) arguments */ 2057c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, "bfhilmpqsw")) != EOF) 2067c478bd9Sstevel@tonic-gate switch (c) { 2077c478bd9Sstevel@tonic-gate case 'b': 2087c478bd9Sstevel@tonic-gate unbrief = 0; 2097c478bd9Sstevel@tonic-gate break; 2107c478bd9Sstevel@tonic-gate case 'f': 2117c478bd9Sstevel@tonic-gate header = 0; 2127c478bd9Sstevel@tonic-gate break; 2137c478bd9Sstevel@tonic-gate case 'h': 2147c478bd9Sstevel@tonic-gate hack = 0; 2157c478bd9Sstevel@tonic-gate break; 2167c478bd9Sstevel@tonic-gate case 'i': 2177c478bd9Sstevel@tonic-gate idle = 1; 2187c478bd9Sstevel@tonic-gate unquick = 0; 2197c478bd9Sstevel@tonic-gate break; 2207c478bd9Sstevel@tonic-gate case 'l': 2217c478bd9Sstevel@tonic-gate large = 1; 2227c478bd9Sstevel@tonic-gate break; 2237c478bd9Sstevel@tonic-gate case 'm': 2247c478bd9Sstevel@tonic-gate match = 0; 2257c478bd9Sstevel@tonic-gate break; 2267c478bd9Sstevel@tonic-gate case 'p': 2277c478bd9Sstevel@tonic-gate plan = 0; 2287c478bd9Sstevel@tonic-gate break; 2297c478bd9Sstevel@tonic-gate case 'q': 2307c478bd9Sstevel@tonic-gate unquick = 0; 2317c478bd9Sstevel@tonic-gate break; 2327c478bd9Sstevel@tonic-gate case 's': 2337c478bd9Sstevel@tonic-gate small = 1; 2347c478bd9Sstevel@tonic-gate break; 2357c478bd9Sstevel@tonic-gate case 'w': 2367c478bd9Sstevel@tonic-gate wide = 0; 2377c478bd9Sstevel@tonic-gate break; 2387c478bd9Sstevel@tonic-gate default: 2397c478bd9Sstevel@tonic-gate (void) fprintf(stderr, usagestr); 2407c478bd9Sstevel@tonic-gate exit(1); 2417c478bd9Sstevel@tonic-gate } 2427c478bd9Sstevel@tonic-gate if (unquick || idle) 2437c478bd9Sstevel@tonic-gate tloc = time(NULL); 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate /* find out what filtering on .plan/.project files we should do */ 2467c478bd9Sstevel@tonic-gate initscreening(); 2477c478bd9Sstevel@tonic-gate 2487c478bd9Sstevel@tonic-gate /* 2497c478bd9Sstevel@tonic-gate * optind == argc means no names given 2507c478bd9Sstevel@tonic-gate */ 2517c478bd9Sstevel@tonic-gate if (optind == argc) 2527c478bd9Sstevel@tonic-gate doall(); 2537c478bd9Sstevel@tonic-gate else 2547c478bd9Sstevel@tonic-gate donames(&argv[optind]); 2557a59e0bfSDavid Edmondson 2567a59e0bfSDavid Edmondson sort_by_username(); 2577a59e0bfSDavid Edmondson 2587a59e0bfSDavid Edmondson if (nperson > 0) 2597c478bd9Sstevel@tonic-gate print(); 2607c478bd9Sstevel@tonic-gate return (0); 2617c478bd9Sstevel@tonic-gate /* NOTREACHED */ 2627c478bd9Sstevel@tonic-gate } 2637c478bd9Sstevel@tonic-gate 2647c478bd9Sstevel@tonic-gate void 2657c478bd9Sstevel@tonic-gate doall(void) 2667c478bd9Sstevel@tonic-gate { 2677c478bd9Sstevel@tonic-gate struct person *p; 2687c478bd9Sstevel@tonic-gate struct passwd *pw; 2697c478bd9Sstevel@tonic-gate struct utmpx *u; 2707c478bd9Sstevel@tonic-gate char name[NMAX + 1]; 2717c478bd9Sstevel@tonic-gate 2727c478bd9Sstevel@tonic-gate unshort = large; 2737c478bd9Sstevel@tonic-gate setutxent(); 2747c478bd9Sstevel@tonic-gate if (unquick) { 2757c478bd9Sstevel@tonic-gate setpwent(); 2767c478bd9Sstevel@tonic-gate fwopen(); 2777c478bd9Sstevel@tonic-gate } 2787a59e0bfSDavid Edmondson while ((u = getutxent()) != NULL) { 2797c478bd9Sstevel@tonic-gate if (u->ut_name[0] == 0 || 2807c478bd9Sstevel@tonic-gate nonuserx(*u) || 2817c478bd9Sstevel@tonic-gate u->ut_type != USER_PROCESS) 2827c478bd9Sstevel@tonic-gate continue; 2837a59e0bfSDavid Edmondson if (person1 == NULL) 2847c478bd9Sstevel@tonic-gate p = person1 = malloc(sizeof (*p)); 2857c478bd9Sstevel@tonic-gate else { 2867c478bd9Sstevel@tonic-gate p->link = malloc(sizeof (*p)); 2877c478bd9Sstevel@tonic-gate p = p->link; 2887c478bd9Sstevel@tonic-gate } 2897c478bd9Sstevel@tonic-gate bcopy(u->ut_name, name, NMAX); 2907c478bd9Sstevel@tonic-gate name[NMAX] = 0; 2917c478bd9Sstevel@tonic-gate bcopy(u->ut_line, p->tty, LMAX); 2927c478bd9Sstevel@tonic-gate p->tty[LMAX] = 0; 2937c478bd9Sstevel@tonic-gate bcopy(u->ut_host, p->host, HMAX); 2947c478bd9Sstevel@tonic-gate p->host[HMAX] = 0; 2957c478bd9Sstevel@tonic-gate p->loginat = u->ut_tv.tv_sec; 2967a59e0bfSDavid Edmondson p->pwd = NULL; 2977c478bd9Sstevel@tonic-gate p->loggedin = 1; 2987c478bd9Sstevel@tonic-gate if (unquick && (pw = getpwnam(name))) { 2997c478bd9Sstevel@tonic-gate p->pwd = pwdcopy(pw); 3007c478bd9Sstevel@tonic-gate decode(p); 3017c478bd9Sstevel@tonic-gate p->name = p->pwd->pw_name; 3027c478bd9Sstevel@tonic-gate } else 3037c478bd9Sstevel@tonic-gate p->name = strdup(name); 3047c478bd9Sstevel@tonic-gate p->ttyloc = NULL; 3057a59e0bfSDavid Edmondson 3067a59e0bfSDavid Edmondson nperson++; 3077c478bd9Sstevel@tonic-gate } 3087c478bd9Sstevel@tonic-gate if (unquick) { 3097c478bd9Sstevel@tonic-gate fwclose(); 3107c478bd9Sstevel@tonic-gate endpwent(); 3117c478bd9Sstevel@tonic-gate } 3127c478bd9Sstevel@tonic-gate endutxent(); 3137a59e0bfSDavid Edmondson if (nperson == 0) { 3147c478bd9Sstevel@tonic-gate (void) printf("No one logged on\n"); 3157c478bd9Sstevel@tonic-gate return; 3167c478bd9Sstevel@tonic-gate } 3177a59e0bfSDavid Edmondson p->link = NULL; 3187c478bd9Sstevel@tonic-gate } 3197c478bd9Sstevel@tonic-gate 3207c478bd9Sstevel@tonic-gate void 3217c478bd9Sstevel@tonic-gate donames(char **argv) 3227c478bd9Sstevel@tonic-gate { 3237c478bd9Sstevel@tonic-gate struct person *p; 3247c478bd9Sstevel@tonic-gate struct passwd *pw; 3257c478bd9Sstevel@tonic-gate struct utmpx *u; 3267c478bd9Sstevel@tonic-gate 3277c478bd9Sstevel@tonic-gate /* 3287c478bd9Sstevel@tonic-gate * get names from command line and check to see if they're 3297c478bd9Sstevel@tonic-gate * logged in 3307c478bd9Sstevel@tonic-gate */ 3317c478bd9Sstevel@tonic-gate unshort = !small; 3327a59e0bfSDavid Edmondson for (; *argv != NULL; argv++) { 3337c478bd9Sstevel@tonic-gate if (netfinger(*argv)) 3347c478bd9Sstevel@tonic-gate continue; 3357a59e0bfSDavid Edmondson if (person1 == NULL) 3367c478bd9Sstevel@tonic-gate p = person1 = malloc(sizeof (*p)); 3377c478bd9Sstevel@tonic-gate else { 3387c478bd9Sstevel@tonic-gate p->link = malloc(sizeof (*p)); 3397c478bd9Sstevel@tonic-gate p = p->link; 3407c478bd9Sstevel@tonic-gate } 3417c478bd9Sstevel@tonic-gate p->name = *argv; 3427c478bd9Sstevel@tonic-gate p->loggedin = 0; 3437c478bd9Sstevel@tonic-gate p->original = 1; 3447a59e0bfSDavid Edmondson p->pwd = NULL; 3457a59e0bfSDavid Edmondson 3467a59e0bfSDavid Edmondson nperson++; 3477c478bd9Sstevel@tonic-gate } 3487a59e0bfSDavid Edmondson if (nperson == 0) 3497c478bd9Sstevel@tonic-gate return; 3507a59e0bfSDavid Edmondson p->link = NULL; 3517c478bd9Sstevel@tonic-gate /* 3527c478bd9Sstevel@tonic-gate * if we are doing it, read /etc/passwd for the useful info 3537c478bd9Sstevel@tonic-gate */ 3547c478bd9Sstevel@tonic-gate if (unquick) { 3557c478bd9Sstevel@tonic-gate setpwent(); 3567c478bd9Sstevel@tonic-gate if (!match) { 3577a59e0bfSDavid Edmondson for (p = person1; p != NULL; p = p->link) { 3587a59e0bfSDavid Edmondson if ((pw = getpwnam(p->name)) != NULL) 3597c478bd9Sstevel@tonic-gate p->pwd = pwdcopy(pw); 3607c478bd9Sstevel@tonic-gate } 3617c478bd9Sstevel@tonic-gate } else { 3627a59e0bfSDavid Edmondson while ((pw = getpwent()) != NULL) { 3637a59e0bfSDavid Edmondson for (p = person1; p != NULL; p = p->link) { 3647c478bd9Sstevel@tonic-gate if (!p->original) 3657c478bd9Sstevel@tonic-gate continue; 3667c478bd9Sstevel@tonic-gate if (strcmp(p->name, pw->pw_name) != 0 && 3677c478bd9Sstevel@tonic-gate !matchcmp(pw->pw_gecos, pw->pw_name, 3687c478bd9Sstevel@tonic-gate p->name)) { 3697c478bd9Sstevel@tonic-gate continue; 3707c478bd9Sstevel@tonic-gate } 3717a59e0bfSDavid Edmondson if (p->pwd == NULL) { 3727c478bd9Sstevel@tonic-gate p->pwd = pwdcopy(pw); 3737c478bd9Sstevel@tonic-gate } else { 3747c478bd9Sstevel@tonic-gate struct person *new; 3757c478bd9Sstevel@tonic-gate /* 3767c478bd9Sstevel@tonic-gate * Handle multiple login names. 3777c478bd9Sstevel@tonic-gate * Insert new "duplicate" entry 3787c478bd9Sstevel@tonic-gate * behind. 3797c478bd9Sstevel@tonic-gate */ 3807c478bd9Sstevel@tonic-gate new = malloc(sizeof (*new)); 3817c478bd9Sstevel@tonic-gate new->pwd = pwdcopy(pw); 3827c478bd9Sstevel@tonic-gate new->name = p->name; 3837c478bd9Sstevel@tonic-gate new->original = 1; 3847c478bd9Sstevel@tonic-gate new->loggedin = 0; 3857c478bd9Sstevel@tonic-gate new->ttyloc = NULL; 3867c478bd9Sstevel@tonic-gate new->link = p->link; 3877c478bd9Sstevel@tonic-gate p->original = 0; 3887c478bd9Sstevel@tonic-gate p->link = new; 3897c478bd9Sstevel@tonic-gate p = new; 3907a59e0bfSDavid Edmondson 3917a59e0bfSDavid Edmondson nperson++; 3927c478bd9Sstevel@tonic-gate } 3937c478bd9Sstevel@tonic-gate } 3947c478bd9Sstevel@tonic-gate } 3957c478bd9Sstevel@tonic-gate } 3967c478bd9Sstevel@tonic-gate endpwent(); 3977c478bd9Sstevel@tonic-gate } 3987c478bd9Sstevel@tonic-gate /* Now get login information */ 3997c478bd9Sstevel@tonic-gate setutxent(); 4007a59e0bfSDavid Edmondson while ((u = getutxent()) != NULL) { 4017c478bd9Sstevel@tonic-gate if (u->ut_name[0] == 0 || u->ut_type != USER_PROCESS) 4027c478bd9Sstevel@tonic-gate continue; 4037a59e0bfSDavid Edmondson for (p = person1; p != NULL; p = p->link) { 4047c478bd9Sstevel@tonic-gate p->ttyloc = NULL; 4057c478bd9Sstevel@tonic-gate if (p->loggedin == 2) 4067c478bd9Sstevel@tonic-gate continue; 4077a59e0bfSDavid Edmondson if (strncmp((p->pwd != NULL) ? 4087a59e0bfSDavid Edmondson p->pwd->pw_name : p->name, 4097c478bd9Sstevel@tonic-gate u->ut_name, NMAX) != 0) 4107c478bd9Sstevel@tonic-gate continue; 4117c478bd9Sstevel@tonic-gate if (p->loggedin == 0) { 4127c478bd9Sstevel@tonic-gate bcopy(u->ut_line, p->tty, LMAX); 4137c478bd9Sstevel@tonic-gate p->tty[LMAX] = 0; 4147c478bd9Sstevel@tonic-gate bcopy(u->ut_host, p->host, HMAX); 4157c478bd9Sstevel@tonic-gate p->host[HMAX] = 0; 4167c478bd9Sstevel@tonic-gate p->loginat = u->ut_tv.tv_sec; 4177c478bd9Sstevel@tonic-gate p->loggedin = 1; 4187c478bd9Sstevel@tonic-gate } else { /* p->loggedin == 1 */ 4197c478bd9Sstevel@tonic-gate struct person *new; 4207c478bd9Sstevel@tonic-gate new = malloc(sizeof (*new)); 4217c478bd9Sstevel@tonic-gate new->name = p->name; 4227c478bd9Sstevel@tonic-gate bcopy(u->ut_line, new->tty, LMAX); 4237c478bd9Sstevel@tonic-gate new->tty[LMAX] = 0; 4247c478bd9Sstevel@tonic-gate bcopy(u->ut_host, new->host, HMAX); 4257c478bd9Sstevel@tonic-gate new->host[HMAX] = 0; 4267c478bd9Sstevel@tonic-gate new->loginat = u->ut_tv.tv_sec; 4277c478bd9Sstevel@tonic-gate new->pwd = p->pwd; 4287c478bd9Sstevel@tonic-gate new->loggedin = 1; 4297c478bd9Sstevel@tonic-gate new->original = 0; 4307c478bd9Sstevel@tonic-gate new->link = p->link; 4317c478bd9Sstevel@tonic-gate p->loggedin = 2; 4327c478bd9Sstevel@tonic-gate p->link = new; 4337c478bd9Sstevel@tonic-gate p = new; 4347a59e0bfSDavid Edmondson 4357a59e0bfSDavid Edmondson nperson++; 4367c478bd9Sstevel@tonic-gate } 4377c478bd9Sstevel@tonic-gate } 4387c478bd9Sstevel@tonic-gate } 4397c478bd9Sstevel@tonic-gate endutxent(); 4407c478bd9Sstevel@tonic-gate if (unquick) { 4417c478bd9Sstevel@tonic-gate fwopen(); 4427a59e0bfSDavid Edmondson for (p = person1; p != NULL; p = p->link) 4437c478bd9Sstevel@tonic-gate decode(p); 4447c478bd9Sstevel@tonic-gate fwclose(); 4457c478bd9Sstevel@tonic-gate } 4467c478bd9Sstevel@tonic-gate } 4477c478bd9Sstevel@tonic-gate 4487c478bd9Sstevel@tonic-gate void 4497c478bd9Sstevel@tonic-gate print(void) 4507c478bd9Sstevel@tonic-gate { 4517c478bd9Sstevel@tonic-gate struct person *p; 4527c478bd9Sstevel@tonic-gate char *s; 4537c478bd9Sstevel@tonic-gate 4547c478bd9Sstevel@tonic-gate /* 4557c478bd9Sstevel@tonic-gate * print out what we got 4567c478bd9Sstevel@tonic-gate */ 4577c478bd9Sstevel@tonic-gate if (header) { 4587c478bd9Sstevel@tonic-gate if (unquick) { 4597c478bd9Sstevel@tonic-gate if (!unshort) { 4607c478bd9Sstevel@tonic-gate if (wide) { 4617c478bd9Sstevel@tonic-gate (void) printf("Login " 4627c478bd9Sstevel@tonic-gate "Name TTY " 4637c478bd9Sstevel@tonic-gate "Idle When Where\n"); 4647c478bd9Sstevel@tonic-gate } else { 4657c478bd9Sstevel@tonic-gate (void) printf("Login TTY Idle " 4667c478bd9Sstevel@tonic-gate "When Where\n"); 4677c478bd9Sstevel@tonic-gate } 4687c478bd9Sstevel@tonic-gate } 4697c478bd9Sstevel@tonic-gate } else { 4707c478bd9Sstevel@tonic-gate (void) printf("Login TTY When"); 4717c478bd9Sstevel@tonic-gate if (idle) 4727c478bd9Sstevel@tonic-gate (void) printf(" Idle"); 4737c478bd9Sstevel@tonic-gate (void) putchar('\n'); 4747c478bd9Sstevel@tonic-gate } 4757c478bd9Sstevel@tonic-gate } 4767a59e0bfSDavid Edmondson for (p = person1; p != NULL; p = p->link) { 4777c478bd9Sstevel@tonic-gate if (!unquick) { 4787c478bd9Sstevel@tonic-gate quickprint(p); 4797c478bd9Sstevel@tonic-gate continue; 4807c478bd9Sstevel@tonic-gate } 4817c478bd9Sstevel@tonic-gate if (!unshort) { 4827c478bd9Sstevel@tonic-gate shortprint(p); 4837c478bd9Sstevel@tonic-gate continue; 4847c478bd9Sstevel@tonic-gate } 4857c478bd9Sstevel@tonic-gate personprint(p); 4867a59e0bfSDavid Edmondson if (p->pwd != NULL && !AlreadyPrinted(p->pwd->pw_uid)) { 4877c478bd9Sstevel@tonic-gate AnyMail(p->pwd->pw_name); 4887c478bd9Sstevel@tonic-gate if (hack) { 4897c478bd9Sstevel@tonic-gate struct stat sbuf; 4907c478bd9Sstevel@tonic-gate 4917c478bd9Sstevel@tonic-gate s = malloc(strlen(p->pwd->pw_dir) + 4927c478bd9Sstevel@tonic-gate sizeof (PROJ)); 4937a59e0bfSDavid Edmondson if (s != NULL) { 4947c478bd9Sstevel@tonic-gate (void) strcpy(s, p->pwd->pw_dir); 4957c478bd9Sstevel@tonic-gate (void) strcat(s, PROJ); 4967c478bd9Sstevel@tonic-gate if (stat(s, &sbuf) != -1 && 4977c478bd9Sstevel@tonic-gate (S_ISREG(sbuf.st_mode) || 4987c478bd9Sstevel@tonic-gate S_ISFIFO(sbuf.st_mode)) && 4997c478bd9Sstevel@tonic-gate (sbuf.st_mode & S_IROTH)) { 5007c478bd9Sstevel@tonic-gate (void) printf("Project: "); 5017c478bd9Sstevel@tonic-gate catfile(s, sbuf.st_mode, 1); 5027c478bd9Sstevel@tonic-gate (void) putchar('\n'); 5037c478bd9Sstevel@tonic-gate } 5047c478bd9Sstevel@tonic-gate free(s); 5057c478bd9Sstevel@tonic-gate } 5067c478bd9Sstevel@tonic-gate } 5077c478bd9Sstevel@tonic-gate if (plan) { 5087c478bd9Sstevel@tonic-gate struct stat sbuf; 5097c478bd9Sstevel@tonic-gate 5107c478bd9Sstevel@tonic-gate s = malloc(strlen(p->pwd->pw_dir) + 5117c478bd9Sstevel@tonic-gate sizeof (PLAN)); 5127a59e0bfSDavid Edmondson if (s != NULL) { 5137c478bd9Sstevel@tonic-gate (void) strcpy(s, p->pwd->pw_dir); 5147c478bd9Sstevel@tonic-gate (void) strcat(s, PLAN); 5157c478bd9Sstevel@tonic-gate if (stat(s, &sbuf) == -1 || 5167c478bd9Sstevel@tonic-gate (!S_ISREG(sbuf.st_mode) && 5177c478bd9Sstevel@tonic-gate !S_ISFIFO(sbuf.st_mode)) || 5187c478bd9Sstevel@tonic-gate ((sbuf.st_mode & S_IROTH) == 0)) 5197c478bd9Sstevel@tonic-gate (void) printf("No Plan.\n"); 5207c478bd9Sstevel@tonic-gate else { 5217c478bd9Sstevel@tonic-gate (void) printf("Plan:\n"); 5227c478bd9Sstevel@tonic-gate catfile(s, sbuf.st_mode, 0); 5237c478bd9Sstevel@tonic-gate } 5247c478bd9Sstevel@tonic-gate free(s); 5257c478bd9Sstevel@tonic-gate } 5267c478bd9Sstevel@tonic-gate } 5277c478bd9Sstevel@tonic-gate } 5287a59e0bfSDavid Edmondson if (p->link != NULL) 5297c478bd9Sstevel@tonic-gate (void) putchar('\n'); 5307c478bd9Sstevel@tonic-gate } 5317c478bd9Sstevel@tonic-gate } 5327c478bd9Sstevel@tonic-gate 5337c478bd9Sstevel@tonic-gate /* 5347c478bd9Sstevel@tonic-gate * Duplicate a pwd entry. 5357c478bd9Sstevel@tonic-gate * Note: Only the useful things (what the program currently uses) are copied. 5367c478bd9Sstevel@tonic-gate */ 5377c478bd9Sstevel@tonic-gate struct passwd * 5387c478bd9Sstevel@tonic-gate pwdcopy(const struct passwd *pfrom) 5397c478bd9Sstevel@tonic-gate { 5407c478bd9Sstevel@tonic-gate struct passwd *pto; 5417c478bd9Sstevel@tonic-gate 5427c478bd9Sstevel@tonic-gate pto = malloc(sizeof (*pto)); 5437c478bd9Sstevel@tonic-gate pto->pw_name = strdup(pfrom->pw_name); 5447c478bd9Sstevel@tonic-gate pto->pw_uid = pfrom->pw_uid; 5457c478bd9Sstevel@tonic-gate pto->pw_gecos = strdup(pfrom->pw_gecos); 5467c478bd9Sstevel@tonic-gate pto->pw_dir = strdup(pfrom->pw_dir); 5477c478bd9Sstevel@tonic-gate pto->pw_shell = strdup(pfrom->pw_shell); 5487c478bd9Sstevel@tonic-gate return (pto); 5497c478bd9Sstevel@tonic-gate } 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate /* 5527c478bd9Sstevel@tonic-gate * print out information on quick format giving just name, tty, login time 5537c478bd9Sstevel@tonic-gate * and idle time if idle is set. 5547c478bd9Sstevel@tonic-gate */ 5557c478bd9Sstevel@tonic-gate void 5567c478bd9Sstevel@tonic-gate quickprint(struct person *pers) 5577c478bd9Sstevel@tonic-gate { 5587c478bd9Sstevel@tonic-gate (void) printf("%-8.8s ", pers->name); 5597c478bd9Sstevel@tonic-gate if (pers->loggedin) { 5607c478bd9Sstevel@tonic-gate if (idle) { 5617c478bd9Sstevel@tonic-gate findidle(pers); 5627c478bd9Sstevel@tonic-gate (void) printf("%c%-12s %-16.16s", 5637c478bd9Sstevel@tonic-gate pers->writable ? ' ' : '*', 5647c478bd9Sstevel@tonic-gate pers->tty, ctime(&pers->loginat)); 5657c478bd9Sstevel@tonic-gate ltimeprint(" ", &pers->idletime, ""); 5667c478bd9Sstevel@tonic-gate } else { 5677c478bd9Sstevel@tonic-gate (void) printf(" %-12s %-16.16s", 5687c478bd9Sstevel@tonic-gate pers->tty, ctime(&pers->loginat)); 5697c478bd9Sstevel@tonic-gate } 5707c478bd9Sstevel@tonic-gate (void) putchar('\n'); 5717c478bd9Sstevel@tonic-gate } else { 5727c478bd9Sstevel@tonic-gate (void) printf(" Not Logged In\n"); 5737c478bd9Sstevel@tonic-gate } 5747c478bd9Sstevel@tonic-gate } 5757c478bd9Sstevel@tonic-gate 5767c478bd9Sstevel@tonic-gate /* 5777c478bd9Sstevel@tonic-gate * print out information in short format, giving login name, full name, 5787c478bd9Sstevel@tonic-gate * tty, idle time, login time, and host. 5797c478bd9Sstevel@tonic-gate */ 5807c478bd9Sstevel@tonic-gate void 5817c478bd9Sstevel@tonic-gate shortprint(struct person *pers) 5827c478bd9Sstevel@tonic-gate { 5837c478bd9Sstevel@tonic-gate char *p; 5847c478bd9Sstevel@tonic-gate 5857a59e0bfSDavid Edmondson if (pers->pwd == NULL) { 5867c478bd9Sstevel@tonic-gate (void) printf("%-15s ???\n", pers->name); 5877c478bd9Sstevel@tonic-gate return; 5887c478bd9Sstevel@tonic-gate } 5897c478bd9Sstevel@tonic-gate (void) printf("%-8s", pers->pwd->pw_name); 5907c478bd9Sstevel@tonic-gate if (wide) { 5917a59e0bfSDavid Edmondson if (pers->realname != NULL) { 5927c478bd9Sstevel@tonic-gate (void) printf(" %-20.20s", pers->realname); 5937c478bd9Sstevel@tonic-gate } else { 5947c478bd9Sstevel@tonic-gate (void) printf(" ??? "); 5957c478bd9Sstevel@tonic-gate } 5967c478bd9Sstevel@tonic-gate } 5977c478bd9Sstevel@tonic-gate (void) putchar(' '); 5987c478bd9Sstevel@tonic-gate if (pers->loggedin && !pers->writable) { 5997c478bd9Sstevel@tonic-gate (void) putchar('*'); 6007c478bd9Sstevel@tonic-gate } else { 6017c478bd9Sstevel@tonic-gate (void) putchar(' '); 6027c478bd9Sstevel@tonic-gate } 6037c478bd9Sstevel@tonic-gate if (*pers->tty) { 6047c478bd9Sstevel@tonic-gate (void) printf("%-11.11s ", pers->tty); 6057c478bd9Sstevel@tonic-gate } else { 6067c478bd9Sstevel@tonic-gate (void) printf(" "); /* 12 spaces */ 6077c478bd9Sstevel@tonic-gate } 6087c478bd9Sstevel@tonic-gate p = ctime(&pers->loginat); 6097c478bd9Sstevel@tonic-gate if (pers->loggedin) { 6107c478bd9Sstevel@tonic-gate stimeprint(&pers->idletime); 6117c478bd9Sstevel@tonic-gate (void) printf(" %3.3s %-5.5s ", p, p + 11); 6127c478bd9Sstevel@tonic-gate } else if (pers->loginat == 0) { 6137c478bd9Sstevel@tonic-gate (void) printf(" < . . . . >"); 6147c478bd9Sstevel@tonic-gate } else if (tloc - pers->loginat >= 180 * 24 * 60 * 60) { 6157c478bd9Sstevel@tonic-gate (void) printf(" <%-6.6s, %-4.4s>", p + 4, p + 20); 6167c478bd9Sstevel@tonic-gate } else { 6177c478bd9Sstevel@tonic-gate (void) printf(" <%-12.12s>", p + 4); 6187c478bd9Sstevel@tonic-gate } 6197c478bd9Sstevel@tonic-gate if (*pers->host) { 6207c478bd9Sstevel@tonic-gate (void) printf(" %-20.20s", pers->host); 6217c478bd9Sstevel@tonic-gate } else { 6227c478bd9Sstevel@tonic-gate if (pers->ttyloc != NULL) 6237c478bd9Sstevel@tonic-gate (void) printf(" %-20.20s", pers->ttyloc); 6247c478bd9Sstevel@tonic-gate } 6257c478bd9Sstevel@tonic-gate (void) putchar('\n'); 6267c478bd9Sstevel@tonic-gate } 6277c478bd9Sstevel@tonic-gate 6287c478bd9Sstevel@tonic-gate 6297c478bd9Sstevel@tonic-gate /* 6307c478bd9Sstevel@tonic-gate * print out a person in long format giving all possible information. 6317c478bd9Sstevel@tonic-gate * directory and shell are inhibited if unbrief is clear. 6327c478bd9Sstevel@tonic-gate */ 6337c478bd9Sstevel@tonic-gate void 6347c478bd9Sstevel@tonic-gate personprint(struct person *pers) 6357c478bd9Sstevel@tonic-gate { 6367a59e0bfSDavid Edmondson if (pers->pwd == NULL) { 6377c478bd9Sstevel@tonic-gate (void) printf("Login name: %-10s\t\t\tIn real life: ???\n", 6387c478bd9Sstevel@tonic-gate pers->name); 6397c478bd9Sstevel@tonic-gate return; 6407c478bd9Sstevel@tonic-gate } 6417c478bd9Sstevel@tonic-gate (void) printf("Login name: %-10s", pers->pwd->pw_name); 6427c478bd9Sstevel@tonic-gate if (pers->loggedin && !pers->writable) { 6437c478bd9Sstevel@tonic-gate (void) printf(" (messages off) "); 6447c478bd9Sstevel@tonic-gate } else { 6457c478bd9Sstevel@tonic-gate (void) printf(" "); 6467c478bd9Sstevel@tonic-gate } 6477a59e0bfSDavid Edmondson if (pers->realname != NULL) { 6487c478bd9Sstevel@tonic-gate (void) printf("In real life: %s", pers->realname); 6497c478bd9Sstevel@tonic-gate } 6507c478bd9Sstevel@tonic-gate if (unbrief) { 6517c478bd9Sstevel@tonic-gate (void) printf("\nDirectory: %-25s", pers->pwd->pw_dir); 6527c478bd9Sstevel@tonic-gate if (*pers->pwd->pw_shell) 6537c478bd9Sstevel@tonic-gate (void) printf("\tShell: %-s", pers->pwd->pw_shell); 6547c478bd9Sstevel@tonic-gate } 6557c478bd9Sstevel@tonic-gate if (pers->loggedin) { 6567c478bd9Sstevel@tonic-gate char *ep = ctime(&pers->loginat); 6577c478bd9Sstevel@tonic-gate if (*pers->host) { 6587c478bd9Sstevel@tonic-gate (void) printf("\nOn since %15.15s on %s from %s", 6597c478bd9Sstevel@tonic-gate &ep[4], pers->tty, pers->host); 6607c478bd9Sstevel@tonic-gate ltimeprint("\n", &pers->idletime, " Idle Time"); 6617c478bd9Sstevel@tonic-gate } else { 6627c478bd9Sstevel@tonic-gate (void) printf("\nOn since %15.15s on %-12s", 6637c478bd9Sstevel@tonic-gate &ep[4], pers->tty); 6647c478bd9Sstevel@tonic-gate ltimeprint("\n", &pers->idletime, " Idle Time"); 6657c478bd9Sstevel@tonic-gate } 6667c478bd9Sstevel@tonic-gate } else if (pers->loginat == 0) { 6677c478bd9Sstevel@tonic-gate (void) printf("\nNever logged in."); 6687c478bd9Sstevel@tonic-gate } else if (tloc - pers->loginat > 180 * 24 * 60 * 60) { 6697c478bd9Sstevel@tonic-gate char *ep = ctime(&pers->loginat); 6707c478bd9Sstevel@tonic-gate (void) printf("\nLast login %10.10s, %4.4s on %s", 6717c478bd9Sstevel@tonic-gate ep, ep+20, pers->tty); 6727c478bd9Sstevel@tonic-gate if (*pers->host) { 6737c478bd9Sstevel@tonic-gate (void) printf(" from %s", pers->host); 6747c478bd9Sstevel@tonic-gate } 6757c478bd9Sstevel@tonic-gate } else { 6767c478bd9Sstevel@tonic-gate char *ep = ctime(&pers->loginat); 6777c478bd9Sstevel@tonic-gate (void) printf("\nLast login %16.16s on %s", ep, pers->tty); 6787c478bd9Sstevel@tonic-gate if (*pers->host) { 6797c478bd9Sstevel@tonic-gate (void) printf(" from %s", pers->host); 6807c478bd9Sstevel@tonic-gate } 6817c478bd9Sstevel@tonic-gate } 6827c478bd9Sstevel@tonic-gate (void) putchar('\n'); 6837c478bd9Sstevel@tonic-gate } 6847c478bd9Sstevel@tonic-gate 6857c478bd9Sstevel@tonic-gate 6867c478bd9Sstevel@tonic-gate /* 6877c478bd9Sstevel@tonic-gate * decode the information in the gecos field of /etc/passwd 6887c478bd9Sstevel@tonic-gate */ 6897c478bd9Sstevel@tonic-gate void 6907c478bd9Sstevel@tonic-gate decode(struct person *pers) 6917c478bd9Sstevel@tonic-gate { 6927c478bd9Sstevel@tonic-gate char buffer[256]; 6937c478bd9Sstevel@tonic-gate char *bp, *gp, *lp; 6947c478bd9Sstevel@tonic-gate 6957a59e0bfSDavid Edmondson pers->realname = NULL; 6967a59e0bfSDavid Edmondson if (pers->pwd == NULL) 6977c478bd9Sstevel@tonic-gate return; 6987c478bd9Sstevel@tonic-gate gp = pers->pwd->pw_gecos; 6997c478bd9Sstevel@tonic-gate bp = buffer; 7007c478bd9Sstevel@tonic-gate 7017c478bd9Sstevel@tonic-gate if (gecos_ignore_c != '\0' && 7027c478bd9Sstevel@tonic-gate *gp == gecos_ignore_c) { 7037c478bd9Sstevel@tonic-gate gp++; 7047c478bd9Sstevel@tonic-gate } 7057c478bd9Sstevel@tonic-gate while (*gp != '\0' && 7067c478bd9Sstevel@tonic-gate *gp != gecos_sep_c) { /* name */ 7077c478bd9Sstevel@tonic-gate if (*gp == gecos_samename) { 7087c478bd9Sstevel@tonic-gate lp = pers->pwd->pw_name; 7097c478bd9Sstevel@tonic-gate if (islower(*lp)) 7107c478bd9Sstevel@tonic-gate *bp++ = toupper(*lp++); 7117c478bd9Sstevel@tonic-gate while (*bp++ = *lp++) 7127c478bd9Sstevel@tonic-gate ; 7137c478bd9Sstevel@tonic-gate bp--; 7147c478bd9Sstevel@tonic-gate gp++; 7157c478bd9Sstevel@tonic-gate } else { 7167c478bd9Sstevel@tonic-gate *bp++ = *gp++; 7177c478bd9Sstevel@tonic-gate } 7187c478bd9Sstevel@tonic-gate } 7197c478bd9Sstevel@tonic-gate *bp++ = 0; 7207c478bd9Sstevel@tonic-gate if (bp > (buffer + 1)) 7217c478bd9Sstevel@tonic-gate pers->realname = strdup(buffer); 7227c478bd9Sstevel@tonic-gate if (pers->loggedin) 7237c478bd9Sstevel@tonic-gate findidle(pers); 7247c478bd9Sstevel@tonic-gate else 7257c478bd9Sstevel@tonic-gate findwhen(pers); 7267c478bd9Sstevel@tonic-gate } 7277c478bd9Sstevel@tonic-gate 7287c478bd9Sstevel@tonic-gate /* 7297c478bd9Sstevel@tonic-gate * find the last log in of a user by checking the LASTLOG file. 7307c478bd9Sstevel@tonic-gate * the entry is indexed by the uid, so this can only be done if 7317c478bd9Sstevel@tonic-gate * the uid is known (which it isn't in quick mode) 7327c478bd9Sstevel@tonic-gate */ 7337c478bd9Sstevel@tonic-gate void 7347c478bd9Sstevel@tonic-gate fwopen(void) 7357c478bd9Sstevel@tonic-gate { 736*2de0a7d6SDan McDonald if ((lf = fopen(LASTLOG, "r")) == NULL) 737*2de0a7d6SDan McDonald (void) fprintf(stderr, "finger: %s open error\n", LASTLOG); 7387c478bd9Sstevel@tonic-gate } 7397c478bd9Sstevel@tonic-gate 7407c478bd9Sstevel@tonic-gate void 7417c478bd9Sstevel@tonic-gate findwhen(struct person *pers) 7427c478bd9Sstevel@tonic-gate { 7437c478bd9Sstevel@tonic-gate struct lastlog ll; 7447c478bd9Sstevel@tonic-gate 7457a59e0bfSDavid Edmondson if (lf != NULL) { 7467c478bd9Sstevel@tonic-gate if (fseeko(lf, (off_t)pers->pwd->pw_uid * (off_t)sizeof (ll), 7477c478bd9Sstevel@tonic-gate SEEK_SET) == 0) { 7487c478bd9Sstevel@tonic-gate if (fread((char *)&ll, sizeof (ll), 1, lf) == 1) { 7497c478bd9Sstevel@tonic-gate int l_max, h_max; 7507c478bd9Sstevel@tonic-gate 7517c478bd9Sstevel@tonic-gate l_max = min(LMAX, sizeof (ll.ll_line)); 7527c478bd9Sstevel@tonic-gate h_max = min(HMAX, sizeof (ll.ll_host)); 7537c478bd9Sstevel@tonic-gate 7547c478bd9Sstevel@tonic-gate bcopy(ll.ll_line, pers->tty, l_max); 7557c478bd9Sstevel@tonic-gate pers->tty[l_max] = '\0'; 7567c478bd9Sstevel@tonic-gate bcopy(ll.ll_host, pers->host, h_max); 7577c478bd9Sstevel@tonic-gate pers->host[h_max] = '\0'; 7587c478bd9Sstevel@tonic-gate pers->loginat = ll.ll_time; 7597c478bd9Sstevel@tonic-gate } else { 7607c478bd9Sstevel@tonic-gate if (ferror(lf)) 7617c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 762*2de0a7d6SDan McDonald "finger: %s read error\n", LASTLOG); 7637c478bd9Sstevel@tonic-gate pers->tty[0] = 0; 7647c478bd9Sstevel@tonic-gate pers->host[0] = 0; 7657c478bd9Sstevel@tonic-gate pers->loginat = 0L; 7667c478bd9Sstevel@tonic-gate } 7677c478bd9Sstevel@tonic-gate } else { 7687c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "finger: %s fseeko error\n", 769*2de0a7d6SDan McDonald LASTLOG); 7707c478bd9Sstevel@tonic-gate } 7717c478bd9Sstevel@tonic-gate } else { 7727c478bd9Sstevel@tonic-gate pers->tty[0] = 0; 7737c478bd9Sstevel@tonic-gate pers->host[0] = 0; 7747c478bd9Sstevel@tonic-gate pers->loginat = 0L; 7757c478bd9Sstevel@tonic-gate } 7767c478bd9Sstevel@tonic-gate } 7777c478bd9Sstevel@tonic-gate 7787c478bd9Sstevel@tonic-gate void 7797c478bd9Sstevel@tonic-gate fwclose(void) 7807c478bd9Sstevel@tonic-gate { 7817a59e0bfSDavid Edmondson if (lf != NULL) 7827c478bd9Sstevel@tonic-gate (void) fclose(lf); 7837c478bd9Sstevel@tonic-gate } 7847c478bd9Sstevel@tonic-gate 7857c478bd9Sstevel@tonic-gate /* 7867c478bd9Sstevel@tonic-gate * find the idle time of a user by doing a stat on /dev/tty??, 7877c478bd9Sstevel@tonic-gate * where tty?? has been gotten from UTMPX_FILE, supposedly. 7887c478bd9Sstevel@tonic-gate */ 7897c478bd9Sstevel@tonic-gate void 7907c478bd9Sstevel@tonic-gate findidle(struct person *pers) 7917c478bd9Sstevel@tonic-gate { 7927c478bd9Sstevel@tonic-gate struct stat ttystatus; 7937c478bd9Sstevel@tonic-gate struct stat inputdevstatus; 7947c478bd9Sstevel@tonic-gate #define TTYLEN (sizeof ("/dev/") - 1) 7957c478bd9Sstevel@tonic-gate static char buffer[TTYLEN + LMAX + 1] = "/dev/"; 7967c478bd9Sstevel@tonic-gate time_t t; 7977c478bd9Sstevel@tonic-gate time_t lastinputtime; 7987c478bd9Sstevel@tonic-gate 7997c478bd9Sstevel@tonic-gate (void) strcpy(buffer + TTYLEN, pers->tty); 8007c478bd9Sstevel@tonic-gate buffer[TTYLEN+LMAX] = 0; 8017c478bd9Sstevel@tonic-gate if (stat(buffer, &ttystatus) < 0) { 8027c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "finger: Can't stat %s\n", buffer); 8037c478bd9Sstevel@tonic-gate exit(4); 8047c478bd9Sstevel@tonic-gate } 8057c478bd9Sstevel@tonic-gate lastinputtime = ttystatus.st_atime; 8067c478bd9Sstevel@tonic-gate if (strcmp(pers->tty, "console") == 0) { 8077c478bd9Sstevel@tonic-gate /* 8087c478bd9Sstevel@tonic-gate * On the console, the user may be running a window system; if 8097c478bd9Sstevel@tonic-gate * so, their activity will show up in the last-access times of 8107c478bd9Sstevel@tonic-gate * "/dev/kbd" and "/dev/mouse", so take the minimum of the idle 8117c478bd9Sstevel@tonic-gate * times on those two devices and "/dev/console" and treat that 8127c478bd9Sstevel@tonic-gate * as the idle time. 8137c478bd9Sstevel@tonic-gate */ 8147c478bd9Sstevel@tonic-gate if (stat("/dev/kbd", &inputdevstatus) == 0) { 8157c478bd9Sstevel@tonic-gate if (lastinputtime < inputdevstatus.st_atime) 8167c478bd9Sstevel@tonic-gate lastinputtime = inputdevstatus.st_atime; 8177c478bd9Sstevel@tonic-gate } 8187c478bd9Sstevel@tonic-gate if (stat("/dev/mouse", &inputdevstatus) == 0) { 8197c478bd9Sstevel@tonic-gate if (lastinputtime < inputdevstatus.st_atime) 8207c478bd9Sstevel@tonic-gate lastinputtime = inputdevstatus.st_atime; 8217c478bd9Sstevel@tonic-gate } 8227c478bd9Sstevel@tonic-gate } 8237c478bd9Sstevel@tonic-gate t = time(NULL); 8247c478bd9Sstevel@tonic-gate if (t < lastinputtime) 8257c478bd9Sstevel@tonic-gate pers->idletime = (time_t)0; 8267c478bd9Sstevel@tonic-gate else 8277c478bd9Sstevel@tonic-gate pers->idletime = t - lastinputtime; 8287c478bd9Sstevel@tonic-gate pers->writable = (ttystatus.st_mode & TALKABLE) == TALKABLE; 8297c478bd9Sstevel@tonic-gate } 8307c478bd9Sstevel@tonic-gate 8317c478bd9Sstevel@tonic-gate /* 8327c478bd9Sstevel@tonic-gate * print idle time in short format; this program always prints 4 characters; 8337c478bd9Sstevel@tonic-gate * if the idle time is zero, it prints 4 blanks. 8347c478bd9Sstevel@tonic-gate */ 8357c478bd9Sstevel@tonic-gate void 8367c478bd9Sstevel@tonic-gate stimeprint(time_t *dt) 8377c478bd9Sstevel@tonic-gate { 8387c478bd9Sstevel@tonic-gate struct tm *delta; 8397c478bd9Sstevel@tonic-gate 8407c478bd9Sstevel@tonic-gate delta = gmtime(dt); 8417c478bd9Sstevel@tonic-gate if (delta->tm_yday == 0) 8427c478bd9Sstevel@tonic-gate if (delta->tm_hour == 0) 8437c478bd9Sstevel@tonic-gate if (delta->tm_min == 0) 8447c478bd9Sstevel@tonic-gate (void) printf(" "); 8457c478bd9Sstevel@tonic-gate else 8467c478bd9Sstevel@tonic-gate (void) printf(" %2d", delta->tm_min); 8477c478bd9Sstevel@tonic-gate else 8487c478bd9Sstevel@tonic-gate if (delta->tm_hour >= 10) 8497c478bd9Sstevel@tonic-gate (void) printf("%3d:", delta->tm_hour); 8507c478bd9Sstevel@tonic-gate else 8517c478bd9Sstevel@tonic-gate (void) printf("%1d:%02d", 8527c478bd9Sstevel@tonic-gate delta->tm_hour, delta->tm_min); 8537c478bd9Sstevel@tonic-gate else 8547c478bd9Sstevel@tonic-gate (void) printf("%3dd", delta->tm_yday); 8557c478bd9Sstevel@tonic-gate } 8567c478bd9Sstevel@tonic-gate 8577c478bd9Sstevel@tonic-gate /* 8587c478bd9Sstevel@tonic-gate * print idle time in long format with care being taken not to pluralize 8597c478bd9Sstevel@tonic-gate * 1 minutes or 1 hours or 1 days. 8607c478bd9Sstevel@tonic-gate * print "prefix" first. 8617c478bd9Sstevel@tonic-gate */ 8627c478bd9Sstevel@tonic-gate void 8637c478bd9Sstevel@tonic-gate ltimeprint(char *before, time_t *dt, char *after) 8647c478bd9Sstevel@tonic-gate { 8657c478bd9Sstevel@tonic-gate struct tm *delta; 8667c478bd9Sstevel@tonic-gate 8677c478bd9Sstevel@tonic-gate delta = gmtime(dt); 8687c478bd9Sstevel@tonic-gate if (delta->tm_yday == 0 && delta->tm_hour == 0 && delta->tm_min == 0 && 8697c478bd9Sstevel@tonic-gate delta->tm_sec <= 10) 8707c478bd9Sstevel@tonic-gate return; 8717c478bd9Sstevel@tonic-gate (void) printf("%s", before); 8727c478bd9Sstevel@tonic-gate if (delta->tm_yday >= 10) 8737c478bd9Sstevel@tonic-gate (void) printf("%d days", delta->tm_yday); 8747c478bd9Sstevel@tonic-gate else if (delta->tm_yday > 0) 8757c478bd9Sstevel@tonic-gate (void) printf("%d day%s %d hour%s", 8767c478bd9Sstevel@tonic-gate delta->tm_yday, delta->tm_yday == 1 ? "" : "s", 8777c478bd9Sstevel@tonic-gate delta->tm_hour, delta->tm_hour == 1 ? "" : "s"); 8787c478bd9Sstevel@tonic-gate else 8797c478bd9Sstevel@tonic-gate if (delta->tm_hour >= 10) 8807c478bd9Sstevel@tonic-gate (void) printf("%d hours", delta->tm_hour); 8817c478bd9Sstevel@tonic-gate else if (delta->tm_hour > 0) 8827c478bd9Sstevel@tonic-gate (void) printf("%d hour%s %d minute%s", 8837c478bd9Sstevel@tonic-gate delta->tm_hour, delta->tm_hour == 1 ? "" : "s", 8847c478bd9Sstevel@tonic-gate delta->tm_min, delta->tm_min == 1 ? "" : "s"); 8857c478bd9Sstevel@tonic-gate else 8867c478bd9Sstevel@tonic-gate if (delta->tm_min >= 10) 8877c478bd9Sstevel@tonic-gate (void) printf("%2d minutes", delta->tm_min); 8887c478bd9Sstevel@tonic-gate else if (delta->tm_min == 0) 8897c478bd9Sstevel@tonic-gate (void) printf("%2d seconds", delta->tm_sec); 8907c478bd9Sstevel@tonic-gate else 8917c478bd9Sstevel@tonic-gate (void) printf("%d minute%s %d second%s", 8927c478bd9Sstevel@tonic-gate delta->tm_min, 8937c478bd9Sstevel@tonic-gate delta->tm_min == 1 ? "" : "s", 8947c478bd9Sstevel@tonic-gate delta->tm_sec, 8957c478bd9Sstevel@tonic-gate delta->tm_sec == 1 ? "" : "s"); 8967c478bd9Sstevel@tonic-gate (void) printf("%s", after); 8977c478bd9Sstevel@tonic-gate } 8987c478bd9Sstevel@tonic-gate 8997c478bd9Sstevel@tonic-gate /* 9007c478bd9Sstevel@tonic-gate * The grammar of the pw_gecos field is sufficiently complex that the 9017c478bd9Sstevel@tonic-gate * best way to parse it is by using an explicit finite-state machine, 9027c478bd9Sstevel@tonic-gate * in which a table defines the rules of interpretation. 9037c478bd9Sstevel@tonic-gate * 9047c478bd9Sstevel@tonic-gate * Some special rules are necessary to handle the fact that names 9057c478bd9Sstevel@tonic-gate * may contain certain punctuation characters. At this writing, 9067c478bd9Sstevel@tonic-gate * the possible punctuation characters are '.', '-', and '_'. 9077c478bd9Sstevel@tonic-gate * 9087c478bd9Sstevel@tonic-gate * Other rules are needed to account for characters that require special 9097c478bd9Sstevel@tonic-gate * processing when they appear in the pw_gecos field. At present, there 9107c478bd9Sstevel@tonic-gate * are three such characters, with these default values and effects: 9117c478bd9Sstevel@tonic-gate * 9127c478bd9Sstevel@tonic-gate * gecos_ignore_c '*' This character is ignored. 9137c478bd9Sstevel@tonic-gate * gecos_sep_c ',' Delimits displayed and nondisplayed contents. 9147c478bd9Sstevel@tonic-gate * gecos_samename '&' Copies the login name into the output. 9157c478bd9Sstevel@tonic-gate * 9167c478bd9Sstevel@tonic-gate * As the program examines each successive character in the returned 9177c478bd9Sstevel@tonic-gate * pw_gecos value, it fetches (from the table) the FSM rule applicable 9187c478bd9Sstevel@tonic-gate * for that character in the current machine state, and thus determines 9197c478bd9Sstevel@tonic-gate * the next state. 9207c478bd9Sstevel@tonic-gate * 9217c478bd9Sstevel@tonic-gate * The possible states are: 9227c478bd9Sstevel@tonic-gate * S0 start 9237c478bd9Sstevel@tonic-gate * S1 in a word 9247c478bd9Sstevel@tonic-gate * S2 not in a word 9257c478bd9Sstevel@tonic-gate * S3 copy login name into output 9267c478bd9Sstevel@tonic-gate * S4 end of GECOS field 9277c478bd9Sstevel@tonic-gate * 9287c478bd9Sstevel@tonic-gate * Here follows a depiction of the state transitions. 9297c478bd9Sstevel@tonic-gate * 9307c478bd9Sstevel@tonic-gate * 9317c478bd9Sstevel@tonic-gate * gecos_ignore_c OR isspace OR any other character 9327c478bd9Sstevel@tonic-gate * +--+ 9337c478bd9Sstevel@tonic-gate * | | 9347c478bd9Sstevel@tonic-gate * | V 9357c478bd9Sstevel@tonic-gate * +-----+ 9367c478bd9Sstevel@tonic-gate * NULL OR | S0 | isalpha OR isdigit 9377c478bd9Sstevel@tonic-gate * +---------------|start|------------------------+ 9387c478bd9Sstevel@tonic-gate * | gecos_sep_c +-----+ | isalpha OR isdigit 9397c478bd9Sstevel@tonic-gate * | | | | +---------------------+ 9407c478bd9Sstevel@tonic-gate * | | | | | OR '.' '-' '_' | 9417c478bd9Sstevel@tonic-gate * | | |isspace | | | 9427c478bd9Sstevel@tonic-gate * | | +-------+ V V | 9437c478bd9Sstevel@tonic-gate * | | | +-----------+ | 9447c478bd9Sstevel@tonic-gate * | | | | S1 |<--+ | 9457c478bd9Sstevel@tonic-gate * | | | | in a word | | isalpha OR | 9467c478bd9Sstevel@tonic-gate * | | | +-----------+ | isdigit OR | 9477c478bd9Sstevel@tonic-gate * | | | | | | | | '.' '-' '_' | 9487c478bd9Sstevel@tonic-gate * | | +----- ---------------+ | | +-----+ | 9497c478bd9Sstevel@tonic-gate * | | | | | | | 9507c478bd9Sstevel@tonic-gate * | | | | gecos_ignore_c | | | 9517c478bd9Sstevel@tonic-gate * | | | | isspace | | | 9527c478bd9Sstevel@tonic-gate * | | | | ispunct/other | | | 9537c478bd9Sstevel@tonic-gate * | | | | any other char | | | 9547c478bd9Sstevel@tonic-gate * | | | | +---------------+ | | 9557c478bd9Sstevel@tonic-gate * | | | | | |NULL OR gecos_sep_c | 9567c478bd9Sstevel@tonic-gate * | | | | | +------------------+ | 9577c478bd9Sstevel@tonic-gate * | gecos_samename| | V V | | 9587c478bd9Sstevel@tonic-gate * | +-------------+ | +---------------+ | | 9597c478bd9Sstevel@tonic-gate * | | | | S2 | isspace OR '.' '-' '_' | | 9607c478bd9Sstevel@tonic-gate * | | gecos_samename | | not in a word |<---------------------+ | | 9617c478bd9Sstevel@tonic-gate * | | +---------------+ +---------------+ OR gecos_ignore_c | | | 9627c478bd9Sstevel@tonic-gate * | | | | ^ | | OR ispunct OR other | | | 9637c478bd9Sstevel@tonic-gate * | | | | | | | | | | 9647c478bd9Sstevel@tonic-gate * | | | gecos_samename | | | +-----------------------+ | | 9657c478bd9Sstevel@tonic-gate * | | | +---------------------+ | | | | 9667c478bd9Sstevel@tonic-gate * | | | | | | | | 9677c478bd9Sstevel@tonic-gate * | | | | gecos_ignore_c| | NULL OR gecos_sep_c | | 9687c478bd9Sstevel@tonic-gate * | | | | gecos_samename| +-----------------------+ | | 9697c478bd9Sstevel@tonic-gate * | | | | ispunct/other | | | | 9707c478bd9Sstevel@tonic-gate * | V V V isspace | | | | 9717c478bd9Sstevel@tonic-gate * | +-----------------+ any other char| | | | 9727c478bd9Sstevel@tonic-gate * | | S3 |---------------+ isalpha OR isdigit OR | | | 9737c478bd9Sstevel@tonic-gate * | |insert login name|------------------------------------------ ----- ---+ 9747c478bd9Sstevel@tonic-gate * | +-----------------+ '.' '-' '_' | | 9757c478bd9Sstevel@tonic-gate * | | NULL OR gecos_sep_c | | 9767c478bd9Sstevel@tonic-gate * | +------------------------------------------+ | | 9777c478bd9Sstevel@tonic-gate * | | | | 9787c478bd9Sstevel@tonic-gate * | V V V 9797c478bd9Sstevel@tonic-gate * | +------------+ 9807c478bd9Sstevel@tonic-gate * | NULL OR gecos_sep_c | S4 | 9817c478bd9Sstevel@tonic-gate * +-------------------------------------------------------->|end of gecos|<--+ 9827c478bd9Sstevel@tonic-gate * +------------+ | 9837c478bd9Sstevel@tonic-gate * | all | 9847c478bd9Sstevel@tonic-gate * +-----+ 9857c478bd9Sstevel@tonic-gate * 9867c478bd9Sstevel@tonic-gate * 9877c478bd9Sstevel@tonic-gate * The transitions from the above diagram are summarized in 9887c478bd9Sstevel@tonic-gate * the following table of target states, which is implemented 9897c478bd9Sstevel@tonic-gate * in code as the gecos_fsm array. 9907c478bd9Sstevel@tonic-gate * 9917c478bd9Sstevel@tonic-gate * Input: 9927c478bd9Sstevel@tonic-gate * +--gecos_ignore_c 9937c478bd9Sstevel@tonic-gate * | +--gecos_sep_c 9947c478bd9Sstevel@tonic-gate * | | +--gecos_samename 9957c478bd9Sstevel@tonic-gate * | | | +--isalpha 9967c478bd9Sstevel@tonic-gate * | | | | +--isdigit 9977c478bd9Sstevel@tonic-gate * | | | | | +--isspace 9987c478bd9Sstevel@tonic-gate * | | | | | | +--punctuation possible in name 9997c478bd9Sstevel@tonic-gate * | | | | | | | +--other punctuation 10007c478bd9Sstevel@tonic-gate * | | | | | | | | +--NULL character 10017c478bd9Sstevel@tonic-gate * | | | | | | | | | +--any other character 10027c478bd9Sstevel@tonic-gate * | | | | | | | | | | 10037c478bd9Sstevel@tonic-gate * V V V V V V V V V V 10047c478bd9Sstevel@tonic-gate * From: --------------------------------------------------- 10057c478bd9Sstevel@tonic-gate * S0 | S0 | S4 | S3 | S1 | S1 | S0 | S1 | S2 | S4 | S0 | 10067c478bd9Sstevel@tonic-gate * S1 | S2 | S4 | S3 | S1 | S1 | S2 | S1 | S2 | S4 | S2 | 10077c478bd9Sstevel@tonic-gate * S2 | S2 | S4 | S3 | S1 | S1 | S2 | S2 | S2 | S4 | S2 | 10087c478bd9Sstevel@tonic-gate * S3 | S2 | S4 | S2 | S1 | S1 | S2 | S1 | S2 | S4 | S2 | 10097c478bd9Sstevel@tonic-gate * S4 | S4 | S4 | S4 | S4 | S4 | S4 | S4 | S4 | S4 | S4 | 10107c478bd9Sstevel@tonic-gate * 10117c478bd9Sstevel@tonic-gate */ 10127c478bd9Sstevel@tonic-gate 10137c478bd9Sstevel@tonic-gate /* 10147c478bd9Sstevel@tonic-gate * Data types and structures for scanning the pw_gecos field. 10157c478bd9Sstevel@tonic-gate */ 10167c478bd9Sstevel@tonic-gate typedef enum gecos_state { 10177c478bd9Sstevel@tonic-gate S0, /* start */ 10187c478bd9Sstevel@tonic-gate S1, /* in a word */ 10197c478bd9Sstevel@tonic-gate S2, /* not in a word */ 10207c478bd9Sstevel@tonic-gate S3, /* copy login */ 10217c478bd9Sstevel@tonic-gate S4 /* end of gecos */ 10227c478bd9Sstevel@tonic-gate } gecos_state_t; 10237c478bd9Sstevel@tonic-gate 10247c478bd9Sstevel@tonic-gate #define GFSM_ROWS 5 10257c478bd9Sstevel@tonic-gate #define GFSM_COLS 10 10267c478bd9Sstevel@tonic-gate 10277c478bd9Sstevel@tonic-gate gecos_state_t gecos_fsm[GFSM_ROWS][GFSM_COLS] = { 10287c478bd9Sstevel@tonic-gate {S0, S4, S3, S1, S1, S0, S1, S2, S4, S0}, /* S0 */ 10297c478bd9Sstevel@tonic-gate {S2, S4, S3, S1, S1, S2, S1, S2, S4, S2}, /* S1 */ 10307c478bd9Sstevel@tonic-gate {S2, S4, S3, S1, S1, S2, S2, S2, S4, S2}, /* S2 */ 10317c478bd9Sstevel@tonic-gate {S2, S4, S2, S1, S1, S2, S1, S2, S4, S2}, /* S3 */ 10327c478bd9Sstevel@tonic-gate {S4, S4, S4, S4, S4, S4, S4, S4, S4, S4} /* S4 */ 10337c478bd9Sstevel@tonic-gate }; 10347c478bd9Sstevel@tonic-gate 10357c478bd9Sstevel@tonic-gate /* 10367c478bd9Sstevel@tonic-gate * Scan the pw_gecos field according to defined state table; 10377c478bd9Sstevel@tonic-gate * return the next state according the the rules. 10387c478bd9Sstevel@tonic-gate */ 10397c478bd9Sstevel@tonic-gate gecos_state_t 10407c478bd9Sstevel@tonic-gate gecos_scan_state(gecos_state_t instate, char ch) 10417c478bd9Sstevel@tonic-gate { 10427c478bd9Sstevel@tonic-gate if (ch == gecos_ignore_c) { 10437c478bd9Sstevel@tonic-gate return (gecos_fsm[instate][0]); 10447c478bd9Sstevel@tonic-gate } else if (ch == gecos_sep_c) { 10457c478bd9Sstevel@tonic-gate return (gecos_fsm[instate][1]); 10467c478bd9Sstevel@tonic-gate } else if (ch == gecos_samename) { 10477c478bd9Sstevel@tonic-gate return (gecos_fsm[instate][2]); 10487c478bd9Sstevel@tonic-gate } else if (isalpha(ch)) { 10497c478bd9Sstevel@tonic-gate return (gecos_fsm[instate][3]); 10507c478bd9Sstevel@tonic-gate } else if (isdigit(ch)) { 10517c478bd9Sstevel@tonic-gate return (gecos_fsm[instate][4]); 10527c478bd9Sstevel@tonic-gate } else if (isspace(ch)) { 10537c478bd9Sstevel@tonic-gate return (gecos_fsm[instate][5]); 10547c478bd9Sstevel@tonic-gate } else if (ch == '.' || ch == '-' || ch == '_') { 10557c478bd9Sstevel@tonic-gate return (gecos_fsm[instate][6]); 10567c478bd9Sstevel@tonic-gate } else if (ispunct(ch)) { 10577c478bd9Sstevel@tonic-gate return (gecos_fsm[instate][7]); 10587c478bd9Sstevel@tonic-gate } else if (ch == '\0') { 10597c478bd9Sstevel@tonic-gate return (gecos_fsm[instate][8]); 10607c478bd9Sstevel@tonic-gate } 10617c478bd9Sstevel@tonic-gate return (gecos_fsm[instate][9]); 10627c478bd9Sstevel@tonic-gate } 10637c478bd9Sstevel@tonic-gate 10647c478bd9Sstevel@tonic-gate 10657c478bd9Sstevel@tonic-gate /* 10667c478bd9Sstevel@tonic-gate * Compare the given argument, which is taken to be a username, with 10677c478bd9Sstevel@tonic-gate * the login name and with strings in the the pw_gecos field. 10687c478bd9Sstevel@tonic-gate */ 10697c478bd9Sstevel@tonic-gate int 10707c478bd9Sstevel@tonic-gate matchcmp(char *gname, char *login, char *given) 10717c478bd9Sstevel@tonic-gate { 10727c478bd9Sstevel@tonic-gate char buffer[100]; 10737c478bd9Sstevel@tonic-gate char *bp, *lp, *gp; 10747c478bd9Sstevel@tonic-gate 10757c478bd9Sstevel@tonic-gate gecos_state_t kstate = S0; 10767c478bd9Sstevel@tonic-gate gecos_state_t kstate_next = S0; 10777c478bd9Sstevel@tonic-gate 10787c478bd9Sstevel@tonic-gate if (*gname == '\0' && *given == '\0') 10797c478bd9Sstevel@tonic-gate return (1); 10807c478bd9Sstevel@tonic-gate 10817c478bd9Sstevel@tonic-gate bp = buffer; 10827c478bd9Sstevel@tonic-gate gp = gname; 10837c478bd9Sstevel@tonic-gate 10847c478bd9Sstevel@tonic-gate do { 10857c478bd9Sstevel@tonic-gate kstate_next = gecos_scan_state(kstate, *gp); 10867c478bd9Sstevel@tonic-gate 10877c478bd9Sstevel@tonic-gate switch (kstate_next) { 10887c478bd9Sstevel@tonic-gate 10897c478bd9Sstevel@tonic-gate case S0: 10907c478bd9Sstevel@tonic-gate gp++; 10917c478bd9Sstevel@tonic-gate break; 10927c478bd9Sstevel@tonic-gate case S1: 10937c478bd9Sstevel@tonic-gate if (bp < buffer + sizeof (buffer)) { 10947c478bd9Sstevel@tonic-gate *bp++ = *gp++; 10957c478bd9Sstevel@tonic-gate } 10967c478bd9Sstevel@tonic-gate break; 10977c478bd9Sstevel@tonic-gate case S2: 10987c478bd9Sstevel@tonic-gate if (kstate == S1 || kstate == S3) { 10997c478bd9Sstevel@tonic-gate *bp++ = ' '; 11007c478bd9Sstevel@tonic-gate } 11017c478bd9Sstevel@tonic-gate gp++; 11027c478bd9Sstevel@tonic-gate break; 11037c478bd9Sstevel@tonic-gate case S3: 11047c478bd9Sstevel@tonic-gate lp = login; 11057c478bd9Sstevel@tonic-gate do { 11067c478bd9Sstevel@tonic-gate *bp++ = *lp++; 11077c478bd9Sstevel@tonic-gate } while (*bp != '\0' && bp < buffer + sizeof (buffer)); 11087c478bd9Sstevel@tonic-gate bp--; 11097c478bd9Sstevel@tonic-gate break; 11107c478bd9Sstevel@tonic-gate case S4: 11117c478bd9Sstevel@tonic-gate *bp++ = '\0'; 11127c478bd9Sstevel@tonic-gate break; 11137c478bd9Sstevel@tonic-gate default: 11147c478bd9Sstevel@tonic-gate *bp++ = '\0'; 11157c478bd9Sstevel@tonic-gate break; 11167c478bd9Sstevel@tonic-gate } 11177c478bd9Sstevel@tonic-gate kstate = kstate_next; 11187c478bd9Sstevel@tonic-gate 11197c478bd9Sstevel@tonic-gate } while ((bp < buffer + sizeof (buffer)) && kstate != S4); 11207c478bd9Sstevel@tonic-gate 11217c478bd9Sstevel@tonic-gate gp = strtok(buffer, " "); 11227c478bd9Sstevel@tonic-gate 11237c478bd9Sstevel@tonic-gate while (gp != NULL) { 11247c478bd9Sstevel@tonic-gate if (namecmp(gp, given) > 0) { 11257c478bd9Sstevel@tonic-gate return (1); 11267c478bd9Sstevel@tonic-gate } 11277c478bd9Sstevel@tonic-gate gp = strtok(NULL, " "); 11287c478bd9Sstevel@tonic-gate } 11297c478bd9Sstevel@tonic-gate return (0); 11307c478bd9Sstevel@tonic-gate } 11317c478bd9Sstevel@tonic-gate 11327c478bd9Sstevel@tonic-gate /* 11337c478bd9Sstevel@tonic-gate * Perform the character-by-character comparison. 11347c478bd9Sstevel@tonic-gate * It is intended that "finger foo" should match "foo2", but an argument 11357c478bd9Sstevel@tonic-gate * consisting entirely of digits should not be matched too broadly. 11367c478bd9Sstevel@tonic-gate * Also, we do not want "finger foo123" to match "Mr. Foo" in the gecos. 11377c478bd9Sstevel@tonic-gate */ 11387c478bd9Sstevel@tonic-gate int 11397c478bd9Sstevel@tonic-gate namecmp(char *name1, char *name2) 11407c478bd9Sstevel@tonic-gate { 11417c478bd9Sstevel@tonic-gate char c1, c2; 11427c478bd9Sstevel@tonic-gate boolean_t alphaseen = B_FALSE; 11437c478bd9Sstevel@tonic-gate boolean_t digitseen = B_FALSE; 11447c478bd9Sstevel@tonic-gate 11457c478bd9Sstevel@tonic-gate for (;;) { 11467c478bd9Sstevel@tonic-gate c1 = *name1++; 11477c478bd9Sstevel@tonic-gate if (isalpha(c1)) 11487c478bd9Sstevel@tonic-gate alphaseen = B_TRUE; 11497c478bd9Sstevel@tonic-gate if (isdigit(c1)) 11507c478bd9Sstevel@tonic-gate digitseen = B_TRUE; 11517c478bd9Sstevel@tonic-gate if (isupper(c1)) 11527c478bd9Sstevel@tonic-gate c1 = tolower(c1); 11537c478bd9Sstevel@tonic-gate 11547c478bd9Sstevel@tonic-gate c2 = *name2++; 11557c478bd9Sstevel@tonic-gate if (isupper(c2)) 11567c478bd9Sstevel@tonic-gate c2 = tolower(c2); 11577c478bd9Sstevel@tonic-gate 11587c478bd9Sstevel@tonic-gate if (c1 != c2) 11597c478bd9Sstevel@tonic-gate break; 11607c478bd9Sstevel@tonic-gate if (c1 == '\0') 11617c478bd9Sstevel@tonic-gate return (1); 11627c478bd9Sstevel@tonic-gate } 11637c478bd9Sstevel@tonic-gate if (!c1) { 11647c478bd9Sstevel@tonic-gate for (name2--; isdigit(*name2); name2++) 11657c478bd9Sstevel@tonic-gate ; 11667c478bd9Sstevel@tonic-gate if (*name2 == '\0' && digitseen) { 11677c478bd9Sstevel@tonic-gate return (1); 11687c478bd9Sstevel@tonic-gate } 11697c478bd9Sstevel@tonic-gate } else if (!c2) { 11707c478bd9Sstevel@tonic-gate for (name1--; isdigit(*name1); name1++) 11717c478bd9Sstevel@tonic-gate ; 11727c478bd9Sstevel@tonic-gate if (*name1 == '\0' && alphaseen) { 11737c478bd9Sstevel@tonic-gate return (1); 11747c478bd9Sstevel@tonic-gate } 11757c478bd9Sstevel@tonic-gate } 11767c478bd9Sstevel@tonic-gate return (0); 11777c478bd9Sstevel@tonic-gate } 11787c478bd9Sstevel@tonic-gate 11797c478bd9Sstevel@tonic-gate 11807c478bd9Sstevel@tonic-gate int 11817c478bd9Sstevel@tonic-gate netfinger(char *name) 11827c478bd9Sstevel@tonic-gate { 11837c478bd9Sstevel@tonic-gate char *host; 11847c478bd9Sstevel@tonic-gate struct hostent *hp; 11857c478bd9Sstevel@tonic-gate struct sockaddr_in6 sin6; 11867c478bd9Sstevel@tonic-gate struct in6_addr ipv6addr; 11877c478bd9Sstevel@tonic-gate struct in_addr ipv4addr; 11887c478bd9Sstevel@tonic-gate int s; 11897c478bd9Sstevel@tonic-gate FILE *f; 11907c478bd9Sstevel@tonic-gate int c; 11917c478bd9Sstevel@tonic-gate int lastc; 11927c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 11937c478bd9Sstevel@tonic-gate int error_num; 11947c478bd9Sstevel@tonic-gate 11957c478bd9Sstevel@tonic-gate if (name == NULL) 11967c478bd9Sstevel@tonic-gate return (0); 11977c478bd9Sstevel@tonic-gate host = strrchr(name, '@'); 11987c478bd9Sstevel@tonic-gate if (host == NULL) 11997c478bd9Sstevel@tonic-gate return (0); 12007c478bd9Sstevel@tonic-gate *host++ = 0; 12017c478bd9Sstevel@tonic-gate 12027c478bd9Sstevel@tonic-gate if ((hp = getipnodebyname(host, AF_INET6, AI_ALL | AI_ADDRCONFIG | 12037c478bd9Sstevel@tonic-gate AI_V4MAPPED, &error_num)) == NULL) { 12047c478bd9Sstevel@tonic-gate if (error_num == TRY_AGAIN) { 12057c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 12067c478bd9Sstevel@tonic-gate "unknown host: %s (try again later)\n", host); 12077c478bd9Sstevel@tonic-gate } else { 12087c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "unknown host: %s\n", host); 12097c478bd9Sstevel@tonic-gate } 12107c478bd9Sstevel@tonic-gate return (1); 12117c478bd9Sstevel@tonic-gate } 12127c478bd9Sstevel@tonic-gate 12137c478bd9Sstevel@tonic-gate /* 12147c478bd9Sstevel@tonic-gate * If hp->h_name is a IPv4-mapped IPv6 literal, we'll convert it to 12157c478bd9Sstevel@tonic-gate * IPv4 literal address. 12167c478bd9Sstevel@tonic-gate */ 12177c478bd9Sstevel@tonic-gate if ((inet_pton(AF_INET6, hp->h_name, &ipv6addr) > 0) && 12187c478bd9Sstevel@tonic-gate IN6_IS_ADDR_V4MAPPED(&ipv6addr)) { 12197c478bd9Sstevel@tonic-gate IN6_V4MAPPED_TO_INADDR(&ipv6addr, &ipv4addr); 12207c478bd9Sstevel@tonic-gate (void) printf("[%s] ", inet_ntop(AF_INET, &ipv4addr, abuf, 12217c478bd9Sstevel@tonic-gate sizeof (abuf))); 12227c478bd9Sstevel@tonic-gate } else { 12237c478bd9Sstevel@tonic-gate (void) printf("[%s] ", hp->h_name); 12247c478bd9Sstevel@tonic-gate } 12257c478bd9Sstevel@tonic-gate bzero(&sin6, sizeof (sin6)); 12267c478bd9Sstevel@tonic-gate sin6.sin6_family = hp->h_addrtype; 12277c478bd9Sstevel@tonic-gate bcopy(hp->h_addr_list[0], (char *)&sin6.sin6_addr, hp->h_length); 12287c478bd9Sstevel@tonic-gate sin6.sin6_port = htons(IPPORT_FINGER); 12297c478bd9Sstevel@tonic-gate s = socket(sin6.sin6_family, SOCK_STREAM, 0); 12307c478bd9Sstevel@tonic-gate if (s < 0) { 12317c478bd9Sstevel@tonic-gate (void) fflush(stdout); 12327c478bd9Sstevel@tonic-gate perror("socket"); 12337c478bd9Sstevel@tonic-gate freehostent(hp); 12347c478bd9Sstevel@tonic-gate return (1); 12357c478bd9Sstevel@tonic-gate } 12367c478bd9Sstevel@tonic-gate while (connect(s, (struct sockaddr *)&sin6, sizeof (sin6)) < 0) { 12377c478bd9Sstevel@tonic-gate 12387c478bd9Sstevel@tonic-gate if (hp && hp->h_addr_list[1]) { 12397c478bd9Sstevel@tonic-gate 12407c478bd9Sstevel@tonic-gate hp->h_addr_list++; 12417c478bd9Sstevel@tonic-gate bcopy(hp->h_addr_list[0], 12427c478bd9Sstevel@tonic-gate (caddr_t)&sin6.sin6_addr, hp->h_length); 12437c478bd9Sstevel@tonic-gate (void) close(s); 12447c478bd9Sstevel@tonic-gate s = socket(sin6.sin6_family, SOCK_STREAM, 0); 12457c478bd9Sstevel@tonic-gate if (s < 0) { 12467c478bd9Sstevel@tonic-gate (void) fflush(stdout); 12477c478bd9Sstevel@tonic-gate perror("socket"); 12487c478bd9Sstevel@tonic-gate freehostent(hp); 12497c478bd9Sstevel@tonic-gate return (0); 12507c478bd9Sstevel@tonic-gate } 12517c478bd9Sstevel@tonic-gate continue; 12527c478bd9Sstevel@tonic-gate } 12537c478bd9Sstevel@tonic-gate 12547c478bd9Sstevel@tonic-gate (void) fflush(stdout); 12557c478bd9Sstevel@tonic-gate perror("connect"); 12567c478bd9Sstevel@tonic-gate (void) close(s); 12577c478bd9Sstevel@tonic-gate freehostent(hp); 12587c478bd9Sstevel@tonic-gate return (1); 12597c478bd9Sstevel@tonic-gate } 12607c478bd9Sstevel@tonic-gate freehostent(hp); 12617c478bd9Sstevel@tonic-gate hp = NULL; 12627c478bd9Sstevel@tonic-gate 12637c478bd9Sstevel@tonic-gate (void) printf("\n"); 12647c478bd9Sstevel@tonic-gate if (large) 12657c478bd9Sstevel@tonic-gate (void) write(s, "/W ", 3); 12667c478bd9Sstevel@tonic-gate (void) write(s, name, strlen(name)); 12677c478bd9Sstevel@tonic-gate (void) write(s, "\r\n", 2); 12687c478bd9Sstevel@tonic-gate f = fdopen(s, "r"); 12697c478bd9Sstevel@tonic-gate 12707c478bd9Sstevel@tonic-gate lastc = '\n'; 12717c478bd9Sstevel@tonic-gate while ((c = getc(f)) != EOF) { 12727c478bd9Sstevel@tonic-gate /* map CRLF -> newline */ 12737c478bd9Sstevel@tonic-gate if ((lastc == '\r') && (c != '\n')) 12747c478bd9Sstevel@tonic-gate /* print out saved CR */ 12757c478bd9Sstevel@tonic-gate (void) putchar('\r'); 12767c478bd9Sstevel@tonic-gate lastc = c; 12777c478bd9Sstevel@tonic-gate if (c == '\r') 12787c478bd9Sstevel@tonic-gate continue; 12797c478bd9Sstevel@tonic-gate (void) putchar(c); 12807c478bd9Sstevel@tonic-gate } 12817c478bd9Sstevel@tonic-gate 12827c478bd9Sstevel@tonic-gate if (lastc != '\n') 12837c478bd9Sstevel@tonic-gate (void) putchar('\n'); 12847c478bd9Sstevel@tonic-gate (void) fclose(f); 12857c478bd9Sstevel@tonic-gate return (1); 12867c478bd9Sstevel@tonic-gate } 12877c478bd9Sstevel@tonic-gate 12887c478bd9Sstevel@tonic-gate /* 12897c478bd9Sstevel@tonic-gate * AnyMail - takes a username (string pointer thereto), and 12907c478bd9Sstevel@tonic-gate * prints on standard output whether there is any unread mail, 12917c478bd9Sstevel@tonic-gate * and if so, how old it is. (JCM@Shasta 15 March 80) 12927c478bd9Sstevel@tonic-gate */ 12937c478bd9Sstevel@tonic-gate void 12947c478bd9Sstevel@tonic-gate AnyMail(char *name) 12957c478bd9Sstevel@tonic-gate { 12967c478bd9Sstevel@tonic-gate struct stat buf; /* space for file status buffer */ 12977c478bd9Sstevel@tonic-gate char *mbxdir = MAILDIR; /* string with path preamble */ 12987c478bd9Sstevel@tonic-gate char *mbxpath; /* space for entire pathname */ 12997c478bd9Sstevel@tonic-gate 13007c478bd9Sstevel@tonic-gate char *timestr; 13017c478bd9Sstevel@tonic-gate 13027c478bd9Sstevel@tonic-gate mbxpath = malloc(strlen(name) + strlen(MAILDIR) + 1); 13037a59e0bfSDavid Edmondson if (mbxpath == NULL) 13047c478bd9Sstevel@tonic-gate return; 13057c478bd9Sstevel@tonic-gate 13067c478bd9Sstevel@tonic-gate (void) strcpy(mbxpath, mbxdir); /* copy preamble into path name */ 13077c478bd9Sstevel@tonic-gate (void) strcat(mbxpath, name); /* concatenate user name to path */ 13087c478bd9Sstevel@tonic-gate 13097c478bd9Sstevel@tonic-gate if (stat(mbxpath, &buf) == -1 || buf.st_size == 0) { 13107c478bd9Sstevel@tonic-gate /* Mailbox is empty or nonexistent */ 13117c478bd9Sstevel@tonic-gate (void) printf("No unread mail\n"); 13127c478bd9Sstevel@tonic-gate } else { 13137c478bd9Sstevel@tonic-gate if (buf.st_mtime < buf.st_atime) { 13147c478bd9Sstevel@tonic-gate /* 13157c478bd9Sstevel@tonic-gate * No new mail since the last time the user read it. 13167c478bd9Sstevel@tonic-gate */ 13177c478bd9Sstevel@tonic-gate (void) printf("Mail last read "); 13187c478bd9Sstevel@tonic-gate (void) printf("%s", ctime(&buf.st_atime)); 13197c478bd9Sstevel@tonic-gate } else if (buf.st_mtime > buf.st_atime) { 13207c478bd9Sstevel@tonic-gate /* 13217c478bd9Sstevel@tonic-gate * New mail has definitely arrived since the last time 13227c478bd9Sstevel@tonic-gate * mail was read. mtime is the time the most recent 13237c478bd9Sstevel@tonic-gate * message arrived; atime is either the time the oldest 13247c478bd9Sstevel@tonic-gate * unread message arrived, or the last time the mail 13257c478bd9Sstevel@tonic-gate * was read. 13267c478bd9Sstevel@tonic-gate */ 13277c478bd9Sstevel@tonic-gate (void) printf("New mail received "); 13287c478bd9Sstevel@tonic-gate timestr = ctime(&buf.st_mtime); /* time last modified */ 13297c478bd9Sstevel@tonic-gate timestr[24] = '\0'; /* suppress newline (ugh) */ 13307c478bd9Sstevel@tonic-gate (void) printf("%s", timestr); 13317c478bd9Sstevel@tonic-gate (void) printf(";\n unread since "); 13327c478bd9Sstevel@tonic-gate (void) printf("%s", ctime(&buf.st_atime)); 13337c478bd9Sstevel@tonic-gate } else { 13347c478bd9Sstevel@tonic-gate /* 13357c478bd9Sstevel@tonic-gate * There is something in mailbox, but we can't really 13367c478bd9Sstevel@tonic-gate * be sure whether it is mail held there by the user 13377c478bd9Sstevel@tonic-gate * or a (single) new message that was placed in a newly 13387c478bd9Sstevel@tonic-gate * recreated mailbox, so punt and call it "unread mail." 13397c478bd9Sstevel@tonic-gate */ 13407c478bd9Sstevel@tonic-gate (void) printf("Unread mail since "); 13417c478bd9Sstevel@tonic-gate (void) printf("%s", ctime(&buf.st_mtime)); 13427c478bd9Sstevel@tonic-gate } 13437c478bd9Sstevel@tonic-gate } 13447c478bd9Sstevel@tonic-gate free(mbxpath); 13457c478bd9Sstevel@tonic-gate } 13467c478bd9Sstevel@tonic-gate 13477c478bd9Sstevel@tonic-gate /* 13487c478bd9Sstevel@tonic-gate * return true iff we've already printed project/plan for this uid; 13497c478bd9Sstevel@tonic-gate * if not, enter this uid into table (so this function has a side-effect.) 13507c478bd9Sstevel@tonic-gate */ 13517c478bd9Sstevel@tonic-gate #define PPMAX 4096 /* assume no more than 4096 logged-in users */ 13527c478bd9Sstevel@tonic-gate uid_t PlanPrinted[PPMAX+1]; 13537c478bd9Sstevel@tonic-gate int PPIndex = 0; /* index of next unused table entry */ 13547c478bd9Sstevel@tonic-gate 13557c478bd9Sstevel@tonic-gate int 13567c478bd9Sstevel@tonic-gate AlreadyPrinted(uid_t uid) 13577c478bd9Sstevel@tonic-gate { 13587c478bd9Sstevel@tonic-gate int i = 0; 13597c478bd9Sstevel@tonic-gate 13607c478bd9Sstevel@tonic-gate while (i++ < PPIndex) { 13617c478bd9Sstevel@tonic-gate if (PlanPrinted[i] == uid) 13627c478bd9Sstevel@tonic-gate return (1); 13637c478bd9Sstevel@tonic-gate } 13647c478bd9Sstevel@tonic-gate if (i < PPMAX) { 13657c478bd9Sstevel@tonic-gate PlanPrinted[i] = uid; 13667c478bd9Sstevel@tonic-gate PPIndex++; 13677c478bd9Sstevel@tonic-gate } 13687c478bd9Sstevel@tonic-gate return (0); 13697c478bd9Sstevel@tonic-gate } 13707c478bd9Sstevel@tonic-gate 13717c478bd9Sstevel@tonic-gate #define FIFOREADTIMEOUT (60) /* read timeout on select */ 13727c478bd9Sstevel@tonic-gate /* BEGIN CSTYLED */ 13737c478bd9Sstevel@tonic-gate #define PRINT_CHAR(c) \ 13747c478bd9Sstevel@tonic-gate ( \ 13757c478bd9Sstevel@tonic-gate ((termpass & TS_HIGH) && ((int)c) > 126) \ 13767c478bd9Sstevel@tonic-gate || \ 13777c478bd9Sstevel@tonic-gate (isascii((int)c) && \ 13787c478bd9Sstevel@tonic-gate (isprint((int)c) || isspace((int)c)) \ 13797c478bd9Sstevel@tonic-gate ) \ 13807c478bd9Sstevel@tonic-gate || \ 13817c478bd9Sstevel@tonic-gate ((termpass & TS_LOW) && ((int)c) < 32) \ 13827c478bd9Sstevel@tonic-gate ) 13837c478bd9Sstevel@tonic-gate /* END CSTYLED */ 13847c478bd9Sstevel@tonic-gate 13857c478bd9Sstevel@tonic-gate 13867c478bd9Sstevel@tonic-gate void 13877c478bd9Sstevel@tonic-gate catfile(char *s, mode_t mode, int trunc_at_nl) 13887c478bd9Sstevel@tonic-gate { 13897c478bd9Sstevel@tonic-gate if (S_ISFIFO(mode)) { 13907c478bd9Sstevel@tonic-gate int fd; 13917c478bd9Sstevel@tonic-gate 13927c478bd9Sstevel@tonic-gate fd = open(s, O_RDONLY | O_NONBLOCK); 13937c478bd9Sstevel@tonic-gate if (fd != -1) { 13947c478bd9Sstevel@tonic-gate fd_set readfds, exceptfds; 13957c478bd9Sstevel@tonic-gate struct timeval tv; 13967c478bd9Sstevel@tonic-gate 13977c478bd9Sstevel@tonic-gate FD_ZERO(&readfds); 13987c478bd9Sstevel@tonic-gate FD_ZERO(&exceptfds); 13997c478bd9Sstevel@tonic-gate FD_SET(fd, &readfds); 14007c478bd9Sstevel@tonic-gate FD_SET(fd, &exceptfds); 14017c478bd9Sstevel@tonic-gate 14027c478bd9Sstevel@tonic-gate timerclear(&tv); 14037c478bd9Sstevel@tonic-gate tv.tv_sec = FIFOREADTIMEOUT; 14047c478bd9Sstevel@tonic-gate 14057c478bd9Sstevel@tonic-gate (void) fflush(stdout); 14067c478bd9Sstevel@tonic-gate while (select(fd + 1, &readfds, (fd_set *) 0, 14077c478bd9Sstevel@tonic-gate &exceptfds, &tv) != -1) { 14087c478bd9Sstevel@tonic-gate unsigned char buf[BUFSIZ]; 14097c478bd9Sstevel@tonic-gate int nread; 14107c478bd9Sstevel@tonic-gate 14117c478bd9Sstevel@tonic-gate nread = read(fd, buf, sizeof (buf)); 14127c478bd9Sstevel@tonic-gate if (nread > 0) { 14137c478bd9Sstevel@tonic-gate unsigned char *p; 14147c478bd9Sstevel@tonic-gate 14157c478bd9Sstevel@tonic-gate FD_SET(fd, &readfds); 14167c478bd9Sstevel@tonic-gate FD_SET(fd, &exceptfds); 14177c478bd9Sstevel@tonic-gate for (p = buf; p < buf + nread; p++) { 14187c478bd9Sstevel@tonic-gate if (trunc_at_nl && *p == '\n') 14197c478bd9Sstevel@tonic-gate goto out; 14207c478bd9Sstevel@tonic-gate if (PRINT_CHAR(*p)) 14217c478bd9Sstevel@tonic-gate (void) putchar((int)*p); 14227c478bd9Sstevel@tonic-gate else if (isascii(*p)) 14237c478bd9Sstevel@tonic-gate (void) fputs(unctrl(*p), 14247c478bd9Sstevel@tonic-gate stdout); 14257c478bd9Sstevel@tonic-gate } 14267c478bd9Sstevel@tonic-gate } else 14277c478bd9Sstevel@tonic-gate break; 14287c478bd9Sstevel@tonic-gate } 14297c478bd9Sstevel@tonic-gate out: 14307c478bd9Sstevel@tonic-gate (void) close(fd); 14317c478bd9Sstevel@tonic-gate } 14327c478bd9Sstevel@tonic-gate } else { 14337c478bd9Sstevel@tonic-gate int c; 14347c478bd9Sstevel@tonic-gate FILE *fp; 14357c478bd9Sstevel@tonic-gate 14367c478bd9Sstevel@tonic-gate fp = fopen(s, "r"); 14377c478bd9Sstevel@tonic-gate if (fp) { 14387c478bd9Sstevel@tonic-gate while ((c = getc(fp)) != EOF) { 14397c478bd9Sstevel@tonic-gate if (trunc_at_nl && c == '\n') 14407c478bd9Sstevel@tonic-gate break; 14417c478bd9Sstevel@tonic-gate if (PRINT_CHAR(c)) 14427c478bd9Sstevel@tonic-gate (void) putchar((int)c); 14437c478bd9Sstevel@tonic-gate else 14447c478bd9Sstevel@tonic-gate if (isascii(c)) 14457c478bd9Sstevel@tonic-gate (void) fputs(unctrl(c), stdout); 14467c478bd9Sstevel@tonic-gate } 14477c478bd9Sstevel@tonic-gate (void) fclose(fp); 14487c478bd9Sstevel@tonic-gate } 14497c478bd9Sstevel@tonic-gate } 14507c478bd9Sstevel@tonic-gate } 14517c478bd9Sstevel@tonic-gate 14527c478bd9Sstevel@tonic-gate 14537c478bd9Sstevel@tonic-gate void 14547c478bd9Sstevel@tonic-gate initscreening(void) 14557c478bd9Sstevel@tonic-gate { 14567c478bd9Sstevel@tonic-gate char *options, *value; 14577c478bd9Sstevel@tonic-gate 14587c478bd9Sstevel@tonic-gate if (defopen(defaultfile) == 0) { 14597c478bd9Sstevel@tonic-gate char *cp; 14607c478bd9Sstevel@tonic-gate int flags; 14617c478bd9Sstevel@tonic-gate 14627c478bd9Sstevel@tonic-gate /* 14637c478bd9Sstevel@tonic-gate * ignore case 14647c478bd9Sstevel@tonic-gate */ 14657c478bd9Sstevel@tonic-gate flags = defcntl(DC_GETFLAGS, 0); 14667c478bd9Sstevel@tonic-gate TURNOFF(flags, DC_CASE); 146706e1a714Sraf (void) defcntl(DC_SETFLAGS, flags); 14687c478bd9Sstevel@tonic-gate 14697c478bd9Sstevel@tonic-gate if (cp = defread(passvar)) { 14707c478bd9Sstevel@tonic-gate options = cp; 14717c478bd9Sstevel@tonic-gate while (*options != '\0') 14727c478bd9Sstevel@tonic-gate switch (getsubopt(&options, termopts, &value)) { 14737c478bd9Sstevel@tonic-gate case TERM_LOW: 14747c478bd9Sstevel@tonic-gate termpass |= TS_LOW; 14757c478bd9Sstevel@tonic-gate break; 14767c478bd9Sstevel@tonic-gate case TERM_HIGH: 14777c478bd9Sstevel@tonic-gate termpass |= TS_HIGH; 14787c478bd9Sstevel@tonic-gate break; 14797c478bd9Sstevel@tonic-gate } 14807c478bd9Sstevel@tonic-gate } 14817c478bd9Sstevel@tonic-gate (void) defopen(NULL); /* close default file */ 14827c478bd9Sstevel@tonic-gate } 14837c478bd9Sstevel@tonic-gate } 14847a59e0bfSDavid Edmondson 14857a59e0bfSDavid Edmondson int 14867a59e0bfSDavid Edmondson person_compare(const void *p1, const void *p2) 14877a59e0bfSDavid Edmondson { 14887a59e0bfSDavid Edmondson const struct person *pp1 = *(struct person **)p1; 14897a59e0bfSDavid Edmondson const struct person *pp2 = *(struct person **)p2; 14907a59e0bfSDavid Edmondson int r; 14917a59e0bfSDavid Edmondson 14927a59e0bfSDavid Edmondson /* 14937a59e0bfSDavid Edmondson * Sort by username. 14947a59e0bfSDavid Edmondson */ 14957a59e0bfSDavid Edmondson r = strcmp(pp1->name, pp2->name); 14967a59e0bfSDavid Edmondson 14977a59e0bfSDavid Edmondson if (r != 0) 14987a59e0bfSDavid Edmondson return (r); 14997a59e0bfSDavid Edmondson 15007a59e0bfSDavid Edmondson /* 15017a59e0bfSDavid Edmondson * If usernames are the same, sort by idle time. 15027a59e0bfSDavid Edmondson */ 15037a59e0bfSDavid Edmondson r = pp1->idletime - pp2->idletime; 15047a59e0bfSDavid Edmondson 15057a59e0bfSDavid Edmondson return (r); 15067a59e0bfSDavid Edmondson } 15077a59e0bfSDavid Edmondson 15087a59e0bfSDavid Edmondson void 15097a59e0bfSDavid Edmondson sort_by_username() 15107a59e0bfSDavid Edmondson { 15117a59e0bfSDavid Edmondson struct person **sortable, *loop; 15127a59e0bfSDavid Edmondson size_t i; 15137a59e0bfSDavid Edmondson 15147a59e0bfSDavid Edmondson sortable = malloc(sizeof (sortable[0]) * nperson); 15157a59e0bfSDavid Edmondson 15167a59e0bfSDavid Edmondson if (sortable == NULL) 15177a59e0bfSDavid Edmondson return; 15187a59e0bfSDavid Edmondson 15197a59e0bfSDavid Edmondson for (i = 0, loop = person1; i < nperson; i++) { 15207a59e0bfSDavid Edmondson struct person *next = loop->link; 15217a59e0bfSDavid Edmondson 15227a59e0bfSDavid Edmondson sortable[i] = loop; 15237a59e0bfSDavid Edmondson loop->link = NULL; 15247a59e0bfSDavid Edmondson 15257a59e0bfSDavid Edmondson loop = next; 15267a59e0bfSDavid Edmondson } 15277a59e0bfSDavid Edmondson 15287a59e0bfSDavid Edmondson qsort(sortable, nperson, sizeof (sortable[0]), person_compare); 15297a59e0bfSDavid Edmondson 15307a59e0bfSDavid Edmondson for (i = 1; i < nperson; i++) 15317a59e0bfSDavid Edmondson sortable[i-1]->link = sortable[i]; 15327a59e0bfSDavid Edmondson person1 = sortable[0]; 15337a59e0bfSDavid Edmondson 15347a59e0bfSDavid Edmondson free(sortable); 15357a59e0bfSDavid Edmondson } 1536