xref: /titanic_54/usr/src/cmd/who/who.c (revision b11e536c7bee7ad575c31194d5e3da89f572ebb5)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*b11e536cSjg  * Common Development and Distribution License (the "License").
6*b11e536cSjg  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
227c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
237c478bd9Sstevel@tonic-gate 
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate /*
26*b11e536cSjg  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
277c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
287c478bd9Sstevel@tonic-gate  */
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate /*
337c478bd9Sstevel@tonic-gate  *	This program analyzes information found in /var/adm/utmpx
347c478bd9Sstevel@tonic-gate  *
357c478bd9Sstevel@tonic-gate  *	Additionally information is gathered from /etc/inittab
367c478bd9Sstevel@tonic-gate  *	if requested.
377c478bd9Sstevel@tonic-gate  *
387c478bd9Sstevel@tonic-gate  *
397c478bd9Sstevel@tonic-gate  *	Syntax:
407c478bd9Sstevel@tonic-gate  *
417c478bd9Sstevel@tonic-gate  *		who am i	Displays info on yourself
427c478bd9Sstevel@tonic-gate  *
437c478bd9Sstevel@tonic-gate  *		who -a		Displays information about All
447c478bd9Sstevel@tonic-gate  *				entries in /var/adm/utmpx
457c478bd9Sstevel@tonic-gate  *
467c478bd9Sstevel@tonic-gate  *		who -b		Displays info on last boot
477c478bd9Sstevel@tonic-gate  *
487c478bd9Sstevel@tonic-gate  *		who -d		Displays info on DEAD PROCESSES
497c478bd9Sstevel@tonic-gate  *
507c478bd9Sstevel@tonic-gate  *		who -H		Displays HEADERS for output
517c478bd9Sstevel@tonic-gate  *
527c478bd9Sstevel@tonic-gate  *		who -l 		Displays info on LOGIN entries
537c478bd9Sstevel@tonic-gate  *
547c478bd9Sstevel@tonic-gate  *		who -m 		Same as who am i
557c478bd9Sstevel@tonic-gate  *
567c478bd9Sstevel@tonic-gate  *		who -p 		Displays info on PROCESSES spawned by init
577c478bd9Sstevel@tonic-gate  *
587c478bd9Sstevel@tonic-gate  *		who -q		Displays short information on
597c478bd9Sstevel@tonic-gate  *				current users who LOGGED ON
607c478bd9Sstevel@tonic-gate  *
617c478bd9Sstevel@tonic-gate  *		who -r		Displays info of current run-level
627c478bd9Sstevel@tonic-gate  *
637c478bd9Sstevel@tonic-gate  *		who -s		Displays requested info in SHORT form
647c478bd9Sstevel@tonic-gate  *
657c478bd9Sstevel@tonic-gate  *		who -t		Displays info on TIME changes
667c478bd9Sstevel@tonic-gate  *
677c478bd9Sstevel@tonic-gate  *		who -T		Displays writeability of each user
687c478bd9Sstevel@tonic-gate  *				(+ writeable, - non-writeable, ? hung)
697c478bd9Sstevel@tonic-gate  *
707c478bd9Sstevel@tonic-gate  *		who -u		Displays LONG info on users
717c478bd9Sstevel@tonic-gate  *				who have LOGGED ON
727c478bd9Sstevel@tonic-gate  */
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate #define		DATE_FMT	"%b %e %H:%M"
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate /*
777c478bd9Sstevel@tonic-gate  *  %b	Abbreviated month name
787c478bd9Sstevel@tonic-gate  *  %e	Day of month
797c478bd9Sstevel@tonic-gate  *  %H	hour (24-hour clock)
807c478bd9Sstevel@tonic-gate  *  %M  minute
817c478bd9Sstevel@tonic-gate  */
827c478bd9Sstevel@tonic-gate #include	<errno.h>
837c478bd9Sstevel@tonic-gate #include	<fcntl.h>
847c478bd9Sstevel@tonic-gate #include	<stdio.h>
857c478bd9Sstevel@tonic-gate #include	<string.h>
867c478bd9Sstevel@tonic-gate #include	<sys/types.h>
877c478bd9Sstevel@tonic-gate #include	<unistd.h>
887c478bd9Sstevel@tonic-gate #include	<stdlib.h>
897c478bd9Sstevel@tonic-gate #include	<sys/stat.h>
907c478bd9Sstevel@tonic-gate #include	<time.h>
917c478bd9Sstevel@tonic-gate #include	<utmpx.h>
927c478bd9Sstevel@tonic-gate #include	<locale.h>
937c478bd9Sstevel@tonic-gate #include	<pwd.h>
947c478bd9Sstevel@tonic-gate #include	<limits.h>
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate static void process(void);
977c478bd9Sstevel@tonic-gate static void ck_file(char *);
987c478bd9Sstevel@tonic-gate static void dump(void);
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate static struct	utmpx *utmpp;	/* pointer for getutxent()	*/
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate /*
1037c478bd9Sstevel@tonic-gate  * utmpx defines wider fields for user and line.  For compatibility of output,
1047c478bd9Sstevel@tonic-gate  * we are limiting these to the old maximums in utmp. Define UTMPX_NAMELEN
1057c478bd9Sstevel@tonic-gate  * to use the full lengths.
1067c478bd9Sstevel@tonic-gate  */
1077c478bd9Sstevel@tonic-gate #ifndef UTMPX_NAMELEN
1087c478bd9Sstevel@tonic-gate /* XXX - utmp - fix name length */
1097c478bd9Sstevel@tonic-gate #define	NMAX	(_POSIX_LOGIN_NAME_MAX - 1)
1107c478bd9Sstevel@tonic-gate #define	LMAX	12
1117c478bd9Sstevel@tonic-gate #else /* UTMPX_NAMELEN */
1127c478bd9Sstevel@tonic-gate #define	NMAX	(sizeof (utmpp->ut_user))
1137c478bd9Sstevel@tonic-gate #define	LMAX	(sizeof (utmpp->ut_line))
1147c478bd9Sstevel@tonic-gate #endif
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate static char	comment[BUFSIZ]; /* holds inittab comment	*/
1177c478bd9Sstevel@tonic-gate static char	errmsg[BUFSIZ];	/* used in snprintf for errors	*/
1187c478bd9Sstevel@tonic-gate static int	fildes;		/* file descriptor for inittab	*/
1197c478bd9Sstevel@tonic-gate static int	Hopt = 0;	/* 1 = who -H			*/
1207c478bd9Sstevel@tonic-gate static char	*inittab;	/* ptr to inittab contents	*/
1217c478bd9Sstevel@tonic-gate static char	*iinit;		/* index into inittab		*/
1227c478bd9Sstevel@tonic-gate static int	justme = 0;	/* 1 = who am i			*/
1237c478bd9Sstevel@tonic-gate static struct	tm *lptr;	/* holds user login time	*/
1247c478bd9Sstevel@tonic-gate static char	*myname;	/* pointer to invoker's name 	*/
1257c478bd9Sstevel@tonic-gate static char	*mytty;		/* holds device user is on	*/
1267c478bd9Sstevel@tonic-gate static char	nameval[sizeof (utmpp->ut_user) + 1]; /*  invoker's name */
1277c478bd9Sstevel@tonic-gate static int	number = 8;	/* number of users per -q line	*/
1287c478bd9Sstevel@tonic-gate static int	optcnt = 0;	/* keeps count of options	*/
1297c478bd9Sstevel@tonic-gate static char	outbuf[BUFSIZ];	/* buffer for output		*/
1307c478bd9Sstevel@tonic-gate static char	*program;	/* holds name of this program	*/
1317c478bd9Sstevel@tonic-gate #ifdef	XPG4
1327c478bd9Sstevel@tonic-gate static int	aopt = 0;	/* 1 = who -a			*/
1337c478bd9Sstevel@tonic-gate static int	dopt = 0;	/* 1 = who -d			*/
1347c478bd9Sstevel@tonic-gate #endif	/* XPG4 */
1357c478bd9Sstevel@tonic-gate static int	qopt = 0;	/* 1 = who -q			*/
1367c478bd9Sstevel@tonic-gate static int	sopt = 0;	/* 1 = who -s			*/
1377c478bd9Sstevel@tonic-gate static struct	stat stbuf;	/* area for stat buffer		*/
1387c478bd9Sstevel@tonic-gate static struct	stat *stbufp;	/* ptr to structure		*/
1397c478bd9Sstevel@tonic-gate static int	terse = 1;	/* 1 = print terse msgs		*/
1407c478bd9Sstevel@tonic-gate static int	Topt = 0;	/* 1 = who -T			*/
1417c478bd9Sstevel@tonic-gate static time_t	timnow;		/* holds current time		*/
1427c478bd9Sstevel@tonic-gate static int	totlusrs = 0;	/* cntr for users on system	*/
1437c478bd9Sstevel@tonic-gate static int	uopt = 0;	/* 1 = who -u			*/
1447c478bd9Sstevel@tonic-gate static char	user[sizeof (utmpp->ut_user) + 1]; /* holds user name */
1457c478bd9Sstevel@tonic-gate static int	validtype[UTMAXTYPE+1];	/* holds valid types	*/
1467c478bd9Sstevel@tonic-gate static int	wrap;		/* flag to indicate wrap	*/
1477c478bd9Sstevel@tonic-gate static char	time_buf[128];	/* holds date and time string	*/
1487c478bd9Sstevel@tonic-gate static char	*end;		/* used in strtol for end pointer */
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate int
1517c478bd9Sstevel@tonic-gate main(int argc, char **argv)
1527c478bd9Sstevel@tonic-gate {
1537c478bd9Sstevel@tonic-gate 	int	goerr = 0;	/* non-zero indicates cmd error	*/
1547c478bd9Sstevel@tonic-gate 	int	i;
1557c478bd9Sstevel@tonic-gate 	int	optsw;		/* switch for while of getopt()	*/
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate #if	!defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
1607c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't */
1617c478bd9Sstevel@tonic-gate #endif
1627c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	validtype[USER_PROCESS] = 1;
1657c478bd9Sstevel@tonic-gate 	validtype[EMPTY] = 0;
1667c478bd9Sstevel@tonic-gate 	stbufp = &stbuf;
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate 	/*
1697c478bd9Sstevel@tonic-gate 	 *	Strip off path name of this command
1707c478bd9Sstevel@tonic-gate 	 */
1717c478bd9Sstevel@tonic-gate 	for (i = strlen(argv[0]); i >= 0 && argv[0][i] != '/'; --i);
1727c478bd9Sstevel@tonic-gate 	if (i >= 0)
1737c478bd9Sstevel@tonic-gate 		argv[0] += i+1;
1747c478bd9Sstevel@tonic-gate 	program = argv[0];
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 	/*
1777c478bd9Sstevel@tonic-gate 	 *	Buffer stdout for speed
1787c478bd9Sstevel@tonic-gate 	 */
1797c478bd9Sstevel@tonic-gate 	setbuf(stdout, outbuf);
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 	/*
1827c478bd9Sstevel@tonic-gate 	 *	Retrieve options specified on command line
1837c478bd9Sstevel@tonic-gate 	 *	XCU4 - add -m option
1847c478bd9Sstevel@tonic-gate 	 */
1857c478bd9Sstevel@tonic-gate 	while ((optsw = getopt(argc, argv, "abdHlmn:pqrstTu")) != EOF) {
1867c478bd9Sstevel@tonic-gate 		optcnt++;
1877c478bd9Sstevel@tonic-gate 		switch (optsw) {
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate 		case 'a':
1907c478bd9Sstevel@tonic-gate 			optcnt += 7;
1917c478bd9Sstevel@tonic-gate 			validtype[BOOT_TIME] = 1;
1927c478bd9Sstevel@tonic-gate 			validtype[DEAD_PROCESS] = 1;
1937c478bd9Sstevel@tonic-gate 			validtype[LOGIN_PROCESS] = 1;
1947c478bd9Sstevel@tonic-gate 			validtype[INIT_PROCESS] = 1;
1957c478bd9Sstevel@tonic-gate 			validtype[RUN_LVL] = 1;
1967c478bd9Sstevel@tonic-gate 			validtype[OLD_TIME] = 1;
1977c478bd9Sstevel@tonic-gate 			validtype[NEW_TIME] = 1;
1987c478bd9Sstevel@tonic-gate 			validtype[USER_PROCESS] = 1;
1997c478bd9Sstevel@tonic-gate #ifdef	XPG4
2007c478bd9Sstevel@tonic-gate 			aopt = 1;
2017c478bd9Sstevel@tonic-gate #endif	/* XPG4 */
2027c478bd9Sstevel@tonic-gate 			uopt = 1;
2037c478bd9Sstevel@tonic-gate 			Topt = 1;
2047c478bd9Sstevel@tonic-gate 			if (!sopt) terse = 0;
2057c478bd9Sstevel@tonic-gate 			break;
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 		case 'b':
2087c478bd9Sstevel@tonic-gate 			validtype[BOOT_TIME] = 1;
2097c478bd9Sstevel@tonic-gate 			if (!uopt) validtype[USER_PROCESS] = 0;
2107c478bd9Sstevel@tonic-gate 			break;
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 		case 'd':
2137c478bd9Sstevel@tonic-gate 			validtype[DEAD_PROCESS] = 1;
2147c478bd9Sstevel@tonic-gate 			if (!uopt) validtype[USER_PROCESS] = 0;
2157c478bd9Sstevel@tonic-gate #ifdef	XPG4
2167c478bd9Sstevel@tonic-gate 			dopt = 1;
2177c478bd9Sstevel@tonic-gate #endif	/* XPG4 */
2187c478bd9Sstevel@tonic-gate 			break;
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate 		case 'H':
2217c478bd9Sstevel@tonic-gate 			optcnt--; /* Don't count Header */
2227c478bd9Sstevel@tonic-gate 			Hopt = 1;
2237c478bd9Sstevel@tonic-gate 			break;
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 		case 'l':
2267c478bd9Sstevel@tonic-gate 			validtype[LOGIN_PROCESS] = 1;
2277c478bd9Sstevel@tonic-gate 			if (!uopt) validtype[USER_PROCESS] = 0;
2287c478bd9Sstevel@tonic-gate 			terse = 0;
2297c478bd9Sstevel@tonic-gate 			break;
2307c478bd9Sstevel@tonic-gate 		case 'm':		/* New XCU4 option */
2317c478bd9Sstevel@tonic-gate 			justme = 1;
2327c478bd9Sstevel@tonic-gate 			break;
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate 		case 'n':
2357c478bd9Sstevel@tonic-gate 			errno = 0;
2367c478bd9Sstevel@tonic-gate 			number = strtol(optarg, &end, 10);
2377c478bd9Sstevel@tonic-gate 			if (errno != 0 || *end != '\0') {
2387c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
2397c478bd9Sstevel@tonic-gate 				    "%s: Invalid numeric argument\n"),
2407c478bd9Sstevel@tonic-gate 				    program);
2417c478bd9Sstevel@tonic-gate 				exit(1);
2427c478bd9Sstevel@tonic-gate 			}
2437c478bd9Sstevel@tonic-gate 			if (number < 1) {
2447c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
2457c478bd9Sstevel@tonic-gate 				    "%s: Number of users per line must "
2467c478bd9Sstevel@tonic-gate 					"be at least 1\n"), program);
2477c478bd9Sstevel@tonic-gate 				exit(1);
2487c478bd9Sstevel@tonic-gate 			}
2497c478bd9Sstevel@tonic-gate 			break;
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 		case 'p':
2527c478bd9Sstevel@tonic-gate 			validtype[INIT_PROCESS] = 1;
2537c478bd9Sstevel@tonic-gate 			if (!uopt) validtype[USER_PROCESS] = 0;
2547c478bd9Sstevel@tonic-gate 			break;
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate 		case 'q':
2577c478bd9Sstevel@tonic-gate 			qopt = 1;
2587c478bd9Sstevel@tonic-gate 			break;
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate 		case 'r':
2617c478bd9Sstevel@tonic-gate 			validtype[RUN_LVL] = 1;
2627c478bd9Sstevel@tonic-gate 			terse = 0;
2637c478bd9Sstevel@tonic-gate 			if (!uopt) validtype[USER_PROCESS] = 0;
2647c478bd9Sstevel@tonic-gate 			break;
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate 		case 's':
2677c478bd9Sstevel@tonic-gate 			sopt = 1;
2687c478bd9Sstevel@tonic-gate 			terse = 1;
2697c478bd9Sstevel@tonic-gate 			break;
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate 		case 't':
2727c478bd9Sstevel@tonic-gate 			validtype[OLD_TIME] = 1;
2737c478bd9Sstevel@tonic-gate 			validtype[NEW_TIME] = 1;
2747c478bd9Sstevel@tonic-gate 			if (!uopt) validtype[USER_PROCESS] = 0;
2757c478bd9Sstevel@tonic-gate 			break;
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate 		case 'T':
2787c478bd9Sstevel@tonic-gate 			Topt = 1;
2797c478bd9Sstevel@tonic-gate #ifdef	XPG4
2807c478bd9Sstevel@tonic-gate 			terse = 1;	/* XPG4 requires -T */
2817c478bd9Sstevel@tonic-gate #else	/* XPG4 */
2827c478bd9Sstevel@tonic-gate 			terse = 0;
2837c478bd9Sstevel@tonic-gate #endif	/* XPG4 */
2847c478bd9Sstevel@tonic-gate 			break;
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 		case 'u':
2877c478bd9Sstevel@tonic-gate 			uopt = 1;
2887c478bd9Sstevel@tonic-gate 			validtype[USER_PROCESS] = 1;
2897c478bd9Sstevel@tonic-gate 			if (!sopt) terse = 0;
2907c478bd9Sstevel@tonic-gate 			break;
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 		case '?':
2937c478bd9Sstevel@tonic-gate 			goerr++;
2947c478bd9Sstevel@tonic-gate 			break;
2957c478bd9Sstevel@tonic-gate 		default:
2967c478bd9Sstevel@tonic-gate 			break;
2977c478bd9Sstevel@tonic-gate 		}
2987c478bd9Sstevel@tonic-gate 	}
2997c478bd9Sstevel@tonic-gate #ifdef	XPG4
3007c478bd9Sstevel@tonic-gate 	/*
3017c478bd9Sstevel@tonic-gate 	 * XCU4 changes - check for illegal sopt, Topt & aopt combination
3027c478bd9Sstevel@tonic-gate 	 */
3037c478bd9Sstevel@tonic-gate 	if (sopt == 1) {
3047c478bd9Sstevel@tonic-gate 		terse = 1;
3057c478bd9Sstevel@tonic-gate 		if (Topt == 1 || aopt == 1)
3067c478bd9Sstevel@tonic-gate 		goerr++;
3077c478bd9Sstevel@tonic-gate 	}
3087c478bd9Sstevel@tonic-gate #endif	/* XPG4 */
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate 	if (goerr > 0) {
3117c478bd9Sstevel@tonic-gate #ifdef	XPG4
3127c478bd9Sstevel@tonic-gate 		/*
3137c478bd9Sstevel@tonic-gate 		 * XCU4 - slightly different usage with -s -a & -T
3147c478bd9Sstevel@tonic-gate 		 */
3157c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("\nUsage:\t%s"), program);
3167c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
3177c478bd9Sstevel@tonic-gate 		    gettext(" -s [-bdHlmpqrtu] [utmpx_like_file]\n"));
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
3207c478bd9Sstevel@tonic-gate 		    "\t%s [-abdHlmpqrtTu] [utmpx_like_file]\n"), program);
3217c478bd9Sstevel@tonic-gate #else	/* XPG4 */
3227c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
3237c478bd9Sstevel@tonic-gate 		    "\nUsage:\t%s [-abdHlmpqrstTu] [utmpx_like_file]\n"),
3247c478bd9Sstevel@tonic-gate 		    program);
3257c478bd9Sstevel@tonic-gate #endif	/* XPG4 */
3267c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
3277c478bd9Sstevel@tonic-gate 		    gettext("\t%s -q [-n x] [utmpx_like_file]\n"), program);
3287c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("\t%s [am i]\n"), program);
3297c478bd9Sstevel@tonic-gate 		/*
3307c478bd9Sstevel@tonic-gate 		 * XCU4 changes - be explicit with "am i" options
3317c478bd9Sstevel@tonic-gate 		 */
3327c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("\t%s [am I]\n"), program);
3337c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
3347c478bd9Sstevel@tonic-gate 		    "a\tall (bdlprtu options)\n"));
3357c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("b\tboot time\n"));
3367c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("d\tdead processes\n"));
3377c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("H\tprint header\n"));
3387c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("l\tlogin processes\n"));
3397c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
3407c478bd9Sstevel@tonic-gate 		    "n #\tspecify number of users per line for -q\n"));
3417c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
3427c478bd9Sstevel@tonic-gate 		    gettext("p\tprocesses other than getty or users\n"));
3437c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("q\tquick %s\n"), program);
3447c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("r\trun level\n"));
3457c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
3467c478bd9Sstevel@tonic-gate 		"s\tshort form of %s (no time since last output or pid)\n"),
3477c478bd9Sstevel@tonic-gate 		    program);
3487c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("t\ttime changes\n"));
3497c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
3507c478bd9Sstevel@tonic-gate 		    "T\tstatus of tty (+ writable, - not writable, "
3517c478bd9Sstevel@tonic-gate 			"? hung)\n"));
3527c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("u\tuseful information\n"));
3537c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
3547c478bd9Sstevel@tonic-gate 		    gettext("m\tinformation only about current terminal\n"));
3557c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
3567c478bd9Sstevel@tonic-gate 		    "am i\tinformation about current terminal "
3577c478bd9Sstevel@tonic-gate 			"(same as -m)\n"));
3587c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
3597c478bd9Sstevel@tonic-gate 		    "am I\tinformation about current terminal "
3607c478bd9Sstevel@tonic-gate 			"(same as -m)\n"));
3617c478bd9Sstevel@tonic-gate 		exit(1);
3627c478bd9Sstevel@tonic-gate 	}
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 	/*
3657c478bd9Sstevel@tonic-gate 	 * XCU4: If -q option ignore all other options
3667c478bd9Sstevel@tonic-gate 	 */
3677c478bd9Sstevel@tonic-gate 	if (qopt == 1) {
3687c478bd9Sstevel@tonic-gate 		Hopt = 0;
3697c478bd9Sstevel@tonic-gate 		sopt = 0;
3707c478bd9Sstevel@tonic-gate 		Topt = 0;
3717c478bd9Sstevel@tonic-gate 		uopt = 0;
3727c478bd9Sstevel@tonic-gate 		justme = 0;
3737c478bd9Sstevel@tonic-gate 		validtype[ACCOUNTING] = 0;
3747c478bd9Sstevel@tonic-gate 		validtype[BOOT_TIME] = 0;
3757c478bd9Sstevel@tonic-gate 		validtype[DEAD_PROCESS] = 0;
3767c478bd9Sstevel@tonic-gate 		validtype[LOGIN_PROCESS] = 0;
3777c478bd9Sstevel@tonic-gate 		validtype[INIT_PROCESS] = 0;
3787c478bd9Sstevel@tonic-gate 		validtype[RUN_LVL] = 0;
3797c478bd9Sstevel@tonic-gate 		validtype[OLD_TIME] = 0;
3807c478bd9Sstevel@tonic-gate 		validtype[NEW_TIME] = 0;
3817c478bd9Sstevel@tonic-gate 		validtype[USER_PROCESS] = 1;
3827c478bd9Sstevel@tonic-gate 	}
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate 	if (argc == optind + 1) {
3857c478bd9Sstevel@tonic-gate 		optcnt++;
3867c478bd9Sstevel@tonic-gate 		ck_file(argv[optind]);
3877c478bd9Sstevel@tonic-gate 		(void) utmpxname(argv[optind]);
3887c478bd9Sstevel@tonic-gate 	}
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate 	/*
3917c478bd9Sstevel@tonic-gate 	 *	Test for 'who am i' or 'who am I'
3927c478bd9Sstevel@tonic-gate 	 *	XCU4 - check if justme was already set by -m option
3937c478bd9Sstevel@tonic-gate 	 */
3947c478bd9Sstevel@tonic-gate 	if (justme == 1 || (argc == 3 && strcmp(argv[1], "am") == 0 &&
3957c478bd9Sstevel@tonic-gate 	    ((argv[2][0] == 'i' || argv[2][0] == 'I') &&
3967c478bd9Sstevel@tonic-gate 		argv[2][1] == '\0'))) {
3977c478bd9Sstevel@tonic-gate 		justme = 1;
3987c478bd9Sstevel@tonic-gate 		myname = nameval;
3997c478bd9Sstevel@tonic-gate 		(void) cuserid(myname);
4007c478bd9Sstevel@tonic-gate 		if ((mytty = ttyname(fileno(stdin))) == NULL &&
4017c478bd9Sstevel@tonic-gate 		    (mytty = ttyname(fileno(stdout))) == NULL &&
4027c478bd9Sstevel@tonic-gate 		    (mytty = ttyname(fileno(stderr))) == NULL) {
4037c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
4047c478bd9Sstevel@tonic-gate 			"Must be attached to terminal for 'am I' option\n"));
4057c478bd9Sstevel@tonic-gate 			(void) fflush(stderr);
4067c478bd9Sstevel@tonic-gate 			exit(1);
4077c478bd9Sstevel@tonic-gate 		} else
4087c478bd9Sstevel@tonic-gate 			mytty += 5; /* bump past "/dev/" */
4097c478bd9Sstevel@tonic-gate 	}
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 	if (!terse) {
4127c478bd9Sstevel@tonic-gate 		if (Hopt)
4137c478bd9Sstevel@tonic-gate 			(void) printf(gettext(
4147c478bd9Sstevel@tonic-gate 	"NAME       LINE         TIME          IDLE    PID  COMMENTS\n"));
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate 		timnow = time(0);
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate 		if ((fildes = open("/etc/inittab",
4197c478bd9Sstevel@tonic-gate 		    O_NONBLOCK|O_RDONLY)) == -1) {
4207c478bd9Sstevel@tonic-gate 			(void) snprintf(errmsg, sizeof (errmsg),
4217c478bd9Sstevel@tonic-gate 			    gettext("%s: Cannot open /etc/inittab"), program);
4227c478bd9Sstevel@tonic-gate 			perror(errmsg);
4237c478bd9Sstevel@tonic-gate 			exit(errno);
4247c478bd9Sstevel@tonic-gate 		}
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate 		if (fstat(fildes, stbufp) == -1) {
4277c478bd9Sstevel@tonic-gate 			(void) snprintf(errmsg, sizeof (errmsg),
4287c478bd9Sstevel@tonic-gate 			    gettext("%s: Cannot stat /etc/inittab"), program);
4297c478bd9Sstevel@tonic-gate 			perror(errmsg);
4307c478bd9Sstevel@tonic-gate 			exit(errno);
4317c478bd9Sstevel@tonic-gate 		}
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 		if ((inittab = malloc(stbufp->st_size + 1)) == NULL) {
4347c478bd9Sstevel@tonic-gate 			(void) snprintf(errmsg, sizeof (errmsg),
4357c478bd9Sstevel@tonic-gate 			    gettext("%s: Cannot allocate %ld bytes"),
4367c478bd9Sstevel@tonic-gate 			    program, stbufp->st_size);
4377c478bd9Sstevel@tonic-gate 			perror(errmsg);
4387c478bd9Sstevel@tonic-gate 			exit(errno);
4397c478bd9Sstevel@tonic-gate 		}
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate 		if (read(fildes, inittab, stbufp->st_size)
4427c478bd9Sstevel@tonic-gate 		    != stbufp->st_size) {
4437c478bd9Sstevel@tonic-gate 			(void) snprintf(errmsg, sizeof (errmsg),
4447c478bd9Sstevel@tonic-gate 			    gettext("%s: Error reading /etc/inittab"),
4457c478bd9Sstevel@tonic-gate 			    program);
4467c478bd9Sstevel@tonic-gate 			perror(errmsg);
4477c478bd9Sstevel@tonic-gate 			exit(errno);
4487c478bd9Sstevel@tonic-gate 		}
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 		inittab[stbufp->st_size] = '\0';
4517c478bd9Sstevel@tonic-gate 		iinit = inittab;
4527c478bd9Sstevel@tonic-gate 	} else {
4537c478bd9Sstevel@tonic-gate 		if (Hopt) {
4547c478bd9Sstevel@tonic-gate #ifdef	XPG4
4557c478bd9Sstevel@tonic-gate 			if (dopt) {
4567c478bd9Sstevel@tonic-gate 				(void) printf(gettext(
4577c478bd9Sstevel@tonic-gate 			"NAME       LINE         TIME		COMMENTS\n"));
4587c478bd9Sstevel@tonic-gate 			} else {
4597c478bd9Sstevel@tonic-gate 				(void) printf(
4607c478bd9Sstevel@tonic-gate 				    gettext("NAME       LINE         TIME\n"));
4617c478bd9Sstevel@tonic-gate 			}
4627c478bd9Sstevel@tonic-gate #else	/* XPG4 */
4637c478bd9Sstevel@tonic-gate 			(void) printf(
4647c478bd9Sstevel@tonic-gate 			    gettext("NAME       LINE         TIME\n"));
4657c478bd9Sstevel@tonic-gate #endif	/* XPG4 */
4667c478bd9Sstevel@tonic-gate 		}
4677c478bd9Sstevel@tonic-gate 	}
4687c478bd9Sstevel@tonic-gate 	process();
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate 	/*
4717c478bd9Sstevel@tonic-gate 	 *	'who -q' requires EOL upon exit,
4727c478bd9Sstevel@tonic-gate 	 *	followed by total line
4737c478bd9Sstevel@tonic-gate 	 */
4747c478bd9Sstevel@tonic-gate 	if (qopt)
4757c478bd9Sstevel@tonic-gate 		(void) printf(gettext("\n# users=%d\n"), totlusrs);
4767c478bd9Sstevel@tonic-gate 	return (0);
4777c478bd9Sstevel@tonic-gate }
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate static void
4807c478bd9Sstevel@tonic-gate dump()
4817c478bd9Sstevel@tonic-gate {
4827c478bd9Sstevel@tonic-gate 	char	device[sizeof (utmpp->ut_line) + 1];
4837c478bd9Sstevel@tonic-gate 	time_t hr;
4847c478bd9Sstevel@tonic-gate 	time_t	idle;
4857c478bd9Sstevel@tonic-gate 	time_t min;
4867c478bd9Sstevel@tonic-gate 	char	path[sizeof (utmpp->ut_line) + 6];
4877c478bd9Sstevel@tonic-gate 	int	pexit;
4887c478bd9Sstevel@tonic-gate 	int	pterm;
4897c478bd9Sstevel@tonic-gate 	int	rc;
4907c478bd9Sstevel@tonic-gate 	char	w;	/* writeability indicator */
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate 	/*
4937c478bd9Sstevel@tonic-gate 	 * Get and check user name
4947c478bd9Sstevel@tonic-gate 	 */
4957c478bd9Sstevel@tonic-gate 	if (utmpp->ut_user[0] == '\0')
4967c478bd9Sstevel@tonic-gate 		(void) strcpy(user, "   .");
4977c478bd9Sstevel@tonic-gate 	else {
4987c478bd9Sstevel@tonic-gate 		(void) strncpy(user, utmpp->ut_user, sizeof (user));
4997c478bd9Sstevel@tonic-gate 		user[sizeof (user) - 1] = '\0';
5007c478bd9Sstevel@tonic-gate 	}
5017c478bd9Sstevel@tonic-gate 	totlusrs++;
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate 	/*
5047c478bd9Sstevel@tonic-gate 	 * Do print in 'who -q' format
5057c478bd9Sstevel@tonic-gate 	 */
5067c478bd9Sstevel@tonic-gate 	if (qopt) {
5077c478bd9Sstevel@tonic-gate 		/*
5087c478bd9Sstevel@tonic-gate 		 * XCU4 - Use non user macro for correct user count
5097c478bd9Sstevel@tonic-gate 		 */
5107c478bd9Sstevel@tonic-gate 		if (((totlusrs - 1) % number) == 0 && totlusrs > 1)
5117c478bd9Sstevel@tonic-gate 			(void) printf("\n");
5127c478bd9Sstevel@tonic-gate 		(void) printf("%-*s ", NMAX, user);
5137c478bd9Sstevel@tonic-gate 		return;
5147c478bd9Sstevel@tonic-gate 	}
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate 	pexit = (int)' ';
5187c478bd9Sstevel@tonic-gate 	pterm = (int)' ';
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 	/*
5217c478bd9Sstevel@tonic-gate 	 *	Get exit info if applicable
5227c478bd9Sstevel@tonic-gate 	 */
5237c478bd9Sstevel@tonic-gate 	if (utmpp->ut_type == RUN_LVL || utmpp->ut_type == DEAD_PROCESS) {
5247c478bd9Sstevel@tonic-gate 		pterm = utmpp->ut_exit.e_termination;
5257c478bd9Sstevel@tonic-gate 		pexit = utmpp->ut_exit.e_exit;
5267c478bd9Sstevel@tonic-gate 	}
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate 	/*
5297c478bd9Sstevel@tonic-gate 	 *	Massage ut_xtime field
5307c478bd9Sstevel@tonic-gate 	 */
5317c478bd9Sstevel@tonic-gate 	lptr = localtime(&utmpp->ut_xtime);
5327c478bd9Sstevel@tonic-gate 	(void) strftime(time_buf, sizeof (time_buf),
5337c478bd9Sstevel@tonic-gate 	    dcgettext(NULL, DATE_FMT, LC_TIME), lptr);
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate 	/*
5367c478bd9Sstevel@tonic-gate 	 *	Get and massage device
5377c478bd9Sstevel@tonic-gate 	 */
5387c478bd9Sstevel@tonic-gate 	if (utmpp->ut_line[0] == '\0')
5397c478bd9Sstevel@tonic-gate 		(void) strcpy(device, "     .");
5407c478bd9Sstevel@tonic-gate 	else {
5417c478bd9Sstevel@tonic-gate 		(void) strncpy(device, utmpp->ut_line,
5427c478bd9Sstevel@tonic-gate 		    sizeof (utmpp->ut_line));
5437c478bd9Sstevel@tonic-gate 		device[sizeof (utmpp->ut_line)] = '\0';
5447c478bd9Sstevel@tonic-gate 	}
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate 	/*
5477c478bd9Sstevel@tonic-gate 	 *	Get writeability if requested
5487c478bd9Sstevel@tonic-gate 	 *	XCU4 - only print + or - for user processes
5497c478bd9Sstevel@tonic-gate 	 */
5507c478bd9Sstevel@tonic-gate 	if (Topt && (utmpp->ut_type == USER_PROCESS)) {
5517c478bd9Sstevel@tonic-gate 		w = '-';
5527c478bd9Sstevel@tonic-gate 		(void) strcpy(path, "/dev/");
5537c478bd9Sstevel@tonic-gate 		(void) strncpy(path + 5, utmpp->ut_line,
5547c478bd9Sstevel@tonic-gate 		    sizeof (utmpp->ut_line));
5557c478bd9Sstevel@tonic-gate 		path[5 + sizeof (utmpp->ut_line)] = '\0';
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate 		if ((rc = stat(path, stbufp)) == -1) w = '?';
5587c478bd9Sstevel@tonic-gate 		else if ((stbufp->st_mode & S_IWOTH) ||
5597c478bd9Sstevel@tonic-gate 		    (stbufp->st_mode & S_IWGRP))  /* Check group & other */
5607c478bd9Sstevel@tonic-gate 			w = '+';
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate 	} else
5637c478bd9Sstevel@tonic-gate 		w = ' ';
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate 	/*
5667c478bd9Sstevel@tonic-gate 	 *	Print the TERSE portion of the output
5677c478bd9Sstevel@tonic-gate 	 */
5687c478bd9Sstevel@tonic-gate 	(void) printf("%-*s %c %-12s %s", NMAX, user, w, device, time_buf);
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate 	if (!terse) {
5717c478bd9Sstevel@tonic-gate 		/*
5727c478bd9Sstevel@tonic-gate 		 *	Stat device for idle time
5737c478bd9Sstevel@tonic-gate 		 *	(Don't complain if you can't)
5747c478bd9Sstevel@tonic-gate 		 */
575*b11e536cSjg 		rc = -1;
576*b11e536cSjg 		if (utmpp->ut_type == USER_PROCESS) {
577*b11e536cSjg 			(void) strcpy(path, "/dev/");
578*b11e536cSjg 			(void) strncpy(path + 5, utmpp->ut_line,
579*b11e536cSjg 			    sizeof (utmpp->ut_line));
580*b11e536cSjg 			path[5 + sizeof (utmpp->ut_line)] = '\0';
581*b11e536cSjg 			rc = stat(path, stbufp);
582*b11e536cSjg 		}
583*b11e536cSjg 		if (rc != -1) {
5847c478bd9Sstevel@tonic-gate 			idle = timnow - stbufp->st_mtime;
5857c478bd9Sstevel@tonic-gate 			hr = idle/3600;
5867c478bd9Sstevel@tonic-gate 			min = (unsigned)(idle/60)%60;
5877c478bd9Sstevel@tonic-gate 			if (hr == 0 && min == 0)
5887c478bd9Sstevel@tonic-gate 				(void) printf(gettext("   .  "));
5897c478bd9Sstevel@tonic-gate 			else {
5907c478bd9Sstevel@tonic-gate 				if (hr < 24)
5917c478bd9Sstevel@tonic-gate 					(void) printf(" %2d:%2.2d", (int)hr,
5927c478bd9Sstevel@tonic-gate 					    (int)min);
5937c478bd9Sstevel@tonic-gate 				else
5947c478bd9Sstevel@tonic-gate 					(void) printf(gettext("  old "));
5957c478bd9Sstevel@tonic-gate 			}
5967c478bd9Sstevel@tonic-gate 		}
5977c478bd9Sstevel@tonic-gate 
5987c478bd9Sstevel@tonic-gate 		/*
5997c478bd9Sstevel@tonic-gate 		 *	Add PID for verbose output
6007c478bd9Sstevel@tonic-gate 		 */
6017c478bd9Sstevel@tonic-gate 		if (utmpp->ut_type != BOOT_TIME &&
6027c478bd9Sstevel@tonic-gate 		    utmpp->ut_type != RUN_LVL &&
6037c478bd9Sstevel@tonic-gate 		    utmpp->ut_type != ACCOUNTING)
6047c478bd9Sstevel@tonic-gate 			(void) printf("  %5ld", utmpp->ut_pid);
6057c478bd9Sstevel@tonic-gate 
6067c478bd9Sstevel@tonic-gate 		/*
6077c478bd9Sstevel@tonic-gate 		 *	Handle /etc/inittab comment
6087c478bd9Sstevel@tonic-gate 		 */
6097c478bd9Sstevel@tonic-gate 		if (utmpp->ut_type == DEAD_PROCESS) {
6107c478bd9Sstevel@tonic-gate 			(void) printf(gettext("  id=%4.4s "),
6117c478bd9Sstevel@tonic-gate 			    utmpp->ut_id);
6127c478bd9Sstevel@tonic-gate 			(void) printf(gettext("term=%-3d "), pterm);
6137c478bd9Sstevel@tonic-gate 			(void) printf(gettext("exit=%d  "), pexit);
6147c478bd9Sstevel@tonic-gate 		} else if (utmpp->ut_type != INIT_PROCESS) {
6157c478bd9Sstevel@tonic-gate 			/*
6167c478bd9Sstevel@tonic-gate 			 *	Search for each entry in inittab
6177c478bd9Sstevel@tonic-gate 			 *	string. Keep our place from
6187c478bd9Sstevel@tonic-gate 			 *	search to search to try and
6197c478bd9Sstevel@tonic-gate 			 *	minimize the work. Wrap once if needed
6207c478bd9Sstevel@tonic-gate 			 *	for each entry.
6217c478bd9Sstevel@tonic-gate 			 */
6227c478bd9Sstevel@tonic-gate 			wrap = 0;
6237c478bd9Sstevel@tonic-gate 			/*
6247c478bd9Sstevel@tonic-gate 			 *	Look for a line beginning with
6257c478bd9Sstevel@tonic-gate 			 *	utmpp->ut_id
6267c478bd9Sstevel@tonic-gate 			 */
6277c478bd9Sstevel@tonic-gate 			while ((rc = strncmp(utmpp->ut_id, iinit,
6287c478bd9Sstevel@tonic-gate 			    strcspn(iinit, ":"))) != 0) {
6297c478bd9Sstevel@tonic-gate 				for (; *iinit != '\n'; iinit++);
6307c478bd9Sstevel@tonic-gate 				iinit++;
6317c478bd9Sstevel@tonic-gate 
6327c478bd9Sstevel@tonic-gate 				/*
6337c478bd9Sstevel@tonic-gate 				 *	Wrap once if necessary to
6347c478bd9Sstevel@tonic-gate 				 *	find entry in inittab
6357c478bd9Sstevel@tonic-gate 				 */
6367c478bd9Sstevel@tonic-gate 				if (*iinit == '\0') {
6377c478bd9Sstevel@tonic-gate 					if (!wrap) {
6387c478bd9Sstevel@tonic-gate 						iinit = inittab;
6397c478bd9Sstevel@tonic-gate 						wrap = 1;
6407c478bd9Sstevel@tonic-gate 					}
6417c478bd9Sstevel@tonic-gate 				}
6427c478bd9Sstevel@tonic-gate 			}
6437c478bd9Sstevel@tonic-gate 
6447c478bd9Sstevel@tonic-gate 			if (*iinit != '\0') {
6457c478bd9Sstevel@tonic-gate 				/*
6467c478bd9Sstevel@tonic-gate 				 *	We found our entry
6477c478bd9Sstevel@tonic-gate 				 */
6487c478bd9Sstevel@tonic-gate 				for (iinit++; *iinit != '#' &&
6497c478bd9Sstevel@tonic-gate 					 *iinit != '\n'; iinit++);
6507c478bd9Sstevel@tonic-gate 				if (*iinit == '#') {
6517c478bd9Sstevel@tonic-gate 					for (iinit++; *iinit == ' ' ||
6527c478bd9Sstevel@tonic-gate 						 *iinit == '\t'; iinit++);
6537c478bd9Sstevel@tonic-gate 					for (rc = 0; *iinit != '\n'; iinit++)
6547c478bd9Sstevel@tonic-gate 						comment[rc++] = *iinit;
6557c478bd9Sstevel@tonic-gate 					comment[rc] = '\0';
6567c478bd9Sstevel@tonic-gate 				} else
6577c478bd9Sstevel@tonic-gate 					(void) strcpy(comment, " ");
6587c478bd9Sstevel@tonic-gate 
6597c478bd9Sstevel@tonic-gate 				(void) printf("  %s", comment);
6607c478bd9Sstevel@tonic-gate 			} else
6617c478bd9Sstevel@tonic-gate 				iinit = inittab;	/* Reset pointer */
6627c478bd9Sstevel@tonic-gate 		}
6637c478bd9Sstevel@tonic-gate 		if (utmpp->ut_type == INIT_PROCESS)
6647c478bd9Sstevel@tonic-gate 			(void) printf(gettext("  id=%4.4s"), utmpp->ut_id);
6657c478bd9Sstevel@tonic-gate 	}
6667c478bd9Sstevel@tonic-gate #ifdef	XPG4
6677c478bd9Sstevel@tonic-gate 	else
6687c478bd9Sstevel@tonic-gate 		if (dopt && utmpp->ut_type == DEAD_PROCESS) {
6697c478bd9Sstevel@tonic-gate 			(void) printf(gettext("\tterm=%-3d "), pterm);
6707c478bd9Sstevel@tonic-gate 			(void) printf(gettext("exit=%d  "), pexit);
6717c478bd9Sstevel@tonic-gate 		}
6727c478bd9Sstevel@tonic-gate #endif	/* XPG4 */
6737c478bd9Sstevel@tonic-gate 
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 	/*
6767c478bd9Sstevel@tonic-gate 	 *	Handle RUN_LVL process - If no alt. file - Only one!
6777c478bd9Sstevel@tonic-gate 	 */
6787c478bd9Sstevel@tonic-gate 	if (utmpp->ut_type == RUN_LVL) {
6797c478bd9Sstevel@tonic-gate 		(void) printf("     %c  %5ld  %c", pterm, utmpp->ut_pid,
6807c478bd9Sstevel@tonic-gate 		    pexit);
6817c478bd9Sstevel@tonic-gate 		if (optcnt == 1 && !validtype[USER_PROCESS]) {
6827c478bd9Sstevel@tonic-gate 			(void) printf("\n");
6837c478bd9Sstevel@tonic-gate 			exit(0);
6847c478bd9Sstevel@tonic-gate 		}
6857c478bd9Sstevel@tonic-gate 	}
6867c478bd9Sstevel@tonic-gate 
6877c478bd9Sstevel@tonic-gate 	/*
6887c478bd9Sstevel@tonic-gate 	 *	Handle BOOT_TIME process -  If no alt. file - Only one!
6897c478bd9Sstevel@tonic-gate 	 */
6907c478bd9Sstevel@tonic-gate 	if (utmpp->ut_type == BOOT_TIME) {
6917c478bd9Sstevel@tonic-gate 		if (optcnt == 1 && !validtype[USER_PROCESS]) {
6927c478bd9Sstevel@tonic-gate 			(void) printf("\n");
6937c478bd9Sstevel@tonic-gate 			exit(0);
6947c478bd9Sstevel@tonic-gate 		}
6957c478bd9Sstevel@tonic-gate 	}
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate 	/*
6987c478bd9Sstevel@tonic-gate 	 *	Get remote host from utmpx structure
6997c478bd9Sstevel@tonic-gate 	 */
7007c478bd9Sstevel@tonic-gate 	if (utmpp && utmpp->ut_host[0])
7017c478bd9Sstevel@tonic-gate 		(void) printf("\t(%.*s)", sizeof (utmpp->ut_host),
7027c478bd9Sstevel@tonic-gate 		    utmpp->ut_host);
7037c478bd9Sstevel@tonic-gate 
7047c478bd9Sstevel@tonic-gate 	/*
7057c478bd9Sstevel@tonic-gate 	 *	Now, put on the trailing EOL
7067c478bd9Sstevel@tonic-gate 	 */
7077c478bd9Sstevel@tonic-gate 	(void) printf("\n");
7087c478bd9Sstevel@tonic-gate }
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate static void
7117c478bd9Sstevel@tonic-gate process()
7127c478bd9Sstevel@tonic-gate {
7137c478bd9Sstevel@tonic-gate 	struct passwd *pwp;
7147c478bd9Sstevel@tonic-gate 	int i = 0;
7157c478bd9Sstevel@tonic-gate 	char *ttname;
7167c478bd9Sstevel@tonic-gate 
7177c478bd9Sstevel@tonic-gate 	/*
7187c478bd9Sstevel@tonic-gate 	 *	Loop over each entry in /var/adm/utmpx
7197c478bd9Sstevel@tonic-gate 	 */
7207c478bd9Sstevel@tonic-gate 
7217c478bd9Sstevel@tonic-gate 	setutxent();
7227c478bd9Sstevel@tonic-gate 	while ((utmpp = getutxent()) != NULL) {
7237c478bd9Sstevel@tonic-gate #ifdef DEBUG
7247c478bd9Sstevel@tonic-gate 	(void) printf(
7257c478bd9Sstevel@tonic-gate 	    "ut_user '%s'\nut_id '%s'\nut_line '%s'\nut_type '%d'\n\n",
7267c478bd9Sstevel@tonic-gate 	    utmpp->ut_user, utmpp->ut_id, utmpp->ut_line, utmpp->ut_type);
7277c478bd9Sstevel@tonic-gate #endif
7287c478bd9Sstevel@tonic-gate 		if (utmpp->ut_type <= UTMAXTYPE) {
7297c478bd9Sstevel@tonic-gate 			/*
7307c478bd9Sstevel@tonic-gate 			 *	Handle "am i"
7317c478bd9Sstevel@tonic-gate 			 */
7327c478bd9Sstevel@tonic-gate 			if (justme) {
7337c478bd9Sstevel@tonic-gate 				if (strncmp(myname, utmpp->ut_user,
7347c478bd9Sstevel@tonic-gate 				    sizeof (utmpp->ut_user)) == 0 &&
7357c478bd9Sstevel@tonic-gate 				    strncmp(mytty, utmpp->ut_line,
7367c478bd9Sstevel@tonic-gate 					sizeof (utmpp->ut_line)) == 0 &&
7377c478bd9Sstevel@tonic-gate 				    utmpp->ut_type == USER_PROCESS) {
7387c478bd9Sstevel@tonic-gate 					/*
7397c478bd9Sstevel@tonic-gate 					 * we have have found ourselves
7407c478bd9Sstevel@tonic-gate 					 * in the utmp file and the entry
7417c478bd9Sstevel@tonic-gate 					 * is a user process, this is not
7427c478bd9Sstevel@tonic-gate 					 * meaningful otherwise
7437c478bd9Sstevel@tonic-gate 					 *
7447c478bd9Sstevel@tonic-gate 					 */
7457c478bd9Sstevel@tonic-gate 
7467c478bd9Sstevel@tonic-gate 					dump();
7477c478bd9Sstevel@tonic-gate 					exit(0);
7487c478bd9Sstevel@tonic-gate 				}
7497c478bd9Sstevel@tonic-gate 				continue;
7507c478bd9Sstevel@tonic-gate 			}
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate 			/*
7537c478bd9Sstevel@tonic-gate 			 *	Print the line if we want it
7547c478bd9Sstevel@tonic-gate 			 */
7557c478bd9Sstevel@tonic-gate 			if (validtype[utmpp->ut_type]) {
7567c478bd9Sstevel@tonic-gate #ifdef	XPG4
7577c478bd9Sstevel@tonic-gate 				if (utmpp->ut_type == LOGIN_PROCESS) {
7587c478bd9Sstevel@tonic-gate 					if ((utmpp->ut_line[0] == '\0') ||
7597c478bd9Sstevel@tonic-gate 					(strcmp(utmpp->ut_user, "LOGIN") != 0))
7607c478bd9Sstevel@tonic-gate 						continue;
7617c478bd9Sstevel@tonic-gate 				}
7627c478bd9Sstevel@tonic-gate #endif	/* XPG4 */
7637c478bd9Sstevel@tonic-gate 				dump();
7647c478bd9Sstevel@tonic-gate 			}
7657c478bd9Sstevel@tonic-gate 		} else {
7667c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
7677c478bd9Sstevel@tonic-gate 			    gettext("%s: Error --- entry has ut_type "
7687c478bd9Sstevel@tonic-gate 				"of %d\n"), program, utmpp->ut_type);
7697c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
7707c478bd9Sstevel@tonic-gate 			    gettext(" when maximum is %d\n"), UTMAXTYPE);
7717c478bd9Sstevel@tonic-gate 		}
7727c478bd9Sstevel@tonic-gate 	}
7737c478bd9Sstevel@tonic-gate 
7747c478bd9Sstevel@tonic-gate 	/*
7757c478bd9Sstevel@tonic-gate 	 * If justme is set at this point than the utmp entry
7767c478bd9Sstevel@tonic-gate 	 * was not found.
7777c478bd9Sstevel@tonic-gate 	 */
7787c478bd9Sstevel@tonic-gate 	if (justme) {
7797c478bd9Sstevel@tonic-gate 		static struct utmpx utmpt;
7807c478bd9Sstevel@tonic-gate 
7817c478bd9Sstevel@tonic-gate 		pwp = getpwuid(geteuid());
7827c478bd9Sstevel@tonic-gate 		if (pwp != NULL)
7837c478bd9Sstevel@tonic-gate 			while (i < (int)sizeof (utmpt.ut_user) &&
7847c478bd9Sstevel@tonic-gate 			    *pwp->pw_name != 0)
7857c478bd9Sstevel@tonic-gate 				utmpt.ut_user[i++] = *pwp->pw_name++;
7867c478bd9Sstevel@tonic-gate 
7877c478bd9Sstevel@tonic-gate 		ttname = ttyname(1);
7887c478bd9Sstevel@tonic-gate 
7897c478bd9Sstevel@tonic-gate 		i = 0;
7907c478bd9Sstevel@tonic-gate 		if (ttname != NULL)
7917c478bd9Sstevel@tonic-gate 			while (i < (int)sizeof (utmpt.ut_line) &&
7927c478bd9Sstevel@tonic-gate 			    *ttname != 0)
7937c478bd9Sstevel@tonic-gate 				utmpt.ut_line[i++] = *ttname++;
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate 		utmpt.ut_id[0] = 0;
7967c478bd9Sstevel@tonic-gate 		utmpt.ut_pid = getpid();
7977c478bd9Sstevel@tonic-gate 		utmpt.ut_type = USER_PROCESS;
7987c478bd9Sstevel@tonic-gate 		(void) time(&utmpt.ut_xtime);
7997c478bd9Sstevel@tonic-gate 		utmpp = &utmpt;
8007c478bd9Sstevel@tonic-gate 		dump();
8017c478bd9Sstevel@tonic-gate 		exit(0);
8027c478bd9Sstevel@tonic-gate 	}
8037c478bd9Sstevel@tonic-gate }
8047c478bd9Sstevel@tonic-gate 
8057c478bd9Sstevel@tonic-gate /*
8067c478bd9Sstevel@tonic-gate  *	This routine checks the following:
8077c478bd9Sstevel@tonic-gate  *
8087c478bd9Sstevel@tonic-gate  *	1.	File exists
8097c478bd9Sstevel@tonic-gate  *
8107c478bd9Sstevel@tonic-gate  *	2.	We have read permissions
8117c478bd9Sstevel@tonic-gate  *
8127c478bd9Sstevel@tonic-gate  *	3.	It is a multiple of utmp entries in size
8137c478bd9Sstevel@tonic-gate  *
8147c478bd9Sstevel@tonic-gate  *	Failing any of these conditions causes who(1) to
8157c478bd9Sstevel@tonic-gate  *	abort processing.
8167c478bd9Sstevel@tonic-gate  *
8177c478bd9Sstevel@tonic-gate  *	4.	If file is empty we exit right away as there
8187c478bd9Sstevel@tonic-gate  *		is no info to report on.
8197c478bd9Sstevel@tonic-gate  *
8207c478bd9Sstevel@tonic-gate  *	This routine does not check utmpx files.
8217c478bd9Sstevel@tonic-gate  */
8227c478bd9Sstevel@tonic-gate static void
8237c478bd9Sstevel@tonic-gate ck_file(char *name)
8247c478bd9Sstevel@tonic-gate {
8257c478bd9Sstevel@tonic-gate 	struct	stat sbuf;
8267c478bd9Sstevel@tonic-gate 	int	rc;
8277c478bd9Sstevel@tonic-gate 
8287c478bd9Sstevel@tonic-gate 	/*
8297c478bd9Sstevel@tonic-gate 	 *	Does file exist? Do stat to check, and save structure
8307c478bd9Sstevel@tonic-gate 	 *	so that we can check on the file's size later on.
8317c478bd9Sstevel@tonic-gate 	 */
8327c478bd9Sstevel@tonic-gate 	if ((rc = stat(name, &sbuf)) == -1) {
8337c478bd9Sstevel@tonic-gate 		(void) snprintf(errmsg, sizeof (errmsg),
8347c478bd9Sstevel@tonic-gate 		    gettext("%s: Cannot stat file '%s'"), program, name);
8357c478bd9Sstevel@tonic-gate 		perror(errmsg);
8367c478bd9Sstevel@tonic-gate 		exit(1);
8377c478bd9Sstevel@tonic-gate 	}
8387c478bd9Sstevel@tonic-gate 
8397c478bd9Sstevel@tonic-gate 	/*
8407c478bd9Sstevel@tonic-gate 	 *	The only real way we can be sure we can access the
8417c478bd9Sstevel@tonic-gate 	 *	file is to try. If we succeed then we close it.
8427c478bd9Sstevel@tonic-gate 	 */
8437c478bd9Sstevel@tonic-gate 	if (access(name, R_OK) < 0) {
8447c478bd9Sstevel@tonic-gate 		(void) snprintf(errmsg, sizeof (errmsg),
8457c478bd9Sstevel@tonic-gate 		    gettext("%s: Cannot open file '%s'"), program, name);
8467c478bd9Sstevel@tonic-gate 		perror(errmsg);
8477c478bd9Sstevel@tonic-gate 		exit(1);
8487c478bd9Sstevel@tonic-gate 	}
8497c478bd9Sstevel@tonic-gate 
8507c478bd9Sstevel@tonic-gate 	/*
8517c478bd9Sstevel@tonic-gate 	 *	If the file is empty, we are all done.
8527c478bd9Sstevel@tonic-gate 	 */
8537c478bd9Sstevel@tonic-gate 	if (!sbuf.st_size)
8547c478bd9Sstevel@tonic-gate 		exit(0);
8557c478bd9Sstevel@tonic-gate 
8567c478bd9Sstevel@tonic-gate 	/*
8577c478bd9Sstevel@tonic-gate 	 *	Make sure the file is a utmp file.
8587c478bd9Sstevel@tonic-gate 	 *	We can only check for size being a multiple of
8597c478bd9Sstevel@tonic-gate 	 *	utmp structures in length.
8607c478bd9Sstevel@tonic-gate 	 */
8617c478bd9Sstevel@tonic-gate 	rc = sbuf.st_size % (int)sizeof (struct utmpx);
8627c478bd9Sstevel@tonic-gate 	if (rc) {
8637c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: File '%s' is not "
8647c478bd9Sstevel@tonic-gate 		    "a utmpx file\n"), program, name);
8657c478bd9Sstevel@tonic-gate 		exit(1);
8667c478bd9Sstevel@tonic-gate 	}
8677c478bd9Sstevel@tonic-gate }
868