hbase

heirloom base
git clone git://git.2f30.org/hbase
Log | Files | Refs | README

ps.c (114086B)


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