xref: /illumos-gate/usr/src/cmd/ps/ucbps.c (revision dfc4fe31)
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
ucbmain(int argc,char ** argv)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 	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 	/* for each active process --- */
394e503abb7SIgor Kozhukhov 	while ((dentp = readdir(dirp)) != NULL) {
395f5c9e9f9SCasper H.S. Dik 		int	psfd;	/* file descriptor for /proc/nnnnn/psinfo */
396f5c9e9f9SCasper H.S. Dik 		int	asfd;	/* file descriptor for /proc/nnnnn/as */
397*dfc4fe31SToomas Soome 		int	n;
398f5c9e9f9SCasper H.S. Dik 
399f5c9e9f9SCasper H.S. Dik 		if (dentp->d_name[0] == '.')		/* skip . and .. */
400f5c9e9f9SCasper H.S. Dik 			continue;
401*dfc4fe31SToomas Soome 		n = snprintf(psname, sizeof (psname), "%s/%s/psinfo",
402*dfc4fe31SToomas Soome 		    procdir, dentp->d_name);
403*dfc4fe31SToomas Soome 		if (n < 0 || n >= sizeof (psname))
404*dfc4fe31SToomas Soome 			exit(1);
405*dfc4fe31SToomas Soome 
406*dfc4fe31SToomas Soome 		n = snprintf(asname, sizeof (asname), "%s/%s/as",
407*dfc4fe31SToomas Soome 		    procdir, dentp->d_name);
408*dfc4fe31SToomas Soome 		if (n < 0 || n >= sizeof (psname))
409*dfc4fe31SToomas Soome 			exit(1);
410*dfc4fe31SToomas Soome 
411f5c9e9f9SCasper H.S. Dik retry:
412f5c9e9f9SCasper H.S. Dik 		if ((psfd = open(psname, O_RDONLY)) == -1)
413f5c9e9f9SCasper H.S. Dik 			continue;
414f5c9e9f9SCasper H.S. Dik 		asfd = -1;
415f5c9e9f9SCasper H.S. Dik 		if (psargs != NULL || eflg) {
416f5c9e9f9SCasper H.S. Dik 
417f5c9e9f9SCasper H.S. Dik 			/* now we need the proc_owner privilege */
418f5c9e9f9SCasper H.S. Dik 			(void) __priv_bracket(PRIV_ON);
419f5c9e9f9SCasper H.S. Dik 
420f5c9e9f9SCasper H.S. Dik 			asfd = open(asname, O_RDONLY);
421f5c9e9f9SCasper H.S. Dik 
422f5c9e9f9SCasper H.S. Dik 			/* drop proc_owner privilege after open */
423f5c9e9f9SCasper H.S. Dik 			(void) __priv_bracket(PRIV_OFF);
424f5c9e9f9SCasper H.S. Dik 		}
425f5c9e9f9SCasper H.S. Dik 
426f5c9e9f9SCasper H.S. Dik 		/*
427f5c9e9f9SCasper H.S. Dik 		 * Get the info structure for the process
428f5c9e9f9SCasper H.S. Dik 		 */
429f5c9e9f9SCasper H.S. Dik 		if (read(psfd, &info, sizeof (info)) != sizeof (info)) {
430f5c9e9f9SCasper H.S. Dik 			int	saverr = errno;
431f5c9e9f9SCasper H.S. Dik 
432f5c9e9f9SCasper H.S. Dik 			(void) close(psfd);
433f5c9e9f9SCasper H.S. Dik 			if (asfd > 0)
434f5c9e9f9SCasper H.S. Dik 				(void) close(asfd);
435f5c9e9f9SCasper H.S. Dik 			if (saverr == EAGAIN)
436f5c9e9f9SCasper H.S. Dik 				goto retry;
437f5c9e9f9SCasper H.S. Dik 			if (saverr != ENOENT)
438f5c9e9f9SCasper H.S. Dik 				(void) fprintf(stderr, "ps: read() on %s: %s\n",
439f5c9e9f9SCasper H.S. Dik 				    psname, err_string(saverr));
440f5c9e9f9SCasper H.S. Dik 			continue;
441f5c9e9f9SCasper H.S. Dik 		}
442f5c9e9f9SCasper H.S. Dik 		(void) close(psfd);
443f5c9e9f9SCasper H.S. Dik 
444f5c9e9f9SCasper H.S. Dik 		found = 0;
445f5c9e9f9SCasper H.S. Dik 		if (info.pr_lwp.pr_state == 0)		/* can't happen? */
446f5c9e9f9SCasper H.S. Dik 			goto closeit;
447f5c9e9f9SCasper H.S. Dik 		pid = info.pr_pid;
448f5c9e9f9SCasper H.S. Dik 		ppid = info.pr_ppid;
449f5c9e9f9SCasper H.S. Dik 
450f5c9e9f9SCasper H.S. Dik 		/* Display only process from command line */
451f5c9e9f9SCasper H.S. Dik 		if (pflg) {	/* pid in arg list */
452f5c9e9f9SCasper H.S. Dik 			if (pidsave == pid)
453f5c9e9f9SCasper H.S. Dik 				found++;
454f5c9e9f9SCasper H.S. Dik 			else
455f5c9e9f9SCasper H.S. Dik 				goto closeit;
456f5c9e9f9SCasper H.S. Dik 		}
457f5c9e9f9SCasper H.S. Dik 
458f5c9e9f9SCasper H.S. Dik 		/*
459f5c9e9f9SCasper H.S. Dik 		 * Omit "uninteresting" processes unless 'g' option.
460f5c9e9f9SCasper H.S. Dik 		 */
461f5c9e9f9SCasper H.S. Dik 		if ((ppid == 1) && !(gflg))
462f5c9e9f9SCasper H.S. Dik 			goto closeit;
463f5c9e9f9SCasper H.S. Dik 
464f5c9e9f9SCasper H.S. Dik 		/*
465f5c9e9f9SCasper H.S. Dik 		 * Omit non-running processes for 'r' option
466f5c9e9f9SCasper H.S. Dik 		 */
467f5c9e9f9SCasper H.S. Dik 		if (rflg &&
468f5c9e9f9SCasper H.S. Dik 		    !(info.pr_lwp.pr_sname == 'O' ||
469f5c9e9f9SCasper H.S. Dik 		    info.pr_lwp.pr_sname == 'R'))
470f5c9e9f9SCasper H.S. Dik 			goto closeit;
471f5c9e9f9SCasper H.S. Dik 
472f5c9e9f9SCasper H.S. Dik 		if (!found && !tflg && !aflg && info.pr_euid != my_uid)
473f5c9e9f9SCasper H.S. Dik 			goto closeit;
474f5c9e9f9SCasper H.S. Dik 
475f5c9e9f9SCasper H.S. Dik 		/*
476f5c9e9f9SCasper H.S. Dik 		 * Read the args for the -w and -ww cases
477f5c9e9f9SCasper H.S. Dik 		 */
478f5c9e9f9SCasper H.S. Dik 		if (asfd > 0) {
479f5c9e9f9SCasper H.S. Dik 			if ((psargs != NULL &&
480f5c9e9f9SCasper H.S. Dik 			    preadargs(asfd, &info, psargs) == -1) ||
481f5c9e9f9SCasper H.S. Dik 			    (eflg && preadenvs(asfd, &info, psargs) == -1)) {
482f5c9e9f9SCasper H.S. Dik 				int	saverr = errno;
483f5c9e9f9SCasper H.S. Dik 
484f5c9e9f9SCasper H.S. Dik 				(void) close(asfd);
485f5c9e9f9SCasper H.S. Dik 				if (saverr == EAGAIN)
486f5c9e9f9SCasper H.S. Dik 					goto retry;
487f5c9e9f9SCasper H.S. Dik 				if (saverr != ENOENT)
488f5c9e9f9SCasper H.S. Dik 					(void) fprintf(stderr,
489f5c9e9f9SCasper H.S. Dik 					    "ps: read() on %s: %s\n",
490f5c9e9f9SCasper H.S. Dik 					    asname, err_string(saverr));
491f5c9e9f9SCasper H.S. Dik 				continue;
492f5c9e9f9SCasper H.S. Dik 			}
493f5c9e9f9SCasper H.S. Dik 		} else {
494f5c9e9f9SCasper H.S. Dik 			psargs = info.pr_psargs;
495f5c9e9f9SCasper H.S. Dik 		}
496f5c9e9f9SCasper H.S. Dik 
497f5c9e9f9SCasper H.S. Dik 		if (nent >= entsize) {
498f5c9e9f9SCasper H.S. Dik 			entsize *= 2;
499f5c9e9f9SCasper H.S. Dik 			psent = (struct psent *)realloc((char *)psent,
500f5c9e9f9SCasper H.S. Dik 			    entsize * sizeof (struct psent));
501f5c9e9f9SCasper H.S. Dik 			if (psent == NULL) {
502f5c9e9f9SCasper H.S. Dik 				(void) fprintf(stderr, "ps: no memory\n");
503f5c9e9f9SCasper H.S. Dik 				exit(1);
504f5c9e9f9SCasper H.S. Dik 			}
505f5c9e9f9SCasper H.S. Dik 		}
506f5c9e9f9SCasper H.S. Dik 		if ((psent[nent].psinfo = malloc(sizeof (psinfo_t)))
507f5c9e9f9SCasper H.S. Dik 		    == NULL) {
508f5c9e9f9SCasper H.S. Dik 			(void) fprintf(stderr, "ps: no memory\n");
509f5c9e9f9SCasper H.S. Dik 			exit(1);
510f5c9e9f9SCasper H.S. Dik 		}
511f5c9e9f9SCasper H.S. Dik 		*psent[nent].psinfo = info;
512f5c9e9f9SCasper H.S. Dik 		if (psargs == NULL)
513f5c9e9f9SCasper H.S. Dik 			psent[nent].psargs = NULL;
514f5c9e9f9SCasper H.S. Dik 		else {
515f5c9e9f9SCasper H.S. Dik 			if ((psent[nent].psargs = malloc(strlen(psargs)+1))
516f5c9e9f9SCasper H.S. Dik 			    == NULL) {
517f5c9e9f9SCasper H.S. Dik 				(void) fprintf(stderr, "ps: no memory\n");
518f5c9e9f9SCasper H.S. Dik 				exit(1);
519f5c9e9f9SCasper H.S. Dik 			}
520f5c9e9f9SCasper H.S. Dik 			(void) strcpy(psent[nent].psargs, psargs);
521f5c9e9f9SCasper H.S. Dik 		}
522f5c9e9f9SCasper H.S. Dik 		psent[nent].found = found;
523f5c9e9f9SCasper H.S. Dik 		nent++;
524f5c9e9f9SCasper H.S. Dik closeit:
525f5c9e9f9SCasper H.S. Dik 		if (asfd > 0)
526f5c9e9f9SCasper H.S. Dik 			(void) close(asfd);
527f5c9e9f9SCasper H.S. Dik 		psargs = svpsargs;
528f5c9e9f9SCasper H.S. Dik 	}
529f5c9e9f9SCasper H.S. Dik 
530f5c9e9f9SCasper H.S. Dik 	/* revert to non-privileged user */
531f5c9e9f9SCasper H.S. Dik 	(void) __priv_relinquish();
532f5c9e9f9SCasper H.S. Dik 
533f5c9e9f9SCasper H.S. Dik 	(void) closedir(dirp);
534f5c9e9f9SCasper H.S. Dik 
535f5c9e9f9SCasper H.S. Dik 	qsort((char *)psent, nent, sizeof (psent[0]), pscompare);
536f5c9e9f9SCasper H.S. Dik 
537f5c9e9f9SCasper H.S. Dik 	for (i = 0; i < nent; i++) {
538f5c9e9f9SCasper H.S. Dik 		struct psent *pp = &psent[i];
539f5c9e9f9SCasper H.S. Dik 		if (prcom(pp->found, pp->psinfo, pp->psargs)) {
540f5c9e9f9SCasper H.S. Dik 			(void) printf("\n");
541f5c9e9f9SCasper H.S. Dik 			retcode = 0;
542f5c9e9f9SCasper H.S. Dik 		}
543f5c9e9f9SCasper H.S. Dik 	}
544f5c9e9f9SCasper H.S. Dik 
545f5c9e9f9SCasper H.S. Dik 	return (retcode);
546f5c9e9f9SCasper H.S. Dik }
547f5c9e9f9SCasper H.S. Dik 
548f5c9e9f9SCasper H.S. Dik static void
usage(void)549*dfc4fe31SToomas Soome usage(void)		/* print usage message and quit */
550f5c9e9f9SCasper H.S. Dik {
551f5c9e9f9SCasper H.S. Dik 	static char usage1[] = "ps [ -aceglnrSuUvwx ] [ -t term ] [ num ]";
552f5c9e9f9SCasper H.S. Dik 
553f5c9e9f9SCasper H.S. Dik 	(void) fprintf(stderr, "usage: %s\n", usage1);
554f5c9e9f9SCasper H.S. Dik 	exit(1);
555f5c9e9f9SCasper H.S. Dik }
556f5c9e9f9SCasper H.S. Dik 
557f5c9e9f9SCasper H.S. Dik /*
558f5c9e9f9SCasper H.S. Dik  * Read the process arguments from the process.
559f5c9e9f9SCasper H.S. Dik  * This allows >PRARGSZ characters of arguments to be displayed but,
560f5c9e9f9SCasper H.S. Dik  * unlike pr_psargs[], the process may have changed them.
561f5c9e9f9SCasper H.S. Dik  */
562f5c9e9f9SCasper H.S. Dik #define	NARG	100
563f5c9e9f9SCasper H.S. Dik static int
preadargs(int pfd,psinfo_t * psinfo,char * psargs)564f5c9e9f9SCasper H.S. Dik preadargs(int pfd, psinfo_t *psinfo, char *psargs)
565f5c9e9f9SCasper H.S. Dik {
566f5c9e9f9SCasper H.S. Dik 	off_t argvoff = (off_t)psinfo->pr_argv;
567f5c9e9f9SCasper H.S. Dik 	size_t len;
568f5c9e9f9SCasper H.S. Dik 	char *psa = psargs;
569f5c9e9f9SCasper H.S. Dik 	int bsize = twidth;
570f5c9e9f9SCasper H.S. Dik 	int narg = NARG;
571f5c9e9f9SCasper H.S. Dik 	off_t argv[NARG];
572f5c9e9f9SCasper H.S. Dik 	off_t argoff;
573f5c9e9f9SCasper H.S. Dik 	off_t nextargoff;
574f5c9e9f9SCasper H.S. Dik 	int i;
575f5c9e9f9SCasper H.S. Dik #ifdef _LP64
576f5c9e9f9SCasper H.S. Dik 	caddr32_t argv32[NARG];
577f5c9e9f9SCasper H.S. Dik 	int is32 = (psinfo->pr_dmodel != PR_MODEL_LP64);
578f5c9e9f9SCasper H.S. Dik #endif
579f5c9e9f9SCasper H.S. Dik 
580f5c9e9f9SCasper H.S. Dik 	if (psinfo->pr_nlwp == 0 ||
581f5c9e9f9SCasper H.S. Dik 	    strcmp(psinfo->pr_lwp.pr_clname, "SYS") == 0)
582f5c9e9f9SCasper H.S. Dik 		goto out;
583f5c9e9f9SCasper H.S. Dik 
584f5c9e9f9SCasper H.S. Dik 	(void) memset(psa, 0, bsize--);
585f5c9e9f9SCasper H.S. Dik 	nextargoff = 0;
586f5c9e9f9SCasper H.S. Dik 	errno = EIO;
587f5c9e9f9SCasper H.S. Dik 	while (bsize > 0) {
588f5c9e9f9SCasper H.S. Dik 		if (narg == NARG) {
589f5c9e9f9SCasper H.S. Dik 			(void) memset(argv, 0, sizeof (argv));
590f5c9e9f9SCasper H.S. Dik #ifdef _LP64
591f5c9e9f9SCasper H.S. Dik 			if (is32) {
592f5c9e9f9SCasper H.S. Dik 				if ((i = pread(pfd, argv32, sizeof (argv32),
593f5c9e9f9SCasper H.S. Dik 				    argvoff)) <= 0) {
594f5c9e9f9SCasper H.S. Dik 					if (i == 0 || errno == EIO)
595f5c9e9f9SCasper H.S. Dik 						break;
596f5c9e9f9SCasper H.S. Dik 					return (-1);
597f5c9e9f9SCasper H.S. Dik 				}
598f5c9e9f9SCasper H.S. Dik 				for (i = 0; i < NARG; i++)
599f5c9e9f9SCasper H.S. Dik 					argv[i] = argv32[i];
600f5c9e9f9SCasper H.S. Dik 			} else
601f5c9e9f9SCasper H.S. Dik #endif
602f5c9e9f9SCasper H.S. Dik 				if ((i = pread(pfd, argv, sizeof (argv),
603f5c9e9f9SCasper H.S. Dik 				    argvoff)) <= 0) {
604f5c9e9f9SCasper H.S. Dik 					if (i == 0 || errno == EIO)
605f5c9e9f9SCasper H.S. Dik 						break;
606f5c9e9f9SCasper H.S. Dik 					return (-1);
607f5c9e9f9SCasper H.S. Dik 				}
608f5c9e9f9SCasper H.S. Dik 			narg = 0;
609f5c9e9f9SCasper H.S. Dik 		}
610f5c9e9f9SCasper H.S. Dik 		if ((argoff = argv[narg++]) == 0)
611f5c9e9f9SCasper H.S. Dik 			break;
612f5c9e9f9SCasper H.S. Dik 		if (argoff != nextargoff &&
613f5c9e9f9SCasper H.S. Dik 		    (i = pread(pfd, psa, bsize, argoff)) <= 0) {
614f5c9e9f9SCasper H.S. Dik 			if (i == 0 || errno == EIO)
615f5c9e9f9SCasper H.S. Dik 				break;
616f5c9e9f9SCasper H.S. Dik 			return (-1);
617f5c9e9f9SCasper H.S. Dik 		}
618f5c9e9f9SCasper H.S. Dik 		len = strlen(psa);
619f5c9e9f9SCasper H.S. Dik 		psa += len;
620f5c9e9f9SCasper H.S. Dik 		*psa++ = ' ';
621f5c9e9f9SCasper H.S. Dik 		bsize -= len + 1;
622f5c9e9f9SCasper H.S. Dik 		nextargoff = argoff + len + 1;
623f5c9e9f9SCasper H.S. Dik #ifdef _LP64
624f5c9e9f9SCasper H.S. Dik 		argvoff += is32? sizeof (caddr32_t) : sizeof (caddr_t);
625f5c9e9f9SCasper H.S. Dik #else
626f5c9e9f9SCasper H.S. Dik 		argvoff += sizeof (caddr_t);
627f5c9e9f9SCasper H.S. Dik #endif
628f5c9e9f9SCasper H.S. Dik 	}
629f5c9e9f9SCasper H.S. Dik 	while (psa > psargs && isspace(*(psa-1)))
630f5c9e9f9SCasper H.S. Dik 		psa--;
631f5c9e9f9SCasper H.S. Dik 
632f5c9e9f9SCasper H.S. Dik out:
633f5c9e9f9SCasper H.S. Dik 	*psa = '\0';
634f5c9e9f9SCasper H.S. Dik 	if (strlen(psinfo->pr_psargs) > strlen(psargs))
635f5c9e9f9SCasper H.S. Dik 		(void) strcpy(psargs, psinfo->pr_psargs);
636f5c9e9f9SCasper H.S. Dik 
637f5c9e9f9SCasper H.S. Dik 	return (0);
638f5c9e9f9SCasper H.S. Dik }
639f5c9e9f9SCasper H.S. Dik 
640f5c9e9f9SCasper H.S. Dik /*
641f5c9e9f9SCasper H.S. Dik  * Read environment variables from the process.
642f5c9e9f9SCasper H.S. Dik  * Append them to psargs if there is room.
643f5c9e9f9SCasper H.S. Dik  */
644f5c9e9f9SCasper H.S. Dik static int
preadenvs(int pfd,psinfo_t * psinfo,char * psargs)645f5c9e9f9SCasper H.S. Dik preadenvs(int pfd, psinfo_t *psinfo, char *psargs)
646f5c9e9f9SCasper H.S. Dik {
647f5c9e9f9SCasper H.S. Dik 	off_t envpoff = (off_t)psinfo->pr_envp;
648f5c9e9f9SCasper H.S. Dik 	int len;
649f5c9e9f9SCasper H.S. Dik 	char *psa;
650f5c9e9f9SCasper H.S. Dik 	char *psainit;
651f5c9e9f9SCasper H.S. Dik 	int bsize;
652f5c9e9f9SCasper H.S. Dik 	int nenv = NARG;
653f5c9e9f9SCasper H.S. Dik 	off_t envp[NARG];
654f5c9e9f9SCasper H.S. Dik 	off_t envoff;
655f5c9e9f9SCasper H.S. Dik 	off_t nextenvoff;
656f5c9e9f9SCasper H.S. Dik 	int i;
657f5c9e9f9SCasper H.S. Dik #ifdef _LP64
658f5c9e9f9SCasper H.S. Dik 	caddr32_t envp32[NARG];
659f5c9e9f9SCasper H.S. Dik 	int is32 = (psinfo->pr_dmodel != PR_MODEL_LP64);
660f5c9e9f9SCasper H.S. Dik #endif
661f5c9e9f9SCasper H.S. Dik 
662f5c9e9f9SCasper H.S. Dik 	psainit = psa = (psargs != NULL)? psargs : psinfo->pr_psargs;
663f5c9e9f9SCasper H.S. Dik 	len = strlen(psa);
664f5c9e9f9SCasper H.S. Dik 	psa += len;
665f5c9e9f9SCasper H.S. Dik 	bsize = twidth - len - 1;
666f5c9e9f9SCasper H.S. Dik 
667f5c9e9f9SCasper H.S. Dik 	if (bsize <= 0 || psinfo->pr_nlwp == 0 ||
668f5c9e9f9SCasper H.S. Dik 	    strcmp(psinfo->pr_lwp.pr_clname, "SYS") == 0)
669f5c9e9f9SCasper H.S. Dik 		return (0);
670f5c9e9f9SCasper H.S. Dik 
671f5c9e9f9SCasper H.S. Dik 	nextenvoff = 0;
672f5c9e9f9SCasper H.S. Dik 	errno = EIO;
673f5c9e9f9SCasper H.S. Dik 	while (bsize > 0) {
674f5c9e9f9SCasper H.S. Dik 		if (nenv == NARG) {
675f5c9e9f9SCasper H.S. Dik 			(void) memset(envp, 0, sizeof (envp));
676f5c9e9f9SCasper H.S. Dik #ifdef _LP64
677f5c9e9f9SCasper H.S. Dik 			if (is32) {
678f5c9e9f9SCasper H.S. Dik 				if ((i = pread(pfd, envp32, sizeof (envp32),
679f5c9e9f9SCasper H.S. Dik 				    envpoff)) <= 0) {
680f5c9e9f9SCasper H.S. Dik 					if (i == 0 || errno == EIO)
681f5c9e9f9SCasper H.S. Dik 						break;
682f5c9e9f9SCasper H.S. Dik 					return (-1);
683f5c9e9f9SCasper H.S. Dik 				}
684f5c9e9f9SCasper H.S. Dik 				for (i = 0; i < NARG; i++)
685f5c9e9f9SCasper H.S. Dik 					envp[i] = envp32[i];
686f5c9e9f9SCasper H.S. Dik 			} else
687f5c9e9f9SCasper H.S. Dik #endif
688f5c9e9f9SCasper H.S. Dik 				if ((i = pread(pfd, envp, sizeof (envp),
689f5c9e9f9SCasper H.S. Dik 				    envpoff)) <= 0) {
690f5c9e9f9SCasper H.S. Dik 					if (i == 0 || errno == EIO)
691f5c9e9f9SCasper H.S. Dik 						break;
692f5c9e9f9SCasper H.S. Dik 					return (-1);
693f5c9e9f9SCasper H.S. Dik 				}
694f5c9e9f9SCasper H.S. Dik 			nenv = 0;
695f5c9e9f9SCasper H.S. Dik 		}
696f5c9e9f9SCasper H.S. Dik 		if ((envoff = envp[nenv++]) == 0)
697f5c9e9f9SCasper H.S. Dik 			break;
698f5c9e9f9SCasper H.S. Dik 		if (envoff != nextenvoff &&
699f5c9e9f9SCasper H.S. Dik 		    (i = pread(pfd, psa+1, bsize, envoff)) <= 0) {
700f5c9e9f9SCasper H.S. Dik 			if (i == 0 || errno == EIO)
701f5c9e9f9SCasper H.S. Dik 				break;
702f5c9e9f9SCasper H.S. Dik 			return (-1);
703f5c9e9f9SCasper H.S. Dik 		}
704f5c9e9f9SCasper H.S. Dik 		*psa++ = ' ';
705f5c9e9f9SCasper H.S. Dik 		len = strlen(psa);
706f5c9e9f9SCasper H.S. Dik 		psa += len;
707f5c9e9f9SCasper H.S. Dik 		bsize -= len + 1;
708f5c9e9f9SCasper H.S. Dik 		nextenvoff = envoff + len + 1;
709f5c9e9f9SCasper H.S. Dik #ifdef _LP64
710f5c9e9f9SCasper H.S. Dik 		envpoff += is32? sizeof (caddr32_t) : sizeof (caddr_t);
711f5c9e9f9SCasper H.S. Dik #else
712f5c9e9f9SCasper H.S. Dik 		envpoff += sizeof (caddr_t);
713f5c9e9f9SCasper H.S. Dik #endif
714f5c9e9f9SCasper H.S. Dik 	}
715f5c9e9f9SCasper H.S. Dik 	while (psa > psainit && isspace(*(psa-1)))
716f5c9e9f9SCasper H.S. Dik 		psa--;
717f5c9e9f9SCasper H.S. Dik 	*psa = '\0';
718f5c9e9f9SCasper H.S. Dik 
719f5c9e9f9SCasper H.S. Dik 	return (0);
720f5c9e9f9SCasper H.S. Dik }
721f5c9e9f9SCasper H.S. Dik 
722f5c9e9f9SCasper H.S. Dik /*
723f5c9e9f9SCasper H.S. Dik  * getarg() finds the next argument in list and copies arg into argbuf.
724f5c9e9f9SCasper H.S. Dik  * p1 first pts to arg passed back from getopt routine.  p1 is then
725f5c9e9f9SCasper H.S. Dik  * bumped to next character that is not a comma or blank -- p1 NULL
726f5c9e9f9SCasper H.S. Dik  * indicates end of list.
727f5c9e9f9SCasper H.S. Dik  */
728f5c9e9f9SCasper H.S. Dik 
729f5c9e9f9SCasper H.S. Dik static void
getarg()730f5c9e9f9SCasper H.S. Dik getarg()
731f5c9e9f9SCasper H.S. Dik {
732f5c9e9f9SCasper H.S. Dik 	char	*parga;
733f5c9e9f9SCasper H.S. Dik 	int c;
734f5c9e9f9SCasper H.S. Dik 
735f5c9e9f9SCasper H.S. Dik 	while ((c = *p1) != '\0' && (c == ',' || isspace(c)))
736f5c9e9f9SCasper H.S. Dik 		p1++;
737f5c9e9f9SCasper H.S. Dik 
738f5c9e9f9SCasper H.S. Dik 	parga = argbuf;
739f5c9e9f9SCasper H.S. Dik 	while ((c = *p1) != '\0' && c != ',' && !isspace(c)) {
740f5c9e9f9SCasper H.S. Dik 		if (parga < argbuf + ARGSIZ - 1)
741f5c9e9f9SCasper H.S. Dik 			*parga++ = c;
742f5c9e9f9SCasper H.S. Dik 		p1++;
743f5c9e9f9SCasper H.S. Dik 	}
744f5c9e9f9SCasper H.S. Dik 	*parga = '\0';
745f5c9e9f9SCasper H.S. Dik 
746f5c9e9f9SCasper H.S. Dik 	while ((c = *p1) != '\0' && (c == ',' || isspace(c)))
747f5c9e9f9SCasper H.S. Dik 		p1++;
748f5c9e9f9SCasper H.S. Dik }
749f5c9e9f9SCasper H.S. Dik 
750f5c9e9f9SCasper H.S. Dik static char *
devlookup(dev_t ddev)751f5c9e9f9SCasper H.S. Dik devlookup(dev_t ddev)
752f5c9e9f9SCasper H.S. Dik {
753f5c9e9f9SCasper H.S. Dik 	struct devl *dp;
754f5c9e9f9SCasper H.S. Dik 	int i;
755f5c9e9f9SCasper H.S. Dik 
756f5c9e9f9SCasper H.S. Dik 	for (dp = devl, i = 0; i < ndev; dp++, i++) {
757f5c9e9f9SCasper H.S. Dik 		if (dp->ddev == ddev)
758f5c9e9f9SCasper H.S. Dik 			return (dp->dname);
759f5c9e9f9SCasper H.S. Dik 	}
760f5c9e9f9SCasper H.S. Dik 	return (NULL);
761f5c9e9f9SCasper H.S. Dik }
762f5c9e9f9SCasper H.S. Dik 
763f5c9e9f9SCasper H.S. Dik static char *
devadd(char * name,dev_t ddev)764f5c9e9f9SCasper H.S. Dik devadd(char *name, dev_t ddev)
765f5c9e9f9SCasper H.S. Dik {
766f5c9e9f9SCasper H.S. Dik 	struct devl *dp;
767f5c9e9f9SCasper H.S. Dik 	int leng, start, i;
768f5c9e9f9SCasper H.S. Dik 
769f5c9e9f9SCasper H.S. Dik 	if (ndev == maxdev) {
770f5c9e9f9SCasper H.S. Dik 		maxdev += DNINCR;
771f5c9e9f9SCasper H.S. Dik 		devl = realloc(devl, maxdev * sizeof (struct devl));
772f5c9e9f9SCasper H.S. Dik 		if (devl == NULL) {
773f5c9e9f9SCasper H.S. Dik 			(void) fprintf(stderr,
774f5c9e9f9SCasper H.S. Dik 			    "ps: not enough memory for %d devices\n", maxdev);
775f5c9e9f9SCasper H.S. Dik 			exit(1);
776f5c9e9f9SCasper H.S. Dik 		}
777f5c9e9f9SCasper H.S. Dik 	}
778f5c9e9f9SCasper H.S. Dik 	dp = &devl[ndev++];
779f5c9e9f9SCasper H.S. Dik 
780f5c9e9f9SCasper H.S. Dik 	dp->ddev = ddev;
781f5c9e9f9SCasper H.S. Dik 	if (name == NULL) {
782f5c9e9f9SCasper H.S. Dik 		(void) strcpy(dp->dname, "??");
783f5c9e9f9SCasper H.S. Dik 		return (dp->dname);
784f5c9e9f9SCasper H.S. Dik 	}
785f5c9e9f9SCasper H.S. Dik 
786f5c9e9f9SCasper H.S. Dik 	leng = strlen(name);
787f5c9e9f9SCasper H.S. Dik 	/* Strip off /dev/ */
788f5c9e9f9SCasper H.S. Dik 	if (leng < DNSIZE + 4)
789f5c9e9f9SCasper H.S. Dik 		(void) strcpy(dp->dname, &name[5]);
790f5c9e9f9SCasper H.S. Dik 	else {
791f5c9e9f9SCasper H.S. Dik 		start = leng - (DNSIZE - 1);
792f5c9e9f9SCasper H.S. Dik 
793f5c9e9f9SCasper H.S. Dik 		for (i = start; i < leng && name[i] != '/'; i++)
794f5c9e9f9SCasper H.S. Dik 				;
795f5c9e9f9SCasper H.S. Dik 		if (i == leng)
796f5c9e9f9SCasper H.S. Dik 			(void) strlcpy(dp->dname, &name[start], DNSIZE);
797f5c9e9f9SCasper H.S. Dik 		else
798f5c9e9f9SCasper H.S. Dik 			(void) strlcpy(dp->dname, &name[i+1], DNSIZE);
799f5c9e9f9SCasper H.S. Dik 	}
800f5c9e9f9SCasper H.S. Dik 	return (dp->dname);
801f5c9e9f9SCasper H.S. Dik }
802f5c9e9f9SCasper H.S. Dik 
803f5c9e9f9SCasper H.S. Dik /*
804f5c9e9f9SCasper H.S. Dik  * gettty returns the user's tty number or ? if none.
805f5c9e9f9SCasper H.S. Dik  */
806f5c9e9f9SCasper H.S. Dik static char *
gettty(psinfo_t * psinfo)807f5c9e9f9SCasper H.S. Dik gettty(psinfo_t *psinfo)
808f5c9e9f9SCasper H.S. Dik {
809f5c9e9f9SCasper H.S. Dik 	extern char *_ttyname_dev(dev_t, char *, size_t);
810fba40a47SBryan Cantrill 	static zoneid_t zid = -1;
811f5c9e9f9SCasper H.S. Dik 	char devname[TTYNAME_MAX];
812f5c9e9f9SCasper H.S. Dik 	char *retval;
813f5c9e9f9SCasper H.S. Dik 
814fba40a47SBryan Cantrill 	if (zid == -1)
815fba40a47SBryan Cantrill 		zid = getzoneid();
816fba40a47SBryan Cantrill 
817fba40a47SBryan Cantrill 	if (psinfo->pr_ttydev == PRNODEV || psinfo->pr_zoneid != zid)
818f5c9e9f9SCasper H.S. Dik 		return ("?");
819f5c9e9f9SCasper H.S. Dik 
820f5c9e9f9SCasper H.S. Dik 	if ((retval = devlookup(psinfo->pr_ttydev)) != NULL)
821f5c9e9f9SCasper H.S. Dik 		return (retval);
822f5c9e9f9SCasper H.S. Dik 
823f5c9e9f9SCasper H.S. Dik 	retval = _ttyname_dev(psinfo->pr_ttydev, devname, sizeof (devname));
824f5c9e9f9SCasper H.S. Dik 
825f5c9e9f9SCasper H.S. Dik 	return (devadd(retval, psinfo->pr_ttydev));
826f5c9e9f9SCasper H.S. Dik }
827f5c9e9f9SCasper H.S. Dik 
828f5c9e9f9SCasper H.S. Dik /*
829f5c9e9f9SCasper H.S. Dik  * Print percent from 16-bit binary fraction [0 .. 1]
830f5c9e9f9SCasper H.S. Dik  * Round up .01 to .1 to indicate some small percentage (the 0x7000 below).
831f5c9e9f9SCasper H.S. Dik  */
832f5c9e9f9SCasper H.S. Dik static void
prtpct(ushort_t pct)833f5c9e9f9SCasper H.S. Dik prtpct(ushort_t pct)
834f5c9e9f9SCasper H.S. Dik {
835f5c9e9f9SCasper H.S. Dik 	uint_t value = pct;	/* need 32 bits to compute with */
836f5c9e9f9SCasper H.S. Dik 
837f5c9e9f9SCasper H.S. Dik 	value = ((value * 1000) + 0x7000) >> 15;	/* [0 .. 1000] */
838f5c9e9f9SCasper H.S. Dik 	(void) printf("%3u.%u", value / 10, value % 10);
839f5c9e9f9SCasper H.S. Dik }
840f5c9e9f9SCasper H.S. Dik 
841f5c9e9f9SCasper H.S. Dik /*
842f5c9e9f9SCasper H.S. Dik  * Print info about the process.
843f5c9e9f9SCasper H.S. Dik  */
844f5c9e9f9SCasper H.S. Dik static int
prcom(int found,psinfo_t * psinfo,char * psargs)845f5c9e9f9SCasper H.S. Dik prcom(int found, psinfo_t *psinfo, char *psargs)
846f5c9e9f9SCasper H.S. Dik {
847f5c9e9f9SCasper H.S. Dik 	char	*cp;
848f5c9e9f9SCasper H.S. Dik 	char	*tp;
849f5c9e9f9SCasper H.S. Dik 	char	*psa;
850f5c9e9f9SCasper H.S. Dik 	long	tm;
851f5c9e9f9SCasper H.S. Dik 	int	i, wcnt, length;
852f5c9e9f9SCasper H.S. Dik 	wchar_t	wchar;
853f5c9e9f9SCasper H.S. Dik 	struct tty *ttyp;
854f5c9e9f9SCasper H.S. Dik 
855f5c9e9f9SCasper H.S. Dik 	/*
856f5c9e9f9SCasper H.S. Dik 	 * If process is zombie, call print routine and return.
857f5c9e9f9SCasper H.S. Dik 	 */
858f5c9e9f9SCasper H.S. Dik 	if (psinfo->pr_nlwp == 0) {
859f5c9e9f9SCasper H.S. Dik 		if (tflg && !found)
860f5c9e9f9SCasper H.S. Dik 			return (0);
861f5c9e9f9SCasper H.S. Dik 		else {
862f5c9e9f9SCasper H.S. Dik 			przom(psinfo);
863f5c9e9f9SCasper H.S. Dik 			return (1);
864f5c9e9f9SCasper H.S. Dik 		}
865f5c9e9f9SCasper H.S. Dik 	}
866f5c9e9f9SCasper H.S. Dik 
867f5c9e9f9SCasper H.S. Dik 	/*
868f5c9e9f9SCasper H.S. Dik 	 * Get current terminal.  If none ("?") and 'a' is set, don't print
869f5c9e9f9SCasper H.S. Dik 	 * info.  If 't' is set, check if term is in list of desired terminals
870f5c9e9f9SCasper H.S. Dik 	 * and print it if it is.
871f5c9e9f9SCasper H.S. Dik 	 */
872f5c9e9f9SCasper H.S. Dik 	i = 0;
873f5c9e9f9SCasper H.S. Dik 	tp = gettty(psinfo);
874f5c9e9f9SCasper H.S. Dik 
875f5c9e9f9SCasper H.S. Dik 	if (*tp == '?' && !found && !xflg)
876f5c9e9f9SCasper H.S. Dik 		return (0);
877f5c9e9f9SCasper H.S. Dik 
878f5c9e9f9SCasper H.S. Dik 	if (!(*tp == '?' && aflg) && tflg && !found) {
879f5c9e9f9SCasper H.S. Dik 		int match = 0;
880f5c9e9f9SCasper H.S. Dik 		char *other = NULL;
881f5c9e9f9SCasper H.S. Dik 		for (ttyp = tty; ttyp->tname != NULL; ttyp++) {
882f5c9e9f9SCasper H.S. Dik 			/*
883f5c9e9f9SCasper H.S. Dik 			 * Look for a name match
884f5c9e9f9SCasper H.S. Dik 			 */
885f5c9e9f9SCasper H.S. Dik 			if (strcmp(tp, ttyp->tname) == 0) {
886f5c9e9f9SCasper H.S. Dik 				match = 1;
887f5c9e9f9SCasper H.S. Dik 				break;
888f5c9e9f9SCasper H.S. Dik 			}
889f5c9e9f9SCasper H.S. Dik 			/*
890f5c9e9f9SCasper H.S. Dik 			 * Look for same device under different names.
891f5c9e9f9SCasper H.S. Dik 			 */
892f5c9e9f9SCasper H.S. Dik 			if ((other == NULL) &&
893f5c9e9f9SCasper H.S. Dik 			    (psinfo->pr_ttydev == ttyp->tdev))
894f5c9e9f9SCasper H.S. Dik 				other = ttyp->tname;
895f5c9e9f9SCasper H.S. Dik 		}
896f5c9e9f9SCasper H.S. Dik 		if (!match) {
897f5c9e9f9SCasper H.S. Dik 			if (other == NULL)
898f5c9e9f9SCasper H.S. Dik 				return (0);
899f5c9e9f9SCasper H.S. Dik 			tp = other;
900f5c9e9f9SCasper H.S. Dik 		}
901f5c9e9f9SCasper H.S. Dik 	}
902f5c9e9f9SCasper H.S. Dik 
903f5c9e9f9SCasper H.S. Dik 	if (lflg)
904f5c9e9f9SCasper H.S. Dik 		(void) printf("%2x", psinfo->pr_flag & 0377);
905f5c9e9f9SCasper H.S. Dik 	if (uflg) {
906f5c9e9f9SCasper H.S. Dik 		if (!nflg) {
907f5c9e9f9SCasper H.S. Dik 			struct passwd *pwd;
908f5c9e9f9SCasper H.S. Dik 
909f5c9e9f9SCasper H.S. Dik 			if ((pwd = getpwuid(psinfo->pr_euid)) != NULL)
910f5c9e9f9SCasper H.S. Dik 								/* USER */
911f5c9e9f9SCasper H.S. Dik 				(void) printf("%-8.8s", pwd->pw_name);
912f5c9e9f9SCasper H.S. Dik 			else
913f5c9e9f9SCasper H.S. Dik 								/* UID */
914f5c9e9f9SCasper H.S. Dik 				(void) printf(" %7.7d", (int)psinfo->pr_euid);
915f5c9e9f9SCasper H.S. Dik 		} else {
916f5c9e9f9SCasper H.S. Dik 			(void) printf(" %5d", (int)psinfo->pr_euid); /* UID */
917f5c9e9f9SCasper H.S. Dik 		}
918f5c9e9f9SCasper H.S. Dik 	} else if (lflg)
919f5c9e9f9SCasper H.S. Dik 		(void) printf(" %5d", (int)psinfo->pr_euid);	/* UID */
920f5c9e9f9SCasper H.S. Dik 
921f5c9e9f9SCasper H.S. Dik 	(void) printf("%*d", pidwidth + 1, (int)psinfo->pr_pid); /* PID */
922f5c9e9f9SCasper H.S. Dik 	if (lflg)
923f5c9e9f9SCasper H.S. Dik 		(void) printf("%*d", pidwidth + 1,
924f5c9e9f9SCasper H.S. Dik 		    (int)psinfo->pr_ppid); /* PPID */
925f5c9e9f9SCasper H.S. Dik 	if (lflg)
926f5c9e9f9SCasper H.S. Dik 		(void) printf("%3d", psinfo->pr_lwp.pr_cpu & 0377); /* CP */
927f5c9e9f9SCasper H.S. Dik 	if (uflg) {
928f5c9e9f9SCasper H.S. Dik 		prtpct(psinfo->pr_pctcpu);			/* %CPU */
929f5c9e9f9SCasper H.S. Dik 		prtpct(psinfo->pr_pctmem);			/* %MEM */
930f5c9e9f9SCasper H.S. Dik 	}
931f5c9e9f9SCasper H.S. Dik 	if (lflg) {
932f5c9e9f9SCasper H.S. Dik 		(void) printf("%4d", psinfo->pr_lwp.pr_pri);	/* PRI */
933f5c9e9f9SCasper H.S. Dik 		(void) printf("%3d", psinfo->pr_lwp.pr_nice);	/* NICE */
934f5c9e9f9SCasper H.S. Dik 	}
935f5c9e9f9SCasper H.S. Dik 	if (lflg || uflg) {
936f5c9e9f9SCasper H.S. Dik 		if (psinfo->pr_flag & SSYS)			/* SZ */
937f5c9e9f9SCasper H.S. Dik 			(void) printf("    0");
938f5c9e9f9SCasper H.S. Dik 		else if (psinfo->pr_size)
939096b2378SJerry Jelinek 			(void) printf(" %4lu", (ulong_t)psinfo->pr_size);
940f5c9e9f9SCasper H.S. Dik 		else
941f5c9e9f9SCasper H.S. Dik 			(void) printf("    ?");
942f5c9e9f9SCasper H.S. Dik 		if (psinfo->pr_flag & SSYS)			/* RSS */
943f5c9e9f9SCasper H.S. Dik 			(void) printf("    0");
944f5c9e9f9SCasper H.S. Dik 		else if (psinfo->pr_rssize)
945096b2378SJerry Jelinek 			(void) printf(" %4lu", (ulong_t)psinfo->pr_rssize);
946f5c9e9f9SCasper H.S. Dik 		else
947f5c9e9f9SCasper H.S. Dik 			(void) printf("    ?");
948f5c9e9f9SCasper H.S. Dik 	}
949f5c9e9f9SCasper H.S. Dik 	if (lflg) {						/* WCHAN */
950f5c9e9f9SCasper H.S. Dik 		if (psinfo->pr_lwp.pr_sname != 'S') {
951f5c9e9f9SCasper H.S. Dik 			(void) printf("         ");
952f5c9e9f9SCasper H.S. Dik 		} else if (psinfo->pr_lwp.pr_wchan) {
953f5c9e9f9SCasper H.S. Dik 			(void) printf(" %+8.8lx",
954f5c9e9f9SCasper H.S. Dik 			    (ulong_t)psinfo->pr_lwp.pr_wchan);
955f5c9e9f9SCasper H.S. Dik 		} else {
956f5c9e9f9SCasper H.S. Dik 			(void) printf("        ?");
957f5c9e9f9SCasper H.S. Dik 		}
958f5c9e9f9SCasper H.S. Dik 	}
959f5c9e9f9SCasper H.S. Dik 	if ((tplen = strlen(tp)) > 9)
960f5c9e9f9SCasper H.S. Dik 		maxlen = twidth - tplen + 9;
961f5c9e9f9SCasper H.S. Dik 	else
962f5c9e9f9SCasper H.S. Dik 		maxlen = twidth;
963f5c9e9f9SCasper H.S. Dik 
964f5c9e9f9SCasper H.S. Dik 	if (!lflg)
965f5c9e9f9SCasper H.S. Dik 		(void) printf(" %-8.14s", tp);			/* TTY */
966f5c9e9f9SCasper H.S. Dik 	(void) printf(" %c", psinfo->pr_lwp.pr_sname);		/* STATE */
967f5c9e9f9SCasper H.S. Dik 	if (lflg)
968f5c9e9f9SCasper H.S. Dik 		(void) printf(" %-8.14s", tp);			/* TTY */
969f5c9e9f9SCasper H.S. Dik 	if (uflg)
970f5c9e9f9SCasper H.S. Dik 		prtime(psinfo->pr_start);			/* START */
971f5c9e9f9SCasper H.S. Dik 
972f5c9e9f9SCasper H.S. Dik 	/* time just for process */
973f5c9e9f9SCasper H.S. Dik 	tm = psinfo->pr_time.tv_sec;
974f5c9e9f9SCasper H.S. Dik 	if (Sflg) {	/* calculate time for process and all reaped children */
975f5c9e9f9SCasper H.S. Dik 		tm += psinfo->pr_ctime.tv_sec;
976f5c9e9f9SCasper H.S. Dik 		if (psinfo->pr_time.tv_nsec + psinfo->pr_ctime.tv_nsec
977f5c9e9f9SCasper H.S. Dik 		    >= 1000000000)
978f5c9e9f9SCasper H.S. Dik 			tm += 1;
979f5c9e9f9SCasper H.S. Dik 	}
980f5c9e9f9SCasper H.S. Dik 
981f5c9e9f9SCasper H.S. Dik 	(void) printf(" %2ld:%.2ld", tm / 60, tm % 60);		/* TIME */
982f5c9e9f9SCasper H.S. Dik 
983f5c9e9f9SCasper H.S. Dik 	if (vflg) {
984f5c9e9f9SCasper H.S. Dik 		if (psinfo->pr_flag & SSYS)			/* SZ */
985f5c9e9f9SCasper H.S. Dik 			(void) printf("    0");
986f5c9e9f9SCasper H.S. Dik 		else if (psinfo->pr_size)
987f5c9e9f9SCasper H.S. Dik 			(void) printf("%5lu", (ulong_t)psinfo->pr_size);
988f5c9e9f9SCasper H.S. Dik 		else
989f5c9e9f9SCasper H.S. Dik 			(void) printf("    ?");
990f5c9e9f9SCasper H.S. Dik 		if (psinfo->pr_flag & SSYS)			/* SZ */
991f5c9e9f9SCasper H.S. Dik 			(void) printf("    0");
992f5c9e9f9SCasper H.S. Dik 		else if (psinfo->pr_rssize)
993f5c9e9f9SCasper H.S. Dik 			(void) printf("%5lu", (ulong_t)psinfo->pr_rssize);
994f5c9e9f9SCasper H.S. Dik 		else
995f5c9e9f9SCasper H.S. Dik 			(void) printf("    ?");
996f5c9e9f9SCasper H.S. Dik 		prtpct(psinfo->pr_pctcpu);			/* %CPU */
997f5c9e9f9SCasper H.S. Dik 		prtpct(psinfo->pr_pctmem);			/* %MEM */
998f5c9e9f9SCasper H.S. Dik 	}
999f5c9e9f9SCasper H.S. Dik 	if (cflg) {						/* CMD */
1000f5c9e9f9SCasper H.S. Dik 		wcnt = namencnt(psinfo->pr_fname, 16, maxlen);
1001f5c9e9f9SCasper H.S. Dik 		(void) printf(" %.*s", wcnt, psinfo->pr_fname);
1002f5c9e9f9SCasper H.S. Dik 		return (1);
1003f5c9e9f9SCasper H.S. Dik 	}
1004f5c9e9f9SCasper H.S. Dik 	/*
1005f5c9e9f9SCasper H.S. Dik 	 * PRARGSZ == length of cmd arg string.
1006f5c9e9f9SCasper H.S. Dik 	 */
1007f5c9e9f9SCasper H.S. Dik 	if (psargs == NULL) {
1008f5c9e9f9SCasper H.S. Dik 		psa = &psinfo->pr_psargs[0];
1009f5c9e9f9SCasper H.S. Dik 		i = PRARGSZ;
1010f5c9e9f9SCasper H.S. Dik 		tp = &psinfo->pr_psargs[PRARGSZ];
1011f5c9e9f9SCasper H.S. Dik 	} else {
1012f5c9e9f9SCasper H.S. Dik 		psa = psargs;
1013f5c9e9f9SCasper H.S. Dik 		i = strlen(psargs);
1014f5c9e9f9SCasper H.S. Dik 		tp = psa + i;
1015f5c9e9f9SCasper H.S. Dik 	}
1016f5c9e9f9SCasper H.S. Dik 
1017f5c9e9f9SCasper H.S. Dik 	for (cp = psa; cp < tp; /* empty */) {
1018f5c9e9f9SCasper H.S. Dik 		if (*cp == 0)
1019f5c9e9f9SCasper H.S. Dik 			break;
1020f5c9e9f9SCasper H.S. Dik 		length = mbtowc(&wchar, cp, MB_LEN_MAX);
1021f5c9e9f9SCasper H.S. Dik 		if (length < 0 || !iswprint(wchar)) {
1022f5c9e9f9SCasper H.S. Dik 			(void) printf(" [ %.16s ]", psinfo->pr_fname);
1023f5c9e9f9SCasper H.S. Dik 			return (1);
1024f5c9e9f9SCasper H.S. Dik 		}
1025f5c9e9f9SCasper H.S. Dik 		cp += length;
1026f5c9e9f9SCasper H.S. Dik 	}
1027f5c9e9f9SCasper H.S. Dik 	wcnt = namencnt(psa, i, maxlen);
1028f5c9e9f9SCasper H.S. Dik #if 0
1029f5c9e9f9SCasper H.S. Dik 	/* dumps core on really long strings */
1030f5c9e9f9SCasper H.S. Dik 	(void) printf(" %.*s", wcnt, psa);
1031f5c9e9f9SCasper H.S. Dik #else
1032f5c9e9f9SCasper H.S. Dik 	(void) putchar(' ');
1033f5c9e9f9SCasper H.S. Dik 	(void) fwrite(psa, 1, wcnt, stdout);
1034f5c9e9f9SCasper H.S. Dik #endif
1035f5c9e9f9SCasper H.S. Dik 	return (1);
1036f5c9e9f9SCasper H.S. Dik }
1037f5c9e9f9SCasper H.S. Dik 
1038f5c9e9f9SCasper H.S. Dik /*
1039f5c9e9f9SCasper H.S. Dik  * Print starting time of process unless process started more than 24 hours
1040f5c9e9f9SCasper H.S. Dik  * ago, in which case the date is printed.
1041f5c9e9f9SCasper H.S. Dik  */
1042f5c9e9f9SCasper H.S. Dik static void
prtime(timestruc_t st)1043f5c9e9f9SCasper H.S. Dik prtime(timestruc_t st)
1044f5c9e9f9SCasper H.S. Dik {
1045f5c9e9f9SCasper H.S. Dik 	char sttim[26];
1046f5c9e9f9SCasper H.S. Dik 	static time_t tim = 0L;
1047f5c9e9f9SCasper H.S. Dik 	time_t starttime;
1048f5c9e9f9SCasper H.S. Dik 
1049f5c9e9f9SCasper H.S. Dik 	if (tim == 0L)
1050f5c9e9f9SCasper H.S. Dik 		tim = time((time_t *)0);
1051f5c9e9f9SCasper H.S. Dik 	starttime = st.tv_sec;
1052f5c9e9f9SCasper H.S. Dik 	if (tim - starttime > 24*60*60) {
1053f5c9e9f9SCasper H.S. Dik 		(void) strftime(sttim, sizeof (sttim), "%b %d",
1054f5c9e9f9SCasper H.S. Dik 		    localtime(&starttime));
1055f5c9e9f9SCasper H.S. Dik 	} else {
1056f5c9e9f9SCasper H.S. Dik 		(void) strftime(sttim, sizeof (sttim), "%H:%M:%S",
1057f5c9e9f9SCasper H.S. Dik 		    localtime(&starttime));
1058f5c9e9f9SCasper H.S. Dik 	}
1059f5c9e9f9SCasper H.S. Dik 	(void) printf("%9.9s", sttim);
1060f5c9e9f9SCasper H.S. Dik }
1061f5c9e9f9SCasper H.S. Dik 
1062f5c9e9f9SCasper H.S. Dik static void
przom(psinfo_t * psinfo)1063f5c9e9f9SCasper H.S. Dik przom(psinfo_t *psinfo)
1064f5c9e9f9SCasper H.S. Dik {
1065f5c9e9f9SCasper H.S. Dik 	long	tm;
1066f5c9e9f9SCasper H.S. Dik 
1067f5c9e9f9SCasper H.S. Dik 	if (lflg)
1068f5c9e9f9SCasper H.S. Dik 		(void) printf("%2x", psinfo->pr_flag & 0377);
1069f5c9e9f9SCasper H.S. Dik 	if (uflg) {
1070f5c9e9f9SCasper H.S. Dik 		struct passwd *pwd;
1071f5c9e9f9SCasper H.S. Dik 
1072f5c9e9f9SCasper H.S. Dik 		if ((pwd = getpwuid(psinfo->pr_euid)) != NULL)
1073f5c9e9f9SCasper H.S. Dik 			(void) printf("%-8.8s", pwd->pw_name);	/* USER */
1074f5c9e9f9SCasper H.S. Dik 		else
1075f5c9e9f9SCasper H.S. Dik 			(void) printf(" %7.7d", (int)psinfo->pr_euid); /* UID */
1076f5c9e9f9SCasper H.S. Dik 	} else if (lflg)
1077f5c9e9f9SCasper H.S. Dik 		(void) printf(" %5d", (int)psinfo->pr_euid);	/* UID */
1078f5c9e9f9SCasper H.S. Dik 
1079f5c9e9f9SCasper H.S. Dik 	(void) printf("%*d", pidwidth + 1, (int)psinfo->pr_pid); /* PID */
1080f5c9e9f9SCasper H.S. Dik 	if (lflg)
1081f5c9e9f9SCasper H.S. Dik 		(void) printf("%*d", pidwidth + 1,
1082f5c9e9f9SCasper H.S. Dik 		    (int)psinfo->pr_ppid); /* PPID */
1083f5c9e9f9SCasper H.S. Dik 	if (lflg)
1084f5c9e9f9SCasper H.S. Dik 		(void) printf("  0");				/* CP */
1085f5c9e9f9SCasper H.S. Dik 	if (uflg) {
1086f5c9e9f9SCasper H.S. Dik 		prtpct(0);					/* %CPU */
1087f5c9e9f9SCasper H.S. Dik 		prtpct(0);					/* %MEM */
1088f5c9e9f9SCasper H.S. Dik 	}
1089f5c9e9f9SCasper H.S. Dik 	if (lflg) {
1090f5c9e9f9SCasper H.S. Dik 		(void) printf("%4d", psinfo->pr_lwp.pr_pri);	/* PRI */
1091f5c9e9f9SCasper H.S. Dik 		(void) printf("   ");				/* NICE */
1092f5c9e9f9SCasper H.S. Dik 	}
1093f5c9e9f9SCasper H.S. Dik 	if (lflg || uflg) {
1094f5c9e9f9SCasper H.S. Dik 		(void) printf("    0");				/* SZ */
1095f5c9e9f9SCasper H.S. Dik 		(void) printf("    0");				/* RSS */
1096f5c9e9f9SCasper H.S. Dik 	}
1097f5c9e9f9SCasper H.S. Dik 	if (lflg)
1098f5c9e9f9SCasper H.S. Dik 		(void) printf("         ");			/* WCHAN */
1099f5c9e9f9SCasper H.S. Dik 	(void) printf("          ");				/* TTY */
1100f5c9e9f9SCasper H.S. Dik 	(void) printf("%c", psinfo->pr_lwp.pr_sname);		/* STATE */
1101f5c9e9f9SCasper H.S. Dik 	if (uflg)
1102f5c9e9f9SCasper H.S. Dik 		(void) printf("         ");			/* START */
1103f5c9e9f9SCasper H.S. Dik 
1104f5c9e9f9SCasper H.S. Dik 	/* time just for process */
1105f5c9e9f9SCasper H.S. Dik 	tm = psinfo->pr_time.tv_sec;
1106f5c9e9f9SCasper H.S. Dik 	if (Sflg) {	/* calculate time for process and all reaped children */
1107f5c9e9f9SCasper H.S. Dik 		tm += psinfo->pr_ctime.tv_sec;
1108f5c9e9f9SCasper H.S. Dik 		if (psinfo->pr_time.tv_nsec + psinfo->pr_ctime.tv_nsec
1109f5c9e9f9SCasper H.S. Dik 		    >= 1000000000)
1110f5c9e9f9SCasper H.S. Dik 			tm += 1;
1111f5c9e9f9SCasper H.S. Dik 	}
1112f5c9e9f9SCasper H.S. Dik 	(void) printf(" %2ld:%.2ld", tm / 60, tm % 60);		/* TIME */
1113f5c9e9f9SCasper H.S. Dik 
1114f5c9e9f9SCasper H.S. Dik 	if (vflg) {
1115f5c9e9f9SCasper H.S. Dik 		(void) printf("    0");				/* SZ */
1116f5c9e9f9SCasper H.S. Dik 		(void) printf("    0");				/* RSS */
1117f5c9e9f9SCasper H.S. Dik 		prtpct(0);					/* %CPU */
1118f5c9e9f9SCasper H.S. Dik 		prtpct(0);					/* %MEM */
1119f5c9e9f9SCasper H.S. Dik 	}
1120f5c9e9f9SCasper H.S. Dik 	(void) printf(" %.*s", maxlen, " <defunct>");
1121f5c9e9f9SCasper H.S. Dik }
1122f5c9e9f9SCasper H.S. Dik 
1123f5c9e9f9SCasper H.S. Dik /*
1124f5c9e9f9SCasper H.S. Dik  * Returns true iff string is all numeric.
1125f5c9e9f9SCasper H.S. Dik  */
1126f5c9e9f9SCasper H.S. Dik static int
num(char * s)1127f5c9e9f9SCasper H.S. Dik num(char *s)
1128f5c9e9f9SCasper H.S. Dik {
1129f5c9e9f9SCasper H.S. Dik 	int c;
1130f5c9e9f9SCasper H.S. Dik 
1131f5c9e9f9SCasper H.S. Dik 	if (s == NULL)
1132f5c9e9f9SCasper H.S. Dik 		return (0);
1133f5c9e9f9SCasper H.S. Dik 	c = *s;
1134f5c9e9f9SCasper H.S. Dik 	do {
1135f5c9e9f9SCasper H.S. Dik 		if (!isdigit(c))
1136f5c9e9f9SCasper H.S. Dik 			return (0);
1137f5c9e9f9SCasper H.S. Dik 	} while ((c = *++s) != '\0');
1138f5c9e9f9SCasper H.S. Dik 	return (1);
1139f5c9e9f9SCasper H.S. Dik }
1140f5c9e9f9SCasper H.S. Dik 
1141f5c9e9f9SCasper H.S. Dik /*
1142f5c9e9f9SCasper H.S. Dik  * Function to compute the number of printable bytes in a multibyte
1143f5c9e9f9SCasper H.S. Dik  * command string ("internationalization").
1144f5c9e9f9SCasper H.S. Dik  */
1145f5c9e9f9SCasper H.S. Dik static int
namencnt(char * cmd,int eucsize,int scrsize)1146f5c9e9f9SCasper H.S. Dik namencnt(char *cmd, int eucsize, int scrsize)
1147f5c9e9f9SCasper H.S. Dik {
1148f5c9e9f9SCasper H.S. Dik 	int eucwcnt = 0, scrwcnt = 0;
1149f5c9e9f9SCasper H.S. Dik 	int neucsz, nscrsz;
1150f5c9e9f9SCasper H.S. Dik 	wchar_t	wchar;
1151f5c9e9f9SCasper H.S. Dik 
1152f5c9e9f9SCasper H.S. Dik 	while (*cmd != '\0') {
1153f5c9e9f9SCasper H.S. Dik 		if ((neucsz = mbtowc(&wchar, cmd, MB_LEN_MAX)) < 0)
1154f5c9e9f9SCasper H.S. Dik 			return (8); /* default to use for illegal chars */
1155f5c9e9f9SCasper H.S. Dik 		if ((nscrsz = scrwidth(wchar)) == 0)
1156f5c9e9f9SCasper H.S. Dik 			return (8);
1157f5c9e9f9SCasper H.S. Dik 		if (eucwcnt + neucsz > eucsize || scrwcnt + nscrsz > scrsize)
1158f5c9e9f9SCasper H.S. Dik 			break;
1159f5c9e9f9SCasper H.S. Dik 		eucwcnt += neucsz;
1160f5c9e9f9SCasper H.S. Dik 		scrwcnt += nscrsz;
1161f5c9e9f9SCasper H.S. Dik 		cmd += neucsz;
1162f5c9e9f9SCasper H.S. Dik 	}
1163f5c9e9f9SCasper H.S. Dik 	return (eucwcnt);
1164f5c9e9f9SCasper H.S. Dik }
1165f5c9e9f9SCasper H.S. Dik 
1166f5c9e9f9SCasper H.S. Dik static int
pscompare(const void * v1,const void * v2)1167f5c9e9f9SCasper H.S. Dik pscompare(const void *v1, const void *v2)
1168f5c9e9f9SCasper H.S. Dik {
1169f5c9e9f9SCasper H.S. Dik 	const struct psent *p1 = v1;
1170f5c9e9f9SCasper H.S. Dik 	const struct psent *p2 = v2;
1171f5c9e9f9SCasper H.S. Dik 	int i;
1172f5c9e9f9SCasper H.S. Dik 
1173f5c9e9f9SCasper H.S. Dik 	if (uflg)
1174f5c9e9f9SCasper H.S. Dik 		i = p2->psinfo->pr_pctcpu - p1->psinfo->pr_pctcpu;
1175f5c9e9f9SCasper H.S. Dik 	else if (vflg)
1176f5c9e9f9SCasper H.S. Dik 		i = p2->psinfo->pr_rssize - p1->psinfo->pr_rssize;
1177f5c9e9f9SCasper H.S. Dik 	else
1178f5c9e9f9SCasper H.S. Dik 		i = p1->psinfo->pr_ttydev - p2->psinfo->pr_ttydev;
1179f5c9e9f9SCasper H.S. Dik 	if (i == 0)
1180f5c9e9f9SCasper H.S. Dik 		i = p1->psinfo->pr_pid - p2->psinfo->pr_pid;
1181f5c9e9f9SCasper H.S. Dik 	return (i);
1182f5c9e9f9SCasper H.S. Dik }
1183f5c9e9f9SCasper H.S. Dik 
1184f5c9e9f9SCasper H.S. Dik static char *
err_string(int err)1185f5c9e9f9SCasper H.S. Dik err_string(int err)
1186f5c9e9f9SCasper H.S. Dik {
1187f5c9e9f9SCasper H.S. Dik 	static char buf[32];
1188f5c9e9f9SCasper H.S. Dik 	char *str = strerror(err);
1189f5c9e9f9SCasper H.S. Dik 
1190f5c9e9f9SCasper H.S. Dik 	if (str == NULL)
1191f5c9e9f9SCasper H.S. Dik 		(void) sprintf(str = buf, "Errno #%d", err);
1192f5c9e9f9SCasper H.S. Dik 
1193f5c9e9f9SCasper H.S. Dik 	return (str);
1194f5c9e9f9SCasper H.S. Dik }
1195