1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 28*7c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 29*7c478bd9Sstevel@tonic-gate 30*7c478bd9Sstevel@tonic-gate /* 31*7c478bd9Sstevel@tonic-gate * Copyright (c) 1982, 1986, 1988 32*7c478bd9Sstevel@tonic-gate * The Regents of the University of California 33*7c478bd9Sstevel@tonic-gate * All Rights Reserved 34*7c478bd9Sstevel@tonic-gate * 35*7c478bd9Sstevel@tonic-gate * Portions of this document are derived from 36*7c478bd9Sstevel@tonic-gate * software developed by the University of California, Berkeley, and its 37*7c478bd9Sstevel@tonic-gate * contributors. 38*7c478bd9Sstevel@tonic-gate */ 39*7c478bd9Sstevel@tonic-gate 40*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 41*7c478bd9Sstevel@tonic-gate 42*7c478bd9Sstevel@tonic-gate /* 43*7c478bd9Sstevel@tonic-gate * This is a finger program. It prints out useful information about users 44*7c478bd9Sstevel@tonic-gate * by digging it up from various system files. 45*7c478bd9Sstevel@tonic-gate * 46*7c478bd9Sstevel@tonic-gate * There are three output formats, all of which give login name, teletype 47*7c478bd9Sstevel@tonic-gate * line number, and login time. The short output format is reminiscent 48*7c478bd9Sstevel@tonic-gate * of finger on ITS, and gives one line of information per user containing 49*7c478bd9Sstevel@tonic-gate * in addition to the minimum basic requirements (MBR), the user's full name, 50*7c478bd9Sstevel@tonic-gate * idle time and location. 51*7c478bd9Sstevel@tonic-gate * The quick style output is UNIX who-like, giving only name, teletype and 52*7c478bd9Sstevel@tonic-gate * login time. Finally, the long style output give the same information 53*7c478bd9Sstevel@tonic-gate * as the short (in more legible format), the home directory and shell 54*7c478bd9Sstevel@tonic-gate * of the user, and, if it exits, a copy of the file .plan in the users 55*7c478bd9Sstevel@tonic-gate * home directory. Finger may be called with or without a list of people 56*7c478bd9Sstevel@tonic-gate * to finger -- if no list is given, all the people currently logged in 57*7c478bd9Sstevel@tonic-gate * are fingered. 58*7c478bd9Sstevel@tonic-gate * 59*7c478bd9Sstevel@tonic-gate * The program is validly called by one of the following: 60*7c478bd9Sstevel@tonic-gate * 61*7c478bd9Sstevel@tonic-gate * finger {short form list of users} 62*7c478bd9Sstevel@tonic-gate * finger -l {long form list of users} 63*7c478bd9Sstevel@tonic-gate * finger -b {briefer long form list of users} 64*7c478bd9Sstevel@tonic-gate * finger -q {quick list of users} 65*7c478bd9Sstevel@tonic-gate * finger -i {quick list of users with idle times} 66*7c478bd9Sstevel@tonic-gate * finger -m {matches arguments against only username} 67*7c478bd9Sstevel@tonic-gate * finger -f {suppress header in non-long form} 68*7c478bd9Sstevel@tonic-gate * finger -p {suppress printing of .plan file} 69*7c478bd9Sstevel@tonic-gate * finger -h {suppress printing of .project file} 70*7c478bd9Sstevel@tonic-gate * finger -i {forces "idle" output format} 71*7c478bd9Sstevel@tonic-gate * finger namelist {long format list of specified users} 72*7c478bd9Sstevel@tonic-gate * finger -s namelist {short format list of specified users} 73*7c478bd9Sstevel@tonic-gate * finger -w namelist {narrow short format list of specified users} 74*7c478bd9Sstevel@tonic-gate * 75*7c478bd9Sstevel@tonic-gate * where 'namelist' is a list of users login names. 76*7c478bd9Sstevel@tonic-gate * The other options can all be given after one '-', or each can have its 77*7c478bd9Sstevel@tonic-gate * own '-'. The -f option disables the printing of headers for short and 78*7c478bd9Sstevel@tonic-gate * quick outputs. The -b option briefens long format outputs. The -p 79*7c478bd9Sstevel@tonic-gate * option turns off plans for long format outputs. 80*7c478bd9Sstevel@tonic-gate */ 81*7c478bd9Sstevel@tonic-gate 82*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 83*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 84*7c478bd9Sstevel@tonic-gate #include <utmpx.h> 85*7c478bd9Sstevel@tonic-gate #include <sys/signal.h> 86*7c478bd9Sstevel@tonic-gate #include <pwd.h> 87*7c478bd9Sstevel@tonic-gate #include <stdio.h> 88*7c478bd9Sstevel@tonic-gate #include <lastlog.h> 89*7c478bd9Sstevel@tonic-gate #include <ctype.h> 90*7c478bd9Sstevel@tonic-gate #include <sys/time.h> 91*7c478bd9Sstevel@tonic-gate #include <time.h> 92*7c478bd9Sstevel@tonic-gate #include <sys/socket.h> 93*7c478bd9Sstevel@tonic-gate #include <netinet/in.h> 94*7c478bd9Sstevel@tonic-gate #include <netdb.h> 95*7c478bd9Sstevel@tonic-gate #include <locale.h> 96*7c478bd9Sstevel@tonic-gate #include <sys/select.h> 97*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 98*7c478bd9Sstevel@tonic-gate #include <strings.h> 99*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 100*7c478bd9Sstevel@tonic-gate #include <curses.h> 101*7c478bd9Sstevel@tonic-gate #include <unctrl.h> 102*7c478bd9Sstevel@tonic-gate #include <maillock.h> 103*7c478bd9Sstevel@tonic-gate #include <deflt.h> 104*7c478bd9Sstevel@tonic-gate #include <unistd.h> 105*7c478bd9Sstevel@tonic-gate #include <arpa/inet.h> 106*7c478bd9Sstevel@tonic-gate #include <macros.h> 107*7c478bd9Sstevel@tonic-gate 108*7c478bd9Sstevel@tonic-gate static char gecos_ignore_c = '*'; /* ignore this in real name */ 109*7c478bd9Sstevel@tonic-gate static char gecos_sep_c = ','; /* separator in pw_gecos field */ 110*7c478bd9Sstevel@tonic-gate static char gecos_samename = '&'; /* repeat login name in real name */ 111*7c478bd9Sstevel@tonic-gate 112*7c478bd9Sstevel@tonic-gate #define TALKABLE 0220 /* tty is writable if this mode */ 113*7c478bd9Sstevel@tonic-gate 114*7c478bd9Sstevel@tonic-gate #define NMAX sizeof (((struct utmpx *)0)->ut_name) 115*7c478bd9Sstevel@tonic-gate #define LMAX sizeof (((struct utmpx *)0)->ut_line) 116*7c478bd9Sstevel@tonic-gate #define HMAX sizeof (((struct utmpx *)0)->ut_host) 117*7c478bd9Sstevel@tonic-gate 118*7c478bd9Sstevel@tonic-gate struct person { /* one for each person fingered */ 119*7c478bd9Sstevel@tonic-gate char *name; /* name */ 120*7c478bd9Sstevel@tonic-gate char tty[LMAX+1]; /* null terminated tty line */ 121*7c478bd9Sstevel@tonic-gate char host[HMAX+1]; /* null terminated remote host name */ 122*7c478bd9Sstevel@tonic-gate char *ttyloc; /* location of tty line, if any */ 123*7c478bd9Sstevel@tonic-gate time_t loginat; /* time of (last) login */ 124*7c478bd9Sstevel@tonic-gate time_t idletime; /* how long idle (if logged in) */ 125*7c478bd9Sstevel@tonic-gate char *realname; /* pointer to full name */ 126*7c478bd9Sstevel@tonic-gate struct passwd *pwd; /* structure of /etc/passwd stuff */ 127*7c478bd9Sstevel@tonic-gate char loggedin; /* person is logged in */ 128*7c478bd9Sstevel@tonic-gate char writable; /* tty is writable */ 129*7c478bd9Sstevel@tonic-gate char original; /* this is not a duplicate entry */ 130*7c478bd9Sstevel@tonic-gate struct person *link; /* link to next person */ 131*7c478bd9Sstevel@tonic-gate }; 132*7c478bd9Sstevel@tonic-gate 133*7c478bd9Sstevel@tonic-gate char LASTLOG[] = "/var/adm/lastlog"; /* last login info */ 134*7c478bd9Sstevel@tonic-gate char PLAN[] = "/.plan"; /* what plan file is */ 135*7c478bd9Sstevel@tonic-gate char PROJ[] = "/.project"; /* what project file */ 136*7c478bd9Sstevel@tonic-gate 137*7c478bd9Sstevel@tonic-gate int unbrief = 1; /* -b option default */ 138*7c478bd9Sstevel@tonic-gate int header = 1; /* -f option default */ 139*7c478bd9Sstevel@tonic-gate int hack = 1; /* -h option default */ 140*7c478bd9Sstevel@tonic-gate int idle = 0; /* -i option default */ 141*7c478bd9Sstevel@tonic-gate int large = 0; /* -l option default */ 142*7c478bd9Sstevel@tonic-gate int match = 1; /* -m option default */ 143*7c478bd9Sstevel@tonic-gate int plan = 1; /* -p option default */ 144*7c478bd9Sstevel@tonic-gate int unquick = 1; /* -q option default */ 145*7c478bd9Sstevel@tonic-gate int small = 0; /* -s option default */ 146*7c478bd9Sstevel@tonic-gate int wide = 1; /* -w option default */ 147*7c478bd9Sstevel@tonic-gate 148*7c478bd9Sstevel@tonic-gate /* 149*7c478bd9Sstevel@tonic-gate * RFC 1288 says that system administrators should have the option of 150*7c478bd9Sstevel@tonic-gate * separately allowing ASCII characters less than 32 or greater than 151*7c478bd9Sstevel@tonic-gate * 126. The termpass variable keeps track of this. 152*7c478bd9Sstevel@tonic-gate */ 153*7c478bd9Sstevel@tonic-gate char defaultfile[] = "/etc/default/finger"; 154*7c478bd9Sstevel@tonic-gate char passvar[] = "PASS="; 155*7c478bd9Sstevel@tonic-gate int termpass = 0; /* default is ASCII only */ 156*7c478bd9Sstevel@tonic-gate char *termopts[] = { 157*7c478bd9Sstevel@tonic-gate #define TERM_LOW 0 158*7c478bd9Sstevel@tonic-gate "low", 159*7c478bd9Sstevel@tonic-gate #define TERM_HIGH 1 160*7c478bd9Sstevel@tonic-gate "high", 161*7c478bd9Sstevel@tonic-gate (char *)NULL 162*7c478bd9Sstevel@tonic-gate }; 163*7c478bd9Sstevel@tonic-gate #define TS_LOW (1 << TERM_LOW) /* print characters less than 32 */ 164*7c478bd9Sstevel@tonic-gate #define TS_HIGH (1 << TERM_HIGH) /* print characters greater than 126 */ 165*7c478bd9Sstevel@tonic-gate 166*7c478bd9Sstevel@tonic-gate 167*7c478bd9Sstevel@tonic-gate int unshort; 168*7c478bd9Sstevel@tonic-gate FILE *lf; /* LASTLOG file pointer */ 169*7c478bd9Sstevel@tonic-gate struct person *person1; /* list of people */ 170*7c478bd9Sstevel@tonic-gate time_t tloc; /* current time */ 171*7c478bd9Sstevel@tonic-gate 172*7c478bd9Sstevel@tonic-gate char usagestr[] = "Usage: " 173*7c478bd9Sstevel@tonic-gate "finger [-bfhilmpqsw] [name1 [name2 ...] ]\n"; 174*7c478bd9Sstevel@tonic-gate 175*7c478bd9Sstevel@tonic-gate int AlreadyPrinted(uid_t uid); 176*7c478bd9Sstevel@tonic-gate void AnyMail(char *name); 177*7c478bd9Sstevel@tonic-gate void catfile(char *s, mode_t mode, int trunc_at_nl); 178*7c478bd9Sstevel@tonic-gate void decode(struct person *pers); 179*7c478bd9Sstevel@tonic-gate void doall(void); 180*7c478bd9Sstevel@tonic-gate void donames(char **argv); 181*7c478bd9Sstevel@tonic-gate void findidle(struct person *pers); 182*7c478bd9Sstevel@tonic-gate void findwhen(struct person *pers); 183*7c478bd9Sstevel@tonic-gate void fwclose(void); 184*7c478bd9Sstevel@tonic-gate void fwopen(void); 185*7c478bd9Sstevel@tonic-gate void initscreening(void); 186*7c478bd9Sstevel@tonic-gate void ltimeprint(char *before, time_t *dt, char *after); 187*7c478bd9Sstevel@tonic-gate int matchcmp(char *gname, char *login, char *given); 188*7c478bd9Sstevel@tonic-gate int namecmp(char *name1, char *name2); 189*7c478bd9Sstevel@tonic-gate int netfinger(char *name); 190*7c478bd9Sstevel@tonic-gate void personprint(struct person *pers); 191*7c478bd9Sstevel@tonic-gate void print(void); 192*7c478bd9Sstevel@tonic-gate struct passwd *pwdcopy(const struct passwd *pfrom); 193*7c478bd9Sstevel@tonic-gate void quickprint(struct person *pers); 194*7c478bd9Sstevel@tonic-gate void shortprint(struct person *pers); 195*7c478bd9Sstevel@tonic-gate void stimeprint(time_t *dt); 196*7c478bd9Sstevel@tonic-gate 197*7c478bd9Sstevel@tonic-gate 198*7c478bd9Sstevel@tonic-gate int 199*7c478bd9Sstevel@tonic-gate main(int argc, char **argv) 200*7c478bd9Sstevel@tonic-gate { 201*7c478bd9Sstevel@tonic-gate int c; 202*7c478bd9Sstevel@tonic-gate 203*7c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 204*7c478bd9Sstevel@tonic-gate /* parse command line for (optional) arguments */ 205*7c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, "bfhilmpqsw")) != EOF) 206*7c478bd9Sstevel@tonic-gate switch (c) { 207*7c478bd9Sstevel@tonic-gate case 'b': 208*7c478bd9Sstevel@tonic-gate unbrief = 0; 209*7c478bd9Sstevel@tonic-gate break; 210*7c478bd9Sstevel@tonic-gate case 'f': 211*7c478bd9Sstevel@tonic-gate header = 0; 212*7c478bd9Sstevel@tonic-gate break; 213*7c478bd9Sstevel@tonic-gate case 'h': 214*7c478bd9Sstevel@tonic-gate hack = 0; 215*7c478bd9Sstevel@tonic-gate break; 216*7c478bd9Sstevel@tonic-gate case 'i': 217*7c478bd9Sstevel@tonic-gate idle = 1; 218*7c478bd9Sstevel@tonic-gate unquick = 0; 219*7c478bd9Sstevel@tonic-gate break; 220*7c478bd9Sstevel@tonic-gate case 'l': 221*7c478bd9Sstevel@tonic-gate large = 1; 222*7c478bd9Sstevel@tonic-gate break; 223*7c478bd9Sstevel@tonic-gate case 'm': 224*7c478bd9Sstevel@tonic-gate match = 0; 225*7c478bd9Sstevel@tonic-gate break; 226*7c478bd9Sstevel@tonic-gate case 'p': 227*7c478bd9Sstevel@tonic-gate plan = 0; 228*7c478bd9Sstevel@tonic-gate break; 229*7c478bd9Sstevel@tonic-gate case 'q': 230*7c478bd9Sstevel@tonic-gate unquick = 0; 231*7c478bd9Sstevel@tonic-gate break; 232*7c478bd9Sstevel@tonic-gate case 's': 233*7c478bd9Sstevel@tonic-gate small = 1; 234*7c478bd9Sstevel@tonic-gate break; 235*7c478bd9Sstevel@tonic-gate case 'w': 236*7c478bd9Sstevel@tonic-gate wide = 0; 237*7c478bd9Sstevel@tonic-gate break; 238*7c478bd9Sstevel@tonic-gate default: 239*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, usagestr); 240*7c478bd9Sstevel@tonic-gate exit(1); 241*7c478bd9Sstevel@tonic-gate } 242*7c478bd9Sstevel@tonic-gate if (unquick || idle) 243*7c478bd9Sstevel@tonic-gate tloc = time(NULL); 244*7c478bd9Sstevel@tonic-gate 245*7c478bd9Sstevel@tonic-gate /* find out what filtering on .plan/.project files we should do */ 246*7c478bd9Sstevel@tonic-gate initscreening(); 247*7c478bd9Sstevel@tonic-gate 248*7c478bd9Sstevel@tonic-gate /* 249*7c478bd9Sstevel@tonic-gate * optind == argc means no names given 250*7c478bd9Sstevel@tonic-gate */ 251*7c478bd9Sstevel@tonic-gate if (optind == argc) 252*7c478bd9Sstevel@tonic-gate doall(); 253*7c478bd9Sstevel@tonic-gate else 254*7c478bd9Sstevel@tonic-gate donames(&argv[optind]); 255*7c478bd9Sstevel@tonic-gate if (person1) 256*7c478bd9Sstevel@tonic-gate print(); 257*7c478bd9Sstevel@tonic-gate return (0); 258*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 259*7c478bd9Sstevel@tonic-gate } 260*7c478bd9Sstevel@tonic-gate 261*7c478bd9Sstevel@tonic-gate void 262*7c478bd9Sstevel@tonic-gate doall(void) 263*7c478bd9Sstevel@tonic-gate { 264*7c478bd9Sstevel@tonic-gate struct person *p; 265*7c478bd9Sstevel@tonic-gate struct passwd *pw; 266*7c478bd9Sstevel@tonic-gate struct utmpx *u; 267*7c478bd9Sstevel@tonic-gate char name[NMAX + 1]; 268*7c478bd9Sstevel@tonic-gate 269*7c478bd9Sstevel@tonic-gate unshort = large; 270*7c478bd9Sstevel@tonic-gate setutxent(); 271*7c478bd9Sstevel@tonic-gate if (unquick) { 272*7c478bd9Sstevel@tonic-gate setpwent(); 273*7c478bd9Sstevel@tonic-gate fwopen(); 274*7c478bd9Sstevel@tonic-gate } 275*7c478bd9Sstevel@tonic-gate while (u = getutxent()) { 276*7c478bd9Sstevel@tonic-gate if (u->ut_name[0] == 0 || 277*7c478bd9Sstevel@tonic-gate nonuserx(*u) || 278*7c478bd9Sstevel@tonic-gate u->ut_type != USER_PROCESS) 279*7c478bd9Sstevel@tonic-gate continue; 280*7c478bd9Sstevel@tonic-gate if (person1 == 0) 281*7c478bd9Sstevel@tonic-gate p = person1 = malloc(sizeof (*p)); 282*7c478bd9Sstevel@tonic-gate else { 283*7c478bd9Sstevel@tonic-gate p->link = malloc(sizeof (*p)); 284*7c478bd9Sstevel@tonic-gate p = p->link; 285*7c478bd9Sstevel@tonic-gate } 286*7c478bd9Sstevel@tonic-gate bcopy(u->ut_name, name, NMAX); 287*7c478bd9Sstevel@tonic-gate name[NMAX] = 0; 288*7c478bd9Sstevel@tonic-gate bcopy(u->ut_line, p->tty, LMAX); 289*7c478bd9Sstevel@tonic-gate p->tty[LMAX] = 0; 290*7c478bd9Sstevel@tonic-gate bcopy(u->ut_host, p->host, HMAX); 291*7c478bd9Sstevel@tonic-gate p->host[HMAX] = 0; 292*7c478bd9Sstevel@tonic-gate p->loginat = u->ut_tv.tv_sec; 293*7c478bd9Sstevel@tonic-gate p->pwd = 0; 294*7c478bd9Sstevel@tonic-gate p->loggedin = 1; 295*7c478bd9Sstevel@tonic-gate if (unquick && (pw = getpwnam(name))) { 296*7c478bd9Sstevel@tonic-gate p->pwd = pwdcopy(pw); 297*7c478bd9Sstevel@tonic-gate decode(p); 298*7c478bd9Sstevel@tonic-gate p->name = p->pwd->pw_name; 299*7c478bd9Sstevel@tonic-gate } else 300*7c478bd9Sstevel@tonic-gate p->name = strdup(name); 301*7c478bd9Sstevel@tonic-gate p->ttyloc = NULL; 302*7c478bd9Sstevel@tonic-gate } 303*7c478bd9Sstevel@tonic-gate if (unquick) { 304*7c478bd9Sstevel@tonic-gate fwclose(); 305*7c478bd9Sstevel@tonic-gate endpwent(); 306*7c478bd9Sstevel@tonic-gate } 307*7c478bd9Sstevel@tonic-gate endutxent(); 308*7c478bd9Sstevel@tonic-gate if (person1 == 0) { 309*7c478bd9Sstevel@tonic-gate (void) printf("No one logged on\n"); 310*7c478bd9Sstevel@tonic-gate return; 311*7c478bd9Sstevel@tonic-gate } 312*7c478bd9Sstevel@tonic-gate p->link = 0; 313*7c478bd9Sstevel@tonic-gate } 314*7c478bd9Sstevel@tonic-gate 315*7c478bd9Sstevel@tonic-gate void 316*7c478bd9Sstevel@tonic-gate donames(char **argv) 317*7c478bd9Sstevel@tonic-gate { 318*7c478bd9Sstevel@tonic-gate struct person *p; 319*7c478bd9Sstevel@tonic-gate struct passwd *pw; 320*7c478bd9Sstevel@tonic-gate struct utmpx *u; 321*7c478bd9Sstevel@tonic-gate 322*7c478bd9Sstevel@tonic-gate /* 323*7c478bd9Sstevel@tonic-gate * get names from command line and check to see if they're 324*7c478bd9Sstevel@tonic-gate * logged in 325*7c478bd9Sstevel@tonic-gate */ 326*7c478bd9Sstevel@tonic-gate unshort = !small; 327*7c478bd9Sstevel@tonic-gate for (; *argv != 0; argv++) { 328*7c478bd9Sstevel@tonic-gate if (netfinger(*argv)) 329*7c478bd9Sstevel@tonic-gate continue; 330*7c478bd9Sstevel@tonic-gate if (person1 == 0) 331*7c478bd9Sstevel@tonic-gate p = person1 = malloc(sizeof (*p)); 332*7c478bd9Sstevel@tonic-gate else { 333*7c478bd9Sstevel@tonic-gate p->link = malloc(sizeof (*p)); 334*7c478bd9Sstevel@tonic-gate p = p->link; 335*7c478bd9Sstevel@tonic-gate } 336*7c478bd9Sstevel@tonic-gate p->name = *argv; 337*7c478bd9Sstevel@tonic-gate p->loggedin = 0; 338*7c478bd9Sstevel@tonic-gate p->original = 1; 339*7c478bd9Sstevel@tonic-gate p->pwd = 0; 340*7c478bd9Sstevel@tonic-gate } 341*7c478bd9Sstevel@tonic-gate if (person1 == 0) 342*7c478bd9Sstevel@tonic-gate return; 343*7c478bd9Sstevel@tonic-gate p->link = 0; 344*7c478bd9Sstevel@tonic-gate /* 345*7c478bd9Sstevel@tonic-gate * if we are doing it, read /etc/passwd for the useful info 346*7c478bd9Sstevel@tonic-gate */ 347*7c478bd9Sstevel@tonic-gate if (unquick) { 348*7c478bd9Sstevel@tonic-gate setpwent(); 349*7c478bd9Sstevel@tonic-gate if (!match) { 350*7c478bd9Sstevel@tonic-gate for (p = person1; p != 0; p = p->link) { 351*7c478bd9Sstevel@tonic-gate if (pw = getpwnam(p->name)) 352*7c478bd9Sstevel@tonic-gate p->pwd = pwdcopy(pw); 353*7c478bd9Sstevel@tonic-gate } 354*7c478bd9Sstevel@tonic-gate } else { 355*7c478bd9Sstevel@tonic-gate while ((pw = getpwent()) != 0) { 356*7c478bd9Sstevel@tonic-gate for (p = person1; p != 0; p = p->link) { 357*7c478bd9Sstevel@tonic-gate if (!p->original) 358*7c478bd9Sstevel@tonic-gate continue; 359*7c478bd9Sstevel@tonic-gate if (strcmp(p->name, pw->pw_name) != 0 && 360*7c478bd9Sstevel@tonic-gate !matchcmp(pw->pw_gecos, pw->pw_name, 361*7c478bd9Sstevel@tonic-gate p->name)) { 362*7c478bd9Sstevel@tonic-gate continue; 363*7c478bd9Sstevel@tonic-gate } 364*7c478bd9Sstevel@tonic-gate if (p->pwd == 0) { 365*7c478bd9Sstevel@tonic-gate p->pwd = pwdcopy(pw); 366*7c478bd9Sstevel@tonic-gate } else { 367*7c478bd9Sstevel@tonic-gate struct person *new; 368*7c478bd9Sstevel@tonic-gate /* 369*7c478bd9Sstevel@tonic-gate * Handle multiple login names. 370*7c478bd9Sstevel@tonic-gate * Insert new "duplicate" entry 371*7c478bd9Sstevel@tonic-gate * behind. 372*7c478bd9Sstevel@tonic-gate */ 373*7c478bd9Sstevel@tonic-gate new = malloc(sizeof (*new)); 374*7c478bd9Sstevel@tonic-gate new->pwd = pwdcopy(pw); 375*7c478bd9Sstevel@tonic-gate new->name = p->name; 376*7c478bd9Sstevel@tonic-gate new->original = 1; 377*7c478bd9Sstevel@tonic-gate new->loggedin = 0; 378*7c478bd9Sstevel@tonic-gate new->ttyloc = NULL; 379*7c478bd9Sstevel@tonic-gate new->link = p->link; 380*7c478bd9Sstevel@tonic-gate p->original = 0; 381*7c478bd9Sstevel@tonic-gate p->link = new; 382*7c478bd9Sstevel@tonic-gate p = new; 383*7c478bd9Sstevel@tonic-gate } 384*7c478bd9Sstevel@tonic-gate } 385*7c478bd9Sstevel@tonic-gate } 386*7c478bd9Sstevel@tonic-gate } 387*7c478bd9Sstevel@tonic-gate endpwent(); 388*7c478bd9Sstevel@tonic-gate } 389*7c478bd9Sstevel@tonic-gate /* Now get login information */ 390*7c478bd9Sstevel@tonic-gate setutxent(); 391*7c478bd9Sstevel@tonic-gate while (u = getutxent()) { 392*7c478bd9Sstevel@tonic-gate if (u->ut_name[0] == 0 || u->ut_type != USER_PROCESS) 393*7c478bd9Sstevel@tonic-gate continue; 394*7c478bd9Sstevel@tonic-gate for (p = person1; p != 0; p = p->link) { 395*7c478bd9Sstevel@tonic-gate p->ttyloc = NULL; 396*7c478bd9Sstevel@tonic-gate if (p->loggedin == 2) 397*7c478bd9Sstevel@tonic-gate continue; 398*7c478bd9Sstevel@tonic-gate if (strncmp(p->pwd ? p->pwd->pw_name : p->name, 399*7c478bd9Sstevel@tonic-gate u->ut_name, NMAX) != 0) 400*7c478bd9Sstevel@tonic-gate continue; 401*7c478bd9Sstevel@tonic-gate if (p->loggedin == 0) { 402*7c478bd9Sstevel@tonic-gate bcopy(u->ut_line, p->tty, LMAX); 403*7c478bd9Sstevel@tonic-gate p->tty[LMAX] = 0; 404*7c478bd9Sstevel@tonic-gate bcopy(u->ut_host, p->host, HMAX); 405*7c478bd9Sstevel@tonic-gate p->host[HMAX] = 0; 406*7c478bd9Sstevel@tonic-gate p->loginat = u->ut_tv.tv_sec; 407*7c478bd9Sstevel@tonic-gate p->loggedin = 1; 408*7c478bd9Sstevel@tonic-gate } else { /* p->loggedin == 1 */ 409*7c478bd9Sstevel@tonic-gate struct person *new; 410*7c478bd9Sstevel@tonic-gate new = malloc(sizeof (*new)); 411*7c478bd9Sstevel@tonic-gate new->name = p->name; 412*7c478bd9Sstevel@tonic-gate bcopy(u->ut_line, new->tty, LMAX); 413*7c478bd9Sstevel@tonic-gate new->tty[LMAX] = 0; 414*7c478bd9Sstevel@tonic-gate bcopy(u->ut_host, new->host, HMAX); 415*7c478bd9Sstevel@tonic-gate new->host[HMAX] = 0; 416*7c478bd9Sstevel@tonic-gate new->loginat = u->ut_tv.tv_sec; 417*7c478bd9Sstevel@tonic-gate new->pwd = p->pwd; 418*7c478bd9Sstevel@tonic-gate new->loggedin = 1; 419*7c478bd9Sstevel@tonic-gate new->original = 0; 420*7c478bd9Sstevel@tonic-gate new->link = p->link; 421*7c478bd9Sstevel@tonic-gate p->loggedin = 2; 422*7c478bd9Sstevel@tonic-gate p->link = new; 423*7c478bd9Sstevel@tonic-gate p = new; 424*7c478bd9Sstevel@tonic-gate } 425*7c478bd9Sstevel@tonic-gate } 426*7c478bd9Sstevel@tonic-gate } 427*7c478bd9Sstevel@tonic-gate endutxent(); 428*7c478bd9Sstevel@tonic-gate if (unquick) { 429*7c478bd9Sstevel@tonic-gate fwopen(); 430*7c478bd9Sstevel@tonic-gate for (p = person1; p != 0; p = p->link) 431*7c478bd9Sstevel@tonic-gate decode(p); 432*7c478bd9Sstevel@tonic-gate fwclose(); 433*7c478bd9Sstevel@tonic-gate } 434*7c478bd9Sstevel@tonic-gate } 435*7c478bd9Sstevel@tonic-gate 436*7c478bd9Sstevel@tonic-gate void 437*7c478bd9Sstevel@tonic-gate print(void) 438*7c478bd9Sstevel@tonic-gate { 439*7c478bd9Sstevel@tonic-gate struct person *p; 440*7c478bd9Sstevel@tonic-gate char *s; 441*7c478bd9Sstevel@tonic-gate 442*7c478bd9Sstevel@tonic-gate /* 443*7c478bd9Sstevel@tonic-gate * print out what we got 444*7c478bd9Sstevel@tonic-gate */ 445*7c478bd9Sstevel@tonic-gate if (header) { 446*7c478bd9Sstevel@tonic-gate if (unquick) { 447*7c478bd9Sstevel@tonic-gate if (!unshort) { 448*7c478bd9Sstevel@tonic-gate if (wide) { 449*7c478bd9Sstevel@tonic-gate (void) printf("Login " 450*7c478bd9Sstevel@tonic-gate "Name TTY " 451*7c478bd9Sstevel@tonic-gate "Idle When Where\n"); 452*7c478bd9Sstevel@tonic-gate } else { 453*7c478bd9Sstevel@tonic-gate (void) printf("Login TTY Idle " 454*7c478bd9Sstevel@tonic-gate "When Where\n"); 455*7c478bd9Sstevel@tonic-gate } 456*7c478bd9Sstevel@tonic-gate } 457*7c478bd9Sstevel@tonic-gate } else { 458*7c478bd9Sstevel@tonic-gate (void) printf("Login TTY When"); 459*7c478bd9Sstevel@tonic-gate if (idle) 460*7c478bd9Sstevel@tonic-gate (void) printf(" Idle"); 461*7c478bd9Sstevel@tonic-gate (void) putchar('\n'); 462*7c478bd9Sstevel@tonic-gate } 463*7c478bd9Sstevel@tonic-gate } 464*7c478bd9Sstevel@tonic-gate for (p = person1; p != 0; p = p->link) { 465*7c478bd9Sstevel@tonic-gate if (!unquick) { 466*7c478bd9Sstevel@tonic-gate quickprint(p); 467*7c478bd9Sstevel@tonic-gate continue; 468*7c478bd9Sstevel@tonic-gate } 469*7c478bd9Sstevel@tonic-gate if (!unshort) { 470*7c478bd9Sstevel@tonic-gate shortprint(p); 471*7c478bd9Sstevel@tonic-gate continue; 472*7c478bd9Sstevel@tonic-gate } 473*7c478bd9Sstevel@tonic-gate personprint(p); 474*7c478bd9Sstevel@tonic-gate if (p->pwd != 0 && !AlreadyPrinted(p->pwd->pw_uid)) { 475*7c478bd9Sstevel@tonic-gate AnyMail(p->pwd->pw_name); 476*7c478bd9Sstevel@tonic-gate if (hack) { 477*7c478bd9Sstevel@tonic-gate struct stat sbuf; 478*7c478bd9Sstevel@tonic-gate 479*7c478bd9Sstevel@tonic-gate s = malloc(strlen(p->pwd->pw_dir) + 480*7c478bd9Sstevel@tonic-gate sizeof (PROJ)); 481*7c478bd9Sstevel@tonic-gate if (s) { 482*7c478bd9Sstevel@tonic-gate (void) strcpy(s, p->pwd->pw_dir); 483*7c478bd9Sstevel@tonic-gate (void) strcat(s, PROJ); 484*7c478bd9Sstevel@tonic-gate if (stat(s, &sbuf) != -1 && 485*7c478bd9Sstevel@tonic-gate (S_ISREG(sbuf.st_mode) || 486*7c478bd9Sstevel@tonic-gate S_ISFIFO(sbuf.st_mode)) && 487*7c478bd9Sstevel@tonic-gate (sbuf.st_mode & S_IROTH)) { 488*7c478bd9Sstevel@tonic-gate (void) printf("Project: "); 489*7c478bd9Sstevel@tonic-gate catfile(s, sbuf.st_mode, 1); 490*7c478bd9Sstevel@tonic-gate (void) putchar('\n'); 491*7c478bd9Sstevel@tonic-gate } 492*7c478bd9Sstevel@tonic-gate free(s); 493*7c478bd9Sstevel@tonic-gate } 494*7c478bd9Sstevel@tonic-gate } 495*7c478bd9Sstevel@tonic-gate if (plan) { 496*7c478bd9Sstevel@tonic-gate struct stat sbuf; 497*7c478bd9Sstevel@tonic-gate 498*7c478bd9Sstevel@tonic-gate s = malloc(strlen(p->pwd->pw_dir) + 499*7c478bd9Sstevel@tonic-gate sizeof (PLAN)); 500*7c478bd9Sstevel@tonic-gate if (s) { 501*7c478bd9Sstevel@tonic-gate (void) strcpy(s, p->pwd->pw_dir); 502*7c478bd9Sstevel@tonic-gate (void) strcat(s, PLAN); 503*7c478bd9Sstevel@tonic-gate if (stat(s, &sbuf) == -1 || 504*7c478bd9Sstevel@tonic-gate (!S_ISREG(sbuf.st_mode) && 505*7c478bd9Sstevel@tonic-gate !S_ISFIFO(sbuf.st_mode)) || 506*7c478bd9Sstevel@tonic-gate ((sbuf.st_mode & S_IROTH) == 0)) 507*7c478bd9Sstevel@tonic-gate (void) printf("No Plan.\n"); 508*7c478bd9Sstevel@tonic-gate else { 509*7c478bd9Sstevel@tonic-gate (void) printf("Plan:\n"); 510*7c478bd9Sstevel@tonic-gate catfile(s, sbuf.st_mode, 0); 511*7c478bd9Sstevel@tonic-gate } 512*7c478bd9Sstevel@tonic-gate free(s); 513*7c478bd9Sstevel@tonic-gate } 514*7c478bd9Sstevel@tonic-gate } 515*7c478bd9Sstevel@tonic-gate } 516*7c478bd9Sstevel@tonic-gate if (p->link != 0) 517*7c478bd9Sstevel@tonic-gate (void) putchar('\n'); 518*7c478bd9Sstevel@tonic-gate } 519*7c478bd9Sstevel@tonic-gate } 520*7c478bd9Sstevel@tonic-gate 521*7c478bd9Sstevel@tonic-gate /* 522*7c478bd9Sstevel@tonic-gate * Duplicate a pwd entry. 523*7c478bd9Sstevel@tonic-gate * Note: Only the useful things (what the program currently uses) are copied. 524*7c478bd9Sstevel@tonic-gate */ 525*7c478bd9Sstevel@tonic-gate struct passwd * 526*7c478bd9Sstevel@tonic-gate pwdcopy(const struct passwd *pfrom) 527*7c478bd9Sstevel@tonic-gate { 528*7c478bd9Sstevel@tonic-gate struct passwd *pto; 529*7c478bd9Sstevel@tonic-gate 530*7c478bd9Sstevel@tonic-gate pto = malloc(sizeof (*pto)); 531*7c478bd9Sstevel@tonic-gate pto->pw_name = strdup(pfrom->pw_name); 532*7c478bd9Sstevel@tonic-gate pto->pw_uid = pfrom->pw_uid; 533*7c478bd9Sstevel@tonic-gate pto->pw_gecos = strdup(pfrom->pw_gecos); 534*7c478bd9Sstevel@tonic-gate pto->pw_dir = strdup(pfrom->pw_dir); 535*7c478bd9Sstevel@tonic-gate pto->pw_shell = strdup(pfrom->pw_shell); 536*7c478bd9Sstevel@tonic-gate return (pto); 537*7c478bd9Sstevel@tonic-gate } 538*7c478bd9Sstevel@tonic-gate 539*7c478bd9Sstevel@tonic-gate /* 540*7c478bd9Sstevel@tonic-gate * print out information on quick format giving just name, tty, login time 541*7c478bd9Sstevel@tonic-gate * and idle time if idle is set. 542*7c478bd9Sstevel@tonic-gate */ 543*7c478bd9Sstevel@tonic-gate void 544*7c478bd9Sstevel@tonic-gate quickprint(struct person *pers) 545*7c478bd9Sstevel@tonic-gate { 546*7c478bd9Sstevel@tonic-gate (void) printf("%-8.8s ", pers->name); 547*7c478bd9Sstevel@tonic-gate if (pers->loggedin) { 548*7c478bd9Sstevel@tonic-gate if (idle) { 549*7c478bd9Sstevel@tonic-gate findidle(pers); 550*7c478bd9Sstevel@tonic-gate (void) printf("%c%-12s %-16.16s", 551*7c478bd9Sstevel@tonic-gate pers->writable ? ' ' : '*', 552*7c478bd9Sstevel@tonic-gate pers->tty, ctime(&pers->loginat)); 553*7c478bd9Sstevel@tonic-gate ltimeprint(" ", &pers->idletime, ""); 554*7c478bd9Sstevel@tonic-gate } else { 555*7c478bd9Sstevel@tonic-gate (void) printf(" %-12s %-16.16s", 556*7c478bd9Sstevel@tonic-gate pers->tty, ctime(&pers->loginat)); 557*7c478bd9Sstevel@tonic-gate } 558*7c478bd9Sstevel@tonic-gate (void) putchar('\n'); 559*7c478bd9Sstevel@tonic-gate } else { 560*7c478bd9Sstevel@tonic-gate (void) printf(" Not Logged In\n"); 561*7c478bd9Sstevel@tonic-gate } 562*7c478bd9Sstevel@tonic-gate } 563*7c478bd9Sstevel@tonic-gate 564*7c478bd9Sstevel@tonic-gate /* 565*7c478bd9Sstevel@tonic-gate * print out information in short format, giving login name, full name, 566*7c478bd9Sstevel@tonic-gate * tty, idle time, login time, and host. 567*7c478bd9Sstevel@tonic-gate */ 568*7c478bd9Sstevel@tonic-gate void 569*7c478bd9Sstevel@tonic-gate shortprint(struct person *pers) 570*7c478bd9Sstevel@tonic-gate { 571*7c478bd9Sstevel@tonic-gate char *p; 572*7c478bd9Sstevel@tonic-gate 573*7c478bd9Sstevel@tonic-gate if (pers->pwd == 0) { 574*7c478bd9Sstevel@tonic-gate (void) printf("%-15s ???\n", pers->name); 575*7c478bd9Sstevel@tonic-gate return; 576*7c478bd9Sstevel@tonic-gate } 577*7c478bd9Sstevel@tonic-gate (void) printf("%-8s", pers->pwd->pw_name); 578*7c478bd9Sstevel@tonic-gate if (wide) { 579*7c478bd9Sstevel@tonic-gate if (pers->realname) { 580*7c478bd9Sstevel@tonic-gate (void) printf(" %-20.20s", pers->realname); 581*7c478bd9Sstevel@tonic-gate } else { 582*7c478bd9Sstevel@tonic-gate (void) printf(" ??? "); 583*7c478bd9Sstevel@tonic-gate } 584*7c478bd9Sstevel@tonic-gate } 585*7c478bd9Sstevel@tonic-gate (void) putchar(' '); 586*7c478bd9Sstevel@tonic-gate if (pers->loggedin && !pers->writable) { 587*7c478bd9Sstevel@tonic-gate (void) putchar('*'); 588*7c478bd9Sstevel@tonic-gate } else { 589*7c478bd9Sstevel@tonic-gate (void) putchar(' '); 590*7c478bd9Sstevel@tonic-gate } 591*7c478bd9Sstevel@tonic-gate if (*pers->tty) { 592*7c478bd9Sstevel@tonic-gate (void) printf("%-11.11s ", pers->tty); 593*7c478bd9Sstevel@tonic-gate } else { 594*7c478bd9Sstevel@tonic-gate (void) printf(" "); /* 12 spaces */ 595*7c478bd9Sstevel@tonic-gate } 596*7c478bd9Sstevel@tonic-gate p = ctime(&pers->loginat); 597*7c478bd9Sstevel@tonic-gate if (pers->loggedin) { 598*7c478bd9Sstevel@tonic-gate stimeprint(&pers->idletime); 599*7c478bd9Sstevel@tonic-gate (void) printf(" %3.3s %-5.5s ", p, p + 11); 600*7c478bd9Sstevel@tonic-gate } else if (pers->loginat == 0) { 601*7c478bd9Sstevel@tonic-gate (void) printf(" < . . . . >"); 602*7c478bd9Sstevel@tonic-gate } else if (tloc - pers->loginat >= 180 * 24 * 60 * 60) { 603*7c478bd9Sstevel@tonic-gate (void) printf(" <%-6.6s, %-4.4s>", p + 4, p + 20); 604*7c478bd9Sstevel@tonic-gate } else { 605*7c478bd9Sstevel@tonic-gate (void) printf(" <%-12.12s>", p + 4); 606*7c478bd9Sstevel@tonic-gate } 607*7c478bd9Sstevel@tonic-gate if (*pers->host) { 608*7c478bd9Sstevel@tonic-gate (void) printf(" %-20.20s", pers->host); 609*7c478bd9Sstevel@tonic-gate } else { 610*7c478bd9Sstevel@tonic-gate if (pers->ttyloc != NULL) 611*7c478bd9Sstevel@tonic-gate (void) printf(" %-20.20s", pers->ttyloc); 612*7c478bd9Sstevel@tonic-gate } 613*7c478bd9Sstevel@tonic-gate (void) putchar('\n'); 614*7c478bd9Sstevel@tonic-gate } 615*7c478bd9Sstevel@tonic-gate 616*7c478bd9Sstevel@tonic-gate 617*7c478bd9Sstevel@tonic-gate /* 618*7c478bd9Sstevel@tonic-gate * print out a person in long format giving all possible information. 619*7c478bd9Sstevel@tonic-gate * directory and shell are inhibited if unbrief is clear. 620*7c478bd9Sstevel@tonic-gate */ 621*7c478bd9Sstevel@tonic-gate void 622*7c478bd9Sstevel@tonic-gate personprint(struct person *pers) 623*7c478bd9Sstevel@tonic-gate { 624*7c478bd9Sstevel@tonic-gate if (pers->pwd == 0) { 625*7c478bd9Sstevel@tonic-gate (void) printf("Login name: %-10s\t\t\tIn real life: ???\n", 626*7c478bd9Sstevel@tonic-gate pers->name); 627*7c478bd9Sstevel@tonic-gate return; 628*7c478bd9Sstevel@tonic-gate } 629*7c478bd9Sstevel@tonic-gate (void) printf("Login name: %-10s", pers->pwd->pw_name); 630*7c478bd9Sstevel@tonic-gate if (pers->loggedin && !pers->writable) { 631*7c478bd9Sstevel@tonic-gate (void) printf(" (messages off) "); 632*7c478bd9Sstevel@tonic-gate } else { 633*7c478bd9Sstevel@tonic-gate (void) printf(" "); 634*7c478bd9Sstevel@tonic-gate } 635*7c478bd9Sstevel@tonic-gate if (pers->realname) { 636*7c478bd9Sstevel@tonic-gate (void) printf("In real life: %s", pers->realname); 637*7c478bd9Sstevel@tonic-gate } 638*7c478bd9Sstevel@tonic-gate if (unbrief) { 639*7c478bd9Sstevel@tonic-gate (void) printf("\nDirectory: %-25s", pers->pwd->pw_dir); 640*7c478bd9Sstevel@tonic-gate if (*pers->pwd->pw_shell) 641*7c478bd9Sstevel@tonic-gate (void) printf("\tShell: %-s", pers->pwd->pw_shell); 642*7c478bd9Sstevel@tonic-gate } 643*7c478bd9Sstevel@tonic-gate if (pers->loggedin) { 644*7c478bd9Sstevel@tonic-gate char *ep = ctime(&pers->loginat); 645*7c478bd9Sstevel@tonic-gate if (*pers->host) { 646*7c478bd9Sstevel@tonic-gate (void) printf("\nOn since %15.15s on %s from %s", 647*7c478bd9Sstevel@tonic-gate &ep[4], pers->tty, pers->host); 648*7c478bd9Sstevel@tonic-gate ltimeprint("\n", &pers->idletime, " Idle Time"); 649*7c478bd9Sstevel@tonic-gate } else { 650*7c478bd9Sstevel@tonic-gate (void) printf("\nOn since %15.15s on %-12s", 651*7c478bd9Sstevel@tonic-gate &ep[4], pers->tty); 652*7c478bd9Sstevel@tonic-gate ltimeprint("\n", &pers->idletime, " Idle Time"); 653*7c478bd9Sstevel@tonic-gate } 654*7c478bd9Sstevel@tonic-gate } else if (pers->loginat == 0) { 655*7c478bd9Sstevel@tonic-gate (void) printf("\nNever logged in."); 656*7c478bd9Sstevel@tonic-gate } else if (tloc - pers->loginat > 180 * 24 * 60 * 60) { 657*7c478bd9Sstevel@tonic-gate char *ep = ctime(&pers->loginat); 658*7c478bd9Sstevel@tonic-gate (void) printf("\nLast login %10.10s, %4.4s on %s", 659*7c478bd9Sstevel@tonic-gate ep, ep+20, pers->tty); 660*7c478bd9Sstevel@tonic-gate if (*pers->host) { 661*7c478bd9Sstevel@tonic-gate (void) printf(" from %s", pers->host); 662*7c478bd9Sstevel@tonic-gate } 663*7c478bd9Sstevel@tonic-gate } else { 664*7c478bd9Sstevel@tonic-gate char *ep = ctime(&pers->loginat); 665*7c478bd9Sstevel@tonic-gate (void) printf("\nLast login %16.16s on %s", ep, pers->tty); 666*7c478bd9Sstevel@tonic-gate if (*pers->host) { 667*7c478bd9Sstevel@tonic-gate (void) printf(" from %s", pers->host); 668*7c478bd9Sstevel@tonic-gate } 669*7c478bd9Sstevel@tonic-gate } 670*7c478bd9Sstevel@tonic-gate (void) putchar('\n'); 671*7c478bd9Sstevel@tonic-gate } 672*7c478bd9Sstevel@tonic-gate 673*7c478bd9Sstevel@tonic-gate 674*7c478bd9Sstevel@tonic-gate /* 675*7c478bd9Sstevel@tonic-gate * decode the information in the gecos field of /etc/passwd 676*7c478bd9Sstevel@tonic-gate */ 677*7c478bd9Sstevel@tonic-gate void 678*7c478bd9Sstevel@tonic-gate decode(struct person *pers) 679*7c478bd9Sstevel@tonic-gate { 680*7c478bd9Sstevel@tonic-gate char buffer[256]; 681*7c478bd9Sstevel@tonic-gate char *bp, *gp, *lp; 682*7c478bd9Sstevel@tonic-gate 683*7c478bd9Sstevel@tonic-gate pers->realname = 0; 684*7c478bd9Sstevel@tonic-gate if (pers->pwd == 0) 685*7c478bd9Sstevel@tonic-gate return; 686*7c478bd9Sstevel@tonic-gate gp = pers->pwd->pw_gecos; 687*7c478bd9Sstevel@tonic-gate bp = buffer; 688*7c478bd9Sstevel@tonic-gate 689*7c478bd9Sstevel@tonic-gate if (gecos_ignore_c != '\0' && 690*7c478bd9Sstevel@tonic-gate *gp == gecos_ignore_c) { 691*7c478bd9Sstevel@tonic-gate gp++; 692*7c478bd9Sstevel@tonic-gate } 693*7c478bd9Sstevel@tonic-gate while (*gp != '\0' && 694*7c478bd9Sstevel@tonic-gate *gp != gecos_sep_c) { /* name */ 695*7c478bd9Sstevel@tonic-gate if (*gp == gecos_samename) { 696*7c478bd9Sstevel@tonic-gate lp = pers->pwd->pw_name; 697*7c478bd9Sstevel@tonic-gate if (islower(*lp)) 698*7c478bd9Sstevel@tonic-gate *bp++ = toupper(*lp++); 699*7c478bd9Sstevel@tonic-gate while (*bp++ = *lp++) 700*7c478bd9Sstevel@tonic-gate ; 701*7c478bd9Sstevel@tonic-gate bp--; 702*7c478bd9Sstevel@tonic-gate gp++; 703*7c478bd9Sstevel@tonic-gate } else { 704*7c478bd9Sstevel@tonic-gate *bp++ = *gp++; 705*7c478bd9Sstevel@tonic-gate } 706*7c478bd9Sstevel@tonic-gate } 707*7c478bd9Sstevel@tonic-gate *bp++ = 0; 708*7c478bd9Sstevel@tonic-gate if (bp > (buffer + 1)) 709*7c478bd9Sstevel@tonic-gate pers->realname = strdup(buffer); 710*7c478bd9Sstevel@tonic-gate if (pers->loggedin) 711*7c478bd9Sstevel@tonic-gate findidle(pers); 712*7c478bd9Sstevel@tonic-gate else 713*7c478bd9Sstevel@tonic-gate findwhen(pers); 714*7c478bd9Sstevel@tonic-gate } 715*7c478bd9Sstevel@tonic-gate 716*7c478bd9Sstevel@tonic-gate /* 717*7c478bd9Sstevel@tonic-gate * find the last log in of a user by checking the LASTLOG file. 718*7c478bd9Sstevel@tonic-gate * the entry is indexed by the uid, so this can only be done if 719*7c478bd9Sstevel@tonic-gate * the uid is known (which it isn't in quick mode) 720*7c478bd9Sstevel@tonic-gate */ 721*7c478bd9Sstevel@tonic-gate void 722*7c478bd9Sstevel@tonic-gate fwopen(void) 723*7c478bd9Sstevel@tonic-gate { 724*7c478bd9Sstevel@tonic-gate if ((lf = fopen(LASTLOG, "r")) == (FILE *)NULL) 725*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "finger: %s open error\n", LASTLOG); 726*7c478bd9Sstevel@tonic-gate } 727*7c478bd9Sstevel@tonic-gate 728*7c478bd9Sstevel@tonic-gate void 729*7c478bd9Sstevel@tonic-gate findwhen(struct person *pers) 730*7c478bd9Sstevel@tonic-gate { 731*7c478bd9Sstevel@tonic-gate struct lastlog ll; 732*7c478bd9Sstevel@tonic-gate 733*7c478bd9Sstevel@tonic-gate if (lf != (FILE *)NULL) { 734*7c478bd9Sstevel@tonic-gate if (fseeko(lf, (off_t)pers->pwd->pw_uid * (off_t)sizeof (ll), 735*7c478bd9Sstevel@tonic-gate SEEK_SET) == 0) { 736*7c478bd9Sstevel@tonic-gate if (fread((char *)&ll, sizeof (ll), 1, lf) == 1) { 737*7c478bd9Sstevel@tonic-gate int l_max, h_max; 738*7c478bd9Sstevel@tonic-gate 739*7c478bd9Sstevel@tonic-gate l_max = min(LMAX, sizeof (ll.ll_line)); 740*7c478bd9Sstevel@tonic-gate h_max = min(HMAX, sizeof (ll.ll_host)); 741*7c478bd9Sstevel@tonic-gate 742*7c478bd9Sstevel@tonic-gate bcopy(ll.ll_line, pers->tty, l_max); 743*7c478bd9Sstevel@tonic-gate pers->tty[l_max] = '\0'; 744*7c478bd9Sstevel@tonic-gate bcopy(ll.ll_host, pers->host, h_max); 745*7c478bd9Sstevel@tonic-gate pers->host[h_max] = '\0'; 746*7c478bd9Sstevel@tonic-gate pers->loginat = ll.ll_time; 747*7c478bd9Sstevel@tonic-gate } else { 748*7c478bd9Sstevel@tonic-gate if (ferror(lf)) 749*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 750*7c478bd9Sstevel@tonic-gate "finger: %s read error\n", LASTLOG); 751*7c478bd9Sstevel@tonic-gate pers->tty[0] = 0; 752*7c478bd9Sstevel@tonic-gate pers->host[0] = 0; 753*7c478bd9Sstevel@tonic-gate pers->loginat = 0L; 754*7c478bd9Sstevel@tonic-gate } 755*7c478bd9Sstevel@tonic-gate } else { 756*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "finger: %s fseeko error\n", 757*7c478bd9Sstevel@tonic-gate LASTLOG); 758*7c478bd9Sstevel@tonic-gate } 759*7c478bd9Sstevel@tonic-gate } else { 760*7c478bd9Sstevel@tonic-gate pers->tty[0] = 0; 761*7c478bd9Sstevel@tonic-gate pers->host[0] = 0; 762*7c478bd9Sstevel@tonic-gate pers->loginat = 0L; 763*7c478bd9Sstevel@tonic-gate } 764*7c478bd9Sstevel@tonic-gate } 765*7c478bd9Sstevel@tonic-gate 766*7c478bd9Sstevel@tonic-gate void 767*7c478bd9Sstevel@tonic-gate fwclose(void) 768*7c478bd9Sstevel@tonic-gate { 769*7c478bd9Sstevel@tonic-gate if (lf != (FILE *)0) 770*7c478bd9Sstevel@tonic-gate (void) fclose(lf); 771*7c478bd9Sstevel@tonic-gate } 772*7c478bd9Sstevel@tonic-gate 773*7c478bd9Sstevel@tonic-gate /* 774*7c478bd9Sstevel@tonic-gate * find the idle time of a user by doing a stat on /dev/tty??, 775*7c478bd9Sstevel@tonic-gate * where tty?? has been gotten from UTMPX_FILE, supposedly. 776*7c478bd9Sstevel@tonic-gate */ 777*7c478bd9Sstevel@tonic-gate void 778*7c478bd9Sstevel@tonic-gate findidle(struct person *pers) 779*7c478bd9Sstevel@tonic-gate { 780*7c478bd9Sstevel@tonic-gate struct stat ttystatus; 781*7c478bd9Sstevel@tonic-gate #ifdef sun 782*7c478bd9Sstevel@tonic-gate struct stat inputdevstatus; 783*7c478bd9Sstevel@tonic-gate #endif 784*7c478bd9Sstevel@tonic-gate #define TTYLEN (sizeof ("/dev/") - 1) 785*7c478bd9Sstevel@tonic-gate static char buffer[TTYLEN + LMAX + 1] = "/dev/"; 786*7c478bd9Sstevel@tonic-gate time_t t; 787*7c478bd9Sstevel@tonic-gate time_t lastinputtime; 788*7c478bd9Sstevel@tonic-gate 789*7c478bd9Sstevel@tonic-gate (void) strcpy(buffer + TTYLEN, pers->tty); 790*7c478bd9Sstevel@tonic-gate buffer[TTYLEN+LMAX] = 0; 791*7c478bd9Sstevel@tonic-gate if (stat(buffer, &ttystatus) < 0) { 792*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "finger: Can't stat %s\n", buffer); 793*7c478bd9Sstevel@tonic-gate exit(4); 794*7c478bd9Sstevel@tonic-gate } 795*7c478bd9Sstevel@tonic-gate lastinputtime = ttystatus.st_atime; 796*7c478bd9Sstevel@tonic-gate #ifdef sun 797*7c478bd9Sstevel@tonic-gate if (strcmp(pers->tty, "console") == 0) { 798*7c478bd9Sstevel@tonic-gate /* 799*7c478bd9Sstevel@tonic-gate * On the console, the user may be running a window system; if 800*7c478bd9Sstevel@tonic-gate * so, their activity will show up in the last-access times of 801*7c478bd9Sstevel@tonic-gate * "/dev/kbd" and "/dev/mouse", so take the minimum of the idle 802*7c478bd9Sstevel@tonic-gate * times on those two devices and "/dev/console" and treat that 803*7c478bd9Sstevel@tonic-gate * as the idle time. 804*7c478bd9Sstevel@tonic-gate */ 805*7c478bd9Sstevel@tonic-gate if (stat("/dev/kbd", &inputdevstatus) == 0) { 806*7c478bd9Sstevel@tonic-gate if (lastinputtime < inputdevstatus.st_atime) 807*7c478bd9Sstevel@tonic-gate lastinputtime = inputdevstatus.st_atime; 808*7c478bd9Sstevel@tonic-gate } 809*7c478bd9Sstevel@tonic-gate if (stat("/dev/mouse", &inputdevstatus) == 0) { 810*7c478bd9Sstevel@tonic-gate if (lastinputtime < inputdevstatus.st_atime) 811*7c478bd9Sstevel@tonic-gate lastinputtime = inputdevstatus.st_atime; 812*7c478bd9Sstevel@tonic-gate } 813*7c478bd9Sstevel@tonic-gate } 814*7c478bd9Sstevel@tonic-gate #endif 815*7c478bd9Sstevel@tonic-gate t = time(NULL); 816*7c478bd9Sstevel@tonic-gate if (t < lastinputtime) 817*7c478bd9Sstevel@tonic-gate pers->idletime = (time_t)0; 818*7c478bd9Sstevel@tonic-gate else 819*7c478bd9Sstevel@tonic-gate pers->idletime = t - lastinputtime; 820*7c478bd9Sstevel@tonic-gate pers->writable = (ttystatus.st_mode & TALKABLE) == TALKABLE; 821*7c478bd9Sstevel@tonic-gate } 822*7c478bd9Sstevel@tonic-gate 823*7c478bd9Sstevel@tonic-gate /* 824*7c478bd9Sstevel@tonic-gate * print idle time in short format; this program always prints 4 characters; 825*7c478bd9Sstevel@tonic-gate * if the idle time is zero, it prints 4 blanks. 826*7c478bd9Sstevel@tonic-gate */ 827*7c478bd9Sstevel@tonic-gate void 828*7c478bd9Sstevel@tonic-gate stimeprint(time_t *dt) 829*7c478bd9Sstevel@tonic-gate { 830*7c478bd9Sstevel@tonic-gate struct tm *delta; 831*7c478bd9Sstevel@tonic-gate 832*7c478bd9Sstevel@tonic-gate delta = gmtime(dt); 833*7c478bd9Sstevel@tonic-gate if (delta->tm_yday == 0) 834*7c478bd9Sstevel@tonic-gate if (delta->tm_hour == 0) 835*7c478bd9Sstevel@tonic-gate if (delta->tm_min == 0) 836*7c478bd9Sstevel@tonic-gate (void) printf(" "); 837*7c478bd9Sstevel@tonic-gate else 838*7c478bd9Sstevel@tonic-gate (void) printf(" %2d", delta->tm_min); 839*7c478bd9Sstevel@tonic-gate else 840*7c478bd9Sstevel@tonic-gate if (delta->tm_hour >= 10) 841*7c478bd9Sstevel@tonic-gate (void) printf("%3d:", delta->tm_hour); 842*7c478bd9Sstevel@tonic-gate else 843*7c478bd9Sstevel@tonic-gate (void) printf("%1d:%02d", 844*7c478bd9Sstevel@tonic-gate delta->tm_hour, delta->tm_min); 845*7c478bd9Sstevel@tonic-gate else 846*7c478bd9Sstevel@tonic-gate (void) printf("%3dd", delta->tm_yday); 847*7c478bd9Sstevel@tonic-gate } 848*7c478bd9Sstevel@tonic-gate 849*7c478bd9Sstevel@tonic-gate /* 850*7c478bd9Sstevel@tonic-gate * print idle time in long format with care being taken not to pluralize 851*7c478bd9Sstevel@tonic-gate * 1 minutes or 1 hours or 1 days. 852*7c478bd9Sstevel@tonic-gate * print "prefix" first. 853*7c478bd9Sstevel@tonic-gate */ 854*7c478bd9Sstevel@tonic-gate void 855*7c478bd9Sstevel@tonic-gate ltimeprint(char *before, time_t *dt, char *after) 856*7c478bd9Sstevel@tonic-gate { 857*7c478bd9Sstevel@tonic-gate struct tm *delta; 858*7c478bd9Sstevel@tonic-gate 859*7c478bd9Sstevel@tonic-gate delta = gmtime(dt); 860*7c478bd9Sstevel@tonic-gate if (delta->tm_yday == 0 && delta->tm_hour == 0 && delta->tm_min == 0 && 861*7c478bd9Sstevel@tonic-gate delta->tm_sec <= 10) 862*7c478bd9Sstevel@tonic-gate return; 863*7c478bd9Sstevel@tonic-gate (void) printf("%s", before); 864*7c478bd9Sstevel@tonic-gate if (delta->tm_yday >= 10) 865*7c478bd9Sstevel@tonic-gate (void) printf("%d days", delta->tm_yday); 866*7c478bd9Sstevel@tonic-gate else if (delta->tm_yday > 0) 867*7c478bd9Sstevel@tonic-gate (void) printf("%d day%s %d hour%s", 868*7c478bd9Sstevel@tonic-gate delta->tm_yday, delta->tm_yday == 1 ? "" : "s", 869*7c478bd9Sstevel@tonic-gate delta->tm_hour, delta->tm_hour == 1 ? "" : "s"); 870*7c478bd9Sstevel@tonic-gate else 871*7c478bd9Sstevel@tonic-gate if (delta->tm_hour >= 10) 872*7c478bd9Sstevel@tonic-gate (void) printf("%d hours", delta->tm_hour); 873*7c478bd9Sstevel@tonic-gate else if (delta->tm_hour > 0) 874*7c478bd9Sstevel@tonic-gate (void) printf("%d hour%s %d minute%s", 875*7c478bd9Sstevel@tonic-gate delta->tm_hour, delta->tm_hour == 1 ? "" : "s", 876*7c478bd9Sstevel@tonic-gate delta->tm_min, delta->tm_min == 1 ? "" : "s"); 877*7c478bd9Sstevel@tonic-gate else 878*7c478bd9Sstevel@tonic-gate if (delta->tm_min >= 10) 879*7c478bd9Sstevel@tonic-gate (void) printf("%2d minutes", delta->tm_min); 880*7c478bd9Sstevel@tonic-gate else if (delta->tm_min == 0) 881*7c478bd9Sstevel@tonic-gate (void) printf("%2d seconds", delta->tm_sec); 882*7c478bd9Sstevel@tonic-gate else 883*7c478bd9Sstevel@tonic-gate (void) printf("%d minute%s %d second%s", 884*7c478bd9Sstevel@tonic-gate delta->tm_min, 885*7c478bd9Sstevel@tonic-gate delta->tm_min == 1 ? "" : "s", 886*7c478bd9Sstevel@tonic-gate delta->tm_sec, 887*7c478bd9Sstevel@tonic-gate delta->tm_sec == 1 ? "" : "s"); 888*7c478bd9Sstevel@tonic-gate (void) printf("%s", after); 889*7c478bd9Sstevel@tonic-gate } 890*7c478bd9Sstevel@tonic-gate 891*7c478bd9Sstevel@tonic-gate /* 892*7c478bd9Sstevel@tonic-gate * The grammar of the pw_gecos field is sufficiently complex that the 893*7c478bd9Sstevel@tonic-gate * best way to parse it is by using an explicit finite-state machine, 894*7c478bd9Sstevel@tonic-gate * in which a table defines the rules of interpretation. 895*7c478bd9Sstevel@tonic-gate * 896*7c478bd9Sstevel@tonic-gate * Some special rules are necessary to handle the fact that names 897*7c478bd9Sstevel@tonic-gate * may contain certain punctuation characters. At this writing, 898*7c478bd9Sstevel@tonic-gate * the possible punctuation characters are '.', '-', and '_'. 899*7c478bd9Sstevel@tonic-gate * 900*7c478bd9Sstevel@tonic-gate * Other rules are needed to account for characters that require special 901*7c478bd9Sstevel@tonic-gate * processing when they appear in the pw_gecos field. At present, there 902*7c478bd9Sstevel@tonic-gate * are three such characters, with these default values and effects: 903*7c478bd9Sstevel@tonic-gate * 904*7c478bd9Sstevel@tonic-gate * gecos_ignore_c '*' This character is ignored. 905*7c478bd9Sstevel@tonic-gate * gecos_sep_c ',' Delimits displayed and nondisplayed contents. 906*7c478bd9Sstevel@tonic-gate * gecos_samename '&' Copies the login name into the output. 907*7c478bd9Sstevel@tonic-gate * 908*7c478bd9Sstevel@tonic-gate * As the program examines each successive character in the returned 909*7c478bd9Sstevel@tonic-gate * pw_gecos value, it fetches (from the table) the FSM rule applicable 910*7c478bd9Sstevel@tonic-gate * for that character in the current machine state, and thus determines 911*7c478bd9Sstevel@tonic-gate * the next state. 912*7c478bd9Sstevel@tonic-gate * 913*7c478bd9Sstevel@tonic-gate * The possible states are: 914*7c478bd9Sstevel@tonic-gate * S0 start 915*7c478bd9Sstevel@tonic-gate * S1 in a word 916*7c478bd9Sstevel@tonic-gate * S2 not in a word 917*7c478bd9Sstevel@tonic-gate * S3 copy login name into output 918*7c478bd9Sstevel@tonic-gate * S4 end of GECOS field 919*7c478bd9Sstevel@tonic-gate * 920*7c478bd9Sstevel@tonic-gate * Here follows a depiction of the state transitions. 921*7c478bd9Sstevel@tonic-gate * 922*7c478bd9Sstevel@tonic-gate * 923*7c478bd9Sstevel@tonic-gate * gecos_ignore_c OR isspace OR any other character 924*7c478bd9Sstevel@tonic-gate * +--+ 925*7c478bd9Sstevel@tonic-gate * | | 926*7c478bd9Sstevel@tonic-gate * | V 927*7c478bd9Sstevel@tonic-gate * +-----+ 928*7c478bd9Sstevel@tonic-gate * NULL OR | S0 | isalpha OR isdigit 929*7c478bd9Sstevel@tonic-gate * +---------------|start|------------------------+ 930*7c478bd9Sstevel@tonic-gate * | gecos_sep_c +-----+ | isalpha OR isdigit 931*7c478bd9Sstevel@tonic-gate * | | | | +---------------------+ 932*7c478bd9Sstevel@tonic-gate * | | | | | OR '.' '-' '_' | 933*7c478bd9Sstevel@tonic-gate * | | |isspace | | | 934*7c478bd9Sstevel@tonic-gate * | | +-------+ V V | 935*7c478bd9Sstevel@tonic-gate * | | | +-----------+ | 936*7c478bd9Sstevel@tonic-gate * | | | | S1 |<--+ | 937*7c478bd9Sstevel@tonic-gate * | | | | in a word | | isalpha OR | 938*7c478bd9Sstevel@tonic-gate * | | | +-----------+ | isdigit OR | 939*7c478bd9Sstevel@tonic-gate * | | | | | | | | '.' '-' '_' | 940*7c478bd9Sstevel@tonic-gate * | | +----- ---------------+ | | +-----+ | 941*7c478bd9Sstevel@tonic-gate * | | | | | | | 942*7c478bd9Sstevel@tonic-gate * | | | | gecos_ignore_c | | | 943*7c478bd9Sstevel@tonic-gate * | | | | isspace | | | 944*7c478bd9Sstevel@tonic-gate * | | | | ispunct/other | | | 945*7c478bd9Sstevel@tonic-gate * | | | | any other char | | | 946*7c478bd9Sstevel@tonic-gate * | | | | +---------------+ | | 947*7c478bd9Sstevel@tonic-gate * | | | | | |NULL OR gecos_sep_c | 948*7c478bd9Sstevel@tonic-gate * | | | | | +------------------+ | 949*7c478bd9Sstevel@tonic-gate * | gecos_samename| | V V | | 950*7c478bd9Sstevel@tonic-gate * | +-------------+ | +---------------+ | | 951*7c478bd9Sstevel@tonic-gate * | | | | S2 | isspace OR '.' '-' '_' | | 952*7c478bd9Sstevel@tonic-gate * | | gecos_samename | | not in a word |<---------------------+ | | 953*7c478bd9Sstevel@tonic-gate * | | +---------------+ +---------------+ OR gecos_ignore_c | | | 954*7c478bd9Sstevel@tonic-gate * | | | | ^ | | OR ispunct OR other | | | 955*7c478bd9Sstevel@tonic-gate * | | | | | | | | | | 956*7c478bd9Sstevel@tonic-gate * | | | gecos_samename | | | +-----------------------+ | | 957*7c478bd9Sstevel@tonic-gate * | | | +---------------------+ | | | | 958*7c478bd9Sstevel@tonic-gate * | | | | | | | | 959*7c478bd9Sstevel@tonic-gate * | | | | gecos_ignore_c| | NULL OR gecos_sep_c | | 960*7c478bd9Sstevel@tonic-gate * | | | | gecos_samename| +-----------------------+ | | 961*7c478bd9Sstevel@tonic-gate * | | | | ispunct/other | | | | 962*7c478bd9Sstevel@tonic-gate * | V V V isspace | | | | 963*7c478bd9Sstevel@tonic-gate * | +-----------------+ any other char| | | | 964*7c478bd9Sstevel@tonic-gate * | | S3 |---------------+ isalpha OR isdigit OR | | | 965*7c478bd9Sstevel@tonic-gate * | |insert login name|------------------------------------------ ----- ---+ 966*7c478bd9Sstevel@tonic-gate * | +-----------------+ '.' '-' '_' | | 967*7c478bd9Sstevel@tonic-gate * | | NULL OR gecos_sep_c | | 968*7c478bd9Sstevel@tonic-gate * | +------------------------------------------+ | | 969*7c478bd9Sstevel@tonic-gate * | | | | 970*7c478bd9Sstevel@tonic-gate * | V V V 971*7c478bd9Sstevel@tonic-gate * | +------------+ 972*7c478bd9Sstevel@tonic-gate * | NULL OR gecos_sep_c | S4 | 973*7c478bd9Sstevel@tonic-gate * +-------------------------------------------------------->|end of gecos|<--+ 974*7c478bd9Sstevel@tonic-gate * +------------+ | 975*7c478bd9Sstevel@tonic-gate * | all | 976*7c478bd9Sstevel@tonic-gate * +-----+ 977*7c478bd9Sstevel@tonic-gate * 978*7c478bd9Sstevel@tonic-gate * 979*7c478bd9Sstevel@tonic-gate * The transitions from the above diagram are summarized in 980*7c478bd9Sstevel@tonic-gate * the following table of target states, which is implemented 981*7c478bd9Sstevel@tonic-gate * in code as the gecos_fsm array. 982*7c478bd9Sstevel@tonic-gate * 983*7c478bd9Sstevel@tonic-gate * Input: 984*7c478bd9Sstevel@tonic-gate * +--gecos_ignore_c 985*7c478bd9Sstevel@tonic-gate * | +--gecos_sep_c 986*7c478bd9Sstevel@tonic-gate * | | +--gecos_samename 987*7c478bd9Sstevel@tonic-gate * | | | +--isalpha 988*7c478bd9Sstevel@tonic-gate * | | | | +--isdigit 989*7c478bd9Sstevel@tonic-gate * | | | | | +--isspace 990*7c478bd9Sstevel@tonic-gate * | | | | | | +--punctuation possible in name 991*7c478bd9Sstevel@tonic-gate * | | | | | | | +--other punctuation 992*7c478bd9Sstevel@tonic-gate * | | | | | | | | +--NULL character 993*7c478bd9Sstevel@tonic-gate * | | | | | | | | | +--any other character 994*7c478bd9Sstevel@tonic-gate * | | | | | | | | | | 995*7c478bd9Sstevel@tonic-gate * V V V V V V V V V V 996*7c478bd9Sstevel@tonic-gate * From: --------------------------------------------------- 997*7c478bd9Sstevel@tonic-gate * S0 | S0 | S4 | S3 | S1 | S1 | S0 | S1 | S2 | S4 | S0 | 998*7c478bd9Sstevel@tonic-gate * S1 | S2 | S4 | S3 | S1 | S1 | S2 | S1 | S2 | S4 | S2 | 999*7c478bd9Sstevel@tonic-gate * S2 | S2 | S4 | S3 | S1 | S1 | S2 | S2 | S2 | S4 | S2 | 1000*7c478bd9Sstevel@tonic-gate * S3 | S2 | S4 | S2 | S1 | S1 | S2 | S1 | S2 | S4 | S2 | 1001*7c478bd9Sstevel@tonic-gate * S4 | S4 | S4 | S4 | S4 | S4 | S4 | S4 | S4 | S4 | S4 | 1002*7c478bd9Sstevel@tonic-gate * 1003*7c478bd9Sstevel@tonic-gate */ 1004*7c478bd9Sstevel@tonic-gate 1005*7c478bd9Sstevel@tonic-gate /* 1006*7c478bd9Sstevel@tonic-gate * Data types and structures for scanning the pw_gecos field. 1007*7c478bd9Sstevel@tonic-gate */ 1008*7c478bd9Sstevel@tonic-gate typedef enum gecos_state { 1009*7c478bd9Sstevel@tonic-gate S0, /* start */ 1010*7c478bd9Sstevel@tonic-gate S1, /* in a word */ 1011*7c478bd9Sstevel@tonic-gate S2, /* not in a word */ 1012*7c478bd9Sstevel@tonic-gate S3, /* copy login */ 1013*7c478bd9Sstevel@tonic-gate S4 /* end of gecos */ 1014*7c478bd9Sstevel@tonic-gate } gecos_state_t; 1015*7c478bd9Sstevel@tonic-gate 1016*7c478bd9Sstevel@tonic-gate #define GFSM_ROWS 5 1017*7c478bd9Sstevel@tonic-gate #define GFSM_COLS 10 1018*7c478bd9Sstevel@tonic-gate 1019*7c478bd9Sstevel@tonic-gate gecos_state_t gecos_fsm[GFSM_ROWS][GFSM_COLS] = { 1020*7c478bd9Sstevel@tonic-gate {S0, S4, S3, S1, S1, S0, S1, S2, S4, S0}, /* S0 */ 1021*7c478bd9Sstevel@tonic-gate {S2, S4, S3, S1, S1, S2, S1, S2, S4, S2}, /* S1 */ 1022*7c478bd9Sstevel@tonic-gate {S2, S4, S3, S1, S1, S2, S2, S2, S4, S2}, /* S2 */ 1023*7c478bd9Sstevel@tonic-gate {S2, S4, S2, S1, S1, S2, S1, S2, S4, S2}, /* S3 */ 1024*7c478bd9Sstevel@tonic-gate {S4, S4, S4, S4, S4, S4, S4, S4, S4, S4} /* S4 */ 1025*7c478bd9Sstevel@tonic-gate }; 1026*7c478bd9Sstevel@tonic-gate 1027*7c478bd9Sstevel@tonic-gate /* 1028*7c478bd9Sstevel@tonic-gate * Scan the pw_gecos field according to defined state table; 1029*7c478bd9Sstevel@tonic-gate * return the next state according the the rules. 1030*7c478bd9Sstevel@tonic-gate */ 1031*7c478bd9Sstevel@tonic-gate gecos_state_t 1032*7c478bd9Sstevel@tonic-gate gecos_scan_state(gecos_state_t instate, char ch) 1033*7c478bd9Sstevel@tonic-gate { 1034*7c478bd9Sstevel@tonic-gate if (ch == gecos_ignore_c) { 1035*7c478bd9Sstevel@tonic-gate return (gecos_fsm[instate][0]); 1036*7c478bd9Sstevel@tonic-gate } else if (ch == gecos_sep_c) { 1037*7c478bd9Sstevel@tonic-gate return (gecos_fsm[instate][1]); 1038*7c478bd9Sstevel@tonic-gate } else if (ch == gecos_samename) { 1039*7c478bd9Sstevel@tonic-gate return (gecos_fsm[instate][2]); 1040*7c478bd9Sstevel@tonic-gate } else if (isalpha(ch)) { 1041*7c478bd9Sstevel@tonic-gate return (gecos_fsm[instate][3]); 1042*7c478bd9Sstevel@tonic-gate } else if (isdigit(ch)) { 1043*7c478bd9Sstevel@tonic-gate return (gecos_fsm[instate][4]); 1044*7c478bd9Sstevel@tonic-gate } else if (isspace(ch)) { 1045*7c478bd9Sstevel@tonic-gate return (gecos_fsm[instate][5]); 1046*7c478bd9Sstevel@tonic-gate } else if (ch == '.' || ch == '-' || ch == '_') { 1047*7c478bd9Sstevel@tonic-gate return (gecos_fsm[instate][6]); 1048*7c478bd9Sstevel@tonic-gate } else if (ispunct(ch)) { 1049*7c478bd9Sstevel@tonic-gate return (gecos_fsm[instate][7]); 1050*7c478bd9Sstevel@tonic-gate } else if (ch == '\0') { 1051*7c478bd9Sstevel@tonic-gate return (gecos_fsm[instate][8]); 1052*7c478bd9Sstevel@tonic-gate } 1053*7c478bd9Sstevel@tonic-gate return (gecos_fsm[instate][9]); 1054*7c478bd9Sstevel@tonic-gate } 1055*7c478bd9Sstevel@tonic-gate 1056*7c478bd9Sstevel@tonic-gate 1057*7c478bd9Sstevel@tonic-gate /* 1058*7c478bd9Sstevel@tonic-gate * Compare the given argument, which is taken to be a username, with 1059*7c478bd9Sstevel@tonic-gate * the login name and with strings in the the pw_gecos field. 1060*7c478bd9Sstevel@tonic-gate */ 1061*7c478bd9Sstevel@tonic-gate int 1062*7c478bd9Sstevel@tonic-gate matchcmp(char *gname, char *login, char *given) 1063*7c478bd9Sstevel@tonic-gate { 1064*7c478bd9Sstevel@tonic-gate char buffer[100]; 1065*7c478bd9Sstevel@tonic-gate char *bp, *lp, *gp; 1066*7c478bd9Sstevel@tonic-gate 1067*7c478bd9Sstevel@tonic-gate gecos_state_t kstate = S0; 1068*7c478bd9Sstevel@tonic-gate gecos_state_t kstate_next = S0; 1069*7c478bd9Sstevel@tonic-gate 1070*7c478bd9Sstevel@tonic-gate if (*gname == '\0' && *given == '\0') 1071*7c478bd9Sstevel@tonic-gate return (1); 1072*7c478bd9Sstevel@tonic-gate 1073*7c478bd9Sstevel@tonic-gate bp = buffer; 1074*7c478bd9Sstevel@tonic-gate gp = gname; 1075*7c478bd9Sstevel@tonic-gate 1076*7c478bd9Sstevel@tonic-gate do { 1077*7c478bd9Sstevel@tonic-gate kstate_next = gecos_scan_state(kstate, *gp); 1078*7c478bd9Sstevel@tonic-gate 1079*7c478bd9Sstevel@tonic-gate switch (kstate_next) { 1080*7c478bd9Sstevel@tonic-gate 1081*7c478bd9Sstevel@tonic-gate case S0: 1082*7c478bd9Sstevel@tonic-gate gp++; 1083*7c478bd9Sstevel@tonic-gate break; 1084*7c478bd9Sstevel@tonic-gate case S1: 1085*7c478bd9Sstevel@tonic-gate if (bp < buffer + sizeof (buffer)) { 1086*7c478bd9Sstevel@tonic-gate *bp++ = *gp++; 1087*7c478bd9Sstevel@tonic-gate } 1088*7c478bd9Sstevel@tonic-gate break; 1089*7c478bd9Sstevel@tonic-gate case S2: 1090*7c478bd9Sstevel@tonic-gate if (kstate == S1 || kstate == S3) { 1091*7c478bd9Sstevel@tonic-gate *bp++ = ' '; 1092*7c478bd9Sstevel@tonic-gate } 1093*7c478bd9Sstevel@tonic-gate gp++; 1094*7c478bd9Sstevel@tonic-gate break; 1095*7c478bd9Sstevel@tonic-gate case S3: 1096*7c478bd9Sstevel@tonic-gate lp = login; 1097*7c478bd9Sstevel@tonic-gate do { 1098*7c478bd9Sstevel@tonic-gate *bp++ = *lp++; 1099*7c478bd9Sstevel@tonic-gate } while (*bp != '\0' && bp < buffer + sizeof (buffer)); 1100*7c478bd9Sstevel@tonic-gate bp--; 1101*7c478bd9Sstevel@tonic-gate break; 1102*7c478bd9Sstevel@tonic-gate case S4: 1103*7c478bd9Sstevel@tonic-gate *bp++ = '\0'; 1104*7c478bd9Sstevel@tonic-gate break; 1105*7c478bd9Sstevel@tonic-gate default: 1106*7c478bd9Sstevel@tonic-gate *bp++ = '\0'; 1107*7c478bd9Sstevel@tonic-gate break; 1108*7c478bd9Sstevel@tonic-gate } 1109*7c478bd9Sstevel@tonic-gate kstate = kstate_next; 1110*7c478bd9Sstevel@tonic-gate 1111*7c478bd9Sstevel@tonic-gate } while ((bp < buffer + sizeof (buffer)) && kstate != S4); 1112*7c478bd9Sstevel@tonic-gate 1113*7c478bd9Sstevel@tonic-gate gp = strtok(buffer, " "); 1114*7c478bd9Sstevel@tonic-gate 1115*7c478bd9Sstevel@tonic-gate while (gp != NULL) { 1116*7c478bd9Sstevel@tonic-gate if (namecmp(gp, given) > 0) { 1117*7c478bd9Sstevel@tonic-gate return (1); 1118*7c478bd9Sstevel@tonic-gate } 1119*7c478bd9Sstevel@tonic-gate gp = strtok(NULL, " "); 1120*7c478bd9Sstevel@tonic-gate } 1121*7c478bd9Sstevel@tonic-gate return (0); 1122*7c478bd9Sstevel@tonic-gate } 1123*7c478bd9Sstevel@tonic-gate 1124*7c478bd9Sstevel@tonic-gate /* 1125*7c478bd9Sstevel@tonic-gate * Perform the character-by-character comparison. 1126*7c478bd9Sstevel@tonic-gate * It is intended that "finger foo" should match "foo2", but an argument 1127*7c478bd9Sstevel@tonic-gate * consisting entirely of digits should not be matched too broadly. 1128*7c478bd9Sstevel@tonic-gate * Also, we do not want "finger foo123" to match "Mr. Foo" in the gecos. 1129*7c478bd9Sstevel@tonic-gate */ 1130*7c478bd9Sstevel@tonic-gate int 1131*7c478bd9Sstevel@tonic-gate namecmp(char *name1, char *name2) 1132*7c478bd9Sstevel@tonic-gate { 1133*7c478bd9Sstevel@tonic-gate char c1, c2; 1134*7c478bd9Sstevel@tonic-gate boolean_t alphaseen = B_FALSE; 1135*7c478bd9Sstevel@tonic-gate boolean_t digitseen = B_FALSE; 1136*7c478bd9Sstevel@tonic-gate 1137*7c478bd9Sstevel@tonic-gate for (;;) { 1138*7c478bd9Sstevel@tonic-gate c1 = *name1++; 1139*7c478bd9Sstevel@tonic-gate if (isalpha(c1)) 1140*7c478bd9Sstevel@tonic-gate alphaseen = B_TRUE; 1141*7c478bd9Sstevel@tonic-gate if (isdigit(c1)) 1142*7c478bd9Sstevel@tonic-gate digitseen = B_TRUE; 1143*7c478bd9Sstevel@tonic-gate if (isupper(c1)) 1144*7c478bd9Sstevel@tonic-gate c1 = tolower(c1); 1145*7c478bd9Sstevel@tonic-gate 1146*7c478bd9Sstevel@tonic-gate c2 = *name2++; 1147*7c478bd9Sstevel@tonic-gate if (isupper(c2)) 1148*7c478bd9Sstevel@tonic-gate c2 = tolower(c2); 1149*7c478bd9Sstevel@tonic-gate 1150*7c478bd9Sstevel@tonic-gate if (c1 != c2) 1151*7c478bd9Sstevel@tonic-gate break; 1152*7c478bd9Sstevel@tonic-gate if (c1 == '\0') 1153*7c478bd9Sstevel@tonic-gate return (1); 1154*7c478bd9Sstevel@tonic-gate } 1155*7c478bd9Sstevel@tonic-gate if (!c1) { 1156*7c478bd9Sstevel@tonic-gate for (name2--; isdigit(*name2); name2++) 1157*7c478bd9Sstevel@tonic-gate ; 1158*7c478bd9Sstevel@tonic-gate if (*name2 == '\0' && digitseen) { 1159*7c478bd9Sstevel@tonic-gate return (1); 1160*7c478bd9Sstevel@tonic-gate } 1161*7c478bd9Sstevel@tonic-gate } else if (!c2) { 1162*7c478bd9Sstevel@tonic-gate for (name1--; isdigit(*name1); name1++) 1163*7c478bd9Sstevel@tonic-gate ; 1164*7c478bd9Sstevel@tonic-gate if (*name1 == '\0' && alphaseen) { 1165*7c478bd9Sstevel@tonic-gate return (1); 1166*7c478bd9Sstevel@tonic-gate } 1167*7c478bd9Sstevel@tonic-gate } 1168*7c478bd9Sstevel@tonic-gate return (0); 1169*7c478bd9Sstevel@tonic-gate } 1170*7c478bd9Sstevel@tonic-gate 1171*7c478bd9Sstevel@tonic-gate 1172*7c478bd9Sstevel@tonic-gate int 1173*7c478bd9Sstevel@tonic-gate netfinger(char *name) 1174*7c478bd9Sstevel@tonic-gate { 1175*7c478bd9Sstevel@tonic-gate char *host; 1176*7c478bd9Sstevel@tonic-gate struct hostent *hp; 1177*7c478bd9Sstevel@tonic-gate struct sockaddr_in6 sin6; 1178*7c478bd9Sstevel@tonic-gate struct in6_addr ipv6addr; 1179*7c478bd9Sstevel@tonic-gate struct in_addr ipv4addr; 1180*7c478bd9Sstevel@tonic-gate int s; 1181*7c478bd9Sstevel@tonic-gate FILE *f; 1182*7c478bd9Sstevel@tonic-gate int c; 1183*7c478bd9Sstevel@tonic-gate int lastc; 1184*7c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 1185*7c478bd9Sstevel@tonic-gate int error_num; 1186*7c478bd9Sstevel@tonic-gate 1187*7c478bd9Sstevel@tonic-gate if (name == NULL) 1188*7c478bd9Sstevel@tonic-gate return (0); 1189*7c478bd9Sstevel@tonic-gate host = strrchr(name, '@'); 1190*7c478bd9Sstevel@tonic-gate if (host == NULL) 1191*7c478bd9Sstevel@tonic-gate return (0); 1192*7c478bd9Sstevel@tonic-gate *host++ = 0; 1193*7c478bd9Sstevel@tonic-gate 1194*7c478bd9Sstevel@tonic-gate if ((hp = getipnodebyname(host, AF_INET6, AI_ALL | AI_ADDRCONFIG | 1195*7c478bd9Sstevel@tonic-gate AI_V4MAPPED, &error_num)) == NULL) { 1196*7c478bd9Sstevel@tonic-gate if (error_num == TRY_AGAIN) { 1197*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1198*7c478bd9Sstevel@tonic-gate "unknown host: %s (try again later)\n", host); 1199*7c478bd9Sstevel@tonic-gate } else { 1200*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "unknown host: %s\n", host); 1201*7c478bd9Sstevel@tonic-gate } 1202*7c478bd9Sstevel@tonic-gate return (1); 1203*7c478bd9Sstevel@tonic-gate } 1204*7c478bd9Sstevel@tonic-gate 1205*7c478bd9Sstevel@tonic-gate /* 1206*7c478bd9Sstevel@tonic-gate * If hp->h_name is a IPv4-mapped IPv6 literal, we'll convert it to 1207*7c478bd9Sstevel@tonic-gate * IPv4 literal address. 1208*7c478bd9Sstevel@tonic-gate */ 1209*7c478bd9Sstevel@tonic-gate if ((inet_pton(AF_INET6, hp->h_name, &ipv6addr) > 0) && 1210*7c478bd9Sstevel@tonic-gate IN6_IS_ADDR_V4MAPPED(&ipv6addr)) { 1211*7c478bd9Sstevel@tonic-gate IN6_V4MAPPED_TO_INADDR(&ipv6addr, &ipv4addr); 1212*7c478bd9Sstevel@tonic-gate (void) printf("[%s] ", inet_ntop(AF_INET, &ipv4addr, abuf, 1213*7c478bd9Sstevel@tonic-gate sizeof (abuf))); 1214*7c478bd9Sstevel@tonic-gate } else { 1215*7c478bd9Sstevel@tonic-gate (void) printf("[%s] ", hp->h_name); 1216*7c478bd9Sstevel@tonic-gate } 1217*7c478bd9Sstevel@tonic-gate bzero(&sin6, sizeof (sin6)); 1218*7c478bd9Sstevel@tonic-gate sin6.sin6_family = hp->h_addrtype; 1219*7c478bd9Sstevel@tonic-gate bcopy(hp->h_addr_list[0], (char *)&sin6.sin6_addr, hp->h_length); 1220*7c478bd9Sstevel@tonic-gate sin6.sin6_port = htons(IPPORT_FINGER); 1221*7c478bd9Sstevel@tonic-gate s = socket(sin6.sin6_family, SOCK_STREAM, 0); 1222*7c478bd9Sstevel@tonic-gate if (s < 0) { 1223*7c478bd9Sstevel@tonic-gate (void) fflush(stdout); 1224*7c478bd9Sstevel@tonic-gate perror("socket"); 1225*7c478bd9Sstevel@tonic-gate freehostent(hp); 1226*7c478bd9Sstevel@tonic-gate return (1); 1227*7c478bd9Sstevel@tonic-gate } 1228*7c478bd9Sstevel@tonic-gate while (connect(s, (struct sockaddr *)&sin6, sizeof (sin6)) < 0) { 1229*7c478bd9Sstevel@tonic-gate 1230*7c478bd9Sstevel@tonic-gate if (hp && hp->h_addr_list[1]) { 1231*7c478bd9Sstevel@tonic-gate 1232*7c478bd9Sstevel@tonic-gate hp->h_addr_list++; 1233*7c478bd9Sstevel@tonic-gate bcopy(hp->h_addr_list[0], 1234*7c478bd9Sstevel@tonic-gate (caddr_t)&sin6.sin6_addr, hp->h_length); 1235*7c478bd9Sstevel@tonic-gate (void) close(s); 1236*7c478bd9Sstevel@tonic-gate s = socket(sin6.sin6_family, SOCK_STREAM, 0); 1237*7c478bd9Sstevel@tonic-gate if (s < 0) { 1238*7c478bd9Sstevel@tonic-gate (void) fflush(stdout); 1239*7c478bd9Sstevel@tonic-gate perror("socket"); 1240*7c478bd9Sstevel@tonic-gate freehostent(hp); 1241*7c478bd9Sstevel@tonic-gate return (0); 1242*7c478bd9Sstevel@tonic-gate } 1243*7c478bd9Sstevel@tonic-gate continue; 1244*7c478bd9Sstevel@tonic-gate } 1245*7c478bd9Sstevel@tonic-gate 1246*7c478bd9Sstevel@tonic-gate (void) fflush(stdout); 1247*7c478bd9Sstevel@tonic-gate perror("connect"); 1248*7c478bd9Sstevel@tonic-gate (void) close(s); 1249*7c478bd9Sstevel@tonic-gate freehostent(hp); 1250*7c478bd9Sstevel@tonic-gate return (1); 1251*7c478bd9Sstevel@tonic-gate } 1252*7c478bd9Sstevel@tonic-gate freehostent(hp); 1253*7c478bd9Sstevel@tonic-gate hp = NULL; 1254*7c478bd9Sstevel@tonic-gate 1255*7c478bd9Sstevel@tonic-gate (void) printf("\n"); 1256*7c478bd9Sstevel@tonic-gate if (large) 1257*7c478bd9Sstevel@tonic-gate (void) write(s, "/W ", 3); 1258*7c478bd9Sstevel@tonic-gate (void) write(s, name, strlen(name)); 1259*7c478bd9Sstevel@tonic-gate (void) write(s, "\r\n", 2); 1260*7c478bd9Sstevel@tonic-gate f = fdopen(s, "r"); 1261*7c478bd9Sstevel@tonic-gate 1262*7c478bd9Sstevel@tonic-gate lastc = '\n'; 1263*7c478bd9Sstevel@tonic-gate while ((c = getc(f)) != EOF) { 1264*7c478bd9Sstevel@tonic-gate /* map CRLF -> newline */ 1265*7c478bd9Sstevel@tonic-gate if ((lastc == '\r') && (c != '\n')) 1266*7c478bd9Sstevel@tonic-gate /* print out saved CR */ 1267*7c478bd9Sstevel@tonic-gate (void) putchar('\r'); 1268*7c478bd9Sstevel@tonic-gate lastc = c; 1269*7c478bd9Sstevel@tonic-gate if (c == '\r') 1270*7c478bd9Sstevel@tonic-gate continue; 1271*7c478bd9Sstevel@tonic-gate (void) putchar(c); 1272*7c478bd9Sstevel@tonic-gate } 1273*7c478bd9Sstevel@tonic-gate 1274*7c478bd9Sstevel@tonic-gate if (lastc != '\n') 1275*7c478bd9Sstevel@tonic-gate (void) putchar('\n'); 1276*7c478bd9Sstevel@tonic-gate (void) fclose(f); 1277*7c478bd9Sstevel@tonic-gate return (1); 1278*7c478bd9Sstevel@tonic-gate } 1279*7c478bd9Sstevel@tonic-gate 1280*7c478bd9Sstevel@tonic-gate /* 1281*7c478bd9Sstevel@tonic-gate * AnyMail - takes a username (string pointer thereto), and 1282*7c478bd9Sstevel@tonic-gate * prints on standard output whether there is any unread mail, 1283*7c478bd9Sstevel@tonic-gate * and if so, how old it is. (JCM@Shasta 15 March 80) 1284*7c478bd9Sstevel@tonic-gate */ 1285*7c478bd9Sstevel@tonic-gate void 1286*7c478bd9Sstevel@tonic-gate AnyMail(char *name) 1287*7c478bd9Sstevel@tonic-gate { 1288*7c478bd9Sstevel@tonic-gate struct stat buf; /* space for file status buffer */ 1289*7c478bd9Sstevel@tonic-gate char *mbxdir = MAILDIR; /* string with path preamble */ 1290*7c478bd9Sstevel@tonic-gate char *mbxpath; /* space for entire pathname */ 1291*7c478bd9Sstevel@tonic-gate 1292*7c478bd9Sstevel@tonic-gate char *timestr; 1293*7c478bd9Sstevel@tonic-gate 1294*7c478bd9Sstevel@tonic-gate mbxpath = malloc(strlen(name) + strlen(MAILDIR) + 1); 1295*7c478bd9Sstevel@tonic-gate if (mbxpath == (char *)NULL) 1296*7c478bd9Sstevel@tonic-gate return; 1297*7c478bd9Sstevel@tonic-gate 1298*7c478bd9Sstevel@tonic-gate (void) strcpy(mbxpath, mbxdir); /* copy preamble into path name */ 1299*7c478bd9Sstevel@tonic-gate (void) strcat(mbxpath, name); /* concatenate user name to path */ 1300*7c478bd9Sstevel@tonic-gate 1301*7c478bd9Sstevel@tonic-gate if (stat(mbxpath, &buf) == -1 || buf.st_size == 0) { 1302*7c478bd9Sstevel@tonic-gate /* Mailbox is empty or nonexistent */ 1303*7c478bd9Sstevel@tonic-gate (void) printf("No unread mail\n"); 1304*7c478bd9Sstevel@tonic-gate } else { 1305*7c478bd9Sstevel@tonic-gate if (buf.st_mtime < buf.st_atime) { 1306*7c478bd9Sstevel@tonic-gate /* 1307*7c478bd9Sstevel@tonic-gate * No new mail since the last time the user read it. 1308*7c478bd9Sstevel@tonic-gate */ 1309*7c478bd9Sstevel@tonic-gate (void) printf("Mail last read "); 1310*7c478bd9Sstevel@tonic-gate (void) printf("%s", ctime(&buf.st_atime)); 1311*7c478bd9Sstevel@tonic-gate } else if (buf.st_mtime > buf.st_atime) { 1312*7c478bd9Sstevel@tonic-gate /* 1313*7c478bd9Sstevel@tonic-gate * New mail has definitely arrived since the last time 1314*7c478bd9Sstevel@tonic-gate * mail was read. mtime is the time the most recent 1315*7c478bd9Sstevel@tonic-gate * message arrived; atime is either the time the oldest 1316*7c478bd9Sstevel@tonic-gate * unread message arrived, or the last time the mail 1317*7c478bd9Sstevel@tonic-gate * was read. 1318*7c478bd9Sstevel@tonic-gate */ 1319*7c478bd9Sstevel@tonic-gate (void) printf("New mail received "); 1320*7c478bd9Sstevel@tonic-gate timestr = ctime(&buf.st_mtime); /* time last modified */ 1321*7c478bd9Sstevel@tonic-gate timestr[24] = '\0'; /* suppress newline (ugh) */ 1322*7c478bd9Sstevel@tonic-gate (void) printf("%s", timestr); 1323*7c478bd9Sstevel@tonic-gate (void) printf(";\n unread since "); 1324*7c478bd9Sstevel@tonic-gate (void) printf("%s", ctime(&buf.st_atime)); 1325*7c478bd9Sstevel@tonic-gate } else { 1326*7c478bd9Sstevel@tonic-gate /* 1327*7c478bd9Sstevel@tonic-gate * There is something in mailbox, but we can't really 1328*7c478bd9Sstevel@tonic-gate * be sure whether it is mail held there by the user 1329*7c478bd9Sstevel@tonic-gate * or a (single) new message that was placed in a newly 1330*7c478bd9Sstevel@tonic-gate * recreated mailbox, so punt and call it "unread mail." 1331*7c478bd9Sstevel@tonic-gate */ 1332*7c478bd9Sstevel@tonic-gate (void) printf("Unread mail since "); 1333*7c478bd9Sstevel@tonic-gate (void) printf("%s", ctime(&buf.st_mtime)); 1334*7c478bd9Sstevel@tonic-gate } 1335*7c478bd9Sstevel@tonic-gate } 1336*7c478bd9Sstevel@tonic-gate free(mbxpath); 1337*7c478bd9Sstevel@tonic-gate } 1338*7c478bd9Sstevel@tonic-gate 1339*7c478bd9Sstevel@tonic-gate /* 1340*7c478bd9Sstevel@tonic-gate * return true iff we've already printed project/plan for this uid; 1341*7c478bd9Sstevel@tonic-gate * if not, enter this uid into table (so this function has a side-effect.) 1342*7c478bd9Sstevel@tonic-gate */ 1343*7c478bd9Sstevel@tonic-gate #define PPMAX 4096 /* assume no more than 4096 logged-in users */ 1344*7c478bd9Sstevel@tonic-gate uid_t PlanPrinted[PPMAX+1]; 1345*7c478bd9Sstevel@tonic-gate int PPIndex = 0; /* index of next unused table entry */ 1346*7c478bd9Sstevel@tonic-gate 1347*7c478bd9Sstevel@tonic-gate int 1348*7c478bd9Sstevel@tonic-gate AlreadyPrinted(uid_t uid) 1349*7c478bd9Sstevel@tonic-gate { 1350*7c478bd9Sstevel@tonic-gate int i = 0; 1351*7c478bd9Sstevel@tonic-gate 1352*7c478bd9Sstevel@tonic-gate while (i++ < PPIndex) { 1353*7c478bd9Sstevel@tonic-gate if (PlanPrinted[i] == uid) 1354*7c478bd9Sstevel@tonic-gate return (1); 1355*7c478bd9Sstevel@tonic-gate } 1356*7c478bd9Sstevel@tonic-gate if (i < PPMAX) { 1357*7c478bd9Sstevel@tonic-gate PlanPrinted[i] = uid; 1358*7c478bd9Sstevel@tonic-gate PPIndex++; 1359*7c478bd9Sstevel@tonic-gate } 1360*7c478bd9Sstevel@tonic-gate return (0); 1361*7c478bd9Sstevel@tonic-gate } 1362*7c478bd9Sstevel@tonic-gate 1363*7c478bd9Sstevel@tonic-gate #define FIFOREADTIMEOUT (60) /* read timeout on select */ 1364*7c478bd9Sstevel@tonic-gate /* BEGIN CSTYLED */ 1365*7c478bd9Sstevel@tonic-gate #define PRINT_CHAR(c) \ 1366*7c478bd9Sstevel@tonic-gate ( \ 1367*7c478bd9Sstevel@tonic-gate ((termpass & TS_HIGH) && ((int)c) > 126) \ 1368*7c478bd9Sstevel@tonic-gate || \ 1369*7c478bd9Sstevel@tonic-gate (isascii((int)c) && \ 1370*7c478bd9Sstevel@tonic-gate (isprint((int)c) || isspace((int)c)) \ 1371*7c478bd9Sstevel@tonic-gate ) \ 1372*7c478bd9Sstevel@tonic-gate || \ 1373*7c478bd9Sstevel@tonic-gate ((termpass & TS_LOW) && ((int)c) < 32) \ 1374*7c478bd9Sstevel@tonic-gate ) 1375*7c478bd9Sstevel@tonic-gate /* END CSTYLED */ 1376*7c478bd9Sstevel@tonic-gate 1377*7c478bd9Sstevel@tonic-gate 1378*7c478bd9Sstevel@tonic-gate void 1379*7c478bd9Sstevel@tonic-gate catfile(char *s, mode_t mode, int trunc_at_nl) 1380*7c478bd9Sstevel@tonic-gate { 1381*7c478bd9Sstevel@tonic-gate if (S_ISFIFO(mode)) { 1382*7c478bd9Sstevel@tonic-gate int fd; 1383*7c478bd9Sstevel@tonic-gate 1384*7c478bd9Sstevel@tonic-gate fd = open(s, O_RDONLY | O_NONBLOCK); 1385*7c478bd9Sstevel@tonic-gate if (fd != -1) { 1386*7c478bd9Sstevel@tonic-gate fd_set readfds, exceptfds; 1387*7c478bd9Sstevel@tonic-gate struct timeval tv; 1388*7c478bd9Sstevel@tonic-gate 1389*7c478bd9Sstevel@tonic-gate FD_ZERO(&readfds); 1390*7c478bd9Sstevel@tonic-gate FD_ZERO(&exceptfds); 1391*7c478bd9Sstevel@tonic-gate FD_SET(fd, &readfds); 1392*7c478bd9Sstevel@tonic-gate FD_SET(fd, &exceptfds); 1393*7c478bd9Sstevel@tonic-gate 1394*7c478bd9Sstevel@tonic-gate timerclear(&tv); 1395*7c478bd9Sstevel@tonic-gate tv.tv_sec = FIFOREADTIMEOUT; 1396*7c478bd9Sstevel@tonic-gate 1397*7c478bd9Sstevel@tonic-gate (void) fflush(stdout); 1398*7c478bd9Sstevel@tonic-gate while (select(fd + 1, &readfds, (fd_set *) 0, 1399*7c478bd9Sstevel@tonic-gate &exceptfds, &tv) != -1) { 1400*7c478bd9Sstevel@tonic-gate unsigned char buf[BUFSIZ]; 1401*7c478bd9Sstevel@tonic-gate int nread; 1402*7c478bd9Sstevel@tonic-gate 1403*7c478bd9Sstevel@tonic-gate nread = read(fd, buf, sizeof (buf)); 1404*7c478bd9Sstevel@tonic-gate if (nread > 0) { 1405*7c478bd9Sstevel@tonic-gate unsigned char *p; 1406*7c478bd9Sstevel@tonic-gate 1407*7c478bd9Sstevel@tonic-gate FD_SET(fd, &readfds); 1408*7c478bd9Sstevel@tonic-gate FD_SET(fd, &exceptfds); 1409*7c478bd9Sstevel@tonic-gate for (p = buf; p < buf + nread; p++) { 1410*7c478bd9Sstevel@tonic-gate if (trunc_at_nl && *p == '\n') 1411*7c478bd9Sstevel@tonic-gate goto out; 1412*7c478bd9Sstevel@tonic-gate if (PRINT_CHAR(*p)) 1413*7c478bd9Sstevel@tonic-gate (void) putchar((int)*p); 1414*7c478bd9Sstevel@tonic-gate else if (isascii(*p)) 1415*7c478bd9Sstevel@tonic-gate (void) fputs(unctrl(*p), 1416*7c478bd9Sstevel@tonic-gate stdout); 1417*7c478bd9Sstevel@tonic-gate } 1418*7c478bd9Sstevel@tonic-gate } else 1419*7c478bd9Sstevel@tonic-gate break; 1420*7c478bd9Sstevel@tonic-gate } 1421*7c478bd9Sstevel@tonic-gate out: 1422*7c478bd9Sstevel@tonic-gate (void) close(fd); 1423*7c478bd9Sstevel@tonic-gate } 1424*7c478bd9Sstevel@tonic-gate } else { 1425*7c478bd9Sstevel@tonic-gate int c; 1426*7c478bd9Sstevel@tonic-gate FILE *fp; 1427*7c478bd9Sstevel@tonic-gate 1428*7c478bd9Sstevel@tonic-gate fp = fopen(s, "r"); 1429*7c478bd9Sstevel@tonic-gate if (fp) { 1430*7c478bd9Sstevel@tonic-gate while ((c = getc(fp)) != EOF) { 1431*7c478bd9Sstevel@tonic-gate if (trunc_at_nl && c == '\n') 1432*7c478bd9Sstevel@tonic-gate break; 1433*7c478bd9Sstevel@tonic-gate if (PRINT_CHAR(c)) 1434*7c478bd9Sstevel@tonic-gate (void) putchar((int)c); 1435*7c478bd9Sstevel@tonic-gate else 1436*7c478bd9Sstevel@tonic-gate if (isascii(c)) 1437*7c478bd9Sstevel@tonic-gate (void) fputs(unctrl(c), stdout); 1438*7c478bd9Sstevel@tonic-gate } 1439*7c478bd9Sstevel@tonic-gate (void) fclose(fp); 1440*7c478bd9Sstevel@tonic-gate } 1441*7c478bd9Sstevel@tonic-gate } 1442*7c478bd9Sstevel@tonic-gate } 1443*7c478bd9Sstevel@tonic-gate 1444*7c478bd9Sstevel@tonic-gate 1445*7c478bd9Sstevel@tonic-gate void 1446*7c478bd9Sstevel@tonic-gate initscreening(void) 1447*7c478bd9Sstevel@tonic-gate { 1448*7c478bd9Sstevel@tonic-gate char *options, *value; 1449*7c478bd9Sstevel@tonic-gate 1450*7c478bd9Sstevel@tonic-gate if (defopen(defaultfile) == 0) { 1451*7c478bd9Sstevel@tonic-gate char *cp; 1452*7c478bd9Sstevel@tonic-gate int flags; 1453*7c478bd9Sstevel@tonic-gate 1454*7c478bd9Sstevel@tonic-gate /* 1455*7c478bd9Sstevel@tonic-gate * ignore case 1456*7c478bd9Sstevel@tonic-gate */ 1457*7c478bd9Sstevel@tonic-gate flags = defcntl(DC_GETFLAGS, 0); 1458*7c478bd9Sstevel@tonic-gate TURNOFF(flags, DC_CASE); 1459*7c478bd9Sstevel@tonic-gate defcntl(DC_SETFLAGS, flags); 1460*7c478bd9Sstevel@tonic-gate 1461*7c478bd9Sstevel@tonic-gate if (cp = defread(passvar)) { 1462*7c478bd9Sstevel@tonic-gate options = cp; 1463*7c478bd9Sstevel@tonic-gate while (*options != '\0') 1464*7c478bd9Sstevel@tonic-gate switch (getsubopt(&options, termopts, &value)) { 1465*7c478bd9Sstevel@tonic-gate case TERM_LOW: 1466*7c478bd9Sstevel@tonic-gate termpass |= TS_LOW; 1467*7c478bd9Sstevel@tonic-gate break; 1468*7c478bd9Sstevel@tonic-gate case TERM_HIGH: 1469*7c478bd9Sstevel@tonic-gate termpass |= TS_HIGH; 1470*7c478bd9Sstevel@tonic-gate break; 1471*7c478bd9Sstevel@tonic-gate } 1472*7c478bd9Sstevel@tonic-gate } 1473*7c478bd9Sstevel@tonic-gate (void) defopen(NULL); /* close default file */ 1474*7c478bd9Sstevel@tonic-gate } 1475*7c478bd9Sstevel@tonic-gate } 1476