xref: /minix/minix/servers/mib/proc.c (revision e3b8d4bb)
125d39513SDavid van Moolenbroek /* MIB service - proc.c - functionality based on service process tables */
225d39513SDavid van Moolenbroek /* Eventually, the CTL_PROC subtree might end up here as well. */
325d39513SDavid van Moolenbroek 
425d39513SDavid van Moolenbroek #include "mib.h"
525d39513SDavid van Moolenbroek 
625d39513SDavid van Moolenbroek #include <sys/exec.h>
725d39513SDavid van Moolenbroek #include <minix/sysinfo.h>
825d39513SDavid van Moolenbroek 
925d39513SDavid van Moolenbroek #include <machine/archtypes.h>
1025d39513SDavid van Moolenbroek #include "kernel/proc.h"
1125d39513SDavid van Moolenbroek #include "servers/pm/mproc.h"
1225d39513SDavid van Moolenbroek #include "servers/vfs/const.h"
1325d39513SDavid van Moolenbroek #include "servers/vfs/fproc.h"
1425d39513SDavid van Moolenbroek 
1525d39513SDavid van Moolenbroek typedef struct proc ixfer_proc_t;
1625d39513SDavid van Moolenbroek typedef struct mproc ixfer_mproc_t;
1725d39513SDavid van Moolenbroek 
1825d39513SDavid van Moolenbroek static ixfer_proc_t proc_tab[NR_TASKS + NR_PROCS];
1925d39513SDavid van Moolenbroek static ixfer_mproc_t mproc_tab[NR_PROCS];
206ad322a9SDavid van Moolenbroek static struct fproc_light fproc_tab[NR_PROCS];
2125d39513SDavid van Moolenbroek 
2225d39513SDavid van Moolenbroek /*
2325d39513SDavid van Moolenbroek  * The number of processes added to the current number of processes when doing
2425d39513SDavid van Moolenbroek  * a size estimation, so that the actual data retrieval does not end up with
2525d39513SDavid van Moolenbroek  * too little space if new processes have forked between the two calls.  We do
2625d39513SDavid van Moolenbroek  * a process table update only once per clock tick, which means that typically
2725d39513SDavid van Moolenbroek  * no update will take place between the user process's size estimation request
2825d39513SDavid van Moolenbroek  * and its subsequent data retrieval request.  On the other hand, if we do
2925d39513SDavid van Moolenbroek  * update process tables in between, quite a bit might have changed.
3025d39513SDavid van Moolenbroek  */
3125d39513SDavid van Moolenbroek #define EXTRA_PROCS	8
3225d39513SDavid van Moolenbroek 
3325d39513SDavid van Moolenbroek #define HASH_SLOTS 	(NR_PROCS / 4)	/* expected nr. of processes in use */
3425d39513SDavid van Moolenbroek #define NO_SLOT		(-1)
3525d39513SDavid van Moolenbroek static int hash_tab[HASH_SLOTS];	/* hash table mapping from PID.. */
3625d39513SDavid van Moolenbroek static int hnext_tab[NR_PROCS];		/* ..to PM process slot */
3725d39513SDavid van Moolenbroek 
3825d39513SDavid van Moolenbroek static clock_t tabs_updated = 0;	/* when the tables were last updated */
3925d39513SDavid van Moolenbroek static int tabs_valid = TRUE;		/* FALSE if obtaining tables failed */
4025d39513SDavid van Moolenbroek 
4125d39513SDavid van Moolenbroek /*
4225d39513SDavid van Moolenbroek  * Update the process tables by pulling in new copies from the kernel, PM, and
4325d39513SDavid van Moolenbroek  * VFS, but only every so often and only if it has not failed before.  Return
4425d39513SDavid van Moolenbroek  * TRUE iff the tables are now valid.
4525d39513SDavid van Moolenbroek  */
4625d39513SDavid van Moolenbroek static int
update_tables(void)4725d39513SDavid van Moolenbroek update_tables(void)
4825d39513SDavid van Moolenbroek {
4925d39513SDavid van Moolenbroek 	clock_t now;
5025d39513SDavid van Moolenbroek 	pid_t pid;
5125d39513SDavid van Moolenbroek 	int r, kslot, mslot, hslot;
5225d39513SDavid van Moolenbroek 
5325d39513SDavid van Moolenbroek 	/*
5425d39513SDavid van Moolenbroek 	 * If retrieving the tables failed at some point, do not keep trying
5525d39513SDavid van Moolenbroek 	 * all the time.  Such a failure is very unlikely to be transient.
5625d39513SDavid van Moolenbroek 	 */
5725d39513SDavid van Moolenbroek 	if (tabs_valid == FALSE)
5825d39513SDavid van Moolenbroek 		return FALSE;
5925d39513SDavid van Moolenbroek 
6025d39513SDavid van Moolenbroek 	/*
6125d39513SDavid van Moolenbroek 	 * Update the tables once per clock tick at most.  The update operation
6225d39513SDavid van Moolenbroek 	 * is rather heavy, transferring several hundreds of kilobytes between
6325d39513SDavid van Moolenbroek 	 * servers.  Userland should be able to live with information that is
6425d39513SDavid van Moolenbroek 	 * outdated by at most one clock tick.
6525d39513SDavid van Moolenbroek 	 */
6625d39513SDavid van Moolenbroek 	now = getticks();
6725d39513SDavid van Moolenbroek 
6825d39513SDavid van Moolenbroek 	if (tabs_updated != 0 && tabs_updated == now)
6925d39513SDavid van Moolenbroek 		return TRUE;
7025d39513SDavid van Moolenbroek 
7125d39513SDavid van Moolenbroek 	/* Perform an actual update now. */
7225d39513SDavid van Moolenbroek 	tabs_valid = FALSE;
7325d39513SDavid van Moolenbroek 
7425d39513SDavid van Moolenbroek 	/* Retrieve and check the kernel process table. */
7525d39513SDavid van Moolenbroek 	if ((r = sys_getproctab(proc_tab)) != OK) {
7625d39513SDavid van Moolenbroek 		printf("MIB: unable to obtain kernel process table (%d)\n", r);
7725d39513SDavid van Moolenbroek 
7825d39513SDavid van Moolenbroek 		return FALSE;
7925d39513SDavid van Moolenbroek 	}
8025d39513SDavid van Moolenbroek 
8125d39513SDavid van Moolenbroek 	for (kslot = 0; kslot < NR_TASKS + NR_PROCS; kslot++) {
8225d39513SDavid van Moolenbroek 		if (proc_tab[kslot].p_magic != PMAGIC) {
8325d39513SDavid van Moolenbroek 			printf("MIB: kernel process table mismatch\n");
8425d39513SDavid van Moolenbroek 
8525d39513SDavid van Moolenbroek 			return FALSE;
8625d39513SDavid van Moolenbroek 		}
8725d39513SDavid van Moolenbroek 	}
8825d39513SDavid van Moolenbroek 
8925d39513SDavid van Moolenbroek 	/* Retrieve and check the PM process table. */
9025d39513SDavid van Moolenbroek 	r = getsysinfo(PM_PROC_NR, SI_PROC_TAB, mproc_tab, sizeof(mproc_tab));
9125d39513SDavid van Moolenbroek 	if (r != OK) {
9225d39513SDavid van Moolenbroek 		printf("MIB: unable to obtain PM process table (%d)\n", r);
9325d39513SDavid van Moolenbroek 
9425d39513SDavid van Moolenbroek 		return FALSE;
9525d39513SDavid van Moolenbroek 	}
9625d39513SDavid van Moolenbroek 
9725d39513SDavid van Moolenbroek 	for (mslot = 0; mslot < NR_PROCS; mslot++) {
9825d39513SDavid van Moolenbroek 		if (mproc_tab[mslot].mp_magic != MP_MAGIC) {
9925d39513SDavid van Moolenbroek 			printf("MIB: PM process table mismatch\n");
10025d39513SDavid van Moolenbroek 
10125d39513SDavid van Moolenbroek 			return FALSE;
10225d39513SDavid van Moolenbroek 		}
10325d39513SDavid van Moolenbroek 	}
10425d39513SDavid van Moolenbroek 
1056ad322a9SDavid van Moolenbroek 	/* Retrieve an extract of the VFS process table. */
1066ad322a9SDavid van Moolenbroek 	r = getsysinfo(VFS_PROC_NR, SI_PROCLIGHT_TAB, fproc_tab,
1076ad322a9SDavid van Moolenbroek 	    sizeof(fproc_tab));
10825d39513SDavid van Moolenbroek 	if (r != OK) {
10925d39513SDavid van Moolenbroek 		printf("MIB: unable to obtain VFS process table (%d)\n", r);
11025d39513SDavid van Moolenbroek 
11125d39513SDavid van Moolenbroek 		return FALSE;
11225d39513SDavid van Moolenbroek 	}
11325d39513SDavid van Moolenbroek 
11425d39513SDavid van Moolenbroek 	tabs_valid = TRUE;
11525d39513SDavid van Moolenbroek 	tabs_updated = now;
11625d39513SDavid van Moolenbroek 
11725d39513SDavid van Moolenbroek 	/*
11825d39513SDavid van Moolenbroek 	 * Build a hash table mapping from process IDs to slot numbers, for
11925d39513SDavid van Moolenbroek 	 * fast access.  TODO: decide if this is better done on demand only.
12025d39513SDavid van Moolenbroek 	 */
12125d39513SDavid van Moolenbroek 	for (hslot = 0; hslot < HASH_SLOTS; hslot++)
12225d39513SDavid van Moolenbroek 		hash_tab[hslot] = NO_SLOT;
12325d39513SDavid van Moolenbroek 
12425d39513SDavid van Moolenbroek 	for (mslot = 0; mslot < NR_PROCS; mslot++) {
12525d39513SDavid van Moolenbroek 		if (mproc_tab[mslot].mp_flags & IN_USE) {
12625d39513SDavid van Moolenbroek 			if ((pid = mproc_tab[mslot].mp_pid) <= 0)
12725d39513SDavid van Moolenbroek 				continue;
12825d39513SDavid van Moolenbroek 
12925d39513SDavid van Moolenbroek 			hslot = mproc_tab[mslot].mp_pid % HASH_SLOTS;
13025d39513SDavid van Moolenbroek 
13125d39513SDavid van Moolenbroek 			hnext_tab[mslot] = hash_tab[hslot];
13225d39513SDavid van Moolenbroek 			hash_tab[hslot] = mslot;
13325d39513SDavid van Moolenbroek 		}
13425d39513SDavid van Moolenbroek 	}
13525d39513SDavid van Moolenbroek 
13625d39513SDavid van Moolenbroek 	return TRUE;
13725d39513SDavid van Moolenbroek }
13825d39513SDavid van Moolenbroek 
13925d39513SDavid van Moolenbroek /*
14025d39513SDavid van Moolenbroek  * Return the PM slot number for the given PID, or NO_SLOT if the PID is not in
14125d39513SDavid van Moolenbroek  * use by a process.
14225d39513SDavid van Moolenbroek  */
14325d39513SDavid van Moolenbroek static int
get_mslot(pid_t pid)14425d39513SDavid van Moolenbroek get_mslot(pid_t pid)
14525d39513SDavid van Moolenbroek {
14625d39513SDavid van Moolenbroek 	int mslot;
14725d39513SDavid van Moolenbroek 
14825d39513SDavid van Moolenbroek 	/* PID 0 identifies the kernel; checking this is up to the caller. */
14925d39513SDavid van Moolenbroek 	if (pid <= 0)
15025d39513SDavid van Moolenbroek 		return NO_SLOT;
15125d39513SDavid van Moolenbroek 
15225d39513SDavid van Moolenbroek 	for (mslot = hash_tab[pid % HASH_SLOTS]; mslot != NO_SLOT;
15325d39513SDavid van Moolenbroek 	    mslot = hnext_tab[mslot])
15425d39513SDavid van Moolenbroek 		if (mproc_tab[mslot].mp_pid == pid)
15525d39513SDavid van Moolenbroek 			break;
15625d39513SDavid van Moolenbroek 
15725d39513SDavid van Moolenbroek 	return mslot;
15825d39513SDavid van Moolenbroek }
15925d39513SDavid van Moolenbroek 
16025d39513SDavid van Moolenbroek /*
16125d39513SDavid van Moolenbroek  * Store the given number of clock ticks as a timeval structure.
16225d39513SDavid van Moolenbroek  */
16325d39513SDavid van Moolenbroek static void
ticks_to_timeval(struct timeval * tv,clock_t ticks)16425d39513SDavid van Moolenbroek ticks_to_timeval(struct timeval * tv, clock_t ticks)
16525d39513SDavid van Moolenbroek {
16625d39513SDavid van Moolenbroek 	clock_t hz;
16725d39513SDavid van Moolenbroek 
16825d39513SDavid van Moolenbroek 	hz = sys_hz();
16925d39513SDavid van Moolenbroek 
17025d39513SDavid van Moolenbroek 	tv->tv_sec = ticks / hz;
17125d39513SDavid van Moolenbroek 	tv->tv_usec = (long)((ticks % hz) * 1000000ULL / hz);
17225d39513SDavid van Moolenbroek }
17325d39513SDavid van Moolenbroek 
17425d39513SDavid van Moolenbroek /*
17525d39513SDavid van Moolenbroek  * Generate a wchan message text for the cases that the process is blocked on
17625d39513SDavid van Moolenbroek  * IPC with another process, of which the endpoint is given as 'endpt' here.
17725d39513SDavid van Moolenbroek  * The name of the other process is to be stored in 'wmesg', which is a buffer
17825d39513SDavid van Moolenbroek  * of size 'wmsz'.  The result should be null terminated.  If 'ipc' is set, the
17925d39513SDavid van Moolenbroek  * process is blocked on a direct IPC call, in which case the name of the other
18025d39513SDavid van Moolenbroek  * process is enclosed in parentheses.  If 'ipc' is not set, the call is made
18125d39513SDavid van Moolenbroek  * indirectly through VFS, and the name of the other process should not be
18225d39513SDavid van Moolenbroek  * enclosed in parentheses.  If no name can be obtained, we use the endpoint of
18325d39513SDavid van Moolenbroek  * the other process instead.
18425d39513SDavid van Moolenbroek  */
18525d39513SDavid van Moolenbroek static void
fill_wmesg(char * wmesg,size_t wmsz,endpoint_t endpt,int ipc)18625d39513SDavid van Moolenbroek fill_wmesg(char * wmesg, size_t wmsz, endpoint_t endpt, int ipc)
18725d39513SDavid van Moolenbroek {
18825d39513SDavid van Moolenbroek 	const char *name;
18925d39513SDavid van Moolenbroek 	int mslot;
19025d39513SDavid van Moolenbroek 
19125d39513SDavid van Moolenbroek 	switch (endpt) {
19225d39513SDavid van Moolenbroek 	case ANY:
19325d39513SDavid van Moolenbroek 		name = "any";
19425d39513SDavid van Moolenbroek 		break;
19525d39513SDavid van Moolenbroek 	case SELF:
19625d39513SDavid van Moolenbroek 		name = "self";
19725d39513SDavid van Moolenbroek 		break;
19825d39513SDavid van Moolenbroek 	case NONE:
19925d39513SDavid van Moolenbroek 		name = "none";
20025d39513SDavid van Moolenbroek 		break;
20125d39513SDavid van Moolenbroek 	default:
20225d39513SDavid van Moolenbroek 		mslot = _ENDPOINT_P(endpt);
20325d39513SDavid van Moolenbroek 		if (mslot >= -NR_TASKS && mslot < NR_PROCS &&
20425d39513SDavid van Moolenbroek 		    (mslot < 0 || (mproc_tab[mslot].mp_flags & IN_USE)))
20525d39513SDavid van Moolenbroek 			name = proc_tab[NR_TASKS + mslot].p_name;
20625d39513SDavid van Moolenbroek 		else
20725d39513SDavid van Moolenbroek 			name = NULL;
20825d39513SDavid van Moolenbroek 	}
20925d39513SDavid van Moolenbroek 
21025d39513SDavid van Moolenbroek 	if (name != NULL)
21125d39513SDavid van Moolenbroek 		snprintf(wmesg, wmsz, "%s%s%s",
21225d39513SDavid van Moolenbroek 		    ipc ? "(" : "", name, ipc ? ")" : "");
21325d39513SDavid van Moolenbroek 	else
21425d39513SDavid van Moolenbroek 		snprintf(wmesg, wmsz, "%s%d%s",
21525d39513SDavid van Moolenbroek 		    ipc ? "(" : "", endpt, ipc ? ")" : "");
21625d39513SDavid van Moolenbroek }
21725d39513SDavid van Moolenbroek 
21825d39513SDavid van Moolenbroek /*
21925d39513SDavid van Moolenbroek  * Return the LWP status of a process, along with additional information in
22025d39513SDavid van Moolenbroek  * case the process is sleeping (LSSLEEP): a wchan value and text to indicate
22125d39513SDavid van Moolenbroek  * what the process is sleeping on, and possibly a flag field modification to
22225d39513SDavid van Moolenbroek  * indicate that the sleep is interruptible.
22325d39513SDavid van Moolenbroek  */
22425d39513SDavid van Moolenbroek static int
get_lwp_stat(int mslot,uint64_t * wcptr,char * wmptr,size_t wmsz,int32_t * flag)22525d39513SDavid van Moolenbroek get_lwp_stat(int mslot, uint64_t * wcptr, char * wmptr, size_t wmsz,
22625d39513SDavid van Moolenbroek 	int32_t * flag)
22725d39513SDavid van Moolenbroek {
22825d39513SDavid van Moolenbroek 	struct mproc *mp;
2296ad322a9SDavid van Moolenbroek 	struct fproc_light *fp;
23025d39513SDavid van Moolenbroek 	struct proc *kp;
23125d39513SDavid van Moolenbroek 	const char *wmesg;
23225d39513SDavid van Moolenbroek 	uint64_t wchan;
23325d39513SDavid van Moolenbroek 	endpoint_t endpt;
23425d39513SDavid van Moolenbroek 
23525d39513SDavid van Moolenbroek 	mp = &mproc_tab[mslot];
23625d39513SDavid van Moolenbroek 	fp = &fproc_tab[mslot];
23725d39513SDavid van Moolenbroek 	kp = &proc_tab[NR_TASKS + mslot];
23825d39513SDavid van Moolenbroek 
23925d39513SDavid van Moolenbroek 	/*
24025d39513SDavid van Moolenbroek 	 * First cover all the cases that the process is not sleeping.  In
24125d39513SDavid van Moolenbroek 	 * those cases, we need not return additional sleep information either.
24225d39513SDavid van Moolenbroek 	 */
24325d39513SDavid van Moolenbroek 	if (mp->mp_flags & (TRACE_ZOMBIE | ZOMBIE))
24425d39513SDavid van Moolenbroek 		return LSZOMB;
24525d39513SDavid van Moolenbroek 
24625d39513SDavid van Moolenbroek 	if (mp->mp_flags & EXITING)
24725d39513SDavid van Moolenbroek 		return LSDEAD;
24825d39513SDavid van Moolenbroek 
24925d39513SDavid van Moolenbroek 	if ((mp->mp_flags & TRACE_STOPPED) || RTS_ISSET(kp, RTS_P_STOP))
25025d39513SDavid van Moolenbroek 		return LSSTOP;
25125d39513SDavid van Moolenbroek 
25225d39513SDavid van Moolenbroek 	if (proc_is_runnable(kp))
25325d39513SDavid van Moolenbroek 		return LSRUN;
25425d39513SDavid van Moolenbroek 
25525d39513SDavid van Moolenbroek 	/*
25625d39513SDavid van Moolenbroek 	 * The process is sleeping.  In that case, we must also figure out why,
25725d39513SDavid van Moolenbroek 	 * and return an appropriate wchan value and human-readable wmesg text.
25825d39513SDavid van Moolenbroek 	 *
25925d39513SDavid van Moolenbroek 	 * The process can be blocked on either a known sleep state in PM or
26025d39513SDavid van Moolenbroek 	 * VFS, or otherwise on IPC communication with another process, or
26125d39513SDavid van Moolenbroek 	 * otherwise on a kernel RTS flag.  In each case, decide what to use as
26225d39513SDavid van Moolenbroek 	 * wchan value and wmesg text, and whether the sleep is interruptible.
26325d39513SDavid van Moolenbroek 	 *
26425d39513SDavid van Moolenbroek 	 * The wchan value should be unique for the sleep reason.  We use its
26525d39513SDavid van Moolenbroek 	 * lower eight bits to indicate a class:
26625d39513SDavid van Moolenbroek 	 *   0x00 = kernel task
26725d39513SDavid van Moolenbroek 	 *   0x01 = kerel RTS block
26825d39513SDavid van Moolenbroek 	 *   0x02 = PM call
26925d39513SDavid van Moolenbroek 	 *   0x03 = VFS call
27025d39513SDavid van Moolenbroek 	 *   0x04 = MIB call
27125d39513SDavid van Moolenbroek 	 *   0xff = blocked on process
27225d39513SDavid van Moolenbroek 	 * The upper bits are used for class-specific information.  The actual
27325d39513SDavid van Moolenbroek 	 * value does not really matter, as long as it is nonzero and there is
27425d39513SDavid van Moolenbroek 	 * no overlap between the different values.
27525d39513SDavid van Moolenbroek 	 */
27625d39513SDavid van Moolenbroek 	wchan = 0;
27725d39513SDavid van Moolenbroek 	wmesg = NULL;
27825d39513SDavid van Moolenbroek 
27925d39513SDavid van Moolenbroek 	/*
28025d39513SDavid van Moolenbroek 	 * First see if the process is marked as blocked in the tables of PM or
28125d39513SDavid van Moolenbroek 	 * VFS.  Such a block reason is always an interruptible sleep.  Note
28225d39513SDavid van Moolenbroek 	 * that we do not use the kernel table at all in this case: each of the
28325d39513SDavid van Moolenbroek 	 * three tables is consistent within itself, but not necessarily
28425d39513SDavid van Moolenbroek 	 * consistent with any of the other tables, so we avoid internal
28525d39513SDavid van Moolenbroek 	 * mismatches if we can.
28625d39513SDavid van Moolenbroek 	 */
28725d39513SDavid van Moolenbroek 	if (mp->mp_flags & WAITING) {
28825d39513SDavid van Moolenbroek 		wchan = 0x102;
28925d39513SDavid van Moolenbroek 		wmesg = "wait";
29025d39513SDavid van Moolenbroek 	} else if (mp->mp_flags & SIGSUSPENDED) {
29125d39513SDavid van Moolenbroek 		wchan = 0x202;
29225d39513SDavid van Moolenbroek 		wmesg = "pause";
2936ad322a9SDavid van Moolenbroek 	} else if (fp->fpl_blocked_on != FP_BLOCKED_ON_NONE) {
2946ad322a9SDavid van Moolenbroek 		wchan = (fp->fpl_blocked_on << 8) | 0x03;
2956ad322a9SDavid van Moolenbroek 		switch (fp->fpl_blocked_on) {
29625d39513SDavid van Moolenbroek 		case FP_BLOCKED_ON_PIPE:
29725d39513SDavid van Moolenbroek 			wmesg = "pipe";
29825d39513SDavid van Moolenbroek 			break;
299232819ddSDavid van Moolenbroek 		case FP_BLOCKED_ON_FLOCK:
300232819ddSDavid van Moolenbroek 			wmesg = "flock";
30125d39513SDavid van Moolenbroek 			break;
30225d39513SDavid van Moolenbroek 		case FP_BLOCKED_ON_POPEN:
30325d39513SDavid van Moolenbroek 			wmesg = "popen";
30425d39513SDavid van Moolenbroek 			break;
30525d39513SDavid van Moolenbroek 		case FP_BLOCKED_ON_SELECT:
30625d39513SDavid van Moolenbroek 			wmesg = "select";
30725d39513SDavid van Moolenbroek 			break;
308232819ddSDavid van Moolenbroek 		case FP_BLOCKED_ON_CDEV:
309*e3b8d4bbSDavid van Moolenbroek 		case FP_BLOCKED_ON_SDEV:
31025d39513SDavid van Moolenbroek 			/*
311*e3b8d4bbSDavid van Moolenbroek 			 * Add the task (= character or socket driver) endpoint
312*e3b8d4bbSDavid van Moolenbroek 			 * to the wchan value, and use the driver's process
313*e3b8d4bbSDavid van Moolenbroek 			 * name, without parentheses, as wmesg text.
31425d39513SDavid van Moolenbroek 			 */
3156ad322a9SDavid van Moolenbroek 			wchan |= (uint64_t)fp->fpl_task << 16;
3166ad322a9SDavid van Moolenbroek 			fill_wmesg(wmptr, wmsz, fp->fpl_task, FALSE /*ipc*/);
31725d39513SDavid van Moolenbroek 			break;
31825d39513SDavid van Moolenbroek 		default:
31925d39513SDavid van Moolenbroek 			/* A newly added flag we don't yet know about? */
32025d39513SDavid van Moolenbroek 			wmesg = "???";
32125d39513SDavid van Moolenbroek 			break;
32225d39513SDavid van Moolenbroek 		}
32325d39513SDavid van Moolenbroek 	}
32425d39513SDavid van Moolenbroek 	if (wchan != 0) {
32525d39513SDavid van Moolenbroek 		*wcptr = wchan;
32625d39513SDavid van Moolenbroek 		if (wmesg != NULL) /* NULL means "already set" here */
32725d39513SDavid van Moolenbroek 			strlcpy(wmptr, wmesg, wmsz);
32825d39513SDavid van Moolenbroek 		*flag |= L_SINTR;
32925d39513SDavid van Moolenbroek 	}
33025d39513SDavid van Moolenbroek 
33125d39513SDavid van Moolenbroek 	/*
33225d39513SDavid van Moolenbroek 	 * See if the process is blocked on sending or receiving.  If not, then
33325d39513SDavid van Moolenbroek 	 * use one of the kernel RTS flags as reason.
33425d39513SDavid van Moolenbroek 	 */
33525d39513SDavid van Moolenbroek 	endpt = P_BLOCKEDON(kp);
33625d39513SDavid van Moolenbroek 
33725d39513SDavid van Moolenbroek 	switch (endpt) {
33825d39513SDavid van Moolenbroek 	case MIB_PROC_NR:
33925d39513SDavid van Moolenbroek 		/* This is really just aesthetics. */
34025d39513SDavid van Moolenbroek 		wchan = 0x04;
34125d39513SDavid van Moolenbroek 		wmesg = "sysctl";
34225d39513SDavid van Moolenbroek 		break;
34325d39513SDavid van Moolenbroek 	case NONE:
34425d39513SDavid van Moolenbroek 		/*
34525d39513SDavid van Moolenbroek 		 * The process is not running, but also not blocked on IPC with
34625d39513SDavid van Moolenbroek 		 * another process.  This means it must be stopped on a kernel
34725d39513SDavid van Moolenbroek 		 * RTS flag.
34825d39513SDavid van Moolenbroek 		 */
34925d39513SDavid van Moolenbroek 		wchan = ((uint64_t)kp->p_rts_flags << 8) | 0x01;
35025d39513SDavid van Moolenbroek 		if (RTS_ISSET(kp, RTS_PROC_STOP))
35125d39513SDavid van Moolenbroek 			wmesg = "kstop";
35225d39513SDavid van Moolenbroek 		else if (RTS_ISSET(kp, RTS_SIGNALED) ||
35325d39513SDavid van Moolenbroek 		    RTS_ISSET(kp, RTS_SIGNALED))
35425d39513SDavid van Moolenbroek 			wmesg = "ksignal";
35525d39513SDavid van Moolenbroek 		else if (RTS_ISSET(kp, RTS_NO_PRIV))
35625d39513SDavid van Moolenbroek 			wmesg = "knopriv";
35725d39513SDavid van Moolenbroek 		else if (RTS_ISSET(kp, RTS_PAGEFAULT) ||
35825d39513SDavid van Moolenbroek 		    RTS_ISSET(kp, RTS_VMREQTARGET))
35925d39513SDavid van Moolenbroek 			wmesg = "fault";
36025d39513SDavid van Moolenbroek 		else if (RTS_ISSET(kp, RTS_NO_QUANTUM))
36125d39513SDavid van Moolenbroek 			wmesg = "sched";
36225d39513SDavid van Moolenbroek 		else
36325d39513SDavid van Moolenbroek 			wmesg = "kflag";
36425d39513SDavid van Moolenbroek 		break;
36525d39513SDavid van Moolenbroek 	case ANY:
36625d39513SDavid van Moolenbroek 		/*
36725d39513SDavid van Moolenbroek 		 * If the process is blocked receiving from ANY, mark it as
36825d39513SDavid van Moolenbroek 		 * being in an interruptible sleep.  This looks nicer, even
36925d39513SDavid van Moolenbroek 		 * though "interruptible" is not applicable to services at all.
37025d39513SDavid van Moolenbroek 		 */
37125d39513SDavid van Moolenbroek 		*flag |= L_SINTR;
37225d39513SDavid van Moolenbroek 		break;
37325d39513SDavid van Moolenbroek 	}
37425d39513SDavid van Moolenbroek 
37525d39513SDavid van Moolenbroek 	/*
37625d39513SDavid van Moolenbroek 	 * If at this point wchan is still zero, the process is blocked sending
37725d39513SDavid van Moolenbroek 	 * or receiving.  Use a wchan value based on the target endpoint, and
37825d39513SDavid van Moolenbroek 	 * use "(procname)" as wmesg text.
37925d39513SDavid van Moolenbroek 	 */
38025d39513SDavid van Moolenbroek 	if (wchan == 0) {
38125d39513SDavid van Moolenbroek 		*wcptr = ((uint64_t)endpt << 8) | 0xff;
38225d39513SDavid van Moolenbroek 		fill_wmesg(wmptr, wmsz, endpt, TRUE /*ipc*/);
38325d39513SDavid van Moolenbroek 	} else {
38425d39513SDavid van Moolenbroek 		*wcptr = wchan;
38525d39513SDavid van Moolenbroek 		if (wmesg != NULL) /* NULL means "already set" here */
38625d39513SDavid van Moolenbroek 			strlcpy(wmptr, wmesg, wmsz);
38725d39513SDavid van Moolenbroek 	}
38825d39513SDavid van Moolenbroek 
38925d39513SDavid van Moolenbroek 	return LSSLEEP;
39025d39513SDavid van Moolenbroek }
39125d39513SDavid van Moolenbroek 
39225d39513SDavid van Moolenbroek 
39325d39513SDavid van Moolenbroek /*
39425d39513SDavid van Moolenbroek  * Fill the part of a LWP structure that is common between kernel tasks and
39525d39513SDavid van Moolenbroek  * user processes.  Also return a CPU estimate in 'estcpu', because we generate
39625d39513SDavid van Moolenbroek  * the value as a side effect here, and the LWP structure has no estcpu field.
39725d39513SDavid van Moolenbroek  */
39825d39513SDavid van Moolenbroek static void
fill_lwp_common(struct kinfo_lwp * l,int kslot,uint32_t * estcpu)39925d39513SDavid van Moolenbroek fill_lwp_common(struct kinfo_lwp * l, int kslot, uint32_t * estcpu)
40025d39513SDavid van Moolenbroek {
40125d39513SDavid van Moolenbroek 	struct proc *kp;
40225d39513SDavid van Moolenbroek 	struct timeval tv;
40325d39513SDavid van Moolenbroek 	clock_t uptime;
40425d39513SDavid van Moolenbroek 	uint32_t hz;
40525d39513SDavid van Moolenbroek 
40625d39513SDavid van Moolenbroek 	kp = &proc_tab[kslot];
40725d39513SDavid van Moolenbroek 
40825d39513SDavid van Moolenbroek 	uptime = getticks();
40925d39513SDavid van Moolenbroek 	hz = sys_hz();
41025d39513SDavid van Moolenbroek 
41125d39513SDavid van Moolenbroek 	/*
41225d39513SDavid van Moolenbroek 	 * We use the process endpoint as the LWP ID.  Not only does this allow
41325d39513SDavid van Moolenbroek 	 * users to obtain process endpoints with "ps -s" (thus replacing the
41425d39513SDavid van Moolenbroek 	 * MINIX3 ps(1)'s "ps -E"), but if we ever do implement kernel threads,
41525d39513SDavid van Moolenbroek 	 * this is probably still going to be accurate.
41625d39513SDavid van Moolenbroek 	 */
41725d39513SDavid van Moolenbroek 	l->l_lid = kp->p_endpoint;
41825d39513SDavid van Moolenbroek 
41925d39513SDavid van Moolenbroek 	/*
42025d39513SDavid van Moolenbroek 	 * The time during which the process has not been swapped in or out is
42125d39513SDavid van Moolenbroek 	 * not applicable for us, and thus, we set it to the time the process
42225d39513SDavid van Moolenbroek 	 * has been running (in seconds).  This value is relevant mostly for
42325d39513SDavid van Moolenbroek 	 * ps(1)'s CPU usage correction for processes that have just started.
42425d39513SDavid van Moolenbroek 	 */
42525d39513SDavid van Moolenbroek 	if (kslot >= NR_TASKS)
42625d39513SDavid van Moolenbroek 		l->l_swtime = uptime - mproc_tab[kslot - NR_TASKS].mp_started;
42725d39513SDavid van Moolenbroek 	else
42825d39513SDavid van Moolenbroek 		l->l_swtime = uptime;
42925d39513SDavid van Moolenbroek 	l->l_swtime /= hz;
43025d39513SDavid van Moolenbroek 
43125d39513SDavid van Moolenbroek 	/*
43225d39513SDavid van Moolenbroek 	 * Sleep (dequeue) times are not maintained for kernel tasks, so
43325d39513SDavid van Moolenbroek 	 * pretend they are never asleep (which is pretty accurate).
43425d39513SDavid van Moolenbroek 	 */
43525d39513SDavid van Moolenbroek 	if (kslot < NR_TASKS)
43625d39513SDavid van Moolenbroek 		l->l_slptime = 0;
43725d39513SDavid van Moolenbroek 	else
43825d39513SDavid van Moolenbroek 		l->l_slptime = (uptime - kp->p_dequeued) / hz;
43925d39513SDavid van Moolenbroek 
44025d39513SDavid van Moolenbroek 	l->l_priority = kp->p_priority;
44125d39513SDavid van Moolenbroek 	l->l_usrpri = kp->p_priority;
44225d39513SDavid van Moolenbroek 	l->l_cpuid = kp->p_cpu;
44325d39513SDavid van Moolenbroek 	ticks_to_timeval(&tv, kp->p_user_time + kp->p_sys_time);
44425d39513SDavid van Moolenbroek 	l->l_rtime_sec = tv.tv_sec;
44525d39513SDavid van Moolenbroek 	l->l_rtime_usec = tv.tv_usec;
44625d39513SDavid van Moolenbroek 
44725d39513SDavid van Moolenbroek 	/*
44825d39513SDavid van Moolenbroek 	 * Obtain CPU usage percentages and estimates through library code
44925d39513SDavid van Moolenbroek 	 * shared between the kernel and this service; see its source for
45025d39513SDavid van Moolenbroek 	 * details.  We note that the produced estcpu value is rather different
45125d39513SDavid van Moolenbroek 	 * from the one produced by NetBSD, but this should not be a problem.
45225d39513SDavid van Moolenbroek 	 */
45325d39513SDavid van Moolenbroek 	l->l_pctcpu = cpuavg_getstats(&kp->p_cpuavg, &l->l_cpticks, estcpu,
45425d39513SDavid van Moolenbroek 	    uptime, hz);
45525d39513SDavid van Moolenbroek }
45625d39513SDavid van Moolenbroek 
45725d39513SDavid van Moolenbroek /*
45825d39513SDavid van Moolenbroek  * Fill a LWP structure for a kernel task.  Each kernel task has its own LWP,
45925d39513SDavid van Moolenbroek  * and all of them have negative PIDs.
46025d39513SDavid van Moolenbroek  */
46125d39513SDavid van Moolenbroek static void
fill_lwp_kern(struct kinfo_lwp * l,int kslot)46225d39513SDavid van Moolenbroek fill_lwp_kern(struct kinfo_lwp * l, int kslot)
46325d39513SDavid van Moolenbroek {
46425d39513SDavid van Moolenbroek 	uint32_t estcpu;
46525d39513SDavid van Moolenbroek 
46625d39513SDavid van Moolenbroek 	memset(l, 0, sizeof(*l));
46725d39513SDavid van Moolenbroek 
46825d39513SDavid van Moolenbroek 	l->l_flag = L_INMEM | L_SINTR | L_SYSTEM;
46925d39513SDavid van Moolenbroek 	l->l_stat = LSSLEEP;
47025d39513SDavid van Moolenbroek 	l->l_pid = kslot - NR_TASKS;
47125d39513SDavid van Moolenbroek 
47225d39513SDavid van Moolenbroek 	/*
47325d39513SDavid van Moolenbroek 	 * When showing LWP entries, ps(1) uses the process name rather than
47425d39513SDavid van Moolenbroek 	 * the LWP name.  All kernel tasks are therefore shown as "[kernel]"
47525d39513SDavid van Moolenbroek 	 * anyway.  We use the wmesg field to show the actual kernel task name.
47625d39513SDavid van Moolenbroek 	 */
47725d39513SDavid van Moolenbroek 	l->l_wchan = ((uint64_t)(l->l_pid) << 8) | 0x00;
47825d39513SDavid van Moolenbroek 	strlcpy(l->l_wmesg, proc_tab[kslot].p_name, sizeof(l->l_wmesg));
47925d39513SDavid van Moolenbroek 	strlcpy(l->l_name, "kernel", sizeof(l->l_name));
48025d39513SDavid van Moolenbroek 
48125d39513SDavid van Moolenbroek 	fill_lwp_common(l, kslot, &estcpu);
48225d39513SDavid van Moolenbroek }
48325d39513SDavid van Moolenbroek 
48425d39513SDavid van Moolenbroek /*
48525d39513SDavid van Moolenbroek  * Fill a LWP structure for a user process.
48625d39513SDavid van Moolenbroek  */
48725d39513SDavid van Moolenbroek static void
fill_lwp_user(struct kinfo_lwp * l,int mslot)48825d39513SDavid van Moolenbroek fill_lwp_user(struct kinfo_lwp * l, int mslot)
48925d39513SDavid van Moolenbroek {
49025d39513SDavid van Moolenbroek 	struct mproc *mp;
49125d39513SDavid van Moolenbroek 	uint32_t estcpu;
49225d39513SDavid van Moolenbroek 
49325d39513SDavid van Moolenbroek 	memset(l, 0, sizeof(*l));
49425d39513SDavid van Moolenbroek 
49525d39513SDavid van Moolenbroek 	mp = &mproc_tab[mslot];
49625d39513SDavid van Moolenbroek 
49725d39513SDavid van Moolenbroek 	l->l_flag = L_INMEM;
49825d39513SDavid van Moolenbroek 	l->l_stat = get_lwp_stat(mslot, &l->l_wchan, l->l_wmesg,
49925d39513SDavid van Moolenbroek 	    sizeof(l->l_wmesg), &l->l_flag);
50025d39513SDavid van Moolenbroek 	l->l_pid = mp->mp_pid;
50125d39513SDavid van Moolenbroek 	strlcpy(l->l_name, mp->mp_name, sizeof(l->l_name));
50225d39513SDavid van Moolenbroek 
50325d39513SDavid van Moolenbroek 	fill_lwp_common(l, NR_TASKS + mslot, &estcpu);
50425d39513SDavid van Moolenbroek }
50525d39513SDavid van Moolenbroek 
50625d39513SDavid van Moolenbroek /*
50725d39513SDavid van Moolenbroek  * Implementation of CTL_KERN KERN_LWP.
50825d39513SDavid van Moolenbroek  */
50925d39513SDavid van Moolenbroek ssize_t
mib_kern_lwp(struct mib_call * call,struct mib_node * node __unused,struct mib_oldp * oldp,struct mib_newp * newp __unused)51025d39513SDavid van Moolenbroek mib_kern_lwp(struct mib_call * call, struct mib_node * node __unused,
51125d39513SDavid van Moolenbroek 	struct mib_oldp * oldp, struct mib_newp * newp __unused)
51225d39513SDavid van Moolenbroek {
51325d39513SDavid van Moolenbroek 	struct kinfo_lwp lwp;
51425d39513SDavid van Moolenbroek 	struct mproc *mp;
51525d39513SDavid van Moolenbroek 	size_t copysz;
51625d39513SDavid van Moolenbroek 	ssize_t off;
51725d39513SDavid van Moolenbroek 	pid_t pid;
51825d39513SDavid van Moolenbroek 	int r, elsz, elmax, kslot, mslot, last_mslot;
51925d39513SDavid van Moolenbroek 
52025d39513SDavid van Moolenbroek 	if (call->call_namelen != 3)
52125d39513SDavid van Moolenbroek 		return EINVAL;
52225d39513SDavid van Moolenbroek 
52325d39513SDavid van Moolenbroek 	pid = (pid_t)call->call_name[0];
52425d39513SDavid van Moolenbroek 	elsz = call->call_name[1];
52525d39513SDavid van Moolenbroek 	elmax = call->call_name[2]; /* redundant with the given oldlen.. */
52625d39513SDavid van Moolenbroek 
52725d39513SDavid van Moolenbroek 	if (pid < -1 || elsz <= 0 || elmax < 0)
52825d39513SDavid van Moolenbroek 		return EINVAL;
52925d39513SDavid van Moolenbroek 
53025d39513SDavid van Moolenbroek 	if (!update_tables())
53125d39513SDavid van Moolenbroek 		return EINVAL;
53225d39513SDavid van Moolenbroek 
53325d39513SDavid van Moolenbroek 	off = 0;
53425d39513SDavid van Moolenbroek 	copysz = MIN((size_t)elsz, sizeof(lwp));
53525d39513SDavid van Moolenbroek 
53625d39513SDavid van Moolenbroek 	/*
53725d39513SDavid van Moolenbroek 	 * We model kernel tasks as LWP threads of the kernel (with PID 0).
53825d39513SDavid van Moolenbroek 	 * Modeling the kernel tasks as processes with negative PIDs, like
53925d39513SDavid van Moolenbroek 	 * ProcFS does, conflicts with the KERN_LWP API here: a PID of -1
54025d39513SDavid van Moolenbroek 	 * indicates that the caller wants a full listing of LWPs.
54125d39513SDavid van Moolenbroek 	 */
54225d39513SDavid van Moolenbroek 	if (pid <= 0) {
54325d39513SDavid van Moolenbroek 		for (kslot = 0; kslot < NR_TASKS; kslot++) {
54425d39513SDavid van Moolenbroek 			if (mib_inrange(oldp, off) && elmax > 0) {
54525d39513SDavid van Moolenbroek 				fill_lwp_kern(&lwp, kslot);
54625d39513SDavid van Moolenbroek 				if ((r = mib_copyout(oldp, off, &lwp,
54725d39513SDavid van Moolenbroek 				    copysz)) < 0)
54825d39513SDavid van Moolenbroek 					return r;
54925d39513SDavid van Moolenbroek 				elmax--;
55025d39513SDavid van Moolenbroek 			}
55125d39513SDavid van Moolenbroek 			off += elsz;
55225d39513SDavid van Moolenbroek 		}
55325d39513SDavid van Moolenbroek 
55425d39513SDavid van Moolenbroek 		/* No need to add extra space here: NR_TASKS is static. */
55525d39513SDavid van Moolenbroek 		if (pid == 0)
55625d39513SDavid van Moolenbroek 			return off;
55725d39513SDavid van Moolenbroek 	}
55825d39513SDavid van Moolenbroek 
55925d39513SDavid van Moolenbroek 	/*
56025d39513SDavid van Moolenbroek 	 * With PID 0 out of the way: the user requested the LWP for either a
56125d39513SDavid van Moolenbroek 	 * specific user process (pid > 0), or for all processes (pid < 0).
56225d39513SDavid van Moolenbroek 	 */
56325d39513SDavid van Moolenbroek 	if (pid > 0) {
56425d39513SDavid van Moolenbroek 		if ((mslot = get_mslot(pid)) == NO_SLOT ||
56525d39513SDavid van Moolenbroek 		    (mproc_tab[mslot].mp_flags & (TRACE_ZOMBIE | ZOMBIE)))
56625d39513SDavid van Moolenbroek 			return ESRCH;
56725d39513SDavid van Moolenbroek 		last_mslot = mslot;
56825d39513SDavid van Moolenbroek 	} else {
56925d39513SDavid van Moolenbroek 		mslot = 0;
57025d39513SDavid van Moolenbroek 		last_mslot = NR_PROCS - 1;
57125d39513SDavid van Moolenbroek 	}
57225d39513SDavid van Moolenbroek 
57325d39513SDavid van Moolenbroek 	for (; mslot <= last_mslot; mslot++) {
57425d39513SDavid van Moolenbroek 		mp = &mproc_tab[mslot];
57525d39513SDavid van Moolenbroek 
57625d39513SDavid van Moolenbroek 		if ((mp->mp_flags & (IN_USE | TRACE_ZOMBIE | ZOMBIE)) !=
57725d39513SDavid van Moolenbroek 		    IN_USE)
57825d39513SDavid van Moolenbroek 			continue;
57925d39513SDavid van Moolenbroek 
58025d39513SDavid van Moolenbroek 		if (mib_inrange(oldp, off) && elmax > 0) {
58125d39513SDavid van Moolenbroek 			fill_lwp_user(&lwp, mslot);
58225d39513SDavid van Moolenbroek 			if ((r = mib_copyout(oldp, off, &lwp, copysz)) < 0)
58325d39513SDavid van Moolenbroek 				return r;
58425d39513SDavid van Moolenbroek 			elmax--;
58525d39513SDavid van Moolenbroek 		}
58625d39513SDavid van Moolenbroek 		off += elsz;
58725d39513SDavid van Moolenbroek 	}
58825d39513SDavid van Moolenbroek 
58925d39513SDavid van Moolenbroek 	if (oldp == NULL && pid < 0)
59025d39513SDavid van Moolenbroek 		off += EXTRA_PROCS * elsz;
59125d39513SDavid van Moolenbroek 
59225d39513SDavid van Moolenbroek 	return off;
59325d39513SDavid van Moolenbroek }
59425d39513SDavid van Moolenbroek 
59525d39513SDavid van Moolenbroek 
59625d39513SDavid van Moolenbroek /*
59725d39513SDavid van Moolenbroek  * Fill the part of a process structure that is common between kernel tasks and
59825d39513SDavid van Moolenbroek  * user processes.
59925d39513SDavid van Moolenbroek  */
60025d39513SDavid van Moolenbroek static void
fill_proc2_common(struct kinfo_proc2 * p,int kslot)60125d39513SDavid van Moolenbroek fill_proc2_common(struct kinfo_proc2 * p, int kslot)
60225d39513SDavid van Moolenbroek {
60325d39513SDavid van Moolenbroek 	struct vm_usage_info vui;
60425d39513SDavid van Moolenbroek 	struct timeval tv;
60525d39513SDavid van Moolenbroek 	struct proc *kp;
60625d39513SDavid van Moolenbroek 	struct kinfo_lwp l;
60725d39513SDavid van Moolenbroek 
60825d39513SDavid van Moolenbroek 	kp = &proc_tab[kslot];
60925d39513SDavid van Moolenbroek 
61025d39513SDavid van Moolenbroek 	/*
61125d39513SDavid van Moolenbroek 	 * Much of the information in the LWP structure also ends up in the
61225d39513SDavid van Moolenbroek 	 * process structure.  In order to avoid duplication of some important
61325d39513SDavid van Moolenbroek 	 * code, first generate LWP values and then copy it them into the
61425d39513SDavid van Moolenbroek 	 * process structure.
61525d39513SDavid van Moolenbroek 	 */
61625d39513SDavid van Moolenbroek 	memset(&l, 0, sizeof(l));
61725d39513SDavid van Moolenbroek 	fill_lwp_common(&l, kslot, &p->p_estcpu);
61825d39513SDavid van Moolenbroek 
61925d39513SDavid van Moolenbroek 	/* Obtain memory usage information from VM.  Ignore failures. */
62025d39513SDavid van Moolenbroek 	memset(&vui, 0, sizeof(vui));
62125d39513SDavid van Moolenbroek 	(void)vm_info_usage(kp->p_endpoint, &vui);
62225d39513SDavid van Moolenbroek 
62325d39513SDavid van Moolenbroek 	ticks_to_timeval(&tv, kp->p_user_time + kp->p_sys_time);
62425d39513SDavid van Moolenbroek 	p->p_rtime_sec = l.l_rtime_sec;
62525d39513SDavid van Moolenbroek 	p->p_rtime_usec = l.l_rtime_usec;
62625d39513SDavid van Moolenbroek 	p->p_cpticks = l.l_cpticks;
62725d39513SDavid van Moolenbroek 	p->p_pctcpu = l.l_pctcpu;
62825d39513SDavid van Moolenbroek 	p->p_swtime = l.l_swtime;
62925d39513SDavid van Moolenbroek 	p->p_slptime = l.l_slptime;
63025d39513SDavid van Moolenbroek 	p->p_uticks = kp->p_user_time;
63125d39513SDavid van Moolenbroek 	p->p_sticks = kp->p_sys_time;
63225d39513SDavid van Moolenbroek 	/* TODO: p->p_iticks */
63325d39513SDavid van Moolenbroek 	ticks_to_timeval(&tv, kp->p_user_time);
63425d39513SDavid van Moolenbroek 	p->p_uutime_sec = tv.tv_sec;
63525d39513SDavid van Moolenbroek 	p->p_uutime_usec = tv.tv_usec;
63625d39513SDavid van Moolenbroek 	ticks_to_timeval(&tv, kp->p_sys_time);
63725d39513SDavid van Moolenbroek 	p->p_ustime_sec = tv.tv_sec;
63825d39513SDavid van Moolenbroek 	p->p_ustime_usec = tv.tv_usec;
63925d39513SDavid van Moolenbroek 
64025d39513SDavid van Moolenbroek 	p->p_priority = l.l_priority;
64125d39513SDavid van Moolenbroek 	p->p_usrpri = l.l_usrpri;
64225d39513SDavid van Moolenbroek 
64325d39513SDavid van Moolenbroek 	p->p_vm_rssize = howmany(vui.vui_total, PAGE_SIZE);
64425d39513SDavid van Moolenbroek 	p->p_vm_vsize = howmany(vui.vui_virtual, PAGE_SIZE);
64525d39513SDavid van Moolenbroek 	p->p_vm_msize = howmany(vui.vui_mvirtual, PAGE_SIZE);
64625d39513SDavid van Moolenbroek 
64725d39513SDavid van Moolenbroek 	p->p_uru_maxrss = vui.vui_maxrss;
64825d39513SDavid van Moolenbroek 	p->p_uru_minflt = vui.vui_minflt;
64925d39513SDavid van Moolenbroek 	p->p_uru_majflt = vui.vui_majflt;
65025d39513SDavid van Moolenbroek 
65125d39513SDavid van Moolenbroek 	p->p_cpuid = l.l_cpuid;
65225d39513SDavid van Moolenbroek }
65325d39513SDavid van Moolenbroek 
65425d39513SDavid van Moolenbroek /*
65525d39513SDavid van Moolenbroek  * Fill a process structure for the kernel pseudo-process (with PID 0).
65625d39513SDavid van Moolenbroek  */
65725d39513SDavid van Moolenbroek static void
fill_proc2_kern(struct kinfo_proc2 * p)65825d39513SDavid van Moolenbroek fill_proc2_kern(struct kinfo_proc2 * p)
65925d39513SDavid van Moolenbroek {
66025d39513SDavid van Moolenbroek 
66125d39513SDavid van Moolenbroek 	memset(p, 0, sizeof(*p));
66225d39513SDavid van Moolenbroek 
66325d39513SDavid van Moolenbroek 	p->p_flag = L_INMEM | L_SYSTEM | L_SINTR;
66425d39513SDavid van Moolenbroek 	p->p_pid = 0;
66525d39513SDavid van Moolenbroek 	p->p_stat = LSSLEEP;
66625d39513SDavid van Moolenbroek 	p->p_nice = NZERO;
66725d39513SDavid van Moolenbroek 
66825d39513SDavid van Moolenbroek 	/* Use the KERNEL task wchan, for consistency between ps and top. */
66925d39513SDavid van Moolenbroek 	p->p_wchan = ((uint64_t)KERNEL << 8) | 0x00;
67025d39513SDavid van Moolenbroek 	strlcpy(p->p_wmesg, "kernel", sizeof(p->p_wmesg));
67125d39513SDavid van Moolenbroek 
67225d39513SDavid van Moolenbroek 	strlcpy(p->p_comm, "kernel", sizeof(p->p_comm));
67325d39513SDavid van Moolenbroek 	p->p_realflag = P_INMEM | P_SYSTEM | P_SINTR;
67425d39513SDavid van Moolenbroek 	p->p_realstat = SACTIVE;
67525d39513SDavid van Moolenbroek 	p->p_nlwps = NR_TASKS;
67625d39513SDavid van Moolenbroek 
67725d39513SDavid van Moolenbroek 	/*
67825d39513SDavid van Moolenbroek 	 * By using the KERNEL slot here, the kernel process will get a proper
67925d39513SDavid van Moolenbroek 	 * CPU usage average.
68025d39513SDavid van Moolenbroek 	 */
68125d39513SDavid van Moolenbroek 	fill_proc2_common(p, KERNEL + NR_TASKS);
68225d39513SDavid van Moolenbroek }
68325d39513SDavid van Moolenbroek 
68425d39513SDavid van Moolenbroek /*
68525d39513SDavid van Moolenbroek  * Fill a process structure for a user process.
68625d39513SDavid van Moolenbroek  */
68725d39513SDavid van Moolenbroek static void
fill_proc2_user(struct kinfo_proc2 * p,int mslot)68825d39513SDavid van Moolenbroek fill_proc2_user(struct kinfo_proc2 * p, int mslot)
68925d39513SDavid van Moolenbroek {
69025d39513SDavid van Moolenbroek 	struct mproc *mp;
6916ad322a9SDavid van Moolenbroek 	struct fproc_light *fp;
69225d39513SDavid van Moolenbroek 	time_t boottime;
69325d39513SDavid van Moolenbroek 	dev_t tty;
69425d39513SDavid van Moolenbroek 	struct timeval tv;
69525d39513SDavid van Moolenbroek 	int i, r, kslot, zombie;
69625d39513SDavid van Moolenbroek 
69725d39513SDavid van Moolenbroek 	memset(p, 0, sizeof(*p));
69825d39513SDavid van Moolenbroek 
69925d39513SDavid van Moolenbroek 	if ((r = getuptime(NULL, NULL, &boottime)) != OK)
70025d39513SDavid van Moolenbroek 		panic("getuptime failed: %d", r);
70125d39513SDavid van Moolenbroek 
70225d39513SDavid van Moolenbroek 	kslot = NR_TASKS + mslot;
70325d39513SDavid van Moolenbroek 	mp = &mproc_tab[mslot];
70425d39513SDavid van Moolenbroek 	fp = &fproc_tab[mslot];
70525d39513SDavid van Moolenbroek 
70625d39513SDavid van Moolenbroek 	zombie = (mp->mp_flags & (TRACE_ZOMBIE | ZOMBIE));
7076ad322a9SDavid van Moolenbroek 	tty = (!zombie) ? fp->fpl_tty : NO_DEV;
70825d39513SDavid van Moolenbroek 
70925d39513SDavid van Moolenbroek 	p->p_eflag = 0;
71025d39513SDavid van Moolenbroek 	if (tty != NO_DEV)
71125d39513SDavid van Moolenbroek 		p->p_eflag |= EPROC_CTTY;
71225d39513SDavid van Moolenbroek 	if (mp->mp_pid == mp->mp_procgrp) /* TODO: job control support */
71325d39513SDavid van Moolenbroek 		p->p_eflag |= EPROC_SLEADER;
71425d39513SDavid van Moolenbroek 
71525d39513SDavid van Moolenbroek 	p->p_exitsig = SIGCHLD; /* TODO */
71625d39513SDavid van Moolenbroek 
71725d39513SDavid van Moolenbroek 	p->p_flag = P_INMEM;
71825d39513SDavid van Moolenbroek 	if (mp->mp_flags & TAINTED)
71925d39513SDavid van Moolenbroek 		p->p_flag |= P_SUGID;
72025d39513SDavid van Moolenbroek 	if (mp->mp_tracer != NO_TRACER)
72125d39513SDavid van Moolenbroek 		p->p_flag |= P_TRACED;
72225d39513SDavid van Moolenbroek 	if (tty != NO_DEV)
72325d39513SDavid van Moolenbroek 		p->p_flag |= P_CONTROLT;
72425d39513SDavid van Moolenbroek 	p->p_pid = mp->mp_pid;
72525d39513SDavid van Moolenbroek 	if (mp->mp_parent >= 0 && mp->mp_parent < NR_PROCS)
72625d39513SDavid van Moolenbroek 		p->p_ppid = mproc_tab[mp->mp_parent].mp_pid;
72725d39513SDavid van Moolenbroek 	p->p_sid = mp->mp_procgrp; /* TODO: job control supported */
72825d39513SDavid van Moolenbroek 	p->p__pgid = mp->mp_procgrp;
72925d39513SDavid van Moolenbroek 	p->p_tpgid = (tty != NO_DEV) ? mp->mp_procgrp : 0;
73025d39513SDavid van Moolenbroek 	p->p_uid = mp->mp_effuid;
73125d39513SDavid van Moolenbroek 	p->p_ruid = mp->mp_realuid;
73225d39513SDavid van Moolenbroek 	p->p_gid = mp->mp_effgid;
73325d39513SDavid van Moolenbroek 	p->p_rgid = mp->mp_realgid;
73425d39513SDavid van Moolenbroek 	p->p_ngroups = MIN(mp->mp_ngroups, KI_NGROUPS);
73525d39513SDavid van Moolenbroek 	for (i = 0; i < p->p_ngroups; i++)
73625d39513SDavid van Moolenbroek 		p->p_groups[i] = mp->mp_sgroups[i];
73725d39513SDavid van Moolenbroek 	p->p_tdev = tty;
73825d39513SDavid van Moolenbroek 	memcpy(&p->p_siglist, &mp->mp_sigpending, sizeof(p->p_siglist));
73925d39513SDavid van Moolenbroek 	memcpy(&p->p_sigmask, &mp->mp_sigmask, sizeof(p->p_sigmask));
74025d39513SDavid van Moolenbroek 	memcpy(&p->p_sigcatch, &mp->mp_catch, sizeof(p->p_sigcatch));
74125d39513SDavid van Moolenbroek 	memcpy(&p->p_sigignore, &mp->mp_ignore, sizeof(p->p_sigignore));
74225d39513SDavid van Moolenbroek 	p->p_nice = mp->mp_nice + NZERO;
74325d39513SDavid van Moolenbroek 	strlcpy(p->p_comm, mp->mp_name, sizeof(p->p_comm));
74425d39513SDavid van Moolenbroek 	p->p_uvalid = 1;
74525d39513SDavid van Moolenbroek 	ticks_to_timeval(&tv, mp->mp_started);
74625d39513SDavid van Moolenbroek 	p->p_ustart_sec = boottime + tv.tv_sec;
74725d39513SDavid van Moolenbroek 	p->p_ustart_usec = tv.tv_usec;
74825d39513SDavid van Moolenbroek 	/* TODO: other rusage fields */
74925d39513SDavid van Moolenbroek 	ticks_to_timeval(&tv, mp->mp_child_utime + mp->mp_child_stime);
75025d39513SDavid van Moolenbroek 	p->p_uctime_sec = tv.tv_sec;
75125d39513SDavid van Moolenbroek 	p->p_uctime_usec = tv.tv_usec;
75225d39513SDavid van Moolenbroek 	p->p_realflag = p->p_flag;
75325d39513SDavid van Moolenbroek 	p->p_nlwps = (zombie) ? 0 : 1;
7541122b286SDavid van Moolenbroek 	p->p_svuid = mp->mp_svuid;
7551122b286SDavid van Moolenbroek 	p->p_svgid = mp->mp_svgid;
75625d39513SDavid van Moolenbroek 
75725d39513SDavid van Moolenbroek 	p->p_stat = get_lwp_stat(mslot, &p->p_wchan, p->p_wmesg,
75825d39513SDavid van Moolenbroek 	    sizeof(p->p_wmesg), &p->p_flag);
75925d39513SDavid van Moolenbroek 
76025d39513SDavid van Moolenbroek 	switch (p->p_stat) {
76125d39513SDavid van Moolenbroek 	case LSRUN:
76225d39513SDavid van Moolenbroek 		p->p_realstat = SACTIVE;
76325d39513SDavid van Moolenbroek 		p->p_nrlwps = 1;
76425d39513SDavid van Moolenbroek 		break;
76525d39513SDavid van Moolenbroek 	case LSSLEEP:
76625d39513SDavid van Moolenbroek 		p->p_realstat = SACTIVE;
76725d39513SDavid van Moolenbroek 		if (p->p_flag & L_SINTR)
76825d39513SDavid van Moolenbroek 			p->p_realflag |= P_SINTR;
76925d39513SDavid van Moolenbroek 		break;
77025d39513SDavid van Moolenbroek 	case LSSTOP:
77125d39513SDavid van Moolenbroek 		p->p_realstat = SSTOP;
77225d39513SDavid van Moolenbroek 		break;
77325d39513SDavid van Moolenbroek 	case LSZOMB:
77425d39513SDavid van Moolenbroek 		p->p_realstat = SZOMB;
77525d39513SDavid van Moolenbroek 		break;
77625d39513SDavid van Moolenbroek 	case LSDEAD:
77725d39513SDavid van Moolenbroek 		p->p_stat = LSZOMB; /* ps(1) STAT does not know LSDEAD */
77825d39513SDavid van Moolenbroek 		p->p_realstat = SDEAD;
77925d39513SDavid van Moolenbroek 		break;
78025d39513SDavid van Moolenbroek 	default:
78125d39513SDavid van Moolenbroek 		assert(0);
78225d39513SDavid van Moolenbroek 	}
78325d39513SDavid van Moolenbroek 
78425d39513SDavid van Moolenbroek 	if (!zombie)
78525d39513SDavid van Moolenbroek 		fill_proc2_common(p, kslot);
78625d39513SDavid van Moolenbroek }
78725d39513SDavid van Moolenbroek 
78825d39513SDavid van Moolenbroek /*
78925d39513SDavid van Moolenbroek  * Implementation of CTL_KERN KERN_PROC2.
79025d39513SDavid van Moolenbroek  */
79125d39513SDavid van Moolenbroek ssize_t
mib_kern_proc2(struct mib_call * call,struct mib_node * node __unused,struct mib_oldp * oldp,struct mib_newp * newp __unused)79225d39513SDavid van Moolenbroek mib_kern_proc2(struct mib_call * call, struct mib_node * node __unused,
79325d39513SDavid van Moolenbroek 	struct mib_oldp * oldp, struct mib_newp * newp __unused)
79425d39513SDavid van Moolenbroek {
79525d39513SDavid van Moolenbroek 	struct kinfo_proc2 proc2;
79625d39513SDavid van Moolenbroek 	struct mproc *mp;
79725d39513SDavid van Moolenbroek 	size_t copysz;
79825d39513SDavid van Moolenbroek 	ssize_t off;
79925d39513SDavid van Moolenbroek 	dev_t tty;
80025d39513SDavid van Moolenbroek 	int r, req, arg, elsz, elmax, kmatch, zombie, mslot;
80125d39513SDavid van Moolenbroek 
80225d39513SDavid van Moolenbroek 	if (call->call_namelen != 4)
80325d39513SDavid van Moolenbroek 		return EINVAL;
80425d39513SDavid van Moolenbroek 
80525d39513SDavid van Moolenbroek 	req = call->call_name[0];
80625d39513SDavid van Moolenbroek 	arg = call->call_name[1];
80725d39513SDavid van Moolenbroek 	elsz = call->call_name[2];
80825d39513SDavid van Moolenbroek 	elmax = call->call_name[3]; /* redundant with the given oldlen.. */
80925d39513SDavid van Moolenbroek 
81025d39513SDavid van Moolenbroek 	/*
81125d39513SDavid van Moolenbroek 	 * The kernel is special, in that it does not have a slot in the PM or
81225d39513SDavid van Moolenbroek 	 * VFS tables.  As such, it is dealt with separately.  While checking
81325d39513SDavid van Moolenbroek 	 * arguments, we might as well check whether the kernel is matched.
81425d39513SDavid van Moolenbroek 	 */
81525d39513SDavid van Moolenbroek 	switch (req) {
81625d39513SDavid van Moolenbroek 	case KERN_PROC_ALL:
81725d39513SDavid van Moolenbroek 		kmatch = TRUE;
81825d39513SDavid van Moolenbroek 		break;
81925d39513SDavid van Moolenbroek 	case KERN_PROC_PID:
82025d39513SDavid van Moolenbroek 	case KERN_PROC_SESSION:
82125d39513SDavid van Moolenbroek 	case KERN_PROC_PGRP:
82225d39513SDavid van Moolenbroek 	case KERN_PROC_UID:
82325d39513SDavid van Moolenbroek 	case KERN_PROC_RUID:
82425d39513SDavid van Moolenbroek 	case KERN_PROC_GID:
82525d39513SDavid van Moolenbroek 	case KERN_PROC_RGID:
82625d39513SDavid van Moolenbroek 		kmatch = (arg == 0);
82725d39513SDavid van Moolenbroek 		break;
82825d39513SDavid van Moolenbroek 	case KERN_PROC_TTY:
82925d39513SDavid van Moolenbroek 		kmatch = ((dev_t)arg == KERN_PROC_TTY_NODEV);
83025d39513SDavid van Moolenbroek 		break;
83125d39513SDavid van Moolenbroek 	default:
83225d39513SDavid van Moolenbroek 		return EINVAL;
83325d39513SDavid van Moolenbroek 	}
83425d39513SDavid van Moolenbroek 
83525d39513SDavid van Moolenbroek 	if (elsz <= 0 || elmax < 0)
83625d39513SDavid van Moolenbroek 		return EINVAL;
83725d39513SDavid van Moolenbroek 
83825d39513SDavid van Moolenbroek 	if (!update_tables())
83925d39513SDavid van Moolenbroek 		return EINVAL;
84025d39513SDavid van Moolenbroek 
84125d39513SDavid van Moolenbroek 	off = 0;
84225d39513SDavid van Moolenbroek 	copysz = MIN((size_t)elsz, sizeof(proc2));
84325d39513SDavid van Moolenbroek 
84425d39513SDavid van Moolenbroek 	if (kmatch) {
84525d39513SDavid van Moolenbroek 		if (mib_inrange(oldp, off) && elmax > 0) {
84625d39513SDavid van Moolenbroek 			fill_proc2_kern(&proc2);
84725d39513SDavid van Moolenbroek 			if ((r = mib_copyout(oldp, off, &proc2, copysz)) < 0)
84825d39513SDavid van Moolenbroek 				return r;
84925d39513SDavid van Moolenbroek 			elmax--;
85025d39513SDavid van Moolenbroek 		}
85125d39513SDavid van Moolenbroek 		off += elsz;
85225d39513SDavid van Moolenbroek 	}
85325d39513SDavid van Moolenbroek 
85425d39513SDavid van Moolenbroek 	for (mslot = 0; mslot < NR_PROCS; mslot++) {
85525d39513SDavid van Moolenbroek 		mp = &mproc_tab[mslot];
85625d39513SDavid van Moolenbroek 
85725d39513SDavid van Moolenbroek 		if (!(mp->mp_flags & IN_USE))
85825d39513SDavid van Moolenbroek 			continue;
85925d39513SDavid van Moolenbroek 
86025d39513SDavid van Moolenbroek 		switch (req) {
86125d39513SDavid van Moolenbroek 		case KERN_PROC_PID:
86225d39513SDavid van Moolenbroek 			if ((pid_t)arg != mp->mp_pid)
86325d39513SDavid van Moolenbroek 				continue;
86425d39513SDavid van Moolenbroek 			break;
86525d39513SDavid van Moolenbroek 		case KERN_PROC_SESSION: /* TODO: job control support */
86625d39513SDavid van Moolenbroek 		case KERN_PROC_PGRP:
86725d39513SDavid van Moolenbroek 			if ((pid_t)arg != mp->mp_procgrp)
86825d39513SDavid van Moolenbroek 				continue;
86925d39513SDavid van Moolenbroek 			break;
87025d39513SDavid van Moolenbroek 		case KERN_PROC_TTY:
87125d39513SDavid van Moolenbroek 			if ((dev_t)arg == KERN_PROC_TTY_REVOKE)
87225d39513SDavid van Moolenbroek 				continue; /* TODO: revoke(2) support */
87325d39513SDavid van Moolenbroek 			/* Do not access the fproc_tab slot of zombies. */
87425d39513SDavid van Moolenbroek 			zombie = (mp->mp_flags & (TRACE_ZOMBIE | ZOMBIE));
8756ad322a9SDavid van Moolenbroek 			tty = (zombie) ? fproc_tab[mslot].fpl_tty : NO_DEV;
87625d39513SDavid van Moolenbroek 			if ((dev_t)arg == KERN_PROC_TTY_NODEV) {
87725d39513SDavid van Moolenbroek 				if (tty != NO_DEV)
87825d39513SDavid van Moolenbroek 					continue;
87925d39513SDavid van Moolenbroek 			} else if ((dev_t)arg == NO_DEV || (dev_t)arg != tty)
88025d39513SDavid van Moolenbroek 				continue;
88125d39513SDavid van Moolenbroek 			break;
88225d39513SDavid van Moolenbroek 		case KERN_PROC_UID:
88325d39513SDavid van Moolenbroek 			if ((uid_t)arg != mp->mp_effuid)
88425d39513SDavid van Moolenbroek 				continue;
88525d39513SDavid van Moolenbroek 			break;
88625d39513SDavid van Moolenbroek 		case KERN_PROC_RUID:
88725d39513SDavid van Moolenbroek 			if ((uid_t)arg != mp->mp_realuid)
88825d39513SDavid van Moolenbroek 				continue;
88925d39513SDavid van Moolenbroek 			break;
89025d39513SDavid van Moolenbroek 		case KERN_PROC_GID:
89125d39513SDavid van Moolenbroek 			if ((gid_t)arg != mp->mp_effgid)
89225d39513SDavid van Moolenbroek 				continue;
89325d39513SDavid van Moolenbroek 			break;
89425d39513SDavid van Moolenbroek 		case KERN_PROC_RGID:
89525d39513SDavid van Moolenbroek 			if ((gid_t)arg != mp->mp_realgid)
89625d39513SDavid van Moolenbroek 				continue;
89725d39513SDavid van Moolenbroek 			break;
89825d39513SDavid van Moolenbroek 		}
89925d39513SDavid van Moolenbroek 
90025d39513SDavid van Moolenbroek 		if (mib_inrange(oldp, off) && elmax > 0) {
90125d39513SDavid van Moolenbroek 			fill_proc2_user(&proc2, mslot);
90225d39513SDavid van Moolenbroek 			if ((r = mib_copyout(oldp, off, &proc2, copysz)) < 0)
90325d39513SDavid van Moolenbroek 				return r;
90425d39513SDavid van Moolenbroek 			elmax--;
90525d39513SDavid van Moolenbroek 		}
90625d39513SDavid van Moolenbroek 		off += elsz;
90725d39513SDavid van Moolenbroek 	}
90825d39513SDavid van Moolenbroek 
90925d39513SDavid van Moolenbroek 	if (oldp == NULL && req != KERN_PROC_PID)
91025d39513SDavid van Moolenbroek 		off += EXTRA_PROCS * elsz;
91125d39513SDavid van Moolenbroek 
91225d39513SDavid van Moolenbroek 	return off;
91325d39513SDavid van Moolenbroek }
91425d39513SDavid van Moolenbroek 
91525d39513SDavid van Moolenbroek /*
91625d39513SDavid van Moolenbroek  * Implementation of CTL_KERN KERN_PROC_ARGS.
91725d39513SDavid van Moolenbroek  */
91825d39513SDavid van Moolenbroek ssize_t
mib_kern_proc_args(struct mib_call * call,struct mib_node * node __unused,struct mib_oldp * oldp,struct mib_newp * newp __unused)91925d39513SDavid van Moolenbroek mib_kern_proc_args(struct mib_call * call, struct mib_node * node __unused,
92025d39513SDavid van Moolenbroek 	struct mib_oldp * oldp, struct mib_newp * newp __unused)
92125d39513SDavid van Moolenbroek {
92225d39513SDavid van Moolenbroek 	char vbuf[PAGE_SIZE], sbuf[PAGE_SIZE], obuf[PAGE_SIZE];
92325d39513SDavid van Moolenbroek 	struct ps_strings pss;
92425d39513SDavid van Moolenbroek 	struct mproc *mp;
92525d39513SDavid van Moolenbroek 	char *buf, *p, *q, *pptr;
92625d39513SDavid van Moolenbroek 	vir_bytes vaddr, vpage, spage, paddr, ppage;
92725d39513SDavid van Moolenbroek 	size_t max, off, olen, oleft, oldlen, bytes, pleft;
92825d39513SDavid van Moolenbroek 	unsigned int copybudget;
92925d39513SDavid van Moolenbroek 	pid_t pid;
93025d39513SDavid van Moolenbroek 	int req, mslot, count, aborted, ended;
93125d39513SDavid van Moolenbroek 	ssize_t r;
93225d39513SDavid van Moolenbroek 
93325d39513SDavid van Moolenbroek 	if (call->call_namelen != 2)
93425d39513SDavid van Moolenbroek 		return EINVAL;
93525d39513SDavid van Moolenbroek 
93625d39513SDavid van Moolenbroek 	pid = call->call_name[0];
93725d39513SDavid van Moolenbroek 	req = call->call_name[1];
93825d39513SDavid van Moolenbroek 
93925d39513SDavid van Moolenbroek 	switch (req) {
94025d39513SDavid van Moolenbroek 	case KERN_PROC_ARGV:
94125d39513SDavid van Moolenbroek 	case KERN_PROC_ENV:
94225d39513SDavid van Moolenbroek 	case KERN_PROC_NARGV:
94325d39513SDavid van Moolenbroek 	case KERN_PROC_NENV:
94425d39513SDavid van Moolenbroek 		break;
94525d39513SDavid van Moolenbroek 	default:
94625d39513SDavid van Moolenbroek 		return EOPNOTSUPP;
94725d39513SDavid van Moolenbroek 	}
94825d39513SDavid van Moolenbroek 
94925d39513SDavid van Moolenbroek 	if (!update_tables())
95025d39513SDavid van Moolenbroek 		return EINVAL;
95125d39513SDavid van Moolenbroek 
95225d39513SDavid van Moolenbroek 	if ((mslot = get_mslot(pid)) == NO_SLOT)
95325d39513SDavid van Moolenbroek 		return ESRCH;
95425d39513SDavid van Moolenbroek 	mp = &mproc_tab[mslot];
95525d39513SDavid van Moolenbroek 	if (mp->mp_flags & (TRACE_ZOMBIE | ZOMBIE))
95625d39513SDavid van Moolenbroek 		return ESRCH;
95725d39513SDavid van Moolenbroek 
95825d39513SDavid van Moolenbroek 	/* We can return the count field size without copying in any data. */
95925d39513SDavid van Moolenbroek 	if (oldp == NULL && (req == KERN_PROC_NARGV || req == KERN_PROC_NENV))
96025d39513SDavid van Moolenbroek 		return sizeof(count);
96125d39513SDavid van Moolenbroek 
96225d39513SDavid van Moolenbroek 	if (sys_datacopy(mp->mp_endpoint,
96325d39513SDavid van Moolenbroek 	    mp->mp_frame_addr + mp->mp_frame_len - sizeof(pss),
96425d39513SDavid van Moolenbroek 	    SELF, (vir_bytes)&pss, sizeof(pss)) != OK)
96525d39513SDavid van Moolenbroek 		return EINVAL;
96625d39513SDavid van Moolenbroek 
96725d39513SDavid van Moolenbroek 	/*
96825d39513SDavid van Moolenbroek 	 * Determine the upper size limit of the requested data.  Not only may
96925d39513SDavid van Moolenbroek 	 * the size never exceed ARG_MAX, it may also not exceed the frame
97025d39513SDavid van Moolenbroek 	 * length as given in its original exec call.  In fact, the frame
97125d39513SDavid van Moolenbroek 	 * length should be substantially larger: all strings for both the
97225d39513SDavid van Moolenbroek 	 * arguments and the environment are in there, along with other stuff,
97325d39513SDavid van Moolenbroek 	 * and there must be no overlap between strings.  It is possible that
97425d39513SDavid van Moolenbroek 	 * the application called setproctitle(3), in which case the ps_strings
97525d39513SDavid van Moolenbroek 	 * pointers refer to data outside the frame altogether.  However, this
97625d39513SDavid van Moolenbroek 	 * data should not exceed 2048 bytes, and we cover this by rounding up
97725d39513SDavid van Moolenbroek 	 * the frame length to a multiple of the page size.  Anyhow, NetBSD
97825d39513SDavid van Moolenbroek 	 * blindly returns ARG_MAX when asked for a size estimate, so with this
97925d39513SDavid van Moolenbroek 	 * maximum we are already quite a bit more accurate.
98025d39513SDavid van Moolenbroek 	 */
98125d39513SDavid van Moolenbroek 	max = roundup(MIN(mp->mp_frame_len, ARG_MAX), PAGE_SIZE);
98225d39513SDavid van Moolenbroek 
98325d39513SDavid van Moolenbroek 	switch (req) {
98425d39513SDavid van Moolenbroek 	case KERN_PROC_NARGV:
98525d39513SDavid van Moolenbroek 		count = pss.ps_nargvstr;
98625d39513SDavid van Moolenbroek 		return mib_copyout(oldp, 0, &count, sizeof(count));
98725d39513SDavid van Moolenbroek 	case KERN_PROC_NENV:
98825d39513SDavid van Moolenbroek 		count = pss.ps_nenvstr;
98925d39513SDavid van Moolenbroek 		return mib_copyout(oldp, 0, &count, sizeof(count));
99025d39513SDavid van Moolenbroek 	case KERN_PROC_ARGV:
99125d39513SDavid van Moolenbroek 		if (oldp == NULL)
99225d39513SDavid van Moolenbroek 			return max;
99325d39513SDavid van Moolenbroek 		vaddr = (vir_bytes)pss.ps_argvstr;
99425d39513SDavid van Moolenbroek 		count = pss.ps_nargvstr;
99525d39513SDavid van Moolenbroek 		break;
99625d39513SDavid van Moolenbroek 	case KERN_PROC_ENV:
99725d39513SDavid van Moolenbroek 		if (oldp == NULL)
99825d39513SDavid van Moolenbroek 			return max;
99925d39513SDavid van Moolenbroek 		vaddr = (vir_bytes)pss.ps_envstr;
100025d39513SDavid van Moolenbroek 		count = pss.ps_nenvstr;
100125d39513SDavid van Moolenbroek 		break;
100225d39513SDavid van Moolenbroek 	}
100325d39513SDavid van Moolenbroek 
100425d39513SDavid van Moolenbroek 	/*
100525d39513SDavid van Moolenbroek 	 * Go through the strings.  Copy in entire, machine-aligned pages at
100625d39513SDavid van Moolenbroek 	 * once, in the hope that all data is stored consecutively, which it
100725d39513SDavid van Moolenbroek 	 * should be: we expect that the vector is followed by the strings, and
100825d39513SDavid van Moolenbroek 	 * that the strings are stored in order of vector reference.  We keep
100925d39513SDavid van Moolenbroek 	 * up to two pages with copied-in data: one for the vector, and
101025d39513SDavid van Moolenbroek 	 * optionally one for string data.  In addition, we keep one page with
101125d39513SDavid van Moolenbroek 	 * data to be copied out, so that we do not cause a lot of copy
101225d39513SDavid van Moolenbroek 	 * overhead for short strings.
101325d39513SDavid van Moolenbroek 	 *
101425d39513SDavid van Moolenbroek 	 * We stop whenever any of the following conditions are met:
101525d39513SDavid van Moolenbroek 	 * - copying in data from the target process fails for any reason;
101625d39513SDavid van Moolenbroek 	 * - we have processed the last index ('count') into the vector;
101725d39513SDavid van Moolenbroek 	 * - the current vector element is a NULL pointer;
101825d39513SDavid van Moolenbroek 	 * - the requested number of output bytes ('oldlen') has been reached;
101925d39513SDavid van Moolenbroek 	 * - the maximum number of output bytes ('max') has been reached;
102025d39513SDavid van Moolenbroek 	 * - the number of page copy-ins exceeds an estimated threshold;
102125d39513SDavid van Moolenbroek 	 * - copying out data fails for any reason (we then return the error).
102225d39513SDavid van Moolenbroek 	 *
102325d39513SDavid van Moolenbroek 	 * We limit the number of page copy-ins because otherwise a rogue
102425d39513SDavid van Moolenbroek 	 * process could create an argument vector consisting of only two-byte
102525d39513SDavid van Moolenbroek 	 * strings that all span two pages, causing us to copy up to 1GB of
102625d39513SDavid van Moolenbroek 	 * data with the current ARG_MAX value of 256K.  No reasonable vector
102725d39513SDavid van Moolenbroek 	 * should cause more than (ARG_MAX / PAGE_SIZE) page copies for
102825d39513SDavid van Moolenbroek 	 * strings; we are nice enough to allow twice that.  Vector copies do
102925d39513SDavid van Moolenbroek 	 * not count, as they are linear anyway.
103025d39513SDavid van Moolenbroek 	 *
103125d39513SDavid van Moolenbroek 	 * Unlike every other sysctl(2) call, we are supposed to truncate the
103225d39513SDavid van Moolenbroek 	 * resulting size (the returned 'oldlen') to the requested size (the
103325d39513SDavid van Moolenbroek 	 * given 'oldlen') *and* return the resulting size, rather than ENOMEM
103425d39513SDavid van Moolenbroek 	 * and the real size.  Unfortunately, libkvm actually relies on this.
103525d39513SDavid van Moolenbroek 	 *
103625d39513SDavid van Moolenbroek 	 * Generally speaking, upon failure we just return a truncated result.
103725d39513SDavid van Moolenbroek 	 * In case of truncation, the data we copy out need not be null
103825d39513SDavid van Moolenbroek 	 * terminated.  It is up to userland to process the data correctly.
103925d39513SDavid van Moolenbroek 	 */
104025d39513SDavid van Moolenbroek 	if (trunc_page(vaddr) == 0 || vaddr % sizeof(char *) != 0)
104125d39513SDavid van Moolenbroek 		return 0;
104225d39513SDavid van Moolenbroek 
104325d39513SDavid van Moolenbroek 	off = 0;
104425d39513SDavid van Moolenbroek 	olen = 0;
104525d39513SDavid van Moolenbroek 	aborted = FALSE;
104625d39513SDavid van Moolenbroek 
104725d39513SDavid van Moolenbroek 	oldlen = mib_getoldlen(oldp);
104825d39513SDavid van Moolenbroek 	if (oldlen > max)
104925d39513SDavid van Moolenbroek 		oldlen = max;
105025d39513SDavid van Moolenbroek 
105125d39513SDavid van Moolenbroek 	copybudget = (ARG_MAX / PAGE_SIZE) * 2;
105225d39513SDavid van Moolenbroek 
105325d39513SDavid van Moolenbroek 	vpage = 0;
105425d39513SDavid van Moolenbroek 	spage = 0;
105525d39513SDavid van Moolenbroek 
105625d39513SDavid van Moolenbroek 	while (count > 0 && off + olen < oldlen && !aborted) {
105725d39513SDavid van Moolenbroek 		/*
105825d39513SDavid van Moolenbroek 		 * Start by fetching the page containing the current vector
105925d39513SDavid van Moolenbroek 		 * element, if needed.  We could limit the fetch to the vector
106025d39513SDavid van Moolenbroek 		 * size, but our hope is that for the simple cases, the strings
106125d39513SDavid van Moolenbroek 		 * are on the remainder of the same page, so we save a copy
106225d39513SDavid van Moolenbroek 		 * call.  TODO: since the strings should follow the vector, we
106325d39513SDavid van Moolenbroek 		 * could start the copy at the base of the vector.
106425d39513SDavid van Moolenbroek 		 */
106525d39513SDavid van Moolenbroek 		if (trunc_page(vaddr) != vpage) {
106625d39513SDavid van Moolenbroek 			vpage = trunc_page(vaddr);
106725d39513SDavid van Moolenbroek 			if (sys_datacopy(mp->mp_endpoint, vpage, SELF,
106825d39513SDavid van Moolenbroek 			    (vir_bytes)vbuf, PAGE_SIZE) != OK)
106925d39513SDavid van Moolenbroek 				break;
107025d39513SDavid van Moolenbroek 		}
107125d39513SDavid van Moolenbroek 
107225d39513SDavid van Moolenbroek 		/* Get the current vector element, pointing to a string. */
107325d39513SDavid van Moolenbroek 		memcpy(&pptr, &vbuf[vaddr - vpage], sizeof(pptr));
107425d39513SDavid van Moolenbroek 		paddr = (vir_bytes)pptr;
107525d39513SDavid van Moolenbroek 		ppage = trunc_page(paddr);
107625d39513SDavid van Moolenbroek 		if (ppage == 0)
107725d39513SDavid van Moolenbroek 			break;
107825d39513SDavid van Moolenbroek 
107925d39513SDavid van Moolenbroek 		/* Fetch the string itself, one page at a time at most. */
108025d39513SDavid van Moolenbroek 		do {
108125d39513SDavid van Moolenbroek 			/*
108225d39513SDavid van Moolenbroek 			 * See if the string pointer falls inside either the
108325d39513SDavid van Moolenbroek 			 * vector page or the previously fetched string page
108425d39513SDavid van Moolenbroek 			 * (if any).  If not, fetch a string page.
108525d39513SDavid van Moolenbroek 			 */
108625d39513SDavid van Moolenbroek 			if (ppage == vpage) {
108725d39513SDavid van Moolenbroek 				buf = vbuf;
108825d39513SDavid van Moolenbroek 			} else if (ppage == spage) {
108925d39513SDavid van Moolenbroek 				buf = sbuf;
109025d39513SDavid van Moolenbroek 			} else {
109125d39513SDavid van Moolenbroek 				if (--copybudget == 0) {
109225d39513SDavid van Moolenbroek 					aborted = TRUE;
109325d39513SDavid van Moolenbroek 					break;
109425d39513SDavid van Moolenbroek 				}
109525d39513SDavid van Moolenbroek 				spage = ppage;
109625d39513SDavid van Moolenbroek 				if (sys_datacopy(mp->mp_endpoint, spage, SELF,
109725d39513SDavid van Moolenbroek 				    (vir_bytes)sbuf, PAGE_SIZE) != OK) {
109825d39513SDavid van Moolenbroek 					aborted = TRUE;
109925d39513SDavid van Moolenbroek 					break;
110025d39513SDavid van Moolenbroek 				}
110125d39513SDavid van Moolenbroek 				buf = sbuf;
110225d39513SDavid van Moolenbroek 			}
110325d39513SDavid van Moolenbroek 
110425d39513SDavid van Moolenbroek 			/*
110525d39513SDavid van Moolenbroek 			 * We now have a string fragment in a buffer.  See if
110625d39513SDavid van Moolenbroek 			 * the string is null terminated.  If not, all the data
110725d39513SDavid van Moolenbroek 			 * up to the buffer end is part of the string, and the
110825d39513SDavid van Moolenbroek 			 * string continues on the next page.
110925d39513SDavid van Moolenbroek 			 */
111025d39513SDavid van Moolenbroek 			p = &buf[paddr - ppage];
111125d39513SDavid van Moolenbroek 			pleft = PAGE_SIZE - (paddr - ppage);
111225d39513SDavid van Moolenbroek 			assert(pleft > 0);
111325d39513SDavid van Moolenbroek 
111425d39513SDavid van Moolenbroek 			if ((q = memchr(p, '\0', pleft)) != NULL) {
111525d39513SDavid van Moolenbroek 				bytes = (size_t)(q - p + 1);
111625d39513SDavid van Moolenbroek 				assert(bytes <= pleft);
111725d39513SDavid van Moolenbroek 				ended = TRUE;
111825d39513SDavid van Moolenbroek 			} else {
111925d39513SDavid van Moolenbroek 				bytes = pleft;
112025d39513SDavid van Moolenbroek 				ended = FALSE;
112125d39513SDavid van Moolenbroek 			}
112225d39513SDavid van Moolenbroek 
112325d39513SDavid van Moolenbroek 			/* Limit the result to the requested length. */
112425d39513SDavid van Moolenbroek 			if (off + olen + bytes > oldlen)
112525d39513SDavid van Moolenbroek 				bytes = oldlen - off - olen;
112625d39513SDavid van Moolenbroek 
112725d39513SDavid van Moolenbroek 			/*
112825d39513SDavid van Moolenbroek 			 * Add 'bytes' bytes from string pointer 'p' to the
112925d39513SDavid van Moolenbroek 			 * output buffer, copying out its contents to userland
113025d39513SDavid van Moolenbroek 			 * if it has filled up.
113125d39513SDavid van Moolenbroek 			 */
113225d39513SDavid van Moolenbroek 			if (olen + bytes > sizeof(obuf)) {
113325d39513SDavid van Moolenbroek 				oleft = sizeof(obuf) - olen;
113425d39513SDavid van Moolenbroek 				memcpy(&obuf[olen], p, oleft);
113525d39513SDavid van Moolenbroek 
113625d39513SDavid van Moolenbroek 				if ((r = mib_copyout(oldp, off, obuf,
113725d39513SDavid van Moolenbroek 				    sizeof(obuf))) < 0)
113825d39513SDavid van Moolenbroek 					return r;
113925d39513SDavid van Moolenbroek 				off += sizeof(obuf);
114025d39513SDavid van Moolenbroek 				olen = 0;
114125d39513SDavid van Moolenbroek 
114225d39513SDavid van Moolenbroek 				p += oleft;
114325d39513SDavid van Moolenbroek 				bytes -= oleft;
114425d39513SDavid van Moolenbroek 			}
114525d39513SDavid van Moolenbroek 			if (bytes > 0) {
114625d39513SDavid van Moolenbroek 				memcpy(&obuf[olen], p, bytes);
114725d39513SDavid van Moolenbroek 				olen += bytes;
114825d39513SDavid van Moolenbroek 			}
114925d39513SDavid van Moolenbroek 
115025d39513SDavid van Moolenbroek 			/*
115125d39513SDavid van Moolenbroek 			 * Continue as long as we have not yet found the string
115225d39513SDavid van Moolenbroek 			 * end, and we have not yet filled the output buffer.
115325d39513SDavid van Moolenbroek 			 */
115425d39513SDavid van Moolenbroek 			paddr += pleft;
115525d39513SDavid van Moolenbroek 			assert(trunc_page(paddr) == paddr);
115625d39513SDavid van Moolenbroek 			ppage = paddr;
115725d39513SDavid van Moolenbroek 		} while (!ended && off + olen < oldlen);
115825d39513SDavid van Moolenbroek 
115925d39513SDavid van Moolenbroek 		vaddr += sizeof(char *);
116025d39513SDavid van Moolenbroek 		count--;
116125d39513SDavid van Moolenbroek 	}
116225d39513SDavid van Moolenbroek 
116325d39513SDavid van Moolenbroek 	/* Copy out any remainder of the output buffer. */
116425d39513SDavid van Moolenbroek 	if (olen > 0) {
116525d39513SDavid van Moolenbroek 		if ((r = mib_copyout(oldp, off, obuf, olen)) < 0)
116625d39513SDavid van Moolenbroek 			return r;
116725d39513SDavid van Moolenbroek 		off += olen;
116825d39513SDavid van Moolenbroek 	}
116925d39513SDavid van Moolenbroek 
117025d39513SDavid van Moolenbroek 	assert(off <= oldlen);
117125d39513SDavid van Moolenbroek 	return off;
117225d39513SDavid van Moolenbroek }
1173305e366fSDavid van Moolenbroek 
1174305e366fSDavid van Moolenbroek /*
1175305e366fSDavid van Moolenbroek  * Implementation of CTL_MINIX MINIX_PROC PROC_LIST.
1176305e366fSDavid van Moolenbroek  */
1177305e366fSDavid van Moolenbroek ssize_t
mib_minix_proc_list(struct mib_call * call __unused,struct mib_node * node __unused,struct mib_oldp * oldp,struct mib_newp * newp __unused)1178305e366fSDavid van Moolenbroek mib_minix_proc_list(struct mib_call * call __unused,
1179305e366fSDavid van Moolenbroek 	struct mib_node * node __unused, struct mib_oldp * oldp,
1180305e366fSDavid van Moolenbroek 	struct mib_newp * newp __unused)
1181305e366fSDavid van Moolenbroek {
1182305e366fSDavid van Moolenbroek 	struct minix_proc_list mpl[NR_PROCS];
1183305e366fSDavid van Moolenbroek 	struct minix_proc_list *mplp;
1184305e366fSDavid van Moolenbroek 	struct mproc *mp;
1185305e366fSDavid van Moolenbroek 	unsigned int mslot;
1186305e366fSDavid van Moolenbroek 
1187305e366fSDavid van Moolenbroek 	if (oldp == NULL)
1188305e366fSDavid van Moolenbroek 		return sizeof(mpl);
1189305e366fSDavid van Moolenbroek 
1190305e366fSDavid van Moolenbroek 	if (!update_tables())
1191305e366fSDavid van Moolenbroek 		return EINVAL;
1192305e366fSDavid van Moolenbroek 
1193305e366fSDavid van Moolenbroek 	memset(&mpl, 0, sizeof(mpl));
1194305e366fSDavid van Moolenbroek 
1195305e366fSDavid van Moolenbroek 	mplp = mpl;
1196305e366fSDavid van Moolenbroek 	mp = mproc_tab;
1197305e366fSDavid van Moolenbroek 
1198305e366fSDavid van Moolenbroek 	for (mslot = 0; mslot < NR_PROCS; mslot++, mplp++, mp++) {
1199305e366fSDavid van Moolenbroek 		if (!(mp->mp_flags & IN_USE) || mp->mp_pid <= 0)
1200305e366fSDavid van Moolenbroek 			continue;
1201305e366fSDavid van Moolenbroek 
1202305e366fSDavid van Moolenbroek 		mplp->mpl_flags = MPLF_IN_USE;
1203305e366fSDavid van Moolenbroek 		if (mp->mp_flags & (TRACE_ZOMBIE | ZOMBIE))
1204305e366fSDavid van Moolenbroek 			mplp->mpl_flags |= MPLF_ZOMBIE;
1205305e366fSDavid van Moolenbroek 		mplp->mpl_pid = mp->mp_pid;
1206305e366fSDavid van Moolenbroek 		mplp->mpl_uid = mp->mp_effuid;
1207305e366fSDavid van Moolenbroek 		mplp->mpl_gid = mp->mp_effgid;
1208305e366fSDavid van Moolenbroek 	}
1209305e366fSDavid van Moolenbroek 
1210305e366fSDavid van Moolenbroek 	return mib_copyout(oldp, 0, &mpl, sizeof(mpl));
1211305e366fSDavid van Moolenbroek }
1212305e366fSDavid van Moolenbroek 
1213305e366fSDavid van Moolenbroek /*
1214305e366fSDavid van Moolenbroek  * Implementation of CTL_MINIX MINIX_PROC PROC_DATA.
1215305e366fSDavid van Moolenbroek  */
1216305e366fSDavid van Moolenbroek ssize_t
mib_minix_proc_data(struct mib_call * call,struct mib_node * node __unused,struct mib_oldp * oldp,struct mib_newp * newp __unused)1217305e366fSDavid van Moolenbroek mib_minix_proc_data(struct mib_call * call, struct mib_node * node __unused,
1218305e366fSDavid van Moolenbroek 	struct mib_oldp * oldp, struct mib_newp * newp __unused)
1219305e366fSDavid van Moolenbroek {
1220305e366fSDavid van Moolenbroek 	struct minix_proc_data mpd;
1221305e366fSDavid van Moolenbroek 	struct proc *kp;
1222305e366fSDavid van Moolenbroek 	int kslot, mslot = 0;
1223305e366fSDavid van Moolenbroek 	unsigned int mflags;
1224305e366fSDavid van Moolenbroek 	pid_t pid;
1225305e366fSDavid van Moolenbroek 
1226305e366fSDavid van Moolenbroek 	/*
1227305e366fSDavid van Moolenbroek 	 * It is currently only possible to retrieve the process data for a
1228305e366fSDavid van Moolenbroek 	 * particular PID, which must be given as the last name component.
1229305e366fSDavid van Moolenbroek 	 */
1230305e366fSDavid van Moolenbroek 	if (call->call_namelen != 1)
1231305e366fSDavid van Moolenbroek 		return EINVAL;
1232305e366fSDavid van Moolenbroek 
1233305e366fSDavid van Moolenbroek 	pid = (pid_t)call->call_name[0];
1234305e366fSDavid van Moolenbroek 
1235305e366fSDavid van Moolenbroek 	if (!update_tables())
1236305e366fSDavid van Moolenbroek 		return EINVAL;
1237305e366fSDavid van Moolenbroek 
1238305e366fSDavid van Moolenbroek 	/*
1239305e366fSDavid van Moolenbroek 	 * Unlike the CTL_KERN nodes, we use the ProcFS semantics here: if the
1240305e366fSDavid van Moolenbroek 	 * given PID is negative, it is a kernel task; otherwise, it identifies
1241305e366fSDavid van Moolenbroek 	 * a user process.  A request for PID 0 will result in ESRCH.
1242305e366fSDavid van Moolenbroek 	 */
1243305e366fSDavid van Moolenbroek 	if (pid < 0) {
1244305e366fSDavid van Moolenbroek 		if (pid < -NR_TASKS)
1245305e366fSDavid van Moolenbroek 			return ESRCH;
1246305e366fSDavid van Moolenbroek 
1247305e366fSDavid van Moolenbroek 		kslot = pid + NR_TASKS;
1248305e366fSDavid van Moolenbroek 		assert(kslot < NR_TASKS);
1249305e366fSDavid van Moolenbroek 	} else {
1250305e366fSDavid van Moolenbroek 		if ((mslot = get_mslot(pid)) == NO_SLOT)
1251305e366fSDavid van Moolenbroek 			return ESRCH;
1252305e366fSDavid van Moolenbroek 
1253305e366fSDavid van Moolenbroek 		kslot = NR_TASKS + mslot;
1254305e366fSDavid van Moolenbroek 	}
1255305e366fSDavid van Moolenbroek 
1256305e366fSDavid van Moolenbroek 	if (oldp == NULL)
1257305e366fSDavid van Moolenbroek 		return sizeof(mpd);
1258305e366fSDavid van Moolenbroek 
1259305e366fSDavid van Moolenbroek 	kp = &proc_tab[kslot];
1260305e366fSDavid van Moolenbroek 
1261305e366fSDavid van Moolenbroek 	mflags = (pid > 0) ? mproc_tab[mslot].mp_flags : 0;
1262305e366fSDavid van Moolenbroek 
1263305e366fSDavid van Moolenbroek 	memset(&mpd, 0, sizeof(mpd));
1264305e366fSDavid van Moolenbroek 	mpd.mpd_endpoint = kp->p_endpoint;
1265305e366fSDavid van Moolenbroek 	if (mflags & PRIV_PROC)
1266305e366fSDavid van Moolenbroek 		mpd.mpd_flags |= MPDF_SYSTEM;
1267305e366fSDavid van Moolenbroek 	if (mflags & (TRACE_ZOMBIE | ZOMBIE))
1268305e366fSDavid van Moolenbroek 		mpd.mpd_flags |= MPDF_ZOMBIE;
1269305e366fSDavid van Moolenbroek 	else if ((mflags & TRACE_STOPPED) || RTS_ISSET(kp, RTS_P_STOP))
1270305e366fSDavid van Moolenbroek 		mpd.mpd_flags |= MPDF_STOPPED;
1271305e366fSDavid van Moolenbroek 	else if (proc_is_runnable(kp))
1272305e366fSDavid van Moolenbroek 		mpd.mpd_flags |= MPDF_RUNNABLE;
1273305e366fSDavid van Moolenbroek 	mpd.mpd_blocked_on = P_BLOCKEDON(kp);
1274305e366fSDavid van Moolenbroek 	mpd.mpd_priority = kp->p_priority;
1275305e366fSDavid van Moolenbroek 	mpd.mpd_user_time = kp->p_user_time;
1276305e366fSDavid van Moolenbroek 	mpd.mpd_sys_time = kp->p_sys_time;
1277305e366fSDavid van Moolenbroek 	mpd.mpd_cycles = kp->p_cycles;
1278305e366fSDavid van Moolenbroek 	mpd.mpd_kipc_cycles = kp->p_kipc_cycles;
1279305e366fSDavid van Moolenbroek 	mpd.mpd_kcall_cycles = kp->p_kcall_cycles;
1280305e366fSDavid van Moolenbroek 	if (kslot >= NR_TASKS) {
1281305e366fSDavid van Moolenbroek 		mpd.mpd_nice = mproc_tab[mslot].mp_nice;
1282305e366fSDavid van Moolenbroek 		strlcpy(mpd.mpd_name, mproc_tab[mslot].mp_name,
1283305e366fSDavid van Moolenbroek 		    sizeof(mpd.mpd_name));
1284305e366fSDavid van Moolenbroek 	} else
1285305e366fSDavid van Moolenbroek 		strlcpy(mpd.mpd_name, kp->p_name, sizeof(mpd.mpd_name));
1286305e366fSDavid van Moolenbroek 
1287305e366fSDavid van Moolenbroek 	return mib_copyout(oldp, 0, &mpd, sizeof(mpd));
1288305e366fSDavid van Moolenbroek }
1289