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 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 23*7c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 24*7c478bd9Sstevel@tonic-gate 25*7c478bd9Sstevel@tonic-gate 26*7c478bd9Sstevel@tonic-gate /* 27*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 28*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 29*7c478bd9Sstevel@tonic-gate */ 30*7c478bd9Sstevel@tonic-gate 31*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 32*7c478bd9Sstevel@tonic-gate 33*7c478bd9Sstevel@tonic-gate /* 34*7c478bd9Sstevel@tonic-gate * This program analyzes information found in /var/adm/utmpx 35*7c478bd9Sstevel@tonic-gate * 36*7c478bd9Sstevel@tonic-gate * Additionally information is gathered from /etc/inittab 37*7c478bd9Sstevel@tonic-gate * if requested. 38*7c478bd9Sstevel@tonic-gate * 39*7c478bd9Sstevel@tonic-gate * 40*7c478bd9Sstevel@tonic-gate * Syntax: 41*7c478bd9Sstevel@tonic-gate * 42*7c478bd9Sstevel@tonic-gate * who am i Displays info on yourself 43*7c478bd9Sstevel@tonic-gate * 44*7c478bd9Sstevel@tonic-gate * who -a Displays information about All 45*7c478bd9Sstevel@tonic-gate * entries in /var/adm/utmpx 46*7c478bd9Sstevel@tonic-gate * 47*7c478bd9Sstevel@tonic-gate * who -b Displays info on last boot 48*7c478bd9Sstevel@tonic-gate * 49*7c478bd9Sstevel@tonic-gate * who -d Displays info on DEAD PROCESSES 50*7c478bd9Sstevel@tonic-gate * 51*7c478bd9Sstevel@tonic-gate * who -H Displays HEADERS for output 52*7c478bd9Sstevel@tonic-gate * 53*7c478bd9Sstevel@tonic-gate * who -l Displays info on LOGIN entries 54*7c478bd9Sstevel@tonic-gate * 55*7c478bd9Sstevel@tonic-gate * who -m Same as who am i 56*7c478bd9Sstevel@tonic-gate * 57*7c478bd9Sstevel@tonic-gate * who -p Displays info on PROCESSES spawned by init 58*7c478bd9Sstevel@tonic-gate * 59*7c478bd9Sstevel@tonic-gate * who -q Displays short information on 60*7c478bd9Sstevel@tonic-gate * current users who LOGGED ON 61*7c478bd9Sstevel@tonic-gate * 62*7c478bd9Sstevel@tonic-gate * who -r Displays info of current run-level 63*7c478bd9Sstevel@tonic-gate * 64*7c478bd9Sstevel@tonic-gate * who -s Displays requested info in SHORT form 65*7c478bd9Sstevel@tonic-gate * 66*7c478bd9Sstevel@tonic-gate * who -t Displays info on TIME changes 67*7c478bd9Sstevel@tonic-gate * 68*7c478bd9Sstevel@tonic-gate * who -T Displays writeability of each user 69*7c478bd9Sstevel@tonic-gate * (+ writeable, - non-writeable, ? hung) 70*7c478bd9Sstevel@tonic-gate * 71*7c478bd9Sstevel@tonic-gate * who -u Displays LONG info on users 72*7c478bd9Sstevel@tonic-gate * who have LOGGED ON 73*7c478bd9Sstevel@tonic-gate */ 74*7c478bd9Sstevel@tonic-gate 75*7c478bd9Sstevel@tonic-gate #define DATE_FMT "%b %e %H:%M" 76*7c478bd9Sstevel@tonic-gate 77*7c478bd9Sstevel@tonic-gate /* 78*7c478bd9Sstevel@tonic-gate * %b Abbreviated month name 79*7c478bd9Sstevel@tonic-gate * %e Day of month 80*7c478bd9Sstevel@tonic-gate * %H hour (24-hour clock) 81*7c478bd9Sstevel@tonic-gate * %M minute 82*7c478bd9Sstevel@tonic-gate */ 83*7c478bd9Sstevel@tonic-gate #include <errno.h> 84*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 85*7c478bd9Sstevel@tonic-gate #include <stdio.h> 86*7c478bd9Sstevel@tonic-gate #include <string.h> 87*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 88*7c478bd9Sstevel@tonic-gate #include <unistd.h> 89*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 90*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 91*7c478bd9Sstevel@tonic-gate #include <time.h> 92*7c478bd9Sstevel@tonic-gate #include <utmpx.h> 93*7c478bd9Sstevel@tonic-gate #include <locale.h> 94*7c478bd9Sstevel@tonic-gate #include <pwd.h> 95*7c478bd9Sstevel@tonic-gate #include <limits.h> 96*7c478bd9Sstevel@tonic-gate 97*7c478bd9Sstevel@tonic-gate static void process(void); 98*7c478bd9Sstevel@tonic-gate static void ck_file(char *); 99*7c478bd9Sstevel@tonic-gate static void dump(void); 100*7c478bd9Sstevel@tonic-gate 101*7c478bd9Sstevel@tonic-gate extern char *optarg; /* for getopt() */ 102*7c478bd9Sstevel@tonic-gate extern int optind; /* for getopt() */ 103*7c478bd9Sstevel@tonic-gate extern char *sys_errlist[]; /* error msgs for errno */ 104*7c478bd9Sstevel@tonic-gate static struct utmpx *utmpp; /* pointer for getutxent() */ 105*7c478bd9Sstevel@tonic-gate 106*7c478bd9Sstevel@tonic-gate /* 107*7c478bd9Sstevel@tonic-gate * utmpx defines wider fields for user and line. For compatibility of output, 108*7c478bd9Sstevel@tonic-gate * we are limiting these to the old maximums in utmp. Define UTMPX_NAMELEN 109*7c478bd9Sstevel@tonic-gate * to use the full lengths. 110*7c478bd9Sstevel@tonic-gate */ 111*7c478bd9Sstevel@tonic-gate #ifndef UTMPX_NAMELEN 112*7c478bd9Sstevel@tonic-gate /* XXX - utmp - fix name length */ 113*7c478bd9Sstevel@tonic-gate #define NMAX (_POSIX_LOGIN_NAME_MAX - 1) 114*7c478bd9Sstevel@tonic-gate #define LMAX 12 115*7c478bd9Sstevel@tonic-gate #else /* UTMPX_NAMELEN */ 116*7c478bd9Sstevel@tonic-gate #define NMAX (sizeof (utmpp->ut_user)) 117*7c478bd9Sstevel@tonic-gate #define LMAX (sizeof (utmpp->ut_line)) 118*7c478bd9Sstevel@tonic-gate #endif 119*7c478bd9Sstevel@tonic-gate 120*7c478bd9Sstevel@tonic-gate static char comment[BUFSIZ]; /* holds inittab comment */ 121*7c478bd9Sstevel@tonic-gate static char errmsg[BUFSIZ]; /* used in snprintf for errors */ 122*7c478bd9Sstevel@tonic-gate static int fildes; /* file descriptor for inittab */ 123*7c478bd9Sstevel@tonic-gate static int Hopt = 0; /* 1 = who -H */ 124*7c478bd9Sstevel@tonic-gate static char *inittab; /* ptr to inittab contents */ 125*7c478bd9Sstevel@tonic-gate static char *iinit; /* index into inittab */ 126*7c478bd9Sstevel@tonic-gate static int justme = 0; /* 1 = who am i */ 127*7c478bd9Sstevel@tonic-gate static struct tm *lptr; /* holds user login time */ 128*7c478bd9Sstevel@tonic-gate static char *myname; /* pointer to invoker's name */ 129*7c478bd9Sstevel@tonic-gate static char *mytty; /* holds device user is on */ 130*7c478bd9Sstevel@tonic-gate static char nameval[sizeof (utmpp->ut_user) + 1]; /* invoker's name */ 131*7c478bd9Sstevel@tonic-gate static int number = 8; /* number of users per -q line */ 132*7c478bd9Sstevel@tonic-gate static int optcnt = 0; /* keeps count of options */ 133*7c478bd9Sstevel@tonic-gate static char outbuf[BUFSIZ]; /* buffer for output */ 134*7c478bd9Sstevel@tonic-gate static char *program; /* holds name of this program */ 135*7c478bd9Sstevel@tonic-gate #ifdef XPG4 136*7c478bd9Sstevel@tonic-gate static int aopt = 0; /* 1 = who -a */ 137*7c478bd9Sstevel@tonic-gate static int dopt = 0; /* 1 = who -d */ 138*7c478bd9Sstevel@tonic-gate #endif /* XPG4 */ 139*7c478bd9Sstevel@tonic-gate static int qopt = 0; /* 1 = who -q */ 140*7c478bd9Sstevel@tonic-gate static int sopt = 0; /* 1 = who -s */ 141*7c478bd9Sstevel@tonic-gate static struct stat stbuf; /* area for stat buffer */ 142*7c478bd9Sstevel@tonic-gate static struct stat *stbufp; /* ptr to structure */ 143*7c478bd9Sstevel@tonic-gate static int terse = 1; /* 1 = print terse msgs */ 144*7c478bd9Sstevel@tonic-gate static int Topt = 0; /* 1 = who -T */ 145*7c478bd9Sstevel@tonic-gate static time_t timnow; /* holds current time */ 146*7c478bd9Sstevel@tonic-gate static int totlusrs = 0; /* cntr for users on system */ 147*7c478bd9Sstevel@tonic-gate static int uopt = 0; /* 1 = who -u */ 148*7c478bd9Sstevel@tonic-gate static char user[sizeof (utmpp->ut_user) + 1]; /* holds user name */ 149*7c478bd9Sstevel@tonic-gate static int validtype[UTMAXTYPE+1]; /* holds valid types */ 150*7c478bd9Sstevel@tonic-gate static int wrap; /* flag to indicate wrap */ 151*7c478bd9Sstevel@tonic-gate static char time_buf[128]; /* holds date and time string */ 152*7c478bd9Sstevel@tonic-gate static char *end; /* used in strtol for end pointer */ 153*7c478bd9Sstevel@tonic-gate 154*7c478bd9Sstevel@tonic-gate int 155*7c478bd9Sstevel@tonic-gate main(int argc, char **argv) 156*7c478bd9Sstevel@tonic-gate { 157*7c478bd9Sstevel@tonic-gate int goerr = 0; /* non-zero indicates cmd error */ 158*7c478bd9Sstevel@tonic-gate int i; 159*7c478bd9Sstevel@tonic-gate int optsw; /* switch for while of getopt() */ 160*7c478bd9Sstevel@tonic-gate 161*7c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 162*7c478bd9Sstevel@tonic-gate 163*7c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 164*7c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 165*7c478bd9Sstevel@tonic-gate #endif 166*7c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 167*7c478bd9Sstevel@tonic-gate 168*7c478bd9Sstevel@tonic-gate validtype[USER_PROCESS] = 1; 169*7c478bd9Sstevel@tonic-gate validtype[EMPTY] = 0; 170*7c478bd9Sstevel@tonic-gate stbufp = &stbuf; 171*7c478bd9Sstevel@tonic-gate 172*7c478bd9Sstevel@tonic-gate /* 173*7c478bd9Sstevel@tonic-gate * Strip off path name of this command 174*7c478bd9Sstevel@tonic-gate */ 175*7c478bd9Sstevel@tonic-gate for (i = strlen(argv[0]); i >= 0 && argv[0][i] != '/'; --i); 176*7c478bd9Sstevel@tonic-gate if (i >= 0) 177*7c478bd9Sstevel@tonic-gate argv[0] += i+1; 178*7c478bd9Sstevel@tonic-gate program = argv[0]; 179*7c478bd9Sstevel@tonic-gate 180*7c478bd9Sstevel@tonic-gate /* 181*7c478bd9Sstevel@tonic-gate * Buffer stdout for speed 182*7c478bd9Sstevel@tonic-gate */ 183*7c478bd9Sstevel@tonic-gate setbuf(stdout, outbuf); 184*7c478bd9Sstevel@tonic-gate 185*7c478bd9Sstevel@tonic-gate /* 186*7c478bd9Sstevel@tonic-gate * Retrieve options specified on command line 187*7c478bd9Sstevel@tonic-gate * XCU4 - add -m option 188*7c478bd9Sstevel@tonic-gate */ 189*7c478bd9Sstevel@tonic-gate while ((optsw = getopt(argc, argv, "abdHlmn:pqrstTu")) != EOF) { 190*7c478bd9Sstevel@tonic-gate optcnt++; 191*7c478bd9Sstevel@tonic-gate switch (optsw) { 192*7c478bd9Sstevel@tonic-gate 193*7c478bd9Sstevel@tonic-gate case 'a': 194*7c478bd9Sstevel@tonic-gate optcnt += 7; 195*7c478bd9Sstevel@tonic-gate validtype[BOOT_TIME] = 1; 196*7c478bd9Sstevel@tonic-gate validtype[DEAD_PROCESS] = 1; 197*7c478bd9Sstevel@tonic-gate validtype[LOGIN_PROCESS] = 1; 198*7c478bd9Sstevel@tonic-gate validtype[INIT_PROCESS] = 1; 199*7c478bd9Sstevel@tonic-gate validtype[RUN_LVL] = 1; 200*7c478bd9Sstevel@tonic-gate validtype[OLD_TIME] = 1; 201*7c478bd9Sstevel@tonic-gate validtype[NEW_TIME] = 1; 202*7c478bd9Sstevel@tonic-gate validtype[USER_PROCESS] = 1; 203*7c478bd9Sstevel@tonic-gate #ifdef XPG4 204*7c478bd9Sstevel@tonic-gate aopt = 1; 205*7c478bd9Sstevel@tonic-gate #endif /* XPG4 */ 206*7c478bd9Sstevel@tonic-gate uopt = 1; 207*7c478bd9Sstevel@tonic-gate Topt = 1; 208*7c478bd9Sstevel@tonic-gate if (!sopt) terse = 0; 209*7c478bd9Sstevel@tonic-gate break; 210*7c478bd9Sstevel@tonic-gate 211*7c478bd9Sstevel@tonic-gate case 'b': 212*7c478bd9Sstevel@tonic-gate validtype[BOOT_TIME] = 1; 213*7c478bd9Sstevel@tonic-gate if (!uopt) validtype[USER_PROCESS] = 0; 214*7c478bd9Sstevel@tonic-gate break; 215*7c478bd9Sstevel@tonic-gate 216*7c478bd9Sstevel@tonic-gate case 'd': 217*7c478bd9Sstevel@tonic-gate validtype[DEAD_PROCESS] = 1; 218*7c478bd9Sstevel@tonic-gate if (!uopt) validtype[USER_PROCESS] = 0; 219*7c478bd9Sstevel@tonic-gate #ifdef XPG4 220*7c478bd9Sstevel@tonic-gate dopt = 1; 221*7c478bd9Sstevel@tonic-gate #endif /* XPG4 */ 222*7c478bd9Sstevel@tonic-gate break; 223*7c478bd9Sstevel@tonic-gate 224*7c478bd9Sstevel@tonic-gate case 'H': 225*7c478bd9Sstevel@tonic-gate optcnt--; /* Don't count Header */ 226*7c478bd9Sstevel@tonic-gate Hopt = 1; 227*7c478bd9Sstevel@tonic-gate break; 228*7c478bd9Sstevel@tonic-gate 229*7c478bd9Sstevel@tonic-gate case 'l': 230*7c478bd9Sstevel@tonic-gate validtype[LOGIN_PROCESS] = 1; 231*7c478bd9Sstevel@tonic-gate if (!uopt) validtype[USER_PROCESS] = 0; 232*7c478bd9Sstevel@tonic-gate terse = 0; 233*7c478bd9Sstevel@tonic-gate break; 234*7c478bd9Sstevel@tonic-gate case 'm': /* New XCU4 option */ 235*7c478bd9Sstevel@tonic-gate justme = 1; 236*7c478bd9Sstevel@tonic-gate break; 237*7c478bd9Sstevel@tonic-gate 238*7c478bd9Sstevel@tonic-gate case 'n': 239*7c478bd9Sstevel@tonic-gate errno = 0; 240*7c478bd9Sstevel@tonic-gate number = strtol(optarg, &end, 10); 241*7c478bd9Sstevel@tonic-gate if (errno != 0 || *end != '\0') { 242*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 243*7c478bd9Sstevel@tonic-gate "%s: Invalid numeric argument\n"), 244*7c478bd9Sstevel@tonic-gate program); 245*7c478bd9Sstevel@tonic-gate exit(1); 246*7c478bd9Sstevel@tonic-gate } 247*7c478bd9Sstevel@tonic-gate if (number < 1) { 248*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 249*7c478bd9Sstevel@tonic-gate "%s: Number of users per line must " 250*7c478bd9Sstevel@tonic-gate "be at least 1\n"), program); 251*7c478bd9Sstevel@tonic-gate exit(1); 252*7c478bd9Sstevel@tonic-gate } 253*7c478bd9Sstevel@tonic-gate break; 254*7c478bd9Sstevel@tonic-gate 255*7c478bd9Sstevel@tonic-gate case 'p': 256*7c478bd9Sstevel@tonic-gate validtype[INIT_PROCESS] = 1; 257*7c478bd9Sstevel@tonic-gate if (!uopt) validtype[USER_PROCESS] = 0; 258*7c478bd9Sstevel@tonic-gate break; 259*7c478bd9Sstevel@tonic-gate 260*7c478bd9Sstevel@tonic-gate case 'q': 261*7c478bd9Sstevel@tonic-gate qopt = 1; 262*7c478bd9Sstevel@tonic-gate break; 263*7c478bd9Sstevel@tonic-gate 264*7c478bd9Sstevel@tonic-gate case 'r': 265*7c478bd9Sstevel@tonic-gate validtype[RUN_LVL] = 1; 266*7c478bd9Sstevel@tonic-gate terse = 0; 267*7c478bd9Sstevel@tonic-gate if (!uopt) validtype[USER_PROCESS] = 0; 268*7c478bd9Sstevel@tonic-gate break; 269*7c478bd9Sstevel@tonic-gate 270*7c478bd9Sstevel@tonic-gate case 's': 271*7c478bd9Sstevel@tonic-gate sopt = 1; 272*7c478bd9Sstevel@tonic-gate terse = 1; 273*7c478bd9Sstevel@tonic-gate break; 274*7c478bd9Sstevel@tonic-gate 275*7c478bd9Sstevel@tonic-gate case 't': 276*7c478bd9Sstevel@tonic-gate validtype[OLD_TIME] = 1; 277*7c478bd9Sstevel@tonic-gate validtype[NEW_TIME] = 1; 278*7c478bd9Sstevel@tonic-gate if (!uopt) validtype[USER_PROCESS] = 0; 279*7c478bd9Sstevel@tonic-gate break; 280*7c478bd9Sstevel@tonic-gate 281*7c478bd9Sstevel@tonic-gate case 'T': 282*7c478bd9Sstevel@tonic-gate Topt = 1; 283*7c478bd9Sstevel@tonic-gate #ifdef XPG4 284*7c478bd9Sstevel@tonic-gate terse = 1; /* XPG4 requires -T */ 285*7c478bd9Sstevel@tonic-gate #else /* XPG4 */ 286*7c478bd9Sstevel@tonic-gate terse = 0; 287*7c478bd9Sstevel@tonic-gate #endif /* XPG4 */ 288*7c478bd9Sstevel@tonic-gate break; 289*7c478bd9Sstevel@tonic-gate 290*7c478bd9Sstevel@tonic-gate case 'u': 291*7c478bd9Sstevel@tonic-gate uopt = 1; 292*7c478bd9Sstevel@tonic-gate validtype[USER_PROCESS] = 1; 293*7c478bd9Sstevel@tonic-gate if (!sopt) terse = 0; 294*7c478bd9Sstevel@tonic-gate break; 295*7c478bd9Sstevel@tonic-gate 296*7c478bd9Sstevel@tonic-gate case '?': 297*7c478bd9Sstevel@tonic-gate goerr++; 298*7c478bd9Sstevel@tonic-gate break; 299*7c478bd9Sstevel@tonic-gate default: 300*7c478bd9Sstevel@tonic-gate break; 301*7c478bd9Sstevel@tonic-gate } 302*7c478bd9Sstevel@tonic-gate } 303*7c478bd9Sstevel@tonic-gate #ifdef XPG4 304*7c478bd9Sstevel@tonic-gate /* 305*7c478bd9Sstevel@tonic-gate * XCU4 changes - check for illegal sopt, Topt & aopt combination 306*7c478bd9Sstevel@tonic-gate */ 307*7c478bd9Sstevel@tonic-gate if (sopt == 1) { 308*7c478bd9Sstevel@tonic-gate terse = 1; 309*7c478bd9Sstevel@tonic-gate if (Topt == 1 || aopt == 1) 310*7c478bd9Sstevel@tonic-gate goerr++; 311*7c478bd9Sstevel@tonic-gate } 312*7c478bd9Sstevel@tonic-gate #endif /* XPG4 */ 313*7c478bd9Sstevel@tonic-gate 314*7c478bd9Sstevel@tonic-gate if (goerr > 0) { 315*7c478bd9Sstevel@tonic-gate #ifdef XPG4 316*7c478bd9Sstevel@tonic-gate /* 317*7c478bd9Sstevel@tonic-gate * XCU4 - slightly different usage with -s -a & -T 318*7c478bd9Sstevel@tonic-gate */ 319*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("\nUsage:\t%s"), program); 320*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 321*7c478bd9Sstevel@tonic-gate gettext(" -s [-bdHlmpqrtu] [utmpx_like_file]\n")); 322*7c478bd9Sstevel@tonic-gate 323*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 324*7c478bd9Sstevel@tonic-gate "\t%s [-abdHlmpqrtTu] [utmpx_like_file]\n"), program); 325*7c478bd9Sstevel@tonic-gate #else /* XPG4 */ 326*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 327*7c478bd9Sstevel@tonic-gate "\nUsage:\t%s [-abdHlmpqrstTu] [utmpx_like_file]\n"), 328*7c478bd9Sstevel@tonic-gate program); 329*7c478bd9Sstevel@tonic-gate #endif /* XPG4 */ 330*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 331*7c478bd9Sstevel@tonic-gate gettext("\t%s -q [-n x] [utmpx_like_file]\n"), program); 332*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("\t%s [am i]\n"), program); 333*7c478bd9Sstevel@tonic-gate /* 334*7c478bd9Sstevel@tonic-gate * XCU4 changes - be explicit with "am i" options 335*7c478bd9Sstevel@tonic-gate */ 336*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("\t%s [am I]\n"), program); 337*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 338*7c478bd9Sstevel@tonic-gate "a\tall (bdlprtu options)\n")); 339*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("b\tboot time\n")); 340*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("d\tdead processes\n")); 341*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("H\tprint header\n")); 342*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("l\tlogin processes\n")); 343*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 344*7c478bd9Sstevel@tonic-gate "n #\tspecify number of users per line for -q\n")); 345*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 346*7c478bd9Sstevel@tonic-gate gettext("p\tprocesses other than getty or users\n")); 347*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("q\tquick %s\n"), program); 348*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("r\trun level\n")); 349*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 350*7c478bd9Sstevel@tonic-gate "s\tshort form of %s (no time since last output or pid)\n"), 351*7c478bd9Sstevel@tonic-gate program); 352*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("t\ttime changes\n")); 353*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 354*7c478bd9Sstevel@tonic-gate "T\tstatus of tty (+ writable, - not writable, " 355*7c478bd9Sstevel@tonic-gate "? hung)\n")); 356*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("u\tuseful information\n")); 357*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 358*7c478bd9Sstevel@tonic-gate gettext("m\tinformation only about current terminal\n")); 359*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 360*7c478bd9Sstevel@tonic-gate "am i\tinformation about current terminal " 361*7c478bd9Sstevel@tonic-gate "(same as -m)\n")); 362*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 363*7c478bd9Sstevel@tonic-gate "am I\tinformation about current terminal " 364*7c478bd9Sstevel@tonic-gate "(same as -m)\n")); 365*7c478bd9Sstevel@tonic-gate exit(1); 366*7c478bd9Sstevel@tonic-gate } 367*7c478bd9Sstevel@tonic-gate 368*7c478bd9Sstevel@tonic-gate /* 369*7c478bd9Sstevel@tonic-gate * XCU4: If -q option ignore all other options 370*7c478bd9Sstevel@tonic-gate */ 371*7c478bd9Sstevel@tonic-gate if (qopt == 1) { 372*7c478bd9Sstevel@tonic-gate Hopt = 0; 373*7c478bd9Sstevel@tonic-gate sopt = 0; 374*7c478bd9Sstevel@tonic-gate Topt = 0; 375*7c478bd9Sstevel@tonic-gate uopt = 0; 376*7c478bd9Sstevel@tonic-gate justme = 0; 377*7c478bd9Sstevel@tonic-gate validtype[ACCOUNTING] = 0; 378*7c478bd9Sstevel@tonic-gate validtype[BOOT_TIME] = 0; 379*7c478bd9Sstevel@tonic-gate validtype[DEAD_PROCESS] = 0; 380*7c478bd9Sstevel@tonic-gate validtype[LOGIN_PROCESS] = 0; 381*7c478bd9Sstevel@tonic-gate validtype[INIT_PROCESS] = 0; 382*7c478bd9Sstevel@tonic-gate validtype[RUN_LVL] = 0; 383*7c478bd9Sstevel@tonic-gate validtype[OLD_TIME] = 0; 384*7c478bd9Sstevel@tonic-gate validtype[NEW_TIME] = 0; 385*7c478bd9Sstevel@tonic-gate validtype[USER_PROCESS] = 1; 386*7c478bd9Sstevel@tonic-gate } 387*7c478bd9Sstevel@tonic-gate 388*7c478bd9Sstevel@tonic-gate if (argc == optind + 1) { 389*7c478bd9Sstevel@tonic-gate optcnt++; 390*7c478bd9Sstevel@tonic-gate ck_file(argv[optind]); 391*7c478bd9Sstevel@tonic-gate (void) utmpxname(argv[optind]); 392*7c478bd9Sstevel@tonic-gate } 393*7c478bd9Sstevel@tonic-gate 394*7c478bd9Sstevel@tonic-gate /* 395*7c478bd9Sstevel@tonic-gate * Test for 'who am i' or 'who am I' 396*7c478bd9Sstevel@tonic-gate * XCU4 - check if justme was already set by -m option 397*7c478bd9Sstevel@tonic-gate */ 398*7c478bd9Sstevel@tonic-gate if (justme == 1 || (argc == 3 && strcmp(argv[1], "am") == 0 && 399*7c478bd9Sstevel@tonic-gate ((argv[2][0] == 'i' || argv[2][0] == 'I') && 400*7c478bd9Sstevel@tonic-gate argv[2][1] == '\0'))) { 401*7c478bd9Sstevel@tonic-gate justme = 1; 402*7c478bd9Sstevel@tonic-gate myname = nameval; 403*7c478bd9Sstevel@tonic-gate (void) cuserid(myname); 404*7c478bd9Sstevel@tonic-gate if ((mytty = ttyname(fileno(stdin))) == NULL && 405*7c478bd9Sstevel@tonic-gate (mytty = ttyname(fileno(stdout))) == NULL && 406*7c478bd9Sstevel@tonic-gate (mytty = ttyname(fileno(stderr))) == NULL) { 407*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 408*7c478bd9Sstevel@tonic-gate "Must be attached to terminal for 'am I' option\n")); 409*7c478bd9Sstevel@tonic-gate (void) fflush(stderr); 410*7c478bd9Sstevel@tonic-gate exit(1); 411*7c478bd9Sstevel@tonic-gate } else 412*7c478bd9Sstevel@tonic-gate mytty += 5; /* bump past "/dev/" */ 413*7c478bd9Sstevel@tonic-gate } 414*7c478bd9Sstevel@tonic-gate 415*7c478bd9Sstevel@tonic-gate if (!terse) { 416*7c478bd9Sstevel@tonic-gate if (Hopt) 417*7c478bd9Sstevel@tonic-gate (void) printf(gettext( 418*7c478bd9Sstevel@tonic-gate "NAME LINE TIME IDLE PID COMMENTS\n")); 419*7c478bd9Sstevel@tonic-gate 420*7c478bd9Sstevel@tonic-gate timnow = time(0); 421*7c478bd9Sstevel@tonic-gate 422*7c478bd9Sstevel@tonic-gate if ((fildes = open("/etc/inittab", 423*7c478bd9Sstevel@tonic-gate O_NONBLOCK|O_RDONLY)) == -1) { 424*7c478bd9Sstevel@tonic-gate (void) snprintf(errmsg, sizeof (errmsg), 425*7c478bd9Sstevel@tonic-gate gettext("%s: Cannot open /etc/inittab"), program); 426*7c478bd9Sstevel@tonic-gate perror(errmsg); 427*7c478bd9Sstevel@tonic-gate exit(errno); 428*7c478bd9Sstevel@tonic-gate } 429*7c478bd9Sstevel@tonic-gate 430*7c478bd9Sstevel@tonic-gate if (fstat(fildes, stbufp) == -1) { 431*7c478bd9Sstevel@tonic-gate (void) snprintf(errmsg, sizeof (errmsg), 432*7c478bd9Sstevel@tonic-gate gettext("%s: Cannot stat /etc/inittab"), program); 433*7c478bd9Sstevel@tonic-gate perror(errmsg); 434*7c478bd9Sstevel@tonic-gate exit(errno); 435*7c478bd9Sstevel@tonic-gate } 436*7c478bd9Sstevel@tonic-gate 437*7c478bd9Sstevel@tonic-gate if ((inittab = malloc(stbufp->st_size + 1)) == NULL) { 438*7c478bd9Sstevel@tonic-gate (void) snprintf(errmsg, sizeof (errmsg), 439*7c478bd9Sstevel@tonic-gate gettext("%s: Cannot allocate %ld bytes"), 440*7c478bd9Sstevel@tonic-gate program, stbufp->st_size); 441*7c478bd9Sstevel@tonic-gate perror(errmsg); 442*7c478bd9Sstevel@tonic-gate exit(errno); 443*7c478bd9Sstevel@tonic-gate } 444*7c478bd9Sstevel@tonic-gate 445*7c478bd9Sstevel@tonic-gate if (read(fildes, inittab, stbufp->st_size) 446*7c478bd9Sstevel@tonic-gate != stbufp->st_size) { 447*7c478bd9Sstevel@tonic-gate (void) snprintf(errmsg, sizeof (errmsg), 448*7c478bd9Sstevel@tonic-gate gettext("%s: Error reading /etc/inittab"), 449*7c478bd9Sstevel@tonic-gate program); 450*7c478bd9Sstevel@tonic-gate perror(errmsg); 451*7c478bd9Sstevel@tonic-gate exit(errno); 452*7c478bd9Sstevel@tonic-gate } 453*7c478bd9Sstevel@tonic-gate 454*7c478bd9Sstevel@tonic-gate inittab[stbufp->st_size] = '\0'; 455*7c478bd9Sstevel@tonic-gate iinit = inittab; 456*7c478bd9Sstevel@tonic-gate } else { 457*7c478bd9Sstevel@tonic-gate if (Hopt) { 458*7c478bd9Sstevel@tonic-gate #ifdef XPG4 459*7c478bd9Sstevel@tonic-gate if (dopt) { 460*7c478bd9Sstevel@tonic-gate (void) printf(gettext( 461*7c478bd9Sstevel@tonic-gate "NAME LINE TIME COMMENTS\n")); 462*7c478bd9Sstevel@tonic-gate } else { 463*7c478bd9Sstevel@tonic-gate (void) printf( 464*7c478bd9Sstevel@tonic-gate gettext("NAME LINE TIME\n")); 465*7c478bd9Sstevel@tonic-gate } 466*7c478bd9Sstevel@tonic-gate #else /* XPG4 */ 467*7c478bd9Sstevel@tonic-gate (void) printf( 468*7c478bd9Sstevel@tonic-gate gettext("NAME LINE TIME\n")); 469*7c478bd9Sstevel@tonic-gate #endif /* XPG4 */ 470*7c478bd9Sstevel@tonic-gate } 471*7c478bd9Sstevel@tonic-gate } 472*7c478bd9Sstevel@tonic-gate process(); 473*7c478bd9Sstevel@tonic-gate 474*7c478bd9Sstevel@tonic-gate /* 475*7c478bd9Sstevel@tonic-gate * 'who -q' requires EOL upon exit, 476*7c478bd9Sstevel@tonic-gate * followed by total line 477*7c478bd9Sstevel@tonic-gate */ 478*7c478bd9Sstevel@tonic-gate if (qopt) 479*7c478bd9Sstevel@tonic-gate (void) printf(gettext("\n# users=%d\n"), totlusrs); 480*7c478bd9Sstevel@tonic-gate return (0); 481*7c478bd9Sstevel@tonic-gate } 482*7c478bd9Sstevel@tonic-gate 483*7c478bd9Sstevel@tonic-gate static void 484*7c478bd9Sstevel@tonic-gate dump() 485*7c478bd9Sstevel@tonic-gate { 486*7c478bd9Sstevel@tonic-gate char device[sizeof (utmpp->ut_line) + 1]; 487*7c478bd9Sstevel@tonic-gate time_t hr; 488*7c478bd9Sstevel@tonic-gate time_t idle; 489*7c478bd9Sstevel@tonic-gate time_t min; 490*7c478bd9Sstevel@tonic-gate char path[sizeof (utmpp->ut_line) + 6]; 491*7c478bd9Sstevel@tonic-gate int pexit; 492*7c478bd9Sstevel@tonic-gate int pterm; 493*7c478bd9Sstevel@tonic-gate int rc; 494*7c478bd9Sstevel@tonic-gate char w; /* writeability indicator */ 495*7c478bd9Sstevel@tonic-gate 496*7c478bd9Sstevel@tonic-gate /* 497*7c478bd9Sstevel@tonic-gate * Get and check user name 498*7c478bd9Sstevel@tonic-gate */ 499*7c478bd9Sstevel@tonic-gate if (utmpp->ut_user[0] == '\0') 500*7c478bd9Sstevel@tonic-gate (void) strcpy(user, " ."); 501*7c478bd9Sstevel@tonic-gate else { 502*7c478bd9Sstevel@tonic-gate (void) strncpy(user, utmpp->ut_user, sizeof (user)); 503*7c478bd9Sstevel@tonic-gate user[sizeof (user) - 1] = '\0'; 504*7c478bd9Sstevel@tonic-gate } 505*7c478bd9Sstevel@tonic-gate totlusrs++; 506*7c478bd9Sstevel@tonic-gate 507*7c478bd9Sstevel@tonic-gate /* 508*7c478bd9Sstevel@tonic-gate * Do print in 'who -q' format 509*7c478bd9Sstevel@tonic-gate */ 510*7c478bd9Sstevel@tonic-gate if (qopt) { 511*7c478bd9Sstevel@tonic-gate /* 512*7c478bd9Sstevel@tonic-gate * XCU4 - Use non user macro for correct user count 513*7c478bd9Sstevel@tonic-gate */ 514*7c478bd9Sstevel@tonic-gate if (((totlusrs - 1) % number) == 0 && totlusrs > 1) 515*7c478bd9Sstevel@tonic-gate (void) printf("\n"); 516*7c478bd9Sstevel@tonic-gate (void) printf("%-*s ", NMAX, user); 517*7c478bd9Sstevel@tonic-gate return; 518*7c478bd9Sstevel@tonic-gate } 519*7c478bd9Sstevel@tonic-gate 520*7c478bd9Sstevel@tonic-gate 521*7c478bd9Sstevel@tonic-gate pexit = (int)' '; 522*7c478bd9Sstevel@tonic-gate pterm = (int)' '; 523*7c478bd9Sstevel@tonic-gate 524*7c478bd9Sstevel@tonic-gate /* 525*7c478bd9Sstevel@tonic-gate * Get exit info if applicable 526*7c478bd9Sstevel@tonic-gate */ 527*7c478bd9Sstevel@tonic-gate if (utmpp->ut_type == RUN_LVL || utmpp->ut_type == DEAD_PROCESS) { 528*7c478bd9Sstevel@tonic-gate pterm = utmpp->ut_exit.e_termination; 529*7c478bd9Sstevel@tonic-gate pexit = utmpp->ut_exit.e_exit; 530*7c478bd9Sstevel@tonic-gate } 531*7c478bd9Sstevel@tonic-gate 532*7c478bd9Sstevel@tonic-gate /* 533*7c478bd9Sstevel@tonic-gate * Massage ut_xtime field 534*7c478bd9Sstevel@tonic-gate */ 535*7c478bd9Sstevel@tonic-gate lptr = localtime(&utmpp->ut_xtime); 536*7c478bd9Sstevel@tonic-gate (void) strftime(time_buf, sizeof (time_buf), 537*7c478bd9Sstevel@tonic-gate dcgettext(NULL, DATE_FMT, LC_TIME), lptr); 538*7c478bd9Sstevel@tonic-gate 539*7c478bd9Sstevel@tonic-gate /* 540*7c478bd9Sstevel@tonic-gate * Get and massage device 541*7c478bd9Sstevel@tonic-gate */ 542*7c478bd9Sstevel@tonic-gate if (utmpp->ut_line[0] == '\0') 543*7c478bd9Sstevel@tonic-gate (void) strcpy(device, " ."); 544*7c478bd9Sstevel@tonic-gate else { 545*7c478bd9Sstevel@tonic-gate (void) strncpy(device, utmpp->ut_line, 546*7c478bd9Sstevel@tonic-gate sizeof (utmpp->ut_line)); 547*7c478bd9Sstevel@tonic-gate device[sizeof (utmpp->ut_line)] = '\0'; 548*7c478bd9Sstevel@tonic-gate } 549*7c478bd9Sstevel@tonic-gate 550*7c478bd9Sstevel@tonic-gate /* 551*7c478bd9Sstevel@tonic-gate * Get writeability if requested 552*7c478bd9Sstevel@tonic-gate * XCU4 - only print + or - for user processes 553*7c478bd9Sstevel@tonic-gate */ 554*7c478bd9Sstevel@tonic-gate if (Topt && (utmpp->ut_type == USER_PROCESS)) { 555*7c478bd9Sstevel@tonic-gate w = '-'; 556*7c478bd9Sstevel@tonic-gate (void) strcpy(path, "/dev/"); 557*7c478bd9Sstevel@tonic-gate (void) strncpy(path + 5, utmpp->ut_line, 558*7c478bd9Sstevel@tonic-gate sizeof (utmpp->ut_line)); 559*7c478bd9Sstevel@tonic-gate path[5 + sizeof (utmpp->ut_line)] = '\0'; 560*7c478bd9Sstevel@tonic-gate 561*7c478bd9Sstevel@tonic-gate if ((rc = stat(path, stbufp)) == -1) w = '?'; 562*7c478bd9Sstevel@tonic-gate else if ((stbufp->st_mode & S_IWOTH) || 563*7c478bd9Sstevel@tonic-gate (stbufp->st_mode & S_IWGRP)) /* Check group & other */ 564*7c478bd9Sstevel@tonic-gate w = '+'; 565*7c478bd9Sstevel@tonic-gate 566*7c478bd9Sstevel@tonic-gate } else 567*7c478bd9Sstevel@tonic-gate w = ' '; 568*7c478bd9Sstevel@tonic-gate 569*7c478bd9Sstevel@tonic-gate /* 570*7c478bd9Sstevel@tonic-gate * Print the TERSE portion of the output 571*7c478bd9Sstevel@tonic-gate */ 572*7c478bd9Sstevel@tonic-gate (void) printf("%-*s %c %-12s %s", NMAX, user, w, device, time_buf); 573*7c478bd9Sstevel@tonic-gate 574*7c478bd9Sstevel@tonic-gate if (!terse) { 575*7c478bd9Sstevel@tonic-gate (void) strcpy(path, "/dev/"); 576*7c478bd9Sstevel@tonic-gate (void) strncpy(path + 5, utmpp->ut_line, 577*7c478bd9Sstevel@tonic-gate sizeof (utmpp->ut_line)); 578*7c478bd9Sstevel@tonic-gate path[5 + sizeof (utmpp->ut_line)] = '\0'; 579*7c478bd9Sstevel@tonic-gate 580*7c478bd9Sstevel@tonic-gate /* 581*7c478bd9Sstevel@tonic-gate * Stat device for idle time 582*7c478bd9Sstevel@tonic-gate * (Don't complain if you can't) 583*7c478bd9Sstevel@tonic-gate */ 584*7c478bd9Sstevel@tonic-gate if ((rc = stat(path, stbufp)) != -1) { 585*7c478bd9Sstevel@tonic-gate idle = timnow - stbufp->st_mtime; 586*7c478bd9Sstevel@tonic-gate hr = idle/3600; 587*7c478bd9Sstevel@tonic-gate min = (unsigned)(idle/60)%60; 588*7c478bd9Sstevel@tonic-gate if (hr == 0 && min == 0) 589*7c478bd9Sstevel@tonic-gate (void) printf(gettext(" . ")); 590*7c478bd9Sstevel@tonic-gate else { 591*7c478bd9Sstevel@tonic-gate if (hr < 24) 592*7c478bd9Sstevel@tonic-gate (void) printf(" %2d:%2.2d", (int)hr, 593*7c478bd9Sstevel@tonic-gate (int)min); 594*7c478bd9Sstevel@tonic-gate else 595*7c478bd9Sstevel@tonic-gate (void) printf(gettext(" old ")); 596*7c478bd9Sstevel@tonic-gate } 597*7c478bd9Sstevel@tonic-gate } 598*7c478bd9Sstevel@tonic-gate 599*7c478bd9Sstevel@tonic-gate /* 600*7c478bd9Sstevel@tonic-gate * Add PID for verbose output 601*7c478bd9Sstevel@tonic-gate */ 602*7c478bd9Sstevel@tonic-gate if (utmpp->ut_type != BOOT_TIME && 603*7c478bd9Sstevel@tonic-gate utmpp->ut_type != RUN_LVL && 604*7c478bd9Sstevel@tonic-gate utmpp->ut_type != ACCOUNTING) 605*7c478bd9Sstevel@tonic-gate (void) printf(" %5ld", utmpp->ut_pid); 606*7c478bd9Sstevel@tonic-gate 607*7c478bd9Sstevel@tonic-gate /* 608*7c478bd9Sstevel@tonic-gate * Handle /etc/inittab comment 609*7c478bd9Sstevel@tonic-gate */ 610*7c478bd9Sstevel@tonic-gate if (utmpp->ut_type == DEAD_PROCESS) { 611*7c478bd9Sstevel@tonic-gate (void) printf(gettext(" id=%4.4s "), 612*7c478bd9Sstevel@tonic-gate utmpp->ut_id); 613*7c478bd9Sstevel@tonic-gate (void) printf(gettext("term=%-3d "), pterm); 614*7c478bd9Sstevel@tonic-gate (void) printf(gettext("exit=%d "), pexit); 615*7c478bd9Sstevel@tonic-gate } else if (utmpp->ut_type != INIT_PROCESS) { 616*7c478bd9Sstevel@tonic-gate /* 617*7c478bd9Sstevel@tonic-gate * Search for each entry in inittab 618*7c478bd9Sstevel@tonic-gate * string. Keep our place from 619*7c478bd9Sstevel@tonic-gate * search to search to try and 620*7c478bd9Sstevel@tonic-gate * minimize the work. Wrap once if needed 621*7c478bd9Sstevel@tonic-gate * for each entry. 622*7c478bd9Sstevel@tonic-gate */ 623*7c478bd9Sstevel@tonic-gate wrap = 0; 624*7c478bd9Sstevel@tonic-gate /* 625*7c478bd9Sstevel@tonic-gate * Look for a line beginning with 626*7c478bd9Sstevel@tonic-gate * utmpp->ut_id 627*7c478bd9Sstevel@tonic-gate */ 628*7c478bd9Sstevel@tonic-gate while ((rc = strncmp(utmpp->ut_id, iinit, 629*7c478bd9Sstevel@tonic-gate strcspn(iinit, ":"))) != 0) { 630*7c478bd9Sstevel@tonic-gate for (; *iinit != '\n'; iinit++); 631*7c478bd9Sstevel@tonic-gate iinit++; 632*7c478bd9Sstevel@tonic-gate 633*7c478bd9Sstevel@tonic-gate /* 634*7c478bd9Sstevel@tonic-gate * Wrap once if necessary to 635*7c478bd9Sstevel@tonic-gate * find entry in inittab 636*7c478bd9Sstevel@tonic-gate */ 637*7c478bd9Sstevel@tonic-gate if (*iinit == '\0') { 638*7c478bd9Sstevel@tonic-gate if (!wrap) { 639*7c478bd9Sstevel@tonic-gate iinit = inittab; 640*7c478bd9Sstevel@tonic-gate wrap = 1; 641*7c478bd9Sstevel@tonic-gate } 642*7c478bd9Sstevel@tonic-gate } 643*7c478bd9Sstevel@tonic-gate } 644*7c478bd9Sstevel@tonic-gate 645*7c478bd9Sstevel@tonic-gate if (*iinit != '\0') { 646*7c478bd9Sstevel@tonic-gate /* 647*7c478bd9Sstevel@tonic-gate * We found our entry 648*7c478bd9Sstevel@tonic-gate */ 649*7c478bd9Sstevel@tonic-gate for (iinit++; *iinit != '#' && 650*7c478bd9Sstevel@tonic-gate *iinit != '\n'; iinit++); 651*7c478bd9Sstevel@tonic-gate if (*iinit == '#') { 652*7c478bd9Sstevel@tonic-gate for (iinit++; *iinit == ' ' || 653*7c478bd9Sstevel@tonic-gate *iinit == '\t'; iinit++); 654*7c478bd9Sstevel@tonic-gate for (rc = 0; *iinit != '\n'; iinit++) 655*7c478bd9Sstevel@tonic-gate comment[rc++] = *iinit; 656*7c478bd9Sstevel@tonic-gate comment[rc] = '\0'; 657*7c478bd9Sstevel@tonic-gate } else 658*7c478bd9Sstevel@tonic-gate (void) strcpy(comment, " "); 659*7c478bd9Sstevel@tonic-gate 660*7c478bd9Sstevel@tonic-gate (void) printf(" %s", comment); 661*7c478bd9Sstevel@tonic-gate } else 662*7c478bd9Sstevel@tonic-gate iinit = inittab; /* Reset pointer */ 663*7c478bd9Sstevel@tonic-gate } 664*7c478bd9Sstevel@tonic-gate if (utmpp->ut_type == INIT_PROCESS) 665*7c478bd9Sstevel@tonic-gate (void) printf(gettext(" id=%4.4s"), utmpp->ut_id); 666*7c478bd9Sstevel@tonic-gate } 667*7c478bd9Sstevel@tonic-gate #ifdef XPG4 668*7c478bd9Sstevel@tonic-gate else 669*7c478bd9Sstevel@tonic-gate if (dopt && utmpp->ut_type == DEAD_PROCESS) { 670*7c478bd9Sstevel@tonic-gate (void) printf(gettext("\tterm=%-3d "), pterm); 671*7c478bd9Sstevel@tonic-gate (void) printf(gettext("exit=%d "), pexit); 672*7c478bd9Sstevel@tonic-gate } 673*7c478bd9Sstevel@tonic-gate #endif /* XPG4 */ 674*7c478bd9Sstevel@tonic-gate 675*7c478bd9Sstevel@tonic-gate 676*7c478bd9Sstevel@tonic-gate /* 677*7c478bd9Sstevel@tonic-gate * Handle RUN_LVL process - If no alt. file - Only one! 678*7c478bd9Sstevel@tonic-gate */ 679*7c478bd9Sstevel@tonic-gate if (utmpp->ut_type == RUN_LVL) { 680*7c478bd9Sstevel@tonic-gate (void) printf(" %c %5ld %c", pterm, utmpp->ut_pid, 681*7c478bd9Sstevel@tonic-gate pexit); 682*7c478bd9Sstevel@tonic-gate if (optcnt == 1 && !validtype[USER_PROCESS]) { 683*7c478bd9Sstevel@tonic-gate (void) printf("\n"); 684*7c478bd9Sstevel@tonic-gate exit(0); 685*7c478bd9Sstevel@tonic-gate } 686*7c478bd9Sstevel@tonic-gate } 687*7c478bd9Sstevel@tonic-gate 688*7c478bd9Sstevel@tonic-gate /* 689*7c478bd9Sstevel@tonic-gate * Handle BOOT_TIME process - If no alt. file - Only one! 690*7c478bd9Sstevel@tonic-gate */ 691*7c478bd9Sstevel@tonic-gate if (utmpp->ut_type == BOOT_TIME) { 692*7c478bd9Sstevel@tonic-gate if (optcnt == 1 && !validtype[USER_PROCESS]) { 693*7c478bd9Sstevel@tonic-gate (void) printf("\n"); 694*7c478bd9Sstevel@tonic-gate exit(0); 695*7c478bd9Sstevel@tonic-gate } 696*7c478bd9Sstevel@tonic-gate } 697*7c478bd9Sstevel@tonic-gate 698*7c478bd9Sstevel@tonic-gate /* 699*7c478bd9Sstevel@tonic-gate * Get remote host from utmpx structure 700*7c478bd9Sstevel@tonic-gate */ 701*7c478bd9Sstevel@tonic-gate if (utmpp && utmpp->ut_host[0]) 702*7c478bd9Sstevel@tonic-gate (void) printf("\t(%.*s)", sizeof (utmpp->ut_host), 703*7c478bd9Sstevel@tonic-gate utmpp->ut_host); 704*7c478bd9Sstevel@tonic-gate 705*7c478bd9Sstevel@tonic-gate /* 706*7c478bd9Sstevel@tonic-gate * Now, put on the trailing EOL 707*7c478bd9Sstevel@tonic-gate */ 708*7c478bd9Sstevel@tonic-gate (void) printf("\n"); 709*7c478bd9Sstevel@tonic-gate } 710*7c478bd9Sstevel@tonic-gate 711*7c478bd9Sstevel@tonic-gate static void 712*7c478bd9Sstevel@tonic-gate process() 713*7c478bd9Sstevel@tonic-gate { 714*7c478bd9Sstevel@tonic-gate struct passwd *pwp; 715*7c478bd9Sstevel@tonic-gate int i = 0; 716*7c478bd9Sstevel@tonic-gate char *ttname; 717*7c478bd9Sstevel@tonic-gate 718*7c478bd9Sstevel@tonic-gate /* 719*7c478bd9Sstevel@tonic-gate * Loop over each entry in /var/adm/utmpx 720*7c478bd9Sstevel@tonic-gate */ 721*7c478bd9Sstevel@tonic-gate 722*7c478bd9Sstevel@tonic-gate setutxent(); 723*7c478bd9Sstevel@tonic-gate while ((utmpp = getutxent()) != NULL) { 724*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 725*7c478bd9Sstevel@tonic-gate (void) printf( 726*7c478bd9Sstevel@tonic-gate "ut_user '%s'\nut_id '%s'\nut_line '%s'\nut_type '%d'\n\n", 727*7c478bd9Sstevel@tonic-gate utmpp->ut_user, utmpp->ut_id, utmpp->ut_line, utmpp->ut_type); 728*7c478bd9Sstevel@tonic-gate #endif 729*7c478bd9Sstevel@tonic-gate if (utmpp->ut_type <= UTMAXTYPE) { 730*7c478bd9Sstevel@tonic-gate /* 731*7c478bd9Sstevel@tonic-gate * Handle "am i" 732*7c478bd9Sstevel@tonic-gate */ 733*7c478bd9Sstevel@tonic-gate if (justme) { 734*7c478bd9Sstevel@tonic-gate if (strncmp(myname, utmpp->ut_user, 735*7c478bd9Sstevel@tonic-gate sizeof (utmpp->ut_user)) == 0 && 736*7c478bd9Sstevel@tonic-gate strncmp(mytty, utmpp->ut_line, 737*7c478bd9Sstevel@tonic-gate sizeof (utmpp->ut_line)) == 0 && 738*7c478bd9Sstevel@tonic-gate utmpp->ut_type == USER_PROCESS) { 739*7c478bd9Sstevel@tonic-gate /* 740*7c478bd9Sstevel@tonic-gate * we have have found ourselves 741*7c478bd9Sstevel@tonic-gate * in the utmp file and the entry 742*7c478bd9Sstevel@tonic-gate * is a user process, this is not 743*7c478bd9Sstevel@tonic-gate * meaningful otherwise 744*7c478bd9Sstevel@tonic-gate * 745*7c478bd9Sstevel@tonic-gate */ 746*7c478bd9Sstevel@tonic-gate 747*7c478bd9Sstevel@tonic-gate dump(); 748*7c478bd9Sstevel@tonic-gate exit(0); 749*7c478bd9Sstevel@tonic-gate } 750*7c478bd9Sstevel@tonic-gate continue; 751*7c478bd9Sstevel@tonic-gate } 752*7c478bd9Sstevel@tonic-gate 753*7c478bd9Sstevel@tonic-gate /* 754*7c478bd9Sstevel@tonic-gate * Print the line if we want it 755*7c478bd9Sstevel@tonic-gate */ 756*7c478bd9Sstevel@tonic-gate if (validtype[utmpp->ut_type]) { 757*7c478bd9Sstevel@tonic-gate #ifdef XPG4 758*7c478bd9Sstevel@tonic-gate if (utmpp->ut_type == LOGIN_PROCESS) { 759*7c478bd9Sstevel@tonic-gate if ((utmpp->ut_line[0] == '\0') || 760*7c478bd9Sstevel@tonic-gate (strcmp(utmpp->ut_user, "LOGIN") != 0)) 761*7c478bd9Sstevel@tonic-gate continue; 762*7c478bd9Sstevel@tonic-gate } 763*7c478bd9Sstevel@tonic-gate #endif /* XPG4 */ 764*7c478bd9Sstevel@tonic-gate dump(); 765*7c478bd9Sstevel@tonic-gate } 766*7c478bd9Sstevel@tonic-gate } else { 767*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 768*7c478bd9Sstevel@tonic-gate gettext("%s: Error --- entry has ut_type " 769*7c478bd9Sstevel@tonic-gate "of %d\n"), program, utmpp->ut_type); 770*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 771*7c478bd9Sstevel@tonic-gate gettext(" when maximum is %d\n"), UTMAXTYPE); 772*7c478bd9Sstevel@tonic-gate } 773*7c478bd9Sstevel@tonic-gate } 774*7c478bd9Sstevel@tonic-gate 775*7c478bd9Sstevel@tonic-gate /* 776*7c478bd9Sstevel@tonic-gate * If justme is set at this point than the utmp entry 777*7c478bd9Sstevel@tonic-gate * was not found. 778*7c478bd9Sstevel@tonic-gate */ 779*7c478bd9Sstevel@tonic-gate if (justme) { 780*7c478bd9Sstevel@tonic-gate static struct utmpx utmpt; 781*7c478bd9Sstevel@tonic-gate 782*7c478bd9Sstevel@tonic-gate pwp = getpwuid(geteuid()); 783*7c478bd9Sstevel@tonic-gate if (pwp != NULL) 784*7c478bd9Sstevel@tonic-gate while (i < (int)sizeof (utmpt.ut_user) && 785*7c478bd9Sstevel@tonic-gate *pwp->pw_name != 0) 786*7c478bd9Sstevel@tonic-gate utmpt.ut_user[i++] = *pwp->pw_name++; 787*7c478bd9Sstevel@tonic-gate 788*7c478bd9Sstevel@tonic-gate ttname = ttyname(1); 789*7c478bd9Sstevel@tonic-gate 790*7c478bd9Sstevel@tonic-gate i = 0; 791*7c478bd9Sstevel@tonic-gate if (ttname != NULL) 792*7c478bd9Sstevel@tonic-gate while (i < (int)sizeof (utmpt.ut_line) && 793*7c478bd9Sstevel@tonic-gate *ttname != 0) 794*7c478bd9Sstevel@tonic-gate utmpt.ut_line[i++] = *ttname++; 795*7c478bd9Sstevel@tonic-gate 796*7c478bd9Sstevel@tonic-gate utmpt.ut_id[0] = 0; 797*7c478bd9Sstevel@tonic-gate utmpt.ut_pid = getpid(); 798*7c478bd9Sstevel@tonic-gate utmpt.ut_type = USER_PROCESS; 799*7c478bd9Sstevel@tonic-gate (void) time(&utmpt.ut_xtime); 800*7c478bd9Sstevel@tonic-gate utmpp = &utmpt; 801*7c478bd9Sstevel@tonic-gate dump(); 802*7c478bd9Sstevel@tonic-gate exit(0); 803*7c478bd9Sstevel@tonic-gate } 804*7c478bd9Sstevel@tonic-gate } 805*7c478bd9Sstevel@tonic-gate 806*7c478bd9Sstevel@tonic-gate /* 807*7c478bd9Sstevel@tonic-gate * This routine checks the following: 808*7c478bd9Sstevel@tonic-gate * 809*7c478bd9Sstevel@tonic-gate * 1. File exists 810*7c478bd9Sstevel@tonic-gate * 811*7c478bd9Sstevel@tonic-gate * 2. We have read permissions 812*7c478bd9Sstevel@tonic-gate * 813*7c478bd9Sstevel@tonic-gate * 3. It is a multiple of utmp entries in size 814*7c478bd9Sstevel@tonic-gate * 815*7c478bd9Sstevel@tonic-gate * Failing any of these conditions causes who(1) to 816*7c478bd9Sstevel@tonic-gate * abort processing. 817*7c478bd9Sstevel@tonic-gate * 818*7c478bd9Sstevel@tonic-gate * 4. If file is empty we exit right away as there 819*7c478bd9Sstevel@tonic-gate * is no info to report on. 820*7c478bd9Sstevel@tonic-gate * 821*7c478bd9Sstevel@tonic-gate * This routine does not check utmpx files. 822*7c478bd9Sstevel@tonic-gate */ 823*7c478bd9Sstevel@tonic-gate static void 824*7c478bd9Sstevel@tonic-gate ck_file(char *name) 825*7c478bd9Sstevel@tonic-gate { 826*7c478bd9Sstevel@tonic-gate struct stat sbuf; 827*7c478bd9Sstevel@tonic-gate int rc; 828*7c478bd9Sstevel@tonic-gate 829*7c478bd9Sstevel@tonic-gate /* 830*7c478bd9Sstevel@tonic-gate * Does file exist? Do stat to check, and save structure 831*7c478bd9Sstevel@tonic-gate * so that we can check on the file's size later on. 832*7c478bd9Sstevel@tonic-gate */ 833*7c478bd9Sstevel@tonic-gate if ((rc = stat(name, &sbuf)) == -1) { 834*7c478bd9Sstevel@tonic-gate (void) snprintf(errmsg, sizeof (errmsg), 835*7c478bd9Sstevel@tonic-gate gettext("%s: Cannot stat file '%s'"), program, name); 836*7c478bd9Sstevel@tonic-gate perror(errmsg); 837*7c478bd9Sstevel@tonic-gate exit(1); 838*7c478bd9Sstevel@tonic-gate } 839*7c478bd9Sstevel@tonic-gate 840*7c478bd9Sstevel@tonic-gate /* 841*7c478bd9Sstevel@tonic-gate * The only real way we can be sure we can access the 842*7c478bd9Sstevel@tonic-gate * file is to try. If we succeed then we close it. 843*7c478bd9Sstevel@tonic-gate */ 844*7c478bd9Sstevel@tonic-gate if (access(name, R_OK) < 0) { 845*7c478bd9Sstevel@tonic-gate (void) snprintf(errmsg, sizeof (errmsg), 846*7c478bd9Sstevel@tonic-gate gettext("%s: Cannot open file '%s'"), program, name); 847*7c478bd9Sstevel@tonic-gate perror(errmsg); 848*7c478bd9Sstevel@tonic-gate exit(1); 849*7c478bd9Sstevel@tonic-gate } 850*7c478bd9Sstevel@tonic-gate 851*7c478bd9Sstevel@tonic-gate /* 852*7c478bd9Sstevel@tonic-gate * If the file is empty, we are all done. 853*7c478bd9Sstevel@tonic-gate */ 854*7c478bd9Sstevel@tonic-gate if (!sbuf.st_size) 855*7c478bd9Sstevel@tonic-gate exit(0); 856*7c478bd9Sstevel@tonic-gate 857*7c478bd9Sstevel@tonic-gate /* 858*7c478bd9Sstevel@tonic-gate * Make sure the file is a utmp file. 859*7c478bd9Sstevel@tonic-gate * We can only check for size being a multiple of 860*7c478bd9Sstevel@tonic-gate * utmp structures in length. 861*7c478bd9Sstevel@tonic-gate */ 862*7c478bd9Sstevel@tonic-gate rc = sbuf.st_size % (int)sizeof (struct utmpx); 863*7c478bd9Sstevel@tonic-gate if (rc) { 864*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: File '%s' is not " 865*7c478bd9Sstevel@tonic-gate "a utmpx file\n"), program, name); 866*7c478bd9Sstevel@tonic-gate exit(1); 867*7c478bd9Sstevel@tonic-gate } 868*7c478bd9Sstevel@tonic-gate } 869