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