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  8822  Casper  * Common Development and Distribution License (the "License").
      6  8822  Casper  * 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     0  stevel /*
     22  8822  Casper  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23     0  stevel  * Use is subject to license terms.
     24     0  stevel  */
     25     0  stevel 
     26     0  stevel /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
     27     0  stevel /*	  All Rights Reserved	*/
     28     0  stevel 
     29     0  stevel /*
     30     0  stevel  * University Copyright- Copyright (c) 1982, 1986, 1988
     31     0  stevel  * The Regents of the University of California
     32     0  stevel  * All Rights Reserved
     33     0  stevel  *
     34     0  stevel  * University Acknowledgment- Portions of this document are derived from
     35     0  stevel  * software developed by the University of California, Berkeley, and its
     36     0  stevel  * contributors.
     37     0  stevel  */
     38     0  stevel 
     39     0  stevel /*
     40     0  stevel  * ps -- print things about processes.
     41     0  stevel  */
     42     0  stevel 
     43     0  stevel #define	_SYSCALL32
     44     0  stevel 
     45     0  stevel #include <stdio.h>
     46     0  stevel #include <ctype.h>
     47     0  stevel #include <string.h>
     48     0  stevel #include <errno.h>
     49     0  stevel #include <fcntl.h>
     50     0  stevel #include <pwd.h>
     51     0  stevel #include <sys/types.h>
     52     0  stevel #include <sys/stat.h>
     53     0  stevel #include <sys/mkdev.h>
     54     0  stevel #include <unistd.h>
     55     0  stevel #include <stdlib.h>
     56     0  stevel #include <limits.h>
     57     0  stevel #include <dirent.h>
     58     0  stevel #include <procfs.h>
     59     0  stevel #include <sys/param.h>
     60     0  stevel #include <sys/ttold.h>
     61     0  stevel #include <libelf.h>
     62     0  stevel #include <gelf.h>
     63     0  stevel #include <locale.h>
     64     0  stevel #include <wctype.h>
     65     0  stevel #include <stdarg.h>
     66     0  stevel #include <sys/proc.h>
     67     0  stevel #include <priv_utils.h>
     68     0  stevel 
     69     0  stevel #define	NTTYS	2	/* max ttys that can be specified with the -t option */
     70     0  stevel 			/* only one tty can be specified with SunOS ps */
     71     0  stevel #define	SIZ	30	/* max processes that can be specified with -p and -g */
     72     0  stevel #define	ARGSIZ	30	/* size of buffer holding args for -t, -p, -u options */
     73     0  stevel 
     74     0  stevel #define	FSTYPE_MAX	8
     75     0  stevel 
     76     0  stevel struct psent {
     77     0  stevel 	psinfo_t *psinfo;
     78     0  stevel 	char *psargs;
     79     0  stevel 	int found;
     80     0  stevel };
     81     0  stevel 
     82     0  stevel static	int	tplen, maxlen, twidth;
     83     0  stevel static	char	hdr[81];
     84     0  stevel static	struct	winsize win;
     85     0  stevel 
     86     0  stevel static	int	retcode = 1;
     87     0  stevel static	int	lflg;	/* long format */
     88     0  stevel static	int	uflg;	/* user-oriented output */
     89     0  stevel static	int	aflg;	/* Display all processes */
     90     0  stevel static	int	eflg;	/* Display environment as well as arguments */
     91     0  stevel static	int	gflg;	/* Display process group leaders */
     92     0  stevel static	int	tflg;	/* Processes running on specific terminals */
     93     0  stevel static	int	rflg;	/* Running processes only flag */
     94     0  stevel static	int	Sflg;	/* Accumulated time plus all reaped children */
     95     0  stevel static	int	xflg;	/* Include processes with no controlling tty */
     96     0  stevel static	int	cflg;	/* Display command name */
     97     0  stevel static	int	vflg;	/* Virtual memory-oriented output */
     98     0  stevel static	int	nflg;	/* Numerical output */
     99     0  stevel static	int	pflg;	/* Specific process id passed as argument */
    100     0  stevel static	int	Uflg;	/* Update private database, ups_data */
    101     0  stevel static	int	errflg;
    102     0  stevel 
    103     0  stevel static	char	*gettty();
    104     0  stevel static	char	argbuf[ARGSIZ];
    105     0  stevel static	char	*parg;
    106     0  stevel static	char	*p1;		/* points to successive option arguments */
    107     0  stevel static	uid_t	my_uid;
    108     0  stevel static char	stdbuf[BUFSIZ];
    109     0  stevel 
    110     0  stevel static	int	ndev;		/* number of devices */
    111     0  stevel static	int	maxdev;		/* number of devl structures allocated */
    112     0  stevel 
    113     0  stevel #define	DNINCR	100
    114     0  stevel #define	DNSIZE	14
    115     0  stevel static	struct devl {		/* device list	 */
    116     0  stevel 	char	dname[DNSIZE];	/* device name	 */
    117     0  stevel 	dev_t	ddev;		/* device number */
    118     0  stevel } *devl;
    119     0  stevel 
    120     0  stevel static	struct tty {
    121     0  stevel 	char *tname;
    122     0  stevel 	dev_t tdev;
    123     0  stevel } tty[NTTYS];			/* for t option */
    124     0  stevel static	int	ntty = 0;
    125     0  stevel static	pid_t	pidsave;
    126     0  stevel static	int	pidwidth;
    127     0  stevel 
    128     0  stevel static	char	*procdir = "/proc";	/* standard /proc directory */
    129     0  stevel static	void	usage();		/* print usage message and quit */
    130     0  stevel static	void	getarg(void);
    131     0  stevel static	void	prtime(timestruc_t st);
    132     0  stevel static	void	przom(psinfo_t *psinfo);
    133     0  stevel static	int	num(char *);
    134     0  stevel static	int	preadargs(int, psinfo_t *, char *);
    135     0  stevel static	int	preadenvs(int, psinfo_t *, char *);
    136     0  stevel static	int	prcom(int, psinfo_t *, char *);
    137     0  stevel static	int	namencnt(char *, int, int);
    138     0  stevel static	int	pscompare(const void *, const void *);
    139     0  stevel static	char	*err_string(int);
    140     0  stevel 
    141     0  stevel extern int	scrwidth(wchar_t);	/* header file? */
    142     0  stevel 
    143     0  stevel int
    144  8822  Casper ucbmain(int argc, char **argv)
    145     0  stevel {
    146     0  stevel 	psinfo_t info;		/* process information structure from /proc */
    147     0  stevel 	char *psargs = NULL;	/* pointer to buffer for -w and -ww options */
    148     0  stevel 	char *svpsargs = NULL;
    149     0  stevel 	struct psent *psent;
    150     0  stevel 	int entsize;
    151     0  stevel 	int nent;
    152     0  stevel 	pid_t maxpid;
    153     0  stevel 
    154     0  stevel 	struct tty *ttyp = tty;
    155     0  stevel 	char	*tmp;
    156     0  stevel 	char	*p;
    157     0  stevel 	int	c;
    158     0  stevel 	pid_t	pid;		/* pid: process id */
    159     0  stevel 	pid_t	ppid;		/* ppid: parent process id */
    160     0  stevel 	int	i, found;
    161     0  stevel 
    162     0  stevel 	size_t	size;
    163     0  stevel 
    164     0  stevel 	DIR *dirp;
    165     0  stevel 	struct dirent *dentp;
    166     0  stevel 	char	psname[100];
    167     0  stevel 	char	asname[100];
    168     0  stevel 	int	pdlen;
    169     0  stevel 	size_t  len;
    170     0  stevel 
    171     0  stevel 	(void) setlocale(LC_ALL, "");
    172     0  stevel 
    173     0  stevel 	my_uid = getuid();
    174     0  stevel 
    175     0  stevel 	/*
    176     0  stevel 	 * This program needs the proc_owner privilege
    177     0  stevel 	 */
    178     0  stevel 	(void) __init_suid_priv(PU_CLEARLIMITSET, PRIV_PROC_OWNER,
    179     0  stevel 	    (char *)NULL);
    180     0  stevel 
    181     0  stevel 	/*
    182     0  stevel 	 * calculate width of pid fields based on configured MAXPID
    183     0  stevel 	 * (must be at least 5 to retain output format compatibility)
    184     0  stevel 	 */
    185     0  stevel 	maxpid = (pid_t)sysconf(_SC_MAXPID);
    186     0  stevel 	pidwidth = 1;
    187     0  stevel 	while ((maxpid /= 10) > 0)
    188     0  stevel 		++pidwidth;
    189     0  stevel 	pidwidth = pidwidth < 5 ? 5 : pidwidth;
    190     0  stevel 
    191     0  stevel 	if (ioctl(1, TIOCGWINSZ, &win) == -1)
    192     0  stevel 		twidth = 80;
    193     0  stevel 	else
    194     0  stevel 		twidth = (win.ws_col == 0 ? 80 : win.ws_col);
    195     0  stevel 
    196     0  stevel 	/* add the '-' for BSD compatibility */
    197     0  stevel 	if (argc > 1) {
    198     0  stevel 		if (argv[1][0] != '-' && !isdigit(argv[1][0])) {
    199     0  stevel 			len = strlen(argv[1]) + 2;
    200     0  stevel 			tmp = malloc(len);
    201     0  stevel 			if (tmp != NULL) {
    202     0  stevel 				(void) snprintf(tmp, len, "%s%s", "-", argv[1]);
    203     0  stevel 				argv[1] = tmp;
    204     0  stevel 			}
    205     0  stevel 		}
    206     0  stevel 	}
    207     0  stevel 
    208     0  stevel 	setbuf(stdout, stdbuf);
    209     0  stevel 	while ((c = getopt(argc, argv, "lcaengrSt:xuvwU")) != EOF)
    210     0  stevel 		switch (c) {
    211     0  stevel 		case 'g':
    212     0  stevel 			gflg++;	/* include process group leaders */
    213     0  stevel 			break;
    214     0  stevel 		case 'c':	/* display internal command name */
    215     0  stevel 			cflg++;
    216     0  stevel 			break;
    217     0  stevel 		case 'r':	/* restrict output to running processes */
    218     0  stevel 			rflg++;
    219     0  stevel 			break;
    220     0  stevel 		case 'S': /* display time by process and all reaped children */
    221     0  stevel 			Sflg++;
    222     0  stevel 			break;
    223     0  stevel 		case 'x':	/* process w/o controlling tty */
    224     0  stevel 			xflg++;
    225     0  stevel 			break;
    226     0  stevel 		case 'l':	/* long listing */
    227     0  stevel 			lflg++;
    228     0  stevel 			uflg = vflg = 0;
    229     0  stevel 			break;
    230     0  stevel 		case 'u':	/* user-oriented output */
    231     0  stevel 			uflg++;
    232     0  stevel 			lflg = vflg = 0;
    233     0  stevel 			break;
    234     0  stevel 		case 'U':	/* update private database ups_data */
    235     0  stevel 			Uflg++;
    236     0  stevel 			break;
    237     0  stevel 		case 'w':	/* increase display width */
    238     0  stevel 			if (twidth < 132)
    239     0  stevel 				twidth = 132;
    240     0  stevel 			else	/* second w option */
    241     0  stevel 				twidth = NCARGS;
    242     0  stevel 			break;
    243     0  stevel 		case 'v':	/* display virtual memory format */
    244     0  stevel 			vflg++;
    245     0  stevel 			lflg = uflg = 0;
    246     0  stevel 			break;
    247     0  stevel 		case 'a':
    248     0  stevel 			/*
    249     0  stevel 			 * display all processes except process group
    250     0  stevel 			 * leaders and processes w/o controlling tty
    251     0  stevel 			 */
    252     0  stevel 			aflg++;
    253     0  stevel 			gflg++;
    254     0  stevel 			break;
    255     0  stevel 		case 'e':
    256     0  stevel 			/* Display environment along with aguments. */
    257     0  stevel 			eflg++;
    258     0  stevel 			break;
    259     0  stevel 		case 'n':	/* Display numerical output */
    260     0  stevel 			nflg++;
    261     0  stevel 			break;
    262     0  stevel 		case 't':	/* restrict output to named terminal */
    263     0  stevel #define	TSZ	30
    264     0  stevel 			tflg++;
    265     0  stevel 			gflg++;
    266     0  stevel 			xflg = 0;
    267     0  stevel 
    268     0  stevel 			p1 = optarg;
    269     0  stevel 			do {	/* only loop through once (NTTYS = 2) */
    270     0  stevel 				parg = argbuf;
    271     0  stevel 				if (ntty >= NTTYS-1)
    272     0  stevel 					break;
    273     0  stevel 				getarg();
    274     0  stevel 				if ((p = malloc(TSZ+1)) == NULL) {
    275     0  stevel 					(void) fprintf(stderr,
    276     0  stevel 					    "ps: no memory\n");
    277     0  stevel 					exit(1);
    278     0  stevel 				}
    279     0  stevel 				p[0] = '\0';
    280     0  stevel 				size = TSZ;
    281     0  stevel 				if (isdigit(*parg)) {
    282     0  stevel 					(void) strcpy(p, "tty");
    283     0  stevel 					size -= 3;
    284     0  stevel 				}
    285     0  stevel 
    286     0  stevel 				(void) strncat(p, parg, size);
    287     0  stevel 				ttyp->tdev = PRNODEV;
    288     0  stevel 				if (parg && *parg == '?')
    289     0  stevel 					xflg++;
    290     0  stevel 				else {
    291     0  stevel 					char nambuf[TSZ+6]; /* for /dev/+\0 */
    292     0  stevel 					struct stat64 s;
    293     0  stevel 					(void) strcpy(nambuf, "/dev/");
    294     0  stevel 					(void) strcat(nambuf, p);
    295     0  stevel 					if (stat64(nambuf, &s) == 0)
    296     0  stevel 						ttyp->tdev = s.st_rdev;
    297     0  stevel 				}
    298     0  stevel 				ttyp++->tname = p;
    299     0  stevel 				ntty++;
    300     0  stevel 			} while (*p1);
    301     0  stevel 			break;
    302     0  stevel 		default:			/* error on ? */
    303     0  stevel 			errflg++;
    304     0  stevel 			break;
    305     0  stevel 		}
    306     0  stevel 
    307     0  stevel 	if (errflg)
    308     0  stevel 		usage();
    309     0  stevel 
    310     0  stevel 	if (optind + 1 < argc) { /* more than one additional argument */
    311     0  stevel 		(void) fprintf(stderr, "ps: too many arguments\n");
    312     0  stevel 		usage();
    313     0  stevel 	}
    314     0  stevel 
    315     0  stevel 	/*
    316     0  stevel 	 * The -U option is obsolete.  Attempts to use it cause ps to exit
    317     0  stevel 	 * without printing anything.
    318     0  stevel 	 */
    319     0  stevel 	if (Uflg)
    320     0  stevel 		exit(0);
    321     0  stevel 
    322     0  stevel 	if (optind < argc) { /* user specified a specific proc id */
    323     0  stevel 		pflg++;
    324     0  stevel 		p1 = argv[optind];
    325     0  stevel 		parg = argbuf;
    326     0  stevel 		getarg();
    327     0  stevel 		if (!num(parg)) {
    328     0  stevel 			(void) fprintf(stderr,
    329     0  stevel 	"ps: %s is an invalid non-numeric argument for a process id\n", parg);
    330     0  stevel 			usage();
    331     0  stevel 		}
    332     0  stevel 		pidsave = (pid_t)atol(parg);
    333     0  stevel 		aflg = rflg = xflg = 0;
    334     0  stevel 		gflg++;
    335     0  stevel 	}
    336     0  stevel 
    337     0  stevel 	if (tflg)
    338     0  stevel 		ttyp->tname = NULL;
    339     0  stevel 
    340     0  stevel 	/* allocate an initial guess for the number of processes */
    341     0  stevel 	entsize = 1024;
    342     0  stevel 	psent = malloc(entsize * sizeof (struct psent));
    343     0  stevel 	if (psent == NULL) {
    344     0  stevel 		(void) fprintf(stderr, "ps: no memory\n");
    345     0  stevel 		exit(1);
    346     0  stevel 	}
    347     0  stevel 	nent = 0;	/* no active entries yet */
    348     0  stevel 
    349     0  stevel 	if (lflg) {
    350     0  stevel 		(void) sprintf(hdr,
    351     0  stevel 		    " F   UID%*s%*s %%C PRI NI   SZ  RSS    "
    352     0  stevel 		    "WCHAN S TT        TIME COMMAND", pidwidth + 1, "PID",
    353     0  stevel 		    pidwidth + 1, "PPID");
    354     0  stevel 	} else if (uflg) {
    355     0  stevel 		if (nflg)
    356     0  stevel 			(void) sprintf(hdr,
    357     0  stevel 			    "   UID%*s %%CPU %%MEM   SZ  RSS "
    358     0  stevel 			    "TT       S    START  TIME COMMAND",
    359     0  stevel 			    pidwidth + 1, "PID");
    360     0  stevel 		else
    361     0  stevel 			(void) sprintf(hdr,
    362     0  stevel 			    "USER    %*s %%CPU %%MEM   SZ  RSS "
    363     0  stevel 			    "TT       S    START  TIME COMMAND",
    364     0  stevel 			    pidwidth + 1, "PID");
    365     0  stevel 	} else if (vflg) {
    366     0  stevel 		(void) sprintf(hdr,
    367     0  stevel 		    "%*s TT       S  TIME SIZE  RSS %%CPU %%MEM "
    368     0  stevel 		    "COMMAND", pidwidth + 1, "PID");
    369     0  stevel 	} else
    370     0  stevel 		(void) sprintf(hdr, "%*s TT       S  TIME COMMAND",
    371     0  stevel 		    pidwidth + 1, "PID");
    372     0  stevel 
    373     0  stevel 	twidth = twidth - strlen(hdr) + 6;
    374     0  stevel 	(void) printf("%s\n", hdr);
    375     0  stevel 
    376     0  stevel 	if (twidth > PRARGSZ && (psargs = malloc(twidth)) == NULL) {
    377     0  stevel 		(void) fprintf(stderr, "ps: no memory\n");
    378     0  stevel 		exit(1);
    379     0  stevel 	}
    380     0  stevel 	svpsargs = psargs;
    381     0  stevel 
    382     0  stevel 	/*
    383     0  stevel 	 * Determine which processes to print info about by searching
    384     0  stevel 	 * the /proc directory and looking at each process.
    385     0  stevel 	 */
    386     0  stevel 	if ((dirp = opendir(procdir)) == NULL) {
    387     0  stevel 		(void) fprintf(stderr, "ps: cannot open PROC directory %s\n",
    388     0  stevel 		    procdir);
    389     0  stevel 		exit(1);
    390     0  stevel 	}
    391     0  stevel 
    392     0  stevel 	(void) strcpy(psname, procdir);
    393     0  stevel 	pdlen = strlen(psname);
    394     0  stevel 	psname[pdlen++] = '/';
    395     0  stevel 
    396     0  stevel 	/* for each active process --- */
    397     0  stevel 	while (dentp = readdir(dirp)) {
    398     0  stevel 		int	psfd;	/* file descriptor for /proc/nnnnn/psinfo */
    399     0  stevel 		int	asfd;	/* file descriptor for /proc/nnnnn/as */
    400     0  stevel 
    401     0  stevel 		if (dentp->d_name[0] == '.')		/* skip . and .. */
    402     0  stevel 			continue;
    403     0  stevel 		(void) strcpy(psname + pdlen, dentp->d_name);
    404     0  stevel 		(void) strcpy(asname, psname);
    405     0  stevel 		(void) strcat(psname, "/psinfo");
    406     0  stevel 		(void) strcat(asname, "/as");
    407     0  stevel retry:
    408     0  stevel 		if ((psfd = open(psname, O_RDONLY)) == -1)
    409     0  stevel 			continue;
    410     0  stevel 		asfd = -1;
    411     0  stevel 		if (psargs != NULL || eflg) {
    412     0  stevel 
    413     0  stevel 			/* now we need the proc_owner privilege */
    414     0  stevel 			(void) __priv_bracket(PRIV_ON);
    415     0  stevel 
    416     0  stevel 			asfd = open(asname, O_RDONLY);
    417     0  stevel 
    418     0  stevel 			/* drop proc_owner privilege after open */
    419     0  stevel 			(void) __priv_bracket(PRIV_OFF);
    420     0  stevel 		}
    421     0  stevel 
    422     0  stevel 		/*
    423     0  stevel 		 * Get the info structure for the process
    424     0  stevel 		 */
    425     0  stevel 		if (read(psfd, &info, sizeof (info)) != sizeof (info)) {
    426     0  stevel 			int	saverr = errno;
    427     0  stevel 
    428     0  stevel 			(void) close(psfd);
    429     0  stevel 			if (asfd > 0)
    430     0  stevel 				(void) close(asfd);
    431     0  stevel 			if (saverr == EAGAIN)
    432     0  stevel 				goto retry;
    433     0  stevel 			if (saverr != ENOENT)
    434     0  stevel 				(void) fprintf(stderr, "ps: read() on %s: %s\n",
    435     0  stevel 				    psname, err_string(saverr));
    436     0  stevel 			continue;
    437     0  stevel 		}
    438     0  stevel 		(void) close(psfd);
    439     0  stevel 
    440     0  stevel 		found = 0;
    441     0  stevel 		if (info.pr_lwp.pr_state == 0)		/* can't happen? */
    442     0  stevel 			goto closeit;
    443     0  stevel 		pid = info.pr_pid;
    444     0  stevel 		ppid = info.pr_ppid;
    445     0  stevel 
    446     0  stevel 		/* Display only process from command line */
    447     0  stevel 		if (pflg) {	/* pid in arg list */
    448     0  stevel 			if (pidsave == pid)
    449     0  stevel 				found++;
    450     0  stevel 			else
    451     0  stevel 				goto closeit;
    452     0  stevel 		}
    453     0  stevel 
    454     0  stevel 		/*
    455     0  stevel 		 * Omit "uninteresting" processes unless 'g' option.
    456     0  stevel 		 */
    457     0  stevel 		if ((ppid == 1) && !(gflg))
    458     0  stevel 			goto closeit;
    459     0  stevel 
    460     0  stevel 		/*
    461     0  stevel 		 * Omit non-running processes for 'r' option
    462     0  stevel 		 */
    463     0  stevel 		if (rflg &&
    464     0  stevel 		    !(info.pr_lwp.pr_sname == 'O' ||
    465     0  stevel 		    info.pr_lwp.pr_sname == 'R'))
    466     0  stevel 			goto closeit;
    467     0  stevel 
    468     0  stevel 		if (!found && !tflg && !aflg && info.pr_euid != my_uid)
    469     0  stevel 			goto closeit;
    470     0  stevel 
    471     0  stevel 		/*
    472     0  stevel 		 * Read the args for the -w and -ww cases
    473     0  stevel 		 */
    474     0  stevel 		if (asfd > 0) {
    475     0  stevel 			if ((psargs != NULL &&
    476     0  stevel 			    preadargs(asfd, &info, psargs) == -1) ||
    477     0  stevel 			    (eflg && preadenvs(asfd, &info, psargs) == -1)) {
    478     0  stevel 				int	saverr = errno;
    479     0  stevel 
    480     0  stevel 				(void) close(asfd);
    481     0  stevel 				if (saverr == EAGAIN)
    482     0  stevel 					goto retry;
    483     0  stevel 				if (saverr != ENOENT)
    484     0  stevel 					(void) fprintf(stderr,
    485     0  stevel 					    "ps: read() on %s: %s\n",
    486     0  stevel 					    asname, err_string(saverr));
    487     0  stevel 				continue;
    488     0  stevel 			}
    489     0  stevel 		} else {
    490     0  stevel 			psargs = info.pr_psargs;
    491     0  stevel 		}
    492     0  stevel 
    493     0  stevel 		if (nent >= entsize) {
    494     0  stevel 			entsize *= 2;
    495     0  stevel 			psent = (struct psent *)realloc((char *)psent,
    496  8822  Casper 			    entsize * sizeof (struct psent));
    497     0  stevel 			if (psent == NULL) {
    498     0  stevel 				(void) fprintf(stderr, "ps: no memory\n");
    499     0  stevel 				exit(1);
    500     0  stevel 			}
    501     0  stevel 		}
    502     0  stevel 		if ((psent[nent].psinfo = malloc(sizeof (psinfo_t)))
    503     0  stevel 		    == NULL) {
    504     0  stevel 			(void) fprintf(stderr, "ps: no memory\n");
    505     0  stevel 			exit(1);
    506     0  stevel 		}
    507     0  stevel 		*psent[nent].psinfo = info;
    508     0  stevel 		if (psargs == NULL)
    509     0  stevel 			psent[nent].psargs = NULL;
    510     0  stevel 		else {
    511     0  stevel 			if ((psent[nent].psargs = malloc(strlen(psargs)+1))
    512     0  stevel 			    == NULL) {
    513     0  stevel 				(void) fprintf(stderr, "ps: no memory\n");
    514     0  stevel 				exit(1);
    515     0  stevel 			}
    516     0  stevel 			(void) strcpy(psent[nent].psargs, psargs);
    517     0  stevel 		}
    518     0  stevel 		psent[nent].found = found;
    519     0  stevel 		nent++;
    520     0  stevel closeit:
    521     0  stevel 		if (asfd > 0)
    522     0  stevel 			(void) close(asfd);
    523     0  stevel 		psargs = svpsargs;
    524     0  stevel 	}
    525     0  stevel 
    526     0  stevel 	/* revert to non-privileged user */
    527     0  stevel 	(void) __priv_relinquish();
    528     0  stevel 
    529     0  stevel 	(void) closedir(dirp);
    530     0  stevel 
    531     0  stevel 	qsort((char *)psent, nent, sizeof (psent[0]), pscompare);
    532     0  stevel 
    533     0  stevel 	for (i = 0; i < nent; i++) {
    534     0  stevel 		struct psent *pp = &psent[i];
    535     0  stevel 		if (prcom(pp->found, pp->psinfo, pp->psargs)) {
    536     0  stevel 			(void) printf("\n");
    537     0  stevel 			retcode = 0;
    538     0  stevel 		}
    539     0  stevel 	}
    540     0  stevel 
    541     0  stevel 	return (retcode);
    542     0  stevel }
    543     0  stevel 
    544     0  stevel static void
    545     0  stevel usage()		/* print usage message and quit */
    546     0  stevel {
    547     0  stevel 	static char usage1[] = "ps [ -aceglnrSuUvwx ] [ -t term ] [ num ]";
    548     0  stevel 
    549     0  stevel 	(void) fprintf(stderr, "usage: %s\n", usage1);
    550     0  stevel 	exit(1);
    551     0  stevel }
    552     0  stevel 
    553     0  stevel /*
    554     0  stevel  * Read the process arguments from the process.
    555     0  stevel  * This allows >PRARGSZ characters of arguments to be displayed but,
    556     0  stevel  * unlike pr_psargs[], the process may have changed them.
    557     0  stevel  */
    558     0  stevel #define	NARG	100
    559     0  stevel static int
    560     0  stevel preadargs(int pfd, psinfo_t *psinfo, char *psargs)
    561     0  stevel {
    562     0  stevel 	off_t argvoff = (off_t)psinfo->pr_argv;
    563     0  stevel 	size_t len;
    564     0  stevel 	char *psa = psargs;
    565     0  stevel 	int bsize = twidth;
    566     0  stevel 	int narg = NARG;
    567     0  stevel 	off_t argv[NARG];
    568     0  stevel 	off_t argoff;
    569     0  stevel 	off_t nextargoff;
    570     0  stevel 	int i;
    571     0  stevel #ifdef _LP64
    572     0  stevel 	caddr32_t argv32[NARG];
    573     0  stevel 	int is32 = (psinfo->pr_dmodel != PR_MODEL_LP64);
    574     0  stevel #endif
    575     0  stevel 
    576     0  stevel 	if (psinfo->pr_nlwp == 0 ||
    577     0  stevel 	    strcmp(psinfo->pr_lwp.pr_clname, "SYS") == 0)
    578     0  stevel 		goto out;
    579     0  stevel 
    580     0  stevel 	(void) memset(psa, 0, bsize--);
    581     0  stevel 	nextargoff = 0;
    582     0  stevel 	errno = EIO;
    583     0  stevel 	while (bsize > 0) {
    584     0  stevel 		if (narg == NARG) {
    585     0  stevel 			(void) memset(argv, 0, sizeof (argv));
    586     0  stevel #ifdef _LP64
    587     0  stevel 			if (is32) {
    588     0  stevel 				if ((i = pread(pfd, argv32, sizeof (argv32),
    589     0  stevel 				    argvoff)) <= 0) {
    590     0  stevel 					if (i == 0 || errno == EIO)
    591     0  stevel 						break;
    592     0  stevel 					return (-1);
    593     0  stevel 				}
    594     0  stevel 				for (i = 0; i < NARG; i++)
    595     0  stevel 					argv[i] = argv32[i];
    596     0  stevel 			} else
    597     0  stevel #endif
    598     0  stevel 				if ((i = pread(pfd, argv, sizeof (argv),
    599     0  stevel 				    argvoff)) <= 0) {
    600     0  stevel 					if (i == 0 || errno == EIO)
    601     0  stevel 						break;
    602     0  stevel 					return (-1);
    603     0  stevel 				}
    604     0  stevel 			narg = 0;
    605     0  stevel 		}
    606     0  stevel 		if ((argoff = argv[narg++]) == 0)
    607     0  stevel 			break;
    608     0  stevel 		if (argoff != nextargoff &&
    609     0  stevel 		    (i = pread(pfd, psa, bsize, argoff)) <= 0) {
    610     0  stevel 			if (i == 0 || errno == EIO)
    611     0  stevel 				break;
    612     0  stevel 			return (-1);
    613     0  stevel 		}
    614     0  stevel 		len = strlen(psa);
    615     0  stevel 		psa += len;
    616     0  stevel 		*psa++ = ' ';
    617     0  stevel 		bsize -= len + 1;
    618     0  stevel 		nextargoff = argoff + len + 1;
    619     0  stevel #ifdef _LP64
    620     0  stevel 		argvoff += is32? sizeof (caddr32_t) : sizeof (caddr_t);
    621     0  stevel #else
    622     0  stevel 		argvoff += sizeof (caddr_t);
    623     0  stevel #endif
    624     0  stevel 	}
    625     0  stevel 	while (psa > psargs && isspace(*(psa-1)))
    626     0  stevel 		psa--;
    627     0  stevel 
    628     0  stevel out:
    629     0  stevel 	*psa = '\0';
    630     0  stevel 	if (strlen(psinfo->pr_psargs) > strlen(psargs))
    631     0  stevel 		(void) strcpy(psargs, psinfo->pr_psargs);
    632     0  stevel 
    633     0  stevel 	return (0);
    634     0  stevel }
    635     0  stevel 
    636     0  stevel /*
    637     0  stevel  * Read environment variables from the process.
    638     0  stevel  * Append them to psargs if there is room.
    639     0  stevel  */
    640     0  stevel static int
    641     0  stevel preadenvs(int pfd, psinfo_t *psinfo, char *psargs)
    642     0  stevel {
    643     0  stevel 	off_t envpoff = (off_t)psinfo->pr_envp;
    644     0  stevel 	int len;
    645     0  stevel 	char *psa;
    646     0  stevel 	char *psainit;
    647     0  stevel 	int bsize;
    648     0  stevel 	int nenv = NARG;
    649     0  stevel 	off_t envp[NARG];
    650     0  stevel 	off_t envoff;
    651     0  stevel 	off_t nextenvoff;
    652     0  stevel 	int i;
    653     0  stevel #ifdef _LP64
    654     0  stevel 	caddr32_t envp32[NARG];
    655     0  stevel 	int is32 = (psinfo->pr_dmodel != PR_MODEL_LP64);
    656     0  stevel #endif
    657     0  stevel 
    658     0  stevel 	psainit = psa = (psargs != NULL)? psargs : psinfo->pr_psargs;
    659     0  stevel 	len = strlen(psa);
    660     0  stevel 	psa += len;
    661     0  stevel 	bsize = twidth - len - 1;
    662     0  stevel 
    663     0  stevel 	if (bsize <= 0 || psinfo->pr_nlwp == 0 ||
    664     0  stevel 	    strcmp(psinfo->pr_lwp.pr_clname, "SYS") == 0)
    665     0  stevel 		return (0);
    666     0  stevel 
    667     0  stevel 	nextenvoff = 0;
    668     0  stevel 	errno = EIO;
    669     0  stevel 	while (bsize > 0) {
    670     0  stevel 		if (nenv == NARG) {
    671     0  stevel 			(void) memset(envp, 0, sizeof (envp));
    672     0  stevel #ifdef _LP64
    673     0  stevel 			if (is32) {
    674     0  stevel 				if ((i = pread(pfd, envp32, sizeof (envp32),
    675     0  stevel 				    envpoff)) <= 0) {
    676     0  stevel 					if (i == 0 || errno == EIO)
    677     0  stevel 						break;
    678     0  stevel 					return (-1);
    679     0  stevel 				}
    680     0  stevel 				for (i = 0; i < NARG; i++)
    681     0  stevel 					envp[i] = envp32[i];
    682     0  stevel 			} else
    683     0  stevel #endif
    684     0  stevel 				if ((i = pread(pfd, envp, sizeof (envp),
    685     0  stevel 				    envpoff)) <= 0) {
    686     0  stevel 					if (i == 0 || errno == EIO)
    687     0  stevel 						break;
    688     0  stevel 					return (-1);
    689     0  stevel 				}
    690     0  stevel 			nenv = 0;
    691     0  stevel 		}
    692     0  stevel 		if ((envoff = envp[nenv++]) == 0)
    693     0  stevel 			break;
    694     0  stevel 		if (envoff != nextenvoff &&
    695     0  stevel 		    (i = pread(pfd, psa+1, bsize, envoff)) <= 0) {
    696     0  stevel 			if (i == 0 || errno == EIO)
    697     0  stevel 				break;
    698     0  stevel 			return (-1);
    699     0  stevel 		}
    700     0  stevel 		*psa++ = ' ';
    701     0  stevel 		len = strlen(psa);
    702     0  stevel 		psa += len;
    703     0  stevel 		bsize -= len + 1;
    704     0  stevel 		nextenvoff = envoff + len + 1;
    705     0  stevel #ifdef _LP64
    706     0  stevel 		envpoff += is32? sizeof (caddr32_t) : sizeof (caddr_t);
    707     0  stevel #else
    708     0  stevel 		envpoff += sizeof (caddr_t);
    709     0  stevel #endif
    710     0  stevel 	}
    711     0  stevel 	while (psa > psainit && isspace(*(psa-1)))
    712     0  stevel 		psa--;
    713     0  stevel 	*psa = '\0';
    714     0  stevel 
    715     0  stevel 	return (0);
    716     0  stevel }
    717     0  stevel 
    718     0  stevel /*
    719     0  stevel  * getarg() finds the next argument in list and copies arg into argbuf.
    720     0  stevel  * p1 first pts to arg passed back from getopt routine.  p1 is then
    721     0  stevel  * bumped to next character that is not a comma or blank -- p1 NULL
    722     0  stevel  * indicates end of list.
    723     0  stevel  */
    724     0  stevel 
    725     0  stevel static void
    726     0  stevel getarg()
    727     0  stevel {
    728     0  stevel 	char	*parga;
    729     0  stevel 	int c;
    730     0  stevel 
    731     0  stevel 	while ((c = *p1) != '\0' && (c == ',' || isspace(c)))
    732     0  stevel 		p1++;
    733     0  stevel 
    734     0  stevel 	parga = argbuf;
    735     0  stevel 	while ((c = *p1) != '\0' && c != ',' && !isspace(c)) {
    736     0  stevel 		if (parga < argbuf + ARGSIZ - 1)
    737     0  stevel 			*parga++ = c;
    738     0  stevel 		p1++;
    739     0  stevel 	}
    740     0  stevel 	*parga = '\0';
    741     0  stevel 
    742     0  stevel 	while ((c = *p1) != '\0' && (c == ',' || isspace(c)))
    743     0  stevel 		p1++;
    744     0  stevel }
    745     0  stevel 
    746     0  stevel static char *
    747     0  stevel devlookup(dev_t ddev)
    748     0  stevel {
    749     0  stevel 	struct devl *dp;
    750     0  stevel 	int i;
    751     0  stevel 
    752     0  stevel 	for (dp = devl, i = 0; i < ndev; dp++, i++) {
    753     0  stevel 		if (dp->ddev == ddev)
    754     0  stevel 			return (dp->dname);
    755     0  stevel 	}
    756     0  stevel 	return (NULL);
    757     0  stevel }
    758     0  stevel 
    759     0  stevel static char *
    760     0  stevel devadd(char *name, dev_t ddev)
    761     0  stevel {
    762     0  stevel 	struct devl *dp;
    763     0  stevel 	int leng, start, i;
    764     0  stevel 
    765     0  stevel 	if (ndev == maxdev) {
    766     0  stevel 		maxdev += DNINCR;
    767     0  stevel 		devl = realloc(devl, maxdev * sizeof (struct devl));
    768     0  stevel 		if (devl == NULL) {
    769     0  stevel 			(void) fprintf(stderr,
    770     0  stevel 			    "ps: not enough memory for %d devices\n", maxdev);
    771     0  stevel 			exit(1);
    772     0  stevel 		}
    773     0  stevel 	}
    774     0  stevel 	dp = &devl[ndev++];
    775     0  stevel 
    776     0  stevel 	dp->ddev = ddev;
    777     0  stevel 	if (name == NULL) {
    778     0  stevel 		(void) strcpy(dp->dname, "??");
    779     0  stevel 		return (dp->dname);
    780     0  stevel 	}
    781     0  stevel 
    782     0  stevel 	leng = strlen(name);
    783     0  stevel 	/* Strip off /dev/ */
    784     0  stevel 	if (leng < DNSIZE + 4)
    785     0  stevel 		(void) strcpy(dp->dname, &name[5]);
    786     0  stevel 	else {
    787     0  stevel 		start = leng - (DNSIZE - 1);
    788     0  stevel 
    789     0  stevel 		for (i = start; i < leng && name[i] != '/'; i++)
    790     0  stevel 				;
    791     0  stevel 		if (i == leng)
    792     0  stevel 			(void) strlcpy(dp->dname, &name[start], DNSIZE);
    793     0  stevel 		else
    794     0  stevel 			(void) strlcpy(dp->dname, &name[i+1], DNSIZE);
    795     0  stevel 	}
    796     0  stevel 	return (dp->dname);
    797     0  stevel }
    798     0  stevel 
    799     0  stevel /*
    800     0  stevel  * gettty returns the user's tty number or ? if none.
    801     0  stevel  */
    802     0  stevel static char *
    803     0  stevel gettty(psinfo_t *psinfo)
    804     0  stevel {
    805     0  stevel 	extern char *_ttyname_dev(dev_t, char *, size_t);
    806     0  stevel 	char devname[TTYNAME_MAX];
    807     0  stevel 	char *retval;
    808     0  stevel 
    809     0  stevel 	if (psinfo->pr_ttydev == PRNODEV)
    810     0  stevel 		return ("?");
    811     0  stevel 
    812     0  stevel 	if ((retval = devlookup(psinfo->pr_ttydev)) != NULL)
    813     0  stevel 		return (retval);
    814     0  stevel 
    815     0  stevel 	retval = _ttyname_dev(psinfo->pr_ttydev, devname, sizeof (devname));
    816     0  stevel 
    817     0  stevel 	return (devadd(retval, psinfo->pr_ttydev));
    818     0  stevel }
    819     0  stevel 
    820     0  stevel /*
    821     0  stevel  * Print percent from 16-bit binary fraction [0 .. 1]
    822     0  stevel  * Round up .01 to .1 to indicate some small percentage (the 0x7000 below).
    823     0  stevel  */
    824     0  stevel static void
    825     0  stevel prtpct(ushort_t pct)
    826     0  stevel {
    827     0  stevel 	uint_t value = pct;	/* need 32 bits to compute with */
    828     0  stevel 
    829     0  stevel 	value = ((value * 1000) + 0x7000) >> 15;	/* [0 .. 1000] */
    830     0  stevel 	(void) printf("%3u.%u", value / 10, value % 10);
    831     0  stevel }
    832     0  stevel 
    833     0  stevel /*
    834     0  stevel  * Print info about the process.
    835     0  stevel  */
    836     0  stevel static int
    837     0  stevel prcom(int found, psinfo_t *psinfo, char *psargs)
    838     0  stevel {
    839     0  stevel 	char	*cp;
    840     0  stevel 	char	*tp;
    841     0  stevel 	char	*psa;
    842     0  stevel 	long	tm;
    843     0  stevel 	int	i, wcnt, length;
    844     0  stevel 	wchar_t	wchar;
    845     0  stevel 	struct tty *ttyp;
    846     0  stevel 
    847     0  stevel 	/*
    848     0  stevel 	 * If process is zombie, call print routine and return.
    849     0  stevel 	 */
    850     0  stevel 	if (psinfo->pr_nlwp == 0) {
    851     0  stevel 		if (tflg && !found)
    852     0  stevel 			return (0);
    853     0  stevel 		else {
    854     0  stevel 			przom(psinfo);
    855     0  stevel 			return (1);
    856     0  stevel 		}
    857     0  stevel 	}
    858     0  stevel 
    859     0  stevel 	/*
    860     0  stevel 	 * Get current terminal.  If none ("?") and 'a' is set, don't print
    861     0  stevel 	 * info.  If 't' is set, check if term is in list of desired terminals
    862     0  stevel 	 * and print it if it is.
    863     0  stevel 	 */
    864     0  stevel 	i = 0;
    865     0  stevel 	tp = gettty(psinfo);
    866     0  stevel 
    867     0  stevel 	if (*tp == '?' && !found && !xflg)
    868     0  stevel 		return (0);
    869     0  stevel 
    870     0  stevel 	if (!(*tp == '?' && aflg) && tflg && !found) {
    871     0  stevel 		int match = 0;
    872     0  stevel 		char *other = NULL;
    873     0  stevel 		for (ttyp = tty; ttyp->tname != NULL; ttyp++) {
    874     0  stevel 			/*
    875     0  stevel 			 * Look for a name match
    876     0  stevel 			 */
    877     0  stevel 			if (strcmp(tp, ttyp->tname) == 0) {
    878     0  stevel 				match = 1;
    879     0  stevel 				break;
    880     0  stevel 			}
    881     0  stevel 			/*
    882     0  stevel 			 * Look for same device under different names.
    883     0  stevel 			 */
    884     0  stevel 			if ((other == NULL) &&
    885     0  stevel 			    (psinfo->pr_ttydev == ttyp->tdev))
    886     0  stevel 				other = ttyp->tname;
    887     0  stevel 		}
    888     0  stevel 		if (!match) {
    889     0  stevel 			if (other == NULL)
    890     0  stevel 				return (0);
    891     0  stevel 			tp = other;
    892     0  stevel 		}
    893     0  stevel 	}
    894     0  stevel 
    895     0  stevel 	if (lflg)
    896     0  stevel 		(void) printf("%2x", psinfo->pr_flag & 0377);
    897     0  stevel 	if (uflg) {
    898     0  stevel 		if (!nflg) {
    899     0  stevel 			struct passwd *pwd;
    900     0  stevel 
    901     0  stevel 			if ((pwd = getpwuid(psinfo->pr_euid)) != NULL)
    902     0  stevel 								/* USER */
    903     0  stevel 				(void) printf("%-8.8s", pwd->pw_name);
    904     0  stevel 			else
    905     0  stevel 								/* UID */
    906     0  stevel 				(void) printf(" %7.7d", (int)psinfo->pr_euid);
    907     0  stevel 		} else {
    908     0  stevel 			(void) printf(" %5d", (int)psinfo->pr_euid); /* UID */
    909     0  stevel 		}
    910     0  stevel 	} else if (lflg)
    911     0  stevel 		(void) printf(" %5d", (int)psinfo->pr_euid);	/* UID */
    912     0  stevel 
    913     0  stevel 	(void) printf("%*d", pidwidth + 1, (int)psinfo->pr_pid); /* PID */
    914     0  stevel 	if (lflg)
    915     0  stevel 		(void) printf("%*d", pidwidth + 1,
    916     0  stevel 		    (int)psinfo->pr_ppid); /* PPID */
    917     0  stevel 	if (lflg)
    918     0  stevel 		(void) printf("%3d", psinfo->pr_lwp.pr_cpu & 0377); /* CP */
    919     0  stevel 	if (uflg) {
    920     0  stevel 		prtpct(psinfo->pr_pctcpu);			/* %CPU */
    921     0  stevel 		prtpct(psinfo->pr_pctmem);			/* %MEM */
    922     0  stevel 	}
    923     0  stevel 	if (lflg) {
    924     0  stevel 		(void) printf("%4d", psinfo->pr_lwp.pr_pri);	/* PRI */
    925     0  stevel 		(void) printf("%3d", psinfo->pr_lwp.pr_nice);	/* NICE */
    926     0  stevel 	}
    927     0  stevel 	if (lflg || uflg) {
    928     0  stevel 		if (psinfo->pr_flag & SSYS)			/* SZ */
    929     0  stevel 			(void) printf("    0");
    930     0  stevel 		else if (psinfo->pr_size)
    931     0  stevel 			(void) printf("%5lu", (ulong_t)psinfo->pr_size);
    932     0  stevel 		else
    933     0  stevel 			(void) printf("    ?");
    934     0  stevel 		if (psinfo->pr_flag & SSYS)			/* RSS */
    935     0  stevel 			(void) printf("    0");
    936     0  stevel 		else if (psinfo->pr_rssize)
    937     0  stevel 			(void) printf("%5lu", (ulong_t)psinfo->pr_rssize);
    938     0  stevel 		else
    939     0  stevel 			(void) printf("    ?");
    940     0  stevel 	}
    941     0  stevel 	if (lflg) {						/* WCHAN */
    942     0  stevel 		if (psinfo->pr_lwp.pr_sname != 'S') {
    943     0  stevel 			(void) printf("         ");
    944     0  stevel 		} else if (psinfo->pr_lwp.pr_wchan) {
    945     0  stevel 			(void) printf(" %+8.8lx",
    946  8822  Casper 			    (ulong_t)psinfo->pr_lwp.pr_wchan);
    947     0  stevel 		} else {
    948     0  stevel 			(void) printf("        ?");
    949     0  stevel 		}
    950     0  stevel 	}
    951     0  stevel 	if ((tplen = strlen(tp)) > 9)
    952     0  stevel 		maxlen = twidth - tplen + 9;
    953     0  stevel 	else
    954     0  stevel 		maxlen = twidth;
    955     0  stevel 
    956     0  stevel 	if (!lflg)
    957     0  stevel 		(void) printf(" %-8.14s", tp);			/* TTY */
    958     0  stevel 	(void) printf(" %c", psinfo->pr_lwp.pr_sname);		/* STATE */
    959     0  stevel 	if (lflg)
    960     0  stevel 		(void) printf(" %-8.14s", tp);			/* TTY */
    961     0  stevel 	if (uflg)
    962     0  stevel 		prtime(psinfo->pr_start);			/* START */
    963     0  stevel 
    964     0  stevel 	/* time just for process */
    965     0  stevel 	tm = psinfo->pr_time.tv_sec;
    966     0  stevel 	if (Sflg) {	/* calculate time for process and all reaped children */
    967     0  stevel 		tm += psinfo->pr_ctime.tv_sec;
    968     0  stevel 		if (psinfo->pr_time.tv_nsec + psinfo->pr_ctime.tv_nsec
    969     0  stevel 		    >= 1000000000)
    970     0  stevel 			tm += 1;
    971     0  stevel 	}
    972     0  stevel 
    973     0  stevel 	(void) printf(" %2ld:%.2ld", tm / 60, tm % 60);		/* TIME */
    974     0  stevel 
    975     0  stevel 	if (vflg) {
    976     0  stevel 		if (psinfo->pr_flag & SSYS)			/* SZ */
    977     0  stevel 			(void) printf("    0");
    978     0  stevel 		else if (psinfo->pr_size)
    979     0  stevel 			(void) printf("%5lu", (ulong_t)psinfo->pr_size);
    980     0  stevel 		else
    981     0  stevel 			(void) printf("    ?");
    982     0  stevel 		if (psinfo->pr_flag & SSYS)			/* SZ */
    983     0  stevel 			(void) printf("    0");
    984     0  stevel 		else if (psinfo->pr_rssize)
    985     0  stevel 			(void) printf("%5lu", (ulong_t)psinfo->pr_rssize);
    986     0  stevel 		else
    987     0  stevel 			(void) printf("    ?");
    988     0  stevel 		prtpct(psinfo->pr_pctcpu);			/* %CPU */
    989     0  stevel 		prtpct(psinfo->pr_pctmem);			/* %MEM */
    990     0  stevel 	}
    991     0  stevel 	if (cflg) {						/* CMD */
    992     0  stevel 		wcnt = namencnt(psinfo->pr_fname, 16, maxlen);
    993     0  stevel 		(void) printf(" %.*s", wcnt, psinfo->pr_fname);
    994     0  stevel 		return (1);
    995     0  stevel 	}
    996     0  stevel 	/*
    997     0  stevel 	 * PRARGSZ == length of cmd arg string.
    998     0  stevel 	 */
    999     0  stevel 	if (psargs == NULL) {
   1000     0  stevel 		psa = &psinfo->pr_psargs[0];
   1001     0  stevel 		i = PRARGSZ;
   1002     0  stevel 		tp = &psinfo->pr_psargs[PRARGSZ];
   1003     0  stevel 	} else {
   1004     0  stevel 		psa = psargs;
   1005     0  stevel 		i = strlen(psargs);
   1006     0  stevel 		tp = psa + i;
   1007     0  stevel 	}
   1008     0  stevel 
   1009     0  stevel 	for (cp = psa; cp < tp; /* empty */) {
   1010     0  stevel 		if (*cp == 0)
   1011     0  stevel 			break;
   1012     0  stevel 		length = mbtowc(&wchar, cp, MB_LEN_MAX);
   1013     0  stevel 		if (length < 0 || !iswprint(wchar)) {
   1014     0  stevel 			(void) printf(" [ %.16s ]", psinfo->pr_fname);
   1015     0  stevel 			return (1);
   1016     0  stevel 		}
   1017     0  stevel 		cp += length;
   1018     0  stevel 	}
   1019     0  stevel 	wcnt = namencnt(psa, i, maxlen);
   1020     0  stevel #if 0
   1021     0  stevel 	/* dumps core on really long strings */
   1022     0  stevel 	(void) printf(" %.*s", wcnt, psa);
   1023     0  stevel #else
   1024     0  stevel 	(void) putchar(' ');
   1025     0  stevel 	(void) fwrite(psa, 1, wcnt, stdout);
   1026     0  stevel #endif
   1027     0  stevel 	return (1);
   1028     0  stevel }
   1029     0  stevel 
   1030     0  stevel /*
   1031     0  stevel  * Print starting time of process unless process started more than 24 hours
   1032     0  stevel  * ago, in which case the date is printed.
   1033     0  stevel  */
   1034     0  stevel static void
   1035     0  stevel prtime(timestruc_t st)
   1036     0  stevel {
   1037     0  stevel 	char sttim[26];
   1038     0  stevel 	static time_t tim = 0L;
   1039     0  stevel 	time_t starttime;
   1040     0  stevel 
   1041     0  stevel 	if (tim == 0L)
   1042     0  stevel 		tim = time((time_t *)0);
   1043     0  stevel 	starttime = st.tv_sec;
   1044     0  stevel 	if (tim - starttime > 24*60*60) {
   1045     0  stevel 		(void) strftime(sttim, sizeof (sttim), "%b %d",
   1046  8822  Casper 		    localtime(&starttime));
   1047     0  stevel 	} else {
   1048     0  stevel 		(void) strftime(sttim, sizeof (sttim), "%H:%M:%S",
   1049  8822  Casper 		    localtime(&starttime));
   1050     0  stevel 	}
   1051     0  stevel 	(void) printf("%9.9s", sttim);
   1052     0  stevel }
   1053     0  stevel 
   1054     0  stevel static void
   1055     0  stevel przom(psinfo_t *psinfo)
   1056     0  stevel {
   1057     0  stevel 	long	tm;
   1058     0  stevel 
   1059     0  stevel 	if (lflg)
   1060     0  stevel 		(void) printf("%2x", psinfo->pr_flag & 0377);
   1061     0  stevel 	if (uflg) {
   1062     0  stevel 		struct passwd *pwd;
   1063     0  stevel 
   1064     0  stevel 		if ((pwd = getpwuid(psinfo->pr_euid)) != NULL)
   1065     0  stevel 			(void) printf("%-8.8s", pwd->pw_name);	/* USER */
   1066     0  stevel 		else
   1067     0  stevel 			(void) printf(" %7.7d", (int)psinfo->pr_euid); /* UID */
   1068     0  stevel 	} else if (lflg)
   1069     0  stevel 		(void) printf(" %5d", (int)psinfo->pr_euid);	/* UID */
   1070     0  stevel 
   1071     0  stevel 	(void) printf("%*d", pidwidth + 1, (int)psinfo->pr_pid); /* PID */
   1072     0  stevel 	if (lflg)
   1073     0  stevel 		(void) printf("%*d", pidwidth + 1,
   1074     0  stevel 		    (int)psinfo->pr_ppid); /* PPID */
   1075     0  stevel 	if (lflg)
   1076     0  stevel 		(void) printf("  0");				/* CP */
   1077     0  stevel 	if (uflg) {
   1078     0  stevel 		prtpct(0);					/* %CPU */
   1079     0  stevel 		prtpct(0);					/* %MEM */
   1080     0  stevel 	}
   1081     0  stevel 	if (lflg) {
   1082     0  stevel 		(void) printf("%4d", psinfo->pr_lwp.pr_pri);	/* PRI */
   1083     0  stevel 		(void) printf("   ");				/* NICE */
   1084     0  stevel 	}
   1085     0  stevel 	if (lflg || uflg) {
   1086     0  stevel 		(void) printf("    0");				/* SZ */
   1087     0  stevel 		(void) printf("    0");				/* RSS */
   1088     0  stevel 	}
   1089     0  stevel 	if (lflg)
   1090     0  stevel 		(void) printf("         ");			/* WCHAN */
   1091     0  stevel 	(void) printf("          ");				/* TTY */
   1092     0  stevel 	(void) printf("%c", psinfo->pr_lwp.pr_sname);		/* STATE */
   1093     0  stevel 	if (uflg)
   1094     0  stevel 		(void) printf("         ");			/* START */
   1095     0  stevel 
   1096     0  stevel 	/* time just for process */
   1097     0  stevel 	tm = psinfo->pr_time.tv_sec;
   1098     0  stevel 	if (Sflg) {	/* calculate time for process and all reaped children */
   1099     0  stevel 		tm += psinfo->pr_ctime.tv_sec;
   1100     0  stevel 		if (psinfo->pr_time.tv_nsec + psinfo->pr_ctime.tv_nsec
   1101     0  stevel 		    >= 1000000000)
   1102     0  stevel 			tm += 1;
   1103     0  stevel 	}
   1104     0  stevel 	(void) printf(" %2ld:%.2ld", tm / 60, tm % 60);		/* TIME */
   1105     0  stevel 
   1106     0  stevel 	if (vflg) {
   1107     0  stevel 		(void) printf("    0");				/* SZ */
   1108     0  stevel 		(void) printf("    0");				/* RSS */
   1109     0  stevel 		prtpct(0);					/* %CPU */
   1110     0  stevel 		prtpct(0);					/* %MEM */
   1111     0  stevel 	}
   1112     0  stevel 	(void) printf(" %.*s", maxlen, " <defunct>");
   1113     0  stevel }
   1114     0  stevel 
   1115     0  stevel /*
   1116     0  stevel  * Returns true iff string is all numeric.
   1117     0  stevel  */
   1118     0  stevel static int
   1119     0  stevel num(char *s)
   1120     0  stevel {
   1121     0  stevel 	int c;
   1122     0  stevel 
   1123     0  stevel 	if (s == NULL)
   1124     0  stevel 		return (0);
   1125     0  stevel 	c = *s;
   1126     0  stevel 	do {
   1127     0  stevel 		if (!isdigit(c))
   1128     0  stevel 			return (0);
   1129     0  stevel 	} while ((c = *++s) != '\0');
   1130     0  stevel 	return (1);
   1131     0  stevel }
   1132     0  stevel 
   1133     0  stevel /*
   1134     0  stevel  * Function to compute the number of printable bytes in a multibyte
   1135     0  stevel  * command string ("internationalization").
   1136     0  stevel  */
   1137     0  stevel static int
   1138     0  stevel namencnt(char *cmd, int eucsize, int scrsize)
   1139     0  stevel {
   1140     0  stevel 	int eucwcnt = 0, scrwcnt = 0;
   1141     0  stevel 	int neucsz, nscrsz;
   1142     0  stevel 	wchar_t	wchar;
   1143     0  stevel 
   1144     0  stevel 	while (*cmd != '\0') {
   1145     0  stevel 		if ((neucsz = mbtowc(&wchar, cmd, MB_LEN_MAX)) < 0)
   1146     0  stevel 			return (8); /* default to use for illegal chars */
   1147     0  stevel 		if ((nscrsz = scrwidth(wchar)) == 0)
   1148     0  stevel 			return (8);
   1149     0  stevel 		if (eucwcnt + neucsz > eucsize || scrwcnt + nscrsz > scrsize)
   1150     0  stevel 			break;
   1151     0  stevel 		eucwcnt += neucsz;
   1152     0  stevel 		scrwcnt += nscrsz;
   1153     0  stevel 		cmd += neucsz;
   1154     0  stevel 	}
   1155     0  stevel 	return (eucwcnt);
   1156     0  stevel }
   1157     0  stevel 
   1158     0  stevel static int
   1159     0  stevel pscompare(const void *v1, const void *v2)
   1160     0  stevel {
   1161     0  stevel 	const struct psent *p1 = v1;
   1162     0  stevel 	const struct psent *p2 = v2;
   1163     0  stevel 	int i;
   1164     0  stevel 
   1165     0  stevel 	if (uflg)
   1166     0  stevel 		i = p2->psinfo->pr_pctcpu - p1->psinfo->pr_pctcpu;
   1167     0  stevel 	else if (vflg)
   1168     0  stevel 		i = p2->psinfo->pr_rssize - p1->psinfo->pr_rssize;
   1169     0  stevel 	else
   1170     0  stevel 		i = p1->psinfo->pr_ttydev - p2->psinfo->pr_ttydev;
   1171     0  stevel 	if (i == 0)
   1172     0  stevel 		i = p1->psinfo->pr_pid - p2->psinfo->pr_pid;
   1173     0  stevel 	return (i);
   1174     0  stevel }
   1175     0  stevel 
   1176     0  stevel static char *
   1177     0  stevel err_string(int err)
   1178     0  stevel {
   1179     0  stevel 	static char buf[32];
   1180     0  stevel 	char *str = strerror(err);
   1181     0  stevel 
   1182     0  stevel 	if (str == NULL)
   1183     0  stevel 		(void) sprintf(str = buf, "Errno #%d", err);
   1184     0  stevel 
   1185     0  stevel 	return (str);
   1186     0  stevel }
   1187