xref: /onnv-gate/usr/src/cmd/prstat/prstat.c (revision 3247:e05001c14ea2)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
52685Sakolb  * Common Development and Distribution License (the "License").
62685Sakolb  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
212685Sakolb 
220Sstevel@tonic-gate /*
232685Sakolb  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include <sys/types.h>
300Sstevel@tonic-gate #include <sys/resource.h>
310Sstevel@tonic-gate #include <sys/loadavg.h>
320Sstevel@tonic-gate #include <sys/time.h>
330Sstevel@tonic-gate #include <sys/pset.h>
34*3247Sgjelinek #include <sys/vm_usage.h>
350Sstevel@tonic-gate #include <zone.h>
360Sstevel@tonic-gate #include <libzonecfg.h>
370Sstevel@tonic-gate 
380Sstevel@tonic-gate #include <stdio.h>
390Sstevel@tonic-gate #include <stdlib.h>
400Sstevel@tonic-gate #include <unistd.h>
410Sstevel@tonic-gate #include <dirent.h>
420Sstevel@tonic-gate #include <string.h>
430Sstevel@tonic-gate #include <errno.h>
440Sstevel@tonic-gate #include <poll.h>
450Sstevel@tonic-gate #include <ctype.h>
460Sstevel@tonic-gate #include <fcntl.h>
470Sstevel@tonic-gate #include <limits.h>
480Sstevel@tonic-gate #include <signal.h>
490Sstevel@tonic-gate #include <time.h>
500Sstevel@tonic-gate #include <project.h>
510Sstevel@tonic-gate 
520Sstevel@tonic-gate #include <libintl.h>
530Sstevel@tonic-gate #include <locale.h>
540Sstevel@tonic-gate 
550Sstevel@tonic-gate #include "prstat.h"
560Sstevel@tonic-gate #include "prutil.h"
570Sstevel@tonic-gate #include "prtable.h"
580Sstevel@tonic-gate #include "prsort.h"
590Sstevel@tonic-gate #include "prfile.h"
600Sstevel@tonic-gate 
610Sstevel@tonic-gate /*
620Sstevel@tonic-gate  * x86 <sys/regs.h> ERR conflicts with <curses.h> ERR.  For the purposes
630Sstevel@tonic-gate  * of this file, we care about the curses.h ERR so include that last.
640Sstevel@tonic-gate  */
650Sstevel@tonic-gate 
660Sstevel@tonic-gate #if	defined(ERR)
670Sstevel@tonic-gate #undef	ERR
680Sstevel@tonic-gate #endif
690Sstevel@tonic-gate 
700Sstevel@tonic-gate #ifndef	TEXT_DOMAIN			/* should be defined by cc -D */
710Sstevel@tonic-gate #define	TEXT_DOMAIN	"SYS_TEST"	/* use this only if it wasn't */
720Sstevel@tonic-gate #endif
730Sstevel@tonic-gate 
740Sstevel@tonic-gate #include <curses.h>
750Sstevel@tonic-gate #include <term.h>
760Sstevel@tonic-gate 
770Sstevel@tonic-gate #define	PSINFO_HEADER_PROC \
780Sstevel@tonic-gate "   PID USERNAME  SIZE   RSS STATE  PRI NICE      TIME  CPU PROCESS/NLWP       "
792685Sakolb #define	PSINFO_HEADER_PROC_LGRP \
802685Sakolb "   PID USERNAME  SIZE   RSS STATE  PRI NICE      TIME  CPU LGRP PROCESS/NLWP  "
810Sstevel@tonic-gate #define	PSINFO_HEADER_LWP \
820Sstevel@tonic-gate "   PID USERNAME  SIZE   RSS STATE  PRI NICE      TIME  CPU PROCESS/LWPID      "
832685Sakolb #define	PSINFO_HEADER_LWP_LGRP \
842685Sakolb "   PID USERNAME  SIZE   RSS STATE  PRI NICE      TIME  CPU LGRP PROCESS/LWPID "
850Sstevel@tonic-gate #define	USAGE_HEADER_PROC \
860Sstevel@tonic-gate "   PID USERNAME USR SYS TRP TFL DFL LCK SLP LAT VCX ICX SCL SIG PROCESS/NLWP  "
870Sstevel@tonic-gate #define	USAGE_HEADER_LWP \
880Sstevel@tonic-gate "   PID USERNAME USR SYS TRP TFL DFL LCK SLP LAT VCX ICX SCL SIG PROCESS/LWPID "
890Sstevel@tonic-gate #define	USER_HEADER_PROC \
90*3247Sgjelinek " NPROC USERNAME  SWAP   RSS MEMORY      TIME  CPU                             "
910Sstevel@tonic-gate #define	USER_HEADER_LWP \
92*3247Sgjelinek "  NLWP USERNAME  SWAP   RSS MEMORY      TIME  CPU                             "
930Sstevel@tonic-gate #define	TASK_HEADER_PROC \
94*3247Sgjelinek "TASKID    NPROC  SWAP   RSS MEMORY      TIME  CPU PROJECT                     "
950Sstevel@tonic-gate #define	TASK_HEADER_LWP \
96*3247Sgjelinek "TASKID     NLWP  SWAP   RSS MEMORY      TIME  CPU PROJECT                     "
970Sstevel@tonic-gate #define	PROJECT_HEADER_PROC \
98*3247Sgjelinek "PROJID    NPROC  SWAP   RSS MEMORY      TIME  CPU PROJECT                     "
990Sstevel@tonic-gate #define	PROJECT_HEADER_LWP \
100*3247Sgjelinek "PROJID     NLWP  SWAP   RSS MEMORY      TIME  CPU PROJECT                     "
1010Sstevel@tonic-gate #define	ZONE_HEADER_PROC \
102*3247Sgjelinek "ZONEID    NPROC  SWAP   RSS MEMORY      TIME  CPU ZONE                        "
1030Sstevel@tonic-gate #define	ZONE_HEADER_LWP \
104*3247Sgjelinek "ZONEID     NLWP  SWAP   RSS MEMORY      TIME  CPU ZONE                        "
1050Sstevel@tonic-gate #define	PSINFO_LINE \
1060Sstevel@tonic-gate "%6d %-8s %5s %5s %-6s %3s  %3s %9s %3.3s%% %-.16s/%d"
1072685Sakolb #define	PSINFO_LINE_LGRP \
1082685Sakolb "%6d %-8s %5s %5s %-6s %3s  %3s %9s %3.3s%% %4d %-.16s/%d"
1090Sstevel@tonic-gate #define	USAGE_LINE \
1100Sstevel@tonic-gate "%6d %-8s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s "\
1110Sstevel@tonic-gate "%3.3s %-.12s/%d"
1120Sstevel@tonic-gate #define	USER_LINE \
1130Sstevel@tonic-gate "%6d %-8s %5.5s %5.5s   %3.3s%% %9s %3.3s%%"
1140Sstevel@tonic-gate #define	TASK_LINE \
1150Sstevel@tonic-gate "%6d %8d %5s %5s   %3.3s%% %9s %3.3s%% %28s"
1160Sstevel@tonic-gate #define	PROJECT_LINE \
1170Sstevel@tonic-gate "%6d %8d %5s %5s   %3.3s%% %9s %3.3s%% %28s"
1180Sstevel@tonic-gate #define	ZONE_LINE \
1190Sstevel@tonic-gate "%6d %8d %5s %5s   %3.3s%% %9s %3.3s%% %28s"
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate #define	TOTAL_LINE \
1220Sstevel@tonic-gate "Total: %d processes, %d lwps, load averages: %3.2f, %3.2f, %3.2f"
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate /* global variables */
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate static char	*t_ulon;			/* termcap: start underline */
1270Sstevel@tonic-gate static char	*t_uloff;			/* termcap: end underline */
1280Sstevel@tonic-gate static char	*t_up;				/* termcap: cursor 1 line up */
1290Sstevel@tonic-gate static char	*t_eol;				/* termcap: clear end of line */
1300Sstevel@tonic-gate static char	*t_smcup;			/* termcap: cursor mvcap on */
1310Sstevel@tonic-gate static char	*t_rmcup;			/* termcap: cursor mvcap off */
1320Sstevel@tonic-gate static char	*t_home;			/* termcap: move cursor home */
1330Sstevel@tonic-gate static char	*movecur = NULL;		/* termcap: move up string */
1340Sstevel@tonic-gate static char	*empty_string = "\0";		/* termcap: empty string */
1350Sstevel@tonic-gate static uint_t	print_movecur = FALSE;		/* print movecur or not */
1360Sstevel@tonic-gate static int	is_curses_on = FALSE;		/* current curses state */
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate static table_t	pid_tbl = {0, 0, NULL};		/* selected processes */
1390Sstevel@tonic-gate static table_t	cpu_tbl = {0, 0, NULL};		/* selected processors */
1400Sstevel@tonic-gate static table_t  set_tbl = {0, 0, NULL};		/* selected processor sets */
1410Sstevel@tonic-gate static table_t	prj_tbl = {0, 0, NULL};		/* selected projects */
1420Sstevel@tonic-gate static table_t	tsk_tbl = {0, 0, NULL};		/* selected tasks */
1432685Sakolb static table_t	lgr_tbl = {0, 0, NULL};		/* selected lgroups */
1440Sstevel@tonic-gate static zonetbl_t zone_tbl = {0, 0, NULL};	/* selected zones */
1450Sstevel@tonic-gate static nametbl_t euid_tbl = {0, 0, NULL}; 	/* selected effective users */
1460Sstevel@tonic-gate static nametbl_t ruid_tbl = {0, 0, NULL}; 	/* selected real users */
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate static uint_t	total_procs;			/* total number of procs */
1490Sstevel@tonic-gate static uint_t	total_lwps;			/* total number of lwps */
1500Sstevel@tonic-gate static float	total_cpu;			/* total cpu usage */
1510Sstevel@tonic-gate static float	total_mem;			/* total memory usage */
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate static list_t	lwps;				/* list of lwps/processes */
1540Sstevel@tonic-gate static list_t	users;				/* list of users */
1550Sstevel@tonic-gate static list_t	tasks;				/* list of tasks */
1560Sstevel@tonic-gate static list_t	projects;			/* list of projects */
1570Sstevel@tonic-gate static list_t	zones;				/* list of zones */
1582685Sakolb static list_t	lgroups;			/* list of lgroups */
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate static volatile uint_t sigwinch = 0;
1610Sstevel@tonic-gate static volatile uint_t sigtstp = 0;
1620Sstevel@tonic-gate static volatile uint_t sigterm = 0;
1630Sstevel@tonic-gate 
164*3247Sgjelinek static long pagesize;
165*3247Sgjelinek 
1660Sstevel@tonic-gate /* default settings */
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate static optdesc_t opts = {
1690Sstevel@tonic-gate 	5,			/* interval between updates, seconds */
1700Sstevel@tonic-gate 	15,			/* number of lines in top part */
1710Sstevel@tonic-gate 	5,			/* number of lines in bottom part */
1720Sstevel@tonic-gate 	-1,			/* number of iterations; infinitely */
1730Sstevel@tonic-gate 	OPT_PSINFO | OPT_FULLSCREEN | OPT_USEHOME | OPT_TERMCAP,
1740Sstevel@tonic-gate 	-1			/* sort in decreasing order */
1750Sstevel@tonic-gate };
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate static void
1780Sstevel@tonic-gate psetloadavg(long psetid, void *ptr)
1790Sstevel@tonic-gate {
1800Sstevel@tonic-gate 	double psetloadavg[3];
1810Sstevel@tonic-gate 	double *loadavg = ptr;
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate 	if (pset_getloadavg((psetid_t)psetid, psetloadavg, 3) != -1) {
1840Sstevel@tonic-gate 		*loadavg++ += psetloadavg[0];
1850Sstevel@tonic-gate 		*loadavg++ += psetloadavg[1];
1860Sstevel@tonic-gate 		*loadavg += psetloadavg[2];
1870Sstevel@tonic-gate 	}
1880Sstevel@tonic-gate }
1890Sstevel@tonic-gate 
1900Sstevel@tonic-gate /*
191*3247Sgjelinek  * Queries the memory virtual and rss size for each member of a list.
192*3247Sgjelinek  * This will override the values computed by /proc aggregation.
193*3247Sgjelinek  */
194*3247Sgjelinek static void
195*3247Sgjelinek list_getsize(list_t *list)
196*3247Sgjelinek {
197*3247Sgjelinek 	id_info_t *id;
198*3247Sgjelinek 	vmusage_t *results, *next;
199*3247Sgjelinek 	vmusage_t *match;
200*3247Sgjelinek 	size_t nres = 0;
201*3247Sgjelinek 	size_t i;
202*3247Sgjelinek 	uint_t flags = 0;
203*3247Sgjelinek 	int ret;
204*3247Sgjelinek 	size_t physmem = sysconf(_SC_PHYS_PAGES) * pagesize;
205*3247Sgjelinek 
206*3247Sgjelinek 	/*
207*3247Sgjelinek 	 * Determine what swap/rss results to calculate.  getvmusage() will
208*3247Sgjelinek 	 * prune results returned to non-global zones automatically, so
209*3247Sgjelinek 	 * there is no need to pass different flags when calling from a
210*3247Sgjelinek 	 * non-global zone.
211*3247Sgjelinek 	 *
212*3247Sgjelinek 	 * Currently list_getsize() is only called with a single flag.  This
213*3247Sgjelinek 	 * is because -Z, -J, -T, and -a are mutually exclusive.  Regardless
214*3247Sgjelinek 	 * of this, we handle multiple flags.
215*3247Sgjelinek 	 */
216*3247Sgjelinek 	if (opts.o_outpmode & OPT_USERS) {
217*3247Sgjelinek 		/*
218*3247Sgjelinek 		 * Gather rss for all users in all zones.  Treat the same
219*3247Sgjelinek 		 * uid in different zones as the same user.
220*3247Sgjelinek 		 */
221*3247Sgjelinek 		flags |= VMUSAGE_COL_RUSERS;
222*3247Sgjelinek 
223*3247Sgjelinek 	} else if (opts.o_outpmode & OPT_TASKS) {
224*3247Sgjelinek 		/* Gather rss for all tasks in all zones */
225*3247Sgjelinek 		flags |= VMUSAGE_ALL_TASKS;
226*3247Sgjelinek 
227*3247Sgjelinek 	} else if (opts.o_outpmode & OPT_PROJECTS) {
228*3247Sgjelinek 		/*
229*3247Sgjelinek 		 * Gather rss for all projects in all zones.  Treat the same
230*3247Sgjelinek 		 * projid in diffrent zones as the same project.
231*3247Sgjelinek 		 */
232*3247Sgjelinek 		flags |= VMUSAGE_COL_PROJECTS;
233*3247Sgjelinek 
234*3247Sgjelinek 	} else if (opts.o_outpmode & OPT_ZONES) {
235*3247Sgjelinek 		/* Gather rss for all zones */
236*3247Sgjelinek 		flags |= VMUSAGE_ALL_ZONES;
237*3247Sgjelinek 
238*3247Sgjelinek 	} else {
239*3247Sgjelinek 		Die(gettext(
240*3247Sgjelinek 		    "Cannot determine rss flags for output options %x\n"),
241*3247Sgjelinek 		    opts.o_outpmode);
242*3247Sgjelinek 	}
243*3247Sgjelinek 
244*3247Sgjelinek 	/*
245*3247Sgjelinek 	 * getvmusage() returns an array of result structures.  One for
246*3247Sgjelinek 	 * each zone, project, task, or user on the system, depending on
247*3247Sgjelinek 	 * flags.
248*3247Sgjelinek 	 *
249*3247Sgjelinek 	 * If getvmusage() fails, prstat will use the size already gathered
250*3247Sgjelinek 	 * from psinfo
251*3247Sgjelinek 	 */
252*3247Sgjelinek 	if (getvmusage(flags, opts.o_interval, NULL, &nres) != 0)
253*3247Sgjelinek 		return;
254*3247Sgjelinek 
255*3247Sgjelinek 	results = (vmusage_t *)Malloc(sizeof (vmusage_t) * nres);
256*3247Sgjelinek 	for (;;) {
257*3247Sgjelinek 		ret = getvmusage(flags, opts.o_interval, results, &nres);
258*3247Sgjelinek 		if (ret == 0)
259*3247Sgjelinek 			break;
260*3247Sgjelinek 		if (errno == EOVERFLOW) {
261*3247Sgjelinek 			results = (vmusage_t *)Realloc(results,
262*3247Sgjelinek 			    sizeof (vmusage_t) * nres);
263*3247Sgjelinek 			continue;
264*3247Sgjelinek 		}
265*3247Sgjelinek 		/*
266*3247Sgjelinek 		 * Failure for some other reason.  Prstat will use the size
267*3247Sgjelinek 		 * already gathered from psinfo.
268*3247Sgjelinek 		 */
269*3247Sgjelinek 		return;
270*3247Sgjelinek 	}
271*3247Sgjelinek 	for (id = list->l_head; id != NULL; id = id->id_next) {
272*3247Sgjelinek 
273*3247Sgjelinek 		match = NULL;
274*3247Sgjelinek 		next = results;
275*3247Sgjelinek 		for (i = 0; i < nres; i++, next++) {
276*3247Sgjelinek 			switch (flags) {
277*3247Sgjelinek 			case VMUSAGE_COL_RUSERS:
278*3247Sgjelinek 				if (next->vmu_id == id->id_uid)
279*3247Sgjelinek 					match = next;
280*3247Sgjelinek 				break;
281*3247Sgjelinek 			case VMUSAGE_ALL_TASKS:
282*3247Sgjelinek 				if (next->vmu_id == id->id_taskid)
283*3247Sgjelinek 					match = next;
284*3247Sgjelinek 				break;
285*3247Sgjelinek 			case VMUSAGE_COL_PROJECTS:
286*3247Sgjelinek 				if (next->vmu_id == id->id_projid)
287*3247Sgjelinek 					match = next;
288*3247Sgjelinek 				break;
289*3247Sgjelinek 			case VMUSAGE_ALL_ZONES:
290*3247Sgjelinek 				if (next->vmu_id == id->id_zoneid)
291*3247Sgjelinek 					match = next;
292*3247Sgjelinek 				break;
293*3247Sgjelinek 			default:
294*3247Sgjelinek 				Die(gettext(
295*3247Sgjelinek 				    "Unknown vmusage flags %d\n"), flags);
296*3247Sgjelinek 			}
297*3247Sgjelinek 		}
298*3247Sgjelinek 		if (match != NULL) {
299*3247Sgjelinek 			id->id_size = match->vmu_swap_all / 1024;
300*3247Sgjelinek 			id->id_rssize = match->vmu_rss_all / 1024;
301*3247Sgjelinek 			id->id_pctmem = (100.0 * (float)match->vmu_rss_all) /
302*3247Sgjelinek 			    (float)physmem;
303*3247Sgjelinek 			/* Output using data from getvmusage() */
304*3247Sgjelinek 			id->id_sizematch = B_TRUE;
305*3247Sgjelinek 		}
306*3247Sgjelinek 		/*
307*3247Sgjelinek 		 * If no match is found, prstat will use the size already
308*3247Sgjelinek 		 * gathered from psinfo.
309*3247Sgjelinek 		 */
310*3247Sgjelinek 	}
311*3247Sgjelinek }
312*3247Sgjelinek 
313*3247Sgjelinek /*
3140Sstevel@tonic-gate  * A routine to display the contents of the list on the screen
3150Sstevel@tonic-gate  */
3160Sstevel@tonic-gate static void
3170Sstevel@tonic-gate list_print(list_t *list)
3180Sstevel@tonic-gate {
3190Sstevel@tonic-gate 	lwp_info_t *lwp;
3200Sstevel@tonic-gate 	id_info_t *id;
3210Sstevel@tonic-gate 	char usr[4], sys[4], trp[4], tfl[4];
3220Sstevel@tonic-gate 	char dfl[4], lck[4], slp[4], lat[4];
3230Sstevel@tonic-gate 	char vcx[4], icx[4], scl[4], sig[4];
3240Sstevel@tonic-gate 	char psize[6], prssize[6], pmem[6], pcpu[6], ptime[12];
3250Sstevel@tonic-gate 	char pstate[7], pnice[4], ppri[4];
3260Sstevel@tonic-gate 	char pname[LOGNAME_MAX+1];
3270Sstevel@tonic-gate 	char projname[PROJNAME_MAX+1];
3280Sstevel@tonic-gate 	char zonename[ZONENAME_MAX+1];
3290Sstevel@tonic-gate 	float cpu, mem;
3300Sstevel@tonic-gate 	double loadavg[3] = {0, 0, 0};
3310Sstevel@tonic-gate 	int i, lwpid;
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate 	if (foreach_element(&set_tbl, &loadavg, psetloadavg) == 0) {
3340Sstevel@tonic-gate 		/*
3350Sstevel@tonic-gate 		 * If processor sets aren't specified, we display system-wide
3360Sstevel@tonic-gate 		 * load averages.
3370Sstevel@tonic-gate 		 */
3380Sstevel@tonic-gate 		(void) getloadavg(loadavg, 3);
3390Sstevel@tonic-gate 	}
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate 	if (opts.o_outpmode & OPT_TTY)
3420Sstevel@tonic-gate 		(void) putchar('\r');
3430Sstevel@tonic-gate 	(void) putp(t_ulon);
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate 	switch (list->l_type) {
3460Sstevel@tonic-gate 	case LT_PROJECTS:
3470Sstevel@tonic-gate 		if (opts.o_outpmode & OPT_LWPS)
3480Sstevel@tonic-gate 			(void) printf(PROJECT_HEADER_LWP);
3490Sstevel@tonic-gate 		else
3500Sstevel@tonic-gate 			(void) printf(PROJECT_HEADER_PROC);
3510Sstevel@tonic-gate 		break;
3520Sstevel@tonic-gate 	case LT_TASKS:
3530Sstevel@tonic-gate 		if (opts.o_outpmode & OPT_LWPS)
3540Sstevel@tonic-gate 			(void) printf(TASK_HEADER_LWP);
3550Sstevel@tonic-gate 		else
3560Sstevel@tonic-gate 			(void) printf(TASK_HEADER_PROC);
3570Sstevel@tonic-gate 		break;
3580Sstevel@tonic-gate 	case LT_ZONES:
3590Sstevel@tonic-gate 		if (opts.o_outpmode & OPT_LWPS)
3600Sstevel@tonic-gate 			(void) printf(ZONE_HEADER_LWP);
3610Sstevel@tonic-gate 		else
3620Sstevel@tonic-gate 			(void) printf(ZONE_HEADER_PROC);
3630Sstevel@tonic-gate 		break;
3640Sstevel@tonic-gate 	case LT_USERS:
3650Sstevel@tonic-gate 		if (opts.o_outpmode & OPT_LWPS)
3660Sstevel@tonic-gate 			(void) printf(USER_HEADER_LWP);
3670Sstevel@tonic-gate 		else
3680Sstevel@tonic-gate 			(void) printf(USER_HEADER_PROC);
3690Sstevel@tonic-gate 		break;
3700Sstevel@tonic-gate 	case LT_LWPS:
3710Sstevel@tonic-gate 		if (opts.o_outpmode & OPT_LWPS) {
3722685Sakolb 			if (opts.o_outpmode & OPT_PSINFO) {
3732685Sakolb 				if (opts.o_outpmode & OPT_LGRP)
3742685Sakolb 					(void) printf(PSINFO_HEADER_LWP_LGRP);
3752685Sakolb 				else
3762685Sakolb 					(void) printf(PSINFO_HEADER_LWP);
3772685Sakolb 			}
3780Sstevel@tonic-gate 			if (opts.o_outpmode & OPT_MSACCT)
3790Sstevel@tonic-gate 				(void) printf(USAGE_HEADER_LWP);
3800Sstevel@tonic-gate 		} else {
3812685Sakolb 			if (opts.o_outpmode & OPT_PSINFO) {
3822685Sakolb 				if (opts.o_outpmode & OPT_LGRP)
3832685Sakolb 					(void) printf(PSINFO_HEADER_PROC_LGRP);
3842685Sakolb 				else
3852685Sakolb 					(void) printf(PSINFO_HEADER_PROC);
3862685Sakolb 			}
3870Sstevel@tonic-gate 			if (opts.o_outpmode & OPT_MSACCT)
3880Sstevel@tonic-gate 				(void) printf(USAGE_HEADER_PROC);
3890Sstevel@tonic-gate 		}
3900Sstevel@tonic-gate 		break;
3910Sstevel@tonic-gate 	}
3920Sstevel@tonic-gate 
3930Sstevel@tonic-gate 	(void) putp(t_uloff);
3940Sstevel@tonic-gate 	(void) putp(t_eol);
3950Sstevel@tonic-gate 	(void) putchar('\n');
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate 	for (i = 0; i < list->l_used; i++) {
3980Sstevel@tonic-gate 		switch (list->l_type) {
3990Sstevel@tonic-gate 		case LT_PROJECTS:
4000Sstevel@tonic-gate 		case LT_TASKS:
4010Sstevel@tonic-gate 		case LT_USERS:
4020Sstevel@tonic-gate 		case LT_ZONES:
4030Sstevel@tonic-gate 			id = list->l_ptrs[i];
4040Sstevel@tonic-gate 			/*
4050Sstevel@tonic-gate 			 * CPU usage and memory usage normalization
4060Sstevel@tonic-gate 			 */
4070Sstevel@tonic-gate 			if (total_cpu >= 100)
4080Sstevel@tonic-gate 				cpu = (100 * id->id_pctcpu) / total_cpu;
4090Sstevel@tonic-gate 			else
4100Sstevel@tonic-gate 				cpu = id->id_pctcpu;
411*3247Sgjelinek 			if (id->id_sizematch == B_FALSE && total_mem >= 100)
4120Sstevel@tonic-gate 				mem = (100 * id->id_pctmem) / total_mem;
4130Sstevel@tonic-gate 			else
4140Sstevel@tonic-gate 				mem = id->id_pctmem;
4150Sstevel@tonic-gate 			if (list->l_type == LT_USERS)
4160Sstevel@tonic-gate 				pwd_getname(id->id_uid, pname, LOGNAME_MAX + 1);
4170Sstevel@tonic-gate 			else if (list->l_type == LT_ZONES)
4180Sstevel@tonic-gate 				getzonename(id->id_zoneid, zonename,
4190Sstevel@tonic-gate 				    ZONENAME_MAX);
4200Sstevel@tonic-gate 			else
4210Sstevel@tonic-gate 				getprojname(id->id_projid, projname,
4220Sstevel@tonic-gate 				    PROJNAME_MAX);
4230Sstevel@tonic-gate 			Format_size(psize, id->id_size, 6);
4240Sstevel@tonic-gate 			Format_size(prssize, id->id_rssize, 6);
4250Sstevel@tonic-gate 			Format_pct(pmem, mem, 4);
4260Sstevel@tonic-gate 			Format_pct(pcpu, cpu, 4);
4270Sstevel@tonic-gate 			Format_time(ptime, id->id_time, 10);
4280Sstevel@tonic-gate 			if (opts.o_outpmode & OPT_TTY)
4290Sstevel@tonic-gate 				(void) putchar('\r');
4300Sstevel@tonic-gate 			if (list->l_type == LT_PROJECTS)
4310Sstevel@tonic-gate 				(void) printf(PROJECT_LINE, (int)id->id_projid,
4320Sstevel@tonic-gate 				    id->id_nproc, psize, prssize, pmem, ptime,
4330Sstevel@tonic-gate 				    pcpu, projname);
4340Sstevel@tonic-gate 			else if (list->l_type == LT_TASKS)
4350Sstevel@tonic-gate 				(void) printf(TASK_LINE, (int)id->id_taskid,
4360Sstevel@tonic-gate 				    id->id_nproc, psize, prssize, pmem, ptime,
4370Sstevel@tonic-gate 				    pcpu, projname);
4380Sstevel@tonic-gate 			else if (list->l_type == LT_ZONES)
4390Sstevel@tonic-gate 				(void) printf(ZONE_LINE, (int)id->id_zoneid,
4400Sstevel@tonic-gate 				    id->id_nproc, psize, prssize, pmem, ptime,
4410Sstevel@tonic-gate 				    pcpu, zonename);
4420Sstevel@tonic-gate 			else
4430Sstevel@tonic-gate 				(void) printf(USER_LINE, id->id_nproc, pname,
4440Sstevel@tonic-gate 				    psize, prssize, pmem, ptime, pcpu);
4450Sstevel@tonic-gate 			(void) putp(t_eol);
4460Sstevel@tonic-gate 			(void) putchar('\n');
4470Sstevel@tonic-gate 			break;
4480Sstevel@tonic-gate 		case LT_LWPS:
4490Sstevel@tonic-gate 			lwp = list->l_ptrs[i];
4500Sstevel@tonic-gate 			if (opts.o_outpmode & OPT_LWPS)
4510Sstevel@tonic-gate 				lwpid = lwp->li_info.pr_lwp.pr_lwpid;
4520Sstevel@tonic-gate 			else
4530Sstevel@tonic-gate 				lwpid = lwp->li_info.pr_nlwp +
4540Sstevel@tonic-gate 				    lwp->li_info.pr_nzomb;
4550Sstevel@tonic-gate 			pwd_getname(lwp->li_info.pr_uid, pname,
4560Sstevel@tonic-gate 			    LOGNAME_MAX + 1);
4570Sstevel@tonic-gate 			if (opts.o_outpmode & OPT_PSINFO) {
4580Sstevel@tonic-gate 				Format_size(psize, lwp->li_info.pr_size, 6);
4590Sstevel@tonic-gate 				Format_size(prssize, lwp->li_info.pr_rssize, 6);
4600Sstevel@tonic-gate 				Format_state(pstate,
4610Sstevel@tonic-gate 				    lwp->li_info.pr_lwp.pr_sname,
4620Sstevel@tonic-gate 				    lwp->li_info.pr_lwp.pr_onpro, 7);
4630Sstevel@tonic-gate 				if (strcmp(lwp->li_info.pr_lwp.pr_clname,
4640Sstevel@tonic-gate 				    "RT") == 0 ||
4650Sstevel@tonic-gate 				    strcmp(lwp->li_info.pr_lwp.pr_clname,
4660Sstevel@tonic-gate 				    "SYS") == 0 ||
4670Sstevel@tonic-gate 				    lwp->li_info.pr_lwp.pr_sname == 'Z')
4680Sstevel@tonic-gate 					(void) strcpy(pnice, "  -");
4690Sstevel@tonic-gate 				else
4700Sstevel@tonic-gate 					Format_num(pnice,
4710Sstevel@tonic-gate 					    lwp->li_info.pr_lwp.pr_nice - NZERO,
4720Sstevel@tonic-gate 					    4);
4730Sstevel@tonic-gate 				Format_num(ppri, lwp->li_info.pr_lwp.pr_pri, 4);
4740Sstevel@tonic-gate 				Format_pct(pcpu,
4750Sstevel@tonic-gate 				    FRC2PCT(lwp->li_info.pr_lwp.pr_pctcpu), 4);
4760Sstevel@tonic-gate 				if (opts.o_outpmode & OPT_LWPS)
4770Sstevel@tonic-gate 					Format_time(ptime,
4780Sstevel@tonic-gate 					    lwp->li_info.pr_lwp.pr_time.tv_sec,
4790Sstevel@tonic-gate 					    10);
4800Sstevel@tonic-gate 				else
4810Sstevel@tonic-gate 					Format_time(ptime,
4820Sstevel@tonic-gate 					    lwp->li_info.pr_time.tv_sec, 10);
4830Sstevel@tonic-gate 				if (opts.o_outpmode & OPT_TTY)
4840Sstevel@tonic-gate 					(void) putchar('\r');
4850Sstevel@tonic-gate 				stripfname(lwp->li_info.pr_fname);
4862685Sakolb 				if (opts.o_outpmode & OPT_LGRP) {
4872685Sakolb 					(void) printf(PSINFO_LINE_LGRP,
4882685Sakolb 					    (int)lwp->li_info.pr_pid, pname,
4892685Sakolb 					    psize, prssize, pstate, ppri, pnice,
4902685Sakolb 					    ptime, pcpu,
4912685Sakolb 					    (int)lwp->li_info.pr_lwp.pr_lgrp,
4922685Sakolb 					    lwp->li_info.pr_fname, lwpid);
4932685Sakolb 				} else {
4942685Sakolb 					(void) printf(PSINFO_LINE,
4952685Sakolb 					    (int)lwp->li_info.pr_pid, pname,
4962685Sakolb 					    psize, prssize, pstate, ppri, pnice,
4972685Sakolb 					    ptime, pcpu,
4982685Sakolb 					    lwp->li_info.pr_fname, lwpid);
4992685Sakolb 				}
5000Sstevel@tonic-gate 				(void) putp(t_eol);
5010Sstevel@tonic-gate 				(void) putchar('\n');
5020Sstevel@tonic-gate 			}
5030Sstevel@tonic-gate 			if (opts.o_outpmode & OPT_MSACCT) {
5040Sstevel@tonic-gate 				Format_pct(usr, lwp->li_usr, 4);
5050Sstevel@tonic-gate 				Format_pct(sys, lwp->li_sys, 4);
5060Sstevel@tonic-gate 				Format_pct(slp, lwp->li_slp, 4);
5070Sstevel@tonic-gate 				Format_num(vcx, lwp->li_vcx, 4);
5080Sstevel@tonic-gate 				Format_num(icx, lwp->li_icx, 4);
5090Sstevel@tonic-gate 				Format_num(scl, lwp->li_scl, 4);
5100Sstevel@tonic-gate 				Format_num(sig, lwp->li_sig, 4);
5110Sstevel@tonic-gate 				Format_pct(trp, lwp->li_trp, 4);
5120Sstevel@tonic-gate 				Format_pct(tfl, lwp->li_tfl, 4);
5130Sstevel@tonic-gate 				Format_pct(dfl, lwp->li_dfl, 4);
5140Sstevel@tonic-gate 				Format_pct(lck, lwp->li_lck, 4);
5150Sstevel@tonic-gate 				Format_pct(lat, lwp->li_lat, 4);
5160Sstevel@tonic-gate 				if (opts.o_outpmode & OPT_TTY)
5170Sstevel@tonic-gate 					(void) putchar('\r');
5180Sstevel@tonic-gate 				stripfname(lwp->li_info.pr_fname);
5190Sstevel@tonic-gate 				(void) printf(USAGE_LINE,
5200Sstevel@tonic-gate 				    (int)lwp->li_info.pr_pid, pname,
5210Sstevel@tonic-gate 				    usr, sys, trp, tfl, dfl, lck,
5220Sstevel@tonic-gate 				    slp, lat, vcx, icx, scl, sig,
5230Sstevel@tonic-gate 				    lwp->li_info.pr_fname, lwpid);
5240Sstevel@tonic-gate 				(void) putp(t_eol);
5250Sstevel@tonic-gate 				(void) putchar('\n');
5260Sstevel@tonic-gate 			}
5270Sstevel@tonic-gate 			break;
5280Sstevel@tonic-gate 		}
5290Sstevel@tonic-gate 	}
5300Sstevel@tonic-gate 
5310Sstevel@tonic-gate 	if (opts.o_outpmode & OPT_TTY)
5320Sstevel@tonic-gate 		(void) putchar('\r');
5330Sstevel@tonic-gate 	if (opts.o_outpmode & OPT_TERMCAP) {
5340Sstevel@tonic-gate 		switch (list->l_type) {
5350Sstevel@tonic-gate 		case LT_PROJECTS:
5360Sstevel@tonic-gate 		case LT_USERS:
5370Sstevel@tonic-gate 		case LT_TASKS:
5380Sstevel@tonic-gate 		case LT_ZONES:
5390Sstevel@tonic-gate 			while (i++ < opts.o_nbottom) {
5400Sstevel@tonic-gate 				(void) putp(t_eol);
5410Sstevel@tonic-gate 				(void) putchar('\n');
5420Sstevel@tonic-gate 			}
5430Sstevel@tonic-gate 			break;
5440Sstevel@tonic-gate 		case LT_LWPS:
5450Sstevel@tonic-gate 			while (i++ < opts.o_ntop) {
5460Sstevel@tonic-gate 				(void) putp(t_eol);
5470Sstevel@tonic-gate 				(void) putchar('\n');
5480Sstevel@tonic-gate 			}
5490Sstevel@tonic-gate 		}
5500Sstevel@tonic-gate 	}
5510Sstevel@tonic-gate 
5520Sstevel@tonic-gate 	if (opts.o_outpmode & OPT_TTY)
5530Sstevel@tonic-gate 		(void) putchar('\r');
5540Sstevel@tonic-gate 
5550Sstevel@tonic-gate 	if ((opts.o_outpmode & OPT_SPLIT) && list->l_type == LT_LWPS)
5560Sstevel@tonic-gate 		return;
5570Sstevel@tonic-gate 
5580Sstevel@tonic-gate 	(void) printf(TOTAL_LINE, total_procs, total_lwps,
5590Sstevel@tonic-gate 	    loadavg[LOADAVG_1MIN], loadavg[LOADAVG_5MIN],
5600Sstevel@tonic-gate 	    loadavg[LOADAVG_15MIN]);
5610Sstevel@tonic-gate 	(void) putp(t_eol);
5620Sstevel@tonic-gate 	(void) putchar('\n');
5630Sstevel@tonic-gate 	if (opts.o_outpmode & OPT_TTY)
5640Sstevel@tonic-gate 		(void) putchar('\r');
5650Sstevel@tonic-gate 	(void) putp(t_eol);
5660Sstevel@tonic-gate 	(void) fflush(stdout);
5670Sstevel@tonic-gate }
5680Sstevel@tonic-gate 
5690Sstevel@tonic-gate static lwp_info_t *
5700Sstevel@tonic-gate list_add_lwp(list_t *list, pid_t pid, id_t lwpid)
5710Sstevel@tonic-gate {
5720Sstevel@tonic-gate 	lwp_info_t *lwp;
5730Sstevel@tonic-gate 
5740Sstevel@tonic-gate 	if (list->l_head == NULL) {
5750Sstevel@tonic-gate 		list->l_head = list->l_tail = lwp = Zalloc(sizeof (lwp_info_t));
5760Sstevel@tonic-gate 	} else {
5770Sstevel@tonic-gate 		lwp = Zalloc(sizeof (lwp_info_t));
5780Sstevel@tonic-gate 		lwp->li_prev = list->l_tail;
5790Sstevel@tonic-gate 		((lwp_info_t *)list->l_tail)->li_next = lwp;
5800Sstevel@tonic-gate 		list->l_tail = lwp;
5810Sstevel@tonic-gate 	}
5820Sstevel@tonic-gate 	lwp->li_info.pr_pid = pid;
5830Sstevel@tonic-gate 	lwp->li_info.pr_lwp.pr_lwpid = lwpid;
5840Sstevel@tonic-gate 	lwpid_add(lwp, pid, lwpid);
5850Sstevel@tonic-gate 	list->l_count++;
5860Sstevel@tonic-gate 	return (lwp);
5870Sstevel@tonic-gate }
5880Sstevel@tonic-gate 
5890Sstevel@tonic-gate static void
5900Sstevel@tonic-gate list_remove_lwp(list_t *list, lwp_info_t *lwp)
5910Sstevel@tonic-gate {
5920Sstevel@tonic-gate 	if (lwp->li_prev)
5930Sstevel@tonic-gate 		lwp->li_prev->li_next = lwp->li_next;
5940Sstevel@tonic-gate 	else
5950Sstevel@tonic-gate 		list->l_head = lwp->li_next;	/* removing the head */
5960Sstevel@tonic-gate 	if (lwp->li_next)
5970Sstevel@tonic-gate 		lwp->li_next->li_prev = lwp->li_prev;
5980Sstevel@tonic-gate 	else
5990Sstevel@tonic-gate 		list->l_tail = lwp->li_prev;	/* removing the tail */
6000Sstevel@tonic-gate 	lwpid_del(lwp->li_info.pr_pid, lwp->li_info.pr_lwp.pr_lwpid);
6010Sstevel@tonic-gate 	if (lwpid_pidcheck(lwp->li_info.pr_pid) == 0)
6020Sstevel@tonic-gate 		fds_rm(lwp->li_info.pr_pid);
6030Sstevel@tonic-gate 	list->l_count--;
6040Sstevel@tonic-gate 	free(lwp);
6050Sstevel@tonic-gate }
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate static void
6080Sstevel@tonic-gate list_clear(list_t *list)
6090Sstevel@tonic-gate {
6100Sstevel@tonic-gate 	if (list->l_type == LT_LWPS) {
6110Sstevel@tonic-gate 		lwp_info_t	*lwp = list->l_tail;
6120Sstevel@tonic-gate 		lwp_info_t	*lwp_tmp;
6130Sstevel@tonic-gate 
6140Sstevel@tonic-gate 		fd_closeall();
6150Sstevel@tonic-gate 		while (lwp) {
6160Sstevel@tonic-gate 			lwp_tmp = lwp;
6170Sstevel@tonic-gate 			lwp = lwp->li_prev;
6180Sstevel@tonic-gate 			list_remove_lwp(&lwps, lwp_tmp);
6190Sstevel@tonic-gate 		}
6200Sstevel@tonic-gate 	} else {
6210Sstevel@tonic-gate 		id_info_t *id = list->l_head;
6220Sstevel@tonic-gate 		id_info_t *nextid;
6230Sstevel@tonic-gate 
6240Sstevel@tonic-gate 		while (id) {
6250Sstevel@tonic-gate 			nextid = id->id_next;
6260Sstevel@tonic-gate 			free(id);
6270Sstevel@tonic-gate 			id = nextid;
6280Sstevel@tonic-gate 		}
6290Sstevel@tonic-gate 		list->l_count = 0;
6300Sstevel@tonic-gate 		list->l_head = list->l_tail = NULL;
6310Sstevel@tonic-gate 	}
6320Sstevel@tonic-gate }
6330Sstevel@tonic-gate 
6340Sstevel@tonic-gate static void
6350Sstevel@tonic-gate list_update(list_t *list, lwp_info_t *lwp)
6360Sstevel@tonic-gate {
6370Sstevel@tonic-gate 	id_info_t *id;
6380Sstevel@tonic-gate 
6390Sstevel@tonic-gate 	if (list->l_head == NULL) {			/* first element */
6400Sstevel@tonic-gate 		list->l_head = list->l_tail = id = Zalloc(sizeof (id_info_t));
6410Sstevel@tonic-gate 		goto update;
6420Sstevel@tonic-gate 	}
6430Sstevel@tonic-gate 
6440Sstevel@tonic-gate 	for (id = list->l_head; id; id = id->id_next) {
6450Sstevel@tonic-gate 		if ((list->l_type == LT_USERS) &&
6460Sstevel@tonic-gate 		    (id->id_uid != lwp->li_info.pr_uid))
6470Sstevel@tonic-gate 			continue;
6480Sstevel@tonic-gate 		if ((list->l_type == LT_TASKS) &&
6490Sstevel@tonic-gate 		    (id->id_taskid != lwp->li_info.pr_taskid))
6500Sstevel@tonic-gate 			continue;
6510Sstevel@tonic-gate 		if ((list->l_type == LT_PROJECTS) &&
6520Sstevel@tonic-gate 		    (id->id_projid != lwp->li_info.pr_projid))
6530Sstevel@tonic-gate 			continue;
6540Sstevel@tonic-gate 		if ((list->l_type == LT_ZONES) &&
6550Sstevel@tonic-gate 		    (id->id_zoneid != lwp->li_info.pr_zoneid))
6560Sstevel@tonic-gate 			continue;
6572685Sakolb 		if ((list->l_type == LT_LGRPS) &&
6582685Sakolb 		    (id->id_lgroup != lwp->li_info.pr_lwp.pr_lgrp))
6592685Sakolb 			continue;
6600Sstevel@tonic-gate 		id->id_nproc++;
6610Sstevel@tonic-gate 		id->id_taskid	= lwp->li_info.pr_taskid;
6620Sstevel@tonic-gate 		id->id_projid	= lwp->li_info.pr_projid;
6630Sstevel@tonic-gate 		id->id_zoneid	= lwp->li_info.pr_zoneid;
6642685Sakolb 		id->id_lgroup	= lwp->li_info.pr_lwp.pr_lgrp;
6652685Sakolb 
6660Sstevel@tonic-gate 		if (lwp->li_flags & LWP_REPRESENT) {
6670Sstevel@tonic-gate 			id->id_size	+= lwp->li_info.pr_size;
6680Sstevel@tonic-gate 			id->id_rssize	+= lwp->li_info.pr_rssize;
6690Sstevel@tonic-gate 		}
6700Sstevel@tonic-gate 		id->id_pctcpu	+= FRC2PCT(lwp->li_info.pr_lwp.pr_pctcpu);
6710Sstevel@tonic-gate 		if (opts.o_outpmode & OPT_LWPS)
6720Sstevel@tonic-gate 			id->id_time += TIME2SEC(lwp->li_info.pr_lwp.pr_time);
6730Sstevel@tonic-gate 		else
6740Sstevel@tonic-gate 			id->id_time += TIME2SEC(lwp->li_info.pr_time);
6750Sstevel@tonic-gate 		id->id_pctmem	+= FRC2PCT(lwp->li_info.pr_pctmem);
6760Sstevel@tonic-gate 		id->id_key	+= lwp->li_key;
6770Sstevel@tonic-gate 		total_cpu	+= FRC2PCT(lwp->li_info.pr_lwp.pr_pctcpu);
6780Sstevel@tonic-gate 		total_mem	+= FRC2PCT(lwp->li_info.pr_pctmem);
6790Sstevel@tonic-gate 		return;
6800Sstevel@tonic-gate 	}
6810Sstevel@tonic-gate 
6820Sstevel@tonic-gate 	id = list->l_tail;
6830Sstevel@tonic-gate 	id->id_next = Zalloc(sizeof (id_info_t));
6840Sstevel@tonic-gate 	id->id_next->id_prev = list->l_tail;
6850Sstevel@tonic-gate 	id->id_next->id_next = NULL;
6860Sstevel@tonic-gate 	list->l_tail = id->id_next;
6870Sstevel@tonic-gate 	id = list->l_tail;
6880Sstevel@tonic-gate update:
6890Sstevel@tonic-gate 	id->id_uid	= lwp->li_info.pr_uid;
6900Sstevel@tonic-gate 	id->id_projid	= lwp->li_info.pr_projid;
6910Sstevel@tonic-gate 	id->id_taskid	= lwp->li_info.pr_taskid;
6920Sstevel@tonic-gate 	id->id_zoneid	= lwp->li_info.pr_zoneid;
6932685Sakolb 	id->id_lgroup	= lwp->li_info.pr_lwp.pr_lgrp;
6940Sstevel@tonic-gate 	id->id_nproc++;
695*3247Sgjelinek 	id->id_sizematch = B_FALSE;
6960Sstevel@tonic-gate 	if (lwp->li_flags & LWP_REPRESENT) {
6970Sstevel@tonic-gate 		id->id_size	= lwp->li_info.pr_size;
6980Sstevel@tonic-gate 		id->id_rssize	= lwp->li_info.pr_rssize;
6990Sstevel@tonic-gate 	}
7000Sstevel@tonic-gate 	id->id_pctcpu	= FRC2PCT(lwp->li_info.pr_lwp.pr_pctcpu);
7010Sstevel@tonic-gate 	if (opts.o_outpmode & OPT_LWPS)
7020Sstevel@tonic-gate 		id->id_time = TIME2SEC(lwp->li_info.pr_lwp.pr_time);
7030Sstevel@tonic-gate 	else
7040Sstevel@tonic-gate 		id->id_time = TIME2SEC(lwp->li_info.pr_time);
7050Sstevel@tonic-gate 	id->id_pctmem	= FRC2PCT(lwp->li_info.pr_pctmem);
7060Sstevel@tonic-gate 	id->id_key	= lwp->li_key;
7070Sstevel@tonic-gate 	total_cpu	+= id->id_pctcpu;
7080Sstevel@tonic-gate 	total_mem	+= id->id_pctmem;
7090Sstevel@tonic-gate 	list->l_count++;
7100Sstevel@tonic-gate }
7110Sstevel@tonic-gate 
7120Sstevel@tonic-gate static void
7130Sstevel@tonic-gate lwp_update(lwp_info_t *lwp, pid_t pid, id_t lwpid, struct prusage *usage)
7140Sstevel@tonic-gate {
7150Sstevel@tonic-gate 	float period;
7160Sstevel@tonic-gate 
7170Sstevel@tonic-gate 	if (!lwpid_is_active(pid, lwpid)) {
7180Sstevel@tonic-gate 		/*
7190Sstevel@tonic-gate 		 * If we are reading cpu times for the first time then
7200Sstevel@tonic-gate 		 * calculate average cpu times based on whole process
7210Sstevel@tonic-gate 		 * execution time.
7220Sstevel@tonic-gate 		 */
7230Sstevel@tonic-gate 		(void) memcpy(&lwp->li_usage, usage, sizeof (prusage_t));
7240Sstevel@tonic-gate 		period = TIME2NSEC(usage->pr_rtime);
7250Sstevel@tonic-gate 		period = period/(float)100;
7260Sstevel@tonic-gate 
7270Sstevel@tonic-gate 		if (period == 0) { /* zombie */
7280Sstevel@tonic-gate 			period = 1;
7290Sstevel@tonic-gate 			lwp->li_usr = 0;
7300Sstevel@tonic-gate 			lwp->li_sys = 0;
7310Sstevel@tonic-gate 			lwp->li_slp = 0;
7320Sstevel@tonic-gate 		} else {
7330Sstevel@tonic-gate 			lwp->li_usr = TIME2NSEC(usage->pr_utime)/period;
7340Sstevel@tonic-gate 			lwp->li_sys = TIME2NSEC(usage->pr_stime)/period;
7350Sstevel@tonic-gate 			lwp->li_slp = TIME2NSEC(usage->pr_slptime)/period;
7360Sstevel@tonic-gate 		}
7370Sstevel@tonic-gate 		lwp->li_trp = TIME2NSEC(usage->pr_ttime)/period;
7380Sstevel@tonic-gate 		lwp->li_tfl = TIME2NSEC(usage->pr_tftime)/period;
7390Sstevel@tonic-gate 		lwp->li_dfl = TIME2NSEC(usage->pr_dftime)/period;
7400Sstevel@tonic-gate 		lwp->li_lck = TIME2NSEC(usage->pr_ltime)/period;
7410Sstevel@tonic-gate 		lwp->li_lat = TIME2NSEC(usage->pr_wtime)/period;
7420Sstevel@tonic-gate 		period = (period / NANOSEC)*(float)100; /* now in seconds */
7430Sstevel@tonic-gate 		lwp->li_vcx = (ulong_t)
7440Sstevel@tonic-gate 		    (opts.o_interval * (usage->pr_vctx/period));
7450Sstevel@tonic-gate 		lwp->li_icx = (ulong_t)
7460Sstevel@tonic-gate 		    (opts.o_interval * (usage->pr_ictx/period));
7470Sstevel@tonic-gate 		lwp->li_scl = (ulong_t)
7480Sstevel@tonic-gate 		    (opts.o_interval * (usage->pr_sysc/period));
7490Sstevel@tonic-gate 		lwp->li_sig = (ulong_t)
7500Sstevel@tonic-gate 		    (opts.o_interval * (usage->pr_sigs/period));
7510Sstevel@tonic-gate 		(void) lwpid_set_active(pid, lwpid);
7520Sstevel@tonic-gate 	} else {
7530Sstevel@tonic-gate 		/*
7540Sstevel@tonic-gate 		 * If this is not a first time we are reading a process's
7550Sstevel@tonic-gate 		 * CPU times then recalculate CPU times based on fresh data
7560Sstevel@tonic-gate 		 * obtained from procfs and previous CPU time usage values.
7570Sstevel@tonic-gate 		 */
7580Sstevel@tonic-gate 		period = TIME2NSEC(usage->pr_rtime)-
7590Sstevel@tonic-gate 		    TIME2NSEC(lwp->li_usage.pr_rtime);
7600Sstevel@tonic-gate 		period = period/(float)100;
7610Sstevel@tonic-gate 
7620Sstevel@tonic-gate 		if (period == 0) { /* zombie */
7630Sstevel@tonic-gate 			period = 1;
7640Sstevel@tonic-gate 			lwp->li_usr = 0;
7650Sstevel@tonic-gate 			lwp->li_sys = 0;
7660Sstevel@tonic-gate 			lwp->li_slp = 0;
7670Sstevel@tonic-gate 		} else {
7680Sstevel@tonic-gate 			lwp->li_usr = (TIME2NSEC(usage->pr_utime)-
7690Sstevel@tonic-gate 			    TIME2NSEC(lwp->li_usage.pr_utime))/period;
7700Sstevel@tonic-gate 			lwp->li_sys = (TIME2NSEC(usage->pr_stime) -
7710Sstevel@tonic-gate 			    TIME2NSEC(lwp->li_usage.pr_stime))/period;
7720Sstevel@tonic-gate 			lwp->li_slp = (TIME2NSEC(usage->pr_slptime) -
7730Sstevel@tonic-gate 			    TIME2NSEC(lwp->li_usage.pr_slptime))/period;
7740Sstevel@tonic-gate 		}
7750Sstevel@tonic-gate 		lwp->li_trp = (TIME2NSEC(usage->pr_ttime) -
7760Sstevel@tonic-gate 		    TIME2NSEC(lwp->li_usage.pr_ttime))/period;
7770Sstevel@tonic-gate 		lwp->li_tfl = (TIME2NSEC(usage->pr_tftime) -
7780Sstevel@tonic-gate 		    TIME2NSEC(lwp->li_usage.pr_tftime))/period;
7790Sstevel@tonic-gate 		lwp->li_dfl = (TIME2NSEC(usage->pr_dftime) -
7800Sstevel@tonic-gate 		    TIME2NSEC(lwp->li_usage.pr_dftime))/period;
7810Sstevel@tonic-gate 		lwp->li_lck = (TIME2NSEC(usage->pr_ltime) -
7820Sstevel@tonic-gate 		    TIME2NSEC(lwp->li_usage.pr_ltime))/period;
7830Sstevel@tonic-gate 		lwp->li_lat = (TIME2NSEC(usage->pr_wtime) -
7840Sstevel@tonic-gate 		    TIME2NSEC(lwp->li_usage.pr_wtime))/period;
7850Sstevel@tonic-gate 		lwp->li_vcx = usage->pr_vctx - lwp->li_usage.pr_vctx;
7860Sstevel@tonic-gate 		lwp->li_icx = usage->pr_ictx - lwp->li_usage.pr_ictx;
7870Sstevel@tonic-gate 		lwp->li_scl = usage->pr_sysc - lwp->li_usage.pr_sysc;
7880Sstevel@tonic-gate 		lwp->li_sig = usage->pr_sigs - lwp->li_usage.pr_sigs;
7890Sstevel@tonic-gate 		(void) memcpy(&lwp->li_usage, usage, sizeof (prusage_t));
7900Sstevel@tonic-gate 	}
7910Sstevel@tonic-gate }
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate static int
7940Sstevel@tonic-gate read_procfile(fd_t **fd, char *pidstr, char *file, void *buf, size_t bufsize)
7950Sstevel@tonic-gate {
7960Sstevel@tonic-gate 	char procfile[MAX_PROCFS_PATH];
7970Sstevel@tonic-gate 
7980Sstevel@tonic-gate 	(void) snprintf(procfile, MAX_PROCFS_PATH,
7990Sstevel@tonic-gate 	    "/proc/%s/%s", pidstr, file);
8000Sstevel@tonic-gate 	if ((*fd = fd_open(procfile, O_RDONLY, *fd)) == NULL)
8010Sstevel@tonic-gate 		return (1);
8020Sstevel@tonic-gate 	if (pread(fd_getfd(*fd), buf, bufsize, 0) != bufsize) {
8030Sstevel@tonic-gate 		fd_close(*fd);
8040Sstevel@tonic-gate 		return (1);
8050Sstevel@tonic-gate 	}
8060Sstevel@tonic-gate 	return (0);
8070Sstevel@tonic-gate }
8080Sstevel@tonic-gate 
8090Sstevel@tonic-gate static void
8100Sstevel@tonic-gate add_proc(psinfo_t *psinfo)
8110Sstevel@tonic-gate {
8120Sstevel@tonic-gate 	lwp_info_t *lwp;
8130Sstevel@tonic-gate 	id_t lwpid;
8140Sstevel@tonic-gate 	pid_t pid = psinfo->pr_pid;
8150Sstevel@tonic-gate 
8160Sstevel@tonic-gate 	lwpid = psinfo->pr_lwp.pr_lwpid;
8170Sstevel@tonic-gate 	if ((lwp = lwpid_get(pid, lwpid)) == NULL)
8180Sstevel@tonic-gate 		lwp = list_add_lwp(&lwps, pid, lwpid);
8190Sstevel@tonic-gate 	lwp->li_flags |= LWP_ALIVE | LWP_REPRESENT;
8200Sstevel@tonic-gate 	(void) memcpy(&lwp->li_info, psinfo, sizeof (psinfo_t));
8210Sstevel@tonic-gate 	lwp->li_info.pr_lwp.pr_pctcpu = lwp->li_info.pr_pctcpu;
8220Sstevel@tonic-gate }
8230Sstevel@tonic-gate 
8240Sstevel@tonic-gate static void
8250Sstevel@tonic-gate add_lwp(psinfo_t *psinfo, lwpsinfo_t *lwpsinfo, int flags)
8260Sstevel@tonic-gate {
8270Sstevel@tonic-gate 	lwp_info_t *lwp;
8280Sstevel@tonic-gate 	pid_t pid = psinfo->pr_pid;
8290Sstevel@tonic-gate 	id_t lwpid = lwpsinfo->pr_lwpid;
8300Sstevel@tonic-gate 
8310Sstevel@tonic-gate 	if ((lwp = lwpid_get(pid, lwpid)) == NULL)
8320Sstevel@tonic-gate 		lwp = list_add_lwp(&lwps, pid, lwpid);
8330Sstevel@tonic-gate 	lwp->li_flags &= ~LWP_REPRESENT;
8340Sstevel@tonic-gate 	lwp->li_flags |= LWP_ALIVE;
8350Sstevel@tonic-gate 	lwp->li_flags |= flags;
8360Sstevel@tonic-gate 	(void) memcpy(&lwp->li_info, psinfo,
8370Sstevel@tonic-gate 	    sizeof (psinfo_t) - sizeof (lwpsinfo_t));
8380Sstevel@tonic-gate 	(void) memcpy(&lwp->li_info.pr_lwp, lwpsinfo, sizeof (lwpsinfo_t));
8390Sstevel@tonic-gate }
8400Sstevel@tonic-gate 
8410Sstevel@tonic-gate static void
8420Sstevel@tonic-gate prstat_scandir(DIR *procdir)
8430Sstevel@tonic-gate {
8440Sstevel@tonic-gate 	char *pidstr;
8450Sstevel@tonic-gate 	pid_t pid;
8460Sstevel@tonic-gate 	id_t lwpid;
8470Sstevel@tonic-gate 	size_t entsz;
8480Sstevel@tonic-gate 	long nlwps, nent, i;
8490Sstevel@tonic-gate 	char *buf, *ptr;
8500Sstevel@tonic-gate 
8510Sstevel@tonic-gate 	fds_t *fds;
8520Sstevel@tonic-gate 	lwp_info_t *lwp;
8530Sstevel@tonic-gate 	dirent_t *direntp;
8540Sstevel@tonic-gate 
8550Sstevel@tonic-gate 	prheader_t	header;
8560Sstevel@tonic-gate 	psinfo_t	psinfo;
8570Sstevel@tonic-gate 	prusage_t	usage;
8580Sstevel@tonic-gate 	lwpsinfo_t	*lwpsinfo;
8590Sstevel@tonic-gate 	prusage_t	*lwpusage;
8600Sstevel@tonic-gate 
8610Sstevel@tonic-gate 	total_procs = 0;
8620Sstevel@tonic-gate 	total_lwps = 0;
8630Sstevel@tonic-gate 	total_cpu = 0;
8640Sstevel@tonic-gate 	total_mem = 0;
8650Sstevel@tonic-gate 
8660Sstevel@tonic-gate 	convert_zone(&zone_tbl);
8670Sstevel@tonic-gate 	for (rewinddir(procdir); (direntp = readdir(procdir)); ) {
8680Sstevel@tonic-gate 		pidstr = direntp->d_name;
8690Sstevel@tonic-gate 		if (pidstr[0] == '.')	/* skip "." and ".."  */
8700Sstevel@tonic-gate 			continue;
8710Sstevel@tonic-gate 		pid = atoi(pidstr);
8720Sstevel@tonic-gate 		if (pid == 0 || pid == 2 || pid == 3)
8730Sstevel@tonic-gate 			continue;	/* skip sched, pageout and fsflush */
8740Sstevel@tonic-gate 		if (has_element(&pid_tbl, pid) == 0)
8750Sstevel@tonic-gate 			continue;	/* check if we really want this pid */
8760Sstevel@tonic-gate 		fds = fds_get(pid);	/* get ptr to file descriptors */
8770Sstevel@tonic-gate 
8780Sstevel@tonic-gate 		if (read_procfile(&fds->fds_psinfo, pidstr,
8790Sstevel@tonic-gate 		    "psinfo", &psinfo, sizeof (psinfo_t)) != 0)
8800Sstevel@tonic-gate 			continue;
8810Sstevel@tonic-gate 		if (!has_uid(&ruid_tbl, psinfo.pr_uid) ||
8820Sstevel@tonic-gate 		    !has_uid(&euid_tbl, psinfo.pr_euid) ||
8830Sstevel@tonic-gate 		    !has_element(&prj_tbl, psinfo.pr_projid) ||
8840Sstevel@tonic-gate 		    !has_element(&tsk_tbl, psinfo.pr_taskid) ||
8850Sstevel@tonic-gate 		    !has_zone(&zone_tbl, psinfo.pr_zoneid)) {
8860Sstevel@tonic-gate 			fd_close(fds->fds_psinfo);
8870Sstevel@tonic-gate 			continue;
8880Sstevel@tonic-gate 		}
8890Sstevel@tonic-gate 		nlwps = psinfo.pr_nlwp + psinfo.pr_nzomb;
8900Sstevel@tonic-gate 
8910Sstevel@tonic-gate 		if (nlwps > 1 && (opts.o_outpmode & (OPT_LWPS | OPT_PSETS))) {
8920Sstevel@tonic-gate 			int rep_lwp = 0;
8930Sstevel@tonic-gate 
8940Sstevel@tonic-gate 			if (read_procfile(&fds->fds_lpsinfo, pidstr, "lpsinfo",
8950Sstevel@tonic-gate 			    &header, sizeof (prheader_t)) != 0) {
8960Sstevel@tonic-gate 				fd_close(fds->fds_psinfo);
8970Sstevel@tonic-gate 				continue;
8980Sstevel@tonic-gate 			}
8990Sstevel@tonic-gate 
9000Sstevel@tonic-gate 			nent = header.pr_nent;
9010Sstevel@tonic-gate 			entsz = header.pr_entsize * nent;
9020Sstevel@tonic-gate 			ptr = buf = Malloc(entsz);
9030Sstevel@tonic-gate 			if (pread(fd_getfd(fds->fds_lpsinfo), buf,
9040Sstevel@tonic-gate 			    entsz, sizeof (struct prheader)) != entsz) {
9050Sstevel@tonic-gate 				fd_close(fds->fds_lpsinfo);
9060Sstevel@tonic-gate 				fd_close(fds->fds_psinfo);
9070Sstevel@tonic-gate 				free(buf);
9080Sstevel@tonic-gate 				continue;
9090Sstevel@tonic-gate 			}
9100Sstevel@tonic-gate 
9110Sstevel@tonic-gate 			nlwps = 0;
9120Sstevel@tonic-gate 			for (i = 0; i < nent; i++, ptr += header.pr_entsize) {
9130Sstevel@tonic-gate 				/*LINTED ALIGNMENT*/
9140Sstevel@tonic-gate 				lwpsinfo = (lwpsinfo_t *)ptr;
9150Sstevel@tonic-gate 				if (!has_element(&cpu_tbl,
9160Sstevel@tonic-gate 				    lwpsinfo->pr_onpro) ||
9170Sstevel@tonic-gate 				    !has_element(&set_tbl,
9182685Sakolb 				    lwpsinfo->pr_bindpset) ||
9192685Sakolb 				    !has_element(&lgr_tbl,
9202685Sakolb 					lwpsinfo->pr_lgrp))
9210Sstevel@tonic-gate 					continue;
9220Sstevel@tonic-gate 				nlwps++;
9230Sstevel@tonic-gate 				if ((opts.o_outpmode & (OPT_PSETS | OPT_LWPS))
9240Sstevel@tonic-gate 				    == OPT_PSETS) {
9250Sstevel@tonic-gate 					/*
9260Sstevel@tonic-gate 					 * If one of process's LWPs is bound
9270Sstevel@tonic-gate 					 * to a given processor set, report the
9280Sstevel@tonic-gate 					 * whole process.  We may be doing this
9290Sstevel@tonic-gate 					 * a few times but we'll get an accurate
9300Sstevel@tonic-gate 					 * lwp count in return.
9310Sstevel@tonic-gate 					 */
9320Sstevel@tonic-gate 					add_proc(&psinfo);
9330Sstevel@tonic-gate 				} else {
9340Sstevel@tonic-gate 					if (rep_lwp == 0) {
9350Sstevel@tonic-gate 						rep_lwp = 1;
9360Sstevel@tonic-gate 						add_lwp(&psinfo, lwpsinfo,
9370Sstevel@tonic-gate 						    LWP_REPRESENT);
9380Sstevel@tonic-gate 					} else {
9390Sstevel@tonic-gate 						add_lwp(&psinfo, lwpsinfo, 0);
9400Sstevel@tonic-gate 					}
9410Sstevel@tonic-gate 				}
9420Sstevel@tonic-gate 			}
9430Sstevel@tonic-gate 			free(buf);
9440Sstevel@tonic-gate 			if (nlwps == 0) {
9450Sstevel@tonic-gate 				fd_close(fds->fds_lpsinfo);
9460Sstevel@tonic-gate 				fd_close(fds->fds_psinfo);
9470Sstevel@tonic-gate 				continue;
9480Sstevel@tonic-gate 			}
9490Sstevel@tonic-gate 		} else {
9500Sstevel@tonic-gate 			if (!has_element(&cpu_tbl, psinfo.pr_lwp.pr_onpro) ||
9512685Sakolb 			    !has_element(&set_tbl, psinfo.pr_lwp.pr_bindpset) ||
9522685Sakolb 			    !has_element(&lgr_tbl, psinfo.pr_lwp.pr_lgrp)) {
9530Sstevel@tonic-gate 				fd_close(fds->fds_psinfo);
9540Sstevel@tonic-gate 				continue;
9550Sstevel@tonic-gate 			}
9560Sstevel@tonic-gate 			add_proc(&psinfo);
9570Sstevel@tonic-gate 		}
9580Sstevel@tonic-gate 		if (!(opts.o_outpmode & OPT_MSACCT)) {
9590Sstevel@tonic-gate 			total_procs++;
9600Sstevel@tonic-gate 			total_lwps += nlwps;
9610Sstevel@tonic-gate 			continue;
9620Sstevel@tonic-gate 		}
9630Sstevel@tonic-gate 		/*
9640Sstevel@tonic-gate 		 * Get more information about processes from /proc/pid/usage.
9650Sstevel@tonic-gate 		 * If process has more than one lwp, then we may have to
9660Sstevel@tonic-gate 		 * also look at the /proc/pid/lusage file.
9670Sstevel@tonic-gate 		 */
9680Sstevel@tonic-gate 		if ((opts.o_outpmode & OPT_LWPS) && (nlwps > 1)) {
9690Sstevel@tonic-gate 			if (read_procfile(&fds->fds_lusage, pidstr, "lusage",
9700Sstevel@tonic-gate 			    &header, sizeof (prheader_t)) != 0) {
9710Sstevel@tonic-gate 				fd_close(fds->fds_lpsinfo);
9720Sstevel@tonic-gate 				fd_close(fds->fds_psinfo);
9730Sstevel@tonic-gate 				continue;
9740Sstevel@tonic-gate 			}
9750Sstevel@tonic-gate 			nent = header.pr_nent;
9760Sstevel@tonic-gate 			entsz = header.pr_entsize * nent;
9770Sstevel@tonic-gate 			buf = Malloc(entsz);
9780Sstevel@tonic-gate 			if (pread(fd_getfd(fds->fds_lusage), buf,
9790Sstevel@tonic-gate 			    entsz, sizeof (struct prheader)) != entsz) {
9800Sstevel@tonic-gate 				fd_close(fds->fds_lusage);
9810Sstevel@tonic-gate 				fd_close(fds->fds_lpsinfo);
9820Sstevel@tonic-gate 				fd_close(fds->fds_psinfo);
9830Sstevel@tonic-gate 				free(buf);
9840Sstevel@tonic-gate 				continue;
9850Sstevel@tonic-gate 			}
9860Sstevel@tonic-gate 			for (i = 1, ptr = buf + header.pr_entsize; i < nent;
9870Sstevel@tonic-gate 			    i++, ptr += header.pr_entsize) {
9880Sstevel@tonic-gate 				/*LINTED ALIGNMENT*/
9890Sstevel@tonic-gate 				lwpusage = (prusage_t *)ptr;
9900Sstevel@tonic-gate 				lwpid = lwpusage->pr_lwpid;
9910Sstevel@tonic-gate 				/*
9920Sstevel@tonic-gate 				 * New LWPs created after we read lpsinfo
9930Sstevel@tonic-gate 				 * will be ignored.  Don't want to do
9940Sstevel@tonic-gate 				 * everything all over again.
9950Sstevel@tonic-gate 				 */
9960Sstevel@tonic-gate 				if ((lwp = lwpid_get(pid, lwpid)) == NULL)
9970Sstevel@tonic-gate 					continue;
9980Sstevel@tonic-gate 				lwp_update(lwp, pid, lwpid, lwpusage);
9990Sstevel@tonic-gate 			}
10000Sstevel@tonic-gate 			free(buf);
10010Sstevel@tonic-gate 		} else {
10020Sstevel@tonic-gate 			if (read_procfile(&fds->fds_usage, pidstr, "usage",
10030Sstevel@tonic-gate 			    &usage, sizeof (prusage_t)) != 0) {
10040Sstevel@tonic-gate 				fd_close(fds->fds_lpsinfo);
10050Sstevel@tonic-gate 				fd_close(fds->fds_psinfo);
10060Sstevel@tonic-gate 				continue;
10070Sstevel@tonic-gate 			}
10080Sstevel@tonic-gate 			lwpid = psinfo.pr_lwp.pr_lwpid;
10090Sstevel@tonic-gate 			if ((lwp = lwpid_get(pid, lwpid)) == NULL)
10100Sstevel@tonic-gate 				continue;
10110Sstevel@tonic-gate 			lwp_update(lwp, pid, lwpid, &usage);
10120Sstevel@tonic-gate 		}
10130Sstevel@tonic-gate 		total_procs++;
10140Sstevel@tonic-gate 		total_lwps += nlwps;
10150Sstevel@tonic-gate 	}
10160Sstevel@tonic-gate 	fd_update();
10170Sstevel@tonic-gate }
10180Sstevel@tonic-gate 
10190Sstevel@tonic-gate /*
10200Sstevel@tonic-gate  * This procedure removes all dead lwps from the linked list of all lwps.
10210Sstevel@tonic-gate  * It also creates linked list of ids if necessary.
10220Sstevel@tonic-gate  */
10230Sstevel@tonic-gate static void
10240Sstevel@tonic-gate list_refresh(list_t *list)
10250Sstevel@tonic-gate {
10260Sstevel@tonic-gate 	lwp_info_t *lwp, *lwp_next;
10270Sstevel@tonic-gate 
10280Sstevel@tonic-gate 	if (!(list->l_type & LT_LWPS))
10290Sstevel@tonic-gate 		return;
10300Sstevel@tonic-gate 
10310Sstevel@tonic-gate 	for (lwp = list->l_head; lwp != NULL; ) {
10320Sstevel@tonic-gate 		if (lwp->li_flags & LWP_ALIVE) {
10330Sstevel@tonic-gate 			/*
10340Sstevel@tonic-gate 			 * Process all live LWPs.
10350Sstevel@tonic-gate 			 * When we're done, mark them as dead.
10360Sstevel@tonic-gate 			 * They will be marked "alive" on the next
10370Sstevel@tonic-gate 			 * /proc scan if they still exist.
10380Sstevel@tonic-gate 			 */
10390Sstevel@tonic-gate 			lwp->li_key = list_getkeyval(list, lwp);
10400Sstevel@tonic-gate 			if (opts.o_outpmode & OPT_USERS)
10410Sstevel@tonic-gate 				list_update(&users, lwp);
10420Sstevel@tonic-gate 			if (opts.o_outpmode & OPT_TASKS)
10430Sstevel@tonic-gate 				list_update(&tasks, lwp);
10440Sstevel@tonic-gate 			if (opts.o_outpmode & OPT_PROJECTS)
10450Sstevel@tonic-gate 				list_update(&projects, lwp);
10460Sstevel@tonic-gate 			if (opts.o_outpmode & OPT_ZONES)
10470Sstevel@tonic-gate 				list_update(&zones, lwp);
10482685Sakolb 			if (opts.o_outpmode & OPT_LGRP)
10492685Sakolb 				list_update(&lgroups, lwp);
10500Sstevel@tonic-gate 			lwp->li_flags &= ~LWP_ALIVE;
10510Sstevel@tonic-gate 			lwp = lwp->li_next;
10520Sstevel@tonic-gate 
10530Sstevel@tonic-gate 		} else {
10540Sstevel@tonic-gate 			lwp_next = lwp->li_next;
10550Sstevel@tonic-gate 			list_remove_lwp(&lwps, lwp);
10560Sstevel@tonic-gate 			lwp = lwp_next;
10570Sstevel@tonic-gate 		}
10580Sstevel@tonic-gate 	}
10590Sstevel@tonic-gate }
10600Sstevel@tonic-gate 
10610Sstevel@tonic-gate static void
10620Sstevel@tonic-gate curses_on()
10630Sstevel@tonic-gate {
10640Sstevel@tonic-gate 	if ((opts.o_outpmode & OPT_TERMCAP) && (is_curses_on == FALSE)) {
10650Sstevel@tonic-gate 		(void) initscr();
10660Sstevel@tonic-gate 		(void) nonl();
10670Sstevel@tonic-gate 		(void) putp(t_smcup);
10680Sstevel@tonic-gate 		is_curses_on = TRUE;
10690Sstevel@tonic-gate 	}
10700Sstevel@tonic-gate }
10710Sstevel@tonic-gate 
10720Sstevel@tonic-gate static void
10730Sstevel@tonic-gate curses_off()
10740Sstevel@tonic-gate {
10750Sstevel@tonic-gate 	if ((is_curses_on == TRUE) && (opts.o_outpmode & OPT_TERMCAP)) {
10760Sstevel@tonic-gate 		(void) putp(t_rmcup);
10770Sstevel@tonic-gate 		(void) endwin();
10780Sstevel@tonic-gate 		is_curses_on = FALSE;
10790Sstevel@tonic-gate 	}
10800Sstevel@tonic-gate 	(void) fflush(stdout);
10810Sstevel@tonic-gate }
10820Sstevel@tonic-gate 
10830Sstevel@tonic-gate static int
10840Sstevel@tonic-gate nlines()
10850Sstevel@tonic-gate {
10860Sstevel@tonic-gate 	struct winsize ws;
10870Sstevel@tonic-gate 	char *envp;
10880Sstevel@tonic-gate 	int n;
10890Sstevel@tonic-gate 	if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != -1) {
10900Sstevel@tonic-gate 		if (ws.ws_row > 0)
10910Sstevel@tonic-gate 			return (ws.ws_row);
10920Sstevel@tonic-gate 	}
10930Sstevel@tonic-gate 	if (envp = getenv("LINES")) {
10940Sstevel@tonic-gate 		if ((n = Atoi(envp)) > 0) {
10950Sstevel@tonic-gate 			opts.o_outpmode &= ~OPT_USEHOME;
10960Sstevel@tonic-gate 			return (n);
10970Sstevel@tonic-gate 		}
10980Sstevel@tonic-gate 	}
10990Sstevel@tonic-gate 	return (-1);
11000Sstevel@tonic-gate }
11010Sstevel@tonic-gate 
11020Sstevel@tonic-gate static void
11030Sstevel@tonic-gate setmovecur()
11040Sstevel@tonic-gate {
11050Sstevel@tonic-gate 	int i, n;
11060Sstevel@tonic-gate 	if ((opts.o_outpmode & OPT_FULLSCREEN) &&
11070Sstevel@tonic-gate 	    (opts.o_outpmode & OPT_USEHOME)) {
11080Sstevel@tonic-gate 		movecur = t_home;
11090Sstevel@tonic-gate 		return;
11100Sstevel@tonic-gate 	}
11110Sstevel@tonic-gate 	if (opts.o_outpmode & OPT_SPLIT) {
11120Sstevel@tonic-gate 		n = opts.o_ntop + opts.o_nbottom + 2;
11130Sstevel@tonic-gate 	} else {
11140Sstevel@tonic-gate 		if (opts.o_outpmode & OPT_USERS)
11150Sstevel@tonic-gate 			n = opts.o_nbottom + 1;
11160Sstevel@tonic-gate 		else
11170Sstevel@tonic-gate 			n = opts.o_ntop + 1;
11180Sstevel@tonic-gate 	}
11190Sstevel@tonic-gate 	if (movecur != NULL && movecur != empty_string && movecur != t_home)
11200Sstevel@tonic-gate 		free(movecur);
11210Sstevel@tonic-gate 	movecur = Zalloc(strlen(t_up) * (n + 5));
11220Sstevel@tonic-gate 	for (i = 0; i <= n; i++)
11230Sstevel@tonic-gate 		(void) strcat(movecur, t_up);
11240Sstevel@tonic-gate }
11250Sstevel@tonic-gate 
11260Sstevel@tonic-gate static int
11270Sstevel@tonic-gate setsize()
11280Sstevel@tonic-gate {
11290Sstevel@tonic-gate 	static int oldn = 0;
11300Sstevel@tonic-gate 	int n;
11310Sstevel@tonic-gate 
11320Sstevel@tonic-gate 	if (opts.o_outpmode & OPT_FULLSCREEN) {
11330Sstevel@tonic-gate 		n = nlines();
11340Sstevel@tonic-gate 		if (n == oldn)
11350Sstevel@tonic-gate 			return (0);
11360Sstevel@tonic-gate 		oldn = n;
11370Sstevel@tonic-gate 		if (n == -1) {
11380Sstevel@tonic-gate 			opts.o_outpmode &= ~OPT_USEHOME;
11390Sstevel@tonic-gate 			setmovecur();		/* set default window size */
11400Sstevel@tonic-gate 			return (1);
11410Sstevel@tonic-gate 		}
11420Sstevel@tonic-gate 		n = n - 3;	/* minus header, total and cursor lines */
11430Sstevel@tonic-gate 		if (n < 1)
11440Sstevel@tonic-gate 			Die(gettext("window is too small (try -n)\n"));
11450Sstevel@tonic-gate 		if (opts.o_outpmode & OPT_SPLIT) {
11460Sstevel@tonic-gate 			if (n < 8) {
11470Sstevel@tonic-gate 				Die(gettext("window is too small (try -n)\n"));
11480Sstevel@tonic-gate 			} else {
11490Sstevel@tonic-gate 				opts.o_ntop = (n / 4) * 3;
11500Sstevel@tonic-gate 				opts.o_nbottom = n - 1 - opts.o_ntop;
11510Sstevel@tonic-gate 			}
11520Sstevel@tonic-gate 		} else {
11530Sstevel@tonic-gate 			if (opts.o_outpmode & OPT_USERS)
11540Sstevel@tonic-gate 				opts.o_nbottom = n;
11550Sstevel@tonic-gate 			else
11560Sstevel@tonic-gate 				opts.o_ntop = n;
11570Sstevel@tonic-gate 		}
11580Sstevel@tonic-gate 	}
11590Sstevel@tonic-gate 	setmovecur();
11600Sstevel@tonic-gate 	return (1);
11610Sstevel@tonic-gate }
11620Sstevel@tonic-gate 
11630Sstevel@tonic-gate static void
11640Sstevel@tonic-gate ldtermcap()
11650Sstevel@tonic-gate {
11660Sstevel@tonic-gate 	int err;
11670Sstevel@tonic-gate 	if (setupterm(NULL, STDIN_FILENO, &err) == ERR) {
11680Sstevel@tonic-gate 		switch (err) {
11690Sstevel@tonic-gate 		case 0:
11700Sstevel@tonic-gate 			Warn(gettext("failed to load terminal info, "
11710Sstevel@tonic-gate 			    "defaulting to -c option\n"));
11720Sstevel@tonic-gate 			break;
11730Sstevel@tonic-gate 		case -1:
11740Sstevel@tonic-gate 			Warn(gettext("terminfo database not found, "
11750Sstevel@tonic-gate 			    "defaulting to -c option\n"));
11760Sstevel@tonic-gate 			break;
11770Sstevel@tonic-gate 		default:
11780Sstevel@tonic-gate 			Warn(gettext("failed to initialize terminal, "
11790Sstevel@tonic-gate 			    "defaulting to -c option\n"));
11800Sstevel@tonic-gate 		}
11810Sstevel@tonic-gate 		opts.o_outpmode &= ~OPT_TERMCAP;
11820Sstevel@tonic-gate 		t_up = t_eol = t_smcup = t_rmcup = movecur = empty_string;
11830Sstevel@tonic-gate 		t_ulon = t_uloff = empty_string;
11840Sstevel@tonic-gate 		return;
11850Sstevel@tonic-gate 	}
11860Sstevel@tonic-gate 	t_ulon	= tigetstr("smul");
11870Sstevel@tonic-gate 	t_uloff	= tigetstr("rmul");
11880Sstevel@tonic-gate 	t_up	= tigetstr("cuu1");
11890Sstevel@tonic-gate 	t_eol	= tigetstr("el");
11900Sstevel@tonic-gate 	t_smcup	= tigetstr("smcup");
11910Sstevel@tonic-gate 	t_rmcup = tigetstr("rmcup");
11920Sstevel@tonic-gate 	t_home  = tigetstr("home");
11930Sstevel@tonic-gate 	if ((t_up == (char *)-1) || (t_eol == (char *)-1) ||
11940Sstevel@tonic-gate 	    (t_smcup == (char *)-1) || (t_rmcup == (char *)-1)) {
11950Sstevel@tonic-gate 		opts.o_outpmode &= ~OPT_TERMCAP;
11960Sstevel@tonic-gate 		t_up = t_eol = t_smcup = t_rmcup = movecur = empty_string;
11970Sstevel@tonic-gate 		return;
11980Sstevel@tonic-gate 	}
11990Sstevel@tonic-gate 	if (t_up == NULL || t_eol == NULL) {
12000Sstevel@tonic-gate 		opts.o_outpmode &= ~OPT_TERMCAP;
12010Sstevel@tonic-gate 		t_eol = t_up = movecur = empty_string;
12020Sstevel@tonic-gate 		return;
12030Sstevel@tonic-gate 	}
12040Sstevel@tonic-gate 	if (t_ulon == (char *)-1 || t_uloff == (char *)-1 ||
12050Sstevel@tonic-gate 	    t_ulon == NULL || t_uloff == NULL) {
12060Sstevel@tonic-gate 		t_ulon = t_uloff = empty_string;  /* can live without it */
12070Sstevel@tonic-gate 	}
12080Sstevel@tonic-gate 	if (t_smcup == NULL || t_rmcup == NULL)
12090Sstevel@tonic-gate 		t_smcup = t_rmcup = empty_string;
12100Sstevel@tonic-gate 	if (t_home == (char *)-1 || t_home == NULL) {
12110Sstevel@tonic-gate 		opts.o_outpmode &= ~OPT_USEHOME;
12120Sstevel@tonic-gate 		t_home = empty_string;
12130Sstevel@tonic-gate 	}
12140Sstevel@tonic-gate }
12150Sstevel@tonic-gate 
12160Sstevel@tonic-gate static void
12170Sstevel@tonic-gate sig_handler(int sig)
12180Sstevel@tonic-gate {
12190Sstevel@tonic-gate 	switch (sig) {
12200Sstevel@tonic-gate 	case SIGTSTP:	sigtstp = 1;
12210Sstevel@tonic-gate 			break;
12220Sstevel@tonic-gate 	case SIGWINCH:	sigwinch = 1;
12230Sstevel@tonic-gate 			break;
12240Sstevel@tonic-gate 	case SIGINT:
12250Sstevel@tonic-gate 	case SIGTERM:	sigterm = 1;
12260Sstevel@tonic-gate 			break;
12270Sstevel@tonic-gate 	}
12280Sstevel@tonic-gate }
12290Sstevel@tonic-gate 
12300Sstevel@tonic-gate static void
12310Sstevel@tonic-gate set_signals()
12320Sstevel@tonic-gate {
12330Sstevel@tonic-gate 	(void) signal(SIGTSTP, sig_handler);
12340Sstevel@tonic-gate 	(void) signal(SIGINT, sig_handler);
12350Sstevel@tonic-gate 	(void) signal(SIGTERM, sig_handler);
12360Sstevel@tonic-gate 	if (opts.o_outpmode & OPT_FULLSCREEN)
12370Sstevel@tonic-gate 		(void) signal(SIGWINCH, sig_handler);
12380Sstevel@tonic-gate }
12390Sstevel@tonic-gate 
12400Sstevel@tonic-gate static void
1241586Svb160487 fill_table(table_t *table, char *arg, char option)
12420Sstevel@tonic-gate {
12430Sstevel@tonic-gate 	char *p = strtok(arg, ", ");
1244586Svb160487 
1245586Svb160487 	if (p == NULL)
1246586Svb160487 		Die(gettext("invalid argument for -%c\n"), option);
12470Sstevel@tonic-gate 
1248586Svb160487 	add_element(table, (long)Atoi(p));
1249586Svb160487 	while (p = strtok(NULL, ", "))
1250586Svb160487 		add_element(table, (long)Atoi(p));
12510Sstevel@tonic-gate }
12520Sstevel@tonic-gate 
12530Sstevel@tonic-gate static void
12540Sstevel@tonic-gate fill_prj_table(char *arg)
12550Sstevel@tonic-gate {
12560Sstevel@tonic-gate 	projid_t projid;
12570Sstevel@tonic-gate 	char *p = strtok(arg, ", ");
12580Sstevel@tonic-gate 
1259586Svb160487 	if (p == NULL)
1260586Svb160487 		Die(gettext("invalid argument for -j\n"));
1261586Svb160487 
12620Sstevel@tonic-gate 	if ((projid = getprojidbyname(p)) == -1)
12630Sstevel@tonic-gate 		projid = Atoi(p);
12640Sstevel@tonic-gate 	add_element(&prj_tbl, (long)projid);
12650Sstevel@tonic-gate 
12660Sstevel@tonic-gate 	while (p = strtok(NULL, ", ")) {
12670Sstevel@tonic-gate 		if ((projid = getprojidbyname(p)) == -1)
12680Sstevel@tonic-gate 			projid = Atoi(p);
12690Sstevel@tonic-gate 		add_element(&prj_tbl, (long)projid);
12700Sstevel@tonic-gate 	}
12710Sstevel@tonic-gate }
12720Sstevel@tonic-gate 
12730Sstevel@tonic-gate static void
12740Sstevel@tonic-gate fill_set_table(char *arg)
12750Sstevel@tonic-gate {
12760Sstevel@tonic-gate 	char *p = strtok(arg, ", ");
12770Sstevel@tonic-gate 	psetid_t id;
12780Sstevel@tonic-gate 
1279586Svb160487 	if (p == NULL)
1280586Svb160487 		Die(gettext("invalid argument for -C\n"));
1281586Svb160487 
12820Sstevel@tonic-gate 	if ((id = Atoi(p)) == 0)
12830Sstevel@tonic-gate 		id = PS_NONE;
12840Sstevel@tonic-gate 	add_element(&set_tbl, id);
12850Sstevel@tonic-gate 	while (p = strtok(NULL, ", ")) {
12860Sstevel@tonic-gate 		if ((id = Atoi(p)) == 0)
12870Sstevel@tonic-gate 			id = PS_NONE;
12880Sstevel@tonic-gate 		if (!has_element(&set_tbl, id))
12890Sstevel@tonic-gate 			add_element(&set_tbl, id);
12900Sstevel@tonic-gate 	}
12910Sstevel@tonic-gate }
12920Sstevel@tonic-gate 
12930Sstevel@tonic-gate static void
12940Sstevel@tonic-gate Exit()
12950Sstevel@tonic-gate {
12960Sstevel@tonic-gate 	curses_off();
12970Sstevel@tonic-gate 	list_clear(&lwps);
12980Sstevel@tonic-gate 	list_clear(&users);
12990Sstevel@tonic-gate 	list_clear(&tasks);
13000Sstevel@tonic-gate 	list_clear(&projects);
13010Sstevel@tonic-gate 	list_clear(&zones);
13020Sstevel@tonic-gate 	fd_exit();
13030Sstevel@tonic-gate }
13040Sstevel@tonic-gate 
1305*3247Sgjelinek 
13060Sstevel@tonic-gate int
13070Sstevel@tonic-gate main(int argc, char **argv)
13080Sstevel@tonic-gate {
13090Sstevel@tonic-gate 	DIR *procdir;
13100Sstevel@tonic-gate 	char *p;
13110Sstevel@tonic-gate 	char *sortk = "cpu";	/* default sort key */
13120Sstevel@tonic-gate 	int opt;
13130Sstevel@tonic-gate 	int timeout;
13140Sstevel@tonic-gate 	struct pollfd pollset;
13150Sstevel@tonic-gate 	char key;
13160Sstevel@tonic-gate 
13170Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
13180Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
13190Sstevel@tonic-gate 	Progname(argv[0]);
13200Sstevel@tonic-gate 	lwpid_init();
13210Sstevel@tonic-gate 	fd_init(Setrlimit());
13220Sstevel@tonic-gate 
1323*3247Sgjelinek 	pagesize = sysconf(_SC_PAGESIZE);
1324*3247Sgjelinek 
13252685Sakolb 	while ((opt = getopt(argc, argv, "vcHmaRLtu:U:n:p:C:P:h:s:S:j:k:TJz:Z"))
13260Sstevel@tonic-gate 	    != (int)EOF) {
13270Sstevel@tonic-gate 		switch (opt) {
13280Sstevel@tonic-gate 		case 'R':
13290Sstevel@tonic-gate 			opts.o_outpmode |= OPT_REALTIME;
13300Sstevel@tonic-gate 			break;
13310Sstevel@tonic-gate 		case 'c':
13320Sstevel@tonic-gate 			opts.o_outpmode &= ~OPT_TERMCAP;
13330Sstevel@tonic-gate 			opts.o_outpmode &= ~OPT_FULLSCREEN;
13340Sstevel@tonic-gate 			break;
13352685Sakolb 		case 'h':
13362685Sakolb 			fill_table(&lgr_tbl, optarg, 'h');
13372685Sakolb 			break;
13382685Sakolb 		case 'H':
13392685Sakolb 			opts.o_outpmode |= OPT_LGRP;
13402685Sakolb 			break;
13410Sstevel@tonic-gate 		case 'm':
13420Sstevel@tonic-gate 		case 'v':
13430Sstevel@tonic-gate 			opts.o_outpmode &= ~OPT_PSINFO;
13440Sstevel@tonic-gate 			opts.o_outpmode |=  OPT_MSACCT;
13450Sstevel@tonic-gate 			break;
13460Sstevel@tonic-gate 		case 't':
13470Sstevel@tonic-gate 			opts.o_outpmode &= ~OPT_PSINFO;
13480Sstevel@tonic-gate 			opts.o_outpmode |= OPT_USERS;
13490Sstevel@tonic-gate 			break;
13500Sstevel@tonic-gate 		case 'a':
13510Sstevel@tonic-gate 			opts.o_outpmode |= OPT_SPLIT | OPT_USERS;
13520Sstevel@tonic-gate 			break;
13530Sstevel@tonic-gate 		case 'T':
13540Sstevel@tonic-gate 			opts.o_outpmode |= OPT_SPLIT | OPT_TASKS;
13550Sstevel@tonic-gate 			break;
13560Sstevel@tonic-gate 		case 'J':
13570Sstevel@tonic-gate 			opts.o_outpmode |= OPT_SPLIT | OPT_PROJECTS;
13580Sstevel@tonic-gate 			break;
13590Sstevel@tonic-gate 		case 'n':
1360586Svb160487 			if ((p = strtok(optarg, ",")) == NULL)
1361586Svb160487 				Die(gettext("invalid argument for -n\n"));
13620Sstevel@tonic-gate 			opts.o_ntop = Atoi(p);
13630Sstevel@tonic-gate 			if (p = strtok(NULL, ","))
13640Sstevel@tonic-gate 				opts.o_nbottom = Atoi(p);
13650Sstevel@tonic-gate 			opts.o_outpmode &= ~OPT_FULLSCREEN;
13660Sstevel@tonic-gate 			break;
13670Sstevel@tonic-gate 		case 's':
13680Sstevel@tonic-gate 			opts.o_sortorder = -1;
13690Sstevel@tonic-gate 			sortk = optarg;
13700Sstevel@tonic-gate 			break;
13710Sstevel@tonic-gate 		case 'S':
13720Sstevel@tonic-gate 			opts.o_sortorder = 1;
13730Sstevel@tonic-gate 			sortk = optarg;
13740Sstevel@tonic-gate 			break;
13750Sstevel@tonic-gate 		case 'u':
1376586Svb160487 			if ((p = strtok(optarg, ", ")) == NULL)
1377586Svb160487 				Die(gettext("invalid argument for -u\n"));
13780Sstevel@tonic-gate 			add_uid(&euid_tbl, p);
13790Sstevel@tonic-gate 			while (p = strtok(NULL, ", "))
13800Sstevel@tonic-gate 				add_uid(&euid_tbl, p);
13810Sstevel@tonic-gate 			break;
13820Sstevel@tonic-gate 		case 'U':
1383586Svb160487 			if ((p = strtok(optarg, ", ")) == NULL)
1384586Svb160487 				Die(gettext("invalid argument for -U\n"));
13850Sstevel@tonic-gate 			add_uid(&ruid_tbl, p);
13860Sstevel@tonic-gate 			while (p = strtok(NULL, ", "))
13870Sstevel@tonic-gate 				add_uid(&ruid_tbl, p);
13880Sstevel@tonic-gate 			break;
13890Sstevel@tonic-gate 		case 'p':
1390586Svb160487 			fill_table(&pid_tbl, optarg, 'p');
13910Sstevel@tonic-gate 			break;
13920Sstevel@tonic-gate 		case 'C':
13930Sstevel@tonic-gate 			fill_set_table(optarg);
13940Sstevel@tonic-gate 			opts.o_outpmode |= OPT_PSETS;
13950Sstevel@tonic-gate 			break;
13960Sstevel@tonic-gate 		case 'P':
1397586Svb160487 			fill_table(&cpu_tbl, optarg, 'P');
13980Sstevel@tonic-gate 			break;
13990Sstevel@tonic-gate 		case 'k':
1400586Svb160487 			fill_table(&tsk_tbl, optarg, 'k');
14010Sstevel@tonic-gate 			break;
14020Sstevel@tonic-gate 		case 'j':
14030Sstevel@tonic-gate 			fill_prj_table(optarg);
14040Sstevel@tonic-gate 			break;
14050Sstevel@tonic-gate 		case 'L':
14060Sstevel@tonic-gate 			opts.o_outpmode |= OPT_LWPS;
14070Sstevel@tonic-gate 			break;
14080Sstevel@tonic-gate 		case 'z':
1409586Svb160487 			if ((p = strtok(optarg, ", ")) == NULL)
1410586Svb160487 				Die(gettext("invalid argument for -z\n"));
14110Sstevel@tonic-gate 			add_zone(&zone_tbl, p);
14120Sstevel@tonic-gate 			while (p = strtok(NULL, ", "))
14130Sstevel@tonic-gate 				add_zone(&zone_tbl, p);
14140Sstevel@tonic-gate 			break;
14150Sstevel@tonic-gate 		case 'Z':
14160Sstevel@tonic-gate 			opts.o_outpmode |= OPT_SPLIT | OPT_ZONES;
14170Sstevel@tonic-gate 			break;
14180Sstevel@tonic-gate 		default:
14190Sstevel@tonic-gate 			Usage();
14200Sstevel@tonic-gate 		}
14210Sstevel@tonic-gate 	}
14220Sstevel@tonic-gate 
14230Sstevel@tonic-gate 	(void) atexit(Exit);
14240Sstevel@tonic-gate 	if ((opts.o_outpmode & OPT_USERS) &&
14250Sstevel@tonic-gate 	    !(opts.o_outpmode & OPT_SPLIT))
14260Sstevel@tonic-gate 		opts.o_nbottom = opts.o_ntop;
14270Sstevel@tonic-gate 	if (opts.o_ntop == 0 || opts.o_nbottom == 0)
14280Sstevel@tonic-gate 		Die(gettext("invalid argument for -n\n"));
14290Sstevel@tonic-gate 	if (!(opts.o_outpmode & OPT_SPLIT) && (opts.o_outpmode & OPT_USERS) &&
14300Sstevel@tonic-gate 	    ((opts.o_outpmode & (OPT_PSINFO | OPT_MSACCT))))
14310Sstevel@tonic-gate 		Die(gettext("-t option cannot be used with -v or -m\n"));
14320Sstevel@tonic-gate 
14330Sstevel@tonic-gate 	if ((opts.o_outpmode & OPT_SPLIT) && (opts.o_outpmode && OPT_USERS) &&
14340Sstevel@tonic-gate 	    !((opts.o_outpmode & (OPT_PSINFO | OPT_MSACCT))))
14350Sstevel@tonic-gate 		Die(gettext("-t option cannot be used with "
14360Sstevel@tonic-gate 		    "-a, -J, -T or -Z\n"));
14370Sstevel@tonic-gate 
14380Sstevel@tonic-gate 	if ((opts.o_outpmode & OPT_USERS) &&
14392685Sakolb 	    (opts.o_outpmode &
14402685Sakolb 		(OPT_TASKS | OPT_PROJECTS | OPT_ZONES)))
14410Sstevel@tonic-gate 		Die(gettext("-a option cannot be used with "
14420Sstevel@tonic-gate 		    "-t, -J, -T or -Z\n"));
14430Sstevel@tonic-gate 
14440Sstevel@tonic-gate 	if (((opts.o_outpmode & OPT_TASKS) &&
14450Sstevel@tonic-gate 	    (opts.o_outpmode & (OPT_PROJECTS|OPT_ZONES))) ||
14460Sstevel@tonic-gate 	    ((opts.o_outpmode & OPT_PROJECTS) &&
14472685Sakolb 		(opts.o_outpmode & (OPT_TASKS|OPT_ZONES)))) {
14482685Sakolb 		Die(gettext(
14492685Sakolb 		    "-J, -T and -Z options are mutually exclusive\n"));
14502685Sakolb 	}
14512685Sakolb 
14522685Sakolb 	/*
14532685Sakolb 	 * There is not enough space to combine microstate information and
14542685Sakolb 	 * lgroup information and still fit in 80-column output.
14552685Sakolb 	 */
14562685Sakolb 	if ((opts.o_outpmode & OPT_LGRP) && (opts.o_outpmode & OPT_MSACCT)) {
14572685Sakolb 		Die(gettext("-H and -m options are mutually exclusive\n"));
14580Sstevel@tonic-gate 	}
14590Sstevel@tonic-gate 
14600Sstevel@tonic-gate 	if (argc > optind)
14610Sstevel@tonic-gate 		opts.o_interval = Atoi(argv[optind++]);
14620Sstevel@tonic-gate 	if (argc > optind)
14630Sstevel@tonic-gate 		opts.o_count = Atoi(argv[optind++]);
14640Sstevel@tonic-gate 	if (opts.o_count == 0)
14650Sstevel@tonic-gate 		Die(gettext("invalid counter value\n"));
14660Sstevel@tonic-gate 	if (argc > optind)
14670Sstevel@tonic-gate 		Usage();
14680Sstevel@tonic-gate 	if (opts.o_outpmode & OPT_REALTIME)
14690Sstevel@tonic-gate 		Priocntl("RT");
14700Sstevel@tonic-gate 	if (isatty(STDOUT_FILENO) == 1 && isatty(STDIN_FILENO))
14710Sstevel@tonic-gate 		opts.o_outpmode |= OPT_TTY;	/* interactive */
14720Sstevel@tonic-gate 	if (!(opts.o_outpmode & OPT_TTY)) {
14730Sstevel@tonic-gate 		opts.o_outpmode &= ~OPT_TERMCAP; /* no termcap for pipes */
14740Sstevel@tonic-gate 		opts.o_outpmode &= ~OPT_FULLSCREEN;
14750Sstevel@tonic-gate 	}
14760Sstevel@tonic-gate 	if (opts.o_outpmode & OPT_TERMCAP)
14770Sstevel@tonic-gate 		ldtermcap();		/* can turn OPT_TERMCAP off */
14780Sstevel@tonic-gate 	if (opts.o_outpmode & OPT_TERMCAP)
14790Sstevel@tonic-gate 		(void) setsize();
14800Sstevel@tonic-gate 	list_alloc(&lwps, opts.o_ntop);
14810Sstevel@tonic-gate 	list_alloc(&users, opts.o_nbottom);
14820Sstevel@tonic-gate 	list_alloc(&tasks, opts.o_nbottom);
14830Sstevel@tonic-gate 	list_alloc(&projects, opts.o_nbottom);
14840Sstevel@tonic-gate 	list_alloc(&zones, opts.o_nbottom);
14852685Sakolb 	list_alloc(&lgroups, opts.o_nbottom);
14860Sstevel@tonic-gate 	list_setkeyfunc(sortk, &opts, &lwps, LT_LWPS);
14870Sstevel@tonic-gate 	list_setkeyfunc(NULL, &opts, &users, LT_USERS);
14880Sstevel@tonic-gate 	list_setkeyfunc(NULL, &opts, &tasks, LT_TASKS);
14890Sstevel@tonic-gate 	list_setkeyfunc(NULL, &opts, &projects, LT_PROJECTS);
14900Sstevel@tonic-gate 	list_setkeyfunc(NULL, &opts, &zones, LT_ZONES);
14912685Sakolb 	list_setkeyfunc(NULL, &opts, &lgroups, LT_LGRPS);
14920Sstevel@tonic-gate 	if (opts.o_outpmode & OPT_TERMCAP)
14930Sstevel@tonic-gate 		curses_on();
14940Sstevel@tonic-gate 	if ((procdir = opendir("/proc")) == NULL)
14950Sstevel@tonic-gate 		Die(gettext("cannot open /proc directory\n"));
14960Sstevel@tonic-gate 	if (opts.o_outpmode & OPT_TTY) {
14970Sstevel@tonic-gate 		(void) printf(gettext("Please wait...\r"));
14980Sstevel@tonic-gate 		(void) fflush(stdout);
14990Sstevel@tonic-gate 	}
15000Sstevel@tonic-gate 	set_signals();
15010Sstevel@tonic-gate 	pollset.fd = STDIN_FILENO;
15020Sstevel@tonic-gate 	pollset.events = POLLIN;
15030Sstevel@tonic-gate 	timeout = opts.o_interval * MILLISEC;
15040Sstevel@tonic-gate 
15050Sstevel@tonic-gate 	/*
15060Sstevel@tonic-gate 	 * main program loop
15070Sstevel@tonic-gate 	 */
15080Sstevel@tonic-gate 	do {
15090Sstevel@tonic-gate 		if (sigterm == 1)
15100Sstevel@tonic-gate 			break;
15110Sstevel@tonic-gate 		if (sigtstp == 1) {
15120Sstevel@tonic-gate 			curses_off();
15130Sstevel@tonic-gate 			(void) signal(SIGTSTP, SIG_DFL);
15140Sstevel@tonic-gate 			(void) kill(0, SIGTSTP);
15150Sstevel@tonic-gate 			/*
15160Sstevel@tonic-gate 			 * prstat stops here until it receives SIGCONT signal.
15170Sstevel@tonic-gate 			 */
15180Sstevel@tonic-gate 			sigtstp = 0;
15190Sstevel@tonic-gate 			(void) signal(SIGTSTP, sig_handler);
15200Sstevel@tonic-gate 			curses_on();
15210Sstevel@tonic-gate 			print_movecur = FALSE;
15220Sstevel@tonic-gate 			if (opts.o_outpmode & OPT_FULLSCREEN)
15230Sstevel@tonic-gate 				sigwinch = 1;
15240Sstevel@tonic-gate 		}
15250Sstevel@tonic-gate 		if (sigwinch == 1) {
15260Sstevel@tonic-gate 			if (setsize() == 1) {
15270Sstevel@tonic-gate 				list_free(&lwps);
15280Sstevel@tonic-gate 				list_free(&users);
15290Sstevel@tonic-gate 				list_free(&tasks);
15300Sstevel@tonic-gate 				list_free(&projects);
15310Sstevel@tonic-gate 				list_free(&zones);
15320Sstevel@tonic-gate 				list_alloc(&lwps, opts.o_ntop);
15330Sstevel@tonic-gate 				list_alloc(&users, opts.o_nbottom);
15340Sstevel@tonic-gate 				list_alloc(&tasks, opts.o_nbottom);
15350Sstevel@tonic-gate 				list_alloc(&projects, opts.o_nbottom);
15360Sstevel@tonic-gate 				list_alloc(&zones, opts.o_nbottom);
15370Sstevel@tonic-gate 			}
15380Sstevel@tonic-gate 			sigwinch = 0;
15390Sstevel@tonic-gate 			(void) signal(SIGWINCH, sig_handler);
15400Sstevel@tonic-gate 		}
15410Sstevel@tonic-gate 		prstat_scandir(procdir);
15420Sstevel@tonic-gate 		list_refresh(&lwps);
15430Sstevel@tonic-gate 		if (print_movecur)
15440Sstevel@tonic-gate 			(void) putp(movecur);
15450Sstevel@tonic-gate 		print_movecur = TRUE;
15460Sstevel@tonic-gate 		if ((opts.o_outpmode & OPT_PSINFO) ||
15470Sstevel@tonic-gate 		    (opts.o_outpmode & OPT_MSACCT)) {
15480Sstevel@tonic-gate 			list_sort(&lwps);
15490Sstevel@tonic-gate 			list_print(&lwps);
15500Sstevel@tonic-gate 		}
15510Sstevel@tonic-gate 		if (opts.o_outpmode & OPT_USERS) {
1552*3247Sgjelinek 			list_getsize(&users);
15530Sstevel@tonic-gate 			list_sort(&users);
15540Sstevel@tonic-gate 			list_print(&users);
15550Sstevel@tonic-gate 			list_clear(&users);
15560Sstevel@tonic-gate 		}
15570Sstevel@tonic-gate 		if (opts.o_outpmode & OPT_TASKS) {
1558*3247Sgjelinek 			list_getsize(&tasks);
15590Sstevel@tonic-gate 			list_sort(&tasks);
15600Sstevel@tonic-gate 			list_print(&tasks);
15610Sstevel@tonic-gate 			list_clear(&tasks);
15620Sstevel@tonic-gate 		}
15630Sstevel@tonic-gate 		if (opts.o_outpmode & OPT_PROJECTS) {
1564*3247Sgjelinek 			list_getsize(&projects);
15650Sstevel@tonic-gate 			list_sort(&projects);
15660Sstevel@tonic-gate 			list_print(&projects);
15670Sstevel@tonic-gate 			list_clear(&projects);
15680Sstevel@tonic-gate 		}
15690Sstevel@tonic-gate 		if (opts.o_outpmode & OPT_ZONES) {
1570*3247Sgjelinek 			list_getsize(&zones);
15710Sstevel@tonic-gate 			list_sort(&zones);
15720Sstevel@tonic-gate 			list_print(&zones);
15730Sstevel@tonic-gate 			list_clear(&zones);
15740Sstevel@tonic-gate 		}
15750Sstevel@tonic-gate 		if (opts.o_count == 1)
15760Sstevel@tonic-gate 			break;
15770Sstevel@tonic-gate 		/*
15780Sstevel@tonic-gate 		 * If poll() returns -1 and sets errno to EINTR here because
15790Sstevel@tonic-gate 		 * the process received a signal, it is Ok to abort this
15800Sstevel@tonic-gate 		 * timeout and loop around because we check the signals at the
15810Sstevel@tonic-gate 		 * top of the loop.
15820Sstevel@tonic-gate 		 */
15830Sstevel@tonic-gate 		if (opts.o_outpmode & OPT_TTY) {
15840Sstevel@tonic-gate 			if (poll(&pollset, (nfds_t)1, timeout) > 0) {
15850Sstevel@tonic-gate 				if (read(STDIN_FILENO, &key, 1) == 1) {
15860Sstevel@tonic-gate 					if (tolower(key) == 'q')
15870Sstevel@tonic-gate 						break;
15880Sstevel@tonic-gate 				}
15890Sstevel@tonic-gate 			}
15900Sstevel@tonic-gate 		} else {
15910Sstevel@tonic-gate 			(void) sleep(opts.o_interval);
15920Sstevel@tonic-gate 		}
15930Sstevel@tonic-gate 	} while (opts.o_count == (-1) || --opts.o_count);
15940Sstevel@tonic-gate 
15950Sstevel@tonic-gate 	if (opts.o_outpmode & OPT_TTY)
15960Sstevel@tonic-gate 		(void) putchar('\r');
15970Sstevel@tonic-gate 	return (0);
15980Sstevel@tonic-gate }
1599