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