xref: /titanic_53/usr/src/cmd/whodo/whodo.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 /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved	*/
29*7c478bd9Sstevel@tonic-gate 
30*7c478bd9Sstevel@tonic-gate /*
31*7c478bd9Sstevel@tonic-gate  * University Copyright- Copyright (c) 1982, 1986, 1988
32*7c478bd9Sstevel@tonic-gate  * The Regents of the University of California
33*7c478bd9Sstevel@tonic-gate  * All Rights Reserved
34*7c478bd9Sstevel@tonic-gate  *
35*7c478bd9Sstevel@tonic-gate  * University Acknowledgment- Portions of this document are derived from
36*7c478bd9Sstevel@tonic-gate  * software developed by the University of California, Berkeley, and its
37*7c478bd9Sstevel@tonic-gate  * contributors.
38*7c478bd9Sstevel@tonic-gate  */
39*7c478bd9Sstevel@tonic-gate 
40*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
41*7c478bd9Sstevel@tonic-gate 
42*7c478bd9Sstevel@tonic-gate /*
43*7c478bd9Sstevel@tonic-gate  * This is the new whodo command which takes advantage of
44*7c478bd9Sstevel@tonic-gate  * the /proc interface to gain access to the information
45*7c478bd9Sstevel@tonic-gate  * of all the processes currently on the system.
46*7c478bd9Sstevel@tonic-gate  *
47*7c478bd9Sstevel@tonic-gate  * Maintenance note:
48*7c478bd9Sstevel@tonic-gate  *
49*7c478bd9Sstevel@tonic-gate  * Much of this code is replicated in w.c.  If you're
50*7c478bd9Sstevel@tonic-gate  * fixing bugs here, then you should probably fix 'em there too.
51*7c478bd9Sstevel@tonic-gate  */
52*7c478bd9Sstevel@tonic-gate 
53*7c478bd9Sstevel@tonic-gate #include <stdio.h>
54*7c478bd9Sstevel@tonic-gate #include <string.h>
55*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
56*7c478bd9Sstevel@tonic-gate #include <ctype.h>
57*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
58*7c478bd9Sstevel@tonic-gate #include <time.h>
59*7c478bd9Sstevel@tonic-gate #include <errno.h>
60*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
61*7c478bd9Sstevel@tonic-gate #include <utmpx.h>
62*7c478bd9Sstevel@tonic-gate #include <sys/utsname.h>
63*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
64*7c478bd9Sstevel@tonic-gate #include <sys/mkdev.h>
65*7c478bd9Sstevel@tonic-gate #include <dirent.h>
66*7c478bd9Sstevel@tonic-gate #include <procfs.h>		/* /proc header file */
67*7c478bd9Sstevel@tonic-gate #include <sys/wait.h>
68*7c478bd9Sstevel@tonic-gate #include <locale.h>
69*7c478bd9Sstevel@tonic-gate #include <unistd.h>
70*7c478bd9Sstevel@tonic-gate #include <limits.h>
71*7c478bd9Sstevel@tonic-gate #include <priv_utils.h>
72*7c478bd9Sstevel@tonic-gate 
73*7c478bd9Sstevel@tonic-gate /*
74*7c478bd9Sstevel@tonic-gate  * utmpx defines wider fields for user and line.  For compatibility of output,
75*7c478bd9Sstevel@tonic-gate  * we are limiting these to the old maximums in utmp. Define UTMPX_NAMELEN
76*7c478bd9Sstevel@tonic-gate  * to use the full lengths.
77*7c478bd9Sstevel@tonic-gate  */
78*7c478bd9Sstevel@tonic-gate #ifndef UTMPX_NAMELEN
79*7c478bd9Sstevel@tonic-gate /* XXX - utmp - fix name length */
80*7c478bd9Sstevel@tonic-gate #define	NMAX		(_POSIX_LOGIN_NAME_MAX - 1)
81*7c478bd9Sstevel@tonic-gate #define	LMAX		12
82*7c478bd9Sstevel@tonic-gate #else /* UTMPX_NAMELEN */
83*7c478bd9Sstevel@tonic-gate static struct utmpx dummy;
84*7c478bd9Sstevel@tonic-gate #define	NMAX	(sizeof (dummy.ut_user))
85*7c478bd9Sstevel@tonic-gate #define	LMAX	(sizeof (dummy.ut_line))
86*7c478bd9Sstevel@tonic-gate #endif /* UTMPX_NAMELEN */
87*7c478bd9Sstevel@tonic-gate 
88*7c478bd9Sstevel@tonic-gate #define	DIV60(t)	((t+30)/60)    /* x/60 rounded */
89*7c478bd9Sstevel@tonic-gate 
90*7c478bd9Sstevel@tonic-gate #ifdef ERR
91*7c478bd9Sstevel@tonic-gate #undef ERR
92*7c478bd9Sstevel@tonic-gate #endif
93*7c478bd9Sstevel@tonic-gate #define	ERR		(-1)
94*7c478bd9Sstevel@tonic-gate 
95*7c478bd9Sstevel@tonic-gate #define	DEVNAMELEN	14
96*7c478bd9Sstevel@tonic-gate #define	HSIZE		256		/* size of process hash table */
97*7c478bd9Sstevel@tonic-gate #define	PROCDIR		"/proc"
98*7c478bd9Sstevel@tonic-gate #define	INITPROCESS	(pid_t)1	/* init process pid */
99*7c478bd9Sstevel@tonic-gate #define	NONE		'n'		/* no state */
100*7c478bd9Sstevel@tonic-gate #define	RUNNING		'r'		/* runnable process */
101*7c478bd9Sstevel@tonic-gate #define	ZOMBIE		'z'		/* zombie process */
102*7c478bd9Sstevel@tonic-gate #define	VISITED		'v'		/* marked node as visited */
103*7c478bd9Sstevel@tonic-gate 
104*7c478bd9Sstevel@tonic-gate static int	ndevs;			/* number of configured devices */
105*7c478bd9Sstevel@tonic-gate static int	maxdev;			/* slots for configured devices */
106*7c478bd9Sstevel@tonic-gate #define	DNINCR	100
107*7c478bd9Sstevel@tonic-gate static struct devl {			/* device list   */
108*7c478bd9Sstevel@tonic-gate 	char	dname[DEVNAMELEN];	/* device name   */
109*7c478bd9Sstevel@tonic-gate 	dev_t	ddev;			/* device number */
110*7c478bd9Sstevel@tonic-gate } *devl;
111*7c478bd9Sstevel@tonic-gate 
112*7c478bd9Sstevel@tonic-gate struct uproc {
113*7c478bd9Sstevel@tonic-gate 	pid_t	p_upid;			/* user process id */
114*7c478bd9Sstevel@tonic-gate 	char	p_state;		/* numeric value of process state */
115*7c478bd9Sstevel@tonic-gate 	dev_t	p_ttyd;			/* controlling tty of process */
116*7c478bd9Sstevel@tonic-gate 	time_t	p_time;			/* ticks of user & system time */
117*7c478bd9Sstevel@tonic-gate 	time_t	p_ctime;		/* ticks of child user & system time */
118*7c478bd9Sstevel@tonic-gate 	int	p_igintr;		/* 1=ignores SIGQUIT and SIGINT */
119*7c478bd9Sstevel@tonic-gate 	char	p_comm[PRARGSZ+1];	/* command */
120*7c478bd9Sstevel@tonic-gate 	char	p_args[PRARGSZ+1];	/* command line arguments */
121*7c478bd9Sstevel@tonic-gate 	struct uproc	*p_child,	/* first child pointer */
122*7c478bd9Sstevel@tonic-gate 			*p_sibling,	/* sibling pointer */
123*7c478bd9Sstevel@tonic-gate 			*p_pgrplink,	/* pgrp link */
124*7c478bd9Sstevel@tonic-gate 			*p_link;	/* hash table chain pointer */
125*7c478bd9Sstevel@tonic-gate };
126*7c478bd9Sstevel@tonic-gate 
127*7c478bd9Sstevel@tonic-gate /*
128*7c478bd9Sstevel@tonic-gate  *	define	hash table for struct uproc
129*7c478bd9Sstevel@tonic-gate  *	Hash function uses process id
130*7c478bd9Sstevel@tonic-gate  *	and the size of the hash table(HSIZE)
131*7c478bd9Sstevel@tonic-gate  *	to determine process index into the table.
132*7c478bd9Sstevel@tonic-gate  */
133*7c478bd9Sstevel@tonic-gate static struct uproc	pr_htbl[HSIZE];
134*7c478bd9Sstevel@tonic-gate 
135*7c478bd9Sstevel@tonic-gate static struct	uproc	*findhash(pid_t);
136*7c478bd9Sstevel@tonic-gate static time_t	findidle(char *);
137*7c478bd9Sstevel@tonic-gate static void	clnarglist(char *);
138*7c478bd9Sstevel@tonic-gate static void	showproc(struct uproc *);
139*7c478bd9Sstevel@tonic-gate static void	showtotals(struct uproc *);
140*7c478bd9Sstevel@tonic-gate static void	calctotals(struct uproc *);
141*7c478bd9Sstevel@tonic-gate static char	*getty(dev_t);
142*7c478bd9Sstevel@tonic-gate static void	prttime(time_t, char *);
143*7c478bd9Sstevel@tonic-gate static void	prtat(time_t *);
144*7c478bd9Sstevel@tonic-gate static void	checkampm(char *);
145*7c478bd9Sstevel@tonic-gate 
146*7c478bd9Sstevel@tonic-gate static char	*prog;
147*7c478bd9Sstevel@tonic-gate static int	header = 1;	/* true if -h flag: don't print heading */
148*7c478bd9Sstevel@tonic-gate static int	lflag = 0;	/* true if -l flag: w command format */
149*7c478bd9Sstevel@tonic-gate static char 	*sel_user;	/* login of particular user selected */
150*7c478bd9Sstevel@tonic-gate static time_t	now;		/* current time of day */
151*7c478bd9Sstevel@tonic-gate static time_t	uptime;		/* time of last reboot & elapsed time since */
152*7c478bd9Sstevel@tonic-gate static int	nusers;		/* number of users logged in now */
153*7c478bd9Sstevel@tonic-gate static time_t	idle;		/* number of minutes user is idle */
154*7c478bd9Sstevel@tonic-gate static time_t	jobtime;	/* total cpu time visible */
155*7c478bd9Sstevel@tonic-gate static char	doing[520];	/* process attached to terminal */
156*7c478bd9Sstevel@tonic-gate static time_t	proctime;	/* cpu time of process in doing */
157*7c478bd9Sstevel@tonic-gate static int	empty;
158*7c478bd9Sstevel@tonic-gate static pid_t	curpid;
159*7c478bd9Sstevel@tonic-gate 
160*7c478bd9Sstevel@tonic-gate #if SIGQUIT > SIGINT
161*7c478bd9Sstevel@tonic-gate #define	ACTSIZE	SIGQUIT
162*7c478bd9Sstevel@tonic-gate #else
163*7c478bd9Sstevel@tonic-gate #define	ACTSIZE	SIGINT
164*7c478bd9Sstevel@tonic-gate #endif
165*7c478bd9Sstevel@tonic-gate 
166*7c478bd9Sstevel@tonic-gate int
167*7c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
168*7c478bd9Sstevel@tonic-gate {
169*7c478bd9Sstevel@tonic-gate 	struct utmpx	*ut;
170*7c478bd9Sstevel@tonic-gate 	struct utmpx	*utmpbegin;
171*7c478bd9Sstevel@tonic-gate 	struct utmpx	*utmpend;
172*7c478bd9Sstevel@tonic-gate 	struct utmpx 	*utp;
173*7c478bd9Sstevel@tonic-gate 	struct tm		*tm;
174*7c478bd9Sstevel@tonic-gate 	struct uproc	*up, *parent, *pgrp;
175*7c478bd9Sstevel@tonic-gate 	struct psinfo	info;
176*7c478bd9Sstevel@tonic-gate 	struct sigaction actinfo[ACTSIZE];
177*7c478bd9Sstevel@tonic-gate 	struct pstatus	statinfo;
178*7c478bd9Sstevel@tonic-gate 	size_t		size;
179*7c478bd9Sstevel@tonic-gate 	struct stat	sbuf;
180*7c478bd9Sstevel@tonic-gate 	struct utsname	uts;
181*7c478bd9Sstevel@tonic-gate 	DIR		*dirp;
182*7c478bd9Sstevel@tonic-gate 	struct	dirent	*dp;
183*7c478bd9Sstevel@tonic-gate 	char 		pname[64];
184*7c478bd9Sstevel@tonic-gate 	char 		*fname;
185*7c478bd9Sstevel@tonic-gate 	int		procfd;
186*7c478bd9Sstevel@tonic-gate 	int		i;
187*7c478bd9Sstevel@tonic-gate 	int		days, hrs, mins;
188*7c478bd9Sstevel@tonic-gate 	int		entries;
189*7c478bd9Sstevel@tonic-gate 
190*7c478bd9Sstevel@tonic-gate 	/*
191*7c478bd9Sstevel@tonic-gate 	 * This program needs the proc_owner privilege
192*7c478bd9Sstevel@tonic-gate 	 */
193*7c478bd9Sstevel@tonic-gate 	(void) __init_suid_priv(PU_CLEARLIMITSET, PRIV_PROC_OWNER,
194*7c478bd9Sstevel@tonic-gate 	    (char *)NULL);
195*7c478bd9Sstevel@tonic-gate 
196*7c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
197*7c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
198*7c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
199*7c478bd9Sstevel@tonic-gate #endif
200*7c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
201*7c478bd9Sstevel@tonic-gate 
202*7c478bd9Sstevel@tonic-gate 	prog = argv[0];
203*7c478bd9Sstevel@tonic-gate 
204*7c478bd9Sstevel@tonic-gate 	while (argc > 1) {
205*7c478bd9Sstevel@tonic-gate 		if (argv[1][0] == '-') {
206*7c478bd9Sstevel@tonic-gate 			for (i = 1; argv[1][i]; i++) {
207*7c478bd9Sstevel@tonic-gate 				switch (argv[1][i]) {
208*7c478bd9Sstevel@tonic-gate 
209*7c478bd9Sstevel@tonic-gate 				case 'h':
210*7c478bd9Sstevel@tonic-gate 					header = 0;
211*7c478bd9Sstevel@tonic-gate 					break;
212*7c478bd9Sstevel@tonic-gate 
213*7c478bd9Sstevel@tonic-gate 				case 'l':
214*7c478bd9Sstevel@tonic-gate 					lflag++;
215*7c478bd9Sstevel@tonic-gate 					break;
216*7c478bd9Sstevel@tonic-gate 
217*7c478bd9Sstevel@tonic-gate 				default:
218*7c478bd9Sstevel@tonic-gate 					(void) printf(gettext(
219*7c478bd9Sstevel@tonic-gate 					    "usage: %s [ -hl ] [ user ]\n"),
220*7c478bd9Sstevel@tonic-gate 					    prog);
221*7c478bd9Sstevel@tonic-gate 					exit(1);
222*7c478bd9Sstevel@tonic-gate 				}
223*7c478bd9Sstevel@tonic-gate 			}
224*7c478bd9Sstevel@tonic-gate 		} else {
225*7c478bd9Sstevel@tonic-gate 			if (!isalnum(argv[1][0]) || argc > 2) {
226*7c478bd9Sstevel@tonic-gate 				(void) printf(gettext(
227*7c478bd9Sstevel@tonic-gate 				    "usage: %s [ -hl ] [ user ]\n"), prog);
228*7c478bd9Sstevel@tonic-gate 				exit(1);
229*7c478bd9Sstevel@tonic-gate 			} else
230*7c478bd9Sstevel@tonic-gate 				sel_user = argv[1];
231*7c478bd9Sstevel@tonic-gate 		}
232*7c478bd9Sstevel@tonic-gate 		argc--; argv++;
233*7c478bd9Sstevel@tonic-gate 	}
234*7c478bd9Sstevel@tonic-gate 
235*7c478bd9Sstevel@tonic-gate 	/*
236*7c478bd9Sstevel@tonic-gate 	 * read the UTMPX_FILE (contains information about
237*7c478bd9Sstevel@tonic-gate 	 * each logged in user)
238*7c478bd9Sstevel@tonic-gate 	 */
239*7c478bd9Sstevel@tonic-gate 	if (stat(UTMPX_FILE, &sbuf) == ERR) {
240*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: stat error of %s: %s\n"),
241*7c478bd9Sstevel@tonic-gate 			prog, UTMPX_FILE, strerror(errno));
242*7c478bd9Sstevel@tonic-gate 		exit(1);
243*7c478bd9Sstevel@tonic-gate 	}
244*7c478bd9Sstevel@tonic-gate 	entries = sbuf.st_size / sizeof (struct futmpx);
245*7c478bd9Sstevel@tonic-gate 	size = sizeof (struct utmpx) * entries;
246*7c478bd9Sstevel@tonic-gate 
247*7c478bd9Sstevel@tonic-gate 	if ((ut = malloc(size)) == NULL) {
248*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: malloc error of %s: %s\n"),
249*7c478bd9Sstevel@tonic-gate 			prog, UTMPX_FILE, strerror(errno));
250*7c478bd9Sstevel@tonic-gate 		exit(1);
251*7c478bd9Sstevel@tonic-gate 	}
252*7c478bd9Sstevel@tonic-gate 
253*7c478bd9Sstevel@tonic-gate 	(void) utmpxname(UTMPX_FILE);
254*7c478bd9Sstevel@tonic-gate 
255*7c478bd9Sstevel@tonic-gate 	utmpbegin = ut;
256*7c478bd9Sstevel@tonic-gate 	/* LINTED pointer cast may result in improper alignment */
257*7c478bd9Sstevel@tonic-gate 	utmpend = (struct utmpx *)((char *)utmpbegin + size);
258*7c478bd9Sstevel@tonic-gate 
259*7c478bd9Sstevel@tonic-gate 	setutxent();
260*7c478bd9Sstevel@tonic-gate 	while ((utp = getutxent()) != NULL)
261*7c478bd9Sstevel@tonic-gate 		(void) memcpy(ut++, utp, sizeof (*ut));
262*7c478bd9Sstevel@tonic-gate 	endutxent();
263*7c478bd9Sstevel@tonic-gate 
264*7c478bd9Sstevel@tonic-gate 	(void) time(&now);	/* get current time */
265*7c478bd9Sstevel@tonic-gate 
266*7c478bd9Sstevel@tonic-gate 	if (header) {	/* print a header */
267*7c478bd9Sstevel@tonic-gate 		if (lflag) {	/* w command format header */
268*7c478bd9Sstevel@tonic-gate 			prtat(&now);
269*7c478bd9Sstevel@tonic-gate 			for (ut = utmpbegin; ut < utmpend; ut++) {
270*7c478bd9Sstevel@tonic-gate 				if (ut->ut_type == USER_PROCESS) {
271*7c478bd9Sstevel@tonic-gate 					nusers++;
272*7c478bd9Sstevel@tonic-gate 				} else if (ut->ut_type == BOOT_TIME) {
273*7c478bd9Sstevel@tonic-gate 					uptime = now - ut->ut_xtime;
274*7c478bd9Sstevel@tonic-gate 					uptime += 30;
275*7c478bd9Sstevel@tonic-gate 					days = uptime / (60*60*24);
276*7c478bd9Sstevel@tonic-gate 					uptime %= (60*60*24);
277*7c478bd9Sstevel@tonic-gate 					hrs = uptime / (60*60);
278*7c478bd9Sstevel@tonic-gate 					uptime %= (60*60);
279*7c478bd9Sstevel@tonic-gate 					mins = uptime / 60;
280*7c478bd9Sstevel@tonic-gate 
281*7c478bd9Sstevel@tonic-gate 					(void) printf(dcgettext(NULL,
282*7c478bd9Sstevel@tonic-gate 					    "  up %d day(s), %d hr(s), "
283*7c478bd9Sstevel@tonic-gate 					    "%d min(s)", LC_TIME),
284*7c478bd9Sstevel@tonic-gate 					    days, hrs, mins);
285*7c478bd9Sstevel@tonic-gate 				}
286*7c478bd9Sstevel@tonic-gate 			}
287*7c478bd9Sstevel@tonic-gate 
288*7c478bd9Sstevel@tonic-gate 			ut = utmpbegin; /* rewind utmp data */
289*7c478bd9Sstevel@tonic-gate 			(void) printf(dcgettext(NULL,
290*7c478bd9Sstevel@tonic-gate 			    "  %d user(s)\n", LC_TIME), nusers);
291*7c478bd9Sstevel@tonic-gate 			(void) printf(dcgettext(NULL, "User     tty           "
292*7c478bd9Sstevel@tonic-gate 			    "login@  idle   JCPU   PCPU  what\n", LC_TIME));
293*7c478bd9Sstevel@tonic-gate 		} else {	/* standard whodo header */
294*7c478bd9Sstevel@tonic-gate 			char date_buf[100];
295*7c478bd9Sstevel@tonic-gate 
296*7c478bd9Sstevel@tonic-gate 			/*
297*7c478bd9Sstevel@tonic-gate 			 * print current time and date
298*7c478bd9Sstevel@tonic-gate 			 */
299*7c478bd9Sstevel@tonic-gate 			(void) strftime(date_buf, sizeof (date_buf),
300*7c478bd9Sstevel@tonic-gate 			    dcgettext(NULL, "%C", LC_TIME), localtime(&now));
301*7c478bd9Sstevel@tonic-gate 			(void) printf("%s\n", date_buf);
302*7c478bd9Sstevel@tonic-gate 
303*7c478bd9Sstevel@tonic-gate 			/*
304*7c478bd9Sstevel@tonic-gate 			 * print system name
305*7c478bd9Sstevel@tonic-gate 			 */
306*7c478bd9Sstevel@tonic-gate 			(void) uname(&uts);
307*7c478bd9Sstevel@tonic-gate 			(void) printf("%s\n", uts.nodename);
308*7c478bd9Sstevel@tonic-gate 		}
309*7c478bd9Sstevel@tonic-gate 	}
310*7c478bd9Sstevel@tonic-gate 
311*7c478bd9Sstevel@tonic-gate 	/*
312*7c478bd9Sstevel@tonic-gate 	 * loop through /proc, reading info about each process
313*7c478bd9Sstevel@tonic-gate 	 * and build the parent/child tree
314*7c478bd9Sstevel@tonic-gate 	 */
315*7c478bd9Sstevel@tonic-gate 	if (!(dirp = opendir(PROCDIR))) {
316*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: could not open %s: %s\n"),
317*7c478bd9Sstevel@tonic-gate 			prog, PROCDIR, strerror(errno));
318*7c478bd9Sstevel@tonic-gate 		exit(1);
319*7c478bd9Sstevel@tonic-gate 	}
320*7c478bd9Sstevel@tonic-gate 
321*7c478bd9Sstevel@tonic-gate 	while ((dp = readdir(dirp)) != NULL) {
322*7c478bd9Sstevel@tonic-gate 		if (dp->d_name[0] == '.')
323*7c478bd9Sstevel@tonic-gate 			continue;
324*7c478bd9Sstevel@tonic-gate retry:
325*7c478bd9Sstevel@tonic-gate 		(void) snprintf(pname, sizeof (pname),
326*7c478bd9Sstevel@tonic-gate 			"%s/%s/", PROCDIR, dp->d_name);
327*7c478bd9Sstevel@tonic-gate 		fname = pname + strlen(pname);
328*7c478bd9Sstevel@tonic-gate 		(void) strcpy(fname, "psinfo");
329*7c478bd9Sstevel@tonic-gate 		if ((procfd = open(pname, O_RDONLY)) < 0)
330*7c478bd9Sstevel@tonic-gate 			continue;
331*7c478bd9Sstevel@tonic-gate 		if (read(procfd, &info, sizeof (info)) != sizeof (info)) {
332*7c478bd9Sstevel@tonic-gate 			int err = errno;
333*7c478bd9Sstevel@tonic-gate 			(void) close(procfd);
334*7c478bd9Sstevel@tonic-gate 			if (err == EAGAIN)
335*7c478bd9Sstevel@tonic-gate 				goto retry;
336*7c478bd9Sstevel@tonic-gate 			if (err != ENOENT)
337*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
338*7c478bd9Sstevel@tonic-gate 				    "%s: read() failed on %s: %s\n"),
339*7c478bd9Sstevel@tonic-gate 				    prog, pname, strerror(err));
340*7c478bd9Sstevel@tonic-gate 			continue;
341*7c478bd9Sstevel@tonic-gate 		}
342*7c478bd9Sstevel@tonic-gate 		(void) close(procfd);
343*7c478bd9Sstevel@tonic-gate 
344*7c478bd9Sstevel@tonic-gate 		up = findhash(info.pr_pid);
345*7c478bd9Sstevel@tonic-gate 		up->p_ttyd = info.pr_ttydev;
346*7c478bd9Sstevel@tonic-gate 		up->p_state = (info.pr_nlwp == 0? ZOMBIE : RUNNING);
347*7c478bd9Sstevel@tonic-gate 		up->p_time = 0;
348*7c478bd9Sstevel@tonic-gate 		up->p_ctime = 0;
349*7c478bd9Sstevel@tonic-gate 		up->p_igintr = 0;
350*7c478bd9Sstevel@tonic-gate 		(void) strncpy(up->p_comm, info.pr_fname,
351*7c478bd9Sstevel@tonic-gate 		    sizeof (info.pr_fname));
352*7c478bd9Sstevel@tonic-gate 		up->p_args[0] = 0;
353*7c478bd9Sstevel@tonic-gate 
354*7c478bd9Sstevel@tonic-gate 		if (up->p_state != NONE && up->p_state != ZOMBIE) {
355*7c478bd9Sstevel@tonic-gate 			(void) strcpy(fname, "status");
356*7c478bd9Sstevel@tonic-gate 
357*7c478bd9Sstevel@tonic-gate 			/* now we need the proc_owner privilege */
358*7c478bd9Sstevel@tonic-gate 			(void) __priv_bracket(PRIV_ON);
359*7c478bd9Sstevel@tonic-gate 
360*7c478bd9Sstevel@tonic-gate 			procfd = open(pname, O_RDONLY);
361*7c478bd9Sstevel@tonic-gate 
362*7c478bd9Sstevel@tonic-gate 			/* drop proc_owner privilege after open */
363*7c478bd9Sstevel@tonic-gate 			(void) __priv_bracket(PRIV_OFF);
364*7c478bd9Sstevel@tonic-gate 
365*7c478bd9Sstevel@tonic-gate 			if (procfd  < 0)
366*7c478bd9Sstevel@tonic-gate 				continue;
367*7c478bd9Sstevel@tonic-gate 
368*7c478bd9Sstevel@tonic-gate 			if (read(procfd, &statinfo, sizeof (statinfo))
369*7c478bd9Sstevel@tonic-gate 			    != sizeof (statinfo)) {
370*7c478bd9Sstevel@tonic-gate 				int err = errno;
371*7c478bd9Sstevel@tonic-gate 				(void) close(procfd);
372*7c478bd9Sstevel@tonic-gate 				if (err == EAGAIN)
373*7c478bd9Sstevel@tonic-gate 					goto retry;
374*7c478bd9Sstevel@tonic-gate 				if (err != ENOENT)
375*7c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr, gettext(
376*7c478bd9Sstevel@tonic-gate 					    "%s: read() failed on %s: %s \n"),
377*7c478bd9Sstevel@tonic-gate 					    prog, pname, strerror(err));
378*7c478bd9Sstevel@tonic-gate 				continue;
379*7c478bd9Sstevel@tonic-gate 			}
380*7c478bd9Sstevel@tonic-gate 			(void) close(procfd);
381*7c478bd9Sstevel@tonic-gate 
382*7c478bd9Sstevel@tonic-gate 			up->p_time = statinfo.pr_utime.tv_sec +
383*7c478bd9Sstevel@tonic-gate 			    statinfo.pr_stime.tv_sec;
384*7c478bd9Sstevel@tonic-gate 			up->p_ctime = statinfo.pr_cutime.tv_sec +
385*7c478bd9Sstevel@tonic-gate 			    statinfo.pr_cstime.tv_sec;
386*7c478bd9Sstevel@tonic-gate 
387*7c478bd9Sstevel@tonic-gate 			(void) strcpy(fname, "sigact");
388*7c478bd9Sstevel@tonic-gate 
389*7c478bd9Sstevel@tonic-gate 			/* now we need the proc_owner privilege */
390*7c478bd9Sstevel@tonic-gate 			(void) __priv_bracket(PRIV_ON);
391*7c478bd9Sstevel@tonic-gate 
392*7c478bd9Sstevel@tonic-gate 			procfd = open(pname, O_RDONLY);
393*7c478bd9Sstevel@tonic-gate 
394*7c478bd9Sstevel@tonic-gate 			/* drop proc_owner privilege after open */
395*7c478bd9Sstevel@tonic-gate 			(void) __priv_bracket(PRIV_OFF);
396*7c478bd9Sstevel@tonic-gate 
397*7c478bd9Sstevel@tonic-gate 			if (procfd  < 0)
398*7c478bd9Sstevel@tonic-gate 				continue;
399*7c478bd9Sstevel@tonic-gate 			if (read(procfd, actinfo, sizeof (actinfo))
400*7c478bd9Sstevel@tonic-gate 			    != sizeof (actinfo)) {
401*7c478bd9Sstevel@tonic-gate 				int err = errno;
402*7c478bd9Sstevel@tonic-gate 				(void) close(procfd);
403*7c478bd9Sstevel@tonic-gate 				if (err == EAGAIN)
404*7c478bd9Sstevel@tonic-gate 					goto retry;
405*7c478bd9Sstevel@tonic-gate 				if (err != ENOENT)
406*7c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr, gettext(
407*7c478bd9Sstevel@tonic-gate 					    "%s: read() failed on %s: %s \n"),
408*7c478bd9Sstevel@tonic-gate 					    prog, pname, strerror(err));
409*7c478bd9Sstevel@tonic-gate 				continue;
410*7c478bd9Sstevel@tonic-gate 			}
411*7c478bd9Sstevel@tonic-gate 			(void) close(procfd);
412*7c478bd9Sstevel@tonic-gate 
413*7c478bd9Sstevel@tonic-gate 			up->p_igintr =
414*7c478bd9Sstevel@tonic-gate 				actinfo[SIGINT-1].sa_handler == SIG_IGN &&
415*7c478bd9Sstevel@tonic-gate 				actinfo[SIGQUIT-1].sa_handler == SIG_IGN;
416*7c478bd9Sstevel@tonic-gate 
417*7c478bd9Sstevel@tonic-gate 			up->p_args[0] = 0;
418*7c478bd9Sstevel@tonic-gate 
419*7c478bd9Sstevel@tonic-gate 			/*
420*7c478bd9Sstevel@tonic-gate 			 * Process args if there's a chance we'll print it.
421*7c478bd9Sstevel@tonic-gate 			 */
422*7c478bd9Sstevel@tonic-gate 			if (lflag) { /* w command needs args */
423*7c478bd9Sstevel@tonic-gate 				clnarglist(info.pr_psargs);
424*7c478bd9Sstevel@tonic-gate 				(void) strcpy(up->p_args, info.pr_psargs);
425*7c478bd9Sstevel@tonic-gate 				if (up->p_args[0] == 0 ||
426*7c478bd9Sstevel@tonic-gate 				    up->p_args[0] == '-' &&
427*7c478bd9Sstevel@tonic-gate 				    up->p_args[1] <= ' ' ||
428*7c478bd9Sstevel@tonic-gate 				    up->p_args[0] == '?') {
429*7c478bd9Sstevel@tonic-gate 					(void) strcat(up->p_args, " (");
430*7c478bd9Sstevel@tonic-gate 					(void) strcat(up->p_args, up->p_comm);
431*7c478bd9Sstevel@tonic-gate 					(void) strcat(up->p_args, ")");
432*7c478bd9Sstevel@tonic-gate 				}
433*7c478bd9Sstevel@tonic-gate 			}
434*7c478bd9Sstevel@tonic-gate 
435*7c478bd9Sstevel@tonic-gate 		}
436*7c478bd9Sstevel@tonic-gate 
437*7c478bd9Sstevel@tonic-gate 		/*
438*7c478bd9Sstevel@tonic-gate 		 * link pgrp together in case parents go away
439*7c478bd9Sstevel@tonic-gate 		 * Pgrp chain is a single linked list originating
440*7c478bd9Sstevel@tonic-gate 		 * from the pgrp leader to its group member.
441*7c478bd9Sstevel@tonic-gate 		 */
442*7c478bd9Sstevel@tonic-gate 		if (info.pr_pgid != info.pr_pid) {	/* not pgrp leader */
443*7c478bd9Sstevel@tonic-gate 			pgrp = findhash(info.pr_pgid);
444*7c478bd9Sstevel@tonic-gate 			up->p_pgrplink = pgrp->p_pgrplink;
445*7c478bd9Sstevel@tonic-gate 			pgrp->p_pgrplink = up;
446*7c478bd9Sstevel@tonic-gate 		}
447*7c478bd9Sstevel@tonic-gate 		parent = findhash(info.pr_ppid);
448*7c478bd9Sstevel@tonic-gate 
449*7c478bd9Sstevel@tonic-gate 		/* if this is the new member, link it in */
450*7c478bd9Sstevel@tonic-gate 		if (parent->p_upid != INITPROCESS) {
451*7c478bd9Sstevel@tonic-gate 			if (parent->p_child) {
452*7c478bd9Sstevel@tonic-gate 				up->p_sibling = parent->p_child;
453*7c478bd9Sstevel@tonic-gate 				up->p_child = 0;
454*7c478bd9Sstevel@tonic-gate 			}
455*7c478bd9Sstevel@tonic-gate 			parent->p_child = up;
456*7c478bd9Sstevel@tonic-gate 		}
457*7c478bd9Sstevel@tonic-gate 
458*7c478bd9Sstevel@tonic-gate 	}
459*7c478bd9Sstevel@tonic-gate 
460*7c478bd9Sstevel@tonic-gate 	/* revert to non-privileged user */
461*7c478bd9Sstevel@tonic-gate 	(void) __priv_relinquish();
462*7c478bd9Sstevel@tonic-gate 
463*7c478bd9Sstevel@tonic-gate 	(void) closedir(dirp);
464*7c478bd9Sstevel@tonic-gate 	(void) time(&now);	/* get current time */
465*7c478bd9Sstevel@tonic-gate 
466*7c478bd9Sstevel@tonic-gate 	/*
467*7c478bd9Sstevel@tonic-gate 	 * loop through utmpx file, printing process info
468*7c478bd9Sstevel@tonic-gate 	 * about each logged in user
469*7c478bd9Sstevel@tonic-gate 	 */
470*7c478bd9Sstevel@tonic-gate 	for (ut = utmpbegin; ut < utmpend; ut++) {
471*7c478bd9Sstevel@tonic-gate 		time_t tim;
472*7c478bd9Sstevel@tonic-gate 
473*7c478bd9Sstevel@tonic-gate 		if (ut->ut_type != USER_PROCESS)
474*7c478bd9Sstevel@tonic-gate 			continue;
475*7c478bd9Sstevel@tonic-gate 		if (sel_user && strncmp(ut->ut_name, sel_user, NMAX) != 0)
476*7c478bd9Sstevel@tonic-gate 			continue;	/* we're looking for somebody else */
477*7c478bd9Sstevel@tonic-gate 		if (lflag) {	/* -l flag format (w command) */
478*7c478bd9Sstevel@tonic-gate 			/* print login name of the user */
479*7c478bd9Sstevel@tonic-gate 			(void) printf("%-*.*s ", NMAX, NMAX, ut->ut_name);
480*7c478bd9Sstevel@tonic-gate 
481*7c478bd9Sstevel@tonic-gate 			/* print tty user is on */
482*7c478bd9Sstevel@tonic-gate 			(void) printf("%-*.*s", LMAX, LMAX, ut->ut_line);
483*7c478bd9Sstevel@tonic-gate 
484*7c478bd9Sstevel@tonic-gate 			/* print when the user logged in */
485*7c478bd9Sstevel@tonic-gate 			tim = ut->ut_xtime;
486*7c478bd9Sstevel@tonic-gate 			(void) prtat(&tim);
487*7c478bd9Sstevel@tonic-gate 
488*7c478bd9Sstevel@tonic-gate 			/* print idle time */
489*7c478bd9Sstevel@tonic-gate 			idle = findidle(ut->ut_line);
490*7c478bd9Sstevel@tonic-gate 			if (idle >= 36 * 60)
491*7c478bd9Sstevel@tonic-gate 				(void) printf(dcgettext(NULL, "%2ddays ",
492*7c478bd9Sstevel@tonic-gate 				    LC_TIME), (idle + 12 * 60) / (24 * 60));
493*7c478bd9Sstevel@tonic-gate 			else
494*7c478bd9Sstevel@tonic-gate 				prttime(idle, " ");
495*7c478bd9Sstevel@tonic-gate 			showtotals(findhash((pid_t)ut->ut_pid));
496*7c478bd9Sstevel@tonic-gate 		} else {	/* standard whodo format */
497*7c478bd9Sstevel@tonic-gate 			tim = ut->ut_xtime;
498*7c478bd9Sstevel@tonic-gate 			tm = localtime(&tim);
499*7c478bd9Sstevel@tonic-gate 			(void) printf("\n%-*.*s %-*.*s %2.1d:%2.2d\n",
500*7c478bd9Sstevel@tonic-gate 			    LMAX, LMAX, ut->ut_line,
501*7c478bd9Sstevel@tonic-gate 			    NMAX, NMAX, ut->ut_name, tm->tm_hour, tm->tm_min);
502*7c478bd9Sstevel@tonic-gate 			showproc(findhash((pid_t)ut->ut_pid));
503*7c478bd9Sstevel@tonic-gate 		}
504*7c478bd9Sstevel@tonic-gate 	}
505*7c478bd9Sstevel@tonic-gate 
506*7c478bd9Sstevel@tonic-gate 	return (0);
507*7c478bd9Sstevel@tonic-gate }
508*7c478bd9Sstevel@tonic-gate 
509*7c478bd9Sstevel@tonic-gate /*
510*7c478bd9Sstevel@tonic-gate  * Used for standard whodo format.
511*7c478bd9Sstevel@tonic-gate  * This is the recursive routine descending the process
512*7c478bd9Sstevel@tonic-gate  * tree starting from the given process pointer(up).
513*7c478bd9Sstevel@tonic-gate  * It used depth-first search strategy and also marked
514*7c478bd9Sstevel@tonic-gate  * each node as printed as it traversed down the tree.
515*7c478bd9Sstevel@tonic-gate  */
516*7c478bd9Sstevel@tonic-gate static void
517*7c478bd9Sstevel@tonic-gate showproc(struct uproc *up)
518*7c478bd9Sstevel@tonic-gate {
519*7c478bd9Sstevel@tonic-gate 	struct	uproc	*zp;
520*7c478bd9Sstevel@tonic-gate 
521*7c478bd9Sstevel@tonic-gate 	if (up->p_state == VISITED) /* we already been here */
522*7c478bd9Sstevel@tonic-gate 		return;
523*7c478bd9Sstevel@tonic-gate 	/* print the data for this process */
524*7c478bd9Sstevel@tonic-gate 	if (up->p_state == ZOMBIE)
525*7c478bd9Sstevel@tonic-gate 		(void) printf("    %-*.*s %5d %4.1ld:%2.2ld %s\n",
526*7c478bd9Sstevel@tonic-gate 		    LMAX, LMAX, "  ?", (int)up->p_upid, 0L, 0L, "<defunct>");
527*7c478bd9Sstevel@tonic-gate 	else if (up->p_state != NONE) {
528*7c478bd9Sstevel@tonic-gate 		(void) printf("    %-*.*s %5d %4.1ld:%2.2ld %s\n",
529*7c478bd9Sstevel@tonic-gate 		    LMAX, LMAX, getty(up->p_ttyd), (int)up->p_upid,
530*7c478bd9Sstevel@tonic-gate 		    up->p_time / 60L, up->p_time % 60L,
531*7c478bd9Sstevel@tonic-gate 		    up->p_comm);
532*7c478bd9Sstevel@tonic-gate 	}
533*7c478bd9Sstevel@tonic-gate 	up->p_state = VISITED;
534*7c478bd9Sstevel@tonic-gate 
535*7c478bd9Sstevel@tonic-gate 	/* descend for its children */
536*7c478bd9Sstevel@tonic-gate 	if (up->p_child) {
537*7c478bd9Sstevel@tonic-gate 		showproc(up->p_child);
538*7c478bd9Sstevel@tonic-gate 		for (zp = up->p_child->p_sibling; zp; zp = zp->p_sibling) {
539*7c478bd9Sstevel@tonic-gate 			showproc(zp);
540*7c478bd9Sstevel@tonic-gate 		}
541*7c478bd9Sstevel@tonic-gate 	}
542*7c478bd9Sstevel@tonic-gate 
543*7c478bd9Sstevel@tonic-gate 	/* print the pgrp relation */
544*7c478bd9Sstevel@tonic-gate 	if (up->p_pgrplink)
545*7c478bd9Sstevel@tonic-gate 		showproc(up->p_pgrplink);
546*7c478bd9Sstevel@tonic-gate }
547*7c478bd9Sstevel@tonic-gate 
548*7c478bd9Sstevel@tonic-gate 
549*7c478bd9Sstevel@tonic-gate /*
550*7c478bd9Sstevel@tonic-gate  * Used for -l flag (w command) format.
551*7c478bd9Sstevel@tonic-gate  * Prints the CPU time for all processes & children,
552*7c478bd9Sstevel@tonic-gate  * and the cpu time for interesting process,
553*7c478bd9Sstevel@tonic-gate  * and what the user is doing.
554*7c478bd9Sstevel@tonic-gate  */
555*7c478bd9Sstevel@tonic-gate static void
556*7c478bd9Sstevel@tonic-gate showtotals(struct uproc *up)
557*7c478bd9Sstevel@tonic-gate {
558*7c478bd9Sstevel@tonic-gate 	jobtime = 0;
559*7c478bd9Sstevel@tonic-gate 	proctime = 0;
560*7c478bd9Sstevel@tonic-gate 	empty = 1;
561*7c478bd9Sstevel@tonic-gate 	curpid = -1;
562*7c478bd9Sstevel@tonic-gate 	(void) strcpy(doing, "-"); /* default act: normally never prints */
563*7c478bd9Sstevel@tonic-gate 	calctotals(up);
564*7c478bd9Sstevel@tonic-gate 
565*7c478bd9Sstevel@tonic-gate 	/* print CPU time for all processes & children */
566*7c478bd9Sstevel@tonic-gate 	/* and need to convert clock ticks to seconds first */
567*7c478bd9Sstevel@tonic-gate 	prttime((time_t)jobtime, " ");
568*7c478bd9Sstevel@tonic-gate 
569*7c478bd9Sstevel@tonic-gate 	/* print cpu time for interesting process */
570*7c478bd9Sstevel@tonic-gate 	/* and need to convert clock ticks to seconds first */
571*7c478bd9Sstevel@tonic-gate 	prttime((time_t)proctime, " ");
572*7c478bd9Sstevel@tonic-gate 
573*7c478bd9Sstevel@tonic-gate 	/* what user is doing, current process */
574*7c478bd9Sstevel@tonic-gate 	(void) printf(" %-.32s\n", doing);
575*7c478bd9Sstevel@tonic-gate }
576*7c478bd9Sstevel@tonic-gate 
577*7c478bd9Sstevel@tonic-gate /*
578*7c478bd9Sstevel@tonic-gate  *  Used for -l flag (w command) format.
579*7c478bd9Sstevel@tonic-gate  *  This recursive routine descends the process
580*7c478bd9Sstevel@tonic-gate  *  tree starting from the given process pointer(up).
581*7c478bd9Sstevel@tonic-gate  *  It used depth-first search strategy and also marked
582*7c478bd9Sstevel@tonic-gate  *  each node as visited as it traversed down the tree.
583*7c478bd9Sstevel@tonic-gate  *  It calculates the process time for all processes &
584*7c478bd9Sstevel@tonic-gate  *  children.  It also finds the "interesting" process
585*7c478bd9Sstevel@tonic-gate  *  and determines its cpu time and command.
586*7c478bd9Sstevel@tonic-gate  */
587*7c478bd9Sstevel@tonic-gate static void
588*7c478bd9Sstevel@tonic-gate calctotals(struct uproc *up)
589*7c478bd9Sstevel@tonic-gate {
590*7c478bd9Sstevel@tonic-gate 	struct uproc	*zp;
591*7c478bd9Sstevel@tonic-gate 
592*7c478bd9Sstevel@tonic-gate 	if (up->p_state == VISITED)
593*7c478bd9Sstevel@tonic-gate 		return;
594*7c478bd9Sstevel@tonic-gate 	up->p_state = VISITED;
595*7c478bd9Sstevel@tonic-gate 	if (up->p_state == NONE || up->p_state == ZOMBIE)
596*7c478bd9Sstevel@tonic-gate 		return;
597*7c478bd9Sstevel@tonic-gate 	jobtime += up->p_time + up->p_ctime;
598*7c478bd9Sstevel@tonic-gate 	proctime += up->p_time;
599*7c478bd9Sstevel@tonic-gate 
600*7c478bd9Sstevel@tonic-gate 	if (empty && !up->p_igintr) {
601*7c478bd9Sstevel@tonic-gate 		empty = 0;
602*7c478bd9Sstevel@tonic-gate 		curpid = -1;
603*7c478bd9Sstevel@tonic-gate 	}
604*7c478bd9Sstevel@tonic-gate 
605*7c478bd9Sstevel@tonic-gate 	if (up->p_upid > curpid && (!up->p_igintr || empty)) {
606*7c478bd9Sstevel@tonic-gate 		curpid = up->p_upid;
607*7c478bd9Sstevel@tonic-gate 		(void) strcpy(doing, up->p_args);
608*7c478bd9Sstevel@tonic-gate 	}
609*7c478bd9Sstevel@tonic-gate 
610*7c478bd9Sstevel@tonic-gate 	/* descend for its children */
611*7c478bd9Sstevel@tonic-gate 	if (up->p_child) {
612*7c478bd9Sstevel@tonic-gate 		calctotals(up->p_child);
613*7c478bd9Sstevel@tonic-gate 		for (zp = up->p_child->p_sibling; zp; zp = zp->p_sibling)
614*7c478bd9Sstevel@tonic-gate 			calctotals(zp);
615*7c478bd9Sstevel@tonic-gate 	}
616*7c478bd9Sstevel@tonic-gate }
617*7c478bd9Sstevel@tonic-gate 
618*7c478bd9Sstevel@tonic-gate static char *
619*7c478bd9Sstevel@tonic-gate devadd(char *name, dev_t ddev)
620*7c478bd9Sstevel@tonic-gate {
621*7c478bd9Sstevel@tonic-gate 	struct devl *dp;
622*7c478bd9Sstevel@tonic-gate 	int leng, start, i;
623*7c478bd9Sstevel@tonic-gate 
624*7c478bd9Sstevel@tonic-gate 	if (ndevs == maxdev) {
625*7c478bd9Sstevel@tonic-gate 		maxdev += DNINCR;
626*7c478bd9Sstevel@tonic-gate 		dp = realloc(devl, maxdev * sizeof (struct devl));
627*7c478bd9Sstevel@tonic-gate 		if (!dp) {
628*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
629*7c478bd9Sstevel@tonic-gate 				gettext("%s: out of memory!: %s\n"),
630*7c478bd9Sstevel@tonic-gate 				prog, strerror(errno));
631*7c478bd9Sstevel@tonic-gate 			exit(1);
632*7c478bd9Sstevel@tonic-gate 		}
633*7c478bd9Sstevel@tonic-gate 		devl = dp;
634*7c478bd9Sstevel@tonic-gate 	}
635*7c478bd9Sstevel@tonic-gate 	dp = &devl[ndevs++];
636*7c478bd9Sstevel@tonic-gate 
637*7c478bd9Sstevel@tonic-gate 	dp->ddev = ddev;
638*7c478bd9Sstevel@tonic-gate 	if (name == NULL) {
639*7c478bd9Sstevel@tonic-gate 		(void) strcpy(dp->dname, "  ?  ");
640*7c478bd9Sstevel@tonic-gate 		return (dp->dname);
641*7c478bd9Sstevel@tonic-gate 	}
642*7c478bd9Sstevel@tonic-gate 
643*7c478bd9Sstevel@tonic-gate 	leng = strlen(name);
644*7c478bd9Sstevel@tonic-gate 	if (leng < DEVNAMELEN + 4) {
645*7c478bd9Sstevel@tonic-gate 		/* strip off "/dev/" */
646*7c478bd9Sstevel@tonic-gate 		(void) strcpy(dp->dname, &name[5]);
647*7c478bd9Sstevel@tonic-gate 	} else {
648*7c478bd9Sstevel@tonic-gate 		/* strip enough off the front to fit */
649*7c478bd9Sstevel@tonic-gate 		start = leng - DEVNAMELEN - 1;
650*7c478bd9Sstevel@tonic-gate 
651*7c478bd9Sstevel@tonic-gate 		for (i = start; i < leng && name[i] != '/'; i++)
652*7c478bd9Sstevel@tonic-gate 				;
653*7c478bd9Sstevel@tonic-gate 		if (i == leng)
654*7c478bd9Sstevel@tonic-gate 			(void) strncpy(dp->dname, &name[start], DEVNAMELEN);
655*7c478bd9Sstevel@tonic-gate 		else
656*7c478bd9Sstevel@tonic-gate 			(void) strncpy(dp->dname, &name[i+1], DEVNAMELEN);
657*7c478bd9Sstevel@tonic-gate 	}
658*7c478bd9Sstevel@tonic-gate 	return (dp->dname);
659*7c478bd9Sstevel@tonic-gate }
660*7c478bd9Sstevel@tonic-gate 
661*7c478bd9Sstevel@tonic-gate static char *
662*7c478bd9Sstevel@tonic-gate devlookup(dev_t ddev)
663*7c478bd9Sstevel@tonic-gate {
664*7c478bd9Sstevel@tonic-gate 	struct devl *dp;
665*7c478bd9Sstevel@tonic-gate 	int i;
666*7c478bd9Sstevel@tonic-gate 
667*7c478bd9Sstevel@tonic-gate 	for (dp = devl, i = 0; i < ndevs; dp++, i++) {
668*7c478bd9Sstevel@tonic-gate 		if (dp->ddev == ddev)
669*7c478bd9Sstevel@tonic-gate 			return (dp->dname);
670*7c478bd9Sstevel@tonic-gate 	}
671*7c478bd9Sstevel@tonic-gate 	return (NULL);
672*7c478bd9Sstevel@tonic-gate }
673*7c478bd9Sstevel@tonic-gate 
674*7c478bd9Sstevel@tonic-gate /*
675*7c478bd9Sstevel@tonic-gate  * This routine gives back a corresponding device name
676*7c478bd9Sstevel@tonic-gate  * from the device number given.
677*7c478bd9Sstevel@tonic-gate  */
678*7c478bd9Sstevel@tonic-gate static char *
679*7c478bd9Sstevel@tonic-gate getty(dev_t dev)
680*7c478bd9Sstevel@tonic-gate {
681*7c478bd9Sstevel@tonic-gate 	extern char *_ttyname_dev(dev_t, char *, size_t);
682*7c478bd9Sstevel@tonic-gate 	char devname[TTYNAME_MAX];
683*7c478bd9Sstevel@tonic-gate 	char *retval;
684*7c478bd9Sstevel@tonic-gate 
685*7c478bd9Sstevel@tonic-gate 	if (dev == PRNODEV)
686*7c478bd9Sstevel@tonic-gate 		return ("  ?  ");
687*7c478bd9Sstevel@tonic-gate 
688*7c478bd9Sstevel@tonic-gate 	if ((retval = devlookup(dev)) != NULL)
689*7c478bd9Sstevel@tonic-gate 		return (retval);
690*7c478bd9Sstevel@tonic-gate 
691*7c478bd9Sstevel@tonic-gate 	retval = _ttyname_dev(dev, devname, sizeof (devname));
692*7c478bd9Sstevel@tonic-gate 	return (devadd(retval, dev));
693*7c478bd9Sstevel@tonic-gate }
694*7c478bd9Sstevel@tonic-gate 
695*7c478bd9Sstevel@tonic-gate /*
696*7c478bd9Sstevel@tonic-gate  * Findhash  finds the appropriate entry in the process
697*7c478bd9Sstevel@tonic-gate  * hash table (pr_htbl) for the given pid in case that
698*7c478bd9Sstevel@tonic-gate  * pid exists on the hash chain. It returns back a pointer
699*7c478bd9Sstevel@tonic-gate  * to that uproc structure. If this is a new pid, it allocates
700*7c478bd9Sstevel@tonic-gate  * a new node, initializes it, links it into the chain (after
701*7c478bd9Sstevel@tonic-gate  * head) and returns a structure pointer.
702*7c478bd9Sstevel@tonic-gate  */
703*7c478bd9Sstevel@tonic-gate static struct uproc *
704*7c478bd9Sstevel@tonic-gate findhash(pid_t pid)
705*7c478bd9Sstevel@tonic-gate {
706*7c478bd9Sstevel@tonic-gate 	struct uproc *up, *tp;
707*7c478bd9Sstevel@tonic-gate 
708*7c478bd9Sstevel@tonic-gate 	tp = up = &pr_htbl[(int)pid % HSIZE];
709*7c478bd9Sstevel@tonic-gate 	if (up->p_upid == 0) {			/* empty slot */
710*7c478bd9Sstevel@tonic-gate 		up->p_upid = pid;
711*7c478bd9Sstevel@tonic-gate 		up->p_state = NONE;
712*7c478bd9Sstevel@tonic-gate 		up->p_child = up->p_sibling = up->p_pgrplink = up->p_link = 0;
713*7c478bd9Sstevel@tonic-gate 		return (up);
714*7c478bd9Sstevel@tonic-gate 	}
715*7c478bd9Sstevel@tonic-gate 	if (up->p_upid == pid) {		/* found in hash table */
716*7c478bd9Sstevel@tonic-gate 		return (up);
717*7c478bd9Sstevel@tonic-gate 	}
718*7c478bd9Sstevel@tonic-gate 	for (tp = up->p_link; tp; tp = tp->p_link) {	/* follow chain */
719*7c478bd9Sstevel@tonic-gate 		if (tp->p_upid == pid) {
720*7c478bd9Sstevel@tonic-gate 			return (tp);
721*7c478bd9Sstevel@tonic-gate 		}
722*7c478bd9Sstevel@tonic-gate 	}
723*7c478bd9Sstevel@tonic-gate 	tp = malloc(sizeof (*tp));		/* add new node */
724*7c478bd9Sstevel@tonic-gate 	if (!tp) {
725*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: out of memory!: %s\n"),
726*7c478bd9Sstevel@tonic-gate 			prog, strerror(errno));
727*7c478bd9Sstevel@tonic-gate 		exit(1);
728*7c478bd9Sstevel@tonic-gate 	}
729*7c478bd9Sstevel@tonic-gate 	(void) memset((char *)tp, 0, sizeof (*tp));
730*7c478bd9Sstevel@tonic-gate 	tp->p_upid = pid;
731*7c478bd9Sstevel@tonic-gate 	tp->p_state = NONE;
732*7c478bd9Sstevel@tonic-gate 	tp->p_child = tp->p_sibling = tp->p_pgrplink = (pid_t)0;
733*7c478bd9Sstevel@tonic-gate 	tp->p_link = up->p_link;		/* insert after head */
734*7c478bd9Sstevel@tonic-gate 	up->p_link = tp;
735*7c478bd9Sstevel@tonic-gate 	return (tp);
736*7c478bd9Sstevel@tonic-gate }
737*7c478bd9Sstevel@tonic-gate 
738*7c478bd9Sstevel@tonic-gate #define	HR	(60 * 60)
739*7c478bd9Sstevel@tonic-gate #define	DAY	(24 * HR)
740*7c478bd9Sstevel@tonic-gate #define	MON	(30 * DAY)
741*7c478bd9Sstevel@tonic-gate 
742*7c478bd9Sstevel@tonic-gate /*
743*7c478bd9Sstevel@tonic-gate  * prints a time in hours and minutes or minutes and seconds.
744*7c478bd9Sstevel@tonic-gate  * The character string 'tail' is printed at the end, obvious
745*7c478bd9Sstevel@tonic-gate  * strings to pass are "", " ", or "am".
746*7c478bd9Sstevel@tonic-gate  */
747*7c478bd9Sstevel@tonic-gate static void
748*7c478bd9Sstevel@tonic-gate prttime(time_t tim, char *tail)
749*7c478bd9Sstevel@tonic-gate {
750*7c478bd9Sstevel@tonic-gate 	if (tim >= 60)
751*7c478bd9Sstevel@tonic-gate 		(void) printf(dcgettext(NULL, "%3d:%02d", LC_TIME),
752*7c478bd9Sstevel@tonic-gate 		    (int)tim/60, (int)tim%60);
753*7c478bd9Sstevel@tonic-gate 	else if (tim > 0)
754*7c478bd9Sstevel@tonic-gate 		(void) printf(dcgettext(NULL, "    %2d", LC_TIME), (int)tim);
755*7c478bd9Sstevel@tonic-gate 	else
756*7c478bd9Sstevel@tonic-gate 		(void) printf("      ");
757*7c478bd9Sstevel@tonic-gate 	(void) printf("%s", tail);
758*7c478bd9Sstevel@tonic-gate }
759*7c478bd9Sstevel@tonic-gate 
760*7c478bd9Sstevel@tonic-gate 
761*7c478bd9Sstevel@tonic-gate /*
762*7c478bd9Sstevel@tonic-gate  * prints a 12 hour time given a pointer to a time of day
763*7c478bd9Sstevel@tonic-gate  */
764*7c478bd9Sstevel@tonic-gate static void
765*7c478bd9Sstevel@tonic-gate prtat(time_t *time)
766*7c478bd9Sstevel@tonic-gate {
767*7c478bd9Sstevel@tonic-gate 	struct tm *p;
768*7c478bd9Sstevel@tonic-gate 
769*7c478bd9Sstevel@tonic-gate 	p = localtime(time);
770*7c478bd9Sstevel@tonic-gate 	if (now - *time <= 18 * HR) {
771*7c478bd9Sstevel@tonic-gate 		char timestr[50];
772*7c478bd9Sstevel@tonic-gate 		(void) strftime(timestr, sizeof (timestr),
773*7c478bd9Sstevel@tonic-gate 		    dcgettext(NULL, " %l:%M""%p", LC_TIME), p);
774*7c478bd9Sstevel@tonic-gate 		checkampm(timestr);
775*7c478bd9Sstevel@tonic-gate 		(void) printf("%s", timestr);
776*7c478bd9Sstevel@tonic-gate 	} else if (now - *time <= 7 * DAY) {
777*7c478bd9Sstevel@tonic-gate 		char weekdaytime[20];
778*7c478bd9Sstevel@tonic-gate 
779*7c478bd9Sstevel@tonic-gate 		(void) strftime(weekdaytime, sizeof (weekdaytime),
780*7c478bd9Sstevel@tonic-gate 		    dcgettext(NULL, "%a%l%p", LC_TIME), p);
781*7c478bd9Sstevel@tonic-gate 		checkampm(weekdaytime);
782*7c478bd9Sstevel@tonic-gate 		(void) printf(" %s", weekdaytime);
783*7c478bd9Sstevel@tonic-gate 	} else {
784*7c478bd9Sstevel@tonic-gate 		char monthtime[20];
785*7c478bd9Sstevel@tonic-gate 
786*7c478bd9Sstevel@tonic-gate 		(void) strftime(monthtime, sizeof (monthtime),
787*7c478bd9Sstevel@tonic-gate 		    dcgettext(NULL, "%e%b%y", LC_TIME), p);
788*7c478bd9Sstevel@tonic-gate 		(void) printf(" %s", monthtime);
789*7c478bd9Sstevel@tonic-gate 	}
790*7c478bd9Sstevel@tonic-gate }
791*7c478bd9Sstevel@tonic-gate 
792*7c478bd9Sstevel@tonic-gate /*
793*7c478bd9Sstevel@tonic-gate  * find & return number of minutes current tty has been idle
794*7c478bd9Sstevel@tonic-gate  */
795*7c478bd9Sstevel@tonic-gate static time_t
796*7c478bd9Sstevel@tonic-gate findidle(char *devname)
797*7c478bd9Sstevel@tonic-gate {
798*7c478bd9Sstevel@tonic-gate 	struct stat stbuf;
799*7c478bd9Sstevel@tonic-gate 	time_t lastaction, diff;
800*7c478bd9Sstevel@tonic-gate 	char ttyname[64];
801*7c478bd9Sstevel@tonic-gate 
802*7c478bd9Sstevel@tonic-gate 	(void) strcpy(ttyname, "/dev/");
803*7c478bd9Sstevel@tonic-gate 	(void) strcat(ttyname, devname);
804*7c478bd9Sstevel@tonic-gate 	if (stat(ttyname, &stbuf) != -1) {
805*7c478bd9Sstevel@tonic-gate 		lastaction = stbuf.st_atime;
806*7c478bd9Sstevel@tonic-gate 		diff = now - lastaction;
807*7c478bd9Sstevel@tonic-gate 		diff = DIV60(diff);
808*7c478bd9Sstevel@tonic-gate 		if (diff < 0)
809*7c478bd9Sstevel@tonic-gate 			diff = 0;
810*7c478bd9Sstevel@tonic-gate 	} else
811*7c478bd9Sstevel@tonic-gate 		diff = 0;
812*7c478bd9Sstevel@tonic-gate 	return (diff);
813*7c478bd9Sstevel@tonic-gate }
814*7c478bd9Sstevel@tonic-gate 
815*7c478bd9Sstevel@tonic-gate /*
816*7c478bd9Sstevel@tonic-gate  * given a pointer to the argument string clean out unsavory characters.
817*7c478bd9Sstevel@tonic-gate  */
818*7c478bd9Sstevel@tonic-gate static void
819*7c478bd9Sstevel@tonic-gate clnarglist(char *arglist)
820*7c478bd9Sstevel@tonic-gate {
821*7c478bd9Sstevel@tonic-gate 	char	*c;
822*7c478bd9Sstevel@tonic-gate 	int	err = 0;
823*7c478bd9Sstevel@tonic-gate 
824*7c478bd9Sstevel@tonic-gate 	/* get rid of unsavory characters */
825*7c478bd9Sstevel@tonic-gate 	for (c = arglist; *c == NULL; c++) {
826*7c478bd9Sstevel@tonic-gate 		if ((*c < ' ') || (*c > 0176)) {
827*7c478bd9Sstevel@tonic-gate 			if (err++ > 5) {
828*7c478bd9Sstevel@tonic-gate 				*arglist = NULL;
829*7c478bd9Sstevel@tonic-gate 				break;
830*7c478bd9Sstevel@tonic-gate 			}
831*7c478bd9Sstevel@tonic-gate 			*c = '?';
832*7c478bd9Sstevel@tonic-gate 		}
833*7c478bd9Sstevel@tonic-gate 	}
834*7c478bd9Sstevel@tonic-gate }
835*7c478bd9Sstevel@tonic-gate 
836*7c478bd9Sstevel@tonic-gate /* replaces all occurences of AM/PM with am/pm */
837*7c478bd9Sstevel@tonic-gate static void
838*7c478bd9Sstevel@tonic-gate checkampm(char *str)
839*7c478bd9Sstevel@tonic-gate {
840*7c478bd9Sstevel@tonic-gate 	char *ampm;
841*7c478bd9Sstevel@tonic-gate 	while ((ampm = strstr(str, "AM")) != NULL ||
842*7c478bd9Sstevel@tonic-gate 	    (ampm = strstr(str, "PM")) != NULL) {
843*7c478bd9Sstevel@tonic-gate 		*ampm = tolower(*ampm);
844*7c478bd9Sstevel@tonic-gate 		*(ampm+1) = tolower(*(ampm+1));
845*7c478bd9Sstevel@tonic-gate 	}
846*7c478bd9Sstevel@tonic-gate }
847