xref: /onnv-gate/usr/src/cmd/prstat/prstat.c (revision 9966:d4ba9662e3c8)
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 /*
239123Sjohn.levon@sun.com  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
25*9966SMenno.Lageman@Sun.COM  *
26*9966SMenno.Lageman@Sun.COM  * Portions Copyright 2009 Chad Mynhier
270Sstevel@tonic-gate  */
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>
343247Sgjelinek #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 
529123Sjohn.levon@sun.com #include <langinfo.h>
530Sstevel@tonic-gate #include <libintl.h>
540Sstevel@tonic-gate #include <locale.h>
550Sstevel@tonic-gate 
560Sstevel@tonic-gate #include "prstat.h"
570Sstevel@tonic-gate #include "prutil.h"
580Sstevel@tonic-gate #include "prtable.h"
590Sstevel@tonic-gate #include "prsort.h"
600Sstevel@tonic-gate #include "prfile.h"
610Sstevel@tonic-gate 
620Sstevel@tonic-gate /*
630Sstevel@tonic-gate  * x86 <sys/regs.h> ERR conflicts with <curses.h> ERR.  For the purposes
640Sstevel@tonic-gate  * of this file, we care about the curses.h ERR so include that last.
650Sstevel@tonic-gate  */
660Sstevel@tonic-gate 
670Sstevel@tonic-gate #if	defined(ERR)
680Sstevel@tonic-gate #undef	ERR
690Sstevel@tonic-gate #endif
700Sstevel@tonic-gate 
710Sstevel@tonic-gate #ifndef	TEXT_DOMAIN			/* should be defined by cc -D */
720Sstevel@tonic-gate #define	TEXT_DOMAIN	"SYS_TEST"	/* use this only if it wasn't */
730Sstevel@tonic-gate #endif
740Sstevel@tonic-gate 
750Sstevel@tonic-gate #include <curses.h>
760Sstevel@tonic-gate #include <term.h>
770Sstevel@tonic-gate 
780Sstevel@tonic-gate #define	PSINFO_HEADER_PROC \
790Sstevel@tonic-gate "   PID USERNAME  SIZE   RSS STATE  PRI NICE      TIME  CPU PROCESS/NLWP       "
802685Sakolb #define	PSINFO_HEADER_PROC_LGRP \
812685Sakolb "   PID USERNAME  SIZE   RSS STATE  PRI NICE      TIME  CPU LGRP PROCESS/NLWP  "
820Sstevel@tonic-gate #define	PSINFO_HEADER_LWP \
830Sstevel@tonic-gate "   PID USERNAME  SIZE   RSS STATE  PRI NICE      TIME  CPU PROCESS/LWPID      "
842685Sakolb #define	PSINFO_HEADER_LWP_LGRP \
852685Sakolb "   PID USERNAME  SIZE   RSS STATE  PRI NICE      TIME  CPU LGRP PROCESS/LWPID "
860Sstevel@tonic-gate #define	USAGE_HEADER_PROC \
870Sstevel@tonic-gate "   PID USERNAME USR SYS TRP TFL DFL LCK SLP LAT VCX ICX SCL SIG PROCESS/NLWP  "
880Sstevel@tonic-gate #define	USAGE_HEADER_LWP \
890Sstevel@tonic-gate "   PID USERNAME USR SYS TRP TFL DFL LCK SLP LAT VCX ICX SCL SIG PROCESS/LWPID "
900Sstevel@tonic-gate #define	USER_HEADER_PROC \
913247Sgjelinek " NPROC USERNAME  SWAP   RSS MEMORY      TIME  CPU                             "
920Sstevel@tonic-gate #define	USER_HEADER_LWP \
933247Sgjelinek "  NLWP USERNAME  SWAP   RSS MEMORY      TIME  CPU                             "
940Sstevel@tonic-gate #define	TASK_HEADER_PROC \
953247Sgjelinek "TASKID    NPROC  SWAP   RSS MEMORY      TIME  CPU PROJECT                     "
960Sstevel@tonic-gate #define	TASK_HEADER_LWP \
973247Sgjelinek "TASKID     NLWP  SWAP   RSS MEMORY      TIME  CPU PROJECT                     "
980Sstevel@tonic-gate #define	PROJECT_HEADER_PROC \
993247Sgjelinek "PROJID    NPROC  SWAP   RSS MEMORY      TIME  CPU PROJECT                     "
1000Sstevel@tonic-gate #define	PROJECT_HEADER_LWP \
1013247Sgjelinek "PROJID     NLWP  SWAP   RSS MEMORY      TIME  CPU PROJECT                     "
1020Sstevel@tonic-gate #define	ZONE_HEADER_PROC \
1033247Sgjelinek "ZONEID    NPROC  SWAP   RSS MEMORY      TIME  CPU ZONE                        "
1040Sstevel@tonic-gate #define	ZONE_HEADER_LWP \
1053247Sgjelinek "ZONEID     NLWP  SWAP   RSS MEMORY      TIME  CPU ZONE                        "
1060Sstevel@tonic-gate #define	PSINFO_LINE \
1070Sstevel@tonic-gate "%6d %-8s %5s %5s %-6s %3s  %3s %9s %3.3s%% %-.16s/%d"
1082685Sakolb #define	PSINFO_LINE_LGRP \
1092685Sakolb "%6d %-8s %5s %5s %-6s %3s  %3s %9s %3.3s%% %4d %-.16s/%d"
1100Sstevel@tonic-gate #define	USAGE_LINE \
1110Sstevel@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 "\
1120Sstevel@tonic-gate "%3.3s %-.12s/%d"
1130Sstevel@tonic-gate #define	USER_LINE \
1140Sstevel@tonic-gate "%6d %-8s %5.5s %5.5s   %3.3s%% %9s %3.3s%%"
1150Sstevel@tonic-gate #define	TASK_LINE \
1160Sstevel@tonic-gate "%6d %8d %5s %5s   %3.3s%% %9s %3.3s%% %28s"
1170Sstevel@tonic-gate #define	PROJECT_LINE \
1180Sstevel@tonic-gate "%6d %8d %5s %5s   %3.3s%% %9s %3.3s%% %28s"
1190Sstevel@tonic-gate #define	ZONE_LINE \
1200Sstevel@tonic-gate "%6d %8d %5s %5s   %3.3s%% %9s %3.3s%% %28s"
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate #define	TOTAL_LINE \
1230Sstevel@tonic-gate "Total: %d processes, %d lwps, load averages: %3.2f, %3.2f, %3.2f"
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate /* global variables */
1260Sstevel@tonic-gate 
1270Sstevel@tonic-gate static char	*t_ulon;			/* termcap: start underline */
1280Sstevel@tonic-gate static char	*t_uloff;			/* termcap: end underline */
1290Sstevel@tonic-gate static char	*t_up;				/* termcap: cursor 1 line up */
1300Sstevel@tonic-gate static char	*t_eol;				/* termcap: clear end of line */
1310Sstevel@tonic-gate static char	*t_smcup;			/* termcap: cursor mvcap on */
1320Sstevel@tonic-gate static char	*t_rmcup;			/* termcap: cursor mvcap off */
1330Sstevel@tonic-gate static char	*t_home;			/* termcap: move cursor home */
1340Sstevel@tonic-gate static char	*movecur = NULL;		/* termcap: move up string */
1350Sstevel@tonic-gate static char	*empty_string = "\0";		/* termcap: empty string */
1360Sstevel@tonic-gate static uint_t	print_movecur = FALSE;		/* print movecur or not */
1370Sstevel@tonic-gate static int	is_curses_on = FALSE;		/* current curses state */
1380Sstevel@tonic-gate 
1390Sstevel@tonic-gate static table_t	pid_tbl = {0, 0, NULL};		/* selected processes */
1400Sstevel@tonic-gate static table_t	cpu_tbl = {0, 0, NULL};		/* selected processors */
1410Sstevel@tonic-gate static table_t  set_tbl = {0, 0, NULL};		/* selected processor sets */
1420Sstevel@tonic-gate static table_t	prj_tbl = {0, 0, NULL};		/* selected projects */
1430Sstevel@tonic-gate static table_t	tsk_tbl = {0, 0, NULL};		/* selected tasks */
1442685Sakolb static table_t	lgr_tbl = {0, 0, NULL};		/* selected lgroups */
1450Sstevel@tonic-gate static zonetbl_t zone_tbl = {0, 0, NULL};	/* selected zones */
146*9966SMenno.Lageman@Sun.COM static uidtbl_t euid_tbl = {0, 0, NULL}; 	/* selected effective users */
147*9966SMenno.Lageman@Sun.COM static uidtbl_t ruid_tbl = {0, 0, NULL}; 	/* selected real users */
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate static uint_t	total_procs;			/* total number of procs */
1500Sstevel@tonic-gate static uint_t	total_lwps;			/* total number of lwps */
1510Sstevel@tonic-gate static float	total_cpu;			/* total cpu usage */
1520Sstevel@tonic-gate static float	total_mem;			/* total memory usage */
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate static list_t	lwps;				/* list of lwps/processes */
1550Sstevel@tonic-gate static list_t	users;				/* list of users */
1560Sstevel@tonic-gate static list_t	tasks;				/* list of tasks */
1570Sstevel@tonic-gate static list_t	projects;			/* list of projects */
1580Sstevel@tonic-gate static list_t	zones;				/* list of zones */
1592685Sakolb static list_t	lgroups;			/* list of lgroups */
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate static volatile uint_t sigwinch = 0;
1620Sstevel@tonic-gate static volatile uint_t sigtstp = 0;
1630Sstevel@tonic-gate static volatile uint_t sigterm = 0;
1640Sstevel@tonic-gate 
1653247Sgjelinek static long pagesize;
1663247Sgjelinek 
1670Sstevel@tonic-gate /* default settings */
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate static optdesc_t opts = {
1700Sstevel@tonic-gate 	5,			/* interval between updates, seconds */
1710Sstevel@tonic-gate 	15,			/* number of lines in top part */
1720Sstevel@tonic-gate 	5,			/* number of lines in bottom part */
1730Sstevel@tonic-gate 	-1,			/* number of iterations; infinitely */
1740Sstevel@tonic-gate 	OPT_PSINFO | OPT_FULLSCREEN | OPT_USEHOME | OPT_TERMCAP,
1750Sstevel@tonic-gate 	-1			/* sort in decreasing order */
1760Sstevel@tonic-gate };
1770Sstevel@tonic-gate 
1789123Sjohn.levon@sun.com /*
1799123Sjohn.levon@sun.com  * Print timestamp as decimal reprentation of time_t value (-d u was specified)
1809123Sjohn.levon@sun.com  * or the standard date format (-d d was specified).
1819123Sjohn.levon@sun.com  */
1829123Sjohn.levon@sun.com static void
print_timestamp(void)1839123Sjohn.levon@sun.com print_timestamp(void)
1849123Sjohn.levon@sun.com {
1859123Sjohn.levon@sun.com 	time_t t = time(NULL);
1869123Sjohn.levon@sun.com 	static char *fmt = NULL;
1879123Sjohn.levon@sun.com 
1889123Sjohn.levon@sun.com 	/* We only need to retrieve this once per invocation */
1899123Sjohn.levon@sun.com 	if (fmt == NULL)
1909123Sjohn.levon@sun.com 		fmt = nl_langinfo(_DATE_FMT);
1919123Sjohn.levon@sun.com 
1929123Sjohn.levon@sun.com 	if (opts.o_outpmode & OPT_UDATE) {
1939123Sjohn.levon@sun.com 		(void) printf("%ld", t);
1949123Sjohn.levon@sun.com 	} else if (opts.o_outpmode & OPT_DDATE) {
1959123Sjohn.levon@sun.com 		char dstr[64];
1969123Sjohn.levon@sun.com 		int len;
1979123Sjohn.levon@sun.com 
1989123Sjohn.levon@sun.com 		len = strftime(dstr, sizeof (dstr), fmt, localtime(&t));
1999123Sjohn.levon@sun.com 		if (len > 0)
2009123Sjohn.levon@sun.com 			(void) printf("%s", dstr);
2019123Sjohn.levon@sun.com 	}
2029123Sjohn.levon@sun.com 	(void) putp(t_eol);
2039123Sjohn.levon@sun.com 	(void) putchar('\n');
2049123Sjohn.levon@sun.com }
2059123Sjohn.levon@sun.com 
2060Sstevel@tonic-gate static void
psetloadavg(long psetid,void * ptr)2070Sstevel@tonic-gate psetloadavg(long psetid, void *ptr)
2080Sstevel@tonic-gate {
2090Sstevel@tonic-gate 	double psetloadavg[3];
2100Sstevel@tonic-gate 	double *loadavg = ptr;
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate 	if (pset_getloadavg((psetid_t)psetid, psetloadavg, 3) != -1) {
2130Sstevel@tonic-gate 		*loadavg++ += psetloadavg[0];
2140Sstevel@tonic-gate 		*loadavg++ += psetloadavg[1];
2150Sstevel@tonic-gate 		*loadavg += psetloadavg[2];
2160Sstevel@tonic-gate 	}
2170Sstevel@tonic-gate }
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate /*
2203247Sgjelinek  * Queries the memory virtual and rss size for each member of a list.
2213247Sgjelinek  * This will override the values computed by /proc aggregation.
2223247Sgjelinek  */
2233247Sgjelinek static void
list_getsize(list_t * list)2243247Sgjelinek list_getsize(list_t *list)
2253247Sgjelinek {
2263247Sgjelinek 	id_info_t *id;
2273247Sgjelinek 	vmusage_t *results, *next;
2283247Sgjelinek 	vmusage_t *match;
2293247Sgjelinek 	size_t nres = 0;
2303247Sgjelinek 	size_t i;
2313247Sgjelinek 	uint_t flags = 0;
2323247Sgjelinek 	int ret;
2333247Sgjelinek 	size_t physmem = sysconf(_SC_PHYS_PAGES) * pagesize;
2343247Sgjelinek 
2353247Sgjelinek 	/*
2363247Sgjelinek 	 * Determine what swap/rss results to calculate.  getvmusage() will
2373247Sgjelinek 	 * prune results returned to non-global zones automatically, so
2383247Sgjelinek 	 * there is no need to pass different flags when calling from a
2393247Sgjelinek 	 * non-global zone.
2403247Sgjelinek 	 *
2413247Sgjelinek 	 * Currently list_getsize() is only called with a single flag.  This
2423247Sgjelinek 	 * is because -Z, -J, -T, and -a are mutually exclusive.  Regardless
2433247Sgjelinek 	 * of this, we handle multiple flags.
2443247Sgjelinek 	 */
2453247Sgjelinek 	if (opts.o_outpmode & OPT_USERS) {
2463247Sgjelinek 		/*
2473247Sgjelinek 		 * Gather rss for all users in all zones.  Treat the same
2483247Sgjelinek 		 * uid in different zones as the same user.
2493247Sgjelinek 		 */
2503247Sgjelinek 		flags |= VMUSAGE_COL_RUSERS;
2513247Sgjelinek 
2523247Sgjelinek 	} else if (opts.o_outpmode & OPT_TASKS) {
2533247Sgjelinek 		/* Gather rss for all tasks in all zones */
2543247Sgjelinek 		flags |= VMUSAGE_ALL_TASKS;
2553247Sgjelinek 
2563247Sgjelinek 	} else if (opts.o_outpmode & OPT_PROJECTS) {
2573247Sgjelinek 		/*
2583247Sgjelinek 		 * Gather rss for all projects in all zones.  Treat the same
2593247Sgjelinek 		 * projid in diffrent zones as the same project.
2603247Sgjelinek 		 */
2613247Sgjelinek 		flags |= VMUSAGE_COL_PROJECTS;
2623247Sgjelinek 
2633247Sgjelinek 	} else if (opts.o_outpmode & OPT_ZONES) {
2643247Sgjelinek 		/* Gather rss for all zones */
2653247Sgjelinek 		flags |= VMUSAGE_ALL_ZONES;
2663247Sgjelinek 
2673247Sgjelinek 	} else {
2683247Sgjelinek 		Die(gettext(
2693247Sgjelinek 		    "Cannot determine rss flags for output options %x\n"),
2703247Sgjelinek 		    opts.o_outpmode);
2713247Sgjelinek 	}
2723247Sgjelinek 
2733247Sgjelinek 	/*
2743247Sgjelinek 	 * getvmusage() returns an array of result structures.  One for
2753247Sgjelinek 	 * each zone, project, task, or user on the system, depending on
2763247Sgjelinek 	 * flags.
2773247Sgjelinek 	 *
2783247Sgjelinek 	 * If getvmusage() fails, prstat will use the size already gathered
2793247Sgjelinek 	 * from psinfo
2803247Sgjelinek 	 */
2813247Sgjelinek 	if (getvmusage(flags, opts.o_interval, NULL, &nres) != 0)
2823247Sgjelinek 		return;
2833247Sgjelinek 
2843247Sgjelinek 	results = (vmusage_t *)Malloc(sizeof (vmusage_t) * nres);
2853247Sgjelinek 	for (;;) {
2863247Sgjelinek 		ret = getvmusage(flags, opts.o_interval, results, &nres);
2873247Sgjelinek 		if (ret == 0)
2883247Sgjelinek 			break;
2893247Sgjelinek 		if (errno == EOVERFLOW) {
2903247Sgjelinek 			results = (vmusage_t *)Realloc(results,
2913247Sgjelinek 			    sizeof (vmusage_t) * nres);
2923247Sgjelinek 			continue;
2933247Sgjelinek 		}
2943247Sgjelinek 		/*
2953247Sgjelinek 		 * Failure for some other reason.  Prstat will use the size
2963247Sgjelinek 		 * already gathered from psinfo.
2973247Sgjelinek 		 */
2989524Sgerald.jelinek@sun.com 		free(results);
2993247Sgjelinek 		return;
3003247Sgjelinek 	}
3013247Sgjelinek 	for (id = list->l_head; id != NULL; id = id->id_next) {
3023247Sgjelinek 
3033247Sgjelinek 		match = NULL;
3043247Sgjelinek 		next = results;
3053247Sgjelinek 		for (i = 0; i < nres; i++, next++) {
3063247Sgjelinek 			switch (flags) {
3073247Sgjelinek 			case VMUSAGE_COL_RUSERS:
3083247Sgjelinek 				if (next->vmu_id == id->id_uid)
3093247Sgjelinek 					match = next;
3103247Sgjelinek 				break;
3113247Sgjelinek 			case VMUSAGE_ALL_TASKS:
3123247Sgjelinek 				if (next->vmu_id == id->id_taskid)
3133247Sgjelinek 					match = next;
3143247Sgjelinek 				break;
3153247Sgjelinek 			case VMUSAGE_COL_PROJECTS:
3163247Sgjelinek 				if (next->vmu_id == id->id_projid)
3173247Sgjelinek 					match = next;
3183247Sgjelinek 				break;
3193247Sgjelinek 			case VMUSAGE_ALL_ZONES:
3203247Sgjelinek 				if (next->vmu_id == id->id_zoneid)
3213247Sgjelinek 					match = next;
3223247Sgjelinek 				break;
3233247Sgjelinek 			default:
3243247Sgjelinek 				Die(gettext(
3253247Sgjelinek 				    "Unknown vmusage flags %d\n"), flags);
3263247Sgjelinek 			}
3273247Sgjelinek 		}
3283247Sgjelinek 		if (match != NULL) {
3293247Sgjelinek 			id->id_size = match->vmu_swap_all / 1024;
3303247Sgjelinek 			id->id_rssize = match->vmu_rss_all / 1024;
3313247Sgjelinek 			id->id_pctmem = (100.0 * (float)match->vmu_rss_all) /
3323247Sgjelinek 			    (float)physmem;
3333247Sgjelinek 			/* Output using data from getvmusage() */
3343247Sgjelinek 			id->id_sizematch = B_TRUE;
3353247Sgjelinek 		}
3363247Sgjelinek 		/*
3373247Sgjelinek 		 * If no match is found, prstat will use the size already
3383247Sgjelinek 		 * gathered from psinfo.
3393247Sgjelinek 		 */
3403247Sgjelinek 	}
3419524Sgerald.jelinek@sun.com 	free(results);
3423247Sgjelinek }
3433247Sgjelinek 
3443247Sgjelinek /*
3450Sstevel@tonic-gate  * A routine to display the contents of the list on the screen
3460Sstevel@tonic-gate  */
3470Sstevel@tonic-gate static void
list_print(list_t * list)3480Sstevel@tonic-gate list_print(list_t *list)
3490Sstevel@tonic-gate {
3500Sstevel@tonic-gate 	lwp_info_t *lwp;
3510Sstevel@tonic-gate 	id_info_t *id;
3520Sstevel@tonic-gate 	char usr[4], sys[4], trp[4], tfl[4];
3530Sstevel@tonic-gate 	char dfl[4], lck[4], slp[4], lat[4];
3540Sstevel@tonic-gate 	char vcx[4], icx[4], scl[4], sig[4];
3550Sstevel@tonic-gate 	char psize[6], prssize[6], pmem[6], pcpu[6], ptime[12];
3560Sstevel@tonic-gate 	char pstate[7], pnice[4], ppri[4];
3570Sstevel@tonic-gate 	char pname[LOGNAME_MAX+1];
3580Sstevel@tonic-gate 	char projname[PROJNAME_MAX+1];
3590Sstevel@tonic-gate 	char zonename[ZONENAME_MAX+1];
3600Sstevel@tonic-gate 	float cpu, mem;
3610Sstevel@tonic-gate 	double loadavg[3] = {0, 0, 0};
3620Sstevel@tonic-gate 	int i, lwpid;
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate 	if (foreach_element(&set_tbl, &loadavg, psetloadavg) == 0) {
3650Sstevel@tonic-gate 		/*
3660Sstevel@tonic-gate 		 * If processor sets aren't specified, we display system-wide
3670Sstevel@tonic-gate 		 * load averages.
3680Sstevel@tonic-gate 		 */
3690Sstevel@tonic-gate 		(void) getloadavg(loadavg, 3);
3700Sstevel@tonic-gate 	}
3710Sstevel@tonic-gate 
3729123Sjohn.levon@sun.com 	if (((opts.o_outpmode & OPT_UDATE) || (opts.o_outpmode & OPT_DDATE)) &&
3739123Sjohn.levon@sun.com 	    ((list->l_type == LT_LWPS) || !(opts.o_outpmode & OPT_SPLIT)))
3749123Sjohn.levon@sun.com 		print_timestamp();
3750Sstevel@tonic-gate 	if (opts.o_outpmode & OPT_TTY)
3760Sstevel@tonic-gate 		(void) putchar('\r');
3770Sstevel@tonic-gate 	(void) putp(t_ulon);
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate 	switch (list->l_type) {
3800Sstevel@tonic-gate 	case LT_PROJECTS:
3810Sstevel@tonic-gate 		if (opts.o_outpmode & OPT_LWPS)
3820Sstevel@tonic-gate 			(void) printf(PROJECT_HEADER_LWP);
3830Sstevel@tonic-gate 		else
3840Sstevel@tonic-gate 			(void) printf(PROJECT_HEADER_PROC);
3850Sstevel@tonic-gate 		break;
3860Sstevel@tonic-gate 	case LT_TASKS:
3870Sstevel@tonic-gate 		if (opts.o_outpmode & OPT_LWPS)
3880Sstevel@tonic-gate 			(void) printf(TASK_HEADER_LWP);
3890Sstevel@tonic-gate 		else
3900Sstevel@tonic-gate 			(void) printf(TASK_HEADER_PROC);
3910Sstevel@tonic-gate 		break;
3920Sstevel@tonic-gate 	case LT_ZONES:
3930Sstevel@tonic-gate 		if (opts.o_outpmode & OPT_LWPS)
3940Sstevel@tonic-gate 			(void) printf(ZONE_HEADER_LWP);
3950Sstevel@tonic-gate 		else
3960Sstevel@tonic-gate 			(void) printf(ZONE_HEADER_PROC);
3970Sstevel@tonic-gate 		break;
3980Sstevel@tonic-gate 	case LT_USERS:
3990Sstevel@tonic-gate 		if (opts.o_outpmode & OPT_LWPS)
4000Sstevel@tonic-gate 			(void) printf(USER_HEADER_LWP);
4010Sstevel@tonic-gate 		else
4020Sstevel@tonic-gate 			(void) printf(USER_HEADER_PROC);
4030Sstevel@tonic-gate 		break;
4040Sstevel@tonic-gate 	case LT_LWPS:
4050Sstevel@tonic-gate 		if (opts.o_outpmode & OPT_LWPS) {
4062685Sakolb 			if (opts.o_outpmode & OPT_PSINFO) {
4072685Sakolb 				if (opts.o_outpmode & OPT_LGRP)
4082685Sakolb 					(void) printf(PSINFO_HEADER_LWP_LGRP);
4092685Sakolb 				else
4102685Sakolb 					(void) printf(PSINFO_HEADER_LWP);
4112685Sakolb 			}
4120Sstevel@tonic-gate 			if (opts.o_outpmode & OPT_MSACCT)
4130Sstevel@tonic-gate 				(void) printf(USAGE_HEADER_LWP);
4140Sstevel@tonic-gate 		} else {
4152685Sakolb 			if (opts.o_outpmode & OPT_PSINFO) {
4162685Sakolb 				if (opts.o_outpmode & OPT_LGRP)
4172685Sakolb 					(void) printf(PSINFO_HEADER_PROC_LGRP);
4182685Sakolb 				else
4192685Sakolb 					(void) printf(PSINFO_HEADER_PROC);
4202685Sakolb 			}
4210Sstevel@tonic-gate 			if (opts.o_outpmode & OPT_MSACCT)
4220Sstevel@tonic-gate 				(void) printf(USAGE_HEADER_PROC);
4230Sstevel@tonic-gate 		}
4240Sstevel@tonic-gate 		break;
4250Sstevel@tonic-gate 	}
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate 	(void) putp(t_uloff);
4280Sstevel@tonic-gate 	(void) putp(t_eol);
4290Sstevel@tonic-gate 	(void) putchar('\n');
4300Sstevel@tonic-gate 
4310Sstevel@tonic-gate 	for (i = 0; i < list->l_used; i++) {
4320Sstevel@tonic-gate 		switch (list->l_type) {
4330Sstevel@tonic-gate 		case LT_PROJECTS:
4340Sstevel@tonic-gate 		case LT_TASKS:
4350Sstevel@tonic-gate 		case LT_USERS:
4360Sstevel@tonic-gate 		case LT_ZONES:
4370Sstevel@tonic-gate 			id = list->l_ptrs[i];
4380Sstevel@tonic-gate 			/*
4390Sstevel@tonic-gate 			 * CPU usage and memory usage normalization
4400Sstevel@tonic-gate 			 */
4410Sstevel@tonic-gate 			if (total_cpu >= 100)
4420Sstevel@tonic-gate 				cpu = (100 * id->id_pctcpu) / total_cpu;
4430Sstevel@tonic-gate 			else
4440Sstevel@tonic-gate 				cpu = id->id_pctcpu;
4453247Sgjelinek 			if (id->id_sizematch == B_FALSE && total_mem >= 100)
4460Sstevel@tonic-gate 				mem = (100 * id->id_pctmem) / total_mem;
4470Sstevel@tonic-gate 			else
4480Sstevel@tonic-gate 				mem = id->id_pctmem;
4490Sstevel@tonic-gate 			if (list->l_type == LT_USERS)
450*9966SMenno.Lageman@Sun.COM 				pwd_getname(id->id_uid, pname, LOGNAME_MAX + 1,
451*9966SMenno.Lageman@Sun.COM 				    opts.o_outpmode & OPT_NORESOLVE);
4520Sstevel@tonic-gate 			else if (list->l_type == LT_ZONES)
4530Sstevel@tonic-gate 				getzonename(id->id_zoneid, zonename,
4540Sstevel@tonic-gate 				    ZONENAME_MAX);
4550Sstevel@tonic-gate 			else
4560Sstevel@tonic-gate 				getprojname(id->id_projid, projname,
457*9966SMenno.Lageman@Sun.COM 				    PROJNAME_MAX,
458*9966SMenno.Lageman@Sun.COM 				    opts.o_outpmode & OPT_NORESOLVE);
4590Sstevel@tonic-gate 			Format_size(psize, id->id_size, 6);
4600Sstevel@tonic-gate 			Format_size(prssize, id->id_rssize, 6);
4610Sstevel@tonic-gate 			Format_pct(pmem, mem, 4);
4620Sstevel@tonic-gate 			Format_pct(pcpu, cpu, 4);
4630Sstevel@tonic-gate 			Format_time(ptime, id->id_time, 10);
4640Sstevel@tonic-gate 			if (opts.o_outpmode & OPT_TTY)
4650Sstevel@tonic-gate 				(void) putchar('\r');
4660Sstevel@tonic-gate 			if (list->l_type == LT_PROJECTS)
4670Sstevel@tonic-gate 				(void) printf(PROJECT_LINE, (int)id->id_projid,
4680Sstevel@tonic-gate 				    id->id_nproc, psize, prssize, pmem, ptime,
4690Sstevel@tonic-gate 				    pcpu, projname);
4700Sstevel@tonic-gate 			else if (list->l_type == LT_TASKS)
4710Sstevel@tonic-gate 				(void) printf(TASK_LINE, (int)id->id_taskid,
4720Sstevel@tonic-gate 				    id->id_nproc, psize, prssize, pmem, ptime,
4730Sstevel@tonic-gate 				    pcpu, projname);
4740Sstevel@tonic-gate 			else if (list->l_type == LT_ZONES)
4750Sstevel@tonic-gate 				(void) printf(ZONE_LINE, (int)id->id_zoneid,
4760Sstevel@tonic-gate 				    id->id_nproc, psize, prssize, pmem, ptime,
4770Sstevel@tonic-gate 				    pcpu, zonename);
4780Sstevel@tonic-gate 			else
4790Sstevel@tonic-gate 				(void) printf(USER_LINE, id->id_nproc, pname,
4800Sstevel@tonic-gate 				    psize, prssize, pmem, ptime, pcpu);
4810Sstevel@tonic-gate 			(void) putp(t_eol);
4820Sstevel@tonic-gate 			(void) putchar('\n');
4830Sstevel@tonic-gate 			break;
4840Sstevel@tonic-gate 		case LT_LWPS:
4850Sstevel@tonic-gate 			lwp = list->l_ptrs[i];
4860Sstevel@tonic-gate 			if (opts.o_outpmode & OPT_LWPS)
4870Sstevel@tonic-gate 				lwpid = lwp->li_info.pr_lwp.pr_lwpid;
4880Sstevel@tonic-gate 			else
4890Sstevel@tonic-gate 				lwpid = lwp->li_info.pr_nlwp +
4900Sstevel@tonic-gate 				    lwp->li_info.pr_nzomb;
491*9966SMenno.Lageman@Sun.COM 			pwd_getname(lwp->li_info.pr_uid, pname, LOGNAME_MAX + 1,
492*9966SMenno.Lageman@Sun.COM 			    opts.o_outpmode & OPT_NORESOLVE);
4930Sstevel@tonic-gate 			if (opts.o_outpmode & OPT_PSINFO) {
4940Sstevel@tonic-gate 				Format_size(psize, lwp->li_info.pr_size, 6);
4950Sstevel@tonic-gate 				Format_size(prssize, lwp->li_info.pr_rssize, 6);
4960Sstevel@tonic-gate 				Format_state(pstate,
4970Sstevel@tonic-gate 				    lwp->li_info.pr_lwp.pr_sname,
4980Sstevel@tonic-gate 				    lwp->li_info.pr_lwp.pr_onpro, 7);
4990Sstevel@tonic-gate 				if (strcmp(lwp->li_info.pr_lwp.pr_clname,
5000Sstevel@tonic-gate 				    "RT") == 0 ||
5010Sstevel@tonic-gate 				    strcmp(lwp->li_info.pr_lwp.pr_clname,
5020Sstevel@tonic-gate 				    "SYS") == 0 ||
5030Sstevel@tonic-gate 				    lwp->li_info.pr_lwp.pr_sname == 'Z')
5040Sstevel@tonic-gate 					(void) strcpy(pnice, "  -");
5050Sstevel@tonic-gate 				else
5060Sstevel@tonic-gate 					Format_num(pnice,
5070Sstevel@tonic-gate 					    lwp->li_info.pr_lwp.pr_nice - NZERO,
5080Sstevel@tonic-gate 					    4);
5090Sstevel@tonic-gate 				Format_num(ppri, lwp->li_info.pr_lwp.pr_pri, 4);
5100Sstevel@tonic-gate 				Format_pct(pcpu,
5110Sstevel@tonic-gate 				    FRC2PCT(lwp->li_info.pr_lwp.pr_pctcpu), 4);
5120Sstevel@tonic-gate 				if (opts.o_outpmode & OPT_LWPS)
5130Sstevel@tonic-gate 					Format_time(ptime,
5140Sstevel@tonic-gate 					    lwp->li_info.pr_lwp.pr_time.tv_sec,
5150Sstevel@tonic-gate 					    10);
5160Sstevel@tonic-gate 				else
5170Sstevel@tonic-gate 					Format_time(ptime,
5180Sstevel@tonic-gate 					    lwp->li_info.pr_time.tv_sec, 10);
5190Sstevel@tonic-gate 				if (opts.o_outpmode & OPT_TTY)
5200Sstevel@tonic-gate 					(void) putchar('\r');
5210Sstevel@tonic-gate 				stripfname(lwp->li_info.pr_fname);
5222685Sakolb 				if (opts.o_outpmode & OPT_LGRP) {
5232685Sakolb 					(void) printf(PSINFO_LINE_LGRP,
5242685Sakolb 					    (int)lwp->li_info.pr_pid, pname,
5252685Sakolb 					    psize, prssize, pstate, ppri, pnice,
5262685Sakolb 					    ptime, pcpu,
5272685Sakolb 					    (int)lwp->li_info.pr_lwp.pr_lgrp,
5282685Sakolb 					    lwp->li_info.pr_fname, lwpid);
5292685Sakolb 				} else {
5302685Sakolb 					(void) printf(PSINFO_LINE,
5312685Sakolb 					    (int)lwp->li_info.pr_pid, pname,
5322685Sakolb 					    psize, prssize, pstate, ppri, pnice,
5332685Sakolb 					    ptime, pcpu,
5342685Sakolb 					    lwp->li_info.pr_fname, lwpid);
5352685Sakolb 				}
5360Sstevel@tonic-gate 				(void) putp(t_eol);
5370Sstevel@tonic-gate 				(void) putchar('\n');
5380Sstevel@tonic-gate 			}
5390Sstevel@tonic-gate 			if (opts.o_outpmode & OPT_MSACCT) {
5400Sstevel@tonic-gate 				Format_pct(usr, lwp->li_usr, 4);
5410Sstevel@tonic-gate 				Format_pct(sys, lwp->li_sys, 4);
5420Sstevel@tonic-gate 				Format_pct(slp, lwp->li_slp, 4);
5430Sstevel@tonic-gate 				Format_num(vcx, lwp->li_vcx, 4);
5440Sstevel@tonic-gate 				Format_num(icx, lwp->li_icx, 4);
5450Sstevel@tonic-gate 				Format_num(scl, lwp->li_scl, 4);
5460Sstevel@tonic-gate 				Format_num(sig, lwp->li_sig, 4);
5470Sstevel@tonic-gate 				Format_pct(trp, lwp->li_trp, 4);
5480Sstevel@tonic-gate 				Format_pct(tfl, lwp->li_tfl, 4);
5490Sstevel@tonic-gate 				Format_pct(dfl, lwp->li_dfl, 4);
5500Sstevel@tonic-gate 				Format_pct(lck, lwp->li_lck, 4);
5510Sstevel@tonic-gate 				Format_pct(lat, lwp->li_lat, 4);
5520Sstevel@tonic-gate 				if (opts.o_outpmode & OPT_TTY)
5530Sstevel@tonic-gate 					(void) putchar('\r');
5540Sstevel@tonic-gate 				stripfname(lwp->li_info.pr_fname);
5550Sstevel@tonic-gate 				(void) printf(USAGE_LINE,
5560Sstevel@tonic-gate 				    (int)lwp->li_info.pr_pid, pname,
5570Sstevel@tonic-gate 				    usr, sys, trp, tfl, dfl, lck,
5580Sstevel@tonic-gate 				    slp, lat, vcx, icx, scl, sig,
5590Sstevel@tonic-gate 				    lwp->li_info.pr_fname, lwpid);
5600Sstevel@tonic-gate 				(void) putp(t_eol);
5610Sstevel@tonic-gate 				(void) putchar('\n');
5620Sstevel@tonic-gate 			}
5630Sstevel@tonic-gate 			break;
5640Sstevel@tonic-gate 		}
5650Sstevel@tonic-gate 	}
5660Sstevel@tonic-gate 
5670Sstevel@tonic-gate 	if (opts.o_outpmode & OPT_TTY)
5680Sstevel@tonic-gate 		(void) putchar('\r');
5690Sstevel@tonic-gate 	if (opts.o_outpmode & OPT_TERMCAP) {
5700Sstevel@tonic-gate 		switch (list->l_type) {
5710Sstevel@tonic-gate 		case LT_PROJECTS:
5720Sstevel@tonic-gate 		case LT_USERS:
5730Sstevel@tonic-gate 		case LT_TASKS:
5740Sstevel@tonic-gate 		case LT_ZONES:
5750Sstevel@tonic-gate 			while (i++ < opts.o_nbottom) {
5760Sstevel@tonic-gate 				(void) putp(t_eol);
5770Sstevel@tonic-gate 				(void) putchar('\n');
5780Sstevel@tonic-gate 			}
5790Sstevel@tonic-gate 			break;
5800Sstevel@tonic-gate 		case LT_LWPS:
5810Sstevel@tonic-gate 			while (i++ < opts.o_ntop) {
5820Sstevel@tonic-gate 				(void) putp(t_eol);
5830Sstevel@tonic-gate 				(void) putchar('\n');
5840Sstevel@tonic-gate 			}
5850Sstevel@tonic-gate 		}
5860Sstevel@tonic-gate 	}
5870Sstevel@tonic-gate 
5880Sstevel@tonic-gate 	if (opts.o_outpmode & OPT_TTY)
5890Sstevel@tonic-gate 		(void) putchar('\r');
5900Sstevel@tonic-gate 
5910Sstevel@tonic-gate 	if ((opts.o_outpmode & OPT_SPLIT) && list->l_type == LT_LWPS)
5920Sstevel@tonic-gate 		return;
5930Sstevel@tonic-gate 
5940Sstevel@tonic-gate 	(void) printf(TOTAL_LINE, total_procs, total_lwps,
5950Sstevel@tonic-gate 	    loadavg[LOADAVG_1MIN], loadavg[LOADAVG_5MIN],
5960Sstevel@tonic-gate 	    loadavg[LOADAVG_15MIN]);
5970Sstevel@tonic-gate 	(void) putp(t_eol);
5980Sstevel@tonic-gate 	(void) putchar('\n');
5990Sstevel@tonic-gate 	if (opts.o_outpmode & OPT_TTY)
6000Sstevel@tonic-gate 		(void) putchar('\r');
6010Sstevel@tonic-gate 	(void) putp(t_eol);
6020Sstevel@tonic-gate 	(void) fflush(stdout);
6030Sstevel@tonic-gate }
6040Sstevel@tonic-gate 
6050Sstevel@tonic-gate static lwp_info_t *
list_add_lwp(list_t * list,pid_t pid,id_t lwpid)6060Sstevel@tonic-gate list_add_lwp(list_t *list, pid_t pid, id_t lwpid)
6070Sstevel@tonic-gate {
6080Sstevel@tonic-gate 	lwp_info_t *lwp;
6090Sstevel@tonic-gate 
6100Sstevel@tonic-gate 	if (list->l_head == NULL) {
6110Sstevel@tonic-gate 		list->l_head = list->l_tail = lwp = Zalloc(sizeof (lwp_info_t));
6120Sstevel@tonic-gate 	} else {
6130Sstevel@tonic-gate 		lwp = Zalloc(sizeof (lwp_info_t));
6140Sstevel@tonic-gate 		lwp->li_prev = list->l_tail;
6150Sstevel@tonic-gate 		((lwp_info_t *)list->l_tail)->li_next = lwp;
6160Sstevel@tonic-gate 		list->l_tail = lwp;
6170Sstevel@tonic-gate 	}
6180Sstevel@tonic-gate 	lwp->li_info.pr_pid = pid;
6190Sstevel@tonic-gate 	lwp->li_info.pr_lwp.pr_lwpid = lwpid;
6200Sstevel@tonic-gate 	lwpid_add(lwp, pid, lwpid);
6210Sstevel@tonic-gate 	list->l_count++;
6220Sstevel@tonic-gate 	return (lwp);
6230Sstevel@tonic-gate }
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate static void
list_remove_lwp(list_t * list,lwp_info_t * lwp)6260Sstevel@tonic-gate list_remove_lwp(list_t *list, lwp_info_t *lwp)
6270Sstevel@tonic-gate {
6280Sstevel@tonic-gate 	if (lwp->li_prev)
6290Sstevel@tonic-gate 		lwp->li_prev->li_next = lwp->li_next;
6300Sstevel@tonic-gate 	else
6310Sstevel@tonic-gate 		list->l_head = lwp->li_next;	/* removing the head */
6320Sstevel@tonic-gate 	if (lwp->li_next)
6330Sstevel@tonic-gate 		lwp->li_next->li_prev = lwp->li_prev;
6340Sstevel@tonic-gate 	else
6350Sstevel@tonic-gate 		list->l_tail = lwp->li_prev;	/* removing the tail */
6360Sstevel@tonic-gate 	lwpid_del(lwp->li_info.pr_pid, lwp->li_info.pr_lwp.pr_lwpid);
6370Sstevel@tonic-gate 	if (lwpid_pidcheck(lwp->li_info.pr_pid) == 0)
6380Sstevel@tonic-gate 		fds_rm(lwp->li_info.pr_pid);
6390Sstevel@tonic-gate 	list->l_count--;
6400Sstevel@tonic-gate 	free(lwp);
6410Sstevel@tonic-gate }
6420Sstevel@tonic-gate 
6430Sstevel@tonic-gate static void
list_clear(list_t * list)6440Sstevel@tonic-gate list_clear(list_t *list)
6450Sstevel@tonic-gate {
6460Sstevel@tonic-gate 	if (list->l_type == LT_LWPS) {
6470Sstevel@tonic-gate 		lwp_info_t	*lwp = list->l_tail;
6480Sstevel@tonic-gate 		lwp_info_t	*lwp_tmp;
6490Sstevel@tonic-gate 
6500Sstevel@tonic-gate 		fd_closeall();
6510Sstevel@tonic-gate 		while (lwp) {
6520Sstevel@tonic-gate 			lwp_tmp = lwp;
6530Sstevel@tonic-gate 			lwp = lwp->li_prev;
6540Sstevel@tonic-gate 			list_remove_lwp(&lwps, lwp_tmp);
6550Sstevel@tonic-gate 		}
6560Sstevel@tonic-gate 	} else {
6570Sstevel@tonic-gate 		id_info_t *id = list->l_head;
6580Sstevel@tonic-gate 		id_info_t *nextid;
6590Sstevel@tonic-gate 
6600Sstevel@tonic-gate 		while (id) {
6610Sstevel@tonic-gate 			nextid = id->id_next;
6620Sstevel@tonic-gate 			free(id);
6630Sstevel@tonic-gate 			id = nextid;
6640Sstevel@tonic-gate 		}
6650Sstevel@tonic-gate 		list->l_count = 0;
6660Sstevel@tonic-gate 		list->l_head = list->l_tail = NULL;
6670Sstevel@tonic-gate 	}
6680Sstevel@tonic-gate }
6690Sstevel@tonic-gate 
6700Sstevel@tonic-gate static void
list_update(list_t * list,lwp_info_t * lwp)6710Sstevel@tonic-gate list_update(list_t *list, lwp_info_t *lwp)
6720Sstevel@tonic-gate {
6730Sstevel@tonic-gate 	id_info_t *id;
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 	if (list->l_head == NULL) {			/* first element */
6760Sstevel@tonic-gate 		list->l_head = list->l_tail = id = Zalloc(sizeof (id_info_t));
6770Sstevel@tonic-gate 		goto update;
6780Sstevel@tonic-gate 	}
6790Sstevel@tonic-gate 
6800Sstevel@tonic-gate 	for (id = list->l_head; id; id = id->id_next) {
6810Sstevel@tonic-gate 		if ((list->l_type == LT_USERS) &&
6820Sstevel@tonic-gate 		    (id->id_uid != lwp->li_info.pr_uid))
6830Sstevel@tonic-gate 			continue;
6840Sstevel@tonic-gate 		if ((list->l_type == LT_TASKS) &&
6850Sstevel@tonic-gate 		    (id->id_taskid != lwp->li_info.pr_taskid))
6860Sstevel@tonic-gate 			continue;
6870Sstevel@tonic-gate 		if ((list->l_type == LT_PROJECTS) &&
6880Sstevel@tonic-gate 		    (id->id_projid != lwp->li_info.pr_projid))
6890Sstevel@tonic-gate 			continue;
6900Sstevel@tonic-gate 		if ((list->l_type == LT_ZONES) &&
6910Sstevel@tonic-gate 		    (id->id_zoneid != lwp->li_info.pr_zoneid))
6920Sstevel@tonic-gate 			continue;
6932685Sakolb 		if ((list->l_type == LT_LGRPS) &&
6942685Sakolb 		    (id->id_lgroup != lwp->li_info.pr_lwp.pr_lgrp))
6952685Sakolb 			continue;
6960Sstevel@tonic-gate 		id->id_nproc++;
6970Sstevel@tonic-gate 		id->id_taskid	= lwp->li_info.pr_taskid;
6980Sstevel@tonic-gate 		id->id_projid	= lwp->li_info.pr_projid;
6990Sstevel@tonic-gate 		id->id_zoneid	= lwp->li_info.pr_zoneid;
7002685Sakolb 		id->id_lgroup	= lwp->li_info.pr_lwp.pr_lgrp;
7012685Sakolb 
7020Sstevel@tonic-gate 		if (lwp->li_flags & LWP_REPRESENT) {
7030Sstevel@tonic-gate 			id->id_size	+= lwp->li_info.pr_size;
7040Sstevel@tonic-gate 			id->id_rssize	+= lwp->li_info.pr_rssize;
7050Sstevel@tonic-gate 		}
7060Sstevel@tonic-gate 		id->id_pctcpu	+= FRC2PCT(lwp->li_info.pr_lwp.pr_pctcpu);
7070Sstevel@tonic-gate 		if (opts.o_outpmode & OPT_LWPS)
7080Sstevel@tonic-gate 			id->id_time += TIME2SEC(lwp->li_info.pr_lwp.pr_time);
7090Sstevel@tonic-gate 		else
7100Sstevel@tonic-gate 			id->id_time += TIME2SEC(lwp->li_info.pr_time);
7110Sstevel@tonic-gate 		id->id_pctmem	+= FRC2PCT(lwp->li_info.pr_pctmem);
7120Sstevel@tonic-gate 		id->id_key	+= lwp->li_key;
7130Sstevel@tonic-gate 		total_cpu	+= FRC2PCT(lwp->li_info.pr_lwp.pr_pctcpu);
7140Sstevel@tonic-gate 		total_mem	+= FRC2PCT(lwp->li_info.pr_pctmem);
7150Sstevel@tonic-gate 		return;
7160Sstevel@tonic-gate 	}
7170Sstevel@tonic-gate 
7180Sstevel@tonic-gate 	id = list->l_tail;
7190Sstevel@tonic-gate 	id->id_next = Zalloc(sizeof (id_info_t));
7200Sstevel@tonic-gate 	id->id_next->id_prev = list->l_tail;
7210Sstevel@tonic-gate 	id->id_next->id_next = NULL;
7220Sstevel@tonic-gate 	list->l_tail = id->id_next;
7230Sstevel@tonic-gate 	id = list->l_tail;
7240Sstevel@tonic-gate update:
7250Sstevel@tonic-gate 	id->id_uid	= lwp->li_info.pr_uid;
7260Sstevel@tonic-gate 	id->id_projid	= lwp->li_info.pr_projid;
7270Sstevel@tonic-gate 	id->id_taskid	= lwp->li_info.pr_taskid;
7280Sstevel@tonic-gate 	id->id_zoneid	= lwp->li_info.pr_zoneid;
7292685Sakolb 	id->id_lgroup	= lwp->li_info.pr_lwp.pr_lgrp;
7300Sstevel@tonic-gate 	id->id_nproc++;
7313247Sgjelinek 	id->id_sizematch = B_FALSE;
7320Sstevel@tonic-gate 	if (lwp->li_flags & LWP_REPRESENT) {
7330Sstevel@tonic-gate 		id->id_size	= lwp->li_info.pr_size;
7340Sstevel@tonic-gate 		id->id_rssize	= lwp->li_info.pr_rssize;
7350Sstevel@tonic-gate 	}
7360Sstevel@tonic-gate 	id->id_pctcpu	= FRC2PCT(lwp->li_info.pr_lwp.pr_pctcpu);
7370Sstevel@tonic-gate 	if (opts.o_outpmode & OPT_LWPS)
7380Sstevel@tonic-gate 		id->id_time = TIME2SEC(lwp->li_info.pr_lwp.pr_time);
7390Sstevel@tonic-gate 	else
7400Sstevel@tonic-gate 		id->id_time = TIME2SEC(lwp->li_info.pr_time);
7410Sstevel@tonic-gate 	id->id_pctmem	= FRC2PCT(lwp->li_info.pr_pctmem);
7420Sstevel@tonic-gate 	id->id_key	= lwp->li_key;
7430Sstevel@tonic-gate 	total_cpu	+= id->id_pctcpu;
7440Sstevel@tonic-gate 	total_mem	+= id->id_pctmem;
7450Sstevel@tonic-gate 	list->l_count++;
7460Sstevel@tonic-gate }
7470Sstevel@tonic-gate 
7480Sstevel@tonic-gate static void
lwp_update(lwp_info_t * lwp,pid_t pid,id_t lwpid,struct prusage * usage)7490Sstevel@tonic-gate lwp_update(lwp_info_t *lwp, pid_t pid, id_t lwpid, struct prusage *usage)
7500Sstevel@tonic-gate {
7510Sstevel@tonic-gate 	float period;
7520Sstevel@tonic-gate 
7530Sstevel@tonic-gate 	if (!lwpid_is_active(pid, lwpid)) {
7540Sstevel@tonic-gate 		/*
7550Sstevel@tonic-gate 		 * If we are reading cpu times for the first time then
7560Sstevel@tonic-gate 		 * calculate average cpu times based on whole process
7570Sstevel@tonic-gate 		 * execution time.
7580Sstevel@tonic-gate 		 */
7590Sstevel@tonic-gate 		(void) memcpy(&lwp->li_usage, usage, sizeof (prusage_t));
7600Sstevel@tonic-gate 		period = TIME2NSEC(usage->pr_rtime);
7610Sstevel@tonic-gate 		period = period/(float)100;
7620Sstevel@tonic-gate 
7630Sstevel@tonic-gate 		if (period == 0) { /* zombie */
7640Sstevel@tonic-gate 			period = 1;
7650Sstevel@tonic-gate 			lwp->li_usr = 0;
7660Sstevel@tonic-gate 			lwp->li_sys = 0;
7670Sstevel@tonic-gate 			lwp->li_slp = 0;
7680Sstevel@tonic-gate 		} else {
7690Sstevel@tonic-gate 			lwp->li_usr = TIME2NSEC(usage->pr_utime)/period;
7700Sstevel@tonic-gate 			lwp->li_sys = TIME2NSEC(usage->pr_stime)/period;
7710Sstevel@tonic-gate 			lwp->li_slp = TIME2NSEC(usage->pr_slptime)/period;
7720Sstevel@tonic-gate 		}
7730Sstevel@tonic-gate 		lwp->li_trp = TIME2NSEC(usage->pr_ttime)/period;
7740Sstevel@tonic-gate 		lwp->li_tfl = TIME2NSEC(usage->pr_tftime)/period;
7750Sstevel@tonic-gate 		lwp->li_dfl = TIME2NSEC(usage->pr_dftime)/period;
7760Sstevel@tonic-gate 		lwp->li_lck = TIME2NSEC(usage->pr_ltime)/period;
7770Sstevel@tonic-gate 		lwp->li_lat = TIME2NSEC(usage->pr_wtime)/period;
7780Sstevel@tonic-gate 		period = (period / NANOSEC)*(float)100; /* now in seconds */
7790Sstevel@tonic-gate 		lwp->li_vcx = (ulong_t)
7800Sstevel@tonic-gate 		    (opts.o_interval * (usage->pr_vctx/period));
7810Sstevel@tonic-gate 		lwp->li_icx = (ulong_t)
7820Sstevel@tonic-gate 		    (opts.o_interval * (usage->pr_ictx/period));
7830Sstevel@tonic-gate 		lwp->li_scl = (ulong_t)
7840Sstevel@tonic-gate 		    (opts.o_interval * (usage->pr_sysc/period));
7850Sstevel@tonic-gate 		lwp->li_sig = (ulong_t)
7860Sstevel@tonic-gate 		    (opts.o_interval * (usage->pr_sigs/period));
7870Sstevel@tonic-gate 		(void) lwpid_set_active(pid, lwpid);
7880Sstevel@tonic-gate 	} else {
7890Sstevel@tonic-gate 		/*
7900Sstevel@tonic-gate 		 * If this is not a first time we are reading a process's
7910Sstevel@tonic-gate 		 * CPU times then recalculate CPU times based on fresh data
7920Sstevel@tonic-gate 		 * obtained from procfs and previous CPU time usage values.
7930Sstevel@tonic-gate 		 */
7940Sstevel@tonic-gate 		period = TIME2NSEC(usage->pr_rtime)-
7950Sstevel@tonic-gate 		    TIME2NSEC(lwp->li_usage.pr_rtime);
7960Sstevel@tonic-gate 		period = period/(float)100;
7970Sstevel@tonic-gate 
7980Sstevel@tonic-gate 		if (period == 0) { /* zombie */
7990Sstevel@tonic-gate 			period = 1;
8000Sstevel@tonic-gate 			lwp->li_usr = 0;
8010Sstevel@tonic-gate 			lwp->li_sys = 0;
8020Sstevel@tonic-gate 			lwp->li_slp = 0;
8030Sstevel@tonic-gate 		} else {
8040Sstevel@tonic-gate 			lwp->li_usr = (TIME2NSEC(usage->pr_utime)-
8050Sstevel@tonic-gate 			    TIME2NSEC(lwp->li_usage.pr_utime))/period;
8060Sstevel@tonic-gate 			lwp->li_sys = (TIME2NSEC(usage->pr_stime) -
8070Sstevel@tonic-gate 			    TIME2NSEC(lwp->li_usage.pr_stime))/period;
8080Sstevel@tonic-gate 			lwp->li_slp = (TIME2NSEC(usage->pr_slptime) -
8090Sstevel@tonic-gate 			    TIME2NSEC(lwp->li_usage.pr_slptime))/period;
8100Sstevel@tonic-gate 		}
8110Sstevel@tonic-gate 		lwp->li_trp = (TIME2NSEC(usage->pr_ttime) -
8120Sstevel@tonic-gate 		    TIME2NSEC(lwp->li_usage.pr_ttime))/period;
8130Sstevel@tonic-gate 		lwp->li_tfl = (TIME2NSEC(usage->pr_tftime) -
8140Sstevel@tonic-gate 		    TIME2NSEC(lwp->li_usage.pr_tftime))/period;
8150Sstevel@tonic-gate 		lwp->li_dfl = (TIME2NSEC(usage->pr_dftime) -
8160Sstevel@tonic-gate 		    TIME2NSEC(lwp->li_usage.pr_dftime))/period;
8170Sstevel@tonic-gate 		lwp->li_lck = (TIME2NSEC(usage->pr_ltime) -
8180Sstevel@tonic-gate 		    TIME2NSEC(lwp->li_usage.pr_ltime))/period;
8190Sstevel@tonic-gate 		lwp->li_lat = (TIME2NSEC(usage->pr_wtime) -
8200Sstevel@tonic-gate 		    TIME2NSEC(lwp->li_usage.pr_wtime))/period;
8210Sstevel@tonic-gate 		lwp->li_vcx = usage->pr_vctx - lwp->li_usage.pr_vctx;
8220Sstevel@tonic-gate 		lwp->li_icx = usage->pr_ictx - lwp->li_usage.pr_ictx;
8230Sstevel@tonic-gate 		lwp->li_scl = usage->pr_sysc - lwp->li_usage.pr_sysc;
8240Sstevel@tonic-gate 		lwp->li_sig = usage->pr_sigs - lwp->li_usage.pr_sigs;
8250Sstevel@tonic-gate 		(void) memcpy(&lwp->li_usage, usage, sizeof (prusage_t));
8260Sstevel@tonic-gate 	}
8270Sstevel@tonic-gate }
8280Sstevel@tonic-gate 
8290Sstevel@tonic-gate static int
read_procfile(fd_t ** fd,char * pidstr,char * file,void * buf,size_t bufsize)8300Sstevel@tonic-gate read_procfile(fd_t **fd, char *pidstr, char *file, void *buf, size_t bufsize)
8310Sstevel@tonic-gate {
8320Sstevel@tonic-gate 	char procfile[MAX_PROCFS_PATH];
8330Sstevel@tonic-gate 
8340Sstevel@tonic-gate 	(void) snprintf(procfile, MAX_PROCFS_PATH,
8350Sstevel@tonic-gate 	    "/proc/%s/%s", pidstr, file);
8360Sstevel@tonic-gate 	if ((*fd = fd_open(procfile, O_RDONLY, *fd)) == NULL)
8370Sstevel@tonic-gate 		return (1);
8380Sstevel@tonic-gate 	if (pread(fd_getfd(*fd), buf, bufsize, 0) != bufsize) {
8390Sstevel@tonic-gate 		fd_close(*fd);
8400Sstevel@tonic-gate 		return (1);
8410Sstevel@tonic-gate 	}
8420Sstevel@tonic-gate 	return (0);
8430Sstevel@tonic-gate }
8440Sstevel@tonic-gate 
8450Sstevel@tonic-gate static void
add_proc(psinfo_t * psinfo)8460Sstevel@tonic-gate add_proc(psinfo_t *psinfo)
8470Sstevel@tonic-gate {
8480Sstevel@tonic-gate 	lwp_info_t *lwp;
8490Sstevel@tonic-gate 	id_t lwpid;
8500Sstevel@tonic-gate 	pid_t pid = psinfo->pr_pid;
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate 	lwpid = psinfo->pr_lwp.pr_lwpid;
8530Sstevel@tonic-gate 	if ((lwp = lwpid_get(pid, lwpid)) == NULL)
8540Sstevel@tonic-gate 		lwp = list_add_lwp(&lwps, pid, lwpid);
8550Sstevel@tonic-gate 	lwp->li_flags |= LWP_ALIVE | LWP_REPRESENT;
8560Sstevel@tonic-gate 	(void) memcpy(&lwp->li_info, psinfo, sizeof (psinfo_t));
8570Sstevel@tonic-gate 	lwp->li_info.pr_lwp.pr_pctcpu = lwp->li_info.pr_pctcpu;
8580Sstevel@tonic-gate }
8590Sstevel@tonic-gate 
8600Sstevel@tonic-gate static void
add_lwp(psinfo_t * psinfo,lwpsinfo_t * lwpsinfo,int flags)8610Sstevel@tonic-gate add_lwp(psinfo_t *psinfo, lwpsinfo_t *lwpsinfo, int flags)
8620Sstevel@tonic-gate {
8630Sstevel@tonic-gate 	lwp_info_t *lwp;
8640Sstevel@tonic-gate 	pid_t pid = psinfo->pr_pid;
8650Sstevel@tonic-gate 	id_t lwpid = lwpsinfo->pr_lwpid;
8660Sstevel@tonic-gate 
8670Sstevel@tonic-gate 	if ((lwp = lwpid_get(pid, lwpid)) == NULL)
8680Sstevel@tonic-gate 		lwp = list_add_lwp(&lwps, pid, lwpid);
8690Sstevel@tonic-gate 	lwp->li_flags &= ~LWP_REPRESENT;
8700Sstevel@tonic-gate 	lwp->li_flags |= LWP_ALIVE;
8710Sstevel@tonic-gate 	lwp->li_flags |= flags;
8720Sstevel@tonic-gate 	(void) memcpy(&lwp->li_info, psinfo,
8730Sstevel@tonic-gate 	    sizeof (psinfo_t) - sizeof (lwpsinfo_t));
8740Sstevel@tonic-gate 	(void) memcpy(&lwp->li_info.pr_lwp, lwpsinfo, sizeof (lwpsinfo_t));
8750Sstevel@tonic-gate }
8760Sstevel@tonic-gate 
8770Sstevel@tonic-gate static void
prstat_scandir(DIR * procdir)8780Sstevel@tonic-gate prstat_scandir(DIR *procdir)
8790Sstevel@tonic-gate {
8800Sstevel@tonic-gate 	char *pidstr;
8810Sstevel@tonic-gate 	pid_t pid;
8820Sstevel@tonic-gate 	id_t lwpid;
8830Sstevel@tonic-gate 	size_t entsz;
8840Sstevel@tonic-gate 	long nlwps, nent, i;
8850Sstevel@tonic-gate 	char *buf, *ptr;
8860Sstevel@tonic-gate 
8870Sstevel@tonic-gate 	fds_t *fds;
8880Sstevel@tonic-gate 	lwp_info_t *lwp;
8890Sstevel@tonic-gate 	dirent_t *direntp;
8900Sstevel@tonic-gate 
8910Sstevel@tonic-gate 	prheader_t	header;
8920Sstevel@tonic-gate 	psinfo_t	psinfo;
8930Sstevel@tonic-gate 	prusage_t	usage;
8940Sstevel@tonic-gate 	lwpsinfo_t	*lwpsinfo;
8950Sstevel@tonic-gate 	prusage_t	*lwpusage;
8960Sstevel@tonic-gate 
8970Sstevel@tonic-gate 	total_procs = 0;
8980Sstevel@tonic-gate 	total_lwps = 0;
8990Sstevel@tonic-gate 	total_cpu = 0;
9000Sstevel@tonic-gate 	total_mem = 0;
9010Sstevel@tonic-gate 
9020Sstevel@tonic-gate 	convert_zone(&zone_tbl);
9030Sstevel@tonic-gate 	for (rewinddir(procdir); (direntp = readdir(procdir)); ) {
9040Sstevel@tonic-gate 		pidstr = direntp->d_name;
9050Sstevel@tonic-gate 		if (pidstr[0] == '.')	/* skip "." and ".."  */
9060Sstevel@tonic-gate 			continue;
9070Sstevel@tonic-gate 		pid = atoi(pidstr);
9080Sstevel@tonic-gate 		if (pid == 0 || pid == 2 || pid == 3)
9090Sstevel@tonic-gate 			continue;	/* skip sched, pageout and fsflush */
9100Sstevel@tonic-gate 		if (has_element(&pid_tbl, pid) == 0)
9110Sstevel@tonic-gate 			continue;	/* check if we really want this pid */
9120Sstevel@tonic-gate 		fds = fds_get(pid);	/* get ptr to file descriptors */
9130Sstevel@tonic-gate 
9140Sstevel@tonic-gate 		if (read_procfile(&fds->fds_psinfo, pidstr,
9150Sstevel@tonic-gate 		    "psinfo", &psinfo, sizeof (psinfo_t)) != 0)
9160Sstevel@tonic-gate 			continue;
9170Sstevel@tonic-gate 		if (!has_uid(&ruid_tbl, psinfo.pr_uid) ||
9180Sstevel@tonic-gate 		    !has_uid(&euid_tbl, psinfo.pr_euid) ||
9190Sstevel@tonic-gate 		    !has_element(&prj_tbl, psinfo.pr_projid) ||
9200Sstevel@tonic-gate 		    !has_element(&tsk_tbl, psinfo.pr_taskid) ||
9210Sstevel@tonic-gate 		    !has_zone(&zone_tbl, psinfo.pr_zoneid)) {
9220Sstevel@tonic-gate 			fd_close(fds->fds_psinfo);
9230Sstevel@tonic-gate 			continue;
9240Sstevel@tonic-gate 		}
9250Sstevel@tonic-gate 		nlwps = psinfo.pr_nlwp + psinfo.pr_nzomb;
9260Sstevel@tonic-gate 
9270Sstevel@tonic-gate 		if (nlwps > 1 && (opts.o_outpmode & (OPT_LWPS | OPT_PSETS))) {
9280Sstevel@tonic-gate 			int rep_lwp = 0;
9290Sstevel@tonic-gate 
9300Sstevel@tonic-gate 			if (read_procfile(&fds->fds_lpsinfo, pidstr, "lpsinfo",
9310Sstevel@tonic-gate 			    &header, sizeof (prheader_t)) != 0) {
9320Sstevel@tonic-gate 				fd_close(fds->fds_psinfo);
9330Sstevel@tonic-gate 				continue;
9340Sstevel@tonic-gate 			}
9350Sstevel@tonic-gate 
9360Sstevel@tonic-gate 			nent = header.pr_nent;
9370Sstevel@tonic-gate 			entsz = header.pr_entsize * nent;
9380Sstevel@tonic-gate 			ptr = buf = Malloc(entsz);
9390Sstevel@tonic-gate 			if (pread(fd_getfd(fds->fds_lpsinfo), buf,
9400Sstevel@tonic-gate 			    entsz, sizeof (struct prheader)) != entsz) {
9410Sstevel@tonic-gate 				fd_close(fds->fds_lpsinfo);
9420Sstevel@tonic-gate 				fd_close(fds->fds_psinfo);
9430Sstevel@tonic-gate 				free(buf);
9440Sstevel@tonic-gate 				continue;
9450Sstevel@tonic-gate 			}
9460Sstevel@tonic-gate 
9470Sstevel@tonic-gate 			nlwps = 0;
9480Sstevel@tonic-gate 			for (i = 0; i < nent; i++, ptr += header.pr_entsize) {
9490Sstevel@tonic-gate 				/*LINTED ALIGNMENT*/
9500Sstevel@tonic-gate 				lwpsinfo = (lwpsinfo_t *)ptr;
9510Sstevel@tonic-gate 				if (!has_element(&cpu_tbl,
9520Sstevel@tonic-gate 				    lwpsinfo->pr_onpro) ||
9530Sstevel@tonic-gate 				    !has_element(&set_tbl,
9542685Sakolb 				    lwpsinfo->pr_bindpset) ||
9559123Sjohn.levon@sun.com 				    !has_element(&lgr_tbl, lwpsinfo->pr_lgrp))
9560Sstevel@tonic-gate 					continue;
9570Sstevel@tonic-gate 				nlwps++;
9580Sstevel@tonic-gate 				if ((opts.o_outpmode & (OPT_PSETS | OPT_LWPS))
9590Sstevel@tonic-gate 				    == OPT_PSETS) {
9600Sstevel@tonic-gate 					/*
9610Sstevel@tonic-gate 					 * If one of process's LWPs is bound
9620Sstevel@tonic-gate 					 * to a given processor set, report the
9630Sstevel@tonic-gate 					 * whole process.  We may be doing this
9640Sstevel@tonic-gate 					 * a few times but we'll get an accurate
9650Sstevel@tonic-gate 					 * lwp count in return.
9660Sstevel@tonic-gate 					 */
9670Sstevel@tonic-gate 					add_proc(&psinfo);
9680Sstevel@tonic-gate 				} else {
9690Sstevel@tonic-gate 					if (rep_lwp == 0) {
9700Sstevel@tonic-gate 						rep_lwp = 1;
9710Sstevel@tonic-gate 						add_lwp(&psinfo, lwpsinfo,
9720Sstevel@tonic-gate 						    LWP_REPRESENT);
9730Sstevel@tonic-gate 					} else {
9740Sstevel@tonic-gate 						add_lwp(&psinfo, lwpsinfo, 0);
9750Sstevel@tonic-gate 					}
9760Sstevel@tonic-gate 				}
9770Sstevel@tonic-gate 			}
9780Sstevel@tonic-gate 			free(buf);
9790Sstevel@tonic-gate 			if (nlwps == 0) {
9800Sstevel@tonic-gate 				fd_close(fds->fds_lpsinfo);
9810Sstevel@tonic-gate 				fd_close(fds->fds_psinfo);
9820Sstevel@tonic-gate 				continue;
9830Sstevel@tonic-gate 			}
9840Sstevel@tonic-gate 		} else {
9850Sstevel@tonic-gate 			if (!has_element(&cpu_tbl, psinfo.pr_lwp.pr_onpro) ||
9862685Sakolb 			    !has_element(&set_tbl, psinfo.pr_lwp.pr_bindpset) ||
9872685Sakolb 			    !has_element(&lgr_tbl, psinfo.pr_lwp.pr_lgrp)) {
9880Sstevel@tonic-gate 				fd_close(fds->fds_psinfo);
9890Sstevel@tonic-gate 				continue;
9900Sstevel@tonic-gate 			}
9910Sstevel@tonic-gate 			add_proc(&psinfo);
9920Sstevel@tonic-gate 		}
9930Sstevel@tonic-gate 		if (!(opts.o_outpmode & OPT_MSACCT)) {
9940Sstevel@tonic-gate 			total_procs++;
9950Sstevel@tonic-gate 			total_lwps += nlwps;
9960Sstevel@tonic-gate 			continue;
9970Sstevel@tonic-gate 		}
9980Sstevel@tonic-gate 		/*
9990Sstevel@tonic-gate 		 * Get more information about processes from /proc/pid/usage.
10000Sstevel@tonic-gate 		 * If process has more than one lwp, then we may have to
10010Sstevel@tonic-gate 		 * also look at the /proc/pid/lusage file.
10020Sstevel@tonic-gate 		 */
10030Sstevel@tonic-gate 		if ((opts.o_outpmode & OPT_LWPS) && (nlwps > 1)) {
10040Sstevel@tonic-gate 			if (read_procfile(&fds->fds_lusage, pidstr, "lusage",
10050Sstevel@tonic-gate 			    &header, sizeof (prheader_t)) != 0) {
10060Sstevel@tonic-gate 				fd_close(fds->fds_lpsinfo);
10070Sstevel@tonic-gate 				fd_close(fds->fds_psinfo);
10080Sstevel@tonic-gate 				continue;
10090Sstevel@tonic-gate 			}
10100Sstevel@tonic-gate 			nent = header.pr_nent;
10110Sstevel@tonic-gate 			entsz = header.pr_entsize * nent;
10120Sstevel@tonic-gate 			buf = Malloc(entsz);
10130Sstevel@tonic-gate 			if (pread(fd_getfd(fds->fds_lusage), buf,
10140Sstevel@tonic-gate 			    entsz, sizeof (struct prheader)) != entsz) {
10150Sstevel@tonic-gate 				fd_close(fds->fds_lusage);
10160Sstevel@tonic-gate 				fd_close(fds->fds_lpsinfo);
10170Sstevel@tonic-gate 				fd_close(fds->fds_psinfo);
10180Sstevel@tonic-gate 				free(buf);
10190Sstevel@tonic-gate 				continue;
10200Sstevel@tonic-gate 			}
10210Sstevel@tonic-gate 			for (i = 1, ptr = buf + header.pr_entsize; i < nent;
10220Sstevel@tonic-gate 			    i++, ptr += header.pr_entsize) {
10230Sstevel@tonic-gate 				/*LINTED ALIGNMENT*/
10240Sstevel@tonic-gate 				lwpusage = (prusage_t *)ptr;
10250Sstevel@tonic-gate 				lwpid = lwpusage->pr_lwpid;
10260Sstevel@tonic-gate 				/*
10270Sstevel@tonic-gate 				 * New LWPs created after we read lpsinfo
10280Sstevel@tonic-gate 				 * will be ignored.  Don't want to do
10290Sstevel@tonic-gate 				 * everything all over again.
10300Sstevel@tonic-gate 				 */
10310Sstevel@tonic-gate 				if ((lwp = lwpid_get(pid, lwpid)) == NULL)
10320Sstevel@tonic-gate 					continue;
10330Sstevel@tonic-gate 				lwp_update(lwp, pid, lwpid, lwpusage);
10340Sstevel@tonic-gate 			}
10350Sstevel@tonic-gate 			free(buf);
10360Sstevel@tonic-gate 		} else {
10370Sstevel@tonic-gate 			if (read_procfile(&fds->fds_usage, pidstr, "usage",
10380Sstevel@tonic-gate 			    &usage, sizeof (prusage_t)) != 0) {
10390Sstevel@tonic-gate 				fd_close(fds->fds_lpsinfo);
10400Sstevel@tonic-gate 				fd_close(fds->fds_psinfo);
10410Sstevel@tonic-gate 				continue;
10420Sstevel@tonic-gate 			}
10430Sstevel@tonic-gate 			lwpid = psinfo.pr_lwp.pr_lwpid;
10440Sstevel@tonic-gate 			if ((lwp = lwpid_get(pid, lwpid)) == NULL)
10450Sstevel@tonic-gate 				continue;
10460Sstevel@tonic-gate 			lwp_update(lwp, pid, lwpid, &usage);
10470Sstevel@tonic-gate 		}
10480Sstevel@tonic-gate 		total_procs++;
10490Sstevel@tonic-gate 		total_lwps += nlwps;
10500Sstevel@tonic-gate 	}
10510Sstevel@tonic-gate 	fd_update();
10520Sstevel@tonic-gate }
10530Sstevel@tonic-gate 
10540Sstevel@tonic-gate /*
10550Sstevel@tonic-gate  * This procedure removes all dead lwps from the linked list of all lwps.
10560Sstevel@tonic-gate  * It also creates linked list of ids if necessary.
10570Sstevel@tonic-gate  */
10580Sstevel@tonic-gate static void
list_refresh(list_t * list)10590Sstevel@tonic-gate list_refresh(list_t *list)
10600Sstevel@tonic-gate {
10610Sstevel@tonic-gate 	lwp_info_t *lwp, *lwp_next;
10620Sstevel@tonic-gate 
10630Sstevel@tonic-gate 	if (!(list->l_type & LT_LWPS))
10640Sstevel@tonic-gate 		return;
10650Sstevel@tonic-gate 
10660Sstevel@tonic-gate 	for (lwp = list->l_head; lwp != NULL; ) {
10670Sstevel@tonic-gate 		if (lwp->li_flags & LWP_ALIVE) {
10680Sstevel@tonic-gate 			/*
10690Sstevel@tonic-gate 			 * Process all live LWPs.
10700Sstevel@tonic-gate 			 * When we're done, mark them as dead.
10710Sstevel@tonic-gate 			 * They will be marked "alive" on the next
10720Sstevel@tonic-gate 			 * /proc scan if they still exist.
10730Sstevel@tonic-gate 			 */
10740Sstevel@tonic-gate 			lwp->li_key = list_getkeyval(list, lwp);
10750Sstevel@tonic-gate 			if (opts.o_outpmode & OPT_USERS)
10760Sstevel@tonic-gate 				list_update(&users, lwp);
10770Sstevel@tonic-gate 			if (opts.o_outpmode & OPT_TASKS)
10780Sstevel@tonic-gate 				list_update(&tasks, lwp);
10790Sstevel@tonic-gate 			if (opts.o_outpmode & OPT_PROJECTS)
10800Sstevel@tonic-gate 				list_update(&projects, lwp);
10810Sstevel@tonic-gate 			if (opts.o_outpmode & OPT_ZONES)
10820Sstevel@tonic-gate 				list_update(&zones, lwp);
10832685Sakolb 			if (opts.o_outpmode & OPT_LGRP)
10842685Sakolb 				list_update(&lgroups, lwp);
10850Sstevel@tonic-gate 			lwp->li_flags &= ~LWP_ALIVE;
10860Sstevel@tonic-gate 			lwp = lwp->li_next;
10870Sstevel@tonic-gate 
10880Sstevel@tonic-gate 		} else {
10890Sstevel@tonic-gate 			lwp_next = lwp->li_next;
10900Sstevel@tonic-gate 			list_remove_lwp(&lwps, lwp);
10910Sstevel@tonic-gate 			lwp = lwp_next;
10920Sstevel@tonic-gate 		}
10930Sstevel@tonic-gate 	}
10940Sstevel@tonic-gate }
10950Sstevel@tonic-gate 
10960Sstevel@tonic-gate static void
curses_on()10970Sstevel@tonic-gate curses_on()
10980Sstevel@tonic-gate {
10990Sstevel@tonic-gate 	if ((opts.o_outpmode & OPT_TERMCAP) && (is_curses_on == FALSE)) {
11000Sstevel@tonic-gate 		(void) initscr();
11010Sstevel@tonic-gate 		(void) nonl();
11020Sstevel@tonic-gate 		(void) putp(t_smcup);
11030Sstevel@tonic-gate 		is_curses_on = TRUE;
11040Sstevel@tonic-gate 	}
11050Sstevel@tonic-gate }
11060Sstevel@tonic-gate 
11070Sstevel@tonic-gate static void
curses_off()11080Sstevel@tonic-gate curses_off()
11090Sstevel@tonic-gate {
11100Sstevel@tonic-gate 	if ((is_curses_on == TRUE) && (opts.o_outpmode & OPT_TERMCAP)) {
11110Sstevel@tonic-gate 		(void) putp(t_rmcup);
11120Sstevel@tonic-gate 		(void) endwin();
11130Sstevel@tonic-gate 		is_curses_on = FALSE;
11140Sstevel@tonic-gate 	}
11150Sstevel@tonic-gate 	(void) fflush(stdout);
11160Sstevel@tonic-gate }
11170Sstevel@tonic-gate 
11180Sstevel@tonic-gate static int
nlines()11190Sstevel@tonic-gate nlines()
11200Sstevel@tonic-gate {
11210Sstevel@tonic-gate 	struct winsize ws;
11220Sstevel@tonic-gate 	char *envp;
11230Sstevel@tonic-gate 	int n;
11240Sstevel@tonic-gate 	if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != -1) {
11250Sstevel@tonic-gate 		if (ws.ws_row > 0)
11260Sstevel@tonic-gate 			return (ws.ws_row);
11270Sstevel@tonic-gate 	}
11280Sstevel@tonic-gate 	if (envp = getenv("LINES")) {
11290Sstevel@tonic-gate 		if ((n = Atoi(envp)) > 0) {
11300Sstevel@tonic-gate 			opts.o_outpmode &= ~OPT_USEHOME;
11310Sstevel@tonic-gate 			return (n);
11320Sstevel@tonic-gate 		}
11330Sstevel@tonic-gate 	}
11340Sstevel@tonic-gate 	return (-1);
11350Sstevel@tonic-gate }
11360Sstevel@tonic-gate 
11370Sstevel@tonic-gate static void
setmovecur()11380Sstevel@tonic-gate setmovecur()
11390Sstevel@tonic-gate {
11400Sstevel@tonic-gate 	int i, n;
11410Sstevel@tonic-gate 	if ((opts.o_outpmode & OPT_FULLSCREEN) &&
11420Sstevel@tonic-gate 	    (opts.o_outpmode & OPT_USEHOME)) {
11430Sstevel@tonic-gate 		movecur = t_home;
11440Sstevel@tonic-gate 		return;
11450Sstevel@tonic-gate 	}
11460Sstevel@tonic-gate 	if (opts.o_outpmode & OPT_SPLIT) {
11470Sstevel@tonic-gate 		n = opts.o_ntop + opts.o_nbottom + 2;
11480Sstevel@tonic-gate 	} else {
11490Sstevel@tonic-gate 		if (opts.o_outpmode & OPT_USERS)
11500Sstevel@tonic-gate 			n = opts.o_nbottom + 1;
11510Sstevel@tonic-gate 		else
11520Sstevel@tonic-gate 			n = opts.o_ntop + 1;
11530Sstevel@tonic-gate 	}
11549123Sjohn.levon@sun.com 	if (((opts.o_outpmode & OPT_UDATE) || (opts.o_outpmode & OPT_DDATE)))
11559123Sjohn.levon@sun.com 		n++;
11569123Sjohn.levon@sun.com 
11570Sstevel@tonic-gate 	if (movecur != NULL && movecur != empty_string && movecur != t_home)
11580Sstevel@tonic-gate 		free(movecur);
11590Sstevel@tonic-gate 	movecur = Zalloc(strlen(t_up) * (n + 5));
11600Sstevel@tonic-gate 	for (i = 0; i <= n; i++)
11610Sstevel@tonic-gate 		(void) strcat(movecur, t_up);
11620Sstevel@tonic-gate }
11630Sstevel@tonic-gate 
11640Sstevel@tonic-gate static int
setsize()11650Sstevel@tonic-gate setsize()
11660Sstevel@tonic-gate {
11670Sstevel@tonic-gate 	static int oldn = 0;
11680Sstevel@tonic-gate 	int n;
11690Sstevel@tonic-gate 
11700Sstevel@tonic-gate 	if (opts.o_outpmode & OPT_FULLSCREEN) {
11710Sstevel@tonic-gate 		n = nlines();
11720Sstevel@tonic-gate 		if (n == oldn)
11730Sstevel@tonic-gate 			return (0);
11740Sstevel@tonic-gate 		oldn = n;
11750Sstevel@tonic-gate 		if (n == -1) {
11760Sstevel@tonic-gate 			opts.o_outpmode &= ~OPT_USEHOME;
11770Sstevel@tonic-gate 			setmovecur();		/* set default window size */
11780Sstevel@tonic-gate 			return (1);
11790Sstevel@tonic-gate 		}
11800Sstevel@tonic-gate 		n = n - 3;	/* minus header, total and cursor lines */
11819123Sjohn.levon@sun.com 		if ((opts.o_outpmode & OPT_UDATE) ||
11829123Sjohn.levon@sun.com 		    (opts.o_outpmode & OPT_DDATE))
11839123Sjohn.levon@sun.com 			n--;	/* minus timestamp */
11840Sstevel@tonic-gate 		if (n < 1)
11850Sstevel@tonic-gate 			Die(gettext("window is too small (try -n)\n"));
11860Sstevel@tonic-gate 		if (opts.o_outpmode & OPT_SPLIT) {
11870Sstevel@tonic-gate 			if (n < 8) {
11880Sstevel@tonic-gate 				Die(gettext("window is too small (try -n)\n"));
11890Sstevel@tonic-gate 			} else {
11900Sstevel@tonic-gate 				opts.o_ntop = (n / 4) * 3;
11910Sstevel@tonic-gate 				opts.o_nbottom = n - 1 - opts.o_ntop;
11920Sstevel@tonic-gate 			}
11930Sstevel@tonic-gate 		} else {
11940Sstevel@tonic-gate 			if (opts.o_outpmode & OPT_USERS)
11950Sstevel@tonic-gate 				opts.o_nbottom = n;
11960Sstevel@tonic-gate 			else
11970Sstevel@tonic-gate 				opts.o_ntop = n;
11980Sstevel@tonic-gate 		}
11990Sstevel@tonic-gate 	}
12000Sstevel@tonic-gate 	setmovecur();
12010Sstevel@tonic-gate 	return (1);
12020Sstevel@tonic-gate }
12030Sstevel@tonic-gate 
12040Sstevel@tonic-gate static void
ldtermcap()12050Sstevel@tonic-gate ldtermcap()
12060Sstevel@tonic-gate {
12070Sstevel@tonic-gate 	int err;
12080Sstevel@tonic-gate 	if (setupterm(NULL, STDIN_FILENO, &err) == ERR) {
12090Sstevel@tonic-gate 		switch (err) {
12100Sstevel@tonic-gate 		case 0:
12110Sstevel@tonic-gate 			Warn(gettext("failed to load terminal info, "
12120Sstevel@tonic-gate 			    "defaulting to -c option\n"));
12130Sstevel@tonic-gate 			break;
12140Sstevel@tonic-gate 		case -1:
12150Sstevel@tonic-gate 			Warn(gettext("terminfo database not found, "
12160Sstevel@tonic-gate 			    "defaulting to -c option\n"));
12170Sstevel@tonic-gate 			break;
12180Sstevel@tonic-gate 		default:
12190Sstevel@tonic-gate 			Warn(gettext("failed to initialize terminal, "
12200Sstevel@tonic-gate 			    "defaulting to -c option\n"));
12210Sstevel@tonic-gate 		}
12220Sstevel@tonic-gate 		opts.o_outpmode &= ~OPT_TERMCAP;
12230Sstevel@tonic-gate 		t_up = t_eol = t_smcup = t_rmcup = movecur = empty_string;
12240Sstevel@tonic-gate 		t_ulon = t_uloff = empty_string;
12250Sstevel@tonic-gate 		return;
12260Sstevel@tonic-gate 	}
12270Sstevel@tonic-gate 	t_ulon	= tigetstr("smul");
12280Sstevel@tonic-gate 	t_uloff	= tigetstr("rmul");
12290Sstevel@tonic-gate 	t_up	= tigetstr("cuu1");
12300Sstevel@tonic-gate 	t_eol	= tigetstr("el");
12310Sstevel@tonic-gate 	t_smcup	= tigetstr("smcup");
12320Sstevel@tonic-gate 	t_rmcup = tigetstr("rmcup");
12330Sstevel@tonic-gate 	t_home  = tigetstr("home");
12340Sstevel@tonic-gate 	if ((t_up == (char *)-1) || (t_eol == (char *)-1) ||
12350Sstevel@tonic-gate 	    (t_smcup == (char *)-1) || (t_rmcup == (char *)-1)) {
12360Sstevel@tonic-gate 		opts.o_outpmode &= ~OPT_TERMCAP;
12370Sstevel@tonic-gate 		t_up = t_eol = t_smcup = t_rmcup = movecur = empty_string;
12380Sstevel@tonic-gate 		return;
12390Sstevel@tonic-gate 	}
12400Sstevel@tonic-gate 	if (t_up == NULL || t_eol == NULL) {
12410Sstevel@tonic-gate 		opts.o_outpmode &= ~OPT_TERMCAP;
12420Sstevel@tonic-gate 		t_eol = t_up = movecur = empty_string;
12430Sstevel@tonic-gate 		return;
12440Sstevel@tonic-gate 	}
12450Sstevel@tonic-gate 	if (t_ulon == (char *)-1 || t_uloff == (char *)-1 ||
12460Sstevel@tonic-gate 	    t_ulon == NULL || t_uloff == NULL) {
12470Sstevel@tonic-gate 		t_ulon = t_uloff = empty_string;  /* can live without it */
12480Sstevel@tonic-gate 	}
12490Sstevel@tonic-gate 	if (t_smcup == NULL || t_rmcup == NULL)
12500Sstevel@tonic-gate 		t_smcup = t_rmcup = empty_string;
12510Sstevel@tonic-gate 	if (t_home == (char *)-1 || t_home == NULL) {
12520Sstevel@tonic-gate 		opts.o_outpmode &= ~OPT_USEHOME;
12530Sstevel@tonic-gate 		t_home = empty_string;
12540Sstevel@tonic-gate 	}
12550Sstevel@tonic-gate }
12560Sstevel@tonic-gate 
12570Sstevel@tonic-gate static void
sig_handler(int sig)12580Sstevel@tonic-gate sig_handler(int sig)
12590Sstevel@tonic-gate {
12600Sstevel@tonic-gate 	switch (sig) {
12610Sstevel@tonic-gate 	case SIGTSTP:	sigtstp = 1;
12620Sstevel@tonic-gate 			break;
12630Sstevel@tonic-gate 	case SIGWINCH:	sigwinch = 1;
12640Sstevel@tonic-gate 			break;
12650Sstevel@tonic-gate 	case SIGINT:
12660Sstevel@tonic-gate 	case SIGTERM:	sigterm = 1;
12670Sstevel@tonic-gate 			break;
12680Sstevel@tonic-gate 	}
12690Sstevel@tonic-gate }
12700Sstevel@tonic-gate 
12710Sstevel@tonic-gate static void
set_signals()12720Sstevel@tonic-gate set_signals()
12730Sstevel@tonic-gate {
12740Sstevel@tonic-gate 	(void) signal(SIGTSTP, sig_handler);
12750Sstevel@tonic-gate 	(void) signal(SIGINT, sig_handler);
12760Sstevel@tonic-gate 	(void) signal(SIGTERM, sig_handler);
12770Sstevel@tonic-gate 	if (opts.o_outpmode & OPT_FULLSCREEN)
12780Sstevel@tonic-gate 		(void) signal(SIGWINCH, sig_handler);
12790Sstevel@tonic-gate }
12800Sstevel@tonic-gate 
12810Sstevel@tonic-gate static void
fill_table(table_t * table,char * arg,char option)1282586Svb160487 fill_table(table_t *table, char *arg, char option)
12830Sstevel@tonic-gate {
12840Sstevel@tonic-gate 	char *p = strtok(arg, ", ");
1285586Svb160487 
1286586Svb160487 	if (p == NULL)
1287586Svb160487 		Die(gettext("invalid argument for -%c\n"), option);
12880Sstevel@tonic-gate 
1289586Svb160487 	add_element(table, (long)Atoi(p));
1290586Svb160487 	while (p = strtok(NULL, ", "))
1291586Svb160487 		add_element(table, (long)Atoi(p));
12920Sstevel@tonic-gate }
12930Sstevel@tonic-gate 
12940Sstevel@tonic-gate static void
fill_prj_table(char * arg)12950Sstevel@tonic-gate fill_prj_table(char *arg)
12960Sstevel@tonic-gate {
12970Sstevel@tonic-gate 	projid_t projid;
12980Sstevel@tonic-gate 	char *p = strtok(arg, ", ");
12990Sstevel@tonic-gate 
1300586Svb160487 	if (p == NULL)
1301586Svb160487 		Die(gettext("invalid argument for -j\n"));
1302586Svb160487 
13030Sstevel@tonic-gate 	if ((projid = getprojidbyname(p)) == -1)
13040Sstevel@tonic-gate 		projid = Atoi(p);
13050Sstevel@tonic-gate 	add_element(&prj_tbl, (long)projid);
13060Sstevel@tonic-gate 
13070Sstevel@tonic-gate 	while (p = strtok(NULL, ", ")) {
13080Sstevel@tonic-gate 		if ((projid = getprojidbyname(p)) == -1)
13090Sstevel@tonic-gate 			projid = Atoi(p);
13100Sstevel@tonic-gate 		add_element(&prj_tbl, (long)projid);
13110Sstevel@tonic-gate 	}
13120Sstevel@tonic-gate }
13130Sstevel@tonic-gate 
13140Sstevel@tonic-gate static void
fill_set_table(char * arg)13150Sstevel@tonic-gate fill_set_table(char *arg)
13160Sstevel@tonic-gate {
13170Sstevel@tonic-gate 	char *p = strtok(arg, ", ");
13180Sstevel@tonic-gate 	psetid_t id;
13190Sstevel@tonic-gate 
1320586Svb160487 	if (p == NULL)
1321586Svb160487 		Die(gettext("invalid argument for -C\n"));
1322586Svb160487 
13230Sstevel@tonic-gate 	if ((id = Atoi(p)) == 0)
13240Sstevel@tonic-gate 		id = PS_NONE;
13250Sstevel@tonic-gate 	add_element(&set_tbl, id);
13260Sstevel@tonic-gate 	while (p = strtok(NULL, ", ")) {
13270Sstevel@tonic-gate 		if ((id = Atoi(p)) == 0)
13280Sstevel@tonic-gate 			id = PS_NONE;
13290Sstevel@tonic-gate 		if (!has_element(&set_tbl, id))
13300Sstevel@tonic-gate 			add_element(&set_tbl, id);
13310Sstevel@tonic-gate 	}
13320Sstevel@tonic-gate }
13330Sstevel@tonic-gate 
13340Sstevel@tonic-gate static void
Exit()13350Sstevel@tonic-gate Exit()
13360Sstevel@tonic-gate {
13370Sstevel@tonic-gate 	curses_off();
13380Sstevel@tonic-gate 	list_clear(&lwps);
13390Sstevel@tonic-gate 	list_clear(&users);
13400Sstevel@tonic-gate 	list_clear(&tasks);
13410Sstevel@tonic-gate 	list_clear(&projects);
13420Sstevel@tonic-gate 	list_clear(&zones);
13430Sstevel@tonic-gate 	fd_exit();
13440Sstevel@tonic-gate }
13450Sstevel@tonic-gate 
13463247Sgjelinek 
13470Sstevel@tonic-gate int
main(int argc,char ** argv)13480Sstevel@tonic-gate main(int argc, char **argv)
13490Sstevel@tonic-gate {
13500Sstevel@tonic-gate 	DIR *procdir;
13510Sstevel@tonic-gate 	char *p;
13520Sstevel@tonic-gate 	char *sortk = "cpu";	/* default sort key */
13530Sstevel@tonic-gate 	int opt;
13540Sstevel@tonic-gate 	int timeout;
13550Sstevel@tonic-gate 	struct pollfd pollset;
13560Sstevel@tonic-gate 	char key;
13570Sstevel@tonic-gate 
13580Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
13590Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
13600Sstevel@tonic-gate 	Progname(argv[0]);
13610Sstevel@tonic-gate 	lwpid_init();
13620Sstevel@tonic-gate 	fd_init(Setrlimit());
13630Sstevel@tonic-gate 
13643247Sgjelinek 	pagesize = sysconf(_SC_PAGESIZE);
13653247Sgjelinek 
13669123Sjohn.levon@sun.com 	while ((opt = getopt(argc, argv,
1367*9966SMenno.Lageman@Sun.COM 	    "vcd:HmarRLtu:U:n:p:C:P:h:s:S:j:k:TJz:Z")) != (int)EOF) {
13680Sstevel@tonic-gate 		switch (opt) {
1369*9966SMenno.Lageman@Sun.COM 		case 'r':
1370*9966SMenno.Lageman@Sun.COM 			opts.o_outpmode |= OPT_NORESOLVE;
1371*9966SMenno.Lageman@Sun.COM 			break;
13720Sstevel@tonic-gate 		case 'R':
13730Sstevel@tonic-gate 			opts.o_outpmode |= OPT_REALTIME;
13740Sstevel@tonic-gate 			break;
13750Sstevel@tonic-gate 		case 'c':
13760Sstevel@tonic-gate 			opts.o_outpmode &= ~OPT_TERMCAP;
13770Sstevel@tonic-gate 			opts.o_outpmode &= ~OPT_FULLSCREEN;
13780Sstevel@tonic-gate 			break;
13799123Sjohn.levon@sun.com 		case 'd':
13809123Sjohn.levon@sun.com 			if (optarg) {
13819123Sjohn.levon@sun.com 				if (*optarg == 'u')
13829123Sjohn.levon@sun.com 					opts.o_outpmode |= OPT_UDATE;
13839123Sjohn.levon@sun.com 				else if (*optarg == 'd')
13849123Sjohn.levon@sun.com 					opts.o_outpmode |= OPT_DDATE;
13859123Sjohn.levon@sun.com 				else
13869123Sjohn.levon@sun.com 					Usage();
13879123Sjohn.levon@sun.com 			} else {
13889123Sjohn.levon@sun.com 				Usage();
13899123Sjohn.levon@sun.com 			}
13909123Sjohn.levon@sun.com 			break;
13912685Sakolb 		case 'h':
13922685Sakolb 			fill_table(&lgr_tbl, optarg, 'h');
13932685Sakolb 			break;
13942685Sakolb 		case 'H':
13952685Sakolb 			opts.o_outpmode |= OPT_LGRP;
13962685Sakolb 			break;
13970Sstevel@tonic-gate 		case 'm':
13980Sstevel@tonic-gate 		case 'v':
13990Sstevel@tonic-gate 			opts.o_outpmode &= ~OPT_PSINFO;
14000Sstevel@tonic-gate 			opts.o_outpmode |=  OPT_MSACCT;
14010Sstevel@tonic-gate 			break;
14020Sstevel@tonic-gate 		case 't':
14030Sstevel@tonic-gate 			opts.o_outpmode &= ~OPT_PSINFO;
14040Sstevel@tonic-gate 			opts.o_outpmode |= OPT_USERS;
14050Sstevel@tonic-gate 			break;
14060Sstevel@tonic-gate 		case 'a':
14070Sstevel@tonic-gate 			opts.o_outpmode |= OPT_SPLIT | OPT_USERS;
14080Sstevel@tonic-gate 			break;
14090Sstevel@tonic-gate 		case 'T':
14100Sstevel@tonic-gate 			opts.o_outpmode |= OPT_SPLIT | OPT_TASKS;
14110Sstevel@tonic-gate 			break;
14120Sstevel@tonic-gate 		case 'J':
14130Sstevel@tonic-gate 			opts.o_outpmode |= OPT_SPLIT | OPT_PROJECTS;
14140Sstevel@tonic-gate 			break;
14150Sstevel@tonic-gate 		case 'n':
1416586Svb160487 			if ((p = strtok(optarg, ",")) == NULL)
1417586Svb160487 				Die(gettext("invalid argument for -n\n"));
14180Sstevel@tonic-gate 			opts.o_ntop = Atoi(p);
14190Sstevel@tonic-gate 			if (p = strtok(NULL, ","))
14200Sstevel@tonic-gate 				opts.o_nbottom = Atoi(p);
14210Sstevel@tonic-gate 			opts.o_outpmode &= ~OPT_FULLSCREEN;
14220Sstevel@tonic-gate 			break;
14230Sstevel@tonic-gate 		case 's':
14240Sstevel@tonic-gate 			opts.o_sortorder = -1;
14250Sstevel@tonic-gate 			sortk = optarg;
14260Sstevel@tonic-gate 			break;
14270Sstevel@tonic-gate 		case 'S':
14280Sstevel@tonic-gate 			opts.o_sortorder = 1;
14290Sstevel@tonic-gate 			sortk = optarg;
14300Sstevel@tonic-gate 			break;
14310Sstevel@tonic-gate 		case 'u':
1432586Svb160487 			if ((p = strtok(optarg, ", ")) == NULL)
1433586Svb160487 				Die(gettext("invalid argument for -u\n"));
14340Sstevel@tonic-gate 			add_uid(&euid_tbl, p);
14350Sstevel@tonic-gate 			while (p = strtok(NULL, ", "))
14360Sstevel@tonic-gate 				add_uid(&euid_tbl, p);
14370Sstevel@tonic-gate 			break;
14380Sstevel@tonic-gate 		case 'U':
1439586Svb160487 			if ((p = strtok(optarg, ", ")) == NULL)
1440586Svb160487 				Die(gettext("invalid argument for -U\n"));
14410Sstevel@tonic-gate 			add_uid(&ruid_tbl, p);
14420Sstevel@tonic-gate 			while (p = strtok(NULL, ", "))
14430Sstevel@tonic-gate 				add_uid(&ruid_tbl, p);
14440Sstevel@tonic-gate 			break;
14450Sstevel@tonic-gate 		case 'p':
1446586Svb160487 			fill_table(&pid_tbl, optarg, 'p');
14470Sstevel@tonic-gate 			break;
14480Sstevel@tonic-gate 		case 'C':
14490Sstevel@tonic-gate 			fill_set_table(optarg);
14500Sstevel@tonic-gate 			opts.o_outpmode |= OPT_PSETS;
14510Sstevel@tonic-gate 			break;
14520Sstevel@tonic-gate 		case 'P':
1453586Svb160487 			fill_table(&cpu_tbl, optarg, 'P');
14540Sstevel@tonic-gate 			break;
14550Sstevel@tonic-gate 		case 'k':
1456586Svb160487 			fill_table(&tsk_tbl, optarg, 'k');
14570Sstevel@tonic-gate 			break;
14580Sstevel@tonic-gate 		case 'j':
14590Sstevel@tonic-gate 			fill_prj_table(optarg);
14600Sstevel@tonic-gate 			break;
14610Sstevel@tonic-gate 		case 'L':
14620Sstevel@tonic-gate 			opts.o_outpmode |= OPT_LWPS;
14630Sstevel@tonic-gate 			break;
14640Sstevel@tonic-gate 		case 'z':
1465586Svb160487 			if ((p = strtok(optarg, ", ")) == NULL)
1466586Svb160487 				Die(gettext("invalid argument for -z\n"));
14670Sstevel@tonic-gate 			add_zone(&zone_tbl, p);
14680Sstevel@tonic-gate 			while (p = strtok(NULL, ", "))
14690Sstevel@tonic-gate 				add_zone(&zone_tbl, p);
14700Sstevel@tonic-gate 			break;
14710Sstevel@tonic-gate 		case 'Z':
14720Sstevel@tonic-gate 			opts.o_outpmode |= OPT_SPLIT | OPT_ZONES;
14730Sstevel@tonic-gate 			break;
14740Sstevel@tonic-gate 		default:
14750Sstevel@tonic-gate 			Usage();
14760Sstevel@tonic-gate 		}
14770Sstevel@tonic-gate 	}
14780Sstevel@tonic-gate 
14790Sstevel@tonic-gate 	(void) atexit(Exit);
14800Sstevel@tonic-gate 	if ((opts.o_outpmode & OPT_USERS) &&
14810Sstevel@tonic-gate 	    !(opts.o_outpmode & OPT_SPLIT))
14820Sstevel@tonic-gate 		opts.o_nbottom = opts.o_ntop;
14830Sstevel@tonic-gate 	if (opts.o_ntop == 0 || opts.o_nbottom == 0)
14840Sstevel@tonic-gate 		Die(gettext("invalid argument for -n\n"));
14850Sstevel@tonic-gate 	if (!(opts.o_outpmode & OPT_SPLIT) && (opts.o_outpmode & OPT_USERS) &&
14860Sstevel@tonic-gate 	    ((opts.o_outpmode & (OPT_PSINFO | OPT_MSACCT))))
14870Sstevel@tonic-gate 		Die(gettext("-t option cannot be used with -v or -m\n"));
14880Sstevel@tonic-gate 
14890Sstevel@tonic-gate 	if ((opts.o_outpmode & OPT_SPLIT) && (opts.o_outpmode && OPT_USERS) &&
14900Sstevel@tonic-gate 	    !((opts.o_outpmode & (OPT_PSINFO | OPT_MSACCT))))
14910Sstevel@tonic-gate 		Die(gettext("-t option cannot be used with "
14920Sstevel@tonic-gate 		    "-a, -J, -T or -Z\n"));
14930Sstevel@tonic-gate 
14940Sstevel@tonic-gate 	if ((opts.o_outpmode & OPT_USERS) &&
14959123Sjohn.levon@sun.com 	    (opts.o_outpmode & (OPT_TASKS | OPT_PROJECTS | OPT_ZONES)))
14960Sstevel@tonic-gate 		Die(gettext("-a option cannot be used with "
14970Sstevel@tonic-gate 		    "-t, -J, -T or -Z\n"));
14980Sstevel@tonic-gate 
14990Sstevel@tonic-gate 	if (((opts.o_outpmode & OPT_TASKS) &&
15000Sstevel@tonic-gate 	    (opts.o_outpmode & (OPT_PROJECTS|OPT_ZONES))) ||
15010Sstevel@tonic-gate 	    ((opts.o_outpmode & OPT_PROJECTS) &&
15029123Sjohn.levon@sun.com 	    (opts.o_outpmode & (OPT_TASKS|OPT_ZONES)))) {
15032685Sakolb 		Die(gettext(
15042685Sakolb 		    "-J, -T and -Z options are mutually exclusive\n"));
15052685Sakolb 	}
15062685Sakolb 
15072685Sakolb 	/*
15082685Sakolb 	 * There is not enough space to combine microstate information and
15092685Sakolb 	 * lgroup information and still fit in 80-column output.
15102685Sakolb 	 */
15112685Sakolb 	if ((opts.o_outpmode & OPT_LGRP) && (opts.o_outpmode & OPT_MSACCT)) {
15122685Sakolb 		Die(gettext("-H and -m options are mutually exclusive\n"));
15130Sstevel@tonic-gate 	}
15140Sstevel@tonic-gate 
15150Sstevel@tonic-gate 	if (argc > optind)
15160Sstevel@tonic-gate 		opts.o_interval = Atoi(argv[optind++]);
15170Sstevel@tonic-gate 	if (argc > optind)
15180Sstevel@tonic-gate 		opts.o_count = Atoi(argv[optind++]);
15190Sstevel@tonic-gate 	if (opts.o_count == 0)
15200Sstevel@tonic-gate 		Die(gettext("invalid counter value\n"));
15210Sstevel@tonic-gate 	if (argc > optind)
15220Sstevel@tonic-gate 		Usage();
15230Sstevel@tonic-gate 	if (opts.o_outpmode & OPT_REALTIME)
15240Sstevel@tonic-gate 		Priocntl("RT");
15250Sstevel@tonic-gate 	if (isatty(STDOUT_FILENO) == 1 && isatty(STDIN_FILENO))
15260Sstevel@tonic-gate 		opts.o_outpmode |= OPT_TTY;	/* interactive */
15270Sstevel@tonic-gate 	if (!(opts.o_outpmode & OPT_TTY)) {
15280Sstevel@tonic-gate 		opts.o_outpmode &= ~OPT_TERMCAP; /* no termcap for pipes */
15290Sstevel@tonic-gate 		opts.o_outpmode &= ~OPT_FULLSCREEN;
15300Sstevel@tonic-gate 	}
15310Sstevel@tonic-gate 	if (opts.o_outpmode & OPT_TERMCAP)
15320Sstevel@tonic-gate 		ldtermcap();		/* can turn OPT_TERMCAP off */
15330Sstevel@tonic-gate 	if (opts.o_outpmode & OPT_TERMCAP)
15340Sstevel@tonic-gate 		(void) setsize();
15350Sstevel@tonic-gate 	list_alloc(&lwps, opts.o_ntop);
15360Sstevel@tonic-gate 	list_alloc(&users, opts.o_nbottom);
15370Sstevel@tonic-gate 	list_alloc(&tasks, opts.o_nbottom);
15380Sstevel@tonic-gate 	list_alloc(&projects, opts.o_nbottom);
15390Sstevel@tonic-gate 	list_alloc(&zones, opts.o_nbottom);
15402685Sakolb 	list_alloc(&lgroups, opts.o_nbottom);
15410Sstevel@tonic-gate 	list_setkeyfunc(sortk, &opts, &lwps, LT_LWPS);
15420Sstevel@tonic-gate 	list_setkeyfunc(NULL, &opts, &users, LT_USERS);
15430Sstevel@tonic-gate 	list_setkeyfunc(NULL, &opts, &tasks, LT_TASKS);
15440Sstevel@tonic-gate 	list_setkeyfunc(NULL, &opts, &projects, LT_PROJECTS);
15450Sstevel@tonic-gate 	list_setkeyfunc(NULL, &opts, &zones, LT_ZONES);
15462685Sakolb 	list_setkeyfunc(NULL, &opts, &lgroups, LT_LGRPS);
15470Sstevel@tonic-gate 	if (opts.o_outpmode & OPT_TERMCAP)
15480Sstevel@tonic-gate 		curses_on();
15490Sstevel@tonic-gate 	if ((procdir = opendir("/proc")) == NULL)
15500Sstevel@tonic-gate 		Die(gettext("cannot open /proc directory\n"));
15510Sstevel@tonic-gate 	if (opts.o_outpmode & OPT_TTY) {
15520Sstevel@tonic-gate 		(void) printf(gettext("Please wait...\r"));
15539123Sjohn.levon@sun.com 		if (!(opts.o_outpmode & OPT_TERMCAP))
15549123Sjohn.levon@sun.com 			(void) putchar('\n');
15550Sstevel@tonic-gate 		(void) fflush(stdout);
15560Sstevel@tonic-gate 	}
15570Sstevel@tonic-gate 	set_signals();
15580Sstevel@tonic-gate 	pollset.fd = STDIN_FILENO;
15590Sstevel@tonic-gate 	pollset.events = POLLIN;
15600Sstevel@tonic-gate 	timeout = opts.o_interval * MILLISEC;
15610Sstevel@tonic-gate 
15620Sstevel@tonic-gate 	/*
15630Sstevel@tonic-gate 	 * main program loop
15640Sstevel@tonic-gate 	 */
15650Sstevel@tonic-gate 	do {
15660Sstevel@tonic-gate 		if (sigterm == 1)
15670Sstevel@tonic-gate 			break;
15680Sstevel@tonic-gate 		if (sigtstp == 1) {
15690Sstevel@tonic-gate 			curses_off();
15700Sstevel@tonic-gate 			(void) signal(SIGTSTP, SIG_DFL);
15710Sstevel@tonic-gate 			(void) kill(0, SIGTSTP);
15720Sstevel@tonic-gate 			/*
15730Sstevel@tonic-gate 			 * prstat stops here until it receives SIGCONT signal.
15740Sstevel@tonic-gate 			 */
15750Sstevel@tonic-gate 			sigtstp = 0;
15760Sstevel@tonic-gate 			(void) signal(SIGTSTP, sig_handler);
15770Sstevel@tonic-gate 			curses_on();
15780Sstevel@tonic-gate 			print_movecur = FALSE;
15790Sstevel@tonic-gate 			if (opts.o_outpmode & OPT_FULLSCREEN)
15800Sstevel@tonic-gate 				sigwinch = 1;
15810Sstevel@tonic-gate 		}
15820Sstevel@tonic-gate 		if (sigwinch == 1) {
15830Sstevel@tonic-gate 			if (setsize() == 1) {
15840Sstevel@tonic-gate 				list_free(&lwps);
15850Sstevel@tonic-gate 				list_free(&users);
15860Sstevel@tonic-gate 				list_free(&tasks);
15870Sstevel@tonic-gate 				list_free(&projects);
15880Sstevel@tonic-gate 				list_free(&zones);
15890Sstevel@tonic-gate 				list_alloc(&lwps, opts.o_ntop);
15900Sstevel@tonic-gate 				list_alloc(&users, opts.o_nbottom);
15910Sstevel@tonic-gate 				list_alloc(&tasks, opts.o_nbottom);
15920Sstevel@tonic-gate 				list_alloc(&projects, opts.o_nbottom);
15930Sstevel@tonic-gate 				list_alloc(&zones, opts.o_nbottom);
15940Sstevel@tonic-gate 			}
15950Sstevel@tonic-gate 			sigwinch = 0;
15960Sstevel@tonic-gate 			(void) signal(SIGWINCH, sig_handler);
15970Sstevel@tonic-gate 		}
15980Sstevel@tonic-gate 		prstat_scandir(procdir);
15990Sstevel@tonic-gate 		list_refresh(&lwps);
16000Sstevel@tonic-gate 		if (print_movecur)
16010Sstevel@tonic-gate 			(void) putp(movecur);
16020Sstevel@tonic-gate 		print_movecur = TRUE;
16030Sstevel@tonic-gate 		if ((opts.o_outpmode & OPT_PSINFO) ||
16040Sstevel@tonic-gate 		    (opts.o_outpmode & OPT_MSACCT)) {
16050Sstevel@tonic-gate 			list_sort(&lwps);
16060Sstevel@tonic-gate 			list_print(&lwps);
16070Sstevel@tonic-gate 		}
16080Sstevel@tonic-gate 		if (opts.o_outpmode & OPT_USERS) {
16093247Sgjelinek 			list_getsize(&users);
16100Sstevel@tonic-gate 			list_sort(&users);
16110Sstevel@tonic-gate 			list_print(&users);
16120Sstevel@tonic-gate 			list_clear(&users);
16130Sstevel@tonic-gate 		}
16140Sstevel@tonic-gate 		if (opts.o_outpmode & OPT_TASKS) {
16153247Sgjelinek 			list_getsize(&tasks);
16160Sstevel@tonic-gate 			list_sort(&tasks);
16170Sstevel@tonic-gate 			list_print(&tasks);
16180Sstevel@tonic-gate 			list_clear(&tasks);
16190Sstevel@tonic-gate 		}
16200Sstevel@tonic-gate 		if (opts.o_outpmode & OPT_PROJECTS) {
16213247Sgjelinek 			list_getsize(&projects);
16220Sstevel@tonic-gate 			list_sort(&projects);
16230Sstevel@tonic-gate 			list_print(&projects);
16240Sstevel@tonic-gate 			list_clear(&projects);
16250Sstevel@tonic-gate 		}
16260Sstevel@tonic-gate 		if (opts.o_outpmode & OPT_ZONES) {
16273247Sgjelinek 			list_getsize(&zones);
16280Sstevel@tonic-gate 			list_sort(&zones);
16290Sstevel@tonic-gate 			list_print(&zones);
16300Sstevel@tonic-gate 			list_clear(&zones);
16310Sstevel@tonic-gate 		}
16320Sstevel@tonic-gate 		if (opts.o_count == 1)
16330Sstevel@tonic-gate 			break;
16340Sstevel@tonic-gate 		/*
16350Sstevel@tonic-gate 		 * If poll() returns -1 and sets errno to EINTR here because
16360Sstevel@tonic-gate 		 * the process received a signal, it is Ok to abort this
16370Sstevel@tonic-gate 		 * timeout and loop around because we check the signals at the
16380Sstevel@tonic-gate 		 * top of the loop.
16390Sstevel@tonic-gate 		 */
16400Sstevel@tonic-gate 		if (opts.o_outpmode & OPT_TTY) {
16410Sstevel@tonic-gate 			if (poll(&pollset, (nfds_t)1, timeout) > 0) {
16420Sstevel@tonic-gate 				if (read(STDIN_FILENO, &key, 1) == 1) {
16430Sstevel@tonic-gate 					if (tolower(key) == 'q')
16440Sstevel@tonic-gate 						break;
16450Sstevel@tonic-gate 				}
16460Sstevel@tonic-gate 			}
16470Sstevel@tonic-gate 		} else {
16480Sstevel@tonic-gate 			(void) sleep(opts.o_interval);
16490Sstevel@tonic-gate 		}
16500Sstevel@tonic-gate 	} while (opts.o_count == (-1) || --opts.o_count);
16510Sstevel@tonic-gate 
16520Sstevel@tonic-gate 	if (opts.o_outpmode & OPT_TTY)
16530Sstevel@tonic-gate 		(void) putchar('\r');
16540Sstevel@tonic-gate 	return (0);
16550Sstevel@tonic-gate }
1656