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