Home | History | Annotate | Download | only in prstat
      1     0    stevel /*
      2     0    stevel  * CDDL HEADER START
      3     0    stevel  *
      4     0    stevel  * The contents of this file are subject to the terms of the
      5  2685     akolb  * Common Development and Distribution License (the "License").
      6  2685     akolb  * You may not use this file except in compliance with the License.
      7     0    stevel  *
      8     0    stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9     0    stevel  * or http://www.opensolaris.org/os/licensing.
     10     0    stevel  * See the License for the specific language governing permissions
     11     0    stevel  * and limitations under the License.
     12     0    stevel  *
     13     0    stevel  * When distributing Covered Code, include this CDDL HEADER in each
     14     0    stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15     0    stevel  * If applicable, add the following below this CDDL HEADER, with the
     16     0    stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     17     0    stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     18     0    stevel  *
     19     0    stevel  * CDDL HEADER END
     20     0    stevel  */
     21  2685     akolb 
     22     0    stevel /*
     23  9123      john  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24     0    stevel  * Use is subject to license terms.
     25  9966     Menno  *
     26  9966     Menno  * Portions Copyright 2009 Chad Mynhier
     27     0    stevel  */
     28     0    stevel 
     29     0    stevel #include <sys/types.h>
     30     0    stevel #include <sys/resource.h>
     31     0    stevel #include <sys/loadavg.h>
     32     0    stevel #include <sys/time.h>
     33     0    stevel #include <sys/pset.h>
     34  3247  gjelinek #include <sys/vm_usage.h>
     35     0    stevel #include <zone.h>
     36     0    stevel #include <libzonecfg.h>
     37     0    stevel 
     38     0    stevel #include <stdio.h>
     39     0    stevel #include <stdlib.h>
     40     0    stevel #include <unistd.h>
     41     0    stevel #include <dirent.h>
     42     0    stevel #include <string.h>
     43     0    stevel #include <errno.h>
     44     0    stevel #include <poll.h>
     45     0    stevel #include <ctype.h>
     46     0    stevel #include <fcntl.h>
     47     0    stevel #include <limits.h>
     48     0    stevel #include <signal.h>
     49     0    stevel #include <time.h>
     50     0    stevel #include <project.h>
     51     0    stevel 
     52  9123      john #include <langinfo.h>
     53     0    stevel #include <libintl.h>
     54     0    stevel #include <locale.h>
     55     0    stevel 
     56     0    stevel #include "prstat.h"
     57     0    stevel #include "prutil.h"
     58     0    stevel #include "prtable.h"
     59     0    stevel #include "prsort.h"
     60     0    stevel #include "prfile.h"
     61     0    stevel 
     62     0    stevel /*
     63     0    stevel  * x86 <sys/regs.h> ERR conflicts with <curses.h> ERR.  For the purposes
     64     0    stevel  * of this file, we care about the curses.h ERR so include that last.
     65     0    stevel  */
     66     0    stevel 
     67     0    stevel #if	defined(ERR)
     68     0    stevel #undef	ERR
     69     0    stevel #endif
     70     0    stevel 
     71     0    stevel #ifndef	TEXT_DOMAIN			/* should be defined by cc -D */
     72     0    stevel #define	TEXT_DOMAIN	"SYS_TEST"	/* use this only if it wasn't */
     73     0    stevel #endif
     74     0    stevel 
     75     0    stevel #include <curses.h>
     76     0    stevel #include <term.h>
     77     0    stevel 
     78     0    stevel #define	PSINFO_HEADER_PROC \
     79     0    stevel "   PID USERNAME  SIZE   RSS STATE  PRI NICE      TIME  CPU PROCESS/NLWP       "
     80  2685     akolb #define	PSINFO_HEADER_PROC_LGRP \
     81  2685     akolb "   PID USERNAME  SIZE   RSS STATE  PRI NICE      TIME  CPU LGRP PROCESS/NLWP  "
     82     0    stevel #define	PSINFO_HEADER_LWP \
     83     0    stevel "   PID USERNAME  SIZE   RSS STATE  PRI NICE      TIME  CPU PROCESS/LWPID      "
     84  2685     akolb #define	PSINFO_HEADER_LWP_LGRP \
     85  2685     akolb "   PID USERNAME  SIZE   RSS STATE  PRI NICE      TIME  CPU LGRP PROCESS/LWPID "
     86     0    stevel #define	USAGE_HEADER_PROC \
     87     0    stevel "   PID USERNAME USR SYS TRP TFL DFL LCK SLP LAT VCX ICX SCL SIG PROCESS/NLWP  "
     88     0    stevel #define	USAGE_HEADER_LWP \
     89     0    stevel "   PID USERNAME USR SYS TRP TFL DFL LCK SLP LAT VCX ICX SCL SIG PROCESS/LWPID "
     90     0    stevel #define	USER_HEADER_PROC \
     91  3247  gjelinek " NPROC USERNAME  SWAP   RSS MEMORY      TIME  CPU                             "
     92     0    stevel #define	USER_HEADER_LWP \
     93  3247  gjelinek "  NLWP USERNAME  SWAP   RSS MEMORY      TIME  CPU                             "
     94     0    stevel #define	TASK_HEADER_PROC \
     95  3247  gjelinek "TASKID    NPROC  SWAP   RSS MEMORY      TIME  CPU PROJECT                     "
     96     0    stevel #define	TASK_HEADER_LWP \
     97  3247  gjelinek "TASKID     NLWP  SWAP   RSS MEMORY      TIME  CPU PROJECT                     "
     98     0    stevel #define	PROJECT_HEADER_PROC \
     99  3247  gjelinek "PROJID    NPROC  SWAP   RSS MEMORY      TIME  CPU PROJECT                     "
    100     0    stevel #define	PROJECT_HEADER_LWP \
    101  3247  gjelinek "PROJID     NLWP  SWAP   RSS MEMORY      TIME  CPU PROJECT                     "
    102     0    stevel #define	ZONE_HEADER_PROC \
    103  3247  gjelinek "ZONEID    NPROC  SWAP   RSS MEMORY      TIME  CPU ZONE                        "
    104     0    stevel #define	ZONE_HEADER_LWP \
    105  3247  gjelinek "ZONEID     NLWP  SWAP   RSS MEMORY      TIME  CPU ZONE                        "
    106     0    stevel #define	PSINFO_LINE \
    107     0    stevel "%6d %-8s %5s %5s %-6s %3s  %3s %9s %3.3s%% %-.16s/%d"
    108  2685     akolb #define	PSINFO_LINE_LGRP \
    109  2685     akolb "%6d %-8s %5s %5s %-6s %3s  %3s %9s %3.3s%% %4d %-.16s/%d"
    110     0    stevel #define	USAGE_LINE \
    111     0    stevel "%6d %-8s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s "\
    112     0    stevel "%3.3s %-.12s/%d"
    113     0    stevel #define	USER_LINE \
    114     0    stevel "%6d %-8s %5.5s %5.5s   %3.3s%% %9s %3.3s%%"
    115     0    stevel #define	TASK_LINE \
    116     0    stevel "%6d %8d %5s %5s   %3.3s%% %9s %3.3s%% %28s"
    117     0    stevel #define	PROJECT_LINE \
    118     0    stevel "%6d %8d %5s %5s   %3.3s%% %9s %3.3s%% %28s"
    119     0    stevel #define	ZONE_LINE \
    120     0    stevel "%6d %8d %5s %5s   %3.3s%% %9s %3.3s%% %28s"
    121     0    stevel 
    122     0    stevel #define	TOTAL_LINE \
    123     0    stevel "Total: %d processes, %d lwps, load averages: %3.2f, %3.2f, %3.2f"
    124     0    stevel 
    125     0    stevel /* global variables */
    126     0    stevel 
    127     0    stevel static char	*t_ulon;			/* termcap: start underline */
    128     0    stevel static char	*t_uloff;			/* termcap: end underline */
    129     0    stevel static char	*t_up;				/* termcap: cursor 1 line up */
    130     0    stevel static char	*t_eol;				/* termcap: clear end of line */
    131     0    stevel static char	*t_smcup;			/* termcap: cursor mvcap on */
    132     0    stevel static char	*t_rmcup;			/* termcap: cursor mvcap off */
    133     0    stevel static char	*t_home;			/* termcap: move cursor home */
    134     0    stevel static char	*movecur = NULL;		/* termcap: move up string */
    135     0    stevel static char	*empty_string = "\0";		/* termcap: empty string */
    136     0    stevel static uint_t	print_movecur = FALSE;		/* print movecur or not */
    137     0    stevel static int	is_curses_on = FALSE;		/* current curses state */
    138     0    stevel 
    139     0    stevel static table_t	pid_tbl = {0, 0, NULL};		/* selected processes */
    140     0    stevel static table_t	cpu_tbl = {0, 0, NULL};		/* selected processors */
    141     0    stevel static table_t  set_tbl = {0, 0, NULL};		/* selected processor sets */
    142     0    stevel static table_t	prj_tbl = {0, 0, NULL};		/* selected projects */
    143     0    stevel static table_t	tsk_tbl = {0, 0, NULL};		/* selected tasks */
    144  2685     akolb static table_t	lgr_tbl = {0, 0, NULL};		/* selected lgroups */
    145     0    stevel static zonetbl_t zone_tbl = {0, 0, NULL};	/* selected zones */
    146  9966     Menno static uidtbl_t euid_tbl = {0, 0, NULL}; 	/* selected effective users */
    147  9966     Menno static uidtbl_t ruid_tbl = {0, 0, NULL}; 	/* selected real users */
    148     0    stevel 
    149     0    stevel static uint_t	total_procs;			/* total number of procs */
    150     0    stevel static uint_t	total_lwps;			/* total number of lwps */
    151     0    stevel static float	total_cpu;			/* total cpu usage */
    152     0    stevel static float	total_mem;			/* total memory usage */
    153     0    stevel 
    154     0    stevel static list_t	lwps;				/* list of lwps/processes */
    155     0    stevel static list_t	users;				/* list of users */
    156     0    stevel static list_t	tasks;				/* list of tasks */
    157     0    stevel static list_t	projects;			/* list of projects */
    158     0    stevel static list_t	zones;				/* list of zones */
    159  2685     akolb static list_t	lgroups;			/* list of lgroups */
    160     0    stevel 
    161     0    stevel static volatile uint_t sigwinch = 0;
    162     0    stevel static volatile uint_t sigtstp = 0;
    163     0    stevel static volatile uint_t sigterm = 0;
    164     0    stevel 
    165  3247  gjelinek static long pagesize;
    166  3247  gjelinek 
    167     0    stevel /* default settings */
    168     0    stevel 
    169     0    stevel static optdesc_t opts = {
    170     0    stevel 	5,			/* interval between updates, seconds */
    171     0    stevel 	15,			/* number of lines in top part */
    172     0    stevel 	5,			/* number of lines in bottom part */
    173     0    stevel 	-1,			/* number of iterations; infinitely */
    174     0    stevel 	OPT_PSINFO | OPT_FULLSCREEN | OPT_USEHOME | OPT_TERMCAP,
    175     0    stevel 	-1			/* sort in decreasing order */
    176     0    stevel };
    177  9123      john 
    178  9123      john /*
    179  9123      john  * Print timestamp as decimal reprentation of time_t value (-d u was specified)
    180  9123      john  * or the standard date format (-d d was specified).
    181  9123      john  */
    182  9123      john static void
    183  9123      john print_timestamp(void)
    184  9123      john {
    185  9123      john 	time_t t = time(NULL);
    186  9123      john 	static char *fmt = NULL;
    187  9123      john 
    188  9123      john 	/* We only need to retrieve this once per invocation */
    189  9123      john 	if (fmt == NULL)
    190  9123      john 		fmt = nl_langinfo(_DATE_FMT);
    191  9123      john 
    192  9123      john 	if (opts.o_outpmode & OPT_UDATE) {
    193  9123      john 		(void) printf("%ld", t);
    194  9123      john 	} else if (opts.o_outpmode & OPT_DDATE) {
    195  9123      john 		char dstr[64];
    196  9123      john 		int len;
    197  9123      john 
    198  9123      john 		len = strftime(dstr, sizeof (dstr), fmt, localtime(&t));
    199  9123      john 		if (len > 0)
    200  9123      john 			(void) printf("%s", dstr);
    201  9123      john 	}
    202  9123      john 	(void) putp(t_eol);
    203  9123      john 	(void) putchar('\n');
    204  9123      john }
    205     0    stevel 
    206     0    stevel static void
    207     0    stevel psetloadavg(long psetid, void *ptr)
    208     0    stevel {
    209     0    stevel 	double psetloadavg[3];
    210     0    stevel 	double *loadavg = ptr;
    211     0    stevel 
    212     0    stevel 	if (pset_getloadavg((psetid_t)psetid, psetloadavg, 3) != -1) {
    213     0    stevel 		*loadavg++ += psetloadavg[0];
    214     0    stevel 		*loadavg++ += psetloadavg[1];
    215     0    stevel 		*loadavg += psetloadavg[2];
    216  3247  gjelinek 	}
    217  3247  gjelinek }
    218  3247  gjelinek 
    219  3247  gjelinek /*
    220  3247  gjelinek  * Queries the memory virtual and rss size for each member of a list.
    221  3247  gjelinek  * This will override the values computed by /proc aggregation.
    222  3247  gjelinek  */
    223  3247  gjelinek static void
    224  3247  gjelinek list_getsize(list_t *list)
    225  3247  gjelinek {
    226  3247  gjelinek 	id_info_t *id;
    227  3247  gjelinek 	vmusage_t *results, *next;
    228  3247  gjelinek 	vmusage_t *match;
    229  3247  gjelinek 	size_t nres = 0;
    230  3247  gjelinek 	size_t i;
    231  3247  gjelinek 	uint_t flags = 0;
    232  3247  gjelinek 	int ret;
    233  3247  gjelinek 	size_t physmem = sysconf(_SC_PHYS_PAGES) * pagesize;
    234  3247  gjelinek 
    235  3247  gjelinek 	/*
    236  3247  gjelinek 	 * Determine what swap/rss results to calculate.  getvmusage() will
    237  3247  gjelinek 	 * prune results returned to non-global zones automatically, so
    238  3247  gjelinek 	 * there is no need to pass different flags when calling from a
    239  3247  gjelinek 	 * non-global zone.
    240  3247  gjelinek 	 *
    241  3247  gjelinek 	 * Currently list_getsize() is only called with a single flag.  This
    242  3247  gjelinek 	 * is because -Z, -J, -T, and -a are mutually exclusive.  Regardless
    243  3247  gjelinek 	 * of this, we handle multiple flags.
    244  3247  gjelinek 	 */
    245  3247  gjelinek 	if (opts.o_outpmode & OPT_USERS) {
    246  3247  gjelinek 		/*
    247  3247  gjelinek 		 * Gather rss for all users in all zones.  Treat the same
    248  3247  gjelinek 		 * uid in different zones as the same user.
    249  3247  gjelinek 		 */
    250  3247  gjelinek 		flags |= VMUSAGE_COL_RUSERS;
    251  3247  gjelinek 
    252  3247  gjelinek 	} else if (opts.o_outpmode & OPT_TASKS) {
    253  3247  gjelinek 		/* Gather rss for all tasks in all zones */
    254  3247  gjelinek 		flags |= VMUSAGE_ALL_TASKS;
    255  3247  gjelinek 
    256  3247  gjelinek 	} else if (opts.o_outpmode & OPT_PROJECTS) {
    257  3247  gjelinek 		/*
    258  3247  gjelinek 		 * Gather rss for all projects in all zones.  Treat the same
    259  3247  gjelinek 		 * projid in diffrent zones as the same project.
    260  3247  gjelinek 		 */
    261  3247  gjelinek 		flags |= VMUSAGE_COL_PROJECTS;
    262  3247  gjelinek 
    263  3247  gjelinek 	} else if (opts.o_outpmode & OPT_ZONES) {
    264  3247  gjelinek 		/* Gather rss for all zones */
    265  3247  gjelinek 		flags |= VMUSAGE_ALL_ZONES;
    266  3247  gjelinek 
    267  3247  gjelinek 	} else {
    268  3247  gjelinek 		Die(gettext(
    269  3247  gjelinek 		    "Cannot determine rss flags for output options %x\n"),
    270  3247  gjelinek 		    opts.o_outpmode);
    271  3247  gjelinek 	}
    272  3247  gjelinek 
    273  3247  gjelinek 	/*
    274  3247  gjelinek 	 * getvmusage() returns an array of result structures.  One for
    275  3247  gjelinek 	 * each zone, project, task, or user on the system, depending on
    276  3247  gjelinek 	 * flags.
    277  3247  gjelinek 	 *
    278  3247  gjelinek 	 * If getvmusage() fails, prstat will use the size already gathered
    279  3247  gjelinek 	 * from psinfo
    280  3247  gjelinek 	 */
    281  3247  gjelinek 	if (getvmusage(flags, opts.o_interval, NULL, &nres) != 0)
    282  3247  gjelinek 		return;
    283  3247  gjelinek 
    284  3247  gjelinek 	results = (vmusage_t *)Malloc(sizeof (vmusage_t) * nres);
    285  3247  gjelinek 	for (;;) {
    286  3247  gjelinek 		ret = getvmusage(flags, opts.o_interval, results, &nres);
    287  3247  gjelinek 		if (ret == 0)
    288  3247  gjelinek 			break;
    289  3247  gjelinek 		if (errno == EOVERFLOW) {
    290  3247  gjelinek 			results = (vmusage_t *)Realloc(results,
    291  3247  gjelinek 			    sizeof (vmusage_t) * nres);
    292  3247  gjelinek 			continue;
    293  3247  gjelinek 		}
    294  3247  gjelinek 		/*
    295  3247  gjelinek 		 * Failure for some other reason.  Prstat will use the size
    296  3247  gjelinek 		 * already gathered from psinfo.
    297  3247  gjelinek 		 */
    298  9524    gerald 		free(results);
    299  3247  gjelinek 		return;
    300  3247  gjelinek 	}
    301  3247  gjelinek 	for (id = list->l_head; id != NULL; id = id->id_next) {
    302  3247  gjelinek 
    303  3247  gjelinek 		match = NULL;
    304  3247  gjelinek 		next = results;
    305  3247  gjelinek 		for (i = 0; i < nres; i++, next++) {
    306  3247  gjelinek 			switch (flags) {
    307  3247  gjelinek 			case VMUSAGE_COL_RUSERS:
    308  3247  gjelinek 				if (next->vmu_id == id->id_uid)
    309  3247  gjelinek 					match = next;
    310  3247  gjelinek 				break;
    311  3247  gjelinek 			case VMUSAGE_ALL_TASKS:
    312  3247  gjelinek 				if (next->vmu_id == id->id_taskid)
    313  3247  gjelinek 					match = next;
    314  3247  gjelinek 				break;
    315  3247  gjelinek 			case VMUSAGE_COL_PROJECTS:
    316  3247  gjelinek 				if (next->vmu_id == id->id_projid)
    317  3247  gjelinek 					match = next;
    318  3247  gjelinek 				break;
    319  3247  gjelinek 			case VMUSAGE_ALL_ZONES:
    320  3247  gjelinek 				if (next->vmu_id == id->id_zoneid)
    321  3247  gjelinek 					match = next;
    322  3247  gjelinek 				break;
    323  3247  gjelinek 			default:
    324  3247  gjelinek 				Die(gettext(
    325  3247  gjelinek 				    "Unknown vmusage flags %d\n"), flags);
    326  3247  gjelinek 			}
    327  3247  gjelinek 		}
    328  3247  gjelinek 		if (match != NULL) {
    329  3247  gjelinek 			id->id_size = match->vmu_swap_all / 1024;
    330  3247  gjelinek 			id->id_rssize = match->vmu_rss_all / 1024;
    331  3247  gjelinek 			id->id_pctmem = (100.0 * (float)match->vmu_rss_all) /
    332  3247  gjelinek 			    (float)physmem;
    333  3247  gjelinek 			/* Output using data from getvmusage() */
    334  3247  gjelinek 			id->id_sizematch = B_TRUE;
    335  3247  gjelinek 		}
    336  3247  gjelinek 		/*
    337  3247  gjelinek 		 * If no match is found, prstat will use the size already
    338  3247  gjelinek 		 * gathered from psinfo.
    339  3247  gjelinek 		 */
    340     0    stevel 	}
    341  9524    gerald 	free(results);
    342     0    stevel }
    343     0    stevel 
    344     0    stevel /*
    345     0    stevel  * A routine to display the contents of the list on the screen
    346     0    stevel  */
    347     0    stevel static void
    348     0    stevel list_print(list_t *list)
    349     0    stevel {
    350     0    stevel 	lwp_info_t *lwp;
    351     0    stevel 	id_info_t *id;
    352     0    stevel 	char usr[4], sys[4], trp[4], tfl[4];
    353     0    stevel 	char dfl[4], lck[4], slp[4], lat[4];
    354     0    stevel 	char vcx[4], icx[4], scl[4], sig[4];
    355     0    stevel 	char psize[6], prssize[6], pmem[6], pcpu[6], ptime[12];
    356     0    stevel 	char pstate[7], pnice[4], ppri[4];
    357     0    stevel 	char pname[LOGNAME_MAX+1];
    358     0    stevel 	char projname[PROJNAME_MAX+1];
    359     0    stevel 	char zonename[ZONENAME_MAX+1];
    360     0    stevel 	float cpu, mem;
    361     0    stevel 	double loadavg[3] = {0, 0, 0};
    362     0    stevel 	int i, lwpid;
    363     0    stevel 
    364     0    stevel 	if (foreach_element(&set_tbl, &loadavg, psetloadavg) == 0) {
    365     0    stevel 		/*
    366     0    stevel 		 * If processor sets aren't specified, we display system-wide
    367     0    stevel 		 * load averages.
    368     0    stevel 		 */
    369     0    stevel 		(void) getloadavg(loadavg, 3);
    370     0    stevel 	}
    371     0    stevel 
    372  9123      john 	if (((opts.o_outpmode & OPT_UDATE) || (opts.o_outpmode & OPT_DDATE)) &&
    373  9123      john 	    ((list->l_type == LT_LWPS) || !(opts.o_outpmode & OPT_SPLIT)))
    374  9123      john 		print_timestamp();
    375     0    stevel 	if (opts.o_outpmode & OPT_TTY)
    376     0    stevel 		(void) putchar('\r');
    377     0    stevel 	(void) putp(t_ulon);
    378     0    stevel 
    379     0    stevel 	switch (list->l_type) {
    380     0    stevel 	case LT_PROJECTS:
    381     0    stevel 		if (opts.o_outpmode & OPT_LWPS)
    382     0    stevel 			(void) printf(PROJECT_HEADER_LWP);
    383     0    stevel 		else
    384     0    stevel 			(void) printf(PROJECT_HEADER_PROC);
    385     0    stevel 		break;
    386     0    stevel 	case LT_TASKS:
    387     0    stevel 		if (opts.o_outpmode & OPT_LWPS)
    388     0    stevel 			(void) printf(TASK_HEADER_LWP);
    389     0    stevel 		else
    390     0    stevel 			(void) printf(TASK_HEADER_PROC);
    391     0    stevel 		break;
    392     0    stevel 	case LT_ZONES:
    393     0    stevel 		if (opts.o_outpmode & OPT_LWPS)
    394     0    stevel 			(void) printf(ZONE_HEADER_LWP);
    395     0    stevel 		else
    396     0    stevel 			(void) printf(ZONE_HEADER_PROC);
    397     0    stevel 		break;
    398     0    stevel 	case LT_USERS:
    399     0    stevel 		if (opts.o_outpmode & OPT_LWPS)
    400     0    stevel 			(void) printf(USER_HEADER_LWP);
    401     0    stevel 		else
    402     0    stevel 			(void) printf(USER_HEADER_PROC);
    403     0    stevel 		break;
    404     0    stevel 	case LT_LWPS:
    405     0    stevel 		if (opts.o_outpmode & OPT_LWPS) {
    406  2685     akolb 			if (opts.o_outpmode & OPT_PSINFO) {
    407  2685     akolb 				if (opts.o_outpmode & OPT_LGRP)
    408  2685     akolb 					(void) printf(PSINFO_HEADER_LWP_LGRP);
    409  2685     akolb 				else
    410  2685     akolb 					(void) printf(PSINFO_HEADER_LWP);
    411  2685     akolb 			}
    412     0    stevel 			if (opts.o_outpmode & OPT_MSACCT)
    413     0    stevel 				(void) printf(USAGE_HEADER_LWP);
    414     0    stevel 		} else {
    415  2685     akolb 			if (opts.o_outpmode & OPT_PSINFO) {
    416  2685     akolb 				if (opts.o_outpmode & OPT_LGRP)
    417  2685     akolb 					(void) printf(PSINFO_HEADER_PROC_LGRP);
    418  2685     akolb 				else
    419  2685     akolb 					(void) printf(PSINFO_HEADER_PROC);
    420  2685     akolb 			}
    421     0    stevel 			if (opts.o_outpmode & OPT_MSACCT)
    422     0    stevel 				(void) printf(USAGE_HEADER_PROC);
    423     0    stevel 		}
    424     0    stevel 		break;
    425     0    stevel 	}
    426     0    stevel 
    427     0    stevel 	(void) putp(t_uloff);
    428     0    stevel 	(void) putp(t_eol);
    429     0    stevel 	(void) putchar('\n');
    430     0    stevel 
    431     0    stevel 	for (i = 0; i < list->l_used; i++) {
    432     0    stevel 		switch (list->l_type) {
    433     0    stevel 		case LT_PROJECTS:
    434     0    stevel 		case LT_TASKS:
    435     0    stevel 		case LT_USERS:
    436     0    stevel 		case LT_ZONES:
    437     0    stevel 			id = list->l_ptrs[i];
    438     0    stevel 			/*
    439     0    stevel 			 * CPU usage and memory usage normalization
    440     0    stevel 			 */
    441     0    stevel 			if (total_cpu >= 100)
    442     0    stevel 				cpu = (100 * id->id_pctcpu) / total_cpu;
    443     0    stevel 			else
    444     0    stevel 				cpu = id->id_pctcpu;
    445  3247  gjelinek 			if (id->id_sizematch == B_FALSE && total_mem >= 100)
    446     0    stevel 				mem = (100 * id->id_pctmem) / total_mem;
    447     0    stevel 			else
    448     0    stevel 				mem = id->id_pctmem;
    449     0    stevel 			if (list->l_type == LT_USERS)
    450  9966     Menno 				pwd_getname(id->id_uid, pname, LOGNAME_MAX + 1,
    451  9966     Menno 				    opts.o_outpmode & OPT_NORESOLVE);
    452     0    stevel 			else if (list->l_type == LT_ZONES)
    453     0    stevel 				getzonename(id->id_zoneid, zonename,
    454     0    stevel 				    ZONENAME_MAX);
    455     0    stevel 			else
    456     0    stevel 				getprojname(id->id_projid, projname,
    457  9966     Menno 				    PROJNAME_MAX,
    458  9966     Menno 				    opts.o_outpmode & OPT_NORESOLVE);
    459     0    stevel 			Format_size(psize, id->id_size, 6);
    460     0    stevel 			Format_size(prssize, id->id_rssize, 6);
    461     0    stevel 			Format_pct(pmem, mem, 4);
    462     0    stevel 			Format_pct(pcpu, cpu, 4);
    463     0    stevel 			Format_time(ptime, id->id_time, 10);
    464     0    stevel 			if (opts.o_outpmode & OPT_TTY)
    465     0    stevel 				(void) putchar('\r');
    466     0    stevel 			if (list->l_type == LT_PROJECTS)
    467     0    stevel 				(void) printf(PROJECT_LINE, (int)id->id_projid,
    468     0    stevel 				    id->id_nproc, psize, prssize, pmem, ptime,
    469     0    stevel 				    pcpu, projname);
    470     0    stevel 			else if (list->l_type == LT_TASKS)
    471     0    stevel 				(void) printf(TASK_LINE, (int)id->id_taskid,
    472     0    stevel 				    id->id_nproc, psize, prssize, pmem, ptime,
    473     0    stevel 				    pcpu, projname);
    474     0    stevel 			else if (list->l_type == LT_ZONES)
    475     0    stevel 				(void) printf(ZONE_LINE, (int)id->id_zoneid,
    476     0    stevel 				    id->id_nproc, psize, prssize, pmem, ptime,
    477     0    stevel 				    pcpu, zonename);
    478     0    stevel 			else
    479     0    stevel 				(void) printf(USER_LINE, id->id_nproc, pname,
    480     0    stevel 				    psize, prssize, pmem, ptime, pcpu);
    481     0    stevel 			(void) putp(t_eol);
    482     0    stevel 			(void) putchar('\n');
    483     0    stevel 			break;
    484     0    stevel 		case LT_LWPS:
    485     0    stevel 			lwp = list->l_ptrs[i];
    486     0    stevel 			if (opts.o_outpmode & OPT_LWPS)
    487     0    stevel 				lwpid = lwp->li_info.pr_lwp.pr_lwpid;
    488     0    stevel 			else
    489     0    stevel 				lwpid = lwp->li_info.pr_nlwp +
    490     0    stevel 				    lwp->li_info.pr_nzomb;
    491  9966     Menno 			pwd_getname(lwp->li_info.pr_uid, pname, LOGNAME_MAX + 1,
    492  9966     Menno 			    opts.o_outpmode & OPT_NORESOLVE);
    493     0    stevel 			if (opts.o_outpmode & OPT_PSINFO) {
    494     0    stevel 				Format_size(psize, lwp->li_info.pr_size, 6);
    495     0    stevel 				Format_size(prssize, lwp->li_info.pr_rssize, 6);
    496     0    stevel 				Format_state(pstate,
    497     0    stevel 				    lwp->li_info.pr_lwp.pr_sname,
    498     0    stevel 				    lwp->li_info.pr_lwp.pr_onpro, 7);
    499     0    stevel 				if (strcmp(lwp->li_info.pr_lwp.pr_clname,
    500     0    stevel 				    "RT") == 0 ||
    501     0    stevel 				    strcmp(lwp->li_info.pr_lwp.pr_clname,
    502     0    stevel 				    "SYS") == 0 ||
    503     0    stevel 				    lwp->li_info.pr_lwp.pr_sname == 'Z')
    504     0    stevel 					(void) strcpy(pnice, "  -");
    505     0    stevel 				else
    506     0    stevel 					Format_num(pnice,
    507     0    stevel 					    lwp->li_info.pr_lwp.pr_nice - NZERO,
    508     0    stevel 					    4);
    509     0    stevel 				Format_num(ppri, lwp->li_info.pr_lwp.pr_pri, 4);
    510     0    stevel 				Format_pct(pcpu,
    511     0    stevel 				    FRC2PCT(lwp->li_info.pr_lwp.pr_pctcpu), 4);
    512     0    stevel 				if (opts.o_outpmode & OPT_LWPS)
    513     0    stevel 					Format_time(ptime,
    514     0    stevel 					    lwp->li_info.pr_lwp.pr_time.tv_sec,
    515     0    stevel 					    10);
    516     0    stevel 				else
    517     0    stevel 					Format_time(ptime,
    518     0    stevel 					    lwp->li_info.pr_time.tv_sec, 10);
    519     0    stevel 				if (opts.o_outpmode & OPT_TTY)
    520     0    stevel 					(void) putchar('\r');
    521     0    stevel 				stripfname(lwp->li_info.pr_fname);
    522  2685     akolb 				if (opts.o_outpmode & OPT_LGRP) {
    523  2685     akolb 					(void) printf(PSINFO_LINE_LGRP,
    524  2685     akolb 					    (int)lwp->li_info.pr_pid, pname,
    525  2685     akolb 					    psize, prssize, pstate, ppri, pnice,
    526  2685     akolb 					    ptime, pcpu,
    527  2685     akolb 					    (int)lwp->li_info.pr_lwp.pr_lgrp,
    528  2685     akolb 					    lwp->li_info.pr_fname, lwpid);
    529  2685     akolb 				} else {
    530  2685     akolb 					(void) printf(PSINFO_LINE,
    531  2685     akolb 					    (int)lwp->li_info.pr_pid, pname,
    532  2685     akolb 					    psize, prssize, pstate, ppri, pnice,
    533  2685     akolb 					    ptime, pcpu,
    534  2685     akolb 					    lwp->li_info.pr_fname, lwpid);
    535  2685     akolb 				}
    536     0    stevel 				(void) putp(t_eol);
    537     0    stevel 				(void) putchar('\n');
    538     0    stevel 			}
    539     0    stevel 			if (opts.o_outpmode & OPT_MSACCT) {
    540     0    stevel 				Format_pct(usr, lwp->li_usr, 4);
    541     0    stevel 				Format_pct(sys, lwp->li_sys, 4);
    542     0    stevel 				Format_pct(slp, lwp->li_slp, 4);
    543     0    stevel 				Format_num(vcx, lwp->li_vcx, 4);
    544     0    stevel 				Format_num(icx, lwp->li_icx, 4);
    545     0    stevel 				Format_num(scl, lwp->li_scl, 4);
    546     0    stevel 				Format_num(sig, lwp->li_sig, 4);
    547     0    stevel 				Format_pct(trp, lwp->li_trp, 4);
    548     0    stevel 				Format_pct(tfl, lwp->li_tfl, 4);
    549     0    stevel 				Format_pct(dfl, lwp->li_dfl, 4);
    550     0    stevel 				Format_pct(lck, lwp->li_lck, 4);
    551     0    stevel 				Format_pct(lat, lwp->li_lat, 4);
    552     0    stevel 				if (opts.o_outpmode & OPT_TTY)
    553     0    stevel 					(void) putchar('\r');
    554     0    stevel 				stripfname(lwp->li_info.pr_fname);
    555     0    stevel 				(void) printf(USAGE_LINE,
    556     0    stevel 				    (int)lwp->li_info.pr_pid, pname,
    557     0    stevel 				    usr, sys, trp, tfl, dfl, lck,
    558     0    stevel 				    slp, lat, vcx, icx, scl, sig,
    559     0    stevel 				    lwp->li_info.pr_fname, lwpid);
    560     0    stevel 				(void) putp(t_eol);
    561     0    stevel 				(void) putchar('\n');
    562     0    stevel 			}
    563     0    stevel 			break;
    564     0    stevel 		}
    565     0    stevel 	}
    566     0    stevel 
    567     0    stevel 	if (opts.o_outpmode & OPT_TTY)
    568     0    stevel 		(void) putchar('\r');
    569     0    stevel 	if (opts.o_outpmode & OPT_TERMCAP) {
    570     0    stevel 		switch (list->l_type) {
    571     0    stevel 		case LT_PROJECTS:
    572     0    stevel 		case LT_USERS:
    573     0    stevel 		case LT_TASKS:
    574     0    stevel 		case LT_ZONES:
    575     0    stevel 			while (i++ < opts.o_nbottom) {
    576     0    stevel 				(void) putp(t_eol);
    577     0    stevel 				(void) putchar('\n');
    578     0    stevel 			}
    579     0    stevel 			break;
    580     0    stevel 		case LT_LWPS:
    581     0    stevel 			while (i++ < opts.o_ntop) {
    582     0    stevel 				(void) putp(t_eol);
    583     0    stevel 				(void) putchar('\n');
    584     0    stevel 			}
    585     0    stevel 		}
    586     0    stevel 	}
    587     0    stevel 
    588     0    stevel 	if (opts.o_outpmode & OPT_TTY)
    589     0    stevel 		(void) putchar('\r');
    590     0    stevel 
    591     0    stevel 	if ((opts.o_outpmode & OPT_SPLIT) && list->l_type == LT_LWPS)
    592     0    stevel 		return;
    593     0    stevel 
    594     0    stevel 	(void) printf(TOTAL_LINE, total_procs, total_lwps,
    595     0    stevel 	    loadavg[LOADAVG_1MIN], loadavg[LOADAVG_5MIN],
    596     0    stevel 	    loadavg[LOADAVG_15MIN]);
    597     0    stevel 	(void) putp(t_eol);
    598     0    stevel 	(void) putchar('\n');
    599     0    stevel 	if (opts.o_outpmode & OPT_TTY)
    600     0    stevel 		(void) putchar('\r');
    601     0    stevel 	(void) putp(t_eol);
    602     0    stevel 	(void) fflush(stdout);
    603     0    stevel }
    604     0    stevel 
    605     0    stevel static lwp_info_t *
    606     0    stevel list_add_lwp(list_t *list, pid_t pid, id_t lwpid)
    607     0    stevel {
    608     0    stevel 	lwp_info_t *lwp;
    609     0    stevel 
    610     0    stevel 	if (list->l_head == NULL) {
    611     0    stevel 		list->l_head = list->l_tail = lwp = Zalloc(sizeof (lwp_info_t));
    612     0    stevel 	} else {
    613     0    stevel 		lwp = Zalloc(sizeof (lwp_info_t));
    614     0    stevel 		lwp->li_prev = list->l_tail;
    615     0    stevel 		((lwp_info_t *)list->l_tail)->li_next = lwp;
    616     0    stevel 		list->l_tail = lwp;
    617     0    stevel 	}
    618     0    stevel 	lwp->li_info.pr_pid = pid;
    619     0    stevel 	lwp->li_info.pr_lwp.pr_lwpid = lwpid;
    620     0    stevel 	lwpid_add(lwp, pid, lwpid);
    621     0    stevel 	list->l_count++;
    622     0    stevel 	return (lwp);
    623     0    stevel }
    624     0    stevel 
    625     0    stevel static void
    626     0    stevel list_remove_lwp(list_t *list, lwp_info_t *lwp)
    627     0    stevel {
    628     0    stevel 	if (lwp->li_prev)
    629     0    stevel 		lwp->li_prev->li_next = lwp->li_next;
    630     0    stevel 	else
    631     0    stevel 		list->l_head = lwp->li_next;	/* removing the head */
    632     0    stevel 	if (lwp->li_next)
    633     0    stevel 		lwp->li_next->li_prev = lwp->li_prev;
    634     0    stevel 	else
    635     0    stevel 		list->l_tail = lwp->li_prev;	/* removing the tail */
    636     0    stevel 	lwpid_del(lwp->li_info.pr_pid, lwp->li_info.pr_lwp.pr_lwpid);
    637     0    stevel 	if (lwpid_pidcheck(lwp->li_info.pr_pid) == 0)
    638     0    stevel 		fds_rm(lwp->li_info.pr_pid);
    639     0    stevel 	list->l_count--;
    640     0    stevel 	free(lwp);
    641     0    stevel }
    642     0    stevel 
    643     0    stevel static void
    644     0    stevel list_clear(list_t *list)
    645     0    stevel {
    646     0    stevel 	if (list->l_type == LT_LWPS) {
    647     0    stevel 		lwp_info_t	*lwp = list->l_tail;
    648     0    stevel 		lwp_info_t	*lwp_tmp;
    649     0    stevel 
    650     0    stevel 		fd_closeall();
    651     0    stevel 		while (lwp) {
    652     0    stevel 			lwp_tmp = lwp;
    653     0    stevel 			lwp = lwp->li_prev;
    654     0    stevel 			list_remove_lwp(&lwps, lwp_tmp);
    655     0    stevel 		}
    656     0    stevel 	} else {
    657     0    stevel 		id_info_t *id = list->l_head;
    658     0    stevel 		id_info_t *nextid;
    659     0    stevel 
    660     0    stevel 		while (id) {
    661     0    stevel 			nextid = id->id_next;
    662     0    stevel 			free(id);
    663     0    stevel 			id = nextid;
    664     0    stevel 		}
    665     0    stevel 		list->l_count = 0;
    666     0    stevel 		list->l_head = list->l_tail = NULL;
    667     0    stevel 	}
    668     0    stevel }
    669     0    stevel 
    670     0    stevel static void
    671     0    stevel list_update(list_t *list, lwp_info_t *lwp)
    672     0    stevel {
    673     0    stevel 	id_info_t *id;
    674     0    stevel 
    675     0    stevel 	if (list->l_head == NULL) {			/* first element */
    676     0    stevel 		list->l_head = list->l_tail = id = Zalloc(sizeof (id_info_t));
    677     0    stevel 		goto update;
    678     0    stevel 	}
    679     0    stevel 
    680     0    stevel 	for (id = list->l_head; id; id = id->id_next) {
    681     0    stevel 		if ((list->l_type == LT_USERS) &&
    682     0    stevel 		    (id->id_uid != lwp->li_info.pr_uid))
    683     0    stevel 			continue;
    684     0    stevel 		if ((list->l_type == LT_TASKS) &&
    685     0    stevel 		    (id->id_taskid != lwp->li_info.pr_taskid))
    686     0    stevel 			continue;
    687     0    stevel 		if ((list->l_type == LT_PROJECTS) &&
    688     0    stevel 		    (id->id_projid != lwp->li_info.pr_projid))
    689     0    stevel 			continue;
    690     0    stevel 		if ((list->l_type == LT_ZONES) &&
    691     0    stevel 		    (id->id_zoneid != lwp->li_info.pr_zoneid))
    692     0    stevel 			continue;
    693  2685     akolb 		if ((list->l_type == LT_LGRPS) &&
    694  2685     akolb 		    (id->id_lgroup != lwp->li_info.pr_lwp.pr_lgrp))
    695  2685     akolb 			continue;
    696     0    stevel 		id->id_nproc++;
    697     0    stevel 		id->id_taskid	= lwp->li_info.pr_taskid;
    698     0    stevel 		id->id_projid	= lwp->li_info.pr_projid;
    699     0    stevel 		id->id_zoneid	= lwp->li_info.pr_zoneid;
    700  2685     akolb 		id->id_lgroup	= lwp->li_info.pr_lwp.pr_lgrp;
    701  2685     akolb 
    702     0    stevel 		if (lwp->li_flags & LWP_REPRESENT) {
    703     0    stevel 			id->id_size	+= lwp->li_info.pr_size;
    704     0    stevel 			id->id_rssize	+= lwp->li_info.pr_rssize;
    705     0    stevel 		}
    706     0    stevel 		id->id_pctcpu	+= FRC2PCT(lwp->li_info.pr_lwp.pr_pctcpu);
    707     0    stevel 		if (opts.o_outpmode & OPT_LWPS)
    708     0    stevel 			id->id_time += TIME2SEC(lwp->li_info.pr_lwp.pr_time);
    709     0    stevel 		else
    710     0    stevel 			id->id_time += TIME2SEC(lwp->li_info.pr_time);
    711     0    stevel 		id->id_pctmem	+= FRC2PCT(lwp->li_info.pr_pctmem);
    712     0    stevel 		id->id_key	+= lwp->li_key;
    713     0    stevel 		total_cpu	+= FRC2PCT(lwp->li_info.pr_lwp.pr_pctcpu);
    714     0    stevel 		total_mem	+= FRC2PCT(lwp->li_info.pr_pctmem);
    715     0    stevel 		return;
    716     0    stevel 	}
    717     0    stevel 
    718     0    stevel 	id = list->l_tail;
    719     0    stevel 	id->id_next = Zalloc(sizeof (id_info_t));
    720     0    stevel 	id->id_next->id_prev = list->l_tail;
    721     0    stevel 	id->id_next->id_next = NULL;
    722     0    stevel 	list->l_tail = id->id_next;
    723     0    stevel 	id = list->l_tail;
    724     0    stevel update:
    725     0    stevel 	id->id_uid	= lwp->li_info.pr_uid;
    726     0    stevel 	id->id_projid	= lwp->li_info.pr_projid;
    727     0    stevel 	id->id_taskid	= lwp->li_info.pr_taskid;
    728     0    stevel 	id->id_zoneid	= lwp->li_info.pr_zoneid;
    729  2685     akolb 	id->id_lgroup	= lwp->li_info.pr_lwp.pr_lgrp;
    730     0    stevel 	id->id_nproc++;
    731  3247  gjelinek 	id->id_sizematch = B_FALSE;
    732     0    stevel 	if (lwp->li_flags & LWP_REPRESENT) {
    733     0    stevel 		id->id_size	= lwp->li_info.pr_size;
    734     0    stevel 		id->id_rssize	= lwp->li_info.pr_rssize;
    735     0    stevel 	}
    736     0    stevel 	id->id_pctcpu	= FRC2PCT(lwp->li_info.pr_lwp.pr_pctcpu);
    737     0    stevel 	if (opts.o_outpmode & OPT_LWPS)
    738     0    stevel 		id->id_time = TIME2SEC(lwp->li_info.pr_lwp.pr_time);
    739     0    stevel 	else
    740     0    stevel 		id->id_time = TIME2SEC(lwp->li_info.pr_time);
    741     0    stevel 	id->id_pctmem	= FRC2PCT(lwp->li_info.pr_pctmem);
    742     0    stevel 	id->id_key	= lwp->li_key;
    743     0    stevel 	total_cpu	+= id->id_pctcpu;
    744     0    stevel 	total_mem	+= id->id_pctmem;
    745     0    stevel 	list->l_count++;
    746     0    stevel }
    747     0    stevel 
    748     0    stevel static void
    749     0    stevel lwp_update(lwp_info_t *lwp, pid_t pid, id_t lwpid, struct prusage *usage)
    750     0    stevel {
    751     0    stevel 	float period;
    752     0    stevel 
    753     0    stevel 	if (!lwpid_is_active(pid, lwpid)) {
    754     0    stevel 		/*
    755     0    stevel 		 * If we are reading cpu times for the first time then
    756     0    stevel 		 * calculate average cpu times based on whole process
    757     0    stevel 		 * execution time.
    758     0    stevel 		 */
    759     0    stevel 		(void) memcpy(&lwp->li_usage, usage, sizeof (prusage_t));
    760     0    stevel 		period = TIME2NSEC(usage->pr_rtime);
    761     0    stevel 		period = period/(float)100;
    762     0    stevel 
    763     0    stevel 		if (period == 0) { /* zombie */
    764     0    stevel 			period = 1;
    765     0    stevel 			lwp->li_usr = 0;
    766     0    stevel 			lwp->li_sys = 0;
    767     0    stevel 			lwp->li_slp = 0;
    768     0    stevel 		} else {
    769     0    stevel 			lwp->li_usr = TIME2NSEC(usage->pr_utime)/period;
    770     0    stevel 			lwp->li_sys = TIME2NSEC(usage->pr_stime)/period;
    771     0    stevel 			lwp->li_slp = TIME2NSEC(usage->pr_slptime)/period;
    772     0    stevel 		}
    773     0    stevel 		lwp->li_trp = TIME2NSEC(usage->pr_ttime)/period;
    774     0    stevel 		lwp->li_tfl = TIME2NSEC(usage->pr_tftime)/period;
    775     0    stevel 		lwp->li_dfl = TIME2NSEC(usage->pr_dftime)/period;
    776     0    stevel 		lwp->li_lck = TIME2NSEC(usage->pr_ltime)/period;
    777     0    stevel 		lwp->li_lat = TIME2NSEC(usage->pr_wtime)/period;
    778     0    stevel 		period = (period / NANOSEC)*(float)100; /* now in seconds */
    779     0    stevel 		lwp->li_vcx = (ulong_t)
    780     0    stevel 		    (opts.o_interval * (usage->pr_vctx/period));
    781     0    stevel 		lwp->li_icx = (ulong_t)
    782     0    stevel 		    (opts.o_interval * (usage->pr_ictx/period));
    783     0    stevel 		lwp->li_scl = (ulong_t)
    784     0    stevel 		    (opts.o_interval * (usage->pr_sysc/period));
    785     0    stevel 		lwp->li_sig = (ulong_t)
    786     0    stevel 		    (opts.o_interval * (usage->pr_sigs/period));
    787     0    stevel 		(void) lwpid_set_active(pid, lwpid);
    788     0    stevel 	} else {
    789     0    stevel 		/*
    790     0    stevel 		 * If this is not a first time we are reading a process's
    791     0    stevel 		 * CPU times then recalculate CPU times based on fresh data
    792     0    stevel 		 * obtained from procfs and previous CPU time usage values.
    793     0    stevel 		 */
    794     0    stevel 		period = TIME2NSEC(usage->pr_rtime)-
    795     0    stevel 		    TIME2NSEC(lwp->li_usage.pr_rtime);
    796     0    stevel 		period = period/(float)100;
    797     0    stevel 
    798     0    stevel 		if (period == 0) { /* zombie */
    799     0    stevel 			period = 1;
    800     0    stevel 			lwp->li_usr = 0;
    801     0    stevel 			lwp->li_sys = 0;
    802     0    stevel 			lwp->li_slp = 0;
    803     0    stevel 		} else {
    804     0    stevel 			lwp->li_usr = (TIME2NSEC(usage->pr_utime)-
    805     0    stevel 			    TIME2NSEC(lwp->li_usage.pr_utime))/period;
    806     0    stevel 			lwp->li_sys = (TIME2NSEC(usage->pr_stime) -
    807     0    stevel 			    TIME2NSEC(lwp->li_usage.pr_stime))/period;
    808     0    stevel 			lwp->li_slp = (TIME2NSEC(usage->pr_slptime) -
    809     0    stevel 			    TIME2NSEC(lwp->li_usage.pr_slptime))/period;
    810     0    stevel 		}
    811     0    stevel 		lwp->li_trp = (TIME2NSEC(usage->pr_ttime) -
    812     0    stevel 		    TIME2NSEC(lwp->li_usage.pr_ttime))/period;
    813     0    stevel 		lwp->li_tfl = (TIME2NSEC(usage->pr_tftime) -
    814     0    stevel 		    TIME2NSEC(lwp->li_usage.pr_tftime))/period;
    815     0    stevel 		lwp->li_dfl = (TIME2NSEC(usage->pr_dftime) -
    816     0    stevel 		    TIME2NSEC(lwp->li_usage.pr_dftime))/period;
    817     0    stevel 		lwp->li_lck = (TIME2NSEC(usage->pr_ltime) -
    818     0    stevel 		    TIME2NSEC(lwp->li_usage.pr_ltime))/period;
    819     0    stevel 		lwp->li_lat = (TIME2NSEC(usage->pr_wtime) -
    820     0    stevel 		    TIME2NSEC(lwp->li_usage.pr_wtime))/period;
    821     0    stevel 		lwp->li_vcx = usage->pr_vctx - lwp->li_usage.pr_vctx;
    822     0    stevel 		lwp->li_icx = usage->pr_ictx - lwp->li_usage.pr_ictx;
    823     0    stevel 		lwp->li_scl = usage->pr_sysc - lwp->li_usage.pr_sysc;
    824     0    stevel 		lwp->li_sig = usage->pr_sigs - lwp->li_usage.pr_sigs;
    825     0    stevel 		(void) memcpy(&lwp->li_usage, usage, sizeof (prusage_t));
    826     0    stevel 	}
    827     0    stevel }
    828     0    stevel 
    829     0    stevel static int
    830     0    stevel read_procfile(fd_t **fd, char *pidstr, char *file, void *buf, size_t bufsize)
    831     0    stevel {
    832     0    stevel 	char procfile[MAX_PROCFS_PATH];
    833     0    stevel 
    834     0    stevel 	(void) snprintf(procfile, MAX_PROCFS_PATH,
    835     0    stevel 	    "/proc/%s/%s", pidstr, file);
    836     0    stevel 	if ((*fd = fd_open(procfile, O_RDONLY, *fd)) == NULL)
    837     0    stevel 		return (1);
    838     0    stevel 	if (pread(fd_getfd(*fd), buf, bufsize, 0) != bufsize) {
    839     0    stevel 		fd_close(*fd);
    840     0    stevel 		return (1);
    841     0    stevel 	}
    842     0    stevel 	return (0);
    843     0    stevel }
    844     0    stevel 
    845     0    stevel static void
    846     0    stevel add_proc(psinfo_t *psinfo)
    847     0    stevel {
    848     0    stevel 	lwp_info_t *lwp;
    849     0    stevel 	id_t lwpid;
    850     0    stevel 	pid_t pid = psinfo->pr_pid;
    851     0    stevel 
    852     0    stevel 	lwpid = psinfo->pr_lwp.pr_lwpid;
    853     0    stevel 	if ((lwp = lwpid_get(pid, lwpid)) == NULL)
    854     0    stevel 		lwp = list_add_lwp(&lwps, pid, lwpid);
    855     0    stevel 	lwp->li_flags |= LWP_ALIVE | LWP_REPRESENT;
    856     0    stevel 	(void) memcpy(&lwp->li_info, psinfo, sizeof (psinfo_t));
    857     0    stevel 	lwp->li_info.pr_lwp.pr_pctcpu = lwp->li_info.pr_pctcpu;
    858     0    stevel }
    859     0    stevel 
    860     0    stevel static void
    861     0    stevel add_lwp(psinfo_t *psinfo, lwpsinfo_t *lwpsinfo, int flags)
    862     0    stevel {
    863     0    stevel 	lwp_info_t *lwp;
    864     0    stevel 	pid_t pid = psinfo->pr_pid;
    865     0    stevel 	id_t lwpid = lwpsinfo->pr_lwpid;
    866     0    stevel 
    867     0    stevel 	if ((lwp = lwpid_get(pid, lwpid)) == NULL)
    868     0    stevel 		lwp = list_add_lwp(&lwps, pid, lwpid);
    869     0    stevel 	lwp->li_flags &= ~LWP_REPRESENT;
    870     0    stevel 	lwp->li_flags |= LWP_ALIVE;
    871     0    stevel 	lwp->li_flags |= flags;
    872     0    stevel 	(void) memcpy(&lwp->li_info, psinfo,
    873     0    stevel 	    sizeof (psinfo_t) - sizeof (lwpsinfo_t));
    874     0    stevel 	(void) memcpy(&lwp->li_info.pr_lwp, lwpsinfo, sizeof (lwpsinfo_t));
    875     0    stevel }
    876     0    stevel 
    877     0    stevel static void
    878     0    stevel prstat_scandir(DIR *procdir)
    879     0    stevel {
    880     0    stevel 	char *pidstr;
    881     0    stevel 	pid_t pid;
    882     0    stevel 	id_t lwpid;
    883     0    stevel 	size_t entsz;
    884     0    stevel 	long nlwps, nent, i;
    885     0    stevel 	char *buf, *ptr;
    886     0    stevel 
    887     0    stevel 	fds_t *fds;
    888     0    stevel 	lwp_info_t *lwp;
    889     0    stevel 	dirent_t *direntp;
    890     0    stevel 
    891     0    stevel 	prheader_t	header;
    892     0    stevel 	psinfo_t	psinfo;
    893     0    stevel 	prusage_t	usage;
    894     0    stevel 	lwpsinfo_t	*lwpsinfo;
    895     0    stevel 	prusage_t	*lwpusage;
    896     0    stevel 
    897     0    stevel 	total_procs = 0;
    898     0    stevel 	total_lwps = 0;
    899     0    stevel 	total_cpu = 0;
    900     0    stevel 	total_mem = 0;
    901     0    stevel 
    902     0    stevel 	convert_zone(&zone_tbl);
    903     0    stevel 	for (rewinddir(procdir); (direntp = readdir(procdir)); ) {
    904     0    stevel 		pidstr = direntp->d_name;
    905     0    stevel 		if (pidstr[0] == '.')	/* skip "." and ".."  */
    906     0    stevel 			continue;
    907     0    stevel 		pid = atoi(pidstr);
    908     0    stevel 		if (pid == 0 || pid == 2 || pid == 3)
    909     0    stevel 			continue;	/* skip sched, pageout and fsflush */
    910     0    stevel 		if (has_element(&pid_tbl, pid) == 0)
    911     0    stevel 			continue;	/* check if we really want this pid */
    912     0    stevel 		fds = fds_get(pid);	/* get ptr to file descriptors */
    913     0    stevel 
    914     0    stevel 		if (read_procfile(&fds->fds_psinfo, pidstr,
    915     0    stevel 		    "psinfo", &psinfo, sizeof (psinfo_t)) != 0)
    916     0    stevel 			continue;
    917     0    stevel 		if (!has_uid(&ruid_tbl, psinfo.pr_uid) ||
    918     0    stevel 		    !has_uid(&euid_tbl, psinfo.pr_euid) ||
    919     0    stevel 		    !has_element(&prj_tbl, psinfo.pr_projid) ||
    920     0    stevel 		    !has_element(&tsk_tbl, psinfo.pr_taskid) ||
    921     0    stevel 		    !has_zone(&zone_tbl, psinfo.pr_zoneid)) {
    922     0    stevel 			fd_close(fds->fds_psinfo);
    923     0    stevel 			continue;
    924     0    stevel 		}
    925     0    stevel 		nlwps = psinfo.pr_nlwp + psinfo.pr_nzomb;
    926     0    stevel 
    927     0    stevel 		if (nlwps > 1 && (opts.o_outpmode & (OPT_LWPS | OPT_PSETS))) {
    928     0    stevel 			int rep_lwp = 0;
    929     0    stevel 
    930     0    stevel 			if (read_procfile(&fds->fds_lpsinfo, pidstr, "lpsinfo",
    931     0    stevel 			    &header, sizeof (prheader_t)) != 0) {
    932     0    stevel 				fd_close(fds->fds_psinfo);
    933     0    stevel 				continue;
    934     0    stevel 			}
    935     0    stevel 
    936     0    stevel 			nent = header.pr_nent;
    937     0    stevel 			entsz = header.pr_entsize * nent;
    938     0    stevel 			ptr = buf = Malloc(entsz);
    939     0    stevel 			if (pread(fd_getfd(fds->fds_lpsinfo), buf,
    940     0    stevel 			    entsz, sizeof (struct prheader)) != entsz) {
    941     0    stevel 				fd_close(fds->fds_lpsinfo);
    942     0    stevel 				fd_close(fds->fds_psinfo);
    943     0    stevel 				free(buf);
    944     0    stevel 				continue;
    945     0    stevel 			}
    946     0    stevel 
    947     0    stevel 			nlwps = 0;
    948     0    stevel 			for (i = 0; i < nent; i++, ptr += header.pr_entsize) {
    949     0    stevel 				/*LINTED ALIGNMENT*/
    950     0    stevel 				lwpsinfo = (lwpsinfo_t *)ptr;
    951     0    stevel 				if (!has_element(&cpu_tbl,
    952     0    stevel 				    lwpsinfo->pr_onpro) ||
    953     0    stevel 				    !has_element(&set_tbl,
    954  2685     akolb 				    lwpsinfo->pr_bindpset) ||
    955  9123      john 				    !has_element(&lgr_tbl, lwpsinfo->pr_lgrp))
    956     0    stevel 					continue;
    957     0    stevel 				nlwps++;
    958     0    stevel 				if ((opts.o_outpmode & (OPT_PSETS | OPT_LWPS))
    959     0    stevel 				    == OPT_PSETS) {
    960     0    stevel 					/*
    961     0    stevel 					 * If one of process's LWPs is bound
    962     0    stevel 					 * to a given processor set, report the
    963     0    stevel 					 * whole process.  We may be doing this
    964     0    stevel 					 * a few times but we'll get an accurate
    965     0    stevel 					 * lwp count in return.
    966     0    stevel 					 */
    967     0    stevel 					add_proc(&psinfo);
    968     0    stevel 				} else {
    969     0    stevel 					if (rep_lwp == 0) {
    970     0    stevel 						rep_lwp = 1;
    971     0    stevel 						add_lwp(&psinfo, lwpsinfo,
    972     0    stevel 						    LWP_REPRESENT);
    973     0    stevel 					} else {
    974     0    stevel 						add_lwp(&psinfo, lwpsinfo, 0);
    975     0    stevel 					}
    976     0    stevel 				}
    977     0    stevel 			}
    978     0    stevel 			free(buf);
    979     0    stevel 			if (nlwps == 0) {
    980     0    stevel 				fd_close(fds->fds_lpsinfo);
    981     0    stevel 				fd_close(fds->fds_psinfo);
    982     0    stevel 				continue;
    983     0    stevel 			}
    984     0    stevel 		} else {
    985     0    stevel 			if (!has_element(&cpu_tbl, psinfo.pr_lwp.pr_onpro) ||
    986  2685     akolb 			    !has_element(&set_tbl, psinfo.pr_lwp.pr_bindpset) ||
    987  2685     akolb 			    !has_element(&lgr_tbl, psinfo.pr_lwp.pr_lgrp)) {
    988     0    stevel 				fd_close(fds->fds_psinfo);
    989     0    stevel 				continue;
    990     0    stevel 			}
    991     0    stevel 			add_proc(&psinfo);
    992     0    stevel 		}
    993     0    stevel 		if (!(opts.o_outpmode & OPT_MSACCT)) {
    994     0    stevel 			total_procs++;
    995     0    stevel 			total_lwps += nlwps;
    996     0    stevel 			continue;
    997     0    stevel 		}
    998     0    stevel 		/*
    999     0    stevel 		 * Get more information about processes from /proc/pid/usage.
   1000     0    stevel 		 * If process has more than one lwp, then we may have to
   1001     0    stevel 		 * also look at the /proc/pid/lusage file.
   1002     0    stevel 		 */
   1003     0    stevel 		if ((opts.o_outpmode & OPT_LWPS) && (nlwps > 1)) {
   1004     0    stevel 			if (read_procfile(&fds->fds_lusage, pidstr, "lusage",
   1005     0    stevel 			    &header, sizeof (prheader_t)) != 0) {
   1006     0    stevel 				fd_close(fds->fds_lpsinfo);
   1007     0    stevel 				fd_close(fds->fds_psinfo);
   1008     0    stevel 				continue;
   1009     0    stevel 			}
   1010     0    stevel 			nent = header.pr_nent;
   1011     0    stevel 			entsz = header.pr_entsize * nent;
   1012     0    stevel 			buf = Malloc(entsz);
   1013     0    stevel 			if (pread(fd_getfd(fds->fds_lusage), buf,
   1014     0    stevel 			    entsz, sizeof (struct prheader)) != entsz) {
   1015     0    stevel 				fd_close(fds->fds_lusage);
   1016     0    stevel 				fd_close(fds->fds_lpsinfo);
   1017     0    stevel 				fd_close(fds->fds_psinfo);
   1018     0    stevel 				free(buf);
   1019     0    stevel 				continue;
   1020     0    stevel 			}
   1021     0    stevel 			for (i = 1, ptr = buf + header.pr_entsize; i < nent;
   1022     0    stevel 			    i++, ptr += header.pr_entsize) {
   1023     0    stevel 				/*LINTED ALIGNMENT*/
   1024     0    stevel 				lwpusage = (prusage_t *)ptr;
   1025     0    stevel 				lwpid = lwpusage->pr_lwpid;
   1026     0    stevel 				/*
   1027     0    stevel 				 * New LWPs created after we read lpsinfo
   1028     0    stevel 				 * will be ignored.  Don't want to do
   1029     0    stevel 				 * everything all over again.
   1030     0    stevel 				 */
   1031     0    stevel 				if ((lwp = lwpid_get(pid, lwpid)) == NULL)
   1032     0    stevel 					continue;
   1033     0    stevel 				lwp_update(lwp, pid, lwpid, lwpusage);
   1034     0    stevel 			}
   1035     0    stevel 			free(buf);
   1036     0    stevel 		} else {
   1037     0    stevel 			if (read_procfile(&fds->fds_usage, pidstr, "usage",
   1038     0    stevel 			    &usage, sizeof (prusage_t)) != 0) {
   1039     0    stevel 				fd_close(fds->fds_lpsinfo);
   1040     0    stevel 				fd_close(fds->fds_psinfo);
   1041     0    stevel 				continue;
   1042     0    stevel 			}
   1043     0    stevel 			lwpid = psinfo.pr_lwp.pr_lwpid;
   1044     0    stevel 			if ((lwp = lwpid_get(pid, lwpid)) == NULL)
   1045     0    stevel 				continue;
   1046     0    stevel 			lwp_update(lwp, pid, lwpid, &usage);
   1047     0    stevel 		}
   1048     0    stevel 		total_procs++;
   1049     0    stevel 		total_lwps += nlwps;
   1050     0    stevel 	}
   1051     0    stevel 	fd_update();
   1052     0    stevel }
   1053     0    stevel 
   1054     0    stevel /*
   1055     0    stevel  * This procedure removes all dead lwps from the linked list of all lwps.
   1056     0    stevel  * It also creates linked list of ids if necessary.
   1057     0    stevel  */
   1058     0    stevel static void
   1059     0    stevel list_refresh(list_t *list)
   1060     0    stevel {
   1061     0    stevel 	lwp_info_t *lwp, *lwp_next;
   1062     0    stevel 
   1063     0    stevel 	if (!(list->l_type & LT_LWPS))
   1064     0    stevel 		return;
   1065     0    stevel 
   1066     0    stevel 	for (lwp = list->l_head; lwp != NULL; ) {
   1067     0    stevel 		if (lwp->li_flags & LWP_ALIVE) {
   1068     0    stevel 			/*
   1069     0    stevel 			 * Process all live LWPs.
   1070     0    stevel 			 * When we're done, mark them as dead.
   1071     0    stevel 			 * They will be marked "alive" on the next
   1072     0    stevel 			 * /proc scan if they still exist.
   1073     0    stevel 			 */
   1074     0    stevel 			lwp->li_key = list_getkeyval(list, lwp);
   1075     0    stevel 			if (opts.o_outpmode & OPT_USERS)
   1076     0    stevel 				list_update(&users, lwp);
   1077     0    stevel 			if (opts.o_outpmode & OPT_TASKS)
   1078     0    stevel 				list_update(&tasks, lwp);
   1079     0    stevel 			if (opts.o_outpmode & OPT_PROJECTS)
   1080     0    stevel 				list_update(&projects, lwp);
   1081     0    stevel 			if (opts.o_outpmode & OPT_ZONES)
   1082     0    stevel 				list_update(&zones, lwp);
   1083  2685     akolb 			if (opts.o_outpmode & OPT_LGRP)
   1084  2685     akolb 				list_update(&lgroups, lwp);
   1085     0    stevel 			lwp->li_flags &= ~LWP_ALIVE;
   1086     0    stevel 			lwp = lwp->li_next;
   1087     0    stevel 
   1088     0    stevel 		} else {
   1089     0    stevel 			lwp_next = lwp->li_next;
   1090     0    stevel 			list_remove_lwp(&lwps, lwp);
   1091     0    stevel 			lwp = lwp_next;
   1092     0    stevel 		}
   1093     0    stevel 	}
   1094     0    stevel }
   1095     0    stevel 
   1096     0    stevel static void
   1097     0    stevel curses_on()
   1098     0    stevel {
   1099     0    stevel 	if ((opts.o_outpmode & OPT_TERMCAP) && (is_curses_on == FALSE)) {
   1100     0    stevel 		(void) initscr();
   1101     0    stevel 		(void) nonl();
   1102     0    stevel 		(void) putp(t_smcup);
   1103     0    stevel 		is_curses_on = TRUE;
   1104     0    stevel 	}
   1105     0    stevel }
   1106     0    stevel 
   1107     0    stevel static void
   1108     0    stevel curses_off()
   1109     0    stevel {
   1110     0    stevel 	if ((is_curses_on == TRUE) && (opts.o_outpmode & OPT_TERMCAP)) {
   1111     0    stevel 		(void) putp(t_rmcup);
   1112     0    stevel 		(void) endwin();
   1113     0    stevel 		is_curses_on = FALSE;
   1114     0    stevel 	}
   1115     0    stevel 	(void) fflush(stdout);
   1116     0    stevel }
   1117     0    stevel 
   1118     0    stevel static int
   1119     0    stevel nlines()
   1120     0    stevel {
   1121     0    stevel 	struct winsize ws;
   1122     0    stevel 	char *envp;
   1123     0    stevel 	int n;
   1124     0    stevel 	if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != -1) {
   1125     0    stevel 		if (ws.ws_row > 0)
   1126     0    stevel 			return (ws.ws_row);
   1127     0    stevel 	}
   1128     0    stevel 	if (envp = getenv("LINES")) {
   1129     0    stevel 		if ((n = Atoi(envp)) > 0) {
   1130     0    stevel 			opts.o_outpmode &= ~OPT_USEHOME;
   1131     0    stevel 			return (n);
   1132     0    stevel 		}
   1133     0    stevel 	}
   1134     0    stevel 	return (-1);
   1135     0    stevel }
   1136     0    stevel 
   1137     0    stevel static void
   1138     0    stevel setmovecur()
   1139     0    stevel {
   1140     0    stevel 	int i, n;
   1141     0    stevel 	if ((opts.o_outpmode & OPT_FULLSCREEN) &&
   1142     0    stevel 	    (opts.o_outpmode & OPT_USEHOME)) {
   1143     0    stevel 		movecur = t_home;
   1144     0    stevel 		return;
   1145     0    stevel 	}
   1146     0    stevel 	if (opts.o_outpmode & OPT_SPLIT) {
   1147     0    stevel 		n = opts.o_ntop + opts.o_nbottom + 2;
   1148     0    stevel 	} else {
   1149     0    stevel 		if (opts.o_outpmode & OPT_USERS)
   1150     0    stevel 			n = opts.o_nbottom + 1;
   1151     0    stevel 		else
   1152     0    stevel 			n = opts.o_ntop + 1;
   1153     0    stevel 	}
   1154  9123      john 	if (((opts.o_outpmode & OPT_UDATE) || (opts.o_outpmode & OPT_DDATE)))
   1155  9123      john 		n++;
   1156  9123      john 
   1157     0    stevel 	if (movecur != NULL && movecur != empty_string && movecur != t_home)
   1158     0    stevel 		free(movecur);
   1159     0    stevel 	movecur = Zalloc(strlen(t_up) * (n + 5));
   1160     0    stevel 	for (i = 0; i <= n; i++)
   1161     0    stevel 		(void) strcat(movecur, t_up);
   1162     0    stevel }
   1163     0    stevel 
   1164     0    stevel static int
   1165     0    stevel setsize()
   1166     0    stevel {
   1167     0    stevel 	static int oldn = 0;
   1168     0    stevel 	int n;
   1169     0    stevel 
   1170     0    stevel 	if (opts.o_outpmode & OPT_FULLSCREEN) {
   1171     0    stevel 		n = nlines();
   1172     0    stevel 		if (n == oldn)
   1173     0    stevel 			return (0);
   1174     0    stevel 		oldn = n;
   1175     0    stevel 		if (n == -1) {
   1176     0    stevel 			opts.o_outpmode &= ~OPT_USEHOME;
   1177     0    stevel 			setmovecur();		/* set default window size */
   1178     0    stevel 			return (1);
   1179     0    stevel 		}
   1180     0    stevel 		n = n - 3;	/* minus header, total and cursor lines */
   1181  9123      john 		if ((opts.o_outpmode & OPT_UDATE) ||
   1182  9123      john 		    (opts.o_outpmode & OPT_DDATE))
   1183  9123      john 			n--;	/* minus timestamp */
   1184     0    stevel 		if (n < 1)
   1185     0    stevel 			Die(gettext("window is too small (try -n)\n"));
   1186     0    stevel 		if (opts.o_outpmode & OPT_SPLIT) {
   1187     0    stevel 			if (n < 8) {
   1188     0    stevel 				Die(gettext("window is too small (try -n)\n"));
   1189     0    stevel 			} else {
   1190     0    stevel 				opts.o_ntop = (n / 4) * 3;
   1191     0    stevel 				opts.o_nbottom = n - 1 - opts.o_ntop;
   1192     0    stevel 			}
   1193     0    stevel 		} else {
   1194     0    stevel 			if (opts.o_outpmode & OPT_USERS)
   1195     0    stevel 				opts.o_nbottom = n;
   1196     0    stevel 			else
   1197     0    stevel 				opts.o_ntop = n;
   1198     0    stevel 		}
   1199     0    stevel 	}
   1200     0    stevel 	setmovecur();
   1201     0    stevel 	return (1);
   1202     0    stevel }
   1203     0    stevel 
   1204     0    stevel static void
   1205     0    stevel ldtermcap()
   1206     0    stevel {
   1207     0    stevel 	int err;
   1208     0    stevel 	if (setupterm(NULL, STDIN_FILENO, &err) == ERR) {
   1209     0    stevel 		switch (err) {
   1210     0    stevel 		case 0:
   1211     0    stevel 			Warn(gettext("failed to load terminal info, "
   1212     0    stevel 			    "defaulting to -c option\n"));
   1213     0    stevel 			break;
   1214     0    stevel 		case -1:
   1215     0    stevel 			Warn(gettext("terminfo database not found, "
   1216     0    stevel 			    "defaulting to -c option\n"));
   1217     0    stevel 			break;
   1218     0    stevel 		default:
   1219     0    stevel 			Warn(gettext("failed to initialize terminal, "
   1220     0    stevel 			    "defaulting to -c option\n"));
   1221     0    stevel 		}
   1222     0    stevel 		opts.o_outpmode &= ~OPT_TERMCAP;
   1223     0    stevel 		t_up = t_eol = t_smcup = t_rmcup = movecur = empty_string;
   1224     0    stevel 		t_ulon = t_uloff = empty_string;
   1225     0    stevel 		return;
   1226     0    stevel 	}
   1227     0    stevel 	t_ulon	= tigetstr("smul");
   1228     0    stevel 	t_uloff	= tigetstr("rmul");
   1229     0    stevel 	t_up	= tigetstr("cuu1");
   1230     0    stevel 	t_eol	= tigetstr("el");
   1231     0    stevel 	t_smcup	= tigetstr("smcup");
   1232     0    stevel 	t_rmcup = tigetstr("rmcup");
   1233     0    stevel 	t_home  = tigetstr("home");
   1234     0    stevel 	if ((t_up == (char *)-1) || (t_eol == (char *)-1) ||
   1235     0    stevel 	    (t_smcup == (char *)-1) || (t_rmcup == (char *)-1)) {
   1236     0    stevel 		opts.o_outpmode &= ~OPT_TERMCAP;
   1237     0    stevel 		t_up = t_eol = t_smcup = t_rmcup = movecur = empty_string;
   1238     0    stevel 		return;
   1239     0    stevel 	}
   1240     0    stevel 	if (t_up == NULL || t_eol == NULL) {
   1241     0    stevel 		opts.o_outpmode &= ~OPT_TERMCAP;
   1242     0    stevel 		t_eol = t_up = movecur = empty_string;
   1243     0    stevel 		return;
   1244     0    stevel 	}
   1245     0    stevel 	if (t_ulon == (char *)-1 || t_uloff == (char *)-1 ||
   1246     0    stevel 	    t_ulon == NULL || t_uloff == NULL) {
   1247     0    stevel 		t_ulon = t_uloff = empty_string;  /* can live without it */
   1248     0    stevel 	}
   1249     0    stevel 	if (t_smcup == NULL || t_rmcup == NULL)
   1250     0    stevel 		t_smcup = t_rmcup = empty_string;
   1251     0    stevel 	if (t_home == (char *)-1 || t_home == NULL) {
   1252     0    stevel 		opts.o_outpmode &= ~OPT_USEHOME;
   1253     0    stevel 		t_home = empty_string;
   1254     0    stevel 	}
   1255     0    stevel }
   1256     0    stevel 
   1257     0    stevel static void
   1258     0    stevel sig_handler(int sig)
   1259     0    stevel {
   1260     0    stevel 	switch (sig) {
   1261     0    stevel 	case SIGTSTP:	sigtstp = 1;
   1262     0    stevel 			break;
   1263     0    stevel 	case SIGWINCH:	sigwinch = 1;
   1264     0    stevel 			break;
   1265     0    stevel 	case SIGINT:
   1266     0    stevel 	case SIGTERM:	sigterm = 1;
   1267     0    stevel 			break;
   1268     0    stevel 	}
   1269     0    stevel }
   1270     0    stevel 
   1271     0    stevel static void
   1272     0    stevel set_signals()
   1273     0    stevel {
   1274     0    stevel 	(void) signal(SIGTSTP, sig_handler);
   1275     0    stevel 	(void) signal(SIGINT, sig_handler);
   1276     0    stevel 	(void) signal(SIGTERM, sig_handler);
   1277     0    stevel 	if (opts.o_outpmode & OPT_FULLSCREEN)
   1278     0    stevel 		(void) signal(SIGWINCH, sig_handler);
   1279     0    stevel }
   1280     0    stevel 
   1281     0    stevel static void
   1282   586  vb160487 fill_table(table_t *table, char *arg, char option)
   1283     0    stevel {
   1284     0    stevel 	char *p = strtok(arg, ", ");
   1285     0    stevel 
   1286   586  vb160487 	if (p == NULL)
   1287   586  vb160487 		Die(gettext("invalid argument for -%c\n"), option);
   1288   586  vb160487 
   1289   586  vb160487 	add_element(table, (long)Atoi(p));
   1290   586  vb160487 	while (p = strtok(NULL, ", "))
   1291   586  vb160487 		add_element(table, (long)Atoi(p));
   1292     0    stevel }
   1293     0    stevel 
   1294     0    stevel static void
   1295     0    stevel fill_prj_table(char *arg)
   1296     0    stevel {
   1297     0    stevel 	projid_t projid;
   1298     0    stevel 	char *p = strtok(arg, ", ");
   1299   586  vb160487 
   1300   586  vb160487 	if (p == NULL)
   1301   586  vb160487 		Die(gettext("invalid argument for -j\n"));
   1302     0    stevel 
   1303     0    stevel 	if ((projid = getprojidbyname(p)) == -1)
   1304     0    stevel 		projid = Atoi(p);
   1305     0    stevel 	add_element(&prj_tbl, (long)projid);
   1306     0    stevel 
   1307     0    stevel 	while (p = strtok(NULL, ", ")) {
   1308     0    stevel 		if ((projid = getprojidbyname(p)) == -1)
   1309     0    stevel 			projid = Atoi(p);
   1310     0    stevel 		add_element(&prj_tbl, (long)projid);
   1311     0    stevel 	}
   1312     0    stevel }
   1313     0    stevel 
   1314     0    stevel static void
   1315     0    stevel fill_set_table(char *arg)
   1316     0    stevel {
   1317     0    stevel 	char *p = strtok(arg, ", ");
   1318     0    stevel 	psetid_t id;
   1319   586  vb160487 
   1320   586  vb160487 	if (p == NULL)
   1321   586  vb160487 		Die(gettext("invalid argument for -C\n"));
   1322     0    stevel 
   1323     0    stevel 	if ((id = Atoi(p)) == 0)
   1324     0    stevel 		id = PS_NONE;
   1325     0    stevel 	add_element(&set_tbl, id);
   1326     0    stevel 	while (p = strtok(NULL, ", ")) {
   1327     0    stevel 		if ((id = Atoi(p)) == 0)
   1328     0    stevel 			id = PS_NONE;
   1329     0    stevel 		if (!has_element(&set_tbl, id))
   1330     0    stevel 			add_element(&set_tbl, id);
   1331     0    stevel 	}
   1332     0    stevel }
   1333     0    stevel 
   1334     0    stevel static void
   1335     0    stevel Exit()
   1336     0    stevel {
   1337     0    stevel 	curses_off();
   1338     0    stevel 	list_clear(&lwps);
   1339     0    stevel 	list_clear(&users);
   1340     0    stevel 	list_clear(&tasks);
   1341     0    stevel 	list_clear(&projects);
   1342     0    stevel 	list_clear(&zones);
   1343     0    stevel 	fd_exit();
   1344     0    stevel }
   1345     0    stevel 
   1346  3247  gjelinek 
   1347     0    stevel int
   1348     0    stevel main(int argc, char **argv)
   1349     0    stevel {
   1350     0    stevel 	DIR *procdir;
   1351     0    stevel 	char *p;
   1352     0    stevel 	char *sortk = "cpu";	/* default sort key */
   1353     0    stevel 	int opt;
   1354     0    stevel 	int timeout;
   1355     0    stevel 	struct pollfd pollset;
   1356     0    stevel 	char key;
   1357     0    stevel 
   1358     0    stevel 	(void) setlocale(LC_ALL, "");
   1359     0    stevel 	(void) textdomain(TEXT_DOMAIN);
   1360     0    stevel 	Progname(argv[0]);
   1361     0    stevel 	lwpid_init();
   1362     0    stevel 	fd_init(Setrlimit());
   1363  3247  gjelinek 
   1364  3247  gjelinek 	pagesize = sysconf(_SC_PAGESIZE);
   1365     0    stevel 
   1366  9123      john 	while ((opt = getopt(argc, argv,
   1367  9966     Menno 	    "vcd:HmarRLtu:U:n:p:C:P:h:s:S:j:k:TJz:Z")) != (int)EOF) {
   1368     0    stevel 		switch (opt) {
   1369  9966     Menno 		case 'r':
   1370  9966     Menno 			opts.o_outpmode |= OPT_NORESOLVE;
   1371  9966     Menno 			break;
   1372     0    stevel 		case 'R':
   1373     0    stevel 			opts.o_outpmode |= OPT_REALTIME;
   1374     0    stevel 			break;
   1375     0    stevel 		case 'c':
   1376     0    stevel 			opts.o_outpmode &= ~OPT_TERMCAP;
   1377     0    stevel 			opts.o_outpmode &= ~OPT_FULLSCREEN;
   1378  9123      john 			break;
   1379  9123      john 		case 'd':
   1380  9123      john 			if (optarg) {
   1381  9123      john 				if (*optarg == 'u')
   1382  9123      john 					opts.o_outpmode |= OPT_UDATE;
   1383  9123      john 				else if (*optarg == 'd')
   1384  9123      john 					opts.o_outpmode |= OPT_DDATE;
   1385  9123      john 				else
   1386  9123      john 					Usage();
   1387  9123      john 			} else {
   1388  9123      john 				Usage();
   1389  9123      john 			}
   1390  2685     akolb 			break;
   1391  2685     akolb 		case 'h':
   1392  2685     akolb 			fill_table(&lgr_tbl, optarg, 'h');
   1393  2685     akolb 			break;
   1394  2685     akolb 		case 'H':
   1395  2685     akolb 			opts.o_outpmode |= OPT_LGRP;
   1396     0    stevel 			break;
   1397     0    stevel 		case 'm':
   1398     0    stevel 		case 'v':
   1399     0    stevel 			opts.o_outpmode &= ~OPT_PSINFO;
   1400     0    stevel 			opts.o_outpmode |=  OPT_MSACCT;
   1401     0    stevel 			break;
   1402     0    stevel 		case 't':
   1403     0    stevel 			opts.o_outpmode &= ~OPT_PSINFO;
   1404     0    stevel 			opts.o_outpmode |= OPT_USERS;
   1405     0    stevel 			break;
   1406     0    stevel 		case 'a':
   1407     0    stevel 			opts.o_outpmode |= OPT_SPLIT | OPT_USERS;
   1408     0    stevel 			break;
   1409     0    stevel 		case 'T':
   1410     0    stevel 			opts.o_outpmode |= OPT_SPLIT | OPT_TASKS;
   1411     0    stevel 			break;
   1412     0    stevel 		case 'J':
   1413     0    stevel 			opts.o_outpmode |= OPT_SPLIT | OPT_PROJECTS;
   1414     0    stevel 			break;
   1415     0    stevel 		case 'n':
   1416   586  vb160487 			if ((p = strtok(optarg, ",")) == NULL)
   1417   586  vb160487 				Die(gettext("invalid argument for -n\n"));
   1418     0    stevel 			opts.o_ntop = Atoi(p);
   1419     0    stevel 			if (p = strtok(NULL, ","))
   1420     0    stevel 				opts.o_nbottom = Atoi(p);
   1421     0    stevel 			opts.o_outpmode &= ~OPT_FULLSCREEN;
   1422     0    stevel 			break;
   1423     0    stevel 		case 's':
   1424     0    stevel 			opts.o_sortorder = -1;
   1425     0    stevel 			sortk = optarg;
   1426     0    stevel 			break;
   1427     0    stevel 		case 'S':
   1428     0    stevel 			opts.o_sortorder = 1;
   1429     0    stevel 			sortk = optarg;
   1430     0    stevel 			break;
   1431     0    stevel 		case 'u':
   1432   586  vb160487 			if ((p = strtok(optarg, ", ")) == NULL)
   1433   586  vb160487 				Die(gettext("invalid argument for -u\n"));
   1434     0    stevel 			add_uid(&euid_tbl, p);
   1435     0    stevel 			while (p = strtok(NULL, ", "))
   1436     0    stevel 				add_uid(&euid_tbl, p);
   1437     0    stevel 			break;
   1438     0    stevel 		case 'U':
   1439   586  vb160487 			if ((p = strtok(optarg, ", ")) == NULL)
   1440   586  vb160487 				Die(gettext("invalid argument for -U\n"));
   1441     0    stevel 			add_uid(&ruid_tbl, p);
   1442     0    stevel 			while (p = strtok(NULL, ", "))
   1443     0    stevel 				add_uid(&ruid_tbl, p);
   1444     0    stevel 			break;
   1445     0    stevel 		case 'p':
   1446   586  vb160487 			fill_table(&pid_tbl, optarg, 'p');
   1447     0    stevel 			break;
   1448     0    stevel 		case 'C':
   1449     0    stevel 			fill_set_table(optarg);
   1450     0    stevel 			opts.o_outpmode |= OPT_PSETS;
   1451     0    stevel 			break;
   1452     0    stevel 		case 'P':
   1453   586  vb160487 			fill_table(&cpu_tbl, optarg, 'P');
   1454     0    stevel 			break;
   1455     0    stevel 		case 'k':
   1456   586  vb160487 			fill_table(&tsk_tbl, optarg, 'k');
   1457     0    stevel 			break;
   1458     0    stevel 		case 'j':
   1459     0    stevel 			fill_prj_table(optarg);
   1460     0    stevel 			break;
   1461     0    stevel 		case 'L':
   1462     0    stevel 			opts.o_outpmode |= OPT_LWPS;
   1463     0    stevel 			break;
   1464     0    stevel 		case 'z':
   1465   586  vb160487 			if ((p = strtok(optarg, ", ")) == NULL)
   1466   586  vb160487 				Die(gettext("invalid argument for -z\n"));
   1467     0    stevel 			add_zone(&zone_tbl, p);
   1468     0    stevel 			while (p = strtok(NULL, ", "))
   1469     0    stevel 				add_zone(&zone_tbl, p);
   1470     0    stevel 			break;
   1471     0    stevel 		case 'Z':
   1472     0    stevel 			opts.o_outpmode |= OPT_SPLIT | OPT_ZONES;
   1473     0    stevel 			break;
   1474     0    stevel 		default:
   1475     0    stevel 			Usage();
   1476     0    stevel 		}
   1477     0    stevel 	}
   1478     0    stevel 
   1479     0    stevel 	(void) atexit(Exit);
   1480     0    stevel 	if ((opts.o_outpmode & OPT_USERS) &&
   1481     0    stevel 	    !(opts.o_outpmode & OPT_SPLIT))
   1482     0    stevel 		opts.o_nbottom = opts.o_ntop;
   1483     0    stevel 	if (opts.o_ntop == 0 || opts.o_nbottom == 0)
   1484     0    stevel 		Die(gettext("invalid argument for -n\n"));
   1485     0    stevel 	if (!(opts.o_outpmode & OPT_SPLIT) && (opts.o_outpmode & OPT_USERS) &&
   1486     0    stevel 	    ((opts.o_outpmode & (OPT_PSINFO | OPT_MSACCT))))
   1487     0    stevel 		Die(gettext("-t option cannot be used with -v or -m\n"));
   1488     0    stevel 
   1489     0    stevel 	if ((opts.o_outpmode & OPT_SPLIT) && (opts.o_outpmode && OPT_USERS) &&
   1490     0    stevel 	    !((opts.o_outpmode & (OPT_PSINFO | OPT_MSACCT))))
   1491     0    stevel 		Die(gettext("-t option cannot be used with "
   1492     0    stevel 		    "-a, -J, -T or -Z\n"));
   1493     0    stevel 
   1494     0    stevel 	if ((opts.o_outpmode & OPT_USERS) &&
   1495  9123      john 	    (opts.o_outpmode & (OPT_TASKS | OPT_PROJECTS | OPT_ZONES)))
   1496     0    stevel 		Die(gettext("-a option cannot be used with "
   1497     0    stevel 		    "-t, -J, -T or -Z\n"));
   1498     0    stevel 
   1499     0    stevel 	if (((opts.o_outpmode & OPT_TASKS) &&
   1500     0    stevel 	    (opts.o_outpmode & (OPT_PROJECTS|OPT_ZONES))) ||
   1501     0    stevel 	    ((opts.o_outpmode & OPT_PROJECTS) &&
   1502  9123      john 	    (opts.o_outpmode & (OPT_TASKS|OPT_ZONES)))) {
   1503  2685     akolb 		Die(gettext(
   1504  2685     akolb 		    "-J, -T and -Z options are mutually exclusive\n"));
   1505  2685     akolb 	}
   1506  2685     akolb 
   1507  2685     akolb 	/*
   1508  2685     akolb 	 * There is not enough space to combine microstate information and
   1509  2685     akolb 	 * lgroup information and still fit in 80-column output.
   1510  2685     akolb 	 */
   1511  2685     akolb 	if ((opts.o_outpmode & OPT_LGRP) && (opts.o_outpmode & OPT_MSACCT)) {
   1512  2685     akolb 		Die(gettext("-H and -m options are mutually exclusive\n"));
   1513     0    stevel 	}
   1514     0    stevel 
   1515     0    stevel 	if (argc > optind)
   1516     0    stevel 		opts.o_interval = Atoi(argv[optind++]);
   1517     0    stevel 	if (argc > optind)
   1518     0    stevel 		opts.o_count = Atoi(argv[optind++]);
   1519     0    stevel 	if (opts.o_count == 0)
   1520     0    stevel 		Die(gettext("invalid counter value\n"));
   1521     0    stevel 	if (argc > optind)
   1522     0    stevel 		Usage();
   1523     0    stevel 	if (opts.o_outpmode & OPT_REALTIME)
   1524     0    stevel 		Priocntl("RT");
   1525     0    stevel 	if (isatty(STDOUT_FILENO) == 1 && isatty(STDIN_FILENO))
   1526     0    stevel 		opts.o_outpmode |= OPT_TTY;	/* interactive */
   1527     0    stevel 	if (!(opts.o_outpmode & OPT_TTY)) {
   1528     0    stevel 		opts.o_outpmode &= ~OPT_TERMCAP; /* no termcap for pipes */
   1529     0    stevel 		opts.o_outpmode &= ~OPT_FULLSCREEN;
   1530     0    stevel 	}
   1531     0    stevel 	if (opts.o_outpmode & OPT_TERMCAP)
   1532     0    stevel 		ldtermcap();		/* can turn OPT_TERMCAP off */
   1533     0    stevel 	if (opts.o_outpmode & OPT_TERMCAP)
   1534     0    stevel 		(void) setsize();
   1535     0    stevel 	list_alloc(&lwps, opts.o_ntop);
   1536     0    stevel 	list_alloc(&users, opts.o_nbottom);
   1537     0    stevel 	list_alloc(&tasks, opts.o_nbottom);
   1538     0    stevel 	list_alloc(&projects, opts.o_nbottom);
   1539     0    stevel 	list_alloc(&zones, opts.o_nbottom);
   1540  2685     akolb 	list_alloc(&lgroups, opts.o_nbottom);
   1541     0    stevel 	list_setkeyfunc(sortk, &opts, &lwps, LT_LWPS);
   1542     0    stevel 	list_setkeyfunc(NULL, &opts, &users, LT_USERS);
   1543     0    stevel 	list_setkeyfunc(NULL, &opts, &tasks, LT_TASKS);
   1544     0    stevel 	list_setkeyfunc(NULL, &opts, &projects, LT_PROJECTS);
   1545     0    stevel 	list_setkeyfunc(NULL, &opts, &zones, LT_ZONES);
   1546  2685     akolb 	list_setkeyfunc(NULL, &opts, &lgroups, LT_LGRPS);
   1547     0    stevel 	if (opts.o_outpmode & OPT_TERMCAP)
   1548     0    stevel 		curses_on();
   1549     0    stevel 	if ((procdir = opendir("/proc")) == NULL)
   1550     0    stevel 		Die(gettext("cannot open /proc directory\n"));
   1551     0    stevel 	if (opts.o_outpmode & OPT_TTY) {
   1552     0    stevel 		(void) printf(gettext("Please wait...\r"));
   1553  9123      john 		if (!(opts.o_outpmode & OPT_TERMCAP))
   1554  9123      john 			(void) putchar('\n');
   1555     0    stevel 		(void) fflush(stdout);
   1556     0    stevel 	}
   1557     0    stevel 	set_signals();
   1558     0    stevel 	pollset.fd = STDIN_FILENO;
   1559     0    stevel 	pollset.events = POLLIN;
   1560     0    stevel 	timeout = opts.o_interval * MILLISEC;
   1561     0    stevel 
   1562     0    stevel 	/*
   1563     0    stevel 	 * main program loop
   1564     0    stevel 	 */
   1565     0    stevel 	do {
   1566     0    stevel 		if (sigterm == 1)
   1567     0    stevel 			break;
   1568     0    stevel 		if (sigtstp == 1) {
   1569     0    stevel 			curses_off();
   1570     0    stevel 			(void) signal(SIGTSTP, SIG_DFL);
   1571     0    stevel 			(void) kill(0, SIGTSTP);
   1572     0    stevel 			/*
   1573     0    stevel 			 * prstat stops here until it receives SIGCONT signal.
   1574     0    stevel 			 */
   1575     0    stevel 			sigtstp = 0;
   1576     0    stevel 			(void) signal(SIGTSTP, sig_handler);
   1577     0    stevel 			curses_on();
   1578     0    stevel 			print_movecur = FALSE;
   1579     0    stevel 			if (opts.o_outpmode & OPT_FULLSCREEN)
   1580     0    stevel 				sigwinch = 1;
   1581     0    stevel 		}
   1582     0    stevel 		if (sigwinch == 1) {
   1583     0    stevel 			if (setsize() == 1) {
   1584     0    stevel 				list_free(&lwps);
   1585     0    stevel 				list_free(&users);
   1586     0    stevel 				list_free(&tasks);
   1587     0    stevel 				list_free(&projects);
   1588     0    stevel 				list_free(&zones);
   1589     0    stevel 				list_alloc(&lwps, opts.o_ntop);
   1590     0    stevel 				list_alloc(&users, opts.o_nbottom);
   1591     0    stevel 				list_alloc(&tasks, opts.o_nbottom);
   1592     0    stevel 				list_alloc(&projects, opts.o_nbottom);
   1593     0    stevel 				list_alloc(&zones, opts.o_nbottom);
   1594     0    stevel 			}
   1595     0    stevel 			sigwinch = 0;
   1596     0    stevel 			(void) signal(SIGWINCH, sig_handler);
   1597     0    stevel 		}
   1598     0    stevel 		prstat_scandir(procdir);
   1599     0    stevel 		list_refresh(&lwps);
   1600     0    stevel 		if (print_movecur)
   1601     0    stevel 			(void) putp(movecur);
   1602     0    stevel 		print_movecur = TRUE;
   1603     0    stevel 		if ((opts.o_outpmode & OPT_PSINFO) ||
   1604     0    stevel 		    (opts.o_outpmode & OPT_MSACCT)) {
   1605     0    stevel 			list_sort(&lwps);
   1606     0    stevel 			list_print(&lwps);
   1607     0    stevel 		}
   1608     0    stevel 		if (opts.o_outpmode & OPT_USERS) {
   1609  3247  gjelinek 			list_getsize(&users);
   1610     0    stevel 			list_sort(&users);
   1611     0    stevel 			list_print(&users);
   1612     0    stevel 			list_clear(&users);
   1613     0    stevel 		}
   1614     0    stevel 		if (opts.o_outpmode & OPT_TASKS) {
   1615  3247  gjelinek 			list_getsize(&tasks);
   1616     0    stevel 			list_sort(&tasks);
   1617     0    stevel 			list_print(&tasks);
   1618     0    stevel 			list_clear(&tasks);
   1619     0    stevel 		}
   1620     0    stevel 		if (opts.o_outpmode & OPT_PROJECTS) {
   1621  3247  gjelinek 			list_getsize(&projects);
   1622     0    stevel 			list_sort(&projects);
   1623     0    stevel 			list_print(&projects);
   1624     0    stevel 			list_clear(&projects);
   1625     0    stevel 		}
   1626     0    stevel 		if (opts.o_outpmode & OPT_ZONES) {
   1627  3247  gjelinek 			list_getsize(&zones);
   1628     0    stevel 			list_sort(&zones);
   1629     0    stevel 			list_print(&zones);
   1630     0    stevel 			list_clear(&zones);
   1631     0    stevel 		}
   1632     0    stevel 		if (opts.o_count == 1)
   1633     0    stevel 			break;
   1634     0    stevel 		/*
   1635     0    stevel 		 * If poll() returns -1 and sets errno to EINTR here because
   1636     0    stevel 		 * the process received a signal, it is Ok to abort this
   1637     0    stevel 		 * timeout and loop around because we check the signals at the
   1638     0    stevel 		 * top of the loop.
   1639     0    stevel 		 */
   1640     0    stevel 		if (opts.o_outpmode & OPT_TTY) {
   1641     0    stevel 			if (poll(&pollset, (nfds_t)1, timeout) > 0) {
   1642     0    stevel 				if (read(STDIN_FILENO, &key, 1) == 1) {
   1643     0    stevel 					if (tolower(key) == 'q')
   1644     0    stevel 						break;
   1645     0    stevel 				}
   1646     0    stevel 			}
   1647     0    stevel 		} else {
   1648     0    stevel 			(void) sleep(opts.o_interval);
   1649     0    stevel 		}
   1650     0    stevel 	} while (opts.o_count == (-1) || --opts.o_count);
   1651     0    stevel 
   1652     0    stevel 	if (opts.o_outpmode & OPT_TTY)
   1653     0    stevel 		(void) putchar('\r');
   1654     0    stevel 	return (0);
   1655     0    stevel }
   1656