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