Home | History | Annotate | Download | only in ps
      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  1454    jonb  * Common Development and Distribution License (the "License").
      6  1454    jonb  * 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  1454    jonb 
     22     0  stevel /*
     23  8822  Casper  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24     0  stevel  * Use is subject to license terms.
     25     0  stevel  */
     26     0  stevel 
     27     0  stevel /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
     28     0  stevel /*	  All Rights Reserved  	*/
     29     0  stevel 
     30     0  stevel /*
     31     0  stevel  * ps -- print things about processes.
     32     0  stevel  */
     33     0  stevel #include <stdio.h>
     34     0  stevel #include <ctype.h>
     35     0  stevel #include <string.h>
     36     0  stevel #include <errno.h>
     37     0  stevel #include <fcntl.h>
     38     0  stevel #include <pwd.h>
     39     0  stevel #include <grp.h>
     40     0  stevel #include <sys/types.h>
     41     0  stevel #include <sys/stat.h>
     42     0  stevel #include <sys/mkdev.h>
     43     0  stevel #include <unistd.h>
     44     0  stevel #include <stdlib.h>
     45     0  stevel #include <limits.h>
     46     0  stevel #include <dirent.h>
     47     0  stevel #include <sys/signal.h>
     48     0  stevel #include <sys/fault.h>
     49     0  stevel #include <sys/syscall.h>
     50     0  stevel #include <sys/time.h>
     51     0  stevel #include <procfs.h>
     52     0  stevel #include <locale.h>
     53     0  stevel #include <wctype.h>
     54     0  stevel #include <wchar.h>
     55     0  stevel #include <libw.h>
     56     0  stevel #include <stdarg.h>
     57     0  stevel #include <sys/proc.h>
     58     0  stevel #include <sys/pset.h>
     59     0  stevel #include <project.h>
     60     0  stevel #include <zone.h>
     61     0  stevel 
     62     0  stevel #define	min(a, b)	((a) > (b) ? (b) : (a))
     63     0  stevel #define	max(a, b)	((a) < (b) ? (b) : (a))
     64     0  stevel 
     65     0  stevel #define	NTTYS	20	/* initial size of table for -t option  */
     66  2685   akolb #define	SIZ	30	/* initial size of tables for -p, -s, -g, -h and -z */
     67  1454    jonb 
     68  1454    jonb /*
     69  1454    jonb  * Size of buffer holding args for t, p, s, g, u, U, G, z options.
     70  1454    jonb  * Set to ZONENAME_MAX, the minimum value needed to allow any
     71  1454    jonb  * zone to be specified.
     72  1454    jonb  */
     73  1454    jonb #define	ARGSIZ ZONENAME_MAX
     74     0  stevel 
     75     0  stevel #define	MAXUGNAME 10	/* max chars in a user/group name or printed u/g id */
     76     0  stevel 
     77     0  stevel /* Structure for storing user or group info */
     78     0  stevel struct ugdata {
     79     0  stevel 	id_t	id;			/* numeric user-id or group-id */
     80     0  stevel 	char	name[MAXUGNAME+1];	/* user/group name, null terminated */
     81     0  stevel };
     82     0  stevel 
     83     0  stevel struct ughead {
     84     0  stevel 	size_t	size;		/* number of ugdata structs allocated */
     85     0  stevel 	size_t	nent;		/* number of active entries */
     86     0  stevel 	struct ugdata *ent;	/* pointer to array of actual entries */
     87     0  stevel };
     88     0  stevel 
     89     0  stevel enum fname {	/* enumeration of field names */
     90     0  stevel 	F_USER,		/* effective user of the process */
     91     0  stevel 	F_RUSER,	/* real user of the process */
     92     0  stevel 	F_GROUP,	/* effective group of the process */
     93     0  stevel 	F_RGROUP,	/* real group of the process */
     94     0  stevel 	F_UID,		/* numeric effective uid of the process */
     95     0  stevel 	F_RUID,		/* numeric real uid of the process */
     96     0  stevel 	F_GID,		/* numeric effective gid of the process */
     97     0  stevel 	F_RGID,		/* numeric real gid of the process */
     98     0  stevel 	F_PID,		/* process id */
     99     0  stevel 	F_PPID,		/* parent process id */
    100     0  stevel 	F_PGID,		/* process group id */
    101     0  stevel 	F_SID,		/* session id */
    102     0  stevel 	F_PSR,		/* bound processor */
    103     0  stevel 	F_LWP,		/* lwp-id */
    104     0  stevel 	F_NLWP,		/* number of lwps */
    105     0  stevel 	F_OPRI,		/* old priority (obsolete) */
    106     0  stevel 	F_PRI,		/* new priority */
    107     0  stevel 	F_F,		/* process flags */
    108     0  stevel 	F_S,		/* letter indicating the state */
    109     0  stevel 	F_C,		/* processor utilization (obsolete) */
    110     0  stevel 	F_PCPU,		/* percent of recently used cpu time */
    111     0  stevel 	F_PMEM,		/* percent of physical memory used (rss) */
    112     0  stevel 	F_OSZ,		/* virtual size of the process in pages */
    113     0  stevel 	F_VSZ,		/* virtual size of the process in kilobytes */
    114     0  stevel 	F_RSS,		/* resident set size of the process in kilobytes */
    115     0  stevel 	F_NICE,		/* "nice" value of the process */
    116     0  stevel 	F_CLASS,	/* scheduler class */
    117     0  stevel 	F_STIME,	/* start time of the process, hh:mm:ss or Month Day */
    118     0  stevel 	F_ETIME,	/* elapsed time of the process, [[dd-]hh:]mm:ss */
    119     0  stevel 	F_TIME,		/* cpu time of the process, [[dd-]hh:]mm:ss */
    120     0  stevel 	F_TTY,		/* name of the controlling terminal */
    121     0  stevel 	F_ADDR,		/* address of the process (obsolete) */
    122     0  stevel 	F_WCHAN,	/* wait channel (sleep condition variable) */
    123     0  stevel 	F_FNAME,	/* file name of command */
    124     0  stevel 	F_COMM,		/* name of command (argv[0] value) */
    125     0  stevel 	F_ARGS,		/* name of command plus all its arguments */
    126     0  stevel 	F_TASKID,	/* task id */
    127     0  stevel 	F_PROJID,	/* project id */
    128     0  stevel 	F_PROJECT,	/* project name of the process */
    129     0  stevel 	F_PSET,		/* bound processor set */
    130     0  stevel 	F_ZONE,		/* zone name */
    131     0  stevel 	F_ZONEID,	/* zone id */
    132  2685   akolb 	F_CTID,		/* process contract id */
    133  2685   akolb 	F_LGRP		/* process home lgroup */
    134     0  stevel };
    135     0  stevel 
    136     0  stevel struct field {
    137     0  stevel 	struct field	*next;		/* linked list */
    138     0  stevel 	int		fname;		/* field index */
    139     0  stevel 	const char	*header;	/* header to use */
    140     0  stevel 	int		width;		/* width of field */
    141     0  stevel };
    142     0  stevel 
    143     0  stevel static	struct field *fields = NULL;	/* fields selected via -o */
    144     0  stevel static	struct field *last_field = NULL;
    145     0  stevel static	int do_header = 0;
    146     0  stevel static	struct timeval now;
    147     0  stevel 
    148     0  stevel /* array of defined fields, in fname order */
    149     0  stevel struct def_field {
    150     0  stevel 	const char *fname;
    151     0  stevel 	const char *header;
    152     0  stevel 	int width;
    153     0  stevel 	int minwidth;
    154     0  stevel };
    155     0  stevel 
    156     0  stevel static struct def_field fname[] = {
    157     0  stevel 	/* fname	header		width	minwidth */
    158     0  stevel 	{ "user",	"USER",		8,	8	},
    159     0  stevel 	{ "ruser",	"RUSER",	8,	8	},
    160     0  stevel 	{ "group",	"GROUP",	8,	8	},
    161     0  stevel 	{ "rgroup",	"RGROUP",	8,	8	},
    162     0  stevel 	{ "uid",	"UID",		5,	5	},
    163     0  stevel 	{ "ruid",	"RUID",		5,	5	},
    164     0  stevel 	{ "gid",	"GID",		5,	5	},
    165     0  stevel 	{ "rgid",	"RGID",		5,	5	},
    166     0  stevel 	{ "pid",	"PID",		5,	5	},
    167     0  stevel 	{ "ppid",	"PPID",		5,	5	},
    168     0  stevel 	{ "pgid",	"PGID",		5,	5	},
    169     0  stevel 	{ "sid",	"SID",		5,	5	},
    170     0  stevel 	{ "psr",	"PSR",		3,	2	},
    171     0  stevel 	{ "lwp",	"LWP",		6,	2	},
    172     0  stevel 	{ "nlwp",	"NLWP",		4,	2	},
    173     0  stevel 	{ "opri",	"PRI",		3,	2	},
    174     0  stevel 	{ "pri",	"PRI",		3,	2	},
    175     0  stevel 	{ "f",		"F",		2,	2	},
    176     0  stevel 	{ "s",		"S",		1,	1	},
    177     0  stevel 	{ "c",		"C",		2,	2	},
    178     0  stevel 	{ "pcpu",	"%CPU",		4,	4	},
    179     0  stevel 	{ "pmem",	"%MEM",		4,	4	},
    180     0  stevel 	{ "osz",	"SZ",		4,	4	},
    181     0  stevel 	{ "vsz",	"VSZ",		4,	4	},
    182     0  stevel 	{ "rss",	"RSS",		4,	4	},
    183     0  stevel 	{ "nice",	"NI",		2,	2	},
    184     0  stevel 	{ "class",	"CLS",		4,	2	},
    185     0  stevel 	{ "stime",	"STIME",	8,	8	},
    186     0  stevel 	{ "etime",	"ELAPSED",	11,	7	},
    187     0  stevel 	{ "time",	"TIME",		11,	5	},
    188     0  stevel 	{ "tty",	"TT",		7,	7	},
    189     0  stevel #ifdef _LP64
    190     0  stevel 	{ "addr",	"ADDR",		16,	8	},
    191     0  stevel 	{ "wchan",	"WCHAN",	16,	8	},
    192     0  stevel #else
    193     0  stevel 	{ "addr",	"ADDR",		8,	8	},
    194     0  stevel 	{ "wchan",	"WCHAN",	8,	8	},
    195     0  stevel #endif
    196     0  stevel 	{ "fname",	"COMMAND",	8,	8	},
    197     0  stevel 	{ "comm",	"COMMAND",	80,	8	},
    198     0  stevel 	{ "args",	"COMMAND",	80,	80	},
    199     0  stevel 	{ "taskid",	"TASKID",	5,	5	},
    200     0  stevel 	{ "projid",	"PROJID",	5,	5	},
    201     0  stevel 	{ "project",	"PROJECT",	8,	8	},
    202     0  stevel 	{ "pset",	"PSET",		3,	3	},
    203     0  stevel 	{ "zone",	"ZONE",		8,	8	},
    204     0  stevel 	{ "zoneid",	"ZONEID",	5,	5	},
    205     0  stevel 	{ "ctid",	"CTID",		5,	5	},
    206  2685   akolb 	{ "lgrp",	"LGRP",		4,	2 	},
    207     0  stevel };
    208     0  stevel 
    209     0  stevel #define	NFIELDS	(sizeof (fname) / sizeof (fname[0]))
    210     0  stevel 
    211     0  stevel static	int	retcode = 1;
    212     0  stevel static	int	lflg;
    213     0  stevel static	int	Aflg;
    214     0  stevel static	int	uflg;
    215     0  stevel static	int	Uflg;
    216     0  stevel static	int	Gflg;
    217     0  stevel static	int	aflg;
    218     0  stevel static	int	dflg;
    219     0  stevel static	int	Lflg;
    220     0  stevel static	int	Pflg;
    221     0  stevel static	int	yflg;
    222     0  stevel static	int	pflg;
    223     0  stevel static	int	fflg;
    224     0  stevel static	int	cflg;
    225     0  stevel static	int	jflg;
    226     0  stevel static	int	gflg;
    227     0  stevel static	int	sflg;
    228     0  stevel static	int	tflg;
    229     0  stevel static	int	zflg;
    230     0  stevel static	int	Zflg;
    231  2685   akolb static	int	hflg;
    232  2685   akolb static	int	Hflg;
    233  4321  casper static	uid_t	tuid = (uid_t)-1;
    234     0  stevel static	int	errflg;
    235     0  stevel 
    236     0  stevel static	int	ndev;		/* number of devices */
    237     0  stevel static	int	maxdev;		/* number of devl structures allocated */
    238     0  stevel 
    239     0  stevel #define	DNINCR	100
    240     0  stevel #define	DNSIZE	14
    241     0  stevel static struct devl {		/* device list   */
    242     0  stevel 	char	dname[DNSIZE];	/* device name   */
    243     0  stevel 	dev_t	ddev;		/* device number */
    244     0  stevel } *devl;
    245     0  stevel 
    246     0  stevel static	struct tty {
    247     0  stevel 	char *tname;
    248     0  stevel 	dev_t tdev;
    249     0  stevel } *tty = NULL;			/* for t option */
    250     0  stevel static	size_t	ttysz = 0;
    251     0  stevel static	int	ntty = 0;
    252     0  stevel 
    253     0  stevel static	pid_t	*pid = NULL;	/* for p option */
    254     0  stevel static	size_t	pidsz = 0;
    255     0  stevel static	size_t	npid = 0;
    256  2685   akolb 
    257  2685   akolb static	int	*lgrps = NULL;	/* list of lgroup IDs for for h option */
    258  2685   akolb static	size_t	lgrps_size = 0;	/* size of the lgrps list */
    259  2685   akolb static	size_t	nlgrps = 0;	/* number elements in the list */
    260  2685   akolb 
    261  2685   akolb /* Maximum possible lgroup ID value */
    262  2685   akolb #define	MAX_LGRP_ID 256
    263     0  stevel 
    264     0  stevel static	pid_t	*grpid = NULL;	/* for g option */
    265     0  stevel static	size_t	grpidsz = 0;
    266     0  stevel static	int	ngrpid = 0;
    267     0  stevel 
    268     0  stevel static	pid_t	*sessid = NULL;	/* for s option */
    269     0  stevel static	size_t	sessidsz = 0;
    270     0  stevel static	int	nsessid = 0;
    271     0  stevel 
    272     0  stevel static	zoneid_t *zoneid = NULL; /* for z option */
    273     0  stevel static	size_t	zoneidsz = 0;
    274     0  stevel static	int	nzoneid = 0;
    275     0  stevel 
    276     0  stevel static	int	kbytes_per_page;
    277     0  stevel static	int	pidwidth;
    278     0  stevel 
    279     0  stevel static	char	*procdir = "/proc";	/* standard /proc directory */
    280     0  stevel 
    281     0  stevel static struct ughead	euid_tbl;	/* table to store selected euid's */
    282     0  stevel static struct ughead	ruid_tbl;	/* table to store selected real uid's */
    283     0  stevel static struct ughead	egid_tbl;	/* table to store selected egid's */
    284     0  stevel static struct ughead	rgid_tbl;	/* table to store selected real gid's */
    285     0  stevel static prheader_t *lpsinfobuf;		/* buffer to contain lpsinfo */
    286     0  stevel static size_t	lpbufsize;
    287     0  stevel 
    288     0  stevel /*
    289     0  stevel  * This constant defines the sentinal number of process IDs below which we
    290     0  stevel  * only examine individual entries in /proc rather than scanning through
    291     0  stevel  * /proc. This optimization is a huge win in the common case.
    292     0  stevel  */
    293     0  stevel #define	PTHRESHOLD	40
    294     0  stevel 
    295  8822  Casper #define	UCB_OPTS	"-aceglnrtuvwxSU"
    296  8822  Casper 
    297     0  stevel static	void	usage(void);
    298     0  stevel static	char	*getarg(char **);
    299     0  stevel static	char	*parse_format(char *);
    300     0  stevel static	char	*gettty(psinfo_t *);
    301     0  stevel static	int	prfind(int, psinfo_t *, char **);
    302     0  stevel static	void	prcom(psinfo_t *, char *);
    303     0  stevel static	void	prtpct(ushort_t, int);
    304     0  stevel static	void	print_time(time_t, int);
    305     0  stevel static	void	print_field(psinfo_t *, struct field *, const char *);
    306     0  stevel static	void	print_zombie_field(psinfo_t *, struct field *, const char *);
    307     0  stevel static	void	pr_fields(psinfo_t *, const char *,
    308     0  stevel 		void (*print_fld)(psinfo_t *, struct field *, const char *));
    309     0  stevel static	int	search(pid_t *, int, pid_t);
    310     0  stevel static	void	add_ugentry(struct ughead *, char *);
    311     0  stevel static	int	uconv(struct ughead *);
    312     0  stevel static	int	gconv(struct ughead *);
    313  4321  casper static	int	ugfind(id_t, struct ughead *);
    314     0  stevel static	void	prtime(timestruc_t, int, int);
    315     0  stevel static	void	przom(psinfo_t *);
    316     0  stevel static	int	namencnt(char *, int, int);
    317     0  stevel static	char	*err_string(int);
    318     0  stevel static	int	print_proc(char *pname);
    319     0  stevel static	time_t	delta_secs(const timestruc_t *);
    320     0  stevel static	int	str2id(const char *, pid_t *, long, long);
    321  4321  casper static	int	str2uid(const char *,  uid_t *, unsigned long, unsigned long);
    322     0  stevel static	void	*Realloc(void *, size_t);
    323     0  stevel static	int	pidcmp(const void *p1, const void *p2);
    324     0  stevel 
    325  8822  Casper extern	int	ucbmain(int, char **);
    326  8822  Casper static	int	stdmain(int, char **);
    327  8822  Casper 
    328     0  stevel int
    329     0  stevel main(int argc, char **argv)
    330  8822  Casper {
    331  8822  Casper 	const char *me;
    332  8822  Casper 
    333  8822  Casper 	/*
    334  8822  Casper 	 * The original two ps'es are linked in a single binary;
    335  8822  Casper 	 * their main()s are renamed to stdmain for /usr/bin/ps and
    336  8822  Casper 	 * ucbmain for /usr/ucb/ps.
    337  8822  Casper 	 * We try to figure out which instance of ps the user wants to run.
    338  8822  Casper 	 * Traditionally, the UCB variant doesn't require the flag argument
    339  8822  Casper 	 * start with a "-".  If the first argument doesn't start with a
    340  8822  Casper 	 * "-", we call "ucbmain".
    341  8822  Casper 	 * If there's a first argument and it starts with a "-", we check
    342  8822  Casper 	 * whether any of the options isn't acceptable to "ucbmain"; in that
    343  8822  Casper 	 * case we run "stdmain".
    344  8822  Casper 	 * If we can't tell from the options which main to call, we check
    345  8822  Casper 	 * the binary we are running.  We default to "stdmain" but
    346  8822  Casper 	 * any mention in the executable name of "ucb" causes us to call
    347  8822  Casper 	 * ucbmain.
    348  8822  Casper 	 */
    349  8822  Casper 	if (argv[1] != NULL) {
    350  8822  Casper 		if (argv[1][0] != '-')
    351  8822  Casper 			return (ucbmain(argc, argv));
    352  8822  Casper 		else if (argv[1][strspn(argv[1], UCB_OPTS)] != '\0')
    353  8822  Casper 			return (stdmain(argc, argv));
    354  8822  Casper 	}
    355  8822  Casper 
    356  8822  Casper 	me = getexecname();
    357  8822  Casper 
    358  8822  Casper 	if (me != NULL && strstr(me, "ucb") != NULL)
    359  8822  Casper 		return (ucbmain(argc, argv));
    360  8822  Casper 	else
    361  8822  Casper 		return (stdmain(argc, argv));
    362  8822  Casper }
    363  8822  Casper 
    364  8822  Casper static int
    365  8822  Casper stdmain(int argc, char **argv)
    366     0  stevel {
    367     0  stevel 	char	*p;
    368     0  stevel 	char	*p1;
    369     0  stevel 	char	*parg;
    370     0  stevel 	int	c;
    371     0  stevel 	int	i;
    372     0  stevel 	int	pgerrflg = 0;	/* err flg: non-numeric arg w/p & g options */
    373  2966  sayama 	size_t	size, len;
    374     0  stevel 	DIR	*dirp;
    375     0  stevel 	struct dirent *dentp;
    376     0  stevel 	pid_t	maxpid;
    377     0  stevel 	pid_t	id;
    378     0  stevel 	int	ret;
    379  2966  sayama 	char	loc_stime_str[32];
    380     0  stevel 
    381     0  stevel 	(void) setlocale(LC_ALL, "");
    382     0  stevel #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
    383     0  stevel #define	TEXT_DOMAIN	"SYS_TEST"	/* Use this only if it weren't */
    384     0  stevel #endif
    385     0  stevel 	(void) textdomain(TEXT_DOMAIN);
    386     0  stevel 
    387     0  stevel 	(void) memset(&euid_tbl, 0, sizeof (euid_tbl));
    388     0  stevel 	(void) memset(&ruid_tbl, 0, sizeof (ruid_tbl));
    389     0  stevel 	(void) memset(&egid_tbl, 0, sizeof (egid_tbl));
    390     0  stevel 	(void) memset(&rgid_tbl, 0, sizeof (rgid_tbl));
    391     0  stevel 
    392     0  stevel 	kbytes_per_page = sysconf(_SC_PAGESIZE) / 1024;
    393     0  stevel 
    394     0  stevel 	(void) gettimeofday(&now, NULL);
    395     0  stevel 
    396     0  stevel 	/*
    397     0  stevel 	 * calculate width of pid fields based on configured MAXPID
    398     0  stevel 	 * (must be at least 5 to retain output format compatibility)
    399     0  stevel 	 */
    400     0  stevel 	id = maxpid = (pid_t)sysconf(_SC_MAXPID);
    401     0  stevel 	pidwidth = 1;
    402     0  stevel 	while ((id /= 10) > 0)
    403     0  stevel 		++pidwidth;
    404     0  stevel 	pidwidth = pidwidth < 5 ? 5 : pidwidth;
    405     0  stevel 
    406     0  stevel 	fname[F_PID].width = fname[F_PPID].width = pidwidth;
    407     0  stevel 	fname[F_PGID].width = fname[F_SID].width = pidwidth;
    408  2966  sayama 
    409  2966  sayama 	/*
    410  2966  sayama 	 * TRANSLATION_NOTE
    411  2966  sayama 	 * Specify the printf format with width and precision for
    412  2966  sayama 	 * the STIME field.
    413  2966  sayama 	 */
    414  2966  sayama 	len = snprintf(loc_stime_str, sizeof (loc_stime_str),
    415  2966  sayama 	    dcgettext(NULL, "%8.8s", LC_TIME), "STIME");
    416  2966  sayama 	if (len >= sizeof (loc_stime_str))
    417  2966  sayama 		len = sizeof (loc_stime_str) - 1;
    418  2966  sayama 
    419  2966  sayama 	fname[F_STIME].width = fname[F_STIME].minwidth = len;
    420     0  stevel 
    421  2685   akolb 	while ((c = getopt(argc, argv, "jlfceAadLPyZHh:t:p:g:u:U:G:n:s:o:z:"))
    422  2685   akolb 	    != EOF)
    423     0  stevel 		switch (c) {
    424  2685   akolb 		case 'H':		/* Show home lgroups */
    425  2685   akolb 			Hflg++;
    426  2685   akolb 			break;
    427  2685   akolb 		case 'h':
    428  2685   akolb 			/*
    429  2685   akolb 			 * Show processes/threads with given home lgroups
    430  2685   akolb 			 */
    431  2685   akolb 			hflg++;
    432  2685   akolb 			p1 = optarg;
    433  2685   akolb 			do {
    434  2685   akolb 				int id;
    435  2685   akolb 
    436  2685   akolb 				/*
    437  2685   akolb 				 * Get all IDs in the list, verify for
    438  2685   akolb 				 * correctness and place in lgrps array.
    439  2685   akolb 				 */
    440  2685   akolb 				parg = getarg(&p1);
    441  2685   akolb 				/* Convert string to integer */
    442  2685   akolb 				ret = str2id(parg, (pid_t *)&id, 0,
    443  8233     dme 				    MAX_LGRP_ID);
    444  2685   akolb 				/* Complain if ID didn't parse correctly */
    445  2685   akolb 				if (ret != 0) {
    446  2685   akolb 					pgerrflg++;
    447  2685   akolb 					(void) fprintf(stderr,
    448  2685   akolb 					    gettext("ps: %s "), parg);
    449  2685   akolb 					if (ret == EINVAL)
    450  2685   akolb 						(void) fprintf(stderr,
    451  2685   akolb 						    gettext("is an invalid "
    452  2685   akolb 						    "non-numeric argument"));
    453  2685   akolb 					else
    454  2685   akolb 						(void) fprintf(stderr,
    455  2685   akolb 						    gettext("exceeds valid "
    456  2685   akolb 						    "range"));
    457  2685   akolb 					(void) fprintf(stderr,
    458  2685   akolb 					    gettext(" for -h option\n"));
    459  2685   akolb 					continue;
    460  2685   akolb 				}
    461  2685   akolb 
    462  2685   akolb 				/* Extend lgrps array if needed */
    463  2685   akolb 				if (nlgrps == lgrps_size) {
    464  2685   akolb 					/* Double the size of the lgrps array */
    465  2685   akolb 					if (lgrps_size == 0)
    466  2685   akolb 						lgrps_size = SIZ;
    467  2685   akolb 					lgrps_size *= 2;
    468  2685   akolb 					lgrps = Realloc(lgrps,
    469  2685   akolb 					    lgrps_size * sizeof (int));
    470  2685   akolb 				}
    471  2685   akolb 				/* place the id in the lgrps table */
    472  2685   akolb 				lgrps[nlgrps++] = id;
    473  2685   akolb 			} while (*p1);
    474  2685   akolb 			break;
    475     0  stevel 		case 'l':		/* long listing */
    476     0  stevel 			lflg++;
    477     0  stevel 			break;
    478     0  stevel 		case 'f':		/* full listing */
    479     0  stevel 			fflg++;
    480     0  stevel 			break;
    481     0  stevel 		case 'j':
    482     0  stevel 			jflg++;
    483     0  stevel 			break;
    484     0  stevel 		case 'c':
    485     0  stevel 			/*
    486     0  stevel 			 * Format output to reflect scheduler changes:
    487     0  stevel 			 * high numbers for high priorities and don't
    488     0  stevel 			 * print nice or p_cpu values.  'c' option only
    489     0  stevel 			 * effective when used with 'l' or 'f' options.
    490     0  stevel 			 */
    491     0  stevel 			cflg++;
    492     0  stevel 			break;
    493     0  stevel 		case 'A':		/* list every process */
    494     0  stevel 		case 'e':		/* (obsolete) list every process */
    495     0  stevel 			Aflg++;
    496     0  stevel 			tflg = Gflg = Uflg = uflg = pflg = gflg = sflg = 0;
    497  2685   akolb 			zflg = hflg = 0;
    498     0  stevel 			break;
    499     0  stevel 		case 'a':
    500     0  stevel 			/*
    501     0  stevel 			 * Same as 'e' except no session group leaders
    502     0  stevel 			 * and no non-terminal processes.
    503     0  stevel 			 */
    504     0  stevel 			aflg++;
    505     0  stevel 			break;
    506     0  stevel 		case 'd':	/* same as e except no session leaders */
    507     0  stevel 			dflg++;
    508     0  stevel 			break;
    509     0  stevel 		case 'L':	/* show lwps */
    510     0  stevel 			Lflg++;
    511     0  stevel 			break;
    512     0  stevel 		case 'P':	/* show bound processor */
    513     0  stevel 			Pflg++;
    514     0  stevel 			break;
    515     0  stevel 		case 'y':	/* omit F & ADDR, report RSS & SZ in Kby */
    516     0  stevel 			yflg++;
    517     0  stevel 			break;
    518     0  stevel 		case 'n':	/* no longer needed; retain as no-op */
    519     0  stevel 			(void) fprintf(stderr,
    520     0  stevel 			    gettext("ps: warning: -n option ignored\n"));
    521     0  stevel 			break;
    522     0  stevel 		case 't':		/* terminals */
    523     0  stevel #define	TSZ	30
    524     0  stevel 			tflg++;
    525     0  stevel 			p1 = optarg;
    526     0  stevel 			do {
    527     0  stevel 				char nambuf[TSZ+6];	/* for "/dev/" + '\0' */
    528     0  stevel 				struct stat64 s;
    529     0  stevel 				parg = getarg(&p1);
    530     0  stevel 				p = Realloc(NULL, TSZ+1);	/* for '\0' */
    531     0  stevel 				/* zero the buffer before using it */
    532     0  stevel 				p[0] = '\0';
    533     0  stevel 				size = TSZ;
    534     0  stevel 				if (isdigit(*parg)) {
    535     0  stevel 					(void) strcpy(p, "tty");
    536     0  stevel 					size -= 3;
    537     0  stevel 				}
    538     0  stevel 				(void) strncat(p, parg, size);
    539     0  stevel 				if (ntty == ttysz) {
    540     0  stevel 					if ((ttysz *= 2) == 0)
    541     0  stevel 						ttysz = NTTYS;
    542     0  stevel 					tty = Realloc(tty,
    543     0  stevel 					    (ttysz + 1) * sizeof (struct tty));
    544     0  stevel 				}
    545     0  stevel 				tty[ntty].tdev = PRNODEV;
    546     0  stevel 				(void) strcpy(nambuf, "/dev/");
    547     0  stevel 				(void) strcat(nambuf, p);
    548     0  stevel 				if (stat64(nambuf, &s) == 0)
    549     0  stevel 					tty[ntty].tdev = s.st_rdev;
    550     0  stevel 				tty[ntty++].tname = p;
    551     0  stevel 			} while (*p1);
    552     0  stevel 			break;
    553     0  stevel 		case 'p':		/* proc ids */
    554     0  stevel 			pflg++;
    555     0  stevel 			p1 = optarg;
    556     0  stevel 			do {
    557     0  stevel 				pid_t id;
    558     0  stevel 
    559     0  stevel 				parg = getarg(&p1);
    560     0  stevel 				if ((ret = str2id(parg, &id, 0, maxpid)) != 0) {
    561     0  stevel 					pgerrflg++;
    562     0  stevel 					(void) fprintf(stderr,
    563     0  stevel 					    gettext("ps: %s "), parg);
    564     0  stevel 					if (ret == EINVAL)
    565     0  stevel 						(void) fprintf(stderr,
    566     0  stevel 						    gettext("is an invalid "
    567     0  stevel 						    "non-numeric argument"));
    568     0  stevel 					else
    569     0  stevel 						(void) fprintf(stderr,
    570     0  stevel 						    gettext("exceeds valid "
    571     0  stevel 						    "range"));
    572     0  stevel 					(void) fprintf(stderr,
    573     0  stevel 					    gettext(" for -p option\n"));
    574     0  stevel 					continue;
    575     0  stevel 				}
    576     0  stevel 
    577     0  stevel 				if (npid == pidsz) {
    578     0  stevel 					if ((pidsz *= 2) == 0)
    579     0  stevel 						pidsz = SIZ;
    580     0  stevel 					pid = Realloc(pid,
    581     0  stevel 					    pidsz * sizeof (pid_t));
    582     0  stevel 				}
    583     0  stevel 				pid[npid++] = id;
    584     0  stevel 			} while (*p1);
    585     0  stevel 			break;
    586     0  stevel 		case 's':		/* session */
    587     0  stevel 			sflg++;
    588     0  stevel 			p1 = optarg;
    589     0  stevel 			do {
    590     0  stevel 				pid_t id;
    591     0  stevel 
    592     0  stevel 				parg = getarg(&p1);
    593     0  stevel 				if ((ret = str2id(parg, &id, 0, maxpid)) != 0) {
    594     0  stevel 					pgerrflg++;
    595     0  stevel 					(void) fprintf(stderr,
    596     0  stevel 					    gettext("ps: %s "), parg);
    597     0  stevel 					if (ret == EINVAL)
    598     0  stevel 						(void) fprintf(stderr,
    599     0  stevel 						    gettext("is an invalid "
    600     0  stevel 						    "non-numeric argument"));
    601     0  stevel 					else
    602     0  stevel 						(void) fprintf(stderr,
    603     0  stevel 						    gettext("exceeds valid "
    604     0  stevel 						    "range"));
    605     0  stevel 					(void) fprintf(stderr,
    606     0  stevel 					    gettext(" for -s option\n"));
    607     0  stevel 					continue;
    608     0  stevel 				}
    609     0  stevel 
    610     0  stevel 				if (nsessid == sessidsz) {
    611     0  stevel 					if ((sessidsz *= 2) == 0)
    612     0  stevel 						sessidsz = SIZ;
    613     0  stevel 					sessid = Realloc(sessid,
    614     0  stevel 					    sessidsz * sizeof (pid_t));
    615     0  stevel 				}
    616     0  stevel 				sessid[nsessid++] = id;
    617     0  stevel 			} while (*p1);
    618     0  stevel 			break;
    619     0  stevel 		case 'g':		/* proc group */
    620     0  stevel 			gflg++;
    621     0  stevel 			p1 = optarg;
    622     0  stevel 			do {
    623     0  stevel 				pid_t id;
    624     0  stevel 
    625     0  stevel 				parg = getarg(&p1);
    626     0  stevel 				if ((ret = str2id(parg, &id, 0, maxpid)) != 0) {
    627     0  stevel 					pgerrflg++;
    628     0  stevel 					(void) fprintf(stderr,
    629     0  stevel 					    gettext("ps: %s "), parg);
    630     0  stevel 					if (ret == EINVAL)
    631     0  stevel 						(void) fprintf(stderr,
    632     0  stevel 						    gettext("is an invalid "
    633     0  stevel 						    "non-numeric argument"));
    634     0  stevel 					else
    635     0  stevel 						(void) fprintf(stderr,
    636     0  stevel 						    gettext("exceeds valid "
    637     0  stevel 						    "range"));
    638     0  stevel 					(void) fprintf(stderr,
    639     0  stevel 					    gettext(" for -g option\n"));
    640     0  stevel 					continue;
    641     0  stevel 				}
    642     0  stevel 
    643     0  stevel 				if (ngrpid == grpidsz) {
    644     0  stevel 					if ((grpidsz *= 2) == 0)
    645     0  stevel 						grpidsz = SIZ;
    646     0  stevel 					grpid = Realloc(grpid,
    647     0  stevel 					    grpidsz * sizeof (pid_t));
    648     0  stevel 				}
    649     0  stevel 				grpid[ngrpid++] = id;
    650     0  stevel 			} while (*p1);
    651     0  stevel 			break;
    652     0  stevel 		case 'u':		/* effective user name or number */
    653     0  stevel 			uflg++;
    654     0  stevel 			p1 = optarg;
    655     0  stevel 			do {
    656     0  stevel 				parg = getarg(&p1);
    657     0  stevel 				add_ugentry(&euid_tbl, parg);
    658     0  stevel 			} while (*p1);
    659     0  stevel 			break;
    660     0  stevel 		case 'U':		/* real user name or number */
    661     0  stevel 			Uflg++;
    662     0  stevel 			p1 = optarg;
    663     0  stevel 			do {
    664     0  stevel 				parg = getarg(&p1);
    665     0  stevel 				add_ugentry(&ruid_tbl, parg);
    666     0  stevel 			} while (*p1);
    667     0  stevel 			break;
    668     0  stevel 		case 'G':		/* real group name or number */
    669     0  stevel 			Gflg++;
    670     0  stevel 			p1 = optarg;
    671     0  stevel 			do {
    672     0  stevel 				parg = getarg(&p1);
    673     0  stevel 				add_ugentry(&rgid_tbl, parg);
    674     0  stevel 			} while (*p1);
    675     0  stevel 			break;
    676     0  stevel 		case 'o':		/* output format */
    677     0  stevel 			p = optarg;
    678     0  stevel 			while ((p = parse_format(p)) != NULL)
    679     0  stevel 				;
    680     0  stevel 			break;
    681     0  stevel 		case 'z':		/* zone name or number */
    682     0  stevel 			zflg++;
    683     0  stevel 			p1 = optarg;
    684     0  stevel 			do {
    685     0  stevel 				zoneid_t id;
    686     0  stevel 
    687     0  stevel 				parg = getarg(&p1);
    688     0  stevel 				if (zone_get_id(parg, &id) != 0) {
    689     0  stevel 					pgerrflg++;
    690     0  stevel 					(void) fprintf(stderr,
    691     0  stevel 					    gettext("ps: unknown zone %s\n"),
    692     0  stevel 					    parg);
    693     0  stevel 					continue;
    694     0  stevel 				}
    695     0  stevel 
    696     0  stevel 				if (nzoneid == zoneidsz) {
    697     0  stevel 					if ((zoneidsz *= 2) == 0)
    698     0  stevel 						zoneidsz = SIZ;
    699     0  stevel 					zoneid = Realloc(zoneid,
    700     0  stevel 					    zoneidsz * sizeof (zoneid_t));
    701     0  stevel 				}
    702     0  stevel 				zoneid[nzoneid++] = id;
    703     0  stevel 			} while (*p1);
    704     0  stevel 			break;
    705     0  stevel 		case 'Z':		/* show zone name */
    706     0  stevel 			Zflg++;
    707     0  stevel 			break;
    708     0  stevel 		default:			/* error on ? */
    709     0  stevel 			errflg++;
    710     0  stevel 			break;
    711     0  stevel 		}
    712     0  stevel 
    713     0  stevel 	if (errflg || optind < argc || pgerrflg)
    714     0  stevel 		usage();
    715     0  stevel 
    716     0  stevel 	if (tflg)
    717     0  stevel 		tty[ntty].tname = NULL;
    718     0  stevel 	/*
    719     0  stevel 	 * If an appropriate option has not been specified, use the
    720     0  stevel 	 * current terminal and effective uid as the default.
    721     0  stevel 	 */
    722  2685   akolb 	if (!(aflg|Aflg|dflg|Gflg|hflg|Uflg|uflg|tflg|pflg|gflg|sflg|zflg)) {
    723     0  stevel 		psinfo_t info;
    724     0  stevel 		int procfd;
    725     0  stevel 		char *name;
    726     0  stevel 		char pname[100];
    727     0  stevel 
    728     0  stevel 		/* get our own controlling tty name using /proc */
    729     0  stevel 		(void) snprintf(pname, sizeof (pname),
    730     0  stevel 		    "%s/self/psinfo", procdir);
    731     0  stevel 		if ((procfd = open(pname, O_RDONLY)) < 0 ||
    732     0  stevel 		    read(procfd, (char *)&info, sizeof (info)) < 0 ||
    733     0  stevel 		    info.pr_ttydev == PRNODEV) {
    734     0  stevel 			(void) fprintf(stderr,
    735     0  stevel 			    gettext("ps: no controlling terminal\n"));
    736     0  stevel 			exit(1);
    737     0  stevel 		}
    738     0  stevel 		(void) close(procfd);
    739     0  stevel 
    740     0  stevel 		i = 0;
    741     0  stevel 		name = gettty(&info);
    742     0  stevel 		if (*name == '?') {
    743     0  stevel 			(void) fprintf(stderr,
    744     0  stevel 			    gettext("ps: can't find controlling terminal\n"));
    745     0  stevel 			exit(1);
    746     0  stevel 		}
    747     0  stevel 		if (ntty == ttysz) {
    748     0  stevel 			if ((ttysz *= 2) == 0)
    749     0  stevel 				ttysz = NTTYS;
    750     0  stevel 			tty = Realloc(tty, (ttysz + 1) * sizeof (struct tty));
    751     0  stevel 		}
    752     0  stevel 		tty[ntty].tdev = info.pr_ttydev;
    753     0  stevel 		tty[ntty++].tname = name;
    754     0  stevel 		tty[ntty].tname = NULL;
    755     0  stevel 		tflg++;
    756     0  stevel 		tuid = getuid();
    757     0  stevel 	}
    758     0  stevel 	if (Aflg) {
    759     0  stevel 		Gflg = Uflg = uflg = pflg = sflg = gflg = aflg = dflg = 0;
    760  2685   akolb 		zflg = hflg = 0;
    761     0  stevel 	}
    762     0  stevel 	if (Aflg | aflg | dflg)
    763     0  stevel 		tflg = 0;
    764     0  stevel 
    765     0  stevel 	i = 0;		/* prepare to exit on name lookup errors */
    766     0  stevel 	i += uconv(&euid_tbl);
    767     0  stevel 	i += uconv(&ruid_tbl);
    768     0  stevel 	i += gconv(&egid_tbl);
    769     0  stevel 	i += gconv(&rgid_tbl);
    770     0  stevel 	if (i)
    771     0  stevel 		exit(1);
    772     0  stevel 
    773     0  stevel 	/* allocate a buffer for lwpsinfo structures */
    774     0  stevel 	lpbufsize = 4096;
    775     0  stevel 	if (Lflg && (lpsinfobuf = malloc(lpbufsize)) == NULL) {
    776     0  stevel 		(void) fprintf(stderr,
    777     0  stevel 		    gettext("ps: no memory\n"));
    778     0  stevel 		exit(1);
    779     0  stevel 	}
    780     0  stevel 
    781     0  stevel 	if (fields) {	/* print user-specified header */
    782     0  stevel 		if (do_header) {
    783     0  stevel 			struct field *f;
    784     0  stevel 
    785     0  stevel 			for (f = fields; f != NULL; f = f->next) {
    786     0  stevel 				if (f != fields)
    787     0  stevel 					(void) printf(" ");
    788     0  stevel 				switch (f->fname) {
    789     0  stevel 				case F_TTY:
    790     0  stevel 					(void) printf("%-*s",
    791     0  stevel 					    f->width, f->header);
    792     0  stevel 					break;
    793     0  stevel 				case F_FNAME:
    794     0  stevel 				case F_COMM:
    795     0  stevel 				case F_ARGS:
    796     0  stevel 					/*
    797     0  stevel 					 * Print these headers full width
    798     0  stevel 					 * unless they appear at the end.
    799     0  stevel 					 */
    800     0  stevel 					if (f->next != NULL) {
    801     0  stevel 						(void) printf("%-*s",
    802     0  stevel 						    f->width, f->header);
    803     0  stevel 					} else {
    804     0  stevel 						(void) printf("%s",
    805     0  stevel 						    f->header);
    806     0  stevel 					}
    807     0  stevel 					break;
    808     0  stevel 				default:
    809     0  stevel 					(void) printf("%*s",
    810     0  stevel 					    f->width, f->header);
    811     0  stevel 					break;
    812     0  stevel 				}
    813     0  stevel 			}
    814     0  stevel 			(void) printf("\n");
    815     0  stevel 		}
    816     0  stevel 	} else {	/* print standard header */
    817  8822  Casper 		/*
    818  8822  Casper 		 * All fields before 'PID' are printed with a trailing space
    819  8822  Casper 		 * as a separator and that is how we print the headers too.
    820  8822  Casper 		 */
    821     0  stevel 		if (lflg) {
    822     0  stevel 			if (yflg)
    823  8822  Casper 				(void) printf("S ");
    824     0  stevel 			else
    825  8822  Casper 				(void) printf(" F S ");
    826     0  stevel 		}
    827     0  stevel 		if (Zflg)
    828  8822  Casper 			(void) printf("    ZONE ");
    829     0  stevel 		if (fflg) {
    830  8822  Casper 			(void) printf("     UID ");
    831     0  stevel 		} else if (lflg)
    832  8822  Casper 			(void) printf("   UID ");
    833     0  stevel 
    834  8822  Casper 		(void) printf("%*s", pidwidth,  "PID");
    835     0  stevel 		if (lflg || fflg)
    836     0  stevel 			(void) printf(" %*s", pidwidth, "PPID");
    837     0  stevel 		if (jflg)
    838     0  stevel 			(void) printf(" %*s %*s", pidwidth, "PGID",
    839     0  stevel 			    pidwidth, "SID");
    840     0  stevel 		if (Lflg)
    841     0  stevel 			(void) printf("   LWP");
    842     0  stevel 		if (Pflg)
    843     0  stevel 			(void) printf(" PSR");
    844     0  stevel 		if (Lflg && fflg)
    845     0  stevel 			(void) printf("  NLWP");
    846     0  stevel 		if (cflg)
    847     0  stevel 			(void) printf("  CLS PRI");
    848     0  stevel 		else if (lflg || fflg) {
    849     0  stevel 			(void) printf("   C");
    850     0  stevel 			if (lflg)
    851     0  stevel 				(void) printf(" PRI NI");
    852     0  stevel 		}
    853     0  stevel 		if (lflg) {
    854     0  stevel 			if (yflg)
    855     0  stevel 				(void) printf("   RSS     SZ    WCHAN");
    856     0  stevel 			else
    857     0  stevel 				(void) printf("     ADDR     SZ    WCHAN");
    858     0  stevel 		}
    859     0  stevel 		if (fflg)
    860  2966  sayama 			(void) printf(" %s", loc_stime_str);
    861  2685   akolb 		if (Hflg)
    862  2685   akolb 			(void) printf(" LGRP");
    863     0  stevel 		if (Lflg)
    864     0  stevel 			(void) printf(" TTY        LTIME CMD\n");
    865     0  stevel 		else
    866     0  stevel 			(void) printf(" TTY         TIME CMD\n");
    867     0  stevel 	}
    868     0  stevel 
    869     0  stevel 
    870  2685   akolb 	if (pflg && !(aflg|Aflg|dflg|Gflg|Uflg|uflg|hflg|tflg|gflg|sflg|zflg) &&
    871     0  stevel 	    npid <= PTHRESHOLD) {
    872     0  stevel 		/*
    873     0  stevel 		 * If we are looking at specific processes go straight
    874     0  stevel 		 * to their /proc entries and don't scan /proc.
    875     0  stevel 		 */
    876     0  stevel 		int i;
    877     0  stevel 
    878     0  stevel 		(void) qsort(pid, npid, sizeof (pid_t), pidcmp);
    879     0  stevel 		for (i = 0; i < npid; i++) {
    880     0  stevel 			char pname[12];
    881     0  stevel 
    882     0  stevel 			if (i >= 1 && pid[i] == pid[i - 1])
    883     0  stevel 				continue;
    884     0  stevel 			(void) sprintf(pname, "%d", (int)pid[i]);
    885     0  stevel 			if (print_proc(pname) == 0)
    886     0  stevel 				retcode = 0;
    887     0  stevel 		}
    888     0  stevel 	} else {
    889     0  stevel 		/*
    890     0  stevel 		 * Determine which processes to print info about by searching
    891     0  stevel 		 * the /proc directory and looking at each process.
    892     0  stevel 		 */
    893     0  stevel 		if ((dirp = opendir(procdir)) == NULL) {
    894     0  stevel 			(void) fprintf(stderr,
    895     0  stevel 			    gettext("ps: cannot open PROC directory %s\n"),
    896     0  stevel 			    procdir);
    897     0  stevel 			exit(1);
    898     0  stevel 		}
    899     0  stevel 
    900     0  stevel 		/* for each active process --- */
    901     0  stevel 		while (dentp = readdir(dirp)) {
    902     0  stevel 			if (dentp->d_name[0] == '.')    /* skip . and .. */
    903     0  stevel 				continue;
    904     0  stevel 			if (print_proc(dentp->d_name) == 0)
    905     0  stevel 				retcode = 0;
    906     0  stevel 		}
    907     0  stevel 
    908     0  stevel 		(void) closedir(dirp);
    909     0  stevel 	}
    910     0  stevel 	return (retcode);
    911     0  stevel }
    912     0  stevel 
    913     0  stevel 
    914     0  stevel int
    915     0  stevel print_proc(char *pid_name)
    916     0  stevel {
    917     0  stevel 	char	pname[PATH_MAX];
    918     0  stevel 	int	pdlen;
    919     0  stevel 	int	found;
    920     0  stevel 	int	procfd; /* filedescriptor for /proc/nnnnn/psinfo */
    921     0  stevel 	char	*tp;    /* ptr to ttyname,  if any */
    922     0  stevel 	psinfo_t info;  /* process information from /proc */
    923     0  stevel 	lwpsinfo_t *lwpsinfo;   /* array of lwpsinfo structs */
    924     0  stevel 
    925     0  stevel 	pdlen = snprintf(pname, sizeof (pname), "%s/%s/", procdir, pid_name);
    926     0  stevel 	if (pdlen >= sizeof (pname) - 10)
    927     0  stevel 		return (1);
    928     0  stevel retry:
    929     0  stevel 	(void) strcpy(&pname[pdlen], "psinfo");
    930     0  stevel 	if ((procfd = open(pname, O_RDONLY)) == -1) {
    931     0  stevel 		/* Process may have exited meanwhile. */
    932     0  stevel 		return (1);
    933     0  stevel 	}
    934     0  stevel 	/*
    935     0  stevel 	 * Get the info structure for the process and close quickly.
    936     0  stevel 	 */
    937     0  stevel 	if (read(procfd, (char *)&info, sizeof (info)) < 0) {
    938     0  stevel 		int	saverr = errno;
    939     0  stevel 
    940     0  stevel 		(void) close(procfd);
    941     0  stevel 		if (saverr == EAGAIN)
    942     0  stevel 			goto retry;
    943     0  stevel 		if (saverr != ENOENT)
    944     0  stevel 			(void) fprintf(stderr,
    945     0  stevel 			    gettext("ps: read() on %s: %s\n"),
    946     0  stevel 			    pname, err_string(saverr));
    947     0  stevel 		return (1);
    948     0  stevel 	}
    949     0  stevel 	(void) close(procfd);
    950     0  stevel 
    951     0  stevel 	found = 0;
    952     0  stevel 	if (info.pr_lwp.pr_state == 0)	/* can't happen? */
    953     0  stevel 		return (1);
    954     0  stevel 
    955     0  stevel 	/*
    956     0  stevel 	 * Omit session group leaders for 'a' and 'd' options.
    957     0  stevel 	 */
    958     0  stevel 	if ((info.pr_pid == info.pr_sid) && (dflg || aflg))
    959     0  stevel 		return (1);
    960     0  stevel 	if (Aflg || dflg)
    961     0  stevel 		found++;
    962     0  stevel 	else if (pflg && search(pid, npid, info.pr_pid))
    963     0  stevel 		found++;	/* ppid in p option arg list */
    964  4321  casper 	else if (uflg && ugfind((id_t)info.pr_euid, &euid_tbl))
    965     0  stevel 		found++;	/* puid in u option arg list */
    966  4321  casper 	else if (Uflg && ugfind((id_t)info.pr_uid, &ruid_tbl))
    967     0  stevel 		found++;	/* puid in U option arg list */
    968     0  stevel #ifdef NOT_YET
    969  4321  casper 	else if (gflg && ugfind((id_t)info.pr_egid, &egid_tbl))
    970     0  stevel 		found++;	/* pgid in g option arg list */
    971     0  stevel #endif	/* NOT_YET */
    972  4321  casper 	else if (Gflg && ugfind((id_t)info.pr_gid, &rgid_tbl))
    973     0  stevel 		found++;	/* pgid in G option arg list */
    974     0  stevel 	else if (gflg && search(grpid, ngrpid, info.pr_pgid))
    975     0  stevel 		found++;	/* grpid in g option arg list */
    976     0  stevel 	else if (sflg && search(sessid, nsessid, info.pr_sid))
    977     0  stevel 		found++;	/* sessid in s option arg list */
    978     0  stevel 	else if (zflg && search(zoneid, nzoneid, info.pr_zoneid))
    979     0  stevel 		found++;	/* zoneid in z option arg list */
    980  2685   akolb 	else if (hflg && search((pid_t *)lgrps, nlgrps, info.pr_lwp.pr_lgrp))
    981  2685   akolb 		found++;	/* home lgroup in h option arg list */
    982     0  stevel 	if (!found && !tflg && !aflg)
    983     0  stevel 		return (1);
    984     0  stevel 	if (!prfind(found, &info, &tp))
    985     0  stevel 		return (1);
    986     0  stevel 	if (Lflg && (info.pr_nlwp + info.pr_nzomb) > 1) {
    987     0  stevel 		ssize_t prsz;
    988     0  stevel 
    989     0  stevel 		(void) strcpy(&pname[pdlen], "lpsinfo");
    990     0  stevel 		if ((procfd = open(pname, O_RDONLY)) == -1)
    991     0  stevel 			return (1);
    992     0  stevel 		/*
    993     0  stevel 		 * Get the info structures for the lwps.
    994     0  stevel 		 */
    995     0  stevel 		prsz = read(procfd, lpsinfobuf, lpbufsize);
    996     0  stevel 		if (prsz == -1) {
    997     0  stevel 			int	saverr = errno;
    998     0  stevel 
    999     0  stevel 			(void) close(procfd);
   1000     0  stevel 			if (saverr == EAGAIN)
   1001     0  stevel 				goto retry;
   1002     0  stevel 			if (saverr != ENOENT)
   1003     0  stevel 				(void) fprintf(stderr,
   1004     0  stevel 				    gettext("ps: read() on %s: %s\n"),
   1005     0  stevel 				    pname, err_string(saverr));
   1006     0  stevel 			return (1);
   1007     0  stevel 		}
   1008     0  stevel 		(void) close(procfd);
   1009     0  stevel 		if (prsz == lpbufsize) {
   1010     0  stevel 			/*
   1011     0  stevel 			 * buffer overflow. Realloc new buffer.
   1012     0  stevel 			 * Error handling is done in Realloc().
   1013     0  stevel 			 */
   1014     0  stevel 			lpbufsize *= 2;
   1015     0  stevel 			lpsinfobuf = Realloc(lpsinfobuf, lpbufsize);
   1016     0  stevel 			goto retry;
   1017     0  stevel 		}
   1018     0  stevel 		if (lpsinfobuf->pr_nent != (info.pr_nlwp + info.pr_nzomb))
   1019     0  stevel 			goto retry;
   1020     0  stevel 		lwpsinfo = (lwpsinfo_t *)(lpsinfobuf + 1);
   1021     0  stevel 	}
   1022     0  stevel 	if (!Lflg || (info.pr_nlwp + info.pr_nzomb) <= 1) {
   1023     0  stevel 		prcom(&info, tp);
   1024     0  stevel 	} else {
   1025     0  stevel 		int nlwp = 0;
   1026     0  stevel 
   1027     0  stevel 		do {
   1028     0  stevel 			info.pr_lwp = *lwpsinfo;
   1029     0  stevel 			prcom(&info, tp);
   1030     0  stevel 			/* LINTED improper alignment */
   1031     0  stevel 			lwpsinfo = (lwpsinfo_t *)((char *)lwpsinfo +
   1032  8233     dme 			    lpsinfobuf->pr_entsize);
   1033     0  stevel 		} while (++nlwp < lpsinfobuf->pr_nent);
   1034     0  stevel 	}
   1035     0  stevel 	return (0);
   1036     0  stevel }
   1037     0  stevel 
   1038     0  stevel 
   1039     0  stevel static void
   1040     0  stevel usage(void)		/* print usage message and quit */
   1041     0  stevel {
   1042     0  stevel 	static char usage1[] =
   1043  2685   akolb 	    "ps [ -aAdefHlcjLPyZ ] [ -o format ] [ -t termlist ]";
   1044     0  stevel 	static char usage2[] =
   1045     0  stevel 	    "\t[ -u userlist ] [ -U userlist ] [ -G grouplist ]";
   1046     0  stevel 	static char usage3[] =
   1047  2685   akolb 	    "\t[ -p proclist ] [ -g pgrplist ] [ -s sidlist ] [ -z zonelist ] "
   1048  2685   akolb 	    "[-h lgrplist]";
   1049     0  stevel 	static char usage4[] =
   1050     0  stevel 	    "  'format' is one or more of:";
   1051     0  stevel 	static char usage5[] =
   1052     0  stevel 	    "\tuser ruser group rgroup uid ruid gid rgid pid ppid pgid "
   1053     0  stevel 	    "sid taskid ctid";
   1054     0  stevel 	static char usage6[] =
   1055     0  stevel 	    "\tpri opri pcpu pmem vsz rss osz nice class time etime stime zone "
   1056     0  stevel 	    "zoneid";
   1057     0  stevel 	static char usage7[] =
   1058     0  stevel 	    "\tf s c lwp nlwp psr tty addr wchan fname comm args "
   1059  2685   akolb 	    "projid project pset lgrp";
   1060     0  stevel 
   1061     0  stevel 	(void) fprintf(stderr,
   1062     0  stevel 	    gettext("usage: %s\n%s\n%s\n%s\n%s\n%s\n%s\n"),
   1063     0  stevel 	    gettext(usage1), gettext(usage2), gettext(usage3),
   1064     0  stevel 	    gettext(usage4), gettext(usage5), gettext(usage6), gettext(usage7));
   1065     0  stevel 	exit(1);
   1066     0  stevel }
   1067     0  stevel 
   1068     0  stevel /*
   1069     0  stevel  * getarg() finds the next argument in list and copies arg into argbuf.
   1070     0  stevel  * p1 first pts to arg passed back from getopt routine.  p1 is then
   1071     0  stevel  * bumped to next character that is not a comma or blank -- p1 NULL
   1072     0  stevel  * indicates end of list.
   1073     0  stevel  */
   1074     0  stevel static char *
   1075     0  stevel getarg(char **pp1)
   1076     0  stevel {
   1077     0  stevel 	static char argbuf[ARGSIZ];
   1078     0  stevel 	char *p1 = *pp1;
   1079     0  stevel 	char *parga = argbuf;
   1080     0  stevel 	int c;
   1081     0  stevel 
   1082     0  stevel 	while ((c = *p1) != '\0' && (c == ',' || isspace(c)))
   1083     0  stevel 		p1++;
   1084     0  stevel 
   1085     0  stevel 	while ((c = *p1) != '\0' && c != ',' && !isspace(c)) {
   1086     0  stevel 		if (parga < argbuf + ARGSIZ - 1)
   1087     0  stevel 			*parga++ = c;
   1088     0  stevel 		p1++;
   1089     0  stevel 	}
   1090     0  stevel 	*parga = '\0';
   1091     0  stevel 
   1092     0  stevel 	while ((c = *p1) != '\0' && (c == ',' || isspace(c)))
   1093     0  stevel 		p1++;
   1094     0  stevel 
   1095     0  stevel 	*pp1 = p1;
   1096     0  stevel 
   1097     0  stevel 	return (argbuf);
   1098     0  stevel }
   1099     0  stevel 
   1100     0  stevel /*
   1101     0  stevel  * parse_format() takes the argument to the -o option,
   1102     0  stevel  * sets up the next output field structure, and returns
   1103     0  stevel  * a pointer to any further output field specifier(s).
   1104     0  stevel  * As a side-effect, it increments errflg if encounters a format error.
   1105     0  stevel  */
   1106     0  stevel static char *
   1107     0  stevel parse_format(char *arg)
   1108     0  stevel {
   1109     0  stevel 	int c;
   1110     0  stevel 	char *name;
   1111     0  stevel 	char *header = NULL;
   1112     0  stevel 	int width = 0;
   1113     0  stevel 	struct def_field *df;
   1114     0  stevel 	struct field *f;
   1115     0  stevel 
   1116     0  stevel 	while ((c = *arg) != '\0' && (c == ',' || isspace(c)))
   1117     0  stevel 		arg++;
   1118     0  stevel 	if (c == '\0')
   1119     0  stevel 		return (NULL);
   1120     0  stevel 	name = arg;
   1121     0  stevel 	arg = strpbrk(arg, " \t\r\v\f\n,=");
   1122     0  stevel 	if (arg != NULL) {
   1123     0  stevel 		c = *arg;
   1124     0  stevel 		*arg++ = '\0';
   1125     0  stevel 		if (c == '=') {
   1126     0  stevel 			char *s;
   1127     0  stevel 
   1128     0  stevel 			header = arg;
   1129     0  stevel 			arg = NULL;
   1130     0  stevel 			width = strlen(header);
   1131     0  stevel 			s = header + width;
   1132     0  stevel 			while (s > header && isspace(*--s))
   1133     0  stevel 				*s = '\0';
   1134     0  stevel 			while (isspace(*header))
   1135     0  stevel 				header++;
   1136     0  stevel 		}
   1137     0  stevel 	}
   1138     0  stevel 	for (df = &fname[0]; df < &fname[NFIELDS]; df++)
   1139     0  stevel 		if (strcmp(name, df->fname) == 0) {
   1140     0  stevel 			if (strcmp(name, "lwp") == 0)
   1141     0  stevel 				Lflg++;
   1142     0  stevel 			break;
   1143     0  stevel 		}
   1144     0  stevel 	if (df >= &fname[NFIELDS]) {
   1145     0  stevel 		(void) fprintf(stderr,
   1146  8233     dme 		    gettext("ps: unknown output format: -o %s\n"),
   1147  8233     dme 		    name);
   1148     0  stevel 		errflg++;
   1149     0  stevel 		return (arg);
   1150     0  stevel 	}
   1151     0  stevel 	if ((f = malloc(sizeof (*f))) == NULL) {
   1152     0  stevel 		(void) fprintf(stderr,
   1153     0  stevel 		    gettext("ps: malloc() for output format failed, %s\n"),
   1154     0  stevel 		    err_string(errno));
   1155     0  stevel 		exit(1);
   1156     0  stevel 	}
   1157     0  stevel 	f->next = NULL;
   1158     0  stevel 	f->fname = df - &fname[0];
   1159     0  stevel 	f->header = header? header : df->header;
   1160     0  stevel 	if (width == 0)
   1161     0  stevel 		width = df->width;
   1162     0  stevel 	if (*f->header != '\0')
   1163     0  stevel 		do_header = 1;
   1164     0  stevel 	f->width = max(width, df->minwidth);
   1165     0  stevel 
   1166     0  stevel 	if (fields == NULL)
   1167     0  stevel 		fields = last_field = f;
   1168     0  stevel 	else {
   1169     0  stevel 		last_field->next = f;
   1170     0  stevel 		last_field = f;
   1171     0  stevel 	}
   1172     0  stevel 
   1173     0  stevel 	return (arg);
   1174     0  stevel }
   1175     0  stevel 
   1176     0  stevel static char *
   1177     0  stevel devlookup(dev_t ddev)
   1178     0  stevel {
   1179     0  stevel 	struct devl *dp;
   1180     0  stevel 	int i;
   1181     0  stevel 
   1182     0  stevel 	for (dp = devl, i = 0; i < ndev; dp++, i++) {
   1183     0  stevel 		if (dp->ddev == ddev)
   1184     0  stevel 			return (dp->dname);
   1185     0  stevel 	}
   1186     0  stevel 	return (NULL);
   1187     0  stevel }
   1188     0  stevel 
   1189     0  stevel static char *
   1190     0  stevel devadd(char *name, dev_t ddev)
   1191     0  stevel {
   1192     0  stevel 	struct devl *dp;
   1193     0  stevel 	int leng, start, i;
   1194     0  stevel 
   1195     0  stevel 	if (ndev == maxdev) {
   1196     0  stevel 		maxdev += DNINCR;
   1197     0  stevel 		devl = Realloc(devl, maxdev * sizeof (struct devl));
   1198     0  stevel 	}
   1199     0  stevel 	dp = &devl[ndev++];
   1200     0  stevel 
   1201     0  stevel 	dp->ddev = ddev;
   1202     0  stevel 	if (name == NULL) {
   1203     0  stevel 		(void) strcpy(dp->dname, "??");
   1204     0  stevel 		return (dp->dname);
   1205     0  stevel 	}
   1206     0  stevel 
   1207     0  stevel 	leng = strlen(name);
   1208     0  stevel 	/* Strip off /dev/ */
   1209     0  stevel 	if (leng < DNSIZE + 4)
   1210     0  stevel 		(void) strcpy(dp->dname, &name[5]);
   1211     0  stevel 	else {
   1212     0  stevel 		start = leng - DNSIZE - 1;
   1213     0  stevel 
   1214     0  stevel 		for (i = start; i < leng && name[i] != '/'; i++)
   1215     0  stevel 				;
   1216     0  stevel 		if (i == leng)
   1217     0  stevel 			(void) strncpy(dp->dname, &name[start], DNSIZE);
   1218     0  stevel 		else
   1219     0  stevel 			(void) strncpy(dp->dname, &name[i+1], DNSIZE);
   1220     0  stevel 	}
   1221     0  stevel 	return (dp->dname);
   1222     0  stevel }
   1223     0  stevel 
   1224     0  stevel /*
   1225     0  stevel  * gettty returns the user's tty number or ? if none.
   1226     0  stevel  */
   1227     0  stevel static char *
   1228     0  stevel gettty(psinfo_t *psinfo)
   1229     0  stevel {
   1230     0  stevel 	extern char *_ttyname_dev(dev_t, char *, size_t);
   1231     0  stevel 	char devname[TTYNAME_MAX];
   1232     0  stevel 	char *retval;
   1233     0  stevel 
   1234     0  stevel 	if (psinfo->pr_ttydev == PRNODEV)
   1235     0  stevel 		return ("?");
   1236     0  stevel 
   1237     0  stevel 	if ((retval = devlookup(psinfo->pr_ttydev)) != NULL)
   1238     0  stevel 		return (retval);
   1239     0  stevel 
   1240     0  stevel 	retval = _ttyname_dev(psinfo->pr_ttydev, devname, sizeof (devname));
   1241     0  stevel 
   1242     0  stevel 	return (devadd(retval, psinfo->pr_ttydev));
   1243     0  stevel }
   1244     0  stevel 
   1245     0  stevel /*
   1246     0  stevel  * Find the process's tty and return 1 if process is to be printed.
   1247     0  stevel  */
   1248     0  stevel static int
   1249     0  stevel prfind(int found, psinfo_t *psinfo, char **tpp)
   1250     0  stevel {
   1251     0  stevel 	char	*tp;
   1252     0  stevel 	struct tty *ttyp;
   1253     0  stevel 
   1254     0  stevel 	if (psinfo->pr_nlwp == 0) {
   1255     0  stevel 		/* process is a zombie */
   1256     0  stevel 		*tpp = "?";
   1257     0  stevel 		if (tflg && !found)
   1258     0  stevel 			return (0);
   1259     0  stevel 		return (1);
   1260     0  stevel 	}
   1261     0  stevel 
   1262     0  stevel 	/*
   1263     0  stevel 	 * Get current terminal.  If none ("?") and 'a' is set, don't print
   1264     0  stevel 	 * info.  If 't' is set, check if term is in list of desired terminals
   1265     0  stevel 	 * and print it if it is.
   1266     0  stevel 	 */
   1267     0  stevel 	tp = gettty(psinfo);
   1268     0  stevel 	if (aflg && *tp == '?') {
   1269     0  stevel 		*tpp = tp;
   1270     0  stevel 		return (0);
   1271     0  stevel 	}
   1272     0  stevel 	if (tflg && !found) {
   1273     0  stevel 		int match = 0;
   1274     0  stevel 		char *other = NULL;
   1275     0  stevel 		for (ttyp = tty; ttyp->tname != NULL; ttyp++) {
   1276     0  stevel 			/*
   1277     0  stevel 			 * Look for a name match
   1278     0  stevel 			 */
   1279     0  stevel 			if (strcmp(tp, ttyp->tname) == 0) {
   1280     0  stevel 				match = 1;
   1281     0  stevel 				break;
   1282     0  stevel 			}
   1283     0  stevel 			/*
   1284     0  stevel 			 * Look for same device under different names.
   1285     0  stevel 			 */
   1286     0  stevel 			if ((other == NULL) &&
   1287     0  stevel 			    (ttyp->tdev != PRNODEV) &&
   1288     0  stevel 			    (psinfo->pr_ttydev == ttyp->tdev))
   1289     0  stevel 				other = ttyp->tname;
   1290     0  stevel 		}
   1291     0  stevel 		if (!match && (other != NULL)) {
   1292     0  stevel 			/*
   1293     0  stevel 			 * found under a different name
   1294     0  stevel 			 */
   1295     0  stevel 			match = 1;
   1296     0  stevel 			tp = other;
   1297     0  stevel 		}
   1298  4321  casper 		if (!match || (tuid != (uid_t)-1 && tuid != psinfo->pr_euid)) {
   1299     0  stevel 			/*
   1300     0  stevel 			 * not found OR not matching euid
   1301     0  stevel 			 */
   1302     0  stevel 			*tpp = tp;
   1303     0  stevel 			return (0);
   1304     0  stevel 		}
   1305     0  stevel 	}
   1306     0  stevel 	*tpp = tp;
   1307     0  stevel 	return (1);
   1308     0  stevel }
   1309     0  stevel 
   1310     0  stevel /*
   1311     0  stevel  * Print info about the process.
   1312     0  stevel  */
   1313     0  stevel static void
   1314     0  stevel prcom(psinfo_t *psinfo, char *ttyp)
   1315     0  stevel {
   1316     0  stevel 	char	*cp;
   1317     0  stevel 	long	tm;
   1318     0  stevel 	int	bytesleft;
   1319     0  stevel 	int	wcnt, length;
   1320     0  stevel 	wchar_t	wchar;
   1321     0  stevel 	struct passwd *pwd;
   1322     0  stevel 	int	zombie_lwp;
   1323     0  stevel 	char	zonename[ZONENAME_MAX];
   1324     0  stevel 
   1325     0  stevel 	/*
   1326     0  stevel 	 * If process is zombie, call zombie print routine and return.
   1327     0  stevel 	 */
   1328     0  stevel 	if (psinfo->pr_nlwp == 0) {
   1329     0  stevel 		if (fields != NULL)
   1330     0  stevel 			pr_fields(psinfo, ttyp, print_zombie_field);
   1331     0  stevel 		else
   1332     0  stevel 			przom(psinfo);
   1333     0  stevel 		return;
   1334     0  stevel 	}
   1335     0  stevel 
   1336     0  stevel 	zombie_lwp = (Lflg && psinfo->pr_lwp.pr_sname == 'Z');
   1337     0  stevel 
   1338     0  stevel 	/*
   1339     0  stevel 	 * If user specified '-o format', print requested fields and return.
   1340     0  stevel 	 */
   1341     0  stevel 	if (fields != NULL) {
   1342     0  stevel 		pr_fields(psinfo, ttyp, print_field);
   1343     0  stevel 		return;
   1344     0  stevel 	}
   1345     0  stevel 
   1346     0  stevel 	/*
   1347     0  stevel 	 * All fields before 'PID' are printed with a trailing space as a
   1348  8822  Casper 	 * separator, rather than keeping track of which column is first.  All
   1349     0  stevel 	 * other fields are printed with a leading space.
   1350     0  stevel 	 */
   1351     0  stevel 	if (lflg) {
   1352     0  stevel 		if (!yflg)
   1353     0  stevel 			(void) printf("%2x ", psinfo->pr_flag & 0377); /* F */
   1354     0  stevel 		(void) printf("%c ", psinfo->pr_lwp.pr_sname);	/* S */
   1355     0  stevel 	}
   1356     0  stevel 
   1357     0  stevel 	if (Zflg) {						/* ZONE */
   1358     0  stevel 		if (getzonenamebyid(psinfo->pr_zoneid, zonename,
   1359     0  stevel 		    sizeof (zonename)) < 0) {
   1360  8822  Casper 			(void) printf(" %7.7d ", ((int)psinfo->pr_zoneid));
   1361     0  stevel 		} else {
   1362     0  stevel 			(void) printf("%8.8s ", zonename);
   1363     0  stevel 		}
   1364     0  stevel 	}
   1365     0  stevel 
   1366     0  stevel 	if (fflg) {						/* UID */
   1367     0  stevel 		if ((pwd = getpwuid(psinfo->pr_euid)) != NULL)
   1368     0  stevel 			(void) printf("%8.8s ", pwd->pw_name);
   1369     0  stevel 		else
   1370  8822  Casper 			(void) printf(" %7.7u ", psinfo->pr_euid);
   1371     0  stevel 	} else if (lflg) {
   1372  4321  casper 		(void) printf("%6u ", psinfo->pr_euid);
   1373     0  stevel 	}
   1374     0  stevel 	(void) printf("%*d", pidwidth, (int)psinfo->pr_pid); /* PID */
   1375     0  stevel 	if (lflg || fflg)
   1376     0  stevel 		(void) printf(" %*d", pidwidth,
   1377     0  stevel 		    (int)psinfo->pr_ppid); /* PPID */
   1378     0  stevel 	if (jflg) {
   1379     0  stevel 		(void) printf(" %*d", pidwidth,
   1380     0  stevel 		    (int)psinfo->pr_pgid);	/* PGID */
   1381     0  stevel 		(void) printf(" %*d", pidwidth,
   1382     0  stevel 		    (int)psinfo->pr_sid);	/* SID  */
   1383     0  stevel 	}
   1384     0  stevel 	if (Lflg)
   1385     0  stevel 		(void) printf(" %5d", (int)psinfo->pr_lwp.pr_lwpid); /* LWP */
   1386     0  stevel 	if (Pflg) {
   1387     0  stevel 		if (psinfo->pr_lwp.pr_bindpro == PBIND_NONE)	/* PSR */
   1388     0  stevel 			(void) printf("   -");
   1389     0  stevel 		else
   1390     0  stevel 			(void) printf(" %3d", psinfo->pr_lwp.pr_bindpro);
   1391     0  stevel 	}
   1392     0  stevel 	if (Lflg && fflg)					/* NLWP */
   1393     0  stevel 		(void) printf(" %5d", psinfo->pr_nlwp + psinfo->pr_nzomb);
   1394     0  stevel 	if (cflg) {
   1395     0  stevel 		if (zombie_lwp)					/* CLS */
   1396     0  stevel 			(void) printf("     ");
   1397     0  stevel 		else
   1398     0  stevel 			(void) printf(" %4s", psinfo->pr_lwp.pr_clname);
   1399     0  stevel 		(void) printf(" %3d", psinfo->pr_lwp.pr_pri);	/* PRI */
   1400     0  stevel 	} else if (lflg || fflg) {
   1401     0  stevel 		(void) printf(" %3d", psinfo->pr_lwp.pr_cpu & 0377); /* C   */
   1402     0  stevel 		if (lflg) {					    /* PRI NI */
   1403     0  stevel 			/*
   1404     0  stevel 			 * Print priorities the old way (lower numbers
   1405     0  stevel 			 * mean higher priority) and print nice value
   1406     0  stevel 			 * for time sharing procs.
   1407     0  stevel 			 */
   1408     0  stevel 			(void) printf(" %3d", psinfo->pr_lwp.pr_oldpri);
   1409     0  stevel 			if (psinfo->pr_lwp.pr_oldpri != 0)
   1410     0  stevel 				(void) printf(" %2d", psinfo->pr_lwp.pr_nice);
   1411     0  stevel 			else
   1412     0  stevel 				(void) printf(" %2.2s",
   1413     0  stevel 				    psinfo->pr_lwp.pr_clname);
   1414     0  stevel 		}
   1415     0  stevel 	}
   1416     0  stevel 	if (lflg) {
   1417     0  stevel 		if (yflg) {
   1418     0  stevel 			if (psinfo->pr_flag & SSYS)		/* RSS */
   1419     0  stevel 				(void) printf("     0");
   1420     0  stevel 			else if (psinfo->pr_rssize)
   1421     0  stevel 				(void) printf(" %5lu",
   1422  8233     dme 				    (ulong_t)psinfo->pr_rssize);
   1423     0  stevel 			else
   1424     0  stevel 				(void) printf("     ?");
   1425     0  stevel 			if (psinfo->pr_flag & SSYS)		/* SZ */
   1426     0  stevel 				(void) printf("      0");
   1427     0  stevel 			else if (psinfo->pr_size)
   1428     0  stevel 				(void) printf(" %6lu",
   1429  8233     dme 				    (ulong_t)psinfo->pr_size);
   1430     0  stevel 			else
   1431     0  stevel 				(void) printf("      ?");
   1432     0  stevel 		} else {
   1433     0  stevel #ifndef _LP64
   1434     0  stevel 			if (psinfo->pr_addr)			/* ADDR */
   1435     0  stevel 				(void) printf(" %8lx",
   1436  8233     dme 				    (ulong_t)psinfo->pr_addr);
   1437     0  stevel 			else
   1438     0  stevel #endif
   1439     0  stevel 				(void) printf("        ?");
   1440     0  stevel 			if (psinfo->pr_flag & SSYS)		/* SZ */
   1441     0  stevel 				(void) printf("      0");
   1442     0  stevel 			else if (psinfo->pr_size)
   1443     0  stevel 				(void) printf(" %6lu",
   1444     0  stevel 				    (ulong_t)psinfo->pr_size / kbytes_per_page);
   1445     0  stevel 			else
   1446     0  stevel 				(void) printf("      ?");
   1447     0  stevel 		}
   1448     0  stevel 		if (psinfo->pr_lwp.pr_sname != 'S')		/* WCHAN */
   1449     0  stevel 			(void) printf("         ");
   1450     0  stevel #ifndef _LP64
   1451     0  stevel 		else if (psinfo->pr_lwp.pr_wchan)
   1452     0  stevel 			(void) printf(" %8lx",
   1453  8233     dme 			    (ulong_t)psinfo->pr_lwp.pr_wchan);
   1454     0  stevel #endif
   1455     0  stevel 		else
   1456     0  stevel 			(void) printf("        ?");
   1457     0  stevel 	}
   1458     0  stevel 	if (fflg) {						/* STIME */
   1459  2966  sayama 		int width = fname[F_STIME].width;
   1460     0  stevel 		if (Lflg)
   1461  2966  sayama 			prtime(psinfo->pr_lwp.pr_start, width + 1, 1);
   1462     0  stevel 		else
   1463  2966  sayama 			prtime(psinfo->pr_start, width + 1, 1);
   1464     0  stevel 	}
   1465  2685   akolb 
   1466  2685   akolb 	if (Hflg) {
   1467  2685   akolb 		/* Display home lgroup */
   1468  2685   akolb 		(void) printf(" %4d", (int)psinfo->pr_lwp.pr_lgrp);
   1469  2685   akolb 	}
   1470  2685   akolb 
   1471     0  stevel 	(void) printf(" %-8.14s", ttyp);			/* TTY */
   1472     0  stevel 	if (Lflg) {
   1473     0  stevel 		tm = psinfo->pr_lwp.pr_time.tv_sec;
   1474     0  stevel 		if (psinfo->pr_lwp.pr_time.tv_nsec > 500000000)
   1475     0  stevel 			tm++;
   1476     0  stevel 	} else {
   1477     0  stevel 		tm = psinfo->pr_time.tv_sec;
   1478     0  stevel 		if (psinfo->pr_time.tv_nsec > 500000000)
   1479     0  stevel 			tm++;
   1480     0  stevel 	}
   1481     0  stevel 	(void) printf(" %4ld:%.2ld", tm / 60, tm % 60);		/* [L]TIME */
   1482     0  stevel 
   1483     0  stevel 	if (zombie_lwp) {
   1484     0  stevel 		(void) printf(" <defunct>\n");
   1485     0  stevel 		return;
   1486     0  stevel 	}
   1487     0  stevel 
   1488     0  stevel 	if (!fflg) {						/* CMD */
   1489     0  stevel 		wcnt = namencnt(psinfo->pr_fname, 16, 8);
   1490     0  stevel 		(void) printf(" %.*s\n", wcnt, psinfo->pr_fname);
   1491     0  stevel 		return;
   1492     0  stevel 	}
   1493  2685   akolb 
   1494     0  stevel 
   1495     0  stevel 	/*
   1496     0  stevel 	 * PRARGSZ == length of cmd arg string.
   1497     0  stevel 	 */
   1498     0  stevel 	psinfo->pr_psargs[PRARGSZ-1] = '\0';
   1499     0  stevel 	bytesleft = PRARGSZ;
   1500     0  stevel 	for (cp = psinfo->pr_psargs; *cp != '\0'; cp += length) {
   1501     0  stevel 		length = mbtowc(&wchar, cp, MB_LEN_MAX);
   1502     0  stevel 		if (length == 0)
   1503     0  stevel 			break;
   1504     0  stevel 		if (length < 0 || !iswprint(wchar)) {
   1505     0  stevel 			if (length < 0)
   1506     0  stevel 				length = 1;
   1507     0  stevel 			if (bytesleft <= length) {
   1508     0  stevel 				*cp = '\0';
   1509     0  stevel 				break;
   1510     0  stevel 			}
   1511     0  stevel 			/* omit the unprintable character */
   1512     0  stevel 			(void) memmove(cp, cp+length, bytesleft-length);
   1513     0  stevel 			length = 0;
   1514     0  stevel 		}
   1515     0  stevel 		bytesleft -= length;
   1516     0  stevel 	}
   1517     0  stevel 	wcnt = namencnt(psinfo->pr_psargs, PRARGSZ, lflg ? 35 : PRARGSZ);
   1518     0  stevel 	(void) printf(" %.*s\n", wcnt, psinfo->pr_psargs);
   1519     0  stevel }
   1520     0  stevel 
   1521     0  stevel /*
   1522     0  stevel  * Print percent from 16-bit binary fraction [0 .. 1]
   1523     0  stevel  * Round up .01 to .1 to indicate some small percentage (the 0x7000 below).
   1524     0  stevel  */
   1525     0  stevel static void
   1526     0  stevel prtpct(ushort_t pct, int width)
   1527     0  stevel {
   1528     0  stevel 	uint_t value = pct;	/* need 32 bits to compute with */
   1529     0  stevel 
   1530     0  stevel 	value = ((value * 1000) + 0x7000) >> 15;	/* [0 .. 1000] */
   1531     0  stevel 	if (value >= 1000)
   1532     0  stevel 		value = 999;
   1533     0  stevel 	if ((width -= 2) < 2)
   1534     0  stevel 		width = 2;
   1535     0  stevel 	(void) printf("%*u.%u", width, value / 10, value % 10);
   1536     0  stevel }
   1537     0  stevel 
   1538     0  stevel static void
   1539     0  stevel print_time(time_t tim, int width)
   1540     0  stevel {
   1541     0  stevel 	char buf[30];
   1542     0  stevel 	time_t seconds;
   1543     0  stevel 	time_t minutes;
   1544     0  stevel 	time_t hours;
   1545     0  stevel 	time_t days;
   1546     0  stevel 
   1547     0  stevel 	if (tim < 0) {
   1548     0  stevel 		(void) printf("%*s", width, "-");
   1549     0  stevel 		return;
   1550     0  stevel 	}
   1551     0  stevel 
   1552     0  stevel 	seconds = tim % 60;
   1553     0  stevel 	tim /= 60;
   1554     0  stevel 	minutes = tim % 60;
   1555     0  stevel 	tim /= 60;
   1556     0  stevel 	hours = tim % 24;
   1557     0  stevel 	days = tim / 24;
   1558     0  stevel 
   1559     0  stevel 	if (days > 0) {
   1560     0  stevel 		(void) snprintf(buf, sizeof (buf), "%ld-%2.2ld:%2.2ld:%2.2ld",
   1561     0  stevel 		    days, hours, minutes, seconds);
   1562     0  stevel 	} else if (hours > 0) {
   1563     0  stevel 		(void) snprintf(buf, sizeof (buf), "%2.2ld:%2.2ld:%2.2ld",
   1564     0  stevel 		    hours, minutes, seconds);
   1565     0  stevel 	} else {
   1566     0  stevel 		(void) snprintf(buf, sizeof (buf), "%2.2ld:%2.2ld",
   1567     0  stevel 		    minutes, seconds);
   1568     0  stevel 	}
   1569     0  stevel 
   1570     0  stevel 	(void) printf("%*s", width, buf);
   1571     0  stevel }
   1572     0  stevel 
   1573     0  stevel static void
   1574     0  stevel print_field(psinfo_t *psinfo, struct field *f, const char *ttyp)
   1575     0  stevel {
   1576     0  stevel 	int width = f->width;
   1577     0  stevel 	struct passwd *pwd;
   1578     0  stevel 	struct group *grp;
   1579     0  stevel 	time_t cputime;
   1580     0  stevel 	int bytesleft;
   1581     0  stevel 	int wcnt;
   1582     0  stevel 	wchar_t	wchar;
   1583     0  stevel 	char *cp;
   1584     0  stevel 	int length;
   1585     0  stevel 	ulong_t mask;
   1586     0  stevel 	char c, *csave;
   1587     0  stevel 	int zombie_lwp;
   1588     0  stevel 
   1589     0  stevel 	zombie_lwp = (Lflg && psinfo->pr_lwp.pr_sname == 'Z');
   1590     0  stevel 
   1591     0  stevel 	switch (f->fname) {
   1592     0  stevel 	case F_RUSER:
   1593     0  stevel 		if ((pwd = getpwuid(psinfo->pr_uid)) != NULL)
   1594     0  stevel 			(void) printf("%*s", width, pwd->pw_name);
   1595     0  stevel 		else
   1596  4321  casper 			(void) printf("%*u", width, psinfo->pr_uid);
   1597     0  stevel 		break;
   1598     0  stevel 	case F_USER:
   1599     0  stevel 		if ((pwd = getpwuid(psinfo->pr_euid)) != NULL)
   1600     0  stevel 			(void) printf("%*s", width, pwd->pw_name);
   1601     0  stevel 		else
   1602  4321  casper 			(void) printf("%*u", width, psinfo->pr_euid);
   1603     0  stevel 		break;
   1604     0  stevel 	case F_RGROUP:
   1605     0  stevel 		if ((grp = getgrgid(psinfo->pr_gid)) != NULL)
   1606     0  stevel 			(void) printf("%*s", width, grp->gr_name);
   1607     0  stevel 		else
   1608  4321  casper 			(void) printf("%*u", width, psinfo->pr_gid);
   1609     0  stevel 		break;
   1610     0  stevel 	case F_GROUP:
   1611     0  stevel 		if ((grp = getgrgid(psinfo->pr_egid)) != NULL)
   1612     0  stevel 			(void) printf("%*s", width, grp->gr_name);
   1613     0  stevel 		else
   1614  4321  casper 			(void) printf("%*u", width, psinfo->pr_egid);
   1615     0  stevel 		break;
   1616     0  stevel 	case F_RUID:
   1617  4321  casper 		(void) printf("%*u", width, psinfo->pr_uid);
   1618     0  stevel 		break;
   1619     0  stevel 	case F_UID:
   1620  4321  casper 		(void) printf("%*u", width, psinfo->pr_euid);
   1621     0  stevel 		break;
   1622     0  stevel 	case F_RGID:
   1623  4321  casper 		(void) printf("%*u", width, psinfo->pr_gid);
   1624     0  stevel 		break;
   1625     0  stevel 	case F_GID:
   1626  4321  casper 		(void) printf("%*u", width, psinfo->pr_egid);
   1627     0  stevel 		break;
   1628     0  stevel 	case F_PID:
   1629     0  stevel 		(void) printf("%*d", width, (int)psinfo->pr_pid);
   1630     0  stevel 		break;
   1631     0  stevel 	case F_PPID:
   1632     0  stevel 		(void) printf("%*d", width, (int)psinfo->pr_ppid);
   1633     0  stevel 		break;
   1634     0  stevel 	case F_PGID:
   1635     0  stevel 		(void) printf("%*d", width, (int)psinfo->pr_pgid);
   1636     0  stevel 		break;
   1637     0  stevel 	case F_SID:
   1638     0  stevel 		(void) printf("%*d", width, (int)psinfo->pr_sid);
   1639     0  stevel 		break;
   1640     0  stevel 	case F_PSR:
   1641     0  stevel 		if (zombie_lwp || psinfo->pr_lwp.pr_bindpro == PBIND_NONE)
   1642     0  stevel 			(void) printf("%*s", width, "-");
   1643     0  stevel 		else
   1644     0  stevel 			(void) printf("%*d", width, psinfo->pr_lwp.pr_bindpro);
   1645     0  stevel 		break;
   1646     0  stevel 	case F_LWP:
   1647     0  stevel 		(void) printf("%*d", width, (int)psinfo->pr_lwp.pr_lwpid);
   1648     0  stevel 		break;
   1649     0  stevel 	case F_NLWP:
   1650     0  stevel 		(void) printf("%*d", width, psinfo->pr_nlwp + psinfo->pr_nzomb);
   1651     0  stevel 		break;
   1652     0  stevel 	case F_OPRI:
   1653     0  stevel 		if (zombie_lwp)
   1654     0  stevel 			(void) printf("%*s", width, "-");
   1655     0  stevel 		else
   1656     0  stevel 			(void) printf("%*d", width, psinfo->pr_lwp.pr_oldpri);
   1657     0  stevel 		break;
   1658     0  stevel 	case F_PRI:
   1659     0  stevel 		if (zombie_lwp)
   1660     0  stevel 			(void) printf("%*s", width, "-");
   1661     0  stevel 		else
   1662     0  stevel 			(void) printf("%*d", width, psinfo->pr_lwp.pr_pri);
   1663     0  stevel 		break;
   1664     0  stevel 	case F_F:
   1665     0  stevel 		mask = 0xffffffffUL;
   1666     0  stevel 		if (width < 8)
   1667     0  stevel 			mask >>= (8 - width) * 4;
   1668     0  stevel 		(void) printf("%*lx", width, psinfo->pr_flag & mask);
   1669     0  stevel 		break;
   1670     0  stevel 	case F_S:
   1671     0  stevel 		(void) printf("%*c", width, psinfo->pr_lwp.pr_sname);
   1672     0  stevel 		break;
   1673     0  stevel 	case F_C:
   1674     0  stevel 		if (zombie_lwp)
   1675     0  stevel 			(void) printf("%*s", width, "-");
   1676     0  stevel 		else
   1677     0  stevel 			(void) printf("%*d", width, psinfo->pr_lwp.pr_cpu);
   1678     0  stevel 		break;
   1679     0  stevel 	case F_PCPU:
   1680     0  stevel 		if (zombie_lwp)
   1681     0  stevel 			(void) printf("%*s", width, "-");
   1682     0  stevel 		else if (Lflg)
   1683     0  stevel 			prtpct(psinfo->pr_lwp.pr_pctcpu, width);
   1684     0  stevel 		else
   1685     0  stevel 			prtpct(psinfo->pr_pctcpu, width);
   1686     0  stevel 		break;
   1687     0  stevel 	case F_PMEM:
   1688     0  stevel 		prtpct(psinfo->pr_pctmem, width);
   1689     0  stevel 		break;
   1690     0  stevel 	case F_OSZ:
   1691     0  stevel 		(void) printf("%*lu", width,
   1692  8233     dme 		    (ulong_t)psinfo->pr_size / kbytes_per_page);
   1693     0  stevel 		break;
   1694     0  stevel 	case F_VSZ:
   1695     0  stevel 		(void) printf("%*lu", width, (ulong_t)psinfo->pr_size);
   1696     0  stevel 		break;
   1697     0  stevel 	case F_RSS:
   1698     0  stevel 		(void) printf("%*lu", width, (ulong_t)psinfo->pr_rssize);
   1699     0  stevel 		break;
   1700     0  stevel 	case F_NICE:
   1701     0  stevel 		/* if pr_oldpri is zero, then this class has no nice */
   1702     0  stevel 		if (zombie_lwp)
   1703     0  stevel 			(void) printf("%*s", width, "-");
   1704     0  stevel 		else if (psinfo->pr_lwp.pr_oldpri != 0)
   1705     0  stevel 			(void) printf("%*d", width, psinfo->pr_lwp.pr_nice);
   1706     0  stevel 		else
   1707     0  stevel 			(void) printf("%*.*s", width, width,
   1708  8233     dme 			    psinfo->pr_lwp.pr_clname);
   1709     0  stevel 		break;
   1710     0  stevel 	case F_CLASS:
   1711     0  stevel 		if (zombie_lwp)
   1712     0  stevel 			(void) printf("%*s", width, "-");
   1713     0  stevel 		else
   1714     0  stevel 			(void) printf("%*.*s", width, width,
   1715  8233     dme 			    psinfo->pr_lwp.pr_clname);
   1716     0  stevel 		break;
   1717     0  stevel 	case F_STIME:
   1718     0  stevel 		if (Lflg)
   1719     0  stevel 			prtime(psinfo->pr_lwp.pr_start, width, 0);
   1720     0  stevel 		else
   1721     0  stevel 			prtime(psinfo->pr_start, width, 0);
   1722     0  stevel 		break;
   1723     0  stevel 	case F_ETIME:
   1724     0  stevel 		if (Lflg)
   1725     0  stevel 			print_time(delta_secs(&psinfo->pr_lwp.pr_start),
   1726  8233     dme 			    width);
   1727     0  stevel 		else
   1728     0  stevel 			print_time(delta_secs(&psinfo->pr_start), width);
   1729     0  stevel 		break;
   1730     0  stevel 	case F_TIME:
   1731     0  stevel 		if (Lflg) {
   1732     0  stevel 			cputime = psinfo->pr_lwp.pr_time.tv_sec;
   1733     0  stevel 			if (psinfo->pr_lwp.pr_time.tv_nsec > 500000000)
   1734     0  stevel 				cputime++;
   1735     0  stevel 		} else {
   1736     0  stevel 			cputime = psinfo->pr_time.tv_sec;
   1737     0  stevel 			if (psinfo->pr_time.tv_nsec > 500000000)
   1738     0  stevel 				cputime++;
   1739     0  stevel 		}
   1740     0  stevel 		print_time(cputime, width);
   1741     0  stevel 		break;
   1742     0  stevel 	case F_TTY:
   1743     0  stevel 		(void) printf("%-*s", width, ttyp);
   1744     0  stevel 		break;
   1745     0  stevel 	case F_ADDR:
   1746     0  stevel 		if (zombie_lwp)
   1747     0  stevel 			(void) printf("%*s", width, "-");
   1748     0  stevel 		else if (Lflg)
   1749     0  stevel 			(void) printf("%*lx", width,
   1750  8233     dme 			    (long)psinfo->pr_lwp.pr_addr);
   1751     0  stevel 		else
   1752     0  stevel 			(void) printf("%*lx", width, (long)psinfo->pr_addr);
   1753     0  stevel 		break;
   1754     0  stevel 	case F_WCHAN:
   1755     0  stevel 		if (!zombie_lwp && psinfo->pr_lwp.pr_wchan)
   1756     0  stevel 			(void) printf("%*lx", width,
   1757  8233     dme 			    (long)psinfo->pr_lwp.pr_wchan);
   1758     0  stevel 		else
   1759     0  stevel 			(void) printf("%*.*s", width, width, "-");
   1760     0  stevel 		break;
   1761     0  stevel 	case F_FNAME:
   1762     0  stevel 		/*
   1763     0  stevel 		 * Print full width unless this is the last output format.
   1764     0  stevel 		 */
   1765     0  stevel 		if (zombie_lwp) {
   1766     0  stevel 			if (f->next != NULL)
   1767     0  stevel 				(void) printf("%-*s", width, "<defunct>");
   1768     0  stevel 			else
   1769     0  stevel 				(void) printf("%s", "<defunct>");
   1770     0  stevel 			break;
   1771     0  stevel 		}
   1772     0  stevel 		wcnt = namencnt(psinfo->pr_fname, 16, width);
   1773     0  stevel 		if (f->next != NULL)
   1774     0  stevel 			(void) printf("%-*.*s", width, wcnt, psinfo->pr_fname);
   1775     0  stevel 		else
   1776     0  stevel 			(void) printf("%-.*s", wcnt, psinfo->pr_fname);
   1777     0  stevel 		break;
   1778     0  stevel 	case F_COMM:
   1779     0  stevel 		if (zombie_lwp) {
   1780     0  stevel 			if (f->next != NULL)
   1781     0  stevel 				(void) printf("%-*s", width, "<defunct>");
   1782     0  stevel 			else
   1783     0  stevel 				(void) printf("%s", "<defunct>");
   1784     0  stevel 			break;
   1785     0  stevel 		}
   1786     0  stevel 		csave = strpbrk(psinfo->pr_psargs, " \t\r\v\f\n");
   1787     0  stevel 		if (csave) {
   1788     0  stevel 			c = *csave;
   1789     0  stevel 			*csave = '\0';
   1790     0  stevel 		}
   1791     0  stevel 		/* FALLTHROUGH */
   1792     0  stevel 	case F_ARGS:
   1793     0  stevel 		/*
   1794     0  stevel 		 * PRARGSZ == length of cmd arg string.
   1795     0  stevel 		 */
   1796     0  stevel 		if (zombie_lwp) {
   1797     0  stevel 			(void) printf("%-*s", width, "<defunct>");
   1798     0  stevel 			break;
   1799     0  stevel 		}
   1800     0  stevel 		psinfo->pr_psargs[PRARGSZ-1] = '\0';
   1801     0  stevel 		bytesleft = PRARGSZ;
   1802     0  stevel 		for (cp = psinfo->pr_psargs; *cp != '\0'; cp += length) {
   1803     0  stevel 			length = mbtowc(&wchar, cp, MB_LEN_MAX);
   1804     0  stevel 			if (length == 0)
   1805     0  stevel 				break;
   1806     0  stevel 			if (length < 0 || !iswprint(wchar)) {
   1807     0  stevel 				if (length < 0)
   1808     0  stevel 					length = 1;
   1809     0  stevel 				if (bytesleft <= length) {
   1810     0  stevel 					*cp = '\0';
   1811     0  stevel 					break;
   1812     0  stevel 				}
   1813     0  stevel 				/* omit the unprintable character */
   1814     0  stevel 				(void) memmove(cp, cp+length, bytesleft-length);
   1815     0  stevel 				length = 0;
   1816     0  stevel 			}
   1817     0  stevel 			bytesleft -= length;
   1818     0  stevel 		}
   1819     0  stevel 		wcnt = namencnt(psinfo->pr_psargs, PRARGSZ, width);
   1820     0  stevel 		/*
   1821     0  stevel 		 * Print full width unless this is the last format.
   1822     0  stevel 		 */
   1823     0  stevel 		if (f->next != NULL)
   1824     0  stevel 			(void) printf("%-*.*s", width, wcnt,
   1825     0  stevel 			    psinfo->pr_psargs);
   1826     0  stevel 		else
   1827     0  stevel 			(void) printf("%-.*s", wcnt,
   1828     0  stevel 			    psinfo->pr_psargs);
   1829     0  stevel 		if (f->fname == F_COMM && csave)
   1830     0  stevel 			*csave = c;
   1831     0  stevel 		break;
   1832     0  stevel 	case F_TASKID:
   1833     0  stevel 		(void) printf("%*d", width, (int)psinfo->pr_taskid);
   1834     0  stevel 		break;
   1835     0  stevel 	case F_PROJID:
   1836     0  stevel 		(void) printf("%*d", width, (int)psinfo->pr_projid);
   1837     0  stevel 		break;
   1838     0  stevel 	case F_PROJECT:
   1839     0  stevel 		{
   1840     0  stevel 			struct project cproj;
   1841     0  stevel 			char proj_buf[PROJECT_BUFSZ];
   1842     0  stevel 
   1843     0  stevel 			if ((getprojbyid(psinfo->pr_projid, &cproj,
   1844     0  stevel 			    (void *)&proj_buf, PROJECT_BUFSZ)) == NULL)
   1845     0  stevel 				(void) printf("%*d", width,
   1846     0  stevel 				    (int)psinfo->pr_projid);
   1847     0  stevel 			else
   1848     0  stevel 				(void) printf("%*s", width,
   1849     0  stevel 				    (cproj.pj_name != NULL) ?
   1850     0  stevel 				    cproj.pj_name : "---");
   1851     0  stevel 		}
   1852     0  stevel 		break;
   1853     0  stevel 	case F_PSET:
   1854     0  stevel 		if (zombie_lwp || psinfo->pr_lwp.pr_bindpset == PS_NONE)
   1855     0  stevel 			(void) printf("%*s", width, "-");
   1856     0  stevel 		else
   1857     0  stevel 			(void) printf("%*d", width, psinfo->pr_lwp.pr_bindpset);
   1858     0  stevel 		break;
   1859     0  stevel 	case F_ZONEID:
   1860     0  stevel 		(void) printf("%*d", width, (int)psinfo->pr_zoneid);
   1861     0  stevel 		break;
   1862     0  stevel 	case F_ZONE:
   1863     0  stevel 		{
   1864     0  stevel 			char zonename[ZONENAME_MAX];
   1865     0  stevel 
   1866     0  stevel 			if (getzonenamebyid(psinfo->pr_zoneid, zonename,
   1867     0  stevel 			    sizeof (zonename)) < 0) {
   1868     0  stevel 				(void) printf("%*d", width,
   1869     0  stevel 				    ((int)psinfo->pr_zoneid));
   1870     0  stevel 			} else {
   1871     0  stevel 				(void) printf("%*s", width, zonename);
   1872     0  stevel 			}
   1873     0  stevel 		}
   1874     0  stevel 		break;
   1875     0  stevel 	case F_CTID:
   1876     0  stevel 		if (psinfo->pr_contract == -1)
   1877     0  stevel 			(void) printf("%*s", width, "-");
   1878     0  stevel 		else
   1879     0  stevel 			(void) printf("%*ld", width, (long)psinfo->pr_contract);
   1880     0  stevel 		break;
   1881  2685   akolb 	case F_LGRP:
   1882  2685   akolb 		/* Display home lgroup */
   1883  2685   akolb 		(void) printf("%*d", width, (int)psinfo->pr_lwp.pr_lgrp);
   1884  2685   akolb 		break;
   1885     0  stevel 	}
   1886     0  stevel }
   1887     0  stevel 
   1888     0  stevel static void
   1889     0  stevel print_zombie_field(psinfo_t *psinfo, struct field *f, const char *ttyp)
   1890     0  stevel {
   1891     0  stevel 	int wcnt;
   1892     0  stevel 	int width = f->width;
   1893     0  stevel 
   1894     0  stevel 	switch (f->fname) {
   1895     0  stevel 	case F_FNAME:
   1896     0  stevel 	case F_COMM:
   1897     0  stevel 	case F_ARGS:
   1898     0  stevel 		/*
   1899     0  stevel 		 * Print full width unless this is the last output format.
   1900     0  stevel 		 */
   1901     0  stevel 		wcnt = min(width, sizeof ("<defunct>"));
   1902     0  stevel 		if (f->next != NULL)
   1903     0  stevel 			(void) printf("%-*.*s", width, wcnt, "<defunct>");
   1904     0  stevel 		else
   1905     0  stevel 			(void) printf("%-.*s", wcnt, "<defunct>");
   1906     0  stevel 		break;
   1907     0  stevel 
   1908     0  stevel 	case F_PSR:
   1909     0  stevel 	case F_PCPU:
   1910     0  stevel 	case F_PMEM:
   1911     0  stevel 	case F_NICE:
   1912     0  stevel 	case F_CLASS:
   1913     0  stevel 	case F_STIME:
   1914     0  stevel 	case F_ETIME:
   1915     0  stevel 	case F_WCHAN:
   1916     0  stevel 	case F_PSET:
   1917     0  stevel 		(void) printf("%*s", width, "-");
   1918     0  stevel 		break;
   1919     0  stevel 
   1920     0  stevel 	case F_OPRI:
   1921     0  stevel 	case F_PRI:
   1922     0  stevel 	case F_OSZ:
   1923     0  stevel 	case F_VSZ:
   1924     0  stevel 	case F_RSS:
   1925     0  stevel 		(void) printf("%*d", width, 0);
   1926     0  stevel 		break;
   1927     0  stevel 
   1928     0  stevel 	default:
   1929     0  stevel 		print_field(psinfo, f, ttyp);
   1930     0  stevel 		break;
   1931     0  stevel 	}
   1932     0  stevel }
   1933     0  stevel 
   1934     0  stevel static void
   1935     0  stevel pr_fields(psinfo_t *psinfo, const char *ttyp,
   1936     0  stevel 	void (*print_fld)(psinfo_t *, struct field *, const char *))
   1937     0  stevel {
   1938     0  stevel 	struct field *f;
   1939     0  stevel 
   1940     0  stevel 	for (f = fields; f != NULL; f = f->next) {
   1941     0  stevel 		print_fld(psinfo, f, ttyp);
   1942     0  stevel 		if (f->next != NULL)
   1943     0  stevel 			(void) printf(" ");
   1944     0  stevel 	}
   1945     0  stevel 	(void) printf("\n");
   1946     0  stevel }
   1947     0  stevel 
   1948     0  stevel /*
   1949     0  stevel  * Returns 1 if arg is found in array arr, of length num; 0 otherwise.
   1950     0  stevel  */
   1951     0  stevel static int
   1952     0  stevel search(pid_t *arr, int number, pid_t arg)
   1953     0  stevel {
   1954     0  stevel 	int i;
   1955     0  stevel 
   1956     0  stevel 	for (i = 0; i < number; i++)
   1957     0  stevel 		if (arg == arr[i])
   1958     0  stevel 			return (1);
   1959     0  stevel 	return (0);
   1960     0  stevel }
   1961     0  stevel 
   1962     0  stevel /*
   1963     0  stevel  * Add an entry (user, group) to the specified table.
   1964     0  stevel  */
   1965     0  stevel static void
   1966     0  stevel add_ugentry(struct ughead *tbl, char *name)
   1967     0  stevel {
   1968     0  stevel 	struct ugdata *entp;
   1969     0  stevel 
   1970     0  stevel 	if (tbl->size == tbl->nent) {	/* reallocate the table entries */
   1971     0  stevel 		if ((tbl->size *= 2) == 0)
   1972     0  stevel 			tbl->size = 32;		/* first time */
   1973     0  stevel 		tbl->ent = Realloc(tbl->ent, tbl->size*sizeof (struct ugdata));
   1974     0  stevel 	}
   1975     0  stevel 	entp = &tbl->ent[tbl->nent++];
   1976     0  stevel 	entp->id = 0;
   1977     0  stevel 	(void) strncpy(entp->name, name, MAXUGNAME);
   1978     0  stevel 	entp->name[MAXUGNAME] = '\0';
   1979     0  stevel }
   1980     0  stevel 
   1981     0  stevel static int
   1982     0  stevel uconv(struct ughead *uhead)
   1983     0  stevel {
   1984     0  stevel 	struct ugdata *utbl = uhead->ent;
   1985     0  stevel 	int n = uhead->nent;
   1986     0  stevel 	struct passwd *pwd;
   1987     0  stevel 	int i;
   1988     0  stevel 	int fnd = 0;
   1989     0  stevel 	uid_t uid;
   1990     0  stevel 
   1991     0  stevel 	/*
   1992     0  stevel 	 * Ask the name service for names.
   1993     0  stevel 	 */
   1994     0  stevel 	for (i = 0; i < n; i++) {
   1995     0  stevel 		/*
   1996     0  stevel 		 * If name is numeric, ask for numeric id
   1997     0  stevel 		 */
   1998  4321  casper 		if (str2uid(utbl[i].name, &uid, 0, MAXEPHUID) == 0)
   1999     0  stevel 			pwd = getpwuid(uid);
   2000     0  stevel 		else
   2001     0  stevel 			pwd = getpwnam(utbl[i].name);
   2002     0  stevel 
   2003     0  stevel 		/*
   2004     0  stevel 		 * If found, enter found index into tbl array.
   2005     0  stevel 		 */
   2006     0  stevel 		if (pwd == NULL) {
   2007     0  stevel 			(void) fprintf(stderr,
   2008     0  stevel 			    gettext("ps: unknown user %s\n"), utbl[i].name);
   2009     0  stevel 			continue;
   2010     0  stevel 		}
   2011     0  stevel 
   2012     0  stevel 		utbl[fnd].id = pwd->pw_uid;
   2013     0  stevel 		(void) strncpy(utbl[fnd].name, pwd->pw_name, MAXUGNAME);
   2014     0  stevel 		fnd++;
   2015     0  stevel 	}
   2016     0  stevel 
   2017     0  stevel 	uhead->nent = fnd;	/* in case it changed */
   2018     0  stevel 	return (n - fnd);
   2019     0  stevel }
   2020     0  stevel 
   2021     0  stevel static int
   2022     0  stevel gconv(struct ughead *ghead)
   2023     0  stevel {
   2024     0  stevel 	struct ugdata *gtbl = ghead->ent;
   2025     0  stevel 	int n = ghead->nent;
   2026     0  stevel 	struct group *grp;
   2027     0  stevel 	gid_t gid;
   2028     0  stevel 	int i;
   2029     0  stevel 	int fnd = 0;
   2030     0  stevel 
   2031     0  stevel 	/*
   2032     0  stevel 	 * Ask the name service for names.
   2033     0  stevel 	 */
   2034     0  stevel 	for (i = 0; i < n; i++) {
   2035     0  stevel 		/*
   2036     0  stevel 		 * If name is numeric, ask for numeric id
   2037     0  stevel 		 */
   2038  4321  casper 		if (str2uid(gtbl[i].name, (uid_t *)&gid, 0, MAXEPHUID) == 0)
   2039     0  stevel 			grp = getgrgid(gid);
   2040     0  stevel 		else
   2041     0  stevel 			grp = getgrnam(gtbl[i].name);
   2042     0  stevel 		/*
   2043     0  stevel 		 * If found, enter found index into tbl array.
   2044     0  stevel 		 */
   2045     0  stevel 		if (grp == NULL) {
   2046     0  stevel 			(void) fprintf(stderr,
   2047     0  stevel 			    gettext("ps: unknown group %s\n"), gtbl[i].name);
   2048     0  stevel 			continue;
   2049     0  stevel 		}
   2050     0  stevel 
   2051     0  stevel 		gtbl[fnd].id = grp->gr_gid;
   2052     0  stevel 		(void) strncpy(gtbl[fnd].name, grp->gr_name, MAXUGNAME);
   2053     0  stevel 		fnd++;
   2054     0  stevel 	}
   2055     0  stevel 
   2056     0  stevel 	ghead->nent = fnd;	/* in case it changed */
   2057     0  stevel 	return (n - fnd);
   2058     0  stevel }
   2059     0  stevel 
   2060     0  stevel /*
   2061     0  stevel  * Return 1 if puid is in table, otherwise 0.
   2062     0  stevel  */
   2063     0  stevel static int
   2064     0  stevel ugfind(id_t id, struct ughead *ughead)
   2065     0  stevel {
   2066     0  stevel 	struct ugdata *utbl = ughead->ent;
   2067     0  stevel 	int n = ughead->nent;
   2068     0  stevel 	int i;
   2069     0  stevel 
   2070     0  stevel 	for (i = 0; i < n; i++)
   2071     0  stevel 		if (utbl[i].id == id)
   2072     0  stevel 			return (1);
   2073     0  stevel 	return (0);
   2074     0  stevel }
   2075     0  stevel 
   2076     0  stevel /*
   2077     0  stevel  * Print starting time of process unless process started more than 24 hours
   2078     0  stevel  * ago, in which case the date is printed.  The date is printed in the form
   2079     0  stevel  * "MMM dd" if old format, else the blank is replaced with an '_' so
   2080     0  stevel  * it appears as a single word (for parseability).
   2081     0  stevel  */
   2082     0  stevel static void
   2083     0  stevel prtime(timestruc_t st, int width, int old)
   2084     0  stevel {
   2085     0  stevel 	char sttim[26];
   2086     0  stevel 	time_t starttime;
   2087     0  stevel 
   2088     0  stevel 	starttime = st.tv_sec;
   2089     0  stevel 	if (st.tv_nsec > 500000000)
   2090     0  stevel 		starttime++;
   2091     0  stevel 	if ((now.tv_sec - starttime) >= 24*60*60) {
   2092  2966  sayama 		(void) strftime(sttim, sizeof (sttim), old?
   2093  2966  sayama 		/*
   2094  2966  sayama 		 * TRANSLATION_NOTE
   2095  2966  sayama 		 * This time format is used by STIME field when -f option
   2096  2966  sayama 		 * is specified.  Used for processes that begun more than
   2097  2966  sayama 		 * 24 hours.
   2098  2966  sayama 		 */
   2099  2966  sayama 		    dcgettext(NULL, "%b %d", LC_TIME) :
   2100  2966  sayama 		/*
   2101  2966  sayama 		 * TRANSLATION_NOTE
   2102  2966  sayama 		 * This time format is used by STIME field when -o option
   2103  2966  sayama 		 * is specified.  Used for processes that begun more than
   2104  2966  sayama 		 * 24 hours.
   2105  2966  sayama 		 */
   2106  2966  sayama 		    dcgettext(NULL, "%b_%d", LC_TIME), localtime(&starttime));
   2107     0  stevel 	} else {
   2108  2966  sayama 		/*
   2109  2966  sayama 		 * TRANSLATION_NOTE
   2110  2966  sayama 		 * This time format is used by STIME field when -f or -o option
   2111  2966  sayama 		 * is specified.  Used for processes that begun less than
   2112  2966  sayama 		 * 24 hours.
   2113  2966  sayama 		 */
   2114  2966  sayama 		(void) strftime(sttim, sizeof (sttim),
   2115  2966  sayama 		    dcgettext(NULL, "%H:%M:%S", LC_TIME),
   2116  2966  sayama 		    localtime(&starttime));
   2117     0  stevel 	}
   2118     0  stevel 	(void) printf("%*.*s", width, width, sttim);
   2119     0  stevel }
   2120     0  stevel 
   2121     0  stevel static void
   2122     0  stevel przom(psinfo_t *psinfo)
   2123     0  stevel {
   2124     0  stevel 	long	tm;
   2125     0  stevel 	struct passwd *pwd;
   2126     0  stevel 	char zonename[ZONENAME_MAX];
   2127     0  stevel 
   2128     0  stevel 	/*
   2129     0  stevel 	 * All fields before 'PID' are printed with a trailing space as a
   2130     0  stevel 	 * spearator, rather than keeping track of which column is first.  All
   2131     0  stevel 	 * other fields are printed with a leading space.
   2132     0  stevel 	 */
   2133     0  stevel 	if (lflg) {	/* F S */
   2134     0  stevel 		if (!yflg)
   2135     0  stevel 			(void) printf("%2x ", psinfo->pr_flag & 0377); /* F */
   2136     0  stevel 		(void) printf("%c ", psinfo->pr_lwp.pr_sname);	/* S */
   2137     0  stevel 	}
   2138     0  stevel 	if (Zflg) {
   2139     0  stevel 		if (getzonenamebyid(psinfo->pr_zoneid, zonename,
   2140     0  stevel 		    sizeof (zonename)) < 0) {
   2141  8822  Casper 			(void) printf(" %7.7d ", ((int)psinfo->pr_zoneid));
   2142     0  stevel 		} else {
   2143     0  stevel 			(void) printf("%8.8s ", zonename);
   2144     0  stevel 		}
   2145     0  stevel 	}
   2146  2685   akolb 	if (Hflg) {
   2147  2685   akolb 		/* Display home lgroup */
   2148  2685   akolb 		(void) printf(" %6d", (int)psinfo->pr_lwp.pr_lgrp); /* LGRP */
   2149  2685   akolb 	}
   2150     0  stevel 	if (fflg) {
   2151     0  stevel 		if ((pwd = getpwuid(psinfo->pr_euid)) != NULL)
   2152     0  stevel 			(void) printf("%8.8s ", pwd->pw_name);
   2153     0  stevel 		else
   2154  8233     dme 			(void) printf(" %7.7u ", psinfo->pr_euid);
   2155     0  stevel 	} else if (lflg)
   2156  4321  casper 		(void) printf("%6u ", psinfo->pr_euid);
   2157     0  stevel 
   2158     0  stevel 	(void) printf("%*d", pidwidth, (int)psinfo->pr_pid);	/* PID */
   2159     0  stevel 	if (lflg || fflg)
   2160     0  stevel 		(void) printf(" %*d", pidwidth,
   2161     0  stevel 		    (int)psinfo->pr_ppid);			/* PPID */
   2162     0  stevel 
   2163     0  stevel 	if (jflg) {
   2164     0  stevel 		(void) printf(" %*d", pidwidth,
   2165     0  stevel 		    (int)psinfo->pr_pgid);			/* PGID */
   2166     0  stevel 		(void) printf(" %*d", pidwidth,
   2167     0  stevel 		    (int)psinfo->pr_sid);			/* SID  */
   2168     0  stevel 	}
   2169     0  stevel 
   2170     0  stevel 	if (Lflg)
   2171     0  stevel 		(void) printf(" %5d", 0);			/* LWP */
   2172     0  stevel 	if (Pflg)
   2173     0  stevel 		(void) printf("   -");				/* PSR */
   2174     0  stevel 	if (Lflg && fflg)
   2175     0  stevel 		(void) printf(" %5d", 0);			/* NLWP */
   2176     0  stevel 
   2177     0  stevel 	if (cflg) {
   2178     0  stevel 		(void) printf(" %4s", "-");	/* zombies have no class */
   2179     0  stevel 		(void) printf(" %3d", psinfo->pr_lwp.pr_pri);	/* PRI	*/
   2180     0  stevel 	} else if (lflg || fflg) {
   2181     0  stevel 		(void) printf(" %3d", psinfo->pr_lwp.pr_cpu & 0377); /* C   */
   2182     0  stevel 		if (lflg)
   2183     0  stevel 			(void) printf(" %3d %2s",
   2184     0  stevel 			    psinfo->pr_lwp.pr_oldpri, "-");	/* PRI NI */
   2185     0  stevel 	}
   2186     0  stevel 	if (lflg) {
   2187     0  stevel 		if (yflg)				/* RSS SZ WCHAN */
   2188     0  stevel 			(void) printf(" %5d %6d %8s", 0, 0, "-");
   2189     0  stevel 		else					/* ADDR SZ WCHAN */
   2190     0  stevel 			(void) printf(" %8s %6d %8s", "-", 0, "-");
   2191     0  stevel 	}
   2192  2966  sayama 	if (fflg) {
   2193  2966  sayama 		int width = fname[F_STIME].width;
   2194  2966  sayama 		(void) printf(" %*.*s", width, width, "-"); 	/* STIME */
   2195  2966  sayama 	}
   2196     0  stevel 	(void) printf(" %-8.14s", "?");				/* TTY */
   2197     0  stevel 
   2198     0  stevel 	tm = psinfo->pr_time.tv_sec;
   2199     0  stevel 	if (psinfo->pr_time.tv_nsec > 500000000)
   2200     0  stevel 		tm++;
   2201     0  stevel 	(void) printf(" %4ld:%.2ld", tm / 60, tm % 60);	/* TIME */
   2202     0  stevel 	(void) printf(" <defunct>\n");
   2203     0  stevel }
   2204     0  stevel 
   2205     0  stevel /*
   2206     0  stevel  * Function to compute the number of printable bytes in a multibyte
   2207     0  stevel  * command string ("internationalization").
   2208     0  stevel  */
   2209     0  stevel static int
   2210     0  stevel namencnt(char *cmd, int csisize, int scrsize)
   2211     0  stevel {
   2212     0  stevel 	int csiwcnt = 0, scrwcnt = 0;
   2213     0  stevel 	int ncsisz, nscrsz;
   2214     0  stevel 	wchar_t  wchar;
   2215     0  stevel 	int	 len;
   2216     0  stevel 
   2217     0  stevel 	while (*cmd != '\0') {
   2218     0  stevel 		if ((len = csisize - csiwcnt) > (int)MB_CUR_MAX)
   2219     0  stevel 			len = MB_CUR_MAX;
   2220     0  stevel 		if ((ncsisz = mbtowc(&wchar, cmd, len)) < 0)
   2221     0  stevel 			return (8); /* default to use for illegal chars */
   2222     0  stevel 		if ((nscrsz = wcwidth(wchar)) <= 0)
   2223     0  stevel 			return (8);
   2224     0  stevel 		if (csiwcnt + ncsisz > csisize || scrwcnt + nscrsz > scrsize)
   2225     0  stevel 			break;
   2226     0  stevel 		csiwcnt += ncsisz;
   2227     0  stevel 		scrwcnt += nscrsz;
   2228     0  stevel 		cmd += ncsisz;
   2229     0  stevel 	}
   2230     0  stevel 	return (csiwcnt);
   2231     0  stevel }
   2232     0  stevel 
   2233     0  stevel static char *
   2234     0  stevel err_string(int err)
   2235     0  stevel {
   2236     0  stevel 	static char buf[32];
   2237     0  stevel 	char *str = strerror(err);
   2238     0  stevel 
   2239     0  stevel 	if (str == NULL)
   2240     0  stevel 		(void) snprintf(str = buf, sizeof (buf), "Errno #%d", err);
   2241     0  stevel 
   2242     0  stevel 	return (str);
   2243     0  stevel }
   2244     0  stevel 
   2245     0  stevel /* If allocation fails, die */
   2246     0  stevel static void *
   2247     0  stevel Realloc(void *ptr, size_t size)
   2248     0  stevel {
   2249     0  stevel 	ptr = realloc(ptr, size);
   2250     0  stevel 	if (ptr == NULL) {
   2251     0  stevel 		(void) fprintf(stderr, gettext("ps: no memory\n"));
   2252     0  stevel 		exit(1);
   2253     0  stevel 	}
   2254     0  stevel 	return (ptr);
   2255     0  stevel }
   2256     0  stevel 
   2257     0  stevel static time_t
   2258     0  stevel delta_secs(const timestruc_t *start)
   2259     0  stevel {
   2260     0  stevel 	time_t seconds = now.tv_sec - start->tv_sec;
   2261     0  stevel 	long nanosecs = now.tv_usec * 1000 - start->tv_nsec;
   2262     0  stevel 
   2263     0  stevel 	if (nanosecs >= (NANOSEC / 2))
   2264     0  stevel 		seconds++;
   2265     0  stevel 	else if (nanosecs < -(NANOSEC / 2))
   2266     0  stevel 		seconds--;
   2267     0  stevel 
   2268     0  stevel 	return (seconds);
   2269     0  stevel }
   2270     0  stevel 
   2271     0  stevel /*
   2272     0  stevel  * Returns the following:
   2273     0  stevel  *
   2274     0  stevel  * 	0	No error
   2275     0  stevel  * 	EINVAL	Invalid number
   2276     0  stevel  * 	ERANGE	Value exceeds (min, max) range
   2277     0  stevel  */
   2278     0  stevel static int
   2279     0  stevel str2id(const char *p, pid_t *val, long min, long max)
   2280     0  stevel {
   2281     0  stevel 	char *q;
   2282     0  stevel 	long number;
   2283     0  stevel 	int error;
   2284     0  stevel 
   2285     0  stevel 	errno = 0;
   2286     0  stevel 	number = strtol(p, &q, 10);
   2287     0  stevel 
   2288     0  stevel 	if (errno != 0 || q == p || *q != '\0') {
   2289     0  stevel 		if ((error = errno) == 0) {
   2290     0  stevel 			/*
   2291     0  stevel 			 * strtol() can fail without setting errno, or it can
   2292     0  stevel 			 * set it to EINVAL or ERANGE.  In the case errno is
   2293     0  stevel 			 * still zero, return EINVAL.
   2294     0  stevel 			 */
   2295     0  stevel 			error = EINVAL;
   2296     0  stevel 		}
   2297     0  stevel 	} else if (number < min || number > max) {
   2298     0  stevel 		error = ERANGE;
   2299     0  stevel 	} else {
   2300     0  stevel 		error = 0;
   2301     0  stevel 	}
   2302     0  stevel 
   2303     0  stevel 	*val = number;
   2304     0  stevel 
   2305     0  stevel 	return (error);
   2306     0  stevel }
   2307     0  stevel 
   2308  4321  casper /*
   2309  4321  casper  * Returns the following:
   2310  4321  casper  *
   2311  4321  casper  * 	0	No error
   2312  4321  casper  * 	EINVAL	Invalid number
   2313  4321  casper  * 	ERANGE	Value exceeds (min, max) range
   2314  4321  casper  */
   2315  4321  casper static int
   2316  4321  casper str2uid(const char *p, uid_t *val, unsigned long min, unsigned long max)
   2317  4321  casper {
   2318  4321  casper 	char *q;
   2319  4321  casper 	unsigned long number;
   2320  4321  casper 	int error;
   2321  4321  casper 
   2322  4321  casper 	errno = 0;
   2323  4321  casper 	number = strtoul(p, &q, 10);
   2324  4321  casper 
   2325  4321  casper 	if (errno != 0 || q == p || *q != '\0') {
   2326  4321  casper 		if ((error = errno) == 0) {
   2327  4321  casper 			/*
   2328  4321  casper 			 * strtoul() can fail without setting errno, or it can
   2329  4321  casper 			 * set it to EINVAL or ERANGE.  In the case errno is
   2330  4321  casper 			 * still zero, return EINVAL.
   2331  4321  casper 			 */
   2332  4321  casper 			error = EINVAL;
   2333  4321  casper 		}
   2334  4321  casper 	} else if (number < min || number > max) {
   2335  4321  casper 		error = ERANGE;
   2336  4321  casper 	} else {
   2337  4321  casper 		error = 0;
   2338  4321  casper 	}
   2339  4321  casper 
   2340  4321  casper 	*val = number;
   2341  4321  casper 
   2342  4321  casper 	return (error);
   2343  4321  casper }
   2344  4321  casper 
   2345     0  stevel static int
   2346     0  stevel pidcmp(const void *p1, const void *p2)
   2347     0  stevel {
   2348     0  stevel 	pid_t i = *((pid_t *)p1);
   2349     0  stevel 	pid_t j = *((pid_t *)p2);
   2350     0  stevel 
   2351     0  stevel 	return (i - j);
   2352     0  stevel }
   2353