xref: /titanic_54/usr/src/cmd/who/who.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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