1 /*
2  * ps - process status
3  *
4  * Gunnar Ritter, Freiburg i. Br., Germany, August 2002.
5  */
6 /*
7  * Copyright (c) 2003 Gunnar Ritter
8  *
9  * This software is provided 'as-is', without any express or implied
10  * warranty. In no event will the authors be held liable for any damages
11  * arising from the use of this software.
12  *
13  * Permission is granted to anyone to use this software for any purpose,
14  * including commercial applications, and to alter it and redistribute
15  * it freely, subject to the following restrictions:
16  *
17  * 1. The origin of this software must not be misrepresented; you must not
18  *    claim that you wrote the original software. If you use this software
19  *    in a product, an acknowledgment in the product documentation would be
20  *    appreciated but is not required.
21  *
22  * 2. Altered source versions must be plainly marked as such, and must not be
23  *    misrepresented as being the original software.
24  *
25  * 3. This notice may not be removed or altered from any source distribution.
26  */
27 
28 #if __GNUC__ >= 3 && __GNUC_MINOR__ >= 4 || __GNUC__ >= 4
29 #define	USED	__attribute__ ((used))
30 #elif defined __GNUC__
31 #define	USED	__attribute__ ((unused))
32 #else
33 #define	USED
34 #endif
35 #if defined (S42)
36 static const char sccsid[] USED = "@(#)ps_s42.sl	2.114 (gritter) 1/12/07";
37 #elif defined (SUS)
38 static const char sccsid[] USED = "@(#)ps_sus.sl	2.114 (gritter) 1/12/07";
39 #elif defined (UCB)
40 static const char sccsid[] USED = "@(#)/usr/ucb/ps.sl	2.114 (gritter) 1/12/07";
41 #else
42 static const char sccsid[] USED = "@(#)ps.sl	2.114 (gritter) 1/12/07";
43 #endif
44 
45 static const char cacheid[] = "@(#)/tmp/ps_cache	2.114 (gritter) 1/12/07";
46 
47 #if !defined (__linux__) && !defined (__sun) && !defined (__FreeBSD__) \
48 	&& !defined (__DragonFly__)
49 #define	_KMEMUSER
50 #endif	/* !__linux__, !__sun, !__FreeBSD__, !__DragonFly__ */
51 #include	<sys/types.h>
52 #include	<sys/stat.h>
53 #include	<sys/utsname.h>
54 #ifdef	__GLIBC__
55 #include	<sys/sysmacros.h>
56 #endif
57 #include	<fcntl.h>
58 #include	<time.h>
59 #include	<unistd.h>
60 #include	<stdio.h>
61 #include	<string.h>
62 #include	<stdlib.h>
63 #include	<errno.h>
64 #include	<libgen.h>
65 #include	<dirent.h>
66 #include	<limits.h>
67 #include	<sched.h>
68 #include	<pwd.h>
69 #include	<grp.h>
70 #include	<langinfo.h>
71 #include	<locale.h>
72 #include	<ctype.h>
73 #include	<blank.h>
74 #include	<inttypes.h>
75 #include 	<termios.h>
76 #if defined (__linux__)
77 #include	<mntent.h>
78 #elif defined (__FreeBSD__) || defined (__DragonFly__)
79 #include	<kvm.h>
80 #include	<sys/param.h>
81 #include	<sys/ucred.h>
82 #include	<sys/mount.h>
83 #include	<sys/time.h>
84 #include	<sys/resource.h>
85 #include	<sys/sysctl.h>
86 #include	<sys/user.h>
87 #define	proc	process
88 #undef	p_pgid
89 #undef	p_pctcpu
90 #if !defined(PS_SWAPPINGOUT) && defined(P_SWAPPINGOUT)
91 #define PS_SWAPPINGOUT P_SWAPPINGOUT
92 #endif
93 #if defined (__DragonFly__)
94 #define SRUN	SACTIVE
95 #endif	/* __DragonFly__ */
96 #elif defined (__hpux)
97 #include	<mntent.h>
98 #include	<sys/param.h>
99 #include	<sys/pstat.h>
100 #elif defined (_AIX)
101 #include	<mntent.h>
102 #include	<procinfo.h>
103 #define	proc	process
104 #ifndef	MNTTYPE_IGNORE
105 #define	MNTTYPE_IGNORE	""
106 #endif
107 #elif defined (__NetBSD__) || defined (__OpenBSD__)
108 #include	<kvm.h>
109 #include	<sys/param.h>
110 #include	<sys/sysctl.h>
111 #include	<sys/mount.h>
112 #define	proc	process
113 #undef	p_pgid
114 #if !defined (SRUN) && defined (LSRUN)
115 #define	SRUN	LSRUN
116 #endif
117 #if !defined (SSLEEP) && defined (LSSLEEP)
118 #define	SSLEEP	LSSLEEP
119 #endif
120 #if !defined (SDEAD) && defined (LSDEAD)
121 #define	SDEAD	LSDEAD
122 #endif
123 #if !defined (SONPROC) && defined (LSONPROC)
124 #define	SONPROC	LSONPROC
125 #endif
126 #if !defined (P_INMEM) && defined (L_INMEM)
127 #define	P_INMEM	L_INMEM
128 #endif
129 #if !defined (P_SINTR) && defined (L_SINTR)
130 #define	P_SINTR	L_SINTR
131 #endif
132 #ifndef	SCHED_OTHER
133 #define	SCHED_OTHER	1
134 #endif
135 #elif defined (__APPLE__)
136 #include	<sys/proc.h>
137 #include        <sys/sysctl.h>
138 #include        <sys/mount.h>
139 #include	<sys/resource.h>
140 #include	<mach/mach_types.h>
141 #include	<mach/task_info.h>
142 #include	<mach/shared_memory_server.h>
143 #define	proc	process
144 #undef	p_pgid
145 #else	/* SVR4 */
146 #include	<sys/mnttab.h>
147 #ifdef	__sun
148 #define	_STRUCTURED_PROC	1
149 #endif	/* __sun */
150 #include	<sys/procfs.h>
151 #include	<sys/proc.h>
152 #undef	p_pid
153 #undef	p_wchan
154 #define	proc	process
155 #endif	/* SVR4 */
156 #include	<wchar.h>
157 #include	<wctype.h>
158 #ifndef	TIOCGWINSZ
159 #include	<sys/ioctl.h>
160 #endif
161 
162 #if __NetBSD_Version__ >= 300000000
163 #include	<sys/statvfs.h>
164 #define	statfs	statvfs
165 #endif
166 
167 #include	<mbtowi.h>
168 
169 #ifdef	__linux__
170 #ifndef	SCHED_BATCH
171 #define	SCHED_BATCH	3
172 #endif
173 #ifndef	SCHED_ISO
174 #define	SCHED_ISO	4
175 #endif
176 #endif	/* __linux__ */
177 
178 #define	PROCDIR		"/proc"
179 #ifndef	UCB
180 #define	DEFUNCT		"<defunct>"
181 #else	/* UCB */
182 #define	DEFUNCT		" <defunct>"
183 #endif	/* UCB */
184 #ifndef	PRNODEV
185 #define	PRNODEV		0
186 #endif	/* !PRNODEV */
187 #define	eq(a, b)	(strcmp(a, b) == 0)
188 
189 #ifdef	__GLIBC__
190 #ifdef	_IO_getc_unlocked
191 #undef	getc
192 #define	getc(f)		_IO_getc_unlocked(f)
193 #endif	/* _IO_getc_unlocked */
194 #ifdef	_IO_putc_unlocked
195 #undef	putchar
196 #define	putchar(c)	_IO_putc_unlocked(c, stdout)
197 #endif	/* _IO_putc_unlocked */
198 #endif	/* __GLIBC__ */
199 
200 #define	next(wc, s, n)	(mb_cur_max > 1 && *(s) & 0200 ? \
201 		((n) = mbtowi(&(wc), (s), mb_cur_max), \
202 		 (n) = ((n) > 0 ? (n) : (n) < 0 ? (wc=WEOF, 1) : 1)) :\
203 		((wc) = *(s) & 0377, (n) = 1))
204 
205 #ifndef	_AIX
206 typedef	uint32_t	dev_type;
207 #else
208 typedef	uint64_t	dev_type;
209 #endif
210 
211 enum	okay {
212 	OKAY,
213 	STOP
214 };
215 
216 enum	crtype {
217 	CR_ALL,				/* -e, -A */
218 	CR_ALL_WITH_TTY,		/* -a */
219 	CR_ALL_BUT_SESSION_LEADERS,	/* -d */
220 	CR_WITHOUT_TTY,			/* UCB -gx */
221 	CR_NO_TTY_NO_SESSION_LEADER,	/* UCB -x */
222 	CR_PROCESS_GROUP,		/* traditional -g ... */
223 	CR_REAL_GID,			/* -G ... */
224 	CR_PROCESS_ID,			/* -p ... */
225 	CR_TTY_DEVICE,			/* -t ... */
226 	CR_SESSION_LEADER,		/* -s ..., SUS -g ... */
227 	CR_EFF_UID,			/* SUS -u ... */
228 	CR_REAL_UID,			/* -U ..., traditional -u ... */
229 	CR_ADD_UNINTERESTING,		/* UCB -g */
230 	CR_INVALID_EFF_UID,		/* invalid eff. uid but look for more */
231 	CR_INVALID_REAL_UID,		/* invalid real uid but look for more */
232 	CR_INVALID_REAL_GID,		/* invalid group but look for more */
233 	CR_INVALID_TTY_DEVICE,		/* invalid tty, ignore */
234 	CR_INVALID_STOP,		/* invalid criterion but stop later */
235 	CR_DEFAULT
236 };
237 
238 enum	outype {
239 	OU_USER,
240 	OU_RUSER,
241 	OU_GROUP,
242 	OU_RGROUP,
243 	OU_PID,
244 	OU_PPID,
245 	OU_PGID,
246 	OU_PCPU,
247 	OU_VSZ,
248 	OU_NICE,
249 	OU_ETIME,
250 	OU_OTIME,
251 	OU_TIME,
252 	OU_ACCUTIME,
253 	OU_TTY,
254 	OU_COMM,
255 	OU_ARGS,
256 	OU_F,
257 	OU_S,
258 	OU_C,
259 	OU_UID,
260 	OU_RUID,
261 	OU_GID,
262 	OU_RGID,
263 	OU_SID,
264 	OU_CLASS,
265 	OU_PRI,
266 	OU_OPRI,
267 	OU_PSR,
268 	OU_ADDR,
269 	OU_OSZ,
270 	OU_WCHAN,
271 	OU_STIME,
272 	OU_RSS,
273 	OU_ORSS,
274 	OU_PMEM,
275 	OU_FNAME,
276 	OU_LWP,
277 	OU_NLWP,
278 	OU_LTIME,
279 	OU_STID,
280 	OU_TID,
281 	OU_NTP,
282 	OU_MRSZ,
283 	OU_PFLTS,
284 	OU_BUFR,
285 	OU_BUFW,
286 	OU_MRCV,
287 	OU_MSND,
288 	OU_UTIME,
289 	OU_KTIME,
290 	OU_SPACE
291 };
292 
293 enum {
294 	FL_LOAD	= 001,
295 	FL_SYS	= 002,
296 	FL_LOCK	= 004,
297 	FL_SWAP	= 010,
298 	FL_TRC	= 020,
299 	FL_WTED	= 040
300 };
301 
302 enum	valtype {
303 	VT_CHAR,
304 	VT_INT,
305 	VT_UINT,
306 	VT_LONG,
307 	VT_ULONG
308 };
309 
310 union	value {
311 	char			v_char;
312 	int			v_int;
313 	unsigned int		v_uint;
314 	long			v_long;
315 	unsigned long		v_ulong;
316 };
317 
318 struct	trenod {
319 	struct trenod		*t_lln;
320 	struct trenod		*t_rln;
321 	char			*t_str;
322 	unsigned long		t_num;
323 };
324 
325 struct	ditem {
326 	struct ditem		*d_lnk;
327 	char			*d_str;
328 	dev_type		d_rdev;
329 };
330 
331 struct	criterion {
332 	struct criterion	*c_nxt;
333 	enum crtype		c_typ;
334 	unsigned long		c_val;
335 };
336 
337 struct	output {
338 	struct output		*o_nxt;
339 	enum outype		o_typ;
340 	char			*o_nam;
341 	int			o_len;
342 };
343 
344 static const struct	{
345 	enum outype		os_typ;
346 	char			*os_fmt;
347 	char			*os_def;
348 	enum {
349 		OS_Lflag = 01
350 	}			os_flags;
351 } outspec[] = {
352 	{ OU_USER,	"user",		"    USER",	0		},
353 	{ OU_RUSER,	"ruser",	"   RUSER",	0		},
354 	{ OU_GROUP,	"group",	"   GROUP",	0		},
355 	{ OU_RGROUP,	"rgroup",	"  RGROUP",	0		},
356 	{ OU_PID,	"pid",		"  PID",	0		},
357 	{ OU_PPID,	"ppid",		" PPID",	0		},
358 	{ OU_PGID,	"pgid",		" PGID",	0		},
359 	{ OU_PCPU,	"pcpu",		"%CPU",		0		},
360 	{ OU_VSZ,	"vsz",		"   VSZ",	0		},
361 	{ OU_NICE,	"nice",		"NI",		0		},
362 	{ OU_ETIME,	"etime",	"    ELAPSED",	0		},
363 	{ OU_TIME,	"time",		"    TIME",	0		},
364 	{ OU_ACCUTIME,	"accutime",	" TIME",	0		},
365 	{ OU_OTIME,	"otime",	" TIME",	0		},
366 	{ OU_TTY,	"tty",		"TT     ",	0		},
367 	{ OU_COMM,	"comm",		"COMMAND",	0		},
368 	{ OU_ARGS,	"args",		"COMMAND",	0		},
369 	{ OU_F,		"f",		" F",		0		},
370 	{ OU_S,		"s",		"S",		0		},
371 	{ OU_C,		"c",		" C",		0		},
372 	{ OU_UID,	"uid",		"  UID",	0		},
373 	{ OU_RUID,	"ruid",		" RUID",	0		},
374 	{ OU_GID,	"gid",		"  GID",	0		},
375 	{ OU_RGID,	"rgid",		" RGID",	0		},
376 	{ OU_SID,	"sid",		"  SID",	0		},
377 	{ OU_CLASS,	"class",	" CLS",		0		},
378 	{ OU_PRI,	"pri",		"PRI",		0		},
379 	{ OU_OPRI,	"opri",		"PRI",		0		},
380 	{ OU_PSR,	"psr",		"PSR",		0		},
381 	{ OU_ADDR,	"addr",		"    ADDR",	0		},
382 	{ OU_OSZ,	"osz",		"    SZ",	0		},
383 	{ OU_WCHAN,	"wchan",	"   WCHAN",	0		},
384 	{ OU_STIME,	"stime",	"   STIME",	0		},
385 	{ OU_RSS,	"rss",		"  RSS",	0		},
386 	{ OU_ORSS,	"orss",		"  RSS",	0		},
387 	{ OU_PMEM,	"pmem",		"%MEM",		0		},
388 	{ OU_FNAME,	"fname",	"COMMAND",	0		},
389 	{ OU_LWP,	"lwp",		"  LWP",	OS_Lflag	},
390 	{ OU_NLWP,	"nlwp",		" NLWP",	0		},
391 	{ OU_LTIME,	"ltime",	"LTIME",	OS_Lflag	},
392 	{ OU_STID,	"stid",		" STID",	OS_Lflag	},
393 	{ OU_TID,	"tid",		"TID",		OS_Lflag	},
394 	{ OU_NTP,	"ntp",		"NTP",		0		},
395 	{ OU_MRSZ,	"mrsz",		" MRSZ",	0		},
396 	{ OU_PFLTS,	"pflts",	"PFLTS",	0		},
397 	{ OU_BUFR,	"bufr",		"  BUFR",	0		},
398 	{ OU_BUFW,	"bufw",		"  BUFW",	0		},
399 	{ OU_MRCV,	"mrcv",		"  MRCV",	0		},
400 	{ OU_MSND,	"msnd",		"  MSND",	0		},
401 	{ OU_UTIME,	"utime",	"   UTIME",	0		},
402 	{ OU_KTIME,	"ktime",	"   KTIME",	0		},
403 	{ OU_SPACE,	NULL,		" ",	 	0		}
404 };
405 
406 struct	proc {
407 	pid_t		p_pid;		/* process id */
408 	char		p_fname[19];	/* executable name */
409 	char		p_state[2];	/* process state */
410 	char		p_lstate[2];	/* linux state */
411 	pid_t		p_ppid;		/* parent process id */
412 	pid_t		p_pgid;		/* process group */
413 	pid_t		p_sid;		/* session */
414 	pid_t		p_lwp;		/* LWP id */
415 	dev_type	p_ttydev;	/* tty device */
416 	unsigned long	p_flag;		/* process flags */
417 	unsigned long	p_lflag;	/* linux flags */
418 	time_t		p_time;		/* cpu time */
419 	time_t		p_accutime;	/* accumulated cpu time */
420 	time_t		p_utime;	/* user time */
421 	time_t		p_ktime;	/* kernel time */
422 	long		p_intpri;	/* priority value from /proc */
423 	long		p_rtpri;	/* rt_priority value from /proc */
424 	long		p_policy;	/* scheduling policy */
425 	int		p_c;		/* cpu usage for scheduling */
426 	int		p_oldpri;	/* old priority */
427 	int		p_pri;		/* new priority */
428 	int		p_nice;		/* nice value */
429 	int		p_nlwp;		/* number of LWPs */
430 	time_t		p_start;	/* start time */
431 	unsigned long	p_size;		/* size in kilobytes */
432 	unsigned long	p_osz;		/* size in pages */
433 	unsigned long	p_rssize;	/* rss size in kbytes */
434 	unsigned long	p_orss;		/* rss size in pages */
435 	unsigned long	p_pflts;	/* page faults */
436 	unsigned long	p_bufr;		/* buffer reads */
437 	unsigned long	p_bufw;		/* buffer writes */
438 	unsigned long	p_mrcv;		/* messages received */
439 	unsigned long	p_msnd;		/* messages sent */
440 	unsigned long	p_addr;		/* address */
441 	unsigned long	p_wchan;	/* wait channel */
442 	int		p_psr;		/* processor */
443 	double		p_pctcpu;	/* cpu percent */
444 	double		p_pctmem;	/* mem percent */
445 	char		*p_clname;	/* scheduling class */
446 	char		p_comm[80];	/* first argument */
447 	char		p_psargs[80];	/* process arguments */
448 	uid_t		p_uid;		/* real uid */
449 	uid_t		p_euid;		/* effective uid */
450 	gid_t		p_gid;		/* real gid */
451 	gid_t		p_egid;		/* effective gid */
452 };
453 
454 static unsigned	errcnt;			/* count of errors */
455 static int		Lflag;		/* show LWPs */
456 static int		oflag;		/* had -o switch */
457 static const char	*rflag;		/* change root directory */
458 static int		ucb_rflag;	/* running processes only */
459 static int		dohdr;		/* output header */
460 #undef	hz
461 static long		hz;		/* clock ticks per second */
462 static time_t		now;		/* current time */
463 #ifdef	__linux__
464 static time_t		uptime;
465 #endif	/* __linux__ */
466 #ifndef	__sun
467 static unsigned long	totalmem;
468 #endif	/* !__sun */
469 static unsigned long	kbytes_per_page;
470 static unsigned long	pagesize;
471 static uid_t		myuid;		/* real uid of ps */
472 static uid_t		myeuid;		/* effective uid of ps */
473 static int		sched_selection;
474 static int		maxcolumn;	/* maximum terminal size */
475 static int		mb_cur_max;	/* MB_CUR_MAX acceleration */
476 static int		ontty;		/* running on a tty */
477 static char		*progname;	/* argv[0] to main() */
478 static struct proc	myproc;		/* struct proc for this ps instance */
479 
480 static struct ditem	**d0;		/* dev_t to device name mapping */
481 static struct criterion	*c0;		/* criteria list */
482 static struct output	*o0;		/* output field list */
483 
484 #ifdef	__linux__
485 static int		linux_version[3] = { 2, 4, 0 };
486 #endif	/* !__linux__ */
487 
488 #ifdef	USE_PS_CACHE
489 static FILE		*devfp;
490 static char		*ps_cache_file = "/tmp/ps_cache";
491 static mode_t		ps_cache_mode = 0664;
492 static gid_t		ps_cache_gid = 3;
493 #endif	/* USE_PS_CACHE */
494 static int		dropprivs;
495 
496 static void		postproc(struct proc *);
497 static enum okay	selectproc(struct proc *);
498 static kvm_t		*kv;
499 
500 /************************************************************************
501  * 			Utility functions				*
502  ************************************************************************/
503 
504 static void *
srealloc(void * vp,size_t nbytes)505 srealloc(void *vp, size_t nbytes)
506 {
507 	void	*p;
508 
509 	if ((p = realloc(vp, nbytes)) == NULL) {
510 		write(2, "no memory\n", 10);
511 		exit(077);
512 	}
513 	return p;
514 }
515 
516 static void *
smalloc(size_t nbytes)517 smalloc(size_t nbytes)
518 {
519 	return srealloc(NULL, nbytes);
520 }
521 
522 static char *
sstrdup(const char * op)523 sstrdup(const char *op)
524 {
525 	char	*np;
526 
527 	np = smalloc(strlen(op) + 1);
528 	strcpy(np, op);
529 	return np;
530 }
531 
532 static void *
scalloc(size_t nmemb,size_t size)533 scalloc(size_t nmemb, size_t size)
534 {
535 	void	*p;
536 
537 	if ((p = (void *)calloc(nmemb, size)) == NULL) {
538 		write(2, "no memory\n", 10);
539 		exit(077);
540 	}
541 	return p;
542 }
543 
544 static FILE *
wopen(const char * fn)545 wopen(const char *fn)
546 {
547 	int	fd;
548 	char	*tl, *dn, *fc;
549 
550 	dn = dirname(fc = sstrdup(fn));
551 	tl = smalloc(strlen(dn) + 10);
552 	strcpy(tl, dn);
553 	strcat(tl, "/psXXXXXX");
554 	free(fc);
555 	if ((fd = mkstemp(tl)) < 0)
556 		return NULL;
557 	if (rename(tl, fn) < 0) {
558 		unlink(tl);
559 		free(tl);
560 		close(fd);
561 		return NULL;
562 	}
563 	free(tl);
564 	return fdopen(fd, "w");
565 }
566 
567 static struct trenod *
treget(unsigned long num,struct trenod ** troot)568 treget(unsigned long num, struct trenod **troot)
569 {
570 	long long	c;
571 	struct trenod	*tp = *troot;
572 
573 	while (tp != NULL) {
574 		if ((c = num - tp->t_num) == 0)
575 			break;
576 		else if (c < 0)
577 			tp = tp->t_lln;
578 		else
579 			tp = tp->t_rln;
580 	}
581 	return tp;
582 }
583 
584 static void
treput(struct trenod * tk,struct trenod ** troot)585 treput(struct trenod *tk, struct trenod **troot)
586 {
587 	if (*troot) {
588 		long long	c;
589 		struct trenod	*tp = *troot, *tq = NULL;
590 
591 		while (tp != NULL) {
592 			tq = tp;
593 			if ((c = tk->t_num - tp->t_num) == 0)
594 				return;
595 			else if (c < 0)
596 				tp = tp->t_lln;
597 			else
598 				tp = tp->t_rln;
599 		}
600 		if (tq != NULL) {
601 			if ((c = tk->t_num - tq->t_num) < 0)
602 				tq->t_lln = tk;
603 			else
604 				tq->t_rln = tk;
605 		}
606 	} else
607 		*troot = tk;
608 }
609 
610 #define	dhash(c)	((uint32_t)(2654435769U * (uint32_t)(c) >> 24))
611 
612 static struct ditem *
dlook(dev_type rdev,struct ditem ** dt,char * str)613 dlook(dev_type rdev, struct ditem **dt, char *str)
614 {
615 	struct ditem	*dp;
616 	int	h;
617 
618 	dp = dt[h = dhash(rdev)];
619 	while (dp != NULL) {
620 		if (dp->d_rdev == rdev)
621 			break;
622 		dp = dp->d_lnk;
623 	}
624 	if (str != NULL && dp == NULL) {
625 		dp = scalloc(1, sizeof *dp);
626 		dp->d_rdev = rdev;
627 		dp->d_str = str;
628 		dp->d_lnk = dt[h];
629 		dt[h] = dp;
630 	}
631 	return dp;
632 }
633 
634 #if !defined (__hpux) && !defined (_AIX) && !defined (__NetBSD__) && \
635 	!defined (__OpenBSD__) && !defined (__APPLE__)
636 static void
chdir_to_proc(void)637 chdir_to_proc(void)
638 {
639 	static int	fd = -1;
640 
641 	if (fd == -1 && (fd = open(PROCDIR, O_RDONLY)) < 0) {
642 		fprintf(stderr, "%s: cannot open %s\n", progname, PROCDIR);
643 		exit(075);
644 	}
645 	if (fchdir(fd) < 0) {
646 		fprintf(stderr, "%s: cannot chdir to %s\n", progname, PROCDIR);
647 		exit(074);
648 	}
649 }
650 #endif	/* !__hpux, !_AIX, !__NetBSD__, !__OpenBSD__, !__APPLE__ */
651 
652 static union value *
getval(char ** listp,enum valtype type,int separator,int sep2)653 getval(char **listp, enum valtype type, int separator, int sep2)
654 {
655 	char	*buf;
656 	static union value	v;
657 	const char	*cp, *op;
658 	char	*cq, *x;
659 
660 	if (**listp == '\0')
661 		return NULL;
662 	op = *listp;
663 	while (**listp != '\0') {
664 		if ((separator == ' ' ? isspace(**listp) : **listp == separator)
665 				|| **listp == sep2)
666 			break;
667 		(*listp)++;
668 	}
669 	buf = alloca(*listp - op + 1);
670 	for (cp = op, cq = buf; cp < *listp; cp++, cq++)
671 		*cq = *cp;
672 	*cq = '\0';
673 	if (**listp) {
674 		while ((separator == ' ' ?
675 				isspace(**listp) : **listp == separator) ||
676 				**listp == sep2)
677 			(*listp)++;
678 	}
679 	switch (type) {
680 	case VT_CHAR:
681 		if (buf[1] != '\0')
682 			return NULL;
683 		v.v_char = buf[0];
684 		break;
685 	case VT_INT:
686 		v.v_int = strtol(buf, &x, 10);
687 		if (*x != '\0')
688 			return NULL;
689 		break;
690 	case VT_UINT:
691 		v.v_uint = strtoul(buf, &x, 10);
692 		if (*x != '\0')
693 			return NULL;
694 		break;
695 	case VT_LONG:
696 		v.v_long = strtol(buf, &x, 10);
697 		if (*x != '\0')
698 			return NULL;
699 		break;
700 	case VT_ULONG:
701 		v.v_ulong = strtoul(buf, &x, 10);
702 		if (*x != '\0')
703 			return NULL;
704 		break;
705 	}
706 	return &v;
707 }
708 
709 #ifdef	__linux__
710 static int
linux_version_lt(int version,int patchlevel,int sublevel)711 linux_version_lt(int version, int patchlevel, int sublevel)
712 {
713 	if (linux_version[0] < version)
714 		return 1;
715 	if (linux_version[0] == version) {
716 		if (linux_version[1] < patchlevel)
717 			return 1;
718 		if (patchlevel == linux_version[1] &&
719 				linux_version[2] < sublevel)
720 			return 1;
721 	}
722 	return 0;
723 }
724 
725 static int
has_o1_sched(void)726 has_o1_sched(void)
727 {
728 	struct stat	st;
729 
730 	if (sched_selection)
731 		return sched_selection > 0;
732 	return stat("/proc/sys/sched", &st) == 0;
733 }
734 #endif	/* __linux__ */
735 
736 static int
hasnonprint(const char * s)737 hasnonprint(const char *s)
738 {
739 	wint_t	wc;
740 	int	n;
741 
742 	while (*s) {
743 		next(wc, s, n);
744 		if (mb_cur_max > 1 ? !iswprint(wc) : !isprint(wc))
745 			return 1;
746 		s += n;
747 	}
748 	return 0;
749 }
750 
751 static int
colwidth(const char * s)752 colwidth(const char *s)
753 {
754 	wint_t	wc;
755 	int	i, n, w = 0;
756 
757 	while (*s) {
758 		next(wc, s, n);
759 		s += n;
760 		if (mb_cur_max > 1)
761 			i = iswprint(wc) ? wcwidth(wc) : 0;
762 		else
763 			i = isprint(wc) != 0;
764 		w += i;
765 	}
766 	return w;
767 }
768 
769 static void
cleanline(struct proc * p)770 cleanline(struct proc *p)
771 {
772 	/*
773 	 * If the argument list contains a nonprintable character,
774 	 * replace it with the file name even if output is not a
775 	 * terminal.
776 	 */
777 	if (*p->p_psargs == '\0' || hasnonprint(p->p_psargs)) {
778 		if (p->p_size == 0 && *p->p_psargs == '\0')
779 			strcpy(p->p_psargs, p->p_fname);
780 		else
781 			snprintf(p->p_psargs, sizeof p->p_psargs, "[ %.8s ]",
782 				p->p_fname);
783 		strcpy(p->p_comm, p->p_psargs);
784 	}
785 }
786 
787 /************************************************************************
788  * 				Execution				*
789  ************************************************************************/
790 
791 static void
putheader(void)792 putheader(void)
793 {
794 	struct output	*o;
795 	unsigned	i;
796 
797 	for (o = o0; o; o = o->o_nxt) {
798 		if (*o->o_nam == '\0') {
799 			for (i = 0; i < o->o_len; i++)
800 				putchar(' ');
801 		} else
802 			fputs(o->o_nam, stdout);
803 		if (o->o_nxt && o->o_typ != OU_SPACE)
804 			putchar(' ');
805 	}
806 	putchar('\n');
807 }
808 
809 /*
810  * Print a string, not exceeding the maximum output width, but with at least
811  * minimum columns. Drop nonprintable characters if printing to a terminal.
812  */
813 static int
putstr(int width,int minimum,int maximum,const char * s)814 putstr(int width, int minimum, int maximum, const char *s)
815 {
816 	wint_t	wc;
817 	int	written = 0, n, cw;
818 
819 	while (next(wc, s, n), cw = wcwidth(wc), cw = cw >= 0 ? cw : 1,
820 			wc != '\0' &&
821 			(maxcolumn == 0 || width + cw <= maxcolumn) &&
822 			(maximum == 0 || written + cw <= maximum)) {
823 		if (!ontty || (mb_cur_max > 1 ? iswprint(wc) : isprint(wc))) {
824 			while (n--) {
825 				putchar(*s);
826 				s++;
827 			}
828 			written += cw;
829 			width += cw;
830 		} else
831 			s += n;
832 	}
833 	while ((maxcolumn == 0 || width < maxcolumn) && written < minimum &&
834 			(maximum == 0 || written < maximum)) {
835 		putchar(' ');
836 		written++;
837 	}
838 	return written;
839 }
840 
841 /*
842  * Print a hexadecimal value with a maximum width, preceded by spaces
843  * if it is short.
844  *
845  * This is used for ADDR and WCHAN. Truncating the addresses to keep
846  * the display columns in order makes sense here since ADDR serves no
847  * known purpose anymore, and for WCHAN only the lower part of the
848  * address is relevant.
849  */
850 static int
putxd(int width,unsigned long val)851 putxd(int width, unsigned long val)
852 {
853 	const char	digits[] = "0123456789abcdef";
854 	char	*buf = alloca(width);
855 	int	m, n = width;
856 
857 	do {
858 		buf[--n] = digits[val & 0xf];
859 		val >>= 4;
860 	} while (val != 0 && n > 0);
861 	for (m = 0; m < n; m++)
862 		putchar(' ');
863 	do
864 		putchar(buf[n]);
865 	while (++n < width);
866 	return width;
867 }
868 
869 static int
putid(unsigned long val,unsigned len,struct trenod ** troot,char * (* func)(unsigned long))870 putid(unsigned long val, unsigned len, struct trenod **troot,
871 		char *(*func)(unsigned long))
872 {
873 	struct trenod	*tp;
874 	char	*str;
875 
876 	if ((tp = treget(val, troot)) == NULL) {
877 		if ((str = func(val)) != NULL) {
878 			tp = scalloc(1, sizeof *tp);
879 			tp->t_str = smalloc(strlen(str) + 1);
880 			strcpy(tp->t_str, str);
881 			tp->t_num = val;
882 			treput(tp, troot);
883 		} else
884 		numeric:
885 #ifdef	UCB
886 			return printf("%-*lu", len, val);
887 #else
888 			return printf("%*lu", len, val);
889 #endif
890 	}
891 	if (oflag && colwidth(tp->t_str) > len)
892 		goto numeric;
893 #ifdef	UCB
894 	return printf("%-*s", len, tp->t_str);
895 #else
896 	return printf("%*s", len, tp->t_str);
897 #endif
898 }
899 
900 static char *
get_username_from_pwd(unsigned long uid)901 get_username_from_pwd(unsigned long uid)
902 {
903 	struct passwd	*pwd;
904 
905 	if ((pwd = getpwuid(uid)) != NULL)
906 		return pwd->pw_name;
907 	return NULL;
908 }
909 
910 static char *
get_groupname_from_grp(unsigned long gid)911 get_groupname_from_grp(unsigned long gid)
912 {
913 	struct group	*grp;
914 
915 	if ((grp = getgrgid(gid)) != NULL)
916 		return grp->gr_name;
917 	return NULL;
918 }
919 
920 static int
putuser(uid_t uid,unsigned len)921 putuser(uid_t uid, unsigned len)
922 {
923 	static struct trenod	*u0;
924 
925 	return putid(uid, len, &u0, get_username_from_pwd);
926 }
927 
928 static int
putgroup(gid_t gid,unsigned len)929 putgroup(gid_t gid, unsigned len)
930 {
931 	static struct trenod	*g0;
932 
933 	return putid(gid, len, &g0, get_groupname_from_grp);
934 }
935 
936 static int
putdev(dev_type dev,unsigned len)937 putdev(dev_type dev, unsigned len)
938 {
939 	struct ditem	*d;
940 	char	*nam;
941 
942 	if (dev != (dev_type)PRNODEV) {
943 		if ((d = dlook(dev, d0, NULL)) != NULL)
944 			nam = d->d_str;
945 		else
946 			nam = "??";
947 	} else
948 		nam = "?";
949 	return printf("%-*s", len, nam);
950 }
951 
952 static int
time2(long t,unsigned len,int format)953 time2(long t, unsigned len, int format)
954 {
955 	char	buf[40];
956 	int	days, hours, minutes, seconds;
957 
958 	if (t < 0)
959 		t = 0;
960 	if (format == 2)
961 		snprintf(buf, sizeof buf, "%2lu:%02lu.%ld", t / 600,
962 				(t/10) % 60,
963 				t % 10);
964 	else if (format == 1)
965 		snprintf(buf, sizeof buf, "%2lu:%02lu", t / 60, t % 60);
966 	else {
967 		days = t / 86400;
968 		t %= 86400;
969 		hours = t / 3600;
970 		t %= 3600;
971 		minutes = t / 60;
972 		t %= 60;
973 		seconds = t;
974 		if (days)
975 			snprintf(buf, sizeof buf, "%02u-:%02u:%02u:%02u",
976 					days, hours, minutes, seconds);
977 		else
978 			snprintf(buf, sizeof buf, "%02u:%02u:%02u",
979 					hours, minutes, seconds);
980 	}
981 	return printf("%*s", len, buf);
982 }
983 
984 static int
time3(time_t t,unsigned len)985 time3(time_t t, unsigned len)
986 {
987 	struct tm	*tp;
988 	int	sz = 8, width = 0;
989 
990 	while (sz++ < len) {
991 		putchar(' ');
992 		width++;
993 	}
994 	tp = localtime(&t);
995 	if (now > t && now - t > 86400) {
996 		nl_item	val;
997 
998 		switch (tp->tm_mon) {
999 		case 0:		val = ABMON_1;	break;
1000 		case 1:		val = ABMON_2;	break;
1001 		case 2:		val = ABMON_3;	break;
1002 		case 3:		val = ABMON_4;	break;
1003 		case 4:		val = ABMON_5;	break;
1004 		case 5:		val = ABMON_6;	break;
1005 		case 6:		val = ABMON_7;	break;
1006 		case 7:		val = ABMON_8;	break;
1007 		case 8:		val = ABMON_9;	break;
1008 		case 9:		val = ABMON_10;	break;
1009 		case 10:	val = ABMON_11;	break;
1010 		case 11:	val = ABMON_12;	break;
1011 		default:	val = ABMON_12;	/* won't happen anyway */
1012 		}
1013 		width += printf("  %s %02u", nl_langinfo(val), tp->tm_mday);
1014 	} else
1015 		width += printf("%02u:%02u:%02u",
1016 				tp->tm_hour, tp->tm_min, tp->tm_sec);
1017 	return width;
1018 }
1019 
1020 #define	ZOMBIE(a)	(p->p_lstate[0] != 'Z' ? (a) : \
1021 				printf("%-*s", o->o_len, oflag ? "-" : " "))
1022 
1023 static void
outproc(struct proc * p)1024 outproc(struct proc *p)
1025 {
1026 	struct output	*o;
1027 	int	width = 0;
1028 
1029 	for (o = o0; o; o = o->o_nxt) {
1030 		switch (o->o_typ) {
1031 		case OU_USER:
1032 			width += putuser(p->p_euid, o->o_len);
1033 			break;
1034 		case OU_RUSER:
1035 			width += putuser(p->p_uid, o->o_len);
1036 			break;
1037 		case OU_RGROUP:
1038 			width += putgroup(p->p_gid, o->o_len);
1039 			break;
1040 		case OU_GROUP:
1041 			width += putgroup(p->p_egid, o->o_len);
1042 			break;
1043 		case OU_PID:
1044 			width += printf("%*u", o->o_len, (int)p->p_pid);
1045 			break;
1046 		case OU_PPID:
1047 			width += printf("%*u", o->o_len, (int)p->p_ppid);
1048 			break;
1049 		case OU_PGID:
1050 			width += printf("%*u", o->o_len, (int)p->p_pgid);
1051 			break;
1052 		case OU_LWP:
1053 		case OU_STID:
1054 			width += ZOMBIE(printf("%*u", o->o_len, (int)p->p_lwp));
1055 			break;
1056 		case OU_PCPU:
1057 			width += printf("%*.1f", o->o_len, p->p_pctcpu);
1058 			break;
1059 		case OU_VSZ:
1060 			width += ZOMBIE(printf("%*lu", o->o_len,
1061 						(long)p->p_size));
1062 			break;
1063 		case OU_NICE:
1064 			if (p->p_policy == SCHED_OTHER && p->p_pid != 0) {
1065 				width += ZOMBIE(printf("%*d", o->o_len,
1066 							(int)p->p_nice));
1067 			} else {
1068 				width += ZOMBIE(printf("%*.*s",
1069 							o->o_len, o->o_len,
1070 							p->p_clname));
1071 			}
1072 			break;
1073 		case OU_NLWP:
1074 			width += ZOMBIE(printf("%*u", o->o_len, p->p_nlwp));
1075 			break;
1076 		case OU_NTP:
1077 			width += ZOMBIE(printf("%*u", o->o_len,
1078 					p->p_nlwp > 1 ? p->p_nlwp : 0));
1079 			break;
1080 		case OU_TID:
1081 			width += ZOMBIE(printf("%*s", o->o_len, "-"));
1082 			break;
1083 		case OU_ETIME:
1084 			width += time2(now - p->p_start, o->o_len, 0);
1085 			break;
1086 		case OU_TTY:
1087 			width += ZOMBIE(putdev(p->p_ttydev, o->o_len));
1088 			break;
1089 		case OU_LTIME:
1090 		case OU_OTIME:
1091 			width += time2(p->p_time, o->o_len, 1);
1092 			break;
1093 		case OU_TIME:
1094 			width += time2(p->p_time, o->o_len, 0);
1095 			break;
1096 		case OU_ACCUTIME:
1097 			width += time2(p->p_accutime, o->o_len, 1);
1098 			break;
1099 		case OU_UTIME:
1100 			width += time2(p->p_utime, o->o_len, 2);
1101 			break;
1102 		case OU_KTIME:
1103 			width += time2(p->p_ktime, o->o_len, 2);
1104 			break;
1105 		case OU_COMM:
1106 			width += putstr(width, o->o_nxt ? o->o_len : 0, 0,
1107 					p->p_lstate[0] != 'Z' ?
1108 					p->p_comm : DEFUNCT);
1109 			break;
1110 		case OU_ARGS:
1111 			width += putstr(width, o->o_nxt ? o->o_len : 0, 0,
1112 					p->p_lstate[0] != 'Z' ?
1113 					p->p_psargs : DEFUNCT);
1114 			break;
1115 		case OU_F:
1116 			width += printf("%*o", o->o_len,
1117 					(int)(p->p_flag & 077));
1118 			break;
1119 		case OU_S:
1120 			width += printf("%*s", o->o_len, p->p_state);
1121 			break;
1122 		case OU_C:
1123 			width += printf("%*d", o->o_len, p->p_c);
1124 			break;
1125 		case OU_UID:
1126 			width += printf("%*u", o->o_len, (int)p->p_euid);
1127 			break;
1128 		case OU_RUID:
1129 			width += printf("%*u", o->o_len, (int)p->p_uid);
1130 			break;
1131 		case OU_GID:
1132 			width += printf("%*u", o->o_len, (int)p->p_egid);
1133 			break;
1134 		case OU_RGID:
1135 			width += printf("%*u", o->o_len, (int)p->p_gid);
1136 			break;
1137 		case OU_SID:
1138 			width += printf("%*u", o->o_len, (int)p->p_sid);
1139 			break;
1140 		case OU_CLASS:
1141 			width += ZOMBIE(printf("%*s", o->o_len, p->p_clname));
1142 			break;
1143 		case OU_PRI:
1144 			width += ZOMBIE(printf("%*d", o->o_len, (int)p->p_pri));
1145 			break;
1146 		case OU_OPRI:
1147 			width += ZOMBIE(printf("%*d", o->o_len,
1148 						(int)p->p_oldpri));
1149 			break;
1150 		case OU_PSR:
1151 			width += printf("%*d", o->o_len, (int)p->p_psr);
1152 			break;
1153 		case OU_ADDR:
1154 			width += ZOMBIE(putxd(o->o_len, (long)p->p_addr));
1155 			break;
1156 		case OU_OSZ:
1157 			width += ZOMBIE(printf("%*lu", o->o_len,
1158 						(long)p->p_osz));
1159 			break;
1160 		case OU_WCHAN:
1161 			if (p->p_lstate[0] == 'S' || p->p_lstate[0] == 'X' ||
1162 					p->p_lstate[0] == 'D')
1163 				width += putxd(o->o_len, (long)p->p_wchan);
1164 			else
1165 				width += printf("%*s", o->o_len, " ");
1166 			break;
1167 		case OU_STIME:
1168 			width += ZOMBIE(time3(p->p_start, o->o_len));
1169 			break;
1170 		case OU_RSS:
1171 			width += ZOMBIE(printf("%*lu", o->o_len,
1172 						(long)p->p_rssize));
1173 			break;
1174 		case OU_ORSS:
1175 		case OU_MRSZ:
1176 			width += ZOMBIE(printf("%*lu", o->o_len,
1177 						(long)p->p_orss));
1178 			break;
1179 		case OU_PMEM:
1180 			width += printf("%*.1f", o->o_len, p->p_pctmem);
1181 			break;
1182 		case OU_PFLTS:
1183 			width += printf("%*lu", o->o_len, p->p_pflts);
1184 			break;
1185 		case OU_BUFW:
1186 			width += printf("%*lu", o->o_len, p->p_bufw);
1187 			break;
1188 		case OU_BUFR:
1189 			width += printf("%*lu", o->o_len, p->p_bufr);
1190 			break;
1191 		case OU_MRCV:
1192 			width += printf("%*lu", o->o_len, p->p_mrcv);
1193 			break;
1194 		case OU_MSND:
1195 			width += printf("%*lu", o->o_len, p->p_msnd);
1196 			break;
1197 		case OU_FNAME:
1198 			width += putstr(width, o->o_nxt ? o->o_len : 0,
1199 #ifndef	UCB
1200 					p->p_lstate[0] != 'Z' ? 8 : 9,
1201 #else	/* UCB */
1202 					16,
1203 #endif	/* UCB */
1204 				p->p_lstate[0] != 'Z' ?
1205 				p->p_fname : DEFUNCT);
1206 			break;
1207 		case OU_SPACE:
1208 			if (o->o_len > 1)
1209 				width += printf("%*s", o->o_len - 1, "");
1210 			break;
1211 		}
1212 		if (o->o_nxt) {
1213 			putchar(' ');
1214 			width++;
1215 		}
1216 	}
1217 	putchar('\n');
1218 }
1219 
1220 #if !defined (__hpux) && !defined (_AIX) && !defined (__NetBSD__) && \
1221 	!defined (__OpenBSD__) && !defined (__APPLE__)
1222 
1223 #if defined (__linux__) || defined (__FreeBSD__) || defined (__DragonFly__)
1224 #define	GETVAL_REQ(a)		if ((v = getval(&cp, (a), ' ', 0)) == NULL) \
1225 					return STOP
1226 
1227 #define	GETVAL_OPT(a)		if ((v = getval(&cp, (a), ' ', 0)) == NULL) \
1228 					goto complete
1229 
1230 #define	GETVAL_COMMA(a)		if ((v = getval(&cp, (a), ' ', ',')) == NULL) \
1231 					return STOP
1232 #endif	/* __linux__ || __FreeBSD__ || __DragonFly__ */
1233 
1234 #if defined (__linux__)
1235 static void
get_linux_version(void)1236 get_linux_version(void)
1237 {
1238 	struct utsname	ut;
1239 	char	*x;
1240 	long	val;
1241 
1242 	if (uname(&ut) == 0) {
1243 		if ((val = strtol(ut.release, &x, 10)) > 0 &&
1244 				(*x == '.' || *x == '\0')) {
1245 			linux_version[0] = val;
1246 			if (*x && (val = strtol(&x[1], &x, 10)) >= 0 &&
1247 					(*x == '.' || *x == '\0')) {
1248 				linux_version[1] = val;
1249 				if (*x && (val = strtol(&x[1], &x, 10)) >= 0)
1250 					linux_version[2] = val;
1251 			}
1252 		}
1253 	}
1254 }
1255 
1256 static time_t
sysup(void)1257 sysup(void)
1258 {
1259 	FILE	*fp;
1260 	char	buf[32];
1261 	char	*cp;
1262 	union value	*v;
1263 	time_t	s = 0;
1264 
1265 	if ((fp = fopen("uptime", "r")) == NULL)
1266 		return 0;
1267 	if (fread(buf, 1, sizeof buf, fp) > 0) {
1268 		cp = buf;
1269 		if ((v = getval(&cp, VT_ULONG, '.', 0)) != NULL)
1270 			s = v->v_ulong;
1271 	}
1272 	fclose(fp);
1273 	return s;
1274 }
1275 
1276 static unsigned long
getmem(void)1277 getmem(void)
1278 {
1279 	FILE	*fp;
1280 	char	line[LINE_MAX];
1281 	char	*cp;
1282 	union value	*v;
1283 	unsigned long	mem = 1;
1284 
1285 	if ((fp = fopen("meminfo", "r")) == NULL)
1286 		return 0;
1287 	while (fgets(line, sizeof line, fp) != NULL) {
1288 		if (strncmp(line, "MemTotal:", 9) == 0) {
1289 			cp = &line[9];
1290 			while (isspace(*cp))
1291 				cp++;
1292 			if ((v = getval(&cp, VT_ULONG, ' ', 0)) != NULL)
1293 				mem = v->v_ulong;
1294 			break;
1295 		}
1296 	}
1297 	fclose(fp);
1298 	return mem;
1299 }
1300 
1301 static time_t
hz2time(long val,int mult)1302 hz2time(long val, int mult)
1303 {
1304 	long long	t;
1305 
1306 	t = val * mult / hz;
1307 	if ((val * mult) % hz >= (hz >> 1))
1308 		t++;
1309 	return t;
1310 }
1311 
1312 static void	(*compute_priority)(struct proc *);
1313 
1314 /*
1315  * Calculate reasonable values for priority fields using all we can get
1316  * from /proc in Linux 2.4: a crippled counter (in p->intpri) and the
1317  * nice value.
1318  */
1319 static void
compute_priority_old(struct proc * p)1320 compute_priority_old(struct proc *p)
1321 {
1322 	static int	def_counter, scale, max_goodness;
1323 	int	full_counter, counter, goodness;
1324 
1325 	/*
1326 	 * This is based on the computations in linux/sched.c, 2.4.19.
1327 	 */
1328 	if (def_counter == 0) {
1329 		def_counter = 10 * hz / 100;
1330 		if (hz < 200)
1331 			scale = 4;
1332 		else if (hz < 400)
1333 			scale = 3;
1334 		else if (hz < 800)
1335 			scale = 2;
1336 		else if (hz < 1600)
1337 			scale = 1;
1338 		else
1339 			scale = 0;
1340 		max_goodness = (((40 << 3) >> scale) + 2) + 40;
1341 	}
1342 	full_counter = (((40 - p->p_nice) << 3) >> scale) + 2;
1343 	/*
1344 	 * Try to reverse the computation in linux/fs/proc/array.c,
1345 	 * 2.4.19.
1346 	 */
1347 	counter = (def_counter * (20 - p->p_intpri)) / 10;
1348 	/*
1349 	 * This can apparently happen if the command is in its first
1350 	 * timeslice after a lower nice value has been set.
1351 	 */
1352 	if (counter > full_counter)
1353 		counter = full_counter;
1354 	/*
1355 	 * This approximation is even worse, as we cannot know about
1356 	 * PROC_CHANGE_PENALTY and MM.
1357 	 */
1358 	if ((goodness = counter) > 0)
1359 		goodness += 40 - p->p_nice;
1360 	/*
1361 	 * Keep all priorities for -c below 60 and with higher
1362 	 * priorities for higher numbers.
1363 	 */
1364 	p->p_pri = goodness * 59 / max_goodness;
1365 	/*
1366 	 * Old-style priorities start at 60 and have lower numbers
1367 	 * for higher priorities.
1368 	 */
1369 	p->p_oldpri = 119 - p->p_pri;
1370 	/*
1371 	 * Our counter emulation can be wrong by 2 in the worst
1372 	 * case. If the process is not currently on a run queue,
1373 	 * assume it did not use the CPU at all.
1374 	 */
1375 	p->p_c = full_counter - counter;
1376 	if (p->p_lstate[0] != 'R' && p->p_c <= 2)
1377 		p->p_c = 0;
1378 	/*
1379 	 * The value for C still depends on the nice value. Make 80
1380 	 * the highest possible C value for all nice values.
1381 	 */
1382 	p->p_c *= 80 / full_counter;
1383 }
1384 
1385 /*
1386  * Priority calculation for Linux 2.5 and (hopefully) above, based
1387  * on 2.5.31. This supplies a sensible priority value, but originally
1388  * nothing we could use to compute "CPU usage for scheduling". More
1389  * recent 2.6 versions have a SleepAVG field in the "status" file.
1390  */
1391 static void
compute_priority_new(struct proc * p)1392 compute_priority_new(struct proc *p)
1393 {
1394 	if (p->p_rtpri) {
1395 		p->p_pri = 100 + p->p_rtpri;
1396 		p->p_oldpri = 60 - (p->p_rtpri >> 1);
1397 	} else {
1398 		p->p_pri = 40 - p->p_intpri;
1399 		p->p_oldpri = 60 + p->p_intpri + (p->p_intpri >> 1);
1400 	}
1401 }
1402 
1403 static void
compute_various(struct proc * p)1404 compute_various(struct proc *p)
1405 {
1406 	/*
1407 	 * All dead processes are considered zombies by us.
1408 	 */
1409 	if (p->p_lstate[0] == 'X')
1410 		p->p_lstate[0] = 'Z';
1411 	/*
1412 	 * Set System V style status. There seems no method to
1413 	 * determine 'O' (not only on run queue, but actually
1414 	 * running).
1415 	 */
1416 	if (p->p_lstate[0] == 'D' || p->p_lstate[0] == 'W')
1417 		p->p_state[0] = 'S';
1418 	else
1419 		p->p_state[0] = p->p_lstate[0];
1420 #ifdef	notdef
1421 	/*
1422 	 * Process flags vary too much between real and vendor kernels
1423 	 * and there's no method to distinguish them - don't use.
1424 	 */
1425 	if (p->p_lflag & 0x00000002)		/* PF_STARTING */
1426 		p->p_state[0] = 'I';
1427 	else if (p->p_lflag & 0x00000800)	/* PF_MEMALLOC */
1428 		p->p_state[0] = 'X';
1429 #endif	/* notdef */
1430 	/*
1431 	 * Set v7 / System III style flags.
1432 	 */
1433 	if (p->p_lstate[0] != 'Z') {
1434 		if (p->p_flag & FL_SYS || p->p_rssize != 0)
1435 			p->p_flag |= FL_LOAD;	/* cf. statm processing */
1436 		else
1437 			p->p_flag |= FL_SWAP;	/* no rss -> swapped */
1438 		if (p->p_lstate[0] == 'D') {
1439 			p->p_flag |= FL_LOCK;
1440 			p->p_flag &= ~FL_SWAP;
1441 		} else if (p->p_lstate[0] == 'W')
1442 			p->p_flag |= FL_SWAP;
1443 		/*if (p->p_lflag & 0x10)		obsolete, doesn't work
1444 			p->p_flag |= FL_TRC;*/
1445 	}
1446 }
1447 
1448 static enum okay
getproc_stat(struct proc * p,pid_t expected_pid)1449 getproc_stat(struct proc *p, pid_t expected_pid)
1450 {
1451 	static char	*buf;
1452 	static size_t	buflen;
1453 	union value	*v;
1454 	FILE	*fp;
1455 	char	*cp, *cq, *ce;
1456 	size_t	sz, sc;
1457 	unsigned long	lval;
1458 	/*
1459 	 * There is no direct method to determine if something is a system
1460 	 * process. We consider a process a system process if a certain set
1461 	 * of criteria is entirely zero.
1462 	 */
1463 	unsigned long	sysfl = 0;
1464 
1465 	if ((fp = fopen("stat", "r")) == NULL)
1466 		return STOP;
1467 	for (cp = buf; ;) {
1468 		const unsigned	chunk = 32;
1469 
1470 		if (buflen < (sz = cp - buf + chunk)) {
1471 			sc = cp - buf;
1472 			buf = srealloc(buf, buflen = sz);
1473 			cp = &buf[sc];
1474 		}
1475 		if ((sz = fread(cp, 1, chunk, fp)) < chunk) {
1476 			ce = &cp[sz - 1];
1477 			break;
1478 		}
1479 		cp += chunk;
1480 	}
1481 	fclose(fp);
1482 	if (*ce != '\n')
1483 		return STOP;
1484 	*ce-- = '\0';
1485 	cp = buf;
1486 	/* pid */
1487 	GETVAL_REQ(VT_INT);
1488 	if ((p->p_pid = v->v_int) != expected_pid)
1489 		return STOP;
1490 	if (*cp++ != '(')
1491 		return STOP;
1492 	for (cq = ce; cq >= cp && *cq != ')'; cq--);
1493 	if (cq < cp)
1494 		return STOP;
1495 	*cq = '\0';
1496 	strncpy(p->p_fname, cp, sizeof p->p_fname);
1497 	p->p_fname[sizeof p->p_fname - 1] = '\0';
1498 	cp = &cq[1];
1499 	while (isspace(*cp))
1500 		cp++;
1501 	/* state */
1502 	GETVAL_REQ(VT_CHAR);
1503 	p->p_lstate[0] = v->v_char;
1504 	sysfl |= v->v_char == 'Z';
1505 	/* ppid */
1506 	GETVAL_REQ(VT_INT);
1507 	p->p_ppid = v->v_int;
1508 	/* pgrp */
1509 	GETVAL_REQ(VT_INT);
1510 	p->p_pgid = v->v_int;
1511 	/* session */
1512 	GETVAL_REQ(VT_INT);
1513 	p->p_sid = v->v_int;
1514 	/* tty_nr */
1515 	GETVAL_REQ(VT_INT);
1516 	p->p_ttydev = v->v_int;
1517 	sysfl |= v->v_int;
1518 	/* tty_pgrp */
1519 	GETVAL_REQ(VT_INT);
1520 	/* flags */
1521 	GETVAL_REQ(VT_ULONG);
1522 	p->p_lflag = v->v_ulong;
1523 	/* minflt */
1524 	GETVAL_REQ(VT_ULONG);
1525 	/* cminflt */
1526 	GETVAL_REQ(VT_ULONG);
1527 	/* majflt */
1528 	GETVAL_REQ(VT_ULONG);
1529 	p->p_pflts = v->v_ulong;
1530 	/* cmajflt */
1531 	GETVAL_REQ(VT_ULONG);
1532 	/* utime */
1533 	GETVAL_REQ(VT_ULONG);
1534 	lval = v->v_ulong;
1535 	p->p_utime = hz2time(lval, 10);
1536 	sysfl |= v->v_ulong;
1537 	/* stime */
1538 	GETVAL_REQ(VT_ULONG);
1539 	p->p_ktime = hz2time(v->v_ulong, 10);
1540 	lval += v->v_ulong;
1541 	p->p_time = hz2time(lval, 1);
1542 	/* cutime */
1543 	GETVAL_REQ(VT_LONG);
1544 	lval += v->v_ulong;
1545 	/* cstime */
1546 	GETVAL_REQ(VT_LONG);
1547 	lval += v->v_ulong;
1548 	p->p_accutime += hz2time(lval, 1);
1549 	/* priority */
1550 	GETVAL_REQ(VT_LONG);
1551 	p->p_intpri = v->v_long;
1552 	/* nice */
1553 	GETVAL_REQ(VT_LONG);
1554 	p->p_nice = v->v_long + 20;
1555 	/* timeout */
1556 	GETVAL_REQ(VT_LONG);
1557 	/* itrealvalue */
1558 	GETVAL_REQ(VT_LONG);
1559 	/* starttime */
1560 	GETVAL_REQ(VT_ULONG);
1561 	p->p_start = hz2time(v->v_ulong, 1) + now - uptime;
1562 	/* vsize */
1563 	GETVAL_REQ(VT_ULONG);
1564 	p->p_size = (v->v_ulong >> 10);
1565 	p->p_osz = v->v_ulong / pagesize;
1566 	sysfl |= v->v_ulong;
1567 	/* rss */
1568 	GETVAL_REQ(VT_LONG);
1569 	p->p_orss = v->v_long;
1570 	p->p_rssize = v->v_long * kbytes_per_page;
1571 	sysfl |= v->v_ulong;
1572 	/* rlim */
1573 	GETVAL_REQ(VT_ULONG);
1574 	/* startcode */
1575 	GETVAL_REQ(VT_ULONG);
1576 	p->p_addr = v->v_ulong;
1577 	sysfl |= v->v_ulong;
1578 	/* endcode */
1579 	GETVAL_REQ(VT_ULONG);
1580 	sysfl |= v->v_ulong;
1581 	/* startstack */
1582 	GETVAL_REQ(VT_ULONG);
1583 	sysfl |= v->v_ulong;
1584 	/* kstkesp */
1585 	GETVAL_REQ(VT_ULONG);
1586 	/* kstkeip */
1587 	GETVAL_REQ(VT_ULONG);
1588 	/* signal */
1589 	GETVAL_REQ(VT_ULONG);
1590 	/* blocked */
1591 	GETVAL_REQ(VT_ULONG);
1592 	/* sigignore */
1593 	GETVAL_REQ(VT_ULONG);
1594 	/* sigcatch */
1595 	GETVAL_REQ(VT_ULONG);
1596 	/* wchan */
1597 	GETVAL_REQ(VT_ULONG);
1598 	p->p_wchan = v->v_ulong;
1599 	/*
1600 	 * These appeared in later Linux versions, so they are not
1601 	 * required to be present.
1602 	 */
1603 	p->p_policy = -1;	/* initialize to invalid values */
1604 	/* nswap */
1605 	GETVAL_OPT(VT_ULONG);
1606 	/* cnswap */
1607 	GETVAL_OPT(VT_ULONG);
1608 	/* exit_signal */
1609 	GETVAL_OPT(VT_INT);
1610 	/* processor */
1611 	GETVAL_OPT(VT_INT);
1612 	p->p_psr = v->v_int;
1613 	/* rt_priority */
1614 	GETVAL_OPT(VT_ULONG);
1615 	p->p_rtpri = v->v_ulong;
1616 	/* policy */
1617 	GETVAL_OPT(VT_ULONG);
1618 	p->p_policy = v->v_ulong;
1619 complete:
1620 	if (sysfl == 0)
1621 		p->p_flag |= FL_SYS;
1622 	compute_various(p);
1623 	return OKAY;
1624 }
1625 
1626 static enum okay
getproc_scheduler(struct proc * p)1627 getproc_scheduler(struct proc *p)
1628 {
1629 	struct sched_param	s;
1630 
1631 	if (p->p_policy == -1)	/* Linux 2.4 and below */
1632 		p->p_policy = sched_getscheduler(p->p_pid);
1633 	switch (p->p_policy) {
1634 	case SCHED_FIFO:
1635 	case SCHED_RR:
1636 		switch (p->p_policy) {
1637 		case SCHED_FIFO:	p->p_clname = "FF"; break;
1638 #ifdef	S42
1639 		case SCHED_RR:		p->p_clname = "FP"; break;
1640 #else
1641 		case SCHED_RR:		p->p_clname = "RT"; break;
1642 #endif
1643 		}
1644 		if (p->p_rtpri == 0 && sched_getparam(p->p_pid, &s) == 0) {
1645 			p->p_rtpri = s.sched_priority;
1646 			/* Linux 2.4 and below */
1647 			p->p_pri = 100 + s.sched_priority;
1648 		}
1649 		break;
1650 	case SCHED_OTHER:
1651 		p->p_clname = "TS";
1652 		break;
1653 #ifdef	SCHED_BATCH
1654 	case SCHED_BATCH:
1655 		p->p_clname = "B";
1656 		break;
1657 #endif	/* SCHED_BATCH */
1658 #ifdef	SCHED_ISO
1659 	case SCHED_ISO:
1660 		p->p_clname = "ISO";
1661 		break;
1662 #endif	/* SCHED_ISO */
1663 	default:
1664 		p->p_clname =  "??";
1665 	}
1666 	compute_priority(p);
1667 	return OKAY;
1668 }
1669 
1670 static enum okay
getproc_cmdline(struct proc * p)1671 getproc_cmdline(struct proc *p)
1672 {
1673 	FILE	*fp;
1674 	char	*cp, *cq, *ce;
1675 	int	hadzero = 0, c;
1676 
1677 	if ((fp = fopen("cmdline", "r")) != NULL) {
1678 		cp = p->p_psargs;
1679 		cq = p->p_comm;
1680 		ce = cp + sizeof p->p_psargs - 1;
1681 		while (cp < ce && (c = getc(fp)) != EOF) {
1682 			if (c != '\0') {
1683 				if (hadzero) {
1684 					*cp++ = ' ';
1685 					if (cp == ce)
1686 						break;
1687 					hadzero = 0;
1688 				}
1689 				*cp++ = c;
1690 				if (cq)
1691 					*cq++ = c;
1692 			} else {
1693 				hadzero = 1;
1694 				if (cq) {
1695 					*cq = c;
1696 					cq = NULL;
1697 				}
1698 			}
1699 		}
1700 		*cp = '\0';
1701 		if (cq)
1702 			*cq = '\0';
1703 		fclose(fp);
1704 	}
1705 	return OKAY;
1706 }
1707 
1708 static enum okay
getproc_status(struct proc * p)1709 getproc_status(struct proc *p)
1710 {
1711 	char	line[LINE_MAX];
1712 	union value	*v;
1713 	FILE	*fp;
1714 	char	*cp;
1715 	int	scanr;
1716 
1717 	if ((fp = fopen("status", "r")) == NULL)
1718 		return STOP;
1719 	scanr = 0;
1720 	while (fgets(line, sizeof line, fp) != NULL) {
1721 		if (strncmp(line, "Uid:", 4) == 0) {
1722 			cp = &line[4];
1723 			while (isspace(*cp))
1724 				cp++;
1725 			if ((v = getval(&cp, VT_INT, ' ', 0)) == NULL) {
1726 				fclose(fp);
1727 				return STOP;
1728 			}
1729 			p->p_uid = v->v_int;
1730 			if ((v = getval(&cp, VT_INT, ' ', 0)) == NULL) {
1731 				fclose(fp);
1732 				return STOP;
1733 			}
1734 			p->p_euid = v->v_int;
1735 			scanr++;
1736 		} else if (strncmp(line, "Gid:", 4) == 0) {
1737 			cp = &line[4];
1738 			while (isspace(*cp))
1739 				cp++;
1740 			if ((v = getval(&cp, VT_INT, ' ', 0)) == NULL) {
1741 				fclose(fp);
1742 				return STOP;
1743 			}
1744 			p->p_gid = v->v_int;
1745 			if ((v = getval(&cp, VT_INT, ' ', 0)) == NULL) {
1746 				fclose(fp);
1747 				return STOP;
1748 			}
1749 			p->p_egid = v->v_int;
1750 			scanr++;
1751 		} else if (strncmp(line, "Threads:", 8) == 0) {
1752 			cp = &line[8];
1753 			while (isspace(*cp))
1754 				cp++;
1755 			if ((v = getval(&cp, VT_INT, ' ', 0)) == NULL) {
1756 				fclose(fp);
1757 				return STOP;
1758 			}
1759 			p->p_nlwp = v->v_int;
1760 		} else if (strncmp(line, "Pid:", 4) == 0) {
1761 			cp = &line[4];
1762 			while (isspace(*cp))
1763 				cp++;
1764 			if ((v = getval(&cp, VT_INT, ' ', 0)) == NULL) {
1765 				fclose(fp);
1766 				return STOP;
1767 			}
1768 			p->p_lwp = v->v_int;
1769 		} else if (strncmp(line, "SleepAVG:", 9) == 0) {
1770 			cp = &line[9];
1771 			while (isspace(*cp))
1772 				cp++;
1773 			if ((v = getval(&cp, VT_INT, '%', 0)) == NULL) {
1774 				fclose(fp);
1775 				return STOP;
1776 			}
1777 			p->p_c = (100 - v->v_int) * 80 / 100;
1778 		}
1779 	}
1780 	fclose(fp);
1781 	if (scanr != 2)
1782 		return STOP;
1783 	return OKAY;
1784 }
1785 
1786 static enum okay
getproc_statm(struct proc * p)1787 getproc_statm(struct proc *p)
1788 {
1789 	char	line[LINE_MAX];
1790 	union value	*v;
1791 	FILE	*fp;
1792 	char	*cp;
1793 	unsigned long	trs, drs, dt;
1794 
1795 	if ((fp = fopen("statm", "r")) == NULL)
1796 		return OKAY;	/* not crucial */
1797 	if (fgets(line, sizeof line, fp) != NULL) {
1798 		cp = line;
1799 		if ((v = getval(&cp, VT_LONG, ' ', 0)) == NULL)	/* size */
1800 			goto out;
1801 		if ((v = getval(&cp, VT_LONG, ' ', 0)) == NULL)	/* resident */
1802 			goto out;
1803 		if ((v = getval(&cp, VT_LONG, ' ', 0)) == NULL)	/* share */
1804 			goto out;
1805 		if ((v = getval(&cp, VT_LONG, ' ', 0)) == NULL)	/* trs */
1806 			goto out;
1807 		trs = v->v_long;
1808 		if ((v = getval(&cp, VT_LONG, ' ', 0)) == NULL)	/* drs */
1809 			goto out;
1810 		drs = v->v_long;
1811 		if ((v = getval(&cp, VT_LONG, ' ', 0)) == NULL)	/* lrs */
1812 			goto out;
1813 		if ((v = getval(&cp, VT_LONG, ' ', 0)) == NULL)	/* dt */
1814 			goto out;
1815 		dt = v->v_long;
1816 		/*
1817 		 * A process is considered to be swapped out if it has
1818 		 * neither resident non-library text, data, nor dirty
1819 		 * pages. A system process is always considered to be
1820 		 * in core.
1821 		 */
1822 		if (trs + drs + dt == 0 &&
1823 				(p->p_flag&(FL_LOAD|FL_SYS|FL_LOCK))==FL_LOAD) {
1824 			p->p_flag &= ~FL_LOAD;
1825 			p->p_flag |= FL_SWAP;
1826 		}
1827 	}
1828 out:	fclose(fp);
1829 	return OKAY;
1830 }
1831 
1832 static enum okay
getproc(const char * dir,struct proc * p,pid_t expected_pid,pid_t lwp)1833 getproc(const char *dir, struct proc *p, pid_t expected_pid, pid_t lwp)
1834 {
1835 	enum okay	result;
1836 
1837 	memset(p, 0, sizeof *p);
1838 	if (chdir(dir) == 0) {
1839 		if ((result = getproc_stat(p, expected_pid)) == OKAY)
1840 			if ((result = getproc_scheduler(p)) == OKAY)
1841 				if ((result = getproc_cmdline(p)) == OKAY)
1842 					if ((result= getproc_status(p)) == OKAY)
1843 						result = getproc_statm(p);
1844 		chdir_to_proc();
1845 	} else
1846 		result = STOP;
1847 	return result;
1848 }
1849 
1850 static enum okay
getLWPs(const char * dir,struct proc * p,pid_t expected_pid)1851 getLWPs(const char *dir, struct proc *p, pid_t expected_pid)
1852 {
1853 	DIR	*Dp;
1854 	struct dirent	*dp;
1855 	unsigned long	val;
1856 	char	*x;
1857 	int	fd;
1858 
1859 	if (chdir(dir) == 0 &&
1860 			(fd = open("task", O_RDONLY)) >= 0 &&
1861 			fchdir(fd) == 0 &&
1862 			(Dp = opendir(".")) != NULL) {
1863 		while ((dp = readdir(Dp)) != NULL) {
1864 			if (dp->d_name[0] == '.' && (dp->d_name[1]=='\0' ||
1865 					(dp->d_name[1]=='.' &&
1866 					 dp->d_name[2]=='\0')))
1867 			continue;
1868 			val = strtoul(dp->d_name, &x, 10);
1869 			if (*x != 0)
1870 				continue;
1871 			if (fchdir(fd) < 0) {
1872 				fprintf(stderr,
1873 					"%s: cannot chdir to %s/%s/task\n",
1874 					progname, PROCDIR, dir);
1875 				errcnt = 1;
1876 				break;
1877 			}
1878 			if (getproc(dp->d_name, p, val, val) == OKAY) {
1879 				postproc(p);
1880 				if (selectproc(p) == OKAY) {
1881 					p->p_pid = expected_pid;
1882 					outproc(p);
1883 				}
1884 			}
1885 		}
1886 		closedir(Dp);
1887 		close(fd);
1888 		return OKAY;
1889 	} else {
1890 		chdir_to_proc();
1891 		return STOP;
1892 	}
1893 }
1894 
1895 #elif defined (__FreeBSD__) || defined (__DragonFly__)
1896 
1897 static unsigned long
getmem(void)1898 getmem(void)
1899 {
1900 	return 0;
1901 }
1902 
1903 static enum okay
getproc_status(struct proc * p,pid_t expected_pid)1904 getproc_status(struct proc *p, pid_t expected_pid)
1905 {
1906 	static char	*buf;
1907 	static size_t	buflen;
1908 	union value	*v;
1909 	FILE	*fp;
1910 	char	*cp, *cq, *ce;
1911 	size_t	sz, sc;
1912 	int	mj, mi;
1913 
1914 	if ((fp = fopen("status", "r")) == NULL)
1915 		return STOP;
1916 	for (cp = buf; ;) {
1917 		const unsigned	chunk = 32;
1918 
1919 		if (buflen < (sz = cp - buf + chunk)) {
1920 			sc = cp - buf;
1921 			buf = srealloc(buf, buflen = sz);
1922 			cp = &buf[sc];
1923 		}
1924 		if ((sz = fread(cp, 1, chunk, fp)) < chunk) {
1925 			ce = &cp[sz - 1];
1926 			break;
1927 		}
1928 		cp += chunk;
1929 	}
1930 	fclose(fp);
1931 	if (*ce != '\n')
1932 		return STOP;
1933 	*ce-- = '\0';
1934 	cp = buf;
1935 	cq = p->p_fname;
1936 	while (*cp != ' ') {
1937 		if (cq - p->p_fname < sizeof p->p_fname - 1) {
1938 			if (cp[0] == '\\' && isdigit(cp[1]) &&
1939 					isdigit(cp[2]) && isdigit(cp[3])) {
1940 				*cq++ = cp[3] - '0' +
1941 					(cp[2] - '0' << 3) +
1942 					(cp[1] - '0' << 6);
1943 				cp += 4;
1944 			} else
1945 				*cq++ = *cp++;
1946 		} else
1947 			cp++;
1948 	}
1949 	*cq = '\0';
1950 	while (*cp == ' ')
1951 		cp++;
1952 	GETVAL_REQ(VT_INT);
1953 	p->p_pid = v->v_int;
1954 	GETVAL_REQ(VT_INT);
1955 	p->p_ppid = v->v_int;
1956 	GETVAL_REQ(VT_INT);
1957 	p->p_pgid = v->v_int;
1958 	GETVAL_REQ(VT_INT);
1959 	p->p_sid = v->v_int;
1960 	if (isdigit(*cp)) {
1961 		GETVAL_COMMA(VT_INT);
1962 		mj = v->v_int;
1963 		GETVAL_REQ(VT_INT);
1964 		mi = v->v_int;
1965 		if (mj != -1 || mi != -1)
1966 			p->p_ttydev = makedev(mj, mi);
1967 	} else {
1968 		struct stat	st;
1969 		char	*dev;
1970 		cq = cp;
1971 		while (*cp != ' ') cp++;
1972 		*cp = '\0';
1973 		dev = smalloc(cp - cq + 8);
1974 		strcpy(dev, "/dev/");
1975 		strcpy(&dev[5], cq);
1976 		if (stat(dev, &st) < 0)
1977 			p->p_ttydev = PRNODEV;
1978 		else
1979 			p->p_ttydev = st.st_rdev;
1980 		free(dev);
1981 		*cp = ' ';
1982 		while (*cp == ' ') cp++;
1983 	}
1984 	while (*cp != ' ') cp++; while (*cp == ' ') cp++;
1985 	/* skip flags */
1986 	GETVAL_COMMA(VT_LONG);
1987 	p->p_start = v->v_long;
1988 	/* microseconds */
1989 	GETVAL_REQ(VT_LONG);
1990 	GETVAL_COMMA(VT_LONG);
1991 	p->p_time = v->v_long;
1992 	p->p_utime = v->v_long;
1993 	/* microseconds */
1994 	GETVAL_REQ(VT_LONG);
1995 	p->p_utime += v->v_long / 100000;
1996 	GETVAL_COMMA(VT_LONG);
1997 	p->p_time += v->v_long;
1998 	p->p_ktime = v->v_long;
1999 	p->p_accutime = p->p_time;
2000 	/* microseconds */
2001 	GETVAL_REQ(VT_LONG);
2002 	p->p_ktime += v->v_long / 100000;
2003 	if (strncmp(cp, "nochan ", 7) == 0)
2004 		p->p_state[0] = p->p_lstate[0] = 'R';
2005 	else
2006 		p->p_state[0] = p->p_lstate[0] = 'S';
2007 	while (*cp != ' ') {
2008 		if (p->p_state[0] == 'S')
2009 			p->p_wchan |= *cp << (*cp&30);	/* fake */
2010 		cp++;
2011 	}
2012 	while (*cp == ' ') cp++;
2013 	GETVAL_REQ(VT_INT);
2014 	p->p_euid = v->v_int;
2015 	GETVAL_REQ(VT_INT);
2016 	p->p_uid = v->v_int;
2017 	GETVAL_COMMA(VT_INT);
2018 	p->p_gid = v->v_int;
2019 	GETVAL_COMMA(VT_INT);
2020 	p->p_egid = v->v_int;
2021 	return OKAY;
2022 }
2023 
2024 static enum okay
getproc_cmdline(struct proc * p)2025 getproc_cmdline(struct proc *p)
2026 {
2027 	FILE	*fp;
2028 	char	*cp, *ce;
2029 	int	hadzero = 0, c;
2030 
2031 	if ((fp = fopen("cmdline", "r")) != NULL) {
2032 		cp = p->p_psargs;
2033 		ce = cp + sizeof p->p_psargs - 1;
2034 		while (cp < ce && (c = getc(fp)) != EOF) {
2035 			if (c != '\0') {
2036 				if (hadzero) {
2037 					*cp++ = ' ';
2038 					if (cp == ce)
2039 						break;
2040 					hadzero = 0;
2041 				}
2042 				*cp++ = c;
2043 			} else {
2044 				hadzero = 1;
2045 			}
2046 		}
2047 		*cp = '\0';
2048 		fclose(fp);
2049 	}
2050 	if (*p->p_psargs == '\0' && p->p_size == 0)
2051 		strcpy(p->p_psargs, p->p_fname);
2052 	return OKAY;
2053 }
2054 
2055 static void
priocomp(struct proc * p)2056 priocomp(struct proc *p)
2057 {
2058 	static int	once;
2059 	static int	ranges[3][2];
2060 	int	*cur;
2061 
2062 	if (once++ == 0) {
2063 		ranges[0][0] = sched_get_priority_min(SCHED_OTHER);
2064 		ranges[0][1] = sched_get_priority_max(SCHED_OTHER);
2065 		ranges[1][0] = sched_get_priority_min(SCHED_FIFO);
2066 		ranges[1][1] = sched_get_priority_max(SCHED_FIFO);
2067 		ranges[2][0] = sched_get_priority_min(SCHED_RR);
2068 		ranges[3][1] = sched_get_priority_max(SCHED_RR);
2069 	}
2070 	switch (p->p_policy) {
2071 	case SCHED_OTHER:
2072 		cur = ranges[0];
2073 		break;
2074 	case SCHED_FIFO:
2075 		cur = ranges[1];
2076 		break;
2077 	case SCHED_RR:
2078 		cur = ranges[2];
2079 		break;
2080 	default:
2081 		return;
2082 	}
2083 	switch (p->p_policy) {
2084 	case SCHED_OTHER:
2085 		p->p_nice = getpriority(PRIO_PROCESS, p->p_pid) + 20;
2086 		break;
2087 	case SCHED_FIFO:
2088 	case SCHED_RR:
2089 		p->p_pri = ((double)p->p_intpri - cur[0]) / (cur[1] - cur[0]) *
2090 			100 + 60;
2091 	}
2092 }
2093 
2094 static enum okay
getproc_map(struct proc * p)2095 getproc_map(struct proc *p)
2096 {
2097 	FILE	*fp;
2098 	long	start, end, resident;
2099 	int	c;
2100 
2101 	if ((fp = fopen("map", "r")) == NULL)
2102 		return OKAY;
2103 	while (fscanf(fp, "0x%lx 0x%lx %ld", &start, &end, &resident) == 3) {
2104 		if (p->p_addr == 0)
2105 			p->p_addr = start;
2106 		while ((c = getc(fp)) != EOF && c != '\n');
2107 		p->p_size += (end - start) / 1024;
2108 		p->p_orss += resident;
2109 	}
2110 	p->p_osz = p->p_size / (pagesize / 1024);
2111 	p->p_rssize = p->p_orss * (pagesize / 1024);
2112 	fclose(fp);
2113 	return OKAY;
2114 }
2115 
2116 static enum okay
getproc_scheduler(struct proc * p)2117 getproc_scheduler(struct proc *p)
2118 {
2119 	struct sched_param	s;
2120 
2121 	switch (p->p_policy = sched_getscheduler(p->p_pid)) {
2122 	case SCHED_FIFO:
2123 		p->p_clname = "FF";
2124 		break;
2125 	case SCHED_RR:
2126 #ifdef	S42
2127 		p->p_clname = "FP";
2128 #else
2129 		p->p_clname = "RT";
2130 #endif
2131 		break;
2132 	case SCHED_OTHER:
2133 		p->p_clname = "TS";
2134 		break;
2135 	default:
2136 		p->p_clname = "??";
2137 	}
2138 	if (sched_getparam(p->p_pid, &s) == 0)
2139 		p->p_intpri = s.sched_priority;
2140 	priocomp(p);
2141 	return OKAY;
2142 }
2143 
2144 static enum okay
getproc_kvm(struct proc * p)2145 getproc_kvm(struct proc *p)
2146 {
2147 	struct kinfo_proc	*kp;
2148 	int	c;
2149 
2150 	if (myeuid != 0)
2151 		return OKAY;
2152 	if (kv == NULL) {
2153 		char	err[_POSIX2_LINE_MAX];
2154 		if ((kv = kvm_open(NULL, NULL, NULL, O_RDONLY, err)) == NULL)
2155 			return OKAY;
2156 	}
2157 	if ((kp = kvm_getprocs(kv, KERN_PROC_PID, p->p_pid, &c)) == NULL)
2158 		return OKAY;
2159 #if defined (__DragonFly__)
2160 	switch (kp->kp_stat) {
2161 #else	/* __FreeBSD__ >= 5 */
2162 	switch (kp->ki_stat) {
2163 #endif	/* __FreeBSD__ >= 5 */
2164 	case SIDL:
2165 		p->p_state[0] = 'I';
2166 		break;
2167 	case SRUN:
2168 		p->p_state[0] = 'R';
2169 		break;
2170 #ifndef __DragonFly__
2171 #if defined (SWAIT) || defined (SLOCK)
2172 #ifdef	SWAIT
2173 	case SWAIT:
2174 #endif	/* SWAIT */
2175 #ifdef	SLOCK
2176 	case SLOCK:
2177 #endif	/* SLOCK */
2178 		p->p_flag |= FL_LOCK;
2179 		/*FALLTHRU*/
2180 #endif	/* SWAIT || SLOCK */
2181 	case SSLEEP:
2182 		p->p_state[0] = 'S';
2183 		break;
2184 #endif
2185 	case SSTOP:
2186 		p->p_state[0] = 'T';
2187 		break;
2188 	case SZOMB:
2189 		p->p_state[0] = 'Z';
2190 		break;
2191 	}
2192 	p->p_lstate[0] = p->p_state[0];
2193 #if defined (__DragonFly__)
2194 #define	ki_flag		kp_flags
2195 #define	ki_pri		kp_lwp.kl_prio
2196 #endif	/* __DragonFly__ */
2197 	if (kp->ki_flag & P_SYSTEM)
2198 		p->p_flag |= FL_SYS;
2199 	if (kp->ki_flag & P_TRACED)
2200 		p->p_flag |= FL_TRC;
2201 #if (__FreeBSD__) < 5 || defined (__DragonFly__)
2202 #ifndef	__DragonFly__
2203 	p->p_intpri = kp->kp_proc.p_usrpri;
2204 	p->p_oldpri = kp->kp_proc.p_usrpri;
2205 	p->p_pri = kp->kp_proc.p_priority;
2206 #endif	/* !__DragonFly__ */
2207 	p->p_policy = SCHED_OTHER;
2208 	p->p_clname = "TS";
2209 #else	/* __FreeBSD__ >= 5 */
2210 	if (kp->ki_sflag & PS_INMEM)
2211 		p->p_flag |= FL_LOAD;
2212 	if (kp->ki_sflag & PS_SWAPPINGOUT)
2213 		p->p_flag |= FL_SWAP;
2214 	p->p_oldpri = ((double)kp->ki_pri.pri_user - PRI_MIN) /
2215 		(PRI_MAX - PRI_MIN) * 60 + 60;
2216 	p->p_pri = 40 - ((double)kp->ki_pri.pri_user - PRI_MIN) /
2217 		(PRI_MAX - PRI_MIN) * 40;
2218 	if (p->p_policy != SCHED_OTHER)
2219 		p->p_pri += 100;
2220 #endif	/* __FreeBSD__ >= 5 */
2221 #ifndef	__DragonFly__
2222 	p->p_psr = kp->ki_oncpu;
2223 	p->p_wchan = (unsigned long)kp->ki_wchan;
2224 #endif	/* !__DragonFly__ */
2225 	return OKAY;
2226 }
2227 
2228 static enum okay
2229 getproc(const char *dir, struct proc *p, pid_t expected_pid, pid_t lwp)
2230 {
2231 	enum okay	result;
2232 
2233 	memset(p, 0, sizeof *p);
2234 	if (chdir(dir) == 0) {
2235 		if ((result = getproc_status(p, expected_pid)) == OKAY)
2236 			if ((result = getproc_cmdline(p)) == OKAY)
2237 				if ((result = getproc_map(p)) == OKAY)
2238 					if ((result = getproc_scheduler(p)) ==
2239 							OKAY)
2240 						result = getproc_kvm(p);
2241 		chdir_to_proc();
2242 	} else
2243 		result = STOP;
2244 	return result;
2245 }
2246 
2247 #else	/* !__linux__, !__FreeBSD__, !__DragonFly__ */
2248 
2249 #ifndef	__sun
2250 static unsigned long
2251 getmem(void)
2252 {
2253 #ifdef	_SC_USEABLE_MEMORY
2254 	long	usm;
2255 
2256 	if ((usm = sysconf(_SC_USEABLE_MEMORY)) > 0)
2257 		return usm * (pagesize / 1024);
2258 #endif	/* _SC_USEABLE_MEMORY */
2259 	return 0;
2260 }
2261 #endif	/* !__sun */
2262 
2263 static const char *
2264 concat(const char *dir, const char *base)
2265 {
2266 	static char	*name;
2267 	static long	size;
2268 	long	length;
2269 	char	*np;
2270 	const char	*cp;
2271 
2272 	if ((length = strlen(dir) + strlen(base) + 2) > size)
2273 		name = srealloc(name, size = length);
2274 	np = name;
2275 	for (cp = dir; *cp; cp++)
2276 		*np++ = *cp;
2277 	*np++ = '/';
2278 	for (cp = base; *cp; cp++)
2279 		*np++ = *cp;
2280 	*np = '\0';
2281 	return name;
2282 }
2283 
2284 static time_t
2285 tv2sec(timestruc_t tv, int mult)
2286 {
2287 	return tv.tv_sec*mult + (tv.tv_nsec >= 500000000/mult);
2288 }
2289 
2290 static enum okay
2291 getproc_psinfo(const char *dir, struct proc *p, pid_t expected_pid)
2292 {
2293 	FILE	*fp;
2294 	struct psinfo	pi;
2295 	const char	*cp;
2296 	char	*np;
2297 
2298 	if ((fp = fopen(concat(dir, "psinfo"), "r")) == NULL)
2299 		return STOP;
2300 	if (fread(&pi, 1, sizeof pi, fp) != sizeof pi ||
2301 			pi.pr_pid != expected_pid) {
2302 		fclose(fp);
2303 		return STOP;
2304 	}
2305 	fclose(fp);
2306 	p->p_pid = pi.pr_pid;
2307 	strncpy(p->p_fname, pi.pr_fname, sizeof p->p_fname);
2308 	p->p_fname[sizeof p->p_fname - 1] = '\0';
2309 	p->p_ppid = pi.pr_ppid;
2310 	p->p_pgid = pi.pr_pgid;
2311 	p->p_sid = pi.pr_sid;
2312 	p->p_nlwp = pi.pr_nlwp;
2313 	p->p_ttydev = pi.pr_ttydev;
2314 	p->p_time = tv2sec(pi.pr_time, 1);
2315 #ifdef	__sun
2316 	p->p_accutime = tv2sec(pi.pr_ctime, 1);
2317 #endif	/* __sun */
2318 	p->p_start = tv2sec(pi.pr_start, 1);
2319 	p->p_size = pi.pr_size;
2320 	p->p_osz = pi.pr_size / kbytes_per_page;
2321 	p->p_rssize = pi.pr_rssize;
2322 	p->p_orss = pi.pr_rssize / kbytes_per_page;
2323 	p->p_addr = (unsigned long)pi.pr_addr;
2324 #ifdef	__sun
2325 	p->p_pctcpu = (double)pi.pr_pctcpu / 0x8000 * 100;
2326 	p->p_pctmem = (double)pi.pr_pctmem / 0x8000 * 100;
2327 #endif	/* __sun */
2328 	strncpy(p->p_psargs, pi.pr_psargs, sizeof p->p_psargs);
2329 	p->p_psargs[sizeof p->p_psargs - 1] = '\0';
2330 	for (np = p->p_comm, cp = p->p_psargs; *cp && !isblank(*cp); cp++)
2331 		*np++ = *cp;
2332 	p->p_uid = pi.pr_uid;
2333 	p->p_gid = pi.pr_gid;
2334 #ifdef	__sun
2335 	p->p_euid = pi.pr_euid;
2336 	p->p_egid = pi.pr_egid;
2337 #endif	/* __sun */
2338 	p->p_lflag = pi.pr_flag;
2339 #if defined (SLOAD)
2340 	if (p->p_lflag & SLOAD)
2341 		p->p_flag |= FL_LOAD;
2342 #elif defined (P_LOAD)
2343 	if (p->p_lflag & P_LOAD)
2344 		p->p_flag |= FL_LOAD;
2345 #endif	/* SLOAD, P_LOAD */
2346 #if defined (SSYS)
2347 	if (p->p_lflag & SSYS)
2348 		p->p_flag |= FL_SYS;
2349 #elif defined (P_SYS)
2350 	if (p->p_lflag & P_SYS)
2351 		p->p_flag |= FL_SYS;
2352 #endif	/* SSYS, P_SYS */
2353 #if defined (SLOCK)
2354 	if (p->p_lflag & SLOCK)
2355 		p->p_flag |= FL_LOCK;
2356 #elif defined (P_NOSWAP)
2357 	if (p->p_lflag & P_NOSWAP)
2358 		p->p_flag |= FL_LOCK;
2359 #endif	/* SLOCK, P_NOSWAP */
2360 #if defined (SPROCTR)
2361 	if (p->p_lflag & SPROCTR)
2362 		p->p_flag |= FL_TRC;
2363 #elif defined (P_PROCTR)
2364 	if (p->p_lflag & P_PROCTR)
2365 		p->p_flag |= FL_TRC;
2366 #endif	/* SPROCTR, P_PROCTR */
2367 	return OKAY;
2368 }
2369 
2370 static enum okay
2371 getproc_lwpsinfo(const char *dir, struct proc *p, pid_t lwp)
2372 {
2373 	static char	clname[PRCLSZ+1];
2374 	char	base[100];
2375 	FILE	*fp;
2376 	struct lwpsinfo	li;
2377 
2378 	if (p->p_nlwp == 0) {	/* zombie process */
2379 		p->p_lstate[0] = p->p_state[0] = 'Z';
2380 		return OKAY;
2381 	}
2382 	if (lwp != (pid_t)-1) {
2383 		snprintf(base, sizeof base, "lwp/%d/lwpsinfo", (int)lwp);
2384 		fp = fopen(concat(dir, base), "r");
2385 	} else {
2386 		int	i;
2387 		for (i = 1; i <= 255; i++) {
2388 			snprintf(base, sizeof base, "lwp/%d/lwpsinfo", i);
2389 			if ((fp = fopen(concat(dir, base), "r")) != NULL ||
2390 					errno != ENOENT)
2391 				break;
2392 		}
2393 	}
2394 	if (fp == NULL)
2395 		return STOP;
2396 	if (fread(&li, 1, sizeof li, fp) != sizeof li) {
2397 		fclose(fp);
2398 		return STOP;
2399 	}
2400 	fclose(fp);
2401 	p->p_lwp = li.pr_lwpid;
2402 	if (Lflag) {
2403 		p->p_time = tv2sec(li.pr_time, 1);
2404 		if (li.pr_name[0]) {
2405 			strncpy(p->p_fname, li.pr_name, sizeof p->p_fname);
2406 			p->p_fname[sizeof p->p_fname - 1] = '\0';
2407 		}
2408 	}
2409 	p->p_lstate[0] = p->p_state[0] = li.pr_sname;
2410 	p->p_intpri = li.pr_pri;
2411 	p->p_rtpri = li.pr_pri;
2412 	p->p_clname = clname;
2413 	memcpy(clname, li.pr_clname, PRCLSZ);
2414 #ifdef	__sun
2415 	p->p_oldpri = li.pr_oldpri;
2416 #endif	/* __sun */
2417 	p->p_pri = li.pr_pri;
2418 	p->p_nice = li.pr_nice;
2419 	p->p_wchan = (unsigned long)li.pr_wchan;
2420 	p->p_psr = li.pr_onpro;
2421 	return OKAY;
2422 }
2423 
2424 #ifdef	__sun
2425 static enum okay
2426 getproc_usage(const char *dir, struct proc *p)
2427 {
2428 	FILE	*fp;
2429 	struct prusage	pu;
2430 
2431 	if ((fp = fopen(concat(dir, "usage"), "r")) == NULL)
2432 		return OKAY;
2433 	if (fread(&pu, 1, sizeof pu, fp) != sizeof pu) {
2434 		fclose(fp);
2435 		return STOP;
2436 	}
2437 	fclose(fp);
2438 	p->p_pflts = pu.pr_majf;
2439 	p->p_bufr = pu.pr_inblk;
2440 	p->p_bufw = pu.pr_oublk;
2441 	p->p_mrcv = pu.pr_mrcv;
2442 	p->p_msnd = pu.pr_msnd;
2443 	p->p_utime = tv2sec(pu.pr_utime, 10);
2444 	p->p_ktime = tv2sec(pu.pr_stime, 10);
2445 	return OKAY;
2446 }
2447 #else	/* !__sun */
2448 static enum okay
2449 getproc_cred(const char *dir, struct proc *p)
2450 {
2451 	FILE	*fp;
2452 	struct prcred	pc;
2453 
2454 	if ((fp = fopen(concat(dir, "cred"), "r")) == NULL)
2455 		/*
2456 		 * Don't require this, as it may be accessible to root
2457 		 * only and it's better to have no effective uids than
2458 		 * to display no content at all.
2459 		 */
2460 		return OKAY;
2461 	if (fread(&pc, 1, sizeof pc, fp) != sizeof pc) {
2462 		fclose(fp);
2463 		return STOP;
2464 	}
2465 	fclose(fp);
2466 	p->p_euid = pc.pr_euid;
2467 	p->p_egid = pc.pr_egid;
2468 	return OKAY;
2469 }
2470 #endif	/* !__sun */
2471 
2472 static enum okay
2473 getproc_status(const char *dir, struct proc *p)
2474 {
2475 	FILE	*fp;
2476 	struct pstatus	ps;
2477 
2478 	if ((fp = fopen(concat(dir, "status"), "r")) == NULL)
2479 		/*
2480 		 * Don't require this, as it may be accessible to root
2481 		 * only and the children times are not that important.
2482 		 */
2483 		return OKAY;
2484 	if (fread(&ps, 1, sizeof ps, fp) != sizeof ps) {
2485 		fclose(fp);
2486 		return STOP;
2487 	}
2488 	fclose(fp);
2489 	p->p_utime = tv2sec(ps.pr_utime, 10);
2490 	p->p_ktime = tv2sec(ps.pr_stime, 10);
2491 	p->p_accutime = tv2sec(ps.pr_cutime, 1) + tv2sec(ps.pr_cstime, 1);
2492 	return OKAY;
2493 }
2494 
2495 static enum okay
2496 getproc_lwpstatus(const char *dir, struct proc *p, pid_t lwp)
2497 {
2498 	FILE	*fp;
2499 	char	base[100];
2500 	struct lwpstatus	ls;
2501 
2502 	if (p->p_nlwp == 0)	/* zombie process */
2503 		return OKAY;
2504 	if (lwp != (pid_t)-1) {
2505 		snprintf(base, sizeof base, "lwp/%d/lwpstatus", (int)lwp);
2506 		fp = fopen(concat(dir, base), "r");
2507 	} else {
2508 		int	i;
2509 		for (i = 1; i <= 20; i++) {
2510 			snprintf(base, sizeof base, "lwp/%d/lwpstatus", i);
2511 			if ((fp = fopen(concat(dir, base), "r")) != NULL ||
2512 					errno != ENOENT)
2513 				break;
2514 		}
2515 	}
2516 	if (fp == NULL)
2517 		/*
2518 		 * Don't require this, as it may be accessible to root
2519 		 * only and the process flags are not that important.
2520 		 */
2521 		return OKAY;
2522 	if (fread(&ls, 1, sizeof ls, fp) != sizeof ls) {
2523 		fclose(fp);
2524 		return STOP;
2525 	}
2526 	fclose(fp);
2527 	if (ls.pr_flags == PR_STOPPED &&
2528 			(ls.pr_why == PR_SYSENTRY || ls.pr_why == PR_SYSEXIT))
2529 		p->p_flag |= FL_LOCK;
2530 	return OKAY;
2531 }
2532 
2533 static enum okay
2534 getproc(const char *dir, struct proc *p, pid_t expected_pid, pid_t lwp)
2535 {
2536 	enum okay	result;
2537 
2538 	memset(p, 0, sizeof *p);
2539 	if ((result = getproc_psinfo(dir, p, expected_pid)) == OKAY) {
2540 		if ((result = getproc_status(dir, p)) == OKAY)
2541 #ifdef	__sun
2542 			if ((result = getproc_usage(dir, p)) == OKAY)
2543 #else	/* !__sun */
2544 			if ((result = getproc_cred(dir, p)) == OKAY)
2545 #endif	/* !__sun */
2546 				if ((result = getproc_lwpsinfo(dir, p, lwp))
2547 						== OKAY)
2548 					result = getproc_lwpstatus(dir, p, lwp);
2549 	} else
2550 		result = STOP;
2551 	return result;
2552 }
2553 
2554 static enum okay
2555 getLWPs(const char *dir, struct proc *p, pid_t expected_pid)
2556 {
2557 	DIR	*Dp;
2558 	struct dirent	*dp;
2559 	unsigned long	val;
2560 	char	*x;
2561 
2562 	if ((Dp = opendir(concat(dir, "lwp"))) != NULL) {
2563 		while ((dp = readdir(Dp)) != NULL) {
2564 			if (dp->d_name[0] == '.' && (dp->d_name[1]=='\0' ||
2565 					(dp->d_name[1]=='.' &&
2566 					 dp->d_name[2]=='\0')))
2567 			continue;
2568 			val = strtoul(dp->d_name, &x, 10);
2569 			if (*x != 0)
2570 				continue;
2571 			if (getproc(dir, p, expected_pid, val) == OKAY) {
2572 				postproc(p);
2573 				if (selectproc(p) == OKAY)
2574 					outproc(p);
2575 			}
2576 		}
2577 		closedir(Dp);
2578 		return OKAY;
2579 	} else
2580 		return STOP;
2581 }
2582 
2583 #endif	/* !__linux__, !__FreeBSD__, !__DragonFly__ */
2584 
2585 static void
2586 postproc(struct proc *p)
2587 {
2588 	cleanline(p);
2589 #ifndef	__sun
2590 	if ((p->p_pctcpu = now - p->p_start) != 0) {
2591 		p->p_pctcpu = (double)p->p_time * 100 / p->p_pctcpu;
2592 		if (p->p_pctcpu < 0)
2593 			p->p_pctcpu = 0;
2594 	}
2595 	if (totalmem)
2596 		p->p_pctmem = (double)p->p_size * 100 / totalmem;
2597 #endif	/* !__sun */
2598 #if !defined (__linux__) && !defined (__sun) && !defined (__FreeBSD__) \
2599 		&& !defined (__DragonFly__)
2600 	p->p_oldpri = 160 - p->p_pri;
2601 #endif	/* !__linux__, !__sun */
2602 #if !defined (__linux__) && !defined (__FreeBSD__) && !defined (__DragonFly__)
2603 	p->p_policy = p->p_clname && strcmp(p->p_clname, "TS") ?
2604 		SCHED_RR : SCHED_OTHER;
2605 #endif	/* !__linux__, !__FreeBSD__, !__DragonFly__ */
2606 }
2607 #endif	/* !__hpux, !_AIX, !__NetBSD__, !__OpenBSD__, !__APPLE__ */
2608 
2609 static enum okay
2610 selectproc(struct proc *p)
2611 {
2612 	struct criterion	*ct;
2613 
2614 	for (ct = c0; ct; ct = ct->c_nxt) {
2615 		if (ucb_rflag && p->p_lstate[0] != 'R')
2616 			continue;
2617 		switch (ct->c_typ) {
2618 		case CR_ALL:
2619 			return OKAY;
2620 		case CR_ALL_WITH_TTY:
2621 			if (p->p_lstate[0] == 'Z')
2622 				break;
2623 #ifndef	UCB
2624 			if (p->p_pid == p->p_sid)
2625 				break;
2626 #endif	/* !UCB */
2627 			if (p->p_ttydev != (dev_type)PRNODEV)
2628 				return OKAY;
2629 			break;
2630 		case CR_ALL_BUT_SESSION_LEADERS:
2631 			if (p->p_pid != p->p_sid)
2632 				return OKAY;
2633 			break;
2634 		case CR_WITHOUT_TTY:
2635 			if (p->p_ttydev == (dev_type)PRNODEV ||
2636 					p->p_lstate[0] == 'Z')
2637 				return OKAY;
2638 			break;
2639 		case CR_NO_TTY_NO_SESSION_LEADER:
2640 			if (p->p_ttydev == (dev_type)PRNODEV &&
2641 					p->p_pid != p->p_sid &&
2642 					p->p_lstate[0] != 'Z')
2643 				return OKAY;
2644 			break;
2645 		case CR_PROCESS_GROUP:
2646 #if defined (SUS) || defined (UCB)
2647 			if (p->p_sid == ct->c_val)
2648 				return OKAY;
2649 #else	/* !SUS, !UCB */
2650 			if (p->p_pgid == ct->c_val)
2651 				return OKAY;
2652 #endif	/* !SUS, !UCB */
2653 			break;
2654 		case CR_REAL_GID:
2655 			if (p->p_gid == ct->c_val)
2656 				return OKAY;
2657 			break;
2658 		case CR_PROCESS_ID:
2659 			if (p->p_pid == ct->c_val)
2660 				return OKAY;
2661 			break;
2662 		case CR_TTY_DEVICE:
2663 			if (/*p->p_ttydev != (dev_type)PRNODEV &&*/
2664 					p->p_ttydev == ct->c_val &&
2665 					p->p_lstate[0] != 'Z')
2666 				return OKAY;
2667 			break;
2668 		case CR_SESSION_LEADER:
2669 			if (p->p_sid == ct->c_val)
2670 				return OKAY;
2671 			break;
2672 		case CR_EFF_UID:
2673 			if (p->p_euid == ct->c_val)
2674 				return OKAY;
2675 			break;
2676 		case CR_REAL_UID:
2677 			if (p->p_uid == ct->c_val)
2678 				return OKAY;
2679 			break;
2680 		case CR_ADD_UNINTERESTING:
2681 			if (p->p_lstate[0] != 'Z' &&
2682 					p->p_euid == myuid &&
2683 					p->p_ttydev != (dev_type)PRNODEV &&
2684 					p->p_ttydev == myproc.p_ttydev)
2685 				return OKAY;
2686 			break;
2687 		case CR_DEFAULT:
2688 			if (p->p_lstate[0] != 'Z' &&
2689 #if defined (SUS) || defined (UCB)
2690 					p->p_euid == myuid &&
2691 #endif	/* SUS || UCB */
2692 #ifdef	UCB
2693 					p->p_pid != p->p_sid &&
2694 					p->p_ttydev != (dev_type)PRNODEV &&
2695 #endif	/* UCB */
2696 					p->p_ttydev == myproc.p_ttydev)
2697 				return OKAY;
2698 			break;
2699 		}
2700 	}
2701 	return STOP;
2702 }
2703 
2704 #if !defined (__hpux) && !defined (_AIX) && !defined (__NetBSD__) && \
2705 	!defined (__OpenBSD__) && !defined (__APPLE__)
2706 static void
2707 do_procs(void)
2708 {
2709 	struct proc	p;
2710 	DIR	*Dp;
2711 	struct dirent	*dp;
2712 	unsigned long	val;
2713 	char	*x;
2714 
2715 	if ((Dp = opendir(".")) != NULL) {
2716 		while ((dp = readdir(Dp)) != NULL) {
2717 			if (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' ||
2718 					(dp->d_name[1] == '.' &&
2719 				 	dp->d_name[2] == '\0')))
2720 				continue;
2721 			val = strtoul(dp->d_name, &x, 10);
2722 			if (*x != 0)
2723 				continue;
2724 #if !defined (__FreeBSD__) && !defined (__DragonFly__)
2725 			if (Lflag)
2726 				if (getLWPs(dp->d_name, &p, val) == OKAY)
2727 					continue;
2728 #endif	/* !__FreeBSD__, !__DragonFly__ */
2729 			if (getproc(dp->d_name, &p, val, -1) == OKAY) {
2730 				postproc(&p);
2731 				if (selectproc(&p) == OKAY)
2732 					outproc(&p);
2733 			}
2734 		}
2735 		closedir(Dp);
2736 	}
2737 }
2738 #elif defined (__hpux)
2739 
2740 static unsigned long
2741 getmem(void)
2742 {
2743 	return 0;
2744 }
2745 
2746 static void
2747 getproc(struct proc *p, struct pst_status *pst)
2748 {
2749 	char	*cp, *np;
2750 
2751 	memset(p, 0, sizeof *p);
2752 	p->p_pid = pst->pst_pid;
2753 	strncpy(p->p_fname, pst->pst_ucomm, sizeof p->p_fname);
2754 	p->p_fname[sizeof p->p_fname - 1] = '\0';
2755 	strncpy(p->p_psargs, pst->pst_cmd, sizeof p->p_psargs);
2756 	p->p_psargs[sizeof p->p_psargs - 1] = '\0';
2757 	for (np = p->p_comm, cp = p->p_psargs; *cp && !isblank(*cp); cp++)
2758 		*np++ = *cp;
2759 	p->p_lstate[0] = pst->pst_stat;
2760 	p->p_ppid = pst->pst_ppid;
2761 	p->p_pgid = pst->pst_pgrp;
2762 	p->p_sid = pst->pst_sid;
2763 	/*p->p_lwp = pst->pst_lwpid;*/
2764 	if (pst->pst_term.psd_major != -1 || pst->pst_term.psd_minor != -1)
2765 		p->p_ttydev = makedev(pst->pst_term.psd_major,
2766 				pst->pst_term.psd_minor);
2767 	p->p_lflag = pst->pst_flag;
2768 	p->p_time = pst->pst_utime + pst->pst_stime;
2769 	p->p_accutime = pst->pst_utime + pst->pst_stime +
2770 		pst->pst_child_utime.pst_sec +
2771 		(pst->pst_child_utime.pst_usec > + 500000) +
2772 		pst->pst_child_stime.pst_sec +
2773 		(pst->pst_child_stime.pst_usec > + 500000);
2774 	p->p_utime = pst->pst_utime * 10;
2775 	p->p_ktime = pst->pst_stime * 10;
2776 	p->p_intpri = p->p_rtpri = pst->pst_pri;
2777 	p->p_policy = pst->pst_schedpolicy;
2778 	p->p_c = pst->pst_cpu;
2779 	p->p_nice = pst->pst_nice;
2780 	p->p_nlwp = pst->pst_nlwps;
2781 	p->p_start = pst->pst_start;
2782 	p->p_osz = pst->pst_dsize + pst->pst_tsize + pst->pst_ssize;
2783 	p->p_size = p->p_osz * kbytes_per_page;
2784 	p->p_orss = pst->pst_rssize;
2785 	p->p_rssize = p->p_orss * kbytes_per_page;
2786 	p->p_pflts = pst->pst_majorfaults;
2787 	p->p_mrcv = pst->pst_msgrcv;
2788 	p->p_msnd = pst->pst_msgsnd;
2789 	p->p_addr = pst->pst_addr;
2790 	p->p_wchan = pst->pst_wchan;
2791 	p->p_psr = pst->pst_procnum;
2792 	p->p_pctcpu = pst->pst_pctcpu;
2793 	p->p_uid = pst->pst_uid;
2794 	p->p_euid = pst->pst_euid;
2795 	p->p_gid = pst->pst_gid;
2796 	p->p_egid = pst->pst_egid;
2797 }
2798 
2799 static void
2800 getlwp(struct proc *p, struct lwp_status *lwp)
2801 {
2802 	p->p_lwp = lwp->lwp_lwpid;
2803 	p->p_intpri = p->p_rtpri = lwp->lwp_pri;
2804 	p->p_c = lwp->lwp_cpu;
2805 	p->p_wchan = lwp->lwp_wchan;
2806 	p->p_psr = lwp->lwp_cpu;
2807 	p->p_start = lwp->lwp_start;
2808 	p->p_lstate[0] = lwp->lwp_stat;
2809 	p->p_policy = lwp->lwp_schedpolicy;
2810 	p->p_utime = lwp->lwp_utime * 10;
2811 	p->p_ktime = lwp->lwp_stime * 10;
2812 	p->p_pflts = lwp->lwp_majorfaults;
2813 	p->p_mrcv = lwp->lwp_msgrcv;
2814 	p->p_msnd = lwp->lwp_msgsnd;
2815 	/*p->p_pctcpu = lwp->lwp_pctcpu;*/
2816 }
2817 
2818 static void
2819 postproc(struct proc *p)
2820 {
2821 	cleanline(p);
2822 	switch (p->p_lstate[0]) {
2823 	case PS_SLEEP:
2824 		p->p_lstate[0] = 'S';
2825 		break;
2826 	case PS_RUN:
2827 		p->p_lstate[0] = 'R';
2828 		break;
2829 	case PS_STOP:
2830 		p->p_lstate[0] = 'T';
2831 		break;
2832 	case PS_ZOMBIE:
2833 		p->p_lstate[0] = 'Z';
2834 		break;
2835 	case PS_IDLE:
2836 	case PS_OTHER:
2837 	default:
2838 		p->p_lstate[0] = 'I';
2839 		break;
2840 	}
2841 	p->p_state[0] = p->p_lstate[0];
2842 	if (p->p_lflag & PS_INCORE)
2843 		p->p_flag |= FL_LOAD;
2844 	if (p->p_lflag & PS_SYS)
2845 		p->p_flag |= FL_SYS;
2846 	if (p->p_lflag & PS_LOCKED)
2847 		p->p_flag |= FL_LOCK;
2848 	if (p->p_lflag & PS_TRACE)
2849 		p->p_flag |= FL_TRC;
2850 	if (p->p_lflag & PS_TRACE2)
2851 		p->p_flag |= FL_WTED;
2852 	p->p_oldpri = p->p_intpri;
2853 	p->p_pri = 220 - p->p_intpri;
2854 	switch (p->p_policy) {
2855 	case PS_TIMESHARE:
2856 		p->p_clname = "TS";
2857 		p->p_policy = SCHED_OTHER;
2858 		p->p_pri /= 2;
2859 		break;
2860 	case PS_RTPRIO:
2861 	case PS_RR:
2862 	case PS_RR2:
2863 #ifdef	S42
2864 		p->p_clname = "FP";
2865 #else
2866 		p->p_clname = "RT";
2867 #endif
2868 		p->p_policy = SCHED_RR;
2869 		p->p_pri += 100;
2870 		break;
2871 	case PS_FIFO:
2872 		p->p_clname = "FF";
2873 		p->p_policy = SCHED_FIFO;
2874 		p->p_pri += 100;
2875 		break;
2876 	case PS_NOAGE:
2877 		p->p_clname = "FC";
2878 		p->p_policy = SCHED_NOAGE;
2879 		p->p_pri /= 2;
2880 		break;
2881 	default:
2882 		p->p_clname = "??";
2883 	}
2884 }
2885 
2886 #define	burst	((size_t)10)
2887 
2888 static void
2889 getLWPs(struct proc *p)
2890 {
2891 	struct lwp_status	lwp[burst];
2892 	int	i, count;
2893 	int	idx = 0;
2894 
2895 	while ((count = pstat_getlwp(lwp, sizeof *lwp, burst, idx, p->p_pid))
2896 			> 0) {
2897 		for (i = 0; i < count; i++) {
2898 			getlwp(p, &lwp[i]);
2899 			postproc(p);
2900 			if (selectproc(p) == OKAY)
2901 				outproc(p);
2902 		}
2903 		idx = lwp[count-1].lwp_idx + 1;
2904 	}
2905 }
2906 
2907 static void
2908 do_procs(void)
2909 {
2910 	struct proc	p;
2911 	struct pst_status	pst[burst];
2912 	int	i, count;
2913 	int	idx = 0;
2914 
2915 	while ((count = pstat_getproc(pst, sizeof *pst, burst, idx)) > 0) {
2916 		for (i = 0; i < count; i++) {
2917 			getproc(&p, &pst[i]);
2918 			if (Lflag && p.p_nlwp > 1)
2919 				getLWPs(&p);
2920 			else {
2921 				postproc(&p);
2922 				if (selectproc(&p) == OKAY)
2923 					outproc(&p);
2924 			}
2925 		}
2926 		idx = pst[count-1].pst_idx + 1;
2927 	}
2928 }
2929 
2930 #elif defined (_AIX)
2931 
2932 static unsigned long
2933 getmem(void)
2934 {
2935 	return 0;
2936 }
2937 
2938 static time_t
2939 tv2sec(struct timeval64 tv, int mult)
2940 {
2941 	return tv.tv_sec*mult + (tv.tv_usec >= 500000/mult);
2942 }
2943 
2944 static void
2945 getproc(struct proc *p, struct procentry64 *pi)
2946 {
2947 	char	args[100], *ap, *cp, *xp;
2948 
2949 	memset(p, 0, sizeof *p);
2950 	p->p_pid = pi->pi_pid;
2951 	strncpy(p->p_fname, pi->pi_comm, sizeof p->p_fname);
2952 	p->p_fname[sizeof p->p_fname - 1] = '\0';
2953 	p->p_lstate[0] = pi->pi_state;
2954 	p->p_ppid = pi->pi_ppid;
2955 	p->p_pgid = pi->pi_pgrp;
2956 	p->p_sid = pi->pi_sid;
2957 	p->p_ttydev = pi->pi_ttyp ? pi->pi_ttyd : PRNODEV;
2958 	p->p_lflag = pi->pi_flags;
2959 	p->p_time = pi->pi_utime + pi->pi_stime;
2960 	p->p_accutime = pi->pi_utime + pi->pi_stime;
2961 	p->p_utime = pi->pi_utime * 10;
2962 	p->p_ktime = pi->pi_stime * 10;
2963 	p->p_intpri = pi->pi_pri;
2964 	p->p_c = pi->pi_cpu;
2965 	p->p_nice = pi->pi_nice;
2966 	p->p_nlwp = pi->pi_thcount;
2967 	p->p_start = pi->pi_start;
2968 	p->p_osz = pi->pi_size;
2969 	p->p_orss = pi->pi_drss + pi->pi_trss;
2970 	p->p_pflts = pi->pi_majflt;
2971 	p->p_addr = pi->pi_adspace;
2972 	p->p_uid = pi->pi_uid;
2973 	p->p_euid = pi->pi_cred.crx_uid;
2974 	p->p_gid = pi->pi_cred.crx_rgid;
2975 	p->p_egid = pi->pi_cred.crx_gid;
2976 	if (getargs(pi, sizeof *pi, args, sizeof args) == 0) {
2977 		ap = args;
2978 		cp = p->p_psargs;
2979 		xp = p->p_comm;
2980 		while (cp < &p->p_psargs[sizeof p->p_psargs - 1]) {
2981 			if (ap[0] == '\0') {
2982 				if (ap[1] == '\0')
2983 					break;
2984 				*cp++ = ' ';
2985 				if (xp) {
2986 					*xp = '\0';
2987 					xp = NULL;
2988 				}
2989 			} else {
2990 				*cp++ = *ap;
2991 				if (xp)
2992 					*xp++ = *ap;
2993 			}
2994 			ap++;
2995 		}
2996 		*cp = '\0';
2997 		if (xp)
2998 			*xp = '\0';
2999 	}
3000 }
3001 
3002 static void
3003 postproc(struct proc *p)
3004 {
3005 	char	*np, *cp;
3006 
3007 	if (p->p_psargs[0] == '\0') {
3008 		strncpy(p->p_psargs, p->p_fname, sizeof p->p_psargs);
3009 		p->p_psargs[sizeof p->p_psargs - 1] = '\0';
3010 	}
3011 	if (p->p_comm[0] == '\0') {
3012 		for (np = p->p_comm, cp = p->p_psargs;
3013 				*cp && !isblank(*cp); cp++)
3014 			*np++ = *cp;
3015 	}
3016 	cleanline(p);
3017 	p->p_clname = "TS";
3018 	switch (p->p_lstate[0]) {
3019 	case SSWAP:
3020 		p->p_flag |= FL_SWAP;
3021 		/*FALLTHRU*/
3022 	default:
3023 	case SIDL:
3024 		p->p_state[0] = 'I';
3025 		break;
3026 	case SZOMB:
3027 		p->p_state[0] = 'Z';
3028 		break;
3029 	case SSTOP:
3030 		p->p_state[0] = 'T';
3031 		break;
3032 	case SACTIVE:
3033 		p->p_state[0] = 'R';
3034 		break;
3035 	}
3036 	p->p_lstate[0] = p->p_state[0];
3037 	if (p->p_lflag & SLOAD)
3038 		p->p_flag |= FL_LOAD;
3039 	if (p->p_lflag & SNOSWAP)
3040 		p->p_flag |= FL_LOCK;
3041 	if (p->p_lflag & SKPROC)
3042 		p->p_flag |= FL_SYS;
3043 	if (p->p_lflag & SFIXPRI)
3044 		p->p_clname = "RT";
3045 	p->p_oldpri = p->p_intpri / 2;
3046 	p->p_pri = 255 - p->p_intpri;
3047 	p->p_size = p->p_osz * kbytes_per_page;
3048 	p->p_rssize = p->p_orss * kbytes_per_page;
3049 }
3050 
3051 static void
3052 getlwp(struct proc *p, struct thrdentry64 *ti)
3053 {
3054 	p->p_lwp = ti->ti_tid;
3055 	p->p_psr = ti->ti_cpuid;
3056 	p->p_wchan = ti->ti_wchan;
3057 	if (Lflag) {
3058 		p->p_intpri = ti->ti_pri;
3059 		p->p_c = ti->ti_cpu;
3060 		p->p_policy = ti->ti_policy;
3061 		p->p_utime = tv2sec(ti->ti_ru.ru_utime, 10);
3062 		p->p_ktime = tv2sec(ti->ti_ru.ru_stime, 10);
3063 		p->p_time = (p->p_utime + p->p_ktime) / 10;
3064 	}
3065 	p->p_pflts = ti->ti_ru.ru_majflt;
3066 	p->p_bufr = ti->ti_ru.ru_inblock;
3067 	p->p_bufw = ti->ti_ru.ru_oublock;
3068 	p->p_mrcv = ti->ti_ru.ru_msgrcv;
3069 	p->p_msnd = ti->ti_ru.ru_msgsnd;
3070 }
3071 
3072 #define	burst	((size_t)10)
3073 
3074 static void
3075 getLWPs(struct proc *p)
3076 {
3077 	struct	thrdentry64	ti[burst];
3078 	tid64_t	idx = 0;
3079 	int	i, count;
3080 
3081 	while ((count=getthrds64(p->p_pid, ti, sizeof *ti, &idx, burst)) > 0) {
3082 		for (i = 0; i < count; i++) {
3083 			getlwp(p, &ti[i]);
3084 			postproc(p);
3085 			if (selectproc(p) == OKAY)
3086 				outproc(p);
3087 		}
3088 		if (count < burst)
3089 			break;
3090 	}
3091 }
3092 
3093 static void
3094 oneLWP(struct proc *p)
3095 {
3096 	struct thrdentry64	ti;
3097 	tid64_t	idx = 0;
3098 
3099 	if (getthrds64(p->p_pid, &ti, sizeof ti, &idx, 1) == 1)
3100 		getlwp(p, &ti);
3101 }
3102 
3103 static void
3104 do_procs(void)
3105 {
3106 	struct proc	p;
3107 	struct procentry64	pi[burst];
3108 	pid_t	idx = 0;
3109 	int	i, count;
3110 
3111 	while ((count = getprocs64(pi, sizeof *pi, NULL, 0, &idx, burst)) > 0) {
3112 		for (i = 0; i < count; i++) {
3113 			getproc(&p, &pi[i]);
3114 			if (Lflag && p.p_nlwp > 1)
3115 				getLWPs(&p);
3116 			else {
3117 				oneLWP(&p);
3118 				postproc(&p);
3119 				if (selectproc(&p) == OKAY)
3120 					outproc(&p);
3121 			}
3122 		}
3123 		if (count < burst)
3124 			break;
3125 	}
3126 }
3127 
3128 #elif defined (__OpenBSD__)
3129 
3130 #include <uvm/uvm_extern.h>
3131 
3132 static unsigned long
3133 getmem(void)
3134 {
3135 	return 0;
3136 }
3137 
3138 static time_t
3139 tv2sec(long sec, long usec, int mult)
3140 {
3141 	return sec*mult + (usec >= 500000/mult);
3142 }
3143 
3144 static void
3145 getproc(struct proc *p, struct kinfo_proc *kp)
3146 {
3147 	memset(p, 0, sizeof *p);
3148 	p->p_pid = kp->kp_proc.p_pid;
3149 	strncpy(p->p_fname, kp->kp_proc.p_comm, sizeof p->p_fname);
3150 	p->p_fname[sizeof p->p_fname - 1] = '\0';
3151 	p->p_lstate[0] = kp->kp_proc.p_stat;
3152 	p->p_ppid = kp->kp_eproc.e_ppid;
3153 	p->p_pgid = kp->kp_eproc.e_pgid;
3154 	p->p_sid = kp->kp_eproc.e_tpgid;	/* ? */
3155 	p->p_ttydev = kp->kp_eproc.e_tdev;
3156 	p->p_lflag = kp->kp_proc.p_flag;
3157 	p->p_time = tv2sec(kp->kp_eproc.e_pstats.p_ru.ru_utime.tv_sec +
3158 				kp->kp_eproc.e_pstats.p_ru.ru_stime.tv_sec,
3159 			kp->kp_eproc.e_pstats.p_ru.ru_utime.tv_usec +
3160 				kp->kp_eproc.e_pstats.p_ru.ru_stime.tv_usec, 1);
3161 	p->p_accutime = p->p_time +
3162 		tv2sec(kp->kp_eproc.e_pstats.p_cru.ru_utime.tv_sec +
3163 				kp->kp_eproc.e_pstats.p_cru.ru_stime.tv_sec,
3164 			kp->kp_eproc.e_pstats.p_cru.ru_utime.tv_usec +
3165 				kp->kp_eproc.e_pstats.p_cru.ru_stime.tv_usec,
3166 			1);
3167 	p->p_utime = tv2sec(kp->kp_eproc.e_pstats.p_ru.ru_utime.tv_sec,
3168 			kp->kp_eproc.e_pstats.p_ru.ru_utime.tv_usec, 10);
3169 	p->p_ktime = tv2sec(kp->kp_eproc.e_pstats.p_ru.ru_stime.tv_sec,
3170 			kp->kp_eproc.e_pstats.p_ru.ru_stime.tv_usec, 10);
3171 	p->p_intpri = kp->kp_proc.p_usrpri;
3172 	p->p_rtpri = kp->kp_proc.p_priority;
3173 	p->p_policy = SCHED_OTHER;
3174 	p->p_c = kp->kp_proc.p_cpticks;
3175 	p->p_nice = kp->kp_proc.p_nice;
3176 	p->p_nlwp = 1;
3177 	p->p_start = tv2sec(kp->kp_eproc.e_pstats.p_start.tv_sec,
3178 		kp->kp_eproc.e_pstats.p_start.tv_usec, 1);
3179 	p->p_osz = kp->kp_eproc.e_vm.vm_tsize + kp->kp_eproc.e_vm.vm_dsize +
3180 		kp->kp_eproc.e_vm.vm_ssize;
3181 	p->p_orss = kp->kp_eproc.e_vm.vm_rssize;
3182 	p->p_pflts = kp->kp_eproc.e_pstats.p_ru.ru_majflt;
3183 	p->p_bufr = kp->kp_eproc.e_pstats.p_ru.ru_inblock;
3184 	p->p_bufw = kp->kp_eproc.e_pstats.p_ru.ru_oublock;
3185 	p->p_mrcv = kp->kp_eproc.e_pstats.p_ru.ru_msgrcv;
3186 	p->p_msnd = kp->kp_eproc.e_pstats.p_ru.ru_msgsnd;
3187 	p->p_addr = (unsigned long)kp->kp_proc.p_addr;
3188 	p->p_wchan = (unsigned long)kp->kp_proc.p_wchan;
3189 	p->p_pctcpu = kp->kp_proc.p_pctcpu;
3190 	p->p_clname = "TS";
3191 	p->p_uid = kp->kp_eproc.e_pcred.p_ruid;
3192 	p->p_euid = kp->kp_eproc.e_ucred.cr_uid;
3193 	p->p_gid = kp->kp_eproc.e_pcred.p_rgid;
3194 	p->p_egid = kp->kp_eproc.e_ucred.cr_gid;
3195 }
3196 
3197 static void
3198 getargv(struct proc *p, struct kinfo_proc *kp, kvm_t *kt)
3199 {
3200 	char	**args;
3201 	char	*ap, *pp, *xp;
3202 
3203 	if ((args = kvm_getargv(kt, kp, sizeof p->p_psargs)) == NULL) {
3204 		strncpy(p->p_psargs, p->p_fname, sizeof p->p_psargs);
3205 		p->p_psargs[sizeof p->p_psargs - 1] = '\0';
3206 		for (ap = p->p_comm, pp = p->p_psargs;
3207 				*pp && !isblank(*pp); pp++)
3208 			*ap++ = *pp;
3209 		return;
3210 	}
3211 	ap = args[0];
3212 	xp = p->p_comm;
3213 	for (pp = p->p_psargs; pp < &p->p_psargs[sizeof p->p_psargs-1]; pp++) {
3214 		if (*ap == '\0') {
3215 			*pp = ' ';
3216 			if (xp) {
3217 				*xp = '\0';
3218 				xp = NULL;
3219 			}
3220 			ap = *++args;
3221 			if (ap == NULL)
3222 				break;
3223 		} else {
3224 			if (xp)
3225 				*xp++ = *ap;
3226 			*pp = *ap++;
3227 		}
3228 	}
3229 }
3230 
3231 static void
3232 postproc(struct proc *p)
3233 {
3234 	cleanline(p);
3235 	switch (p->p_lstate[0]) {
3236 	default:
3237 	case SIDL:
3238 		p->p_state[0] = 'I';
3239 		break;
3240 	case SRUN:
3241 		p->p_state[0] = 'R';
3242 		break;
3243 	case SSLEEP:
3244 		p->p_state[0] = 'S';
3245 		break;
3246 	case SSTOP:
3247 		p->p_state[0] = 'T';
3248 		break;
3249 	case SZOMB:
3250 	case SDEAD:
3251 		p->p_state[0] = 'Z';
3252 		break;
3253 	}
3254 	p->p_lstate[0] = p->p_state[0];
3255 	if ((p->p_lflag & P_CONTROLT) == 0)
3256 		p->p_ttydev = PRNODEV;
3257 	if ((p->p_lflag & P_INMEM) == 0)
3258 		p->p_flag |= FL_SWAP;
3259 	else
3260 		p->p_flag |= FL_LOAD;
3261 	if (p->p_lflag & P_SYSTEM)
3262 		p->p_flag |= FL_SYS;
3263 	if ((p->p_lflag & P_SINTR) == 0)
3264 		p->p_flag |= FL_LOCK;
3265 	p->p_pri = p->p_rtpri;
3266 	p->p_oldpri = p->p_intpri + 40;
3267 	p->p_size = p->p_osz * kbytes_per_page;
3268 	p->p_rssize = p->p_orss * kbytes_per_page;
3269 }
3270 
3271 static void
3272 do_procs(void)
3273 {
3274 	struct proc	p;
3275 	kvm_t	*kt;
3276 	struct kinfo_proc	*kp;
3277 	int	i, cnt;
3278 	pid_t	mypid = getpid();
3279 	int	gotme = 0;
3280 
3281 	if ((kt = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, "kvm_open")) == NULL)
3282 		exit(1);
3283 	kp = kvm_getprocs(kt, KERN_PROC_ALL, 0, &cnt);
3284 	i = cnt;
3285 	while (--i >= 0) {
3286 	one:	if (kp[i].kp_proc.p_pid == mypid)
3287 			gotme = 1;
3288 		getproc(&p, &kp[i]);
3289 		getargv(&p, &kp[i], kt);
3290 		postproc(&p);
3291 		if (selectproc(&p) == OKAY)
3292 			outproc(&p);
3293 	}
3294 	if (gotme == 0) {
3295 		kp = kvm_getprocs(kt, KERN_PROC_PID, mypid, &cnt);
3296 		goto one;
3297 	}
3298 	kvm_close(kt);
3299 }
3300 
3301 #elif defined (__NetBSD__)
3302 
3303 static unsigned long
3304 getmem(void)
3305 {
3306 	return 0;
3307 }
3308 
3309 static time_t
3310 tv2sec(long sec, long usec, int mult)
3311 {
3312 	return sec*mult + (usec >= 500000/mult);
3313 }
3314 
3315 static void
3316 getproc(struct proc *p, struct kinfo_proc2 *kp)
3317 {
3318 	memset(p, 0, sizeof *p);
3319 	p->p_pid = kp->p_pid;
3320 	strncpy(p->p_fname, kp->p_comm, sizeof p->p_fname);
3321 	p->p_fname[sizeof p->p_fname - 1] = '\0';
3322 	p->p_lstate[0] = kp->p_stat;
3323 	p->p_ppid = kp->p_ppid;
3324 	p->p_pgid = kp->p__pgid;
3325 	p->p_sid = kp->p_sid;
3326 	p->p_ttydev = kp->p_tdev;
3327 	p->p_lflag = kp->p_flag;
3328 	p->p_time = tv2sec(kp->p_uutime_sec + kp->p_ustime_sec,
3329 			kp->p_uutime_usec + kp->p_ustime_usec, 1);
3330 	p->p_accutime = p->p_time + tv2sec(kp->p_uctime_sec,
3331 			kp->p_uctime_usec, 1);
3332 	p->p_utime = tv2sec(kp->p_uutime_sec, kp->p_uutime_usec, 10);
3333 	p->p_ktime = tv2sec(kp->p_ustime_sec, kp->p_ustime_usec, 10);
3334 	p->p_intpri = kp->p_usrpri;
3335 	p->p_rtpri = kp->p_priority;
3336 	p->p_policy = SCHED_OTHER;
3337 	p->p_c = kp->p_cpticks;
3338 	p->p_nice = kp->p_nice;
3339 	p->p_nlwp = 1;
3340 	p->p_start = tv2sec(kp->p_ustart_sec, kp->p_ustart_usec, 1);
3341 	p->p_osz = kp->p_vm_tsize + kp->p_vm_dsize + kp->p_vm_ssize;
3342 	p->p_orss = kp->p_vm_rssize;
3343 	p->p_pflts = kp->p_uru_majflt;
3344 	p->p_bufr = kp->p_uru_inblock;
3345 	p->p_bufw = kp->p_uru_oublock;
3346 	p->p_mrcv = kp->p_uru_msgrcv;
3347 	p->p_msnd = kp->p_uru_msgsnd;
3348 	p->p_addr = kp->p_addr;
3349 	p->p_wchan = kp->p_wchan;
3350 	p->p_psr = kp->p_cpuid;
3351 	p->p_pctcpu = kp->p_pctcpu;
3352 	p->p_clname = "TS";
3353 	p->p_uid = kp->p_ruid;
3354 	p->p_euid = kp->p_uid;
3355 	p->p_gid = kp->p_rgid;
3356 	p->p_egid = kp->p_gid;
3357 }
3358 
3359 static void
3360 getargv(struct proc *p, struct kinfo_proc2 *kp, kvm_t *kt)
3361 {
3362 	char	**args;
3363 	char	*ap, *pp, *xp;
3364 
3365 	if ((args = kvm_getargv2(kt, kp, sizeof p->p_psargs)) == NULL) {
3366 		strncpy(p->p_psargs, p->p_fname, sizeof p->p_psargs);
3367 		p->p_psargs[sizeof p->p_psargs - 1] = '\0';
3368 		for (ap = p->p_comm, pp = p->p_psargs;
3369 				*pp && !isblank(*pp); pp++)
3370 			*ap++ = *pp;
3371 		return;
3372 	}
3373 	ap = args[0];
3374 	xp = p->p_comm;
3375 	for (pp = p->p_psargs; pp < &p->p_psargs[sizeof p->p_psargs-1]; pp++) {
3376 		if (*ap == '\0') {
3377 			*pp = ' ';
3378 			if (xp) {
3379 				*xp = '\0';
3380 				xp = NULL;
3381 			}
3382 			ap = *++args;
3383 			if (ap == NULL)
3384 				break;
3385 		} else {
3386 			if (xp)
3387 				*xp++ = *ap;
3388 			*pp = *ap++;
3389 		}
3390 	}
3391 }
3392 
3393 static void
3394 postproc(struct proc *p)
3395 {
3396 	cleanline(p);
3397 	switch (p->p_lstate[0]) {
3398 	default:
3399 	case SIDL:
3400 		p->p_state[0] = 'I';
3401 		break;
3402 	case SRUN:
3403 		p->p_state[0] = 'R';
3404 		break;
3405 	case SSLEEP:
3406 		p->p_state[0] = 'S';
3407 		break;
3408 	case SSTOP:
3409 		p->p_state[0] = 'T';
3410 		break;
3411 	case SZOMB:
3412 	case SDEAD:
3413 		p->p_state[0] = 'Z';
3414 		break;
3415 	case SONPROC:
3416 		p->p_state[0] = 'O';
3417 		break;
3418 	}
3419 	p->p_lstate[0] = p->p_state[0];
3420 	if ((p->p_lflag & P_CONTROLT) == 0)
3421 		p->p_ttydev = PRNODEV;
3422 	if ((p->p_lflag & P_INMEM) == 0)
3423 		p->p_flag |= FL_SWAP;
3424 	else
3425 		p->p_flag |= FL_LOAD;
3426 	if (p->p_lflag & P_SYSTEM)
3427 		p->p_flag |= FL_SYS;
3428 	if ((p->p_lflag & P_SINTR) == 0)
3429 		p->p_flag |= FL_LOCK;
3430 	p->p_pri = p->p_rtpri;
3431 	p->p_oldpri = p->p_intpri + 40;
3432 	p->p_size = p->p_osz * kbytes_per_page;
3433 	p->p_rssize = p->p_orss * kbytes_per_page;
3434 }
3435 
3436 static void
3437 do_procs(void)
3438 {
3439 	struct proc	p;
3440 	kvm_t	*kt;
3441 	struct kinfo_proc2	*kp;
3442 	int	i, cnt;
3443 	pid_t	mypid = getpid();
3444 	int	gotme = 0;
3445 
3446 	if ((kt = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, "kvm_open")) == NULL)
3447 		exit(1);
3448 	kp = kvm_getproc2(kt, KERN_PROC_ALL, 0, sizeof *kp, &cnt);
3449 	i = cnt;
3450 	while (--i >= 0) {
3451 	one:	if (kp[i].p_pid == mypid)
3452 			gotme = 1;
3453 		getproc(&p, &kp[i]);
3454 		getargv(&p, &kp[i], kt);
3455 		postproc(&p);
3456 		if (selectproc(&p) == OKAY)
3457 			outproc(&p);
3458 	}
3459 	if (gotme == 0) {
3460 		kp = kvm_getproc2(kt, KERN_PROC_PID, mypid, sizeof *kp, &cnt);
3461 		goto one;
3462 	}
3463 	kvm_close(kt);
3464 }
3465 
3466 #elif defined (__APPLE__)
3467 
3468 typedef struct kinfo_proc kinfo_proc;
3469 
3470 static int
3471 GetBSDProcessList(pid_t thepid, struct kinfo_proc **procList, size_t *procCount)
3472     /* derived from http://developer.apple.com/qa/qa2001/qa1123.html */
3473     /* Returns a list of all BSD processes on the system.  This routine
3474        allocates the list and puts it in *procList and a count of the
3475        number of entries in *procCount.  You are responsible for freeing
3476        this list (use "free" from System framework).
3477        all classic apps run in one process
3478        On success, the function returns 0.
3479        On error, the function returns a BSD errno value.
3480        Preconditions:
3481 	assert( procList != NULL);
3482 	assert(*procList == NULL);
3483 	assert(procCount != NULL);
3484        Postconditions:
3485 	assert( (err == 0) == (*procList != NULL) );
3486     */
3487 {
3488 	int			err;
3489 	struct kinfo_proc	*result;
3490 	int			mib[4];
3491 	size_t			length;
3492 
3493 	mib[0] = CTL_KERN;
3494 	mib[1] = KERN_PROC;
3495 	if (thepid == 0) {
3496 		mib[2] = KERN_PROC_ALL;
3497 		mib[3] = 0;
3498 	} else {
3499 		mib[2] = KERN_PROC_PID;
3500 		mib[3] = thepid;
3501 	}
3502 	/* We start by calling sysctl with result == NULL and length == 0.
3503 	   That will succeed, and set length to the appropriate length.
3504 	   We then allocate a buffer of that size and call sysctl again
3505 	   with that buffer.
3506 	*/
3507 	length = 0;
3508 	err = sysctl(mib, 4, NULL, &length, NULL, 0);
3509 	if (err == -1)
3510 		err = errno;
3511 	if (err == 0) {
3512 		result = smalloc(length);
3513 		err = sysctl(mib, 4, result, &length, NULL, 0);
3514 		if (err == -1)
3515 			err = errno;
3516 		if (err == ENOMEM) {
3517 			free(result); /* clean up */
3518 			result = NULL;
3519 		}
3520 	}
3521 	*procList = result;
3522 	*procCount = err == 0 ? length / sizeof **procList : 0;
3523 	return err;
3524 }
3525 
3526 static time_t
3527 tv2sec(time_value_t *tv, int mult)
3528 {
3529 	return tv->seconds*mult + (tv->microseconds >= 500000/mult);
3530 }
3531 
3532 static unsigned long
3533 getmem(void)
3534 {
3535 	static int	mib[] = {CTL_HW, HW_PHYSMEM, 0};
3536 	size_t		size;
3537 	unsigned long	mem;
3538 
3539 	size = sizeof mem;
3540 	if (sysctl(mib, 2, &mem, &size, NULL, 0) == -1) {
3541 		fprintf(stderr, "error in sysctl(): %s\n", strerror(errno));
3542 		exit(3);
3543 	}
3544 	return mem;
3545 }
3546 
3547 extern kern_return_t task_for_pid(task_port_t task, pid_t pid, task_port_t *target);
3548 
3549 static void
3550 getproc(struct proc *p, struct kinfo_proc *kp)
3551 {
3552 	kern_return_t   error;
3553 	unsigned int	info_count = TASK_BASIC_INFO_COUNT;
3554 	unsigned int 	thread_info_count = THREAD_BASIC_INFO_COUNT;
3555 	task_port_t	task;
3556 	pid_t		pid;
3557 	struct		task_basic_info	task_binfo;
3558 	struct		task_thread_times_info task_times;
3559 	time_value_t	total_time, system_time;
3560 	struct		task_events_info task_events;
3561 	struct		policy_timeshare_info tshare;
3562 	struct		policy_rr_info rr;
3563 	struct		policy_fifo_info fifo;
3564 	struct		thread_basic_info th_binfo;
3565 	thread_port_array_t	thread_list;
3566 	int		thread_count;
3567 	int		j, temp, curpri;
3568 
3569 	memset(p, 0, sizeof *p);
3570 
3571 	p->p_pid = kp->kp_proc.p_pid;
3572 	strncpy(p->p_fname, kp->kp_proc.p_comm, sizeof p->p_fname);
3573 	p->p_fname[sizeof p->p_fname - 1] = '\0';
3574 	p->p_lstate[0] = kp->kp_proc.p_stat; /* contains at least zombie info */
3575 	p->p_lflag = kp->kp_proc.p_flag;
3576 	p->p_ppid = kp->kp_eproc.e_ppid;
3577 	p->p_pgid = kp->kp_eproc.e_pgid;
3578 	p->p_sid = kp->kp_eproc.e_tpgid;
3579 	p->p_ttydev = kp->kp_eproc.e_tdev == -1 ? PRNODEV : kp->kp_eproc.e_tdev;
3580 	p->p_uid = kp->kp_eproc.e_pcred.p_ruid;
3581 	p->p_euid = kp->kp_eproc.e_ucred.cr_uid;
3582 	p->p_gid = kp->kp_eproc.e_pcred.p_rgid;
3583 	p->p_egid = kp->kp_eproc.e_ucred.cr_gid;
3584 	p->p_start = kp->kp_proc.p_starttime.tv_sec +
3585 		(kp->kp_proc.p_starttime.tv_usec >= 500000);
3586 	p->p_addr = (unsigned long)kp->kp_proc.p_addr;
3587 	p->p_wchan = (unsigned long)kp->kp_proc.p_wchan;
3588 
3589 	if (p->p_lstate[0] == SZOMB) {
3590 		p->p_lstate[0] = 7;
3591 		return; /* do not fetch more data for zombies */
3592 	}
3593 
3594 	pid = kp->kp_proc.p_pid;
3595 	error = task_for_pid(mach_task_self(), pid, &task);
3596 	if (error != KERN_SUCCESS) {
3597 		/* process already left the system */
3598 		p->p_lstate[0] = 7; /* handle exited process/task like zombie */
3599 		p->p_clname = "??"; /* will be used as nice value */
3600 		return;
3601 	}
3602 	info_count = TASK_BASIC_INFO_COUNT;
3603 	error = task_info(task, TASK_BASIC_INFO, &task_binfo, &info_count);
3604 	if (error != KERN_SUCCESS) {
3605 		fprintf(stderr, "Error calling task_info():%d\n", error);
3606 		exit(3);
3607 	}
3608 	info_count = TASK_THREAD_TIMES_INFO_COUNT;
3609 	error = task_info(task, TASK_THREAD_TIMES_INFO, &task_times, &info_count);
3610 	if (error != KERN_SUCCESS) {
3611 		fprintf(stderr, "Error calling task_info():%d\n", error);
3612 		exit(3);
3613 	}
3614 	info_count = TASK_EVENTS_INFO_COUNT;
3615 	error = task_info(task, TASK_EVENTS_INFO, &task_events, &info_count);
3616 	if (error != KERN_SUCCESS) {
3617 		fprintf(stderr, "Error calling task_info():%d\n", error);
3618 		exit(3);
3619 	}
3620 
3621 	total_time = task_times.user_time;
3622 	p->p_utime = tv2sec(&total_time, 1);
3623 
3624 	system_time = task_times.system_time;
3625 	p->p_ktime = tv2sec(&system_time, 1);
3626 
3627 	time_value_add(&total_time, &system_time);
3628 	p->p_time = tv2sec(&total_time, 1);
3629 
3630 	time_value_add(&total_time, &task_binfo.user_time);
3631 	time_value_add(&total_time, &task_binfo.system_time);
3632 	p->p_accutime = tv2sec(&total_time, 1);
3633 
3634 	switch(task_binfo.policy) {
3635 		case POLICY_TIMESHARE :
3636 			info_count = POLICY_TIMESHARE_INFO_COUNT;
3637 			error = task_info(task, TASK_SCHED_TIMESHARE_INFO, &tshare, &info_count);
3638 			if (error == KERN_SUCCESS) {
3639 				p->p_intpri = tshare.cur_priority;
3640 				p->p_rtpri = tshare.base_priority;
3641 				p->p_clname = "TS";
3642 				p->p_policy = SCHED_OTHER;
3643 			}
3644 			break;
3645 		case POLICY_RR :
3646 			info_count = POLICY_RR_INFO_COUNT;
3647 			error = task_info(task, TASK_SCHED_RR_INFO, &rr, &info_count);
3648 			if (error == KERN_SUCCESS) {
3649 				p->p_intpri = rr.base_priority;
3650 				p->p_rtpri = rr.base_priority;
3651 				p->p_clname = "RT";
3652 				p->p_policy = SCHED_RR;
3653 			}
3654 			break;
3655 		case POLICY_FIFO :
3656 			info_count = POLICY_FIFO_INFO_COUNT;
3657 			error = task_info(task, TASK_SCHED_FIFO_INFO, &fifo, &info_count);
3658 			if (error == KERN_SUCCESS) {
3659 				p->p_intpri = fifo.base_priority;
3660 				p->p_rtpri = fifo.base_priority;
3661 				p->p_clname = "FF";
3662 				p->p_policy = SCHED_FIFO;
3663 			}
3664 			break;
3665 	}
3666 	p->p_nice = kp->kp_proc.p_nice;
3667 
3668 	/* allocates a thread port array */
3669 	error = task_threads(task, &thread_list, &thread_count);
3670 	if (error != KERN_SUCCESS) {
3671 		mach_port_deallocate(mach_task_self(), task);
3672 		fprintf(stderr, "Error calling task_threads():%d\n", error);
3673 		exit(3);
3674 	}
3675 	p->p_nlwp = thread_count;
3676 	/* iterate over all threads for: cpu, state, swapped, prio */
3677 	/* it should also be possible to print all mach threads as LWPs */
3678 	p->p_lflag |= FL_SWAP; /* assume swapped */
3679 	curpri = p->p_intpri;
3680 	for (j = 0; j < thread_count; j++) {
3681 		info_count = THREAD_BASIC_INFO_COUNT;
3682 		error = thread_info(thread_list[j], THREAD_BASIC_INFO, &th_binfo, &info_count);
3683 		if (error != KERN_SUCCESS) {
3684 			fprintf(stderr, "Error calling thread_info():%d\n", error);
3685 			exit(3);
3686 		}
3687 		p->p_c += th_binfo.cpu_usage;
3688 		switch (th_binfo.run_state) {
3689 			case TH_STATE_RUNNING:
3690 				temp=1;
3691 				break;
3692 			case TH_STATE_UNINTERRUPTIBLE:
3693 				temp=2;
3694 				break;
3695 			case TH_STATE_WAITING:
3696 				temp=(th_binfo.sleep_time <= 20) ? 3 : 4;
3697 				break;
3698 			case TH_STATE_STOPPED:
3699 				temp=5;
3700 				break;
3701 			case TH_STATE_HALTED:
3702 				temp=6;
3703 				break;
3704 			default:
3705 				temp=8;
3706 		}
3707 		if (temp < p->p_lstate[0])
3708 			p->p_lstate[0] = temp;
3709 		if ((th_binfo.flags & TH_FLAGS_SWAPPED ) == 0)
3710 			p->p_lflag &= ~FL_SWAP; /* in mem */
3711 		switch(th_binfo.policy) {
3712 			case POLICY_TIMESHARE :
3713 				info_count = POLICY_TIMESHARE_INFO_COUNT;
3714 				error = thread_info(thread_list[j], THREAD_SCHED_TIMESHARE_INFO, &tshare, &info_count);
3715 				if (error == KERN_SUCCESS && curpri < tshare.cur_priority)
3716 					curpri = tshare.cur_priority;
3717 				break;
3718 			case POLICY_RR :
3719 				info_count = POLICY_RR_INFO_COUNT;
3720 				error = thread_info(thread_list[j], THREAD_SCHED_RR_INFO, &rr, &info_count);
3721 				if (error == KERN_SUCCESS && curpri < rr.base_priority)
3722 					curpri = rr.base_priority;
3723 				break;
3724 			case POLICY_FIFO :
3725 				info_count = POLICY_FIFO_INFO_COUNT;
3726 				error = thread_info(thread_list[j], THREAD_SCHED_FIFO_INFO, &fifo, &info_count);
3727 				if (error == KERN_SUCCESS && curpri < fifo.base_priority)
3728 					curpri = fifo.base_priority;
3729 				break;
3730 		}
3731 		mach_port_deallocate(mach_task_self(), thread_list[j]);
3732 	}
3733 	p->p_intpri = curpri;
3734 	/* free the thread port array */
3735 	error = vm_deallocate(mach_task_self(), (vm_address_t)thread_list, thread_count * sizeof(thread_port_array_t));
3736 	p->p_c = p->p_c / (TH_USAGE_SCALE/100);
3737 	p->p_pctcpu = p->p_c;
3738 
3739 	p->p_osz = task_binfo.virtual_size / pagesize;
3740 	p->p_orss = task_binfo.resident_size / pagesize;
3741 
3742 	p->p_pflts = task_events.pageins;
3743 	p->p_bufr = 0;
3744 	p->p_bufw = 0;
3745 	p->p_mrcv = task_events.messages_sent; /* Mach messages */
3746 	p->p_msnd = task_events.messages_received;
3747 
3748 	mach_port_deallocate(mach_task_self(), task);
3749 }
3750 
3751 static void
3752 getargv(struct proc *p, struct kinfo_proc *kp)
3753 {
3754 	size_t	size, argsz;
3755 	char	*argbuf;
3756 	int	mib[3];
3757 	long	nargs;
3758 	char	*ap, *pp, *xp;
3759 
3760 	/* ignore kernel and zombies */
3761 	if (kp->kp_proc.p_pid == 0 || p->p_lstate[0] == 7)
3762 		return;
3763 
3764 	/* allocate a procargs space per process */
3765 	mib[0] = CTL_KERN;
3766 	mib[1] = KERN_ARGMAX;
3767 	size = sizeof argsz;
3768 	if (sysctl(mib, 2, &argsz, &size, NULL, 0) == -1) {
3769 		fprintf(stderr, "error in sysctl(): %s\n", strerror(errno));
3770 		exit(3);
3771 	}
3772 	argbuf = smalloc(argsz);
3773 
3774 	/* fetch the process arguments */
3775 	mib[0] = CTL_KERN;
3776 	mib[1] = KERN_PROCARGS2;
3777 	mib[2] = kp->kp_proc.p_pid;
3778 	if (sysctl(mib, 3, argbuf, &argsz, NULL, 0) == -1) {
3779 		/* process already left the system */
3780 		return;
3781 	}
3782 
3783 	/* the number of args is at offset 0, this works for 32 and 64bit */
3784 	memcpy(&nargs, argbuf, sizeof nargs);
3785 	ap = argbuf + sizeof nargs;
3786 
3787 	/* skip the exec_path */
3788 	while (ap < &argbuf[argsz] && *ap != '\0')
3789 		ap++;
3790 	if (ap == &argbuf[argsz])
3791 		goto DONE; /* no args to show */
3792 	/* skip trailing '\0' chars */
3793 	while (ap < &argbuf[argsz] && *ap == '\0')
3794 		ap++;
3795 	if (ap == &argbuf[argsz])
3796 		goto DONE; /* no args to show */
3797 
3798 	xp = p->p_comm; /* copy the command name also */
3799 	/* now concat copy the arguments */
3800 	for (pp = p->p_psargs; pp < &p->p_psargs[sizeof p->p_psargs-1]; pp++) {
3801 		if (*ap == '\0') {
3802 			if (xp) {
3803 				*xp = '\0';
3804 				xp = NULL;
3805 			}
3806 			if (--nargs == 0)
3807 				break;
3808 			*pp = ' ';
3809 			++ap;
3810 		} else {
3811 			if (xp)
3812 				*xp++ = *ap;
3813 			*pp = *ap++;
3814 		}
3815 	}
3816 	*pp = '\0';
3817 
3818 DONE:	free(argbuf);
3819 	return;
3820 }
3821 
3822 static void
3823 postproc(struct proc *p)
3824 {
3825 	cleanline(p);
3826 	if (p->p_lstate[0] < 0 || p->p_lstate[0] > 8) /* play safe */
3827 		p->p_lstate[0] = 8;
3828 	p->p_state[0] = " RSSITHZ?"[p->p_lstate[0]];
3829 	p->p_lstate[0] = p->p_state[0];
3830 	if (p->p_lflag & P_SYSTEM)
3831 		p->p_flag |= FL_SYS;
3832 	p->p_pri = p->p_rtpri;
3833 	p->p_oldpri = p->p_intpri;
3834 	p->p_size = p->p_osz * kbytes_per_page;
3835 	p->p_rssize = p->p_orss * kbytes_per_page;
3836 }
3837 
3838 static void
3839 do_procs(void)
3840 {
3841 	struct	proc p;
3842 	struct	kinfo_proc *kp = NULL;
3843 	size_t	i, cnt;
3844 	pid_t	pid0;
3845 	int	err;
3846 
3847 	/* get all processes */
3848 	pid0 = 0;
3849 	if ((err = GetBSDProcessList(pid0, &kp, &cnt)) != 0) {
3850 		fprintf(stderr, "error getting proc list: %s\n", strerror(err));
3851 		exit(3);
3852 	}
3853 	i = cnt;
3854 	while (--i >= 0) {
3855 		/* ignore trailing garbage processes with pid 0 */
3856 		if (kp[i].kp_proc.p_pid == 0 && pid0++ > 0)
3857 			break;
3858 		getproc(&p, &kp[i]);
3859 		getargv(&p, &kp[i]);
3860 		postproc(&p);
3861 		if (selectproc(&p) == OKAY)
3862 			outproc(&p);
3863 	}
3864 	/* free the memory allocated by GetBSDProcessList */
3865 	free(kp);
3866 }
3867 
3868 #endif	/* all */
3869 
3870 /************************************************************************
3871  * 			Option scanning					*
3872  ************************************************************************/
3873 
3874 static void
3875 add_device(const char *prefix, size_t prefixlen,
3876 		const char *name, struct stat *sp)
3877 {
3878 	char	*str;
3879 	dev_type	sz;
3880 
3881 	if (eq(name, "stdin") || eq(name, "stdout") || eq(name, "stderr"))
3882 		return;
3883 	sz = prefixlen + strlen(name) + 1;
3884 	str = smalloc(sz);
3885 	strcpy(str, prefix);
3886 	strcpy(&str[prefixlen], name);
3887 	dlook(sp->st_rdev, d0, str);
3888 #ifdef	USE_PS_CACHE
3889 	if (devfp != NULL) {
3890 		dev_type	dev = sp->st_rdev;
3891 
3892 		fwrite(&dev, sizeof dev, 1, devfp);
3893 		fwrite(&sz, sizeof sz, 1, devfp);
3894 		fwrite(str, 1, sz, devfp);
3895 	}
3896 #endif	/* USE_PS_CACHE */
3897 }
3898 
3899 static void
3900 add_devices_from(const char *path, const char *prefix)
3901 {
3902 	DIR	*Dp;
3903 	struct dirent	*dp;
3904 	struct stat	st;
3905 	size_t	prefixlen;
3906 
3907 	if (chdir(path) == 0) {
3908 		if ((Dp = opendir(".")) != NULL) {
3909 			prefixlen = strlen(prefix);
3910 			while ((dp = readdir(Dp)) != NULL) {
3911 				if (stat(dp->d_name, &st) == 0 &&
3912 						S_ISCHR(st.st_mode))
3913 					add_device(prefix, prefixlen,
3914 							dp->d_name, &st);
3915 			}
3916 			closedir(Dp);
3917 		}
3918 	}
3919 }
3920 
3921 static void
3922 devices(void)
3923 {
3924 #ifdef	USE_PS_CACHE
3925 	struct stat	dst, fst;
3926 #endif	/* USE_PS_CACHE */
3927 	struct output	*o;
3928 
3929 	for (o = o0; o; o = o->o_nxt)
3930 		if (o->o_typ == OU_TTY)
3931 			break;
3932 	if (o == NULL)
3933 		return;
3934 	d0 = scalloc(256, sizeof *d0);
3935 	add_devices_from("/dev/pts", "pts/");
3936 	/*
3937 	 * Names in devfs.
3938 	 */
3939 	add_devices_from("/dev/tts", "tts/");
3940 	add_devices_from("/dev/cua", "cua/");
3941 	add_devices_from("/dev/vc", "vc/");
3942 	add_devices_from("/dev/vcc", "vcc/");
3943 	add_devices_from("/dev/pty", "pty/");
3944 #ifdef	USE_PS_CACHE
3945 	if (stat(ps_cache_file, &fst) < 0 ||
3946 		(stat("/dev", &dst) == 0 && dst.st_mtime > fst.st_mtime) ||
3947 		(stat("/dev/usb", &dst) == 0 && dst.st_mtime > fst.st_mtime) ||
3948 		(stat("/dev/term", &dst) == 0 && dst.st_mtime > fst.st_mtime)) {
3949 putcache:
3950 		if (dropprivs && myuid && myeuid && myuid != myeuid)
3951 			setuid(myeuid);
3952 		umask(0022);
3953 		if ((devfp = wopen(ps_cache_file)) != NULL) {
3954 			fchown(fileno(devfp), myeuid, ps_cache_gid);
3955 			fchmod(fileno(devfp), ps_cache_mode);
3956 			fwrite(cacheid, 1, strlen(cacheid) + 1, devfp);
3957 		}
3958 		if (dropprivs && myuid != myeuid)
3959 			setuid(myuid);
3960 muststat:
3961 #endif	/* USE_PS_CACHE */
3962 		add_devices_from("/dev/term", "term/");
3963 		add_devices_from("/dev/usb", "usb/");
3964 		add_devices_from("/dev", "");
3965 #ifdef	USE_PS_CACHE
3966 	} else {
3967 		char	*str;
3968 		dev_type	dev;
3969 		dev_type	sz;
3970 		char	*thisid;
3971 
3972 		if ((fst.st_uid != 0 && fst.st_uid != myeuid) ||
3973 				(devfp = fopen(ps_cache_file, "r")) == NULL)
3974 			goto muststat;
3975 		sz = strlen(cacheid) + 1;
3976 		thisid = alloca(sz);
3977 		if (fread(thisid, 1, sz, devfp) != sz ||
3978 				strcmp(cacheid, thisid)) {
3979 			fclose(devfp);
3980 			devfp = NULL;
3981 			goto putcache;
3982 		}
3983 		if (dropprivs && myuid != myeuid)
3984 			setuid(myuid);
3985 		while (fread(&dev, sizeof dev, 1, devfp) == 1 &&
3986 				fread(&sz, sizeof sz, 1, devfp) == 1) {
3987 			str = smalloc(sz);
3988 			if (fread(str, 1, sz, devfp) != sz)
3989 				break;
3990 			dlook(dev, d0, str);
3991 		}
3992 	}
3993 	if (devfp != NULL) {
3994 		fclose(devfp);
3995 		devfp = NULL;
3996 	}
3997 #endif	/* USE_PS_CACHE */
3998 }
3999 
4000 #ifdef	UCB
4001 static void
4002 usage(void)
4003 {
4004 	fprintf(stderr, "usage: %s [ -acglnrSuvwx ] [ -t term ] [ num ]\n",
4005 		progname);
4006 	exit(2);
4007 }
4008 #else	/* !UCB */
4009 static void
4010 usage(void)
4011 {
4012 	fprintf(stderr, "\
4013 usage: %s [ -edalfcj ] [ -r sysname ] [ -t termlist ]\n\
4014         [ -u uidlist ] [ -p proclist ] [ -g grplist ] [ -s sidlist ]\n",
4015 	  progname);
4016 	exit(2);
4017 }
4018 #endif	/* !UCB */
4019 
4020 static const char *
4021 element(const char **listp, int override)
4022 {
4023 	static char	*buf;
4024 	static size_t	buflen;
4025 	const char	*cp, *op;
4026 	char	*cq;
4027 	size_t	sz;
4028 	int	stop = ',';
4029 
4030 	if (**listp == '\0')
4031 		return NULL;
4032 	op = *listp;
4033 	while (**listp != '\0') {
4034 		if (**listp == override)
4035 			stop = '\0';
4036 		if (stop != '\0' && (**listp == stop || isblank(**listp)))
4037 			break;
4038 		(*listp)++;
4039 	}
4040 	if (**listp == '\0')
4041 		return op;
4042 	if ((sz = *listp - op + 1) > buflen) {
4043 		buflen = sz;
4044 		buf = srealloc(buf, buflen);
4045 	}
4046 	for (cp = op, cq = buf; cp < *listp; cp++, cq++)
4047 		*cq = *cp;
4048 	*cq = '\0';
4049 	if (**listp) {
4050 		while (**listp == stop || isblank(**listp))
4051 			(*listp)++;
4052 	}
4053 	return buf;
4054 }
4055 
4056 static void
4057 add_criterion(enum crtype cy, unsigned long val)
4058 {
4059 	struct criterion	*ct;
4060 
4061 	ct = scalloc(1, sizeof *ct);
4062 	ct->c_typ = cy;
4063 	ct->c_val = val;
4064 	ct->c_nxt = c0;
4065 	c0 = ct;
4066 }
4067 
4068 static enum okay
4069 get_rdev(const char *device, unsigned long *id)
4070 {
4071 	struct stat	st;
4072 	char	*file;
4073 
4074 	*id = 0;
4075 	file = alloca(strlen(device) + 9);
4076 	strcpy(file, "/dev/");
4077 	strcpy(&file[5], device);
4078 	if (stat(file, &st) < 0) {
4079 		strcpy(file, "/dev/tty");
4080 		strcpy(&file[8], device);
4081 		if (stat(file, &st) == 0)
4082 			*id = st.st_rdev;
4083 		else if ((device[0] == '?' || device[0] == '-') &&
4084 				device[1] == '\0')
4085 			add_criterion(CR_WITHOUT_TTY, 0);
4086 		else
4087 			return STOP;
4088 	} else
4089 		*id = st.st_rdev;
4090 	return OKAY;
4091 }
4092 
4093 static void
4094 nonnumeric(const char *string, enum crtype ct)
4095 {
4096 #ifndef	UCB
4097 	int	c;
4098 
4099 	switch (ct) {
4100 	case CR_PROCESS_GROUP:
4101 		c = 'g';
4102 		break;
4103 	case CR_PROCESS_ID:
4104 		c = 'p';
4105 		break;
4106 	case CR_SESSION_LEADER:
4107 		c = 's';
4108 		break;
4109 	default:
4110 		c = '?';
4111 	}
4112 	fprintf(stderr,
4113 		"%s: %s is an invalid non-numeric argument for -%c option\n",
4114 			progname, string, c);
4115 #else	/* UCB */
4116 	fprintf(stderr,
4117 		"%s: %s is an invalid non-numeric argument for a process id\n",
4118 			progname, string);
4119 #endif	/* UCB */
4120 }
4121 
4122 static void
4123 add_criterion_string(enum crtype ct, const char *string)
4124 {
4125 	struct passwd	*pwd;
4126 	struct group	*grp;
4127 	char	*x;
4128 	unsigned long	val = 0;
4129 
4130 	switch (ct) {
4131 	case CR_ALL:
4132 	case CR_ALL_WITH_TTY:
4133 	case CR_ALL_BUT_SESSION_LEADERS:
4134 	case CR_WITHOUT_TTY:
4135 	case CR_NO_TTY_NO_SESSION_LEADER:
4136 	case CR_ADD_UNINTERESTING:
4137 	case CR_DEFAULT:
4138 		val = 0;
4139 		break;
4140 	case CR_PROCESS_GROUP:
4141 	case CR_PROCESS_ID:
4142 	case CR_SESSION_LEADER:
4143 		val = strtoul(string, &x, 10);
4144 		if (*x != '\0' || *string == '+' || *string == '-' ||
4145 				*string == '\0') {
4146 			nonnumeric(string, ct);
4147 			ct = CR_INVALID_STOP;
4148 		}
4149 		break;
4150 	case CR_REAL_GID:
4151 		if ((grp = getgrnam(string)) != NULL) {
4152 			val = grp->gr_gid;
4153 		} else {
4154 			val = strtoul(string, &x, 10);
4155 			if (*x != '\0' || *string == '+' || *string == '-' ||
4156 					*string == '\0') {
4157 				fprintf(stderr, "%s: unknown group %s\n",
4158 						progname, string);
4159 				ct = CR_INVALID_REAL_GID;
4160 			}
4161 		}
4162 		break;
4163 	case CR_EFF_UID:
4164 	case CR_REAL_UID:
4165 		if ((pwd = getpwnam(string)) != NULL) {
4166 			val = pwd->pw_uid;
4167 		} else {
4168 			val = strtoul(string, &x, 10);
4169 			if (*x != '\0' || *string == '+' || *string == '-' ||
4170 					*string == '\0') {
4171 				fprintf(stderr, "%s: unknown user %s\n",
4172 						progname, string);
4173 				ct = (ct == CR_EFF_UID ? CR_INVALID_EFF_UID :
4174 					CR_INVALID_REAL_UID);
4175 			}
4176 		}
4177 		break;
4178 	case CR_TTY_DEVICE:
4179 		if (get_rdev(string, &val) == STOP) {
4180 			add_criterion(CR_INVALID_TTY_DEVICE, 0);
4181 			return;
4182 		}
4183 		break;
4184 	}
4185 	add_criterion(ct, val);
4186 }
4187 
4188 static void
4189 add_criteria_list(enum crtype ct, const char *list)
4190 {
4191 	const char	*cp;
4192 
4193 	if (*list)
4194 		while ((cp = element(&list, '\0')) != NULL)
4195 			add_criterion_string(ct, cp);
4196 	else
4197 		add_criterion_string(ct, "");
4198 }
4199 
4200 static void
4201 add_format(enum outype ot, const char *name)
4202 {
4203 	struct output	*op, *oq;
4204 	unsigned	i = 0;
4205 
4206 	while (outspec[i].os_typ != ot)
4207 		i++;
4208 	op = scalloc(1, sizeof *op);
4209 	op->o_typ = ot;
4210 	if (outspec[i].os_flags & OS_Lflag)
4211 		Lflag |= 1;
4212 	if (name == NULL) {
4213 		op->o_nam = outspec[i].os_def;
4214 		op->o_len = strlen(op->o_nam);
4215 		dohdr++;
4216 	} else if (*name == '\0') {
4217 		op->o_nam = "";
4218 		op->o_len = strlen(outspec[i].os_def);
4219 	} else {
4220 		op->o_nam = smalloc(strlen(name) + 1);
4221 		strcpy(op->o_nam, name);
4222 		op->o_len = strlen(op->o_nam);
4223 		dohdr++;
4224 	}
4225 	if (o0 != NULL) {
4226 		for (oq = o0; oq->o_nxt; oq = oq->o_nxt);
4227 		oq->o_nxt = op;
4228 	} else
4229 		o0 = op;
4230 }
4231 
4232 static void
4233 add_format_string(const char *string)
4234 {
4235 	char	*fmt;
4236 	char	*name = NULL;
4237 	unsigned	i;
4238 
4239 	fmt = alloca(strlen(string) + 1);
4240 	strcpy(fmt, string);
4241 	if ((name = strchr(fmt, '=')) != NULL) {
4242 		*name++ = '\0';
4243 	}
4244 	for (i = 0; outspec[i].os_fmt != NULL; i++) {
4245 		if (eq(outspec[i].os_fmt, fmt)) {
4246 			add_format(outspec[i].os_typ, name);
4247 			break;
4248 		}
4249 	}
4250 	if (outspec[i].os_fmt == NULL) {
4251 		fprintf(stderr, "%s: unknown output format: -o %s\n",
4252 				progname, string);
4253 		usage();
4254 	}
4255 }
4256 
4257 static void
4258 add_format_list(const char *list)
4259 {
4260 	const char	*cp;
4261 
4262 	while ((cp = element(&list, '=')) != NULL)
4263 		add_format_string(cp);
4264 }
4265 
4266 static void
4267 defaults(void)
4268 {
4269 	FILE	*fp;
4270 
4271 	if ((fp = fopen(DEFAULT, "r")) != NULL) {
4272 		char	buf[LINE_MAX];
4273 		char	*cp, *x;
4274 
4275 		while (fgets(buf, sizeof buf, fp) != NULL) {
4276 			if (buf[0] == '\0' || buf[0] == '\n' || buf[0] == '#')
4277 				continue;
4278 			if ((cp = strchr(buf, '\n')) != NULL)
4279 				*cp = '\0';
4280 			if (strncmp(buf, "O1_SCHEDULER=", 13) == 0) {
4281 				sched_selection = atoi(&buf[13]) ? 1 : -1;
4282 			} else if (strncmp(buf, "DROPPRIVS=", 10) == 0) {
4283 				dropprivs = strtol(&buf[10], &x, 10);
4284 				if (*x != '\0' || dropprivs != 1)
4285 					dropprivs = 0;
4286 			}
4287 #ifdef	USE_PS_CACHE
4288 			else if (strncmp(buf, "CACHE_FILE=", 11) == 0) {
4289 				if (buf[11] == '/' && buf[12] != '\0') {
4290 					ps_cache_file = smalloc(strlen(
4291 							&buf[11]) + 1);
4292 					strcpy(ps_cache_file, &buf[11]);
4293 				}
4294 			} else if (strncmp(buf, "CACHE_MODE=", 11) == 0) {
4295 				mode_t	m;
4296 
4297 				m = strtol(&buf[11], &x, 8);
4298 				if (*x == '\0')
4299 					ps_cache_mode = m;
4300 			} else if (strncmp(buf, "CACHE_GROUP=", 12) == 0) {
4301 				struct group	*grp;
4302 				gid_t	gid;
4303 
4304 				if ((grp = getgrnam(&buf[12])) == NULL) {
4305 					gid = strtoul(&buf[12], &x, 10);
4306 					if (*x == '\0')
4307 						ps_cache_gid = gid;
4308 				} else
4309 					ps_cache_gid = grp->gr_gid;
4310 			}
4311 #endif	/* USE_PS_CACHE */
4312 		}
4313 		fclose(fp);
4314 	}
4315 }
4316 
4317 #ifndef	UCB
4318 static const char	optstring[] = ":aAcdefg:G:jlLn:o:Pp:r:Rs:t:u:U:Ty";
4319 #else	/* UCB */
4320 static const char	optstring[] = ":acglLnrSuvwxt:R:AG:p:U:o:";
4321 #endif	/* UCB */
4322 
4323 /*
4324  * If -r sysname is given, chroot() needs to be done before any files are
4325  * opened -> scan options twice, first for evaluating '-r' and syntactic
4326  * correctness, then for evaluating other options (in options() below).
4327  */
4328 static void
4329 sysname(int ac, char **av)
4330 {
4331 	extern int	chroot(const char *);
4332 	const char	*dir = NULL;
4333 	int	i, hadflag = 0, illegal = 0;
4334 
4335 	while ((i = getopt(ac, av, optstring)) != EOF) {
4336 		switch (i) {
4337 #ifndef	UCB
4338 		case 'r':
4339 			rflag = optarg;
4340 			break;
4341 		case 'e':
4342 		case 's':
4343 		case 'd':
4344 		case 'a':
4345 		case 't':
4346 		case 'p':
4347 		case 'u':
4348 		case 'g':
4349 		case 'U':
4350 		case 'G':
4351 		case 'A':
4352 			hadflag = 1;
4353 			break;
4354 #else	/* UCB */
4355 		case 'R':
4356 			rflag = optarg;
4357 			break;
4358 		case 'a':
4359 		case 'x':
4360 		case 't':
4361 		case 'p':
4362 		case 'U':
4363 		case 'G':
4364 		case 'A':
4365 			hadflag = 1;
4366 			break;
4367 #endif	/* UCB */
4368 		case ':':
4369 			fprintf(stderr,
4370 				"%s: option requires an argument -- %c\n",
4371 				progname, optopt);
4372 			illegal = 1;
4373 			break;
4374 		case '?':
4375 			fprintf(stderr, "%s: illegal option -- %c\n",
4376 				progname, optopt);
4377 			illegal = 1;
4378 			break;
4379 		}
4380 	}
4381 	if (illegal)
4382 		usage();
4383 #ifndef	UCB
4384 	if (av[optind])
4385 		usage();
4386 #else	/* UCB */
4387 	if (av[optind] && av[optind + 1]) {
4388 		fprintf(stderr, "%s: too many arguments\n", progname);
4389 		usage();
4390 	}
4391 #endif	/* UCB */
4392 	if (rflag) {
4393 		if (hadflag == 0) {
4394 			fprintf(stderr,
4395 		"%s: one of -%s must be used with -%c sysname\n",
4396 				progname,
4397 #ifndef	UCB
4398 				"esdatpugUGA", 'r'
4399 #else
4400 				"axtpUGA", 'R'
4401 #endif
4402 				);
4403 			usage();
4404 		}
4405 		if (*rflag != '/') {
4406 #if defined (__linux__) || defined (__hpux) || defined (_AIX)
4407 			FILE	*fp;
4408 			struct mntent	*mp;
4409 #if defined (__linux__) || defined (_AIX)
4410 			const char	mtab[] = "/etc/mtab";
4411 #else
4412 			const char	mtab[] = "/etc/mnttab";
4413 #endif
4414 
4415 			if ((fp = setmntent(mtab, "r")) == NULL) {
4416 				fprintf(stderr, "%s: cannot open %s\n",
4417 						progname, mtab);
4418 				exit(1);
4419 			}
4420 			dir = NULL;
4421 			while ((mp = getmntent(fp)) != NULL) {
4422 				if (strcmp(mp->mnt_type, MNTTYPE_IGNORE) == 0)
4423 					continue;
4424 				if (strcmp(rflag, basename(mp->mnt_dir)) == 0) {
4425 					dir = sstrdup(mp->mnt_dir);
4426 					break;
4427 				}
4428 			}
4429 			endmntent(fp);
4430 #elif defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) \
4431 	|| defined (__DragonFly__) || defined (__APPLE__)
4432 			struct statfs	*sp = NULL;
4433 			int	cnt, i;
4434 
4435 			if ((cnt = getmntinfo(&sp, MNT_WAIT)) <= 0) {
4436 				fprintf(stderr, "%s: cannot get mounts\n",
4437 						progname);
4438 				exit(1);
4439 			}
4440 			for (i = 0; i < cnt; i++)
4441 				if (!strcmp(rflag,
4442 						basename(sp[i].f_mntonname))) {
4443 					dir = sstrdup(sp[i].f_mntonname);
4444 					break;
4445 				}
4446 #else	/* SVR4 */
4447 			FILE	*fp;
4448 			struct mnttab	mt;
4449 			const char	mtab[] = "/etc/mnttab";
4450 
4451 			if ((fp = fopen(mtab, "r")) == NULL) {
4452 				fprintf(stderr, "%s: cannot open %s\n",
4453 						progname, mtab);
4454 				exit(1);
4455 			}
4456 			dir = NULL;
4457 			while (getmntent(fp, &mt) == 0)
4458 				if (!strcmp(rflag, basename(mt.mnt_mountp))) {
4459 					dir = sstrdup(mt.mnt_mountp);
4460 					break;
4461 				}
4462 			fclose(fp);
4463 #endif	/* SVR4 */
4464 			if (dir == NULL) {
4465 				fprintf(stderr,
4466 					"%s: cannot find path to system %s\n",
4467 					progname, rflag);
4468 				exit(1);
4469 			}
4470 		} else
4471 			dir = rflag;
4472 		if (chroot(dir) < 0) {
4473 			fprintf(stderr, "%s: cannot change root to %s\n",
4474 					progname, dir);
4475 			exit(1);
4476 		}
4477 	}
4478 	optind = 1;
4479 }
4480 
4481 #ifndef	UCB
4482 extern int		sysv3;		/* emulate SYSV3 behavior */
4483 
4484 static void
4485 options(int ac, char **av)
4486 {
4487 	int	cflag = 0;		/* priocntl format */
4488 	int	fflag = 0;		/* full format */
4489 	int	jflag = 0;		/* jobs format */
4490 	int	lflag = 0;		/* long format */
4491 	int	Pflag = 0;		/* print processor information */
4492 	int	Rflag = 0;		/* EP/IX resource format */
4493 	int	Tflag = 0;		/* EP/IX thread format */
4494 	int	yflag = 0;		/* modify format */
4495 	int	i;
4496 
4497 	if (getenv("SYSV3") != NULL)
4498 		sysv3 = 1;
4499 #ifdef	S42
4500 	cflag = 1;
4501 #endif	/* S42 */
4502 	while ((i = getopt(ac, av, optstring)) != EOF) {
4503 		switch (i) {
4504 		case 'a':
4505 			add_criterion(CR_ALL_WITH_TTY, 0);
4506 			break;
4507 		case 'c':
4508 			cflag++;
4509 			break;
4510 		case 'd':
4511 			add_criterion(CR_ALL_BUT_SESSION_LEADERS, 0);
4512 			break;
4513 		case 'e':
4514 		case 'A':
4515 			add_criterion(CR_ALL, 0);
4516 			break;
4517 		case 'f':
4518 			fflag = 1;
4519 			break;
4520 		case 'g':
4521 			add_criteria_list(CR_PROCESS_GROUP, optarg);
4522 			break;
4523 		case 'G':
4524 			add_criteria_list(CR_REAL_GID, optarg);
4525 			break;
4526 		case 'j':
4527 			jflag = 1;
4528 			break;
4529 		case 'l':
4530 			lflag = 1;
4531 			break;
4532 		case 'L':
4533 			Lflag = 3;
4534 			break;
4535 		case 'n':
4536 			fprintf(stderr, "%s: warning: -n option ignored\n",
4537 					progname);
4538 			break;
4539 		case 'o':
4540 			oflag = 1;
4541 			add_format_list(optarg);
4542 			break;
4543 		case 'P':
4544 			Pflag = 1;
4545 			break;
4546 		case 'p':
4547 			add_criteria_list(CR_PROCESS_ID, optarg);
4548 			break;
4549 		case 'r':
4550 			rflag = optarg;
4551 			break;
4552 		case 'R':
4553 			Rflag = 1;
4554 			break;
4555 		case 's':
4556 			add_criteria_list(CR_SESSION_LEADER, optarg);
4557 			break;
4558 		case 't':
4559 			add_criteria_list(CR_TTY_DEVICE, optarg);
4560 			break;
4561 		case 'T':
4562 			Tflag = 1;
4563 			break;
4564 		case 'u':
4565 #ifdef	SUS
4566 			add_criteria_list(CR_EFF_UID, optarg);
4567 			break;
4568 #else	/* !SUS */
4569 			/*FALLTHRU*/
4570 #endif	/* !SUS */
4571 		case 'U':
4572 			add_criteria_list(CR_REAL_UID, optarg);
4573 			break;
4574 		case 'y':
4575 			yflag = 1;
4576 			break;
4577 		}
4578 	}
4579 	if (Rflag)
4580 		lflag = fflag = 0;
4581 	if (o0 == NULL) {
4582 #ifdef	SUS
4583 		const char	*cmd_str = "CMD";
4584 #else
4585 		const char	*cmd_str = "COMD";
4586 		if (sysv3 && !lflag)
4587 			cmd_str = "COMMAND";
4588 #endif
4589 		if (fflag || jflag || lflag) {
4590 			if (jflag || (lflag && yflag))
4591 				add_format(OU_SPACE, NULL);
4592 			if (lflag && !yflag)
4593 				add_format(OU_F, NULL);
4594 			if (lflag)
4595 				add_format(OU_S, NULL);
4596 #ifdef	SUS
4597 			if (fflag)
4598 				add_format(OU_USER, "     UID");
4599 			else if (lflag)
4600 				add_format(OU_UID, NULL);
4601 #else	/* !SUS */
4602 			if (fflag)
4603 				add_format(OU_RUSER, "     UID");
4604 			else if (lflag)
4605 				add_format(OU_RUID, "  UID");
4606 #endif	/* !SUS */
4607 			add_format(OU_PID, NULL);
4608 			if (Tflag && !fflag)
4609 				add_format(OU_STID, NULL);
4610 			if (fflag || lflag)
4611 				add_format(OU_PPID, NULL);
4612 			if (jflag) {
4613 				add_format(OU_PGID, NULL);
4614 				add_format(OU_SID, NULL);
4615 			}
4616 			if (Lflag & 2) {
4617 				add_format(OU_LWP, NULL);
4618 				if (fflag)
4619 					add_format(OU_NLWP, NULL);
4620 			}
4621 			if (Tflag)
4622 				add_format(OU_TID, NULL);
4623 			if (Pflag || Tflag)
4624 				add_format(OU_PSR, NULL);
4625 			if (Tflag && !fflag)
4626 				add_format(OU_NTP, NULL);
4627 #ifndef	S42
4628 			if (cflag) {
4629 				add_format(OU_CLASS, NULL);
4630 				add_format(OU_PRI, NULL);
4631 			} else {
4632 				if (fflag || lflag)
4633 					add_format(OU_C, NULL);
4634 				if (lflag) {
4635 					add_format(OU_OPRI, NULL);
4636 					add_format(OU_NICE, NULL);
4637 				}
4638 			}
4639 #else	/* S42 */
4640 			add_format(OU_CLASS, NULL);
4641 			add_format(OU_PRI, NULL);
4642 			if (fflag || lflag)
4643 				add_format(OU_C, NULL);
4644 #endif	/* S42 */
4645 			if (lflag) {
4646 				if (yflag) {
4647 					add_format(OU_RSS, NULL);
4648 					add_format(OU_VSZ, "    SZ");
4649 				} else {
4650 					add_format(OU_ADDR, NULL);
4651 					add_format(OU_OSZ, NULL);
4652 				}
4653 				add_format(OU_WCHAN, NULL);
4654 			}
4655 			if (fflag)
4656 				add_format(OU_STIME, NULL);
4657 			add_format(OU_TTY, "TTY    ");
4658 			if (Lflag & 2)
4659 				add_format(OU_LTIME, NULL);
4660 			else
4661 				add_format(OU_OTIME, NULL);
4662 			if (fflag)
4663 				add_format(OU_ARGS, cmd_str);
4664 			else
4665 				add_format(OU_FNAME, cmd_str);
4666 		} else {
4667 			add_format(OU_SPACE, NULL);
4668 			add_format(OU_PID, NULL);
4669 			if (Lflag & 2)
4670 				add_format(OU_LWP, NULL);
4671 			if (Tflag) {
4672 				add_format(OU_STID, NULL);
4673 				add_format(OU_TID, NULL);
4674 			}
4675 			if (Pflag || Tflag)
4676 				add_format(OU_PSR, NULL);
4677 			if (Tflag)
4678 				add_format(OU_NTP, NULL);
4679 			if (cflag) {
4680 				add_format(OU_CLASS, NULL);
4681 				add_format(OU_PRI, NULL);
4682 			}
4683 			if (Rflag) {
4684 				add_format(OU_OSZ, "   SZ");
4685 				add_format(OU_MRSZ, NULL);
4686 				add_format(OU_PFLTS, NULL);
4687 				add_format(OU_BUFR, NULL);
4688 				add_format(OU_BUFW, NULL);
4689 				add_format(OU_MRCV, NULL);
4690 				add_format(OU_MSND, NULL);
4691 				add_format(OU_UTIME, NULL);
4692 				add_format(OU_KTIME, NULL);
4693 			} else {
4694 				add_format(OU_TTY, "TTY    ");
4695 				if (Lflag & 2)
4696 					add_format(OU_LTIME, NULL);
4697 				else
4698 					add_format(OU_OTIME, NULL);
4699 			}
4700 			add_format(OU_FNAME, cmd_str);
4701 		}
4702 	}
4703 }
4704 #else	/* UCB */
4705 /*
4706  * Note that the 'UCB' version is not actually oriented at historical
4707  * BSD usage, but at /usr/ucb/ps of SVR4 (with POSIX.2 extensions).
4708  */
4709 static void
4710 options(int ac, char **av)
4711 {
4712 	char	*cp;
4713 	int	i, format = 0, agxsel = 0, illegal = 0;
4714 	int	cflag = 0;	/* display command name instead of args */
4715 	int	nflag = 0;	/* print numerical IDs */
4716 	int	Sflag = 0;	/* display accumulated time */
4717 	int	wflag = 0;	/* screen width */
4718 
4719 	while ((i = getopt(ac, av, optstring)) != EOF) {
4720 		switch (i) {
4721 		case 'a':
4722 			agxsel |= 01;
4723 			break;
4724 		case 'A':
4725 			add_criterion(CR_ALL, 0);
4726 			break;
4727 		case 'c':
4728 			cflag = 1;
4729 			break;
4730 		case 'g':
4731 			agxsel |= 02;
4732 			break;
4733 		case 'G':
4734 			add_criteria_list(CR_REAL_GID, optarg);
4735 			break;
4736 		case 'l':
4737 			format = 'l';
4738 			break;
4739 		case 'L':
4740 			Lflag = 1;
4741 			break;
4742 		case 'n':
4743 			nflag = 1;
4744 			break;
4745 		case 'o':
4746 			oflag = 1;
4747 			wflag = 2;	/* do not limit width */
4748 			add_format_list(optarg);
4749 			break;
4750 		case 'p':
4751 			add_criteria_list(CR_PROCESS_ID, optarg);
4752 			break;
4753 		case 'r':
4754 			ucb_rflag = 1;
4755 			break;
4756 		case 'S':
4757 			Sflag = 1;
4758 			break;
4759 		case 't':
4760 			add_criteria_list(CR_TTY_DEVICE, optarg);
4761 			agxsel &= ~04;
4762 			break;
4763 		case 'u':
4764 			format = 'u';
4765 			break;
4766 		case 'U':
4767 			/*
4768 			 * 'U' without argument is 'update ps database' in
4769 			 * historical /usr/ucb/ps. We implement the POSIX.2
4770 			 * option instead.
4771 			 */
4772 			add_criteria_list(CR_REAL_UID, optarg);
4773 			break;
4774 		case 'v':
4775 			format = 'v';
4776 			break;
4777 		case 'w':
4778 			wflag++;
4779 			break;
4780 		case 'x':
4781 			agxsel |= 04;
4782 			break;
4783 		}
4784 	}
4785 	if (illegal)
4786 		usage();
4787 	if (av[optind]) {
4788 		add_criteria_list(CR_PROCESS_ID, av[optind]);
4789 		agxsel = 0;
4790 		ucb_rflag = 0;
4791 	}
4792 	switch (agxsel) {
4793 	case 01|04:
4794 	case 01|02|04:
4795 		add_criterion(CR_ALL, 0);
4796 		break;
4797 	case 02|04:
4798 		add_criterion(CR_WITHOUT_TTY, 0);
4799 		add_criterion(CR_ADD_UNINTERESTING, 0);
4800 		break;
4801 	case 01:
4802 	case 01|02:
4803 		add_criterion(CR_ALL_WITH_TTY, 0);
4804 		break;
4805 	case 02:
4806 		add_criterion(CR_ADD_UNINTERESTING, 0);
4807 		break;
4808 	case 04:
4809 		add_criterion(CR_NO_TTY_NO_SESSION_LEADER, 0);
4810 		break;
4811 	}
4812 	if (o0 == NULL) {
4813 		if (format == 'l') {
4814 			add_format(OU_F, NULL);
4815 			add_format(OU_RUID, "  UID");
4816 		} else if (format == 'u') {
4817 			if (nflag)
4818 				add_format(OU_RUID, "   UID");
4819 			else
4820 				add_format(OU_RUSER, "USER    ");
4821 		}
4822 		if (format == 'l') {
4823 			add_format(OU_PID, NULL);
4824 			add_format(OU_PPID, NULL);
4825 		} else if (format == 'u')
4826 			add_format(OU_PID, "  PID");
4827 		else
4828 			add_format(OU_PID, "   PID");
4829 		if (format == 'l' || format == 'u')
4830 			add_format(OU_C, "CP");
4831 		if (format == 'l') {
4832 			add_format(OU_OPRI, NULL);
4833 			add_format(OU_NICE, NULL);
4834 		}
4835 		if (format == 'l' || format == 'u') {
4836 			add_format(OU_OSZ, "   SZ");
4837 			add_format(OU_ORSS, "  RSS");
4838 		}
4839 		if (format == 'l') {
4840 			add_format(OU_WCHAN, NULL);
4841 			add_format(OU_S, NULL);
4842 			add_format(OU_TTY, "TT      ");
4843 		} else
4844 			add_format(OU_TTY, "TT     ");
4845 		if (format == 'u' || format == 'v' || format == 0)
4846 			add_format(OU_S, " S");
4847 		if (format == 'u')
4848 			add_format(OU_STIME, "   START");
4849 		else if (format == 'v') {
4850 			add_format(OU_OSZ, " SIZE");
4851 			add_format(OU_ORSS, "  RSS");
4852 		}
4853 		add_format(Sflag ? OU_ACCUTIME : OU_OTIME, NULL);
4854 		add_format(cflag ? OU_FNAME : OU_ARGS, "COMMAND");
4855 	}
4856 	if ((cp = getenv("COLUMNS")) != NULL)
4857 		maxcolumn = strtol(cp, NULL, 10);
4858 	if (maxcolumn <= 0) {
4859 #ifdef	TIOCGWINSZ
4860 		struct winsize	winsz;
4861 
4862 		if (ioctl(1, TIOCGWINSZ, &winsz) == 0 && winsz.ws_col > 0)
4863 			maxcolumn = winsz.ws_col;
4864 		else
4865 #endif	/* TIOCGWINSZ */
4866 			maxcolumn = 80;
4867 	}
4868 	if (wflag == 1)
4869 		maxcolumn += 52;
4870 	else if (wflag > 1)
4871 		maxcolumn = 0;
4872 }
4873 #endif	/* UCB */
4874 
4875 int
4876 main(int argc, char **argv)
4877 {
4878 #ifdef	__GLIBC__
4879 	putenv("POSIXLY_CORRECT=1");
4880 #endif
4881 	kv = NULL;
4882 	progname = basename(argv[0]);
4883 	sysname(argc, argv);
4884 	defaults();
4885 	myuid = getuid();
4886 	myeuid = geteuid();
4887 	if (dropprivs && myuid && myeuid && myuid != myeuid)
4888 		setuid(myuid);
4889 	setlocale(LC_CTYPE, "");
4890 	setlocale(LC_TIME, "");
4891 	mb_cur_max = MB_CUR_MAX;
4892 	ontty = isatty(1);
4893 	options(argc, argv);
4894 	devices();
4895 #if !defined (__hpux) && !defined (_AIX) && !defined (__NetBSD__) && \
4896 		!defined (__OpenBSD__) && !defined (__APPLE__)
4897 	chdir_to_proc();
4898 #endif
4899 #ifdef	__linux__
4900 	get_linux_version();
4901 	if (linux_version_lt(2, 5, 0) && has_o1_sched() == 0)
4902 		compute_priority = compute_priority_old;
4903 	else
4904 		compute_priority = compute_priority_new;
4905 #endif	/* __linux__ */
4906 	hz = sysconf(_SC_CLK_TCK);
4907 	time(&now);
4908 #ifdef	__linux__
4909 	uptime = sysup();
4910 #endif	/* __linux__ */
4911 #ifdef __APPLE__
4912 	{
4913 		static int mib[] = {CTL_HW, HW_PAGESIZE, 0};
4914 		size_t size;
4915 		size = sizeof pagesize;
4916 		if (sysctl(mib, 2, &pagesize, &size, NULL, 0) == -1) {
4917 			fprintf(stderr, "error in sysctl(): %s\n", strerror(errno));
4918 			exit(3);
4919 		}
4920 	}
4921 #else
4922 	pagesize = sysconf(_SC_PAGESIZE);
4923 #endif
4924 	kbytes_per_page = (pagesize >> 10);
4925 #ifndef	__sun
4926 	totalmem = getmem();
4927 #endif	/* !__sun */
4928 #if defined (__linux__) || defined (__sun)
4929 	getproc("self", &myproc, getpid(), -1);
4930 #elif defined (__FreeBSD__) || defined (__DragonFly__)
4931 	getproc("curproc", &myproc, getpid(), -1);
4932 #elif defined (__hpux)
4933 	{
4934 		struct pst_status	pst;
4935 		pid_t	mypid = getpid();
4936 		pstat_getproc(&pst, sizeof pst, (size_t)0, mypid);
4937 		getproc(&myproc, &pst);
4938 	}
4939 #elif defined (_AIX)
4940 	{
4941 		struct stat	st;
4942 		int	fd;
4943 
4944 		if ((fd = open("/dev/tty", O_RDONLY)) >= 0) {
4945 			if (stat(ttyname(fd), &st) == 0)
4946 				myproc.p_ttydev = st.st_rdev;
4947 			close(fd);
4948 		}
4949 	}
4950 #elif defined (__OpenBSD__)
4951 	{
4952 		kvm_t	*kt;
4953 		struct kinfo_proc	*kp;
4954 		int	mypid = getpid();
4955 		int	cnt;
4956 
4957 		if ((kt = kvm_open(NULL, NULL, NULL, KVM_NO_FILES,
4958 						"kvm_open")) == NULL)
4959 			exit(1);
4960 		kp = kvm_getprocs(kt, KERN_PROC_PID, mypid, &cnt);
4961 		if (kp != NULL)
4962 			getproc(&myproc, &kp[0]);
4963 		kvm_close(kt);
4964 	}
4965 #elif defined (__NetBSD__)
4966 	{
4967 		kvm_t	*kt;
4968 		struct kinfo_proc2	*kp;
4969 		int	mypid = getpid();
4970 		int	cnt;
4971 
4972 		if ((kt = kvm_open(NULL, NULL, NULL, KVM_NO_FILES,
4973 						"kvm_open")) == NULL)
4974 			exit(1);
4975 		kp = kvm_getproc2(kt, KERN_PROC_PID, mypid,
4976 				sizeof *kp, &cnt);
4977 		if (kp != NULL)
4978 			getproc(&myproc, &kp[0]);
4979 		kvm_close(kt);
4980 	}
4981 #elif defined (__APPLE__)
4982 	{
4983 		struct kinfo_proc	*kp;
4984 		pid_t	mypid = getpid();
4985 		size_t	cnt;
4986 		int	err;
4987 
4988 		kp = NULL;
4989 		if ((err = GetBSDProcessList(mypid, &kp, &cnt)) != 0) {
4990 			fprintf(stderr, "error getting proc list: %s\n", strerror(err));
4991 			exit(3);
4992 		}
4993 		if (kp != NULL) {
4994 			getproc(&myproc, kp);
4995 			free(kp);
4996 		}
4997 	}
4998 #else	/* SVR4 */
4999 	{
5000 		/*
5001 		 * /proc/self has no useful pr_ttydev value on Open UNIX 8.
5002 		 */
5003 		 char	num[20];
5004 		 pid_t	mypid = getpid();
5005 		 snprintf(num, sizeof num, "%d", mypid);
5006 		 getproc(num, &myproc, mypid, -1);
5007 	}
5008 #endif	/* SVR4 */
5009 	if (c0 == NULL) {
5010 #ifndef	UCB
5011 		if (myproc.p_ttydev == (dev_type)PRNODEV) {
5012 			fprintf(stderr,
5013 				"%s: can't find controlling terminal\n",
5014 				progname);
5015 			exit(1);
5016 		}
5017 #endif	/* !UCB */
5018 		add_criterion(CR_DEFAULT, 0);
5019 	} else {
5020 		struct criterion	*ct;
5021 		int	valid = 0, invalid = 0;
5022 
5023 		for (ct = c0; ct; ct = ct->c_nxt) {
5024 			if (ct->c_typ == CR_INVALID_STOP)
5025 				usage();
5026 			else if (ct->c_typ == CR_EFF_UID)
5027 				valid |= 01;
5028 			else if (ct->c_typ == CR_INVALID_EFF_UID)
5029 				invalid |= 01;
5030 			else if (ct->c_typ == CR_REAL_UID)
5031 				valid |= 02;
5032 			else if (ct->c_typ == CR_INVALID_REAL_UID)
5033 				invalid |= 02;
5034 			else if (ct->c_typ == CR_REAL_GID)
5035 				valid |= 04;
5036 			else if (ct->c_typ == CR_INVALID_REAL_GID)
5037 				invalid |= 04;
5038 		}
5039 		if ((invalid & valid) != invalid)
5040 			return 1;
5041 	}
5042 	if (dohdr)
5043 		putheader();
5044 	do_procs();
5045 	return errcnt;
5046 }
5047