make ps(1) use ProcFS

This commit is contained in:
David van Moolenbroek 2010-09-14 21:29:40 +00:00
parent d7b10963c2
commit 40c8a7062c
3 changed files with 249 additions and 355 deletions

View file

@ -2,8 +2,6 @@
#
PROG= ps
CPPFLAGS+= -I${MINIXSRCDIR} -I${MINIXSRCDIR}/servers
BINMODE= 4755
MAN=
.include <bsd.prog.mk>

View file

@ -1,4 +1,5 @@
/* ps - print status Author: Peter Valkenburg */
/* Modified for ProcFS by Alen Stojanov and David van Moolenbroek */
/* Ps.c, Peter Valkenburg (valke@psy.vu.nl), january 1990.
*
@ -32,19 +33,16 @@
* Most fields are similar to V7 ps(1), except for CPU, NICE, PRI which are
* absent, RECV which replaces WCHAN, and PGRP that is an extra.
* The info is obtained from the following fields of proc, mproc and fproc:
* F - kernel status field, p_rts_flags
* S - kernel status field, p_rts_flags; mm status field, mp_flags (R if p_rts_flags
* is 0; Z if mp_flags == ZOMBIE; T if mp_flags == STOPPED; else W).
* UID - mm eff uid field, mp_effuid
* PID - mm pid field, mp_pid
* PPID - mm parent process index field, mp_parent (used as index in proc).
* PGRP - mm process group field, mp_procgrp
* SZ - kernel text size + physical stack address - physical data address
* + stack size
* p_memmap[T].mem_len + p_memmap[S].mem_phys - p_memmap[D].mem_phys
* + p_memmap[S].mem_len
* ST - kernel status field, p_rts_flags; pm status field, mp_flags (R if
* p_rts_flags is 0; Z if mp_flags == ZOMBIE; T if mp_flags == STOPPED;
* else W).
* UID - pm eff uid field, mp_effuid
* PID - pm pid field, mp_pid
* PPID - pm parent process index field, mp_parent (used as index in proc).
* PGRP - pm process group field, mp_procgrp
* SZ - memory size, including common and shared memory
* RECV - kernel process index field for message receiving, p_getfrom
* If sleeping, mm's mp_flags, or fs's fp_task are used for more info.
* If sleeping, pm's mp_flags, or fs's fp_task are used for more info.
* TTY - fs controlling tty device field, fp_tty.
* TIME - kernel user + system times fields, user_time + sys_time
* CMD - system process index (converted to mnemonic name by using the p_name
@ -54,50 +52,28 @@
*/
#include <minix/config.h>
#include <minix/com.h>
#include <minix/sysinfo.h>
#include <minix/endpoint.h>
#include <minix/paths.h>
#include <minix/procfs.h>
#include <limits.h>
#include <timers.h>
#include <sys/types.h>
#include <minix/const.h>
#include <minix/type.h>
#include <minix/ipc.h>
#include <minix/dmap.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <minix/com.h>
#include <fcntl.h>
#include <a.out.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <stdio.h>
#include <ttyent.h>
#include <machine/archtypes.h>
#include "kernel/const.h"
#include "kernel/type.h"
#include "kernel/proc.h"
#include "pm/mproc.h"
#include "pm/const.h"
#include "vfs/fproc.h"
#include "vfs/const.h"
#include "mfs/const.h"
/*----- ps's local stuff below this line ------*/
#define mindev(dev) (((dev)>>MINOR) & 0377) /* yield minor device */
#define majdev(dev) (((dev)>>MAJOR) & 0377) /* yield major device */
#define TTY_MAJ 4 /* major device of console */
/* Structure for tty name info. */
typedef struct {
char tty_name[NAME_MAX + 1]; /* file name in /dev */
@ -107,81 +83,57 @@ typedef struct {
ttyinfo_t *ttyinfo; /* ttyinfo holds actual tty info */
size_t n_ttyinfo; /* Number of tty info slots */
u32_t system_hz; /* system clock frequency */
unsigned int nr_procs; /* maximum number of processes */
unsigned int nr_tasks; /* maximum number of tasks */
struct pstat *ptable; /* table with process information */
/* Macro to convert endpoints to slots into ptable */
#define SLOT_NR(e) (_ENDPOINT_P(e) + nr_tasks)
/* Macro to convert memory offsets to rounded kilo-units */
#define off_to_k(off) ((unsigned) (((off) + 512) / 1024))
/* Number of tasks and processes and addresses of the main process tables. */
int nr_tasks, nr_procs;
extern int errno;
/* Process tables of the kernel, PM, and VFS. */
struct proc *ps_proc;
struct mproc *ps_mproc;
struct fproc *ps_fproc;
/* Where is INIT? */
int init_proc_nr;
#define low_user init_proc_nr
#define KMEM_PATH "/dev/kmem" /* opened for kernel proc table */
#define MEM_PATH "/dev/mem" /* opened for pm/fs + user processes */
int kmemfd, memfd; /* file descriptors of [k]mem */
/* Short and long listing formats:
*
* PID TTY TIME CMD
* ppppp tttmmm:ss cccccccccc...
*
* F S UID PID PPID PGRP SZ RECV TTY TIME CMD
* fff s uuu ppppp ppppp ppppp ssss rrrrrrrrrr tttmmm:ss cccccccc...
* ST UID PID PPID PGRP SZ RECV TTY TIME CMD
* s uuu ppppp ppppp ppppp ssss rrrrrrrrrr tttmmm:ss cccccccc...
*/
#define S_HEADER " PID TTY TIME CMD\n"
#define S_FORMAT "%5s %3s %s %s\n"
#define L_HEADER " F S UID PID PPID PGRP SZ RECV TTY TIME CMD\n"
#define L_FORMAT "%3o %c %3d %5s %5d %5d %6d %12s %3s %s %s\n"
#define L_HEADER "ST UID PID PPID PGRP SZ RECV TTY TIME CMD\n"
#define L_FORMAT " %c %3d %5s %5d %5d %6d %12s %3s %s %s\n"
struct pstat { /* structure filled by pstat() */
struct pstat *ps_next; /* next in process list */
int ps_task; /* is this process a task or not? */
int ps_endpt; /* process endpoint (NONE means unused slot) */
dev_t ps_dev; /* major/minor of controlling tty */
uid_t ps_ruid; /* real uid */
uid_t ps_euid; /* effective uid */
pid_t ps_pid; /* process id */
pid_t ps_ppid; /* parent process id */
int ps_pgrp; /* process group id */
int ps_flags; /* kernel flags */
int ps_mflags; /* mm flags */
int ps_ftask; /* fs suspend task */
int ps_blocked_on; /* what is the process blocked on */
char ps_state; /* process state */
vir_bytes ps_tsize; /* text size (in bytes) */
vir_bytes ps_dsize; /* data size (in bytes) */
vir_bytes ps_ssize; /* stack size (in bytes) */
phys_bytes ps_vtext; /* virtual text offset */
phys_bytes ps_vdata; /* virtual data offset */
phys_bytes ps_vstack; /* virtual stack offset */
phys_bytes ps_text; /* physical text offset */
phys_bytes ps_data; /* physical data offset */
phys_bytes ps_stack; /* physical stack offset */
int ps_recv; /* process number to receive from */
char ps_pstate; /* sleep state */
char ps_fstate; /* VFS block state */
int ps_ftask; /* VFS suspend task (endpoint) */
vir_bytes ps_memory; /* memory usage */
int ps_recv; /* process number to receive from (endpoint) */
time_t ps_utime; /* accumulated user time */
time_t ps_stime; /* accumulated system time */
char ps_name[PROC_NAME_LEN+1];/* process name */
char *ps_args; /* concatenated argument string */
vir_bytes ps_procargs; /* initial stack frame from PM */
};
/* Ps_state field values in pstat struct above */
#define Z_STATE 'Z' /* Zombie */
#define W_STATE 'W' /* Waiting */
#define S_STATE 'S' /* Sleeping */
#define R_STATE 'R' /* Runnable */
#define T_STATE 'T' /* stopped (Trace) */
_PROTOTYPE(void disaster, (int sig ));
_PROTOTYPE(int main, (int argc, char *argv []));
_PROTOTYPE(char *get_args, (struct pstat *bufp ));
_PROTOTYPE(int pstat, (int p_nr, struct pstat *bufp, int Eflag ));
_PROTOTYPE(void plist, (void));
_PROTOTYPE(int addrread, (int fd, phys_clicks base, vir_bytes addr,
char *buf, int nbytes ));
_PROTOTYPE(void usage, (const char *pname ));
@ -197,9 +149,9 @@ _PROTOTYPE(int gettynames, (void));
*/
PRIVATE char *tname(dev_t dev_nr)
{
int i;
unsigned int i;
if (majdev(dev_nr) == TTY_MAJ && mindev(dev_nr) == 0) return "co";
if (major(dev_nr) == TTY_MAJOR && minor(dev_nr) == 0) return "co";
for (i = 0; i < n_ttyinfo && ttyinfo[i].tty_name[0] != '\0'; i++)
if (ttyinfo[i].tty_dev == dev_nr)
@ -208,109 +160,101 @@ PRIVATE char *tname(dev_t dev_nr)
return "?";
}
/* Return canonical task name of task p_nr; overwritten on each call (yucch) */
PRIVATE char *taskname(int p_nr)
/* Find a task by its endpoint. */
PRIVATE struct pstat *findtask(endpoint_t endpt)
{
int n;
n = _ENDPOINT_P(p_nr) + nr_tasks;
if(n < 0 || n >= nr_tasks + nr_procs) {
return "OUTOFRANGE";
}
return ps_proc[n].p_name;
struct pstat *ps;
unsigned int slot;
slot = SLOT_NR(endpt);
if (slot >= nr_tasks + nr_procs)
return NULL;
ps = &ptable[slot];
if (ps != NULL && ps->ps_endpt == (int) endpt)
return ps;
return NULL;
}
/* Prrecv prints the RECV field for process with pstat buffer pointer bufp.
/* Return canonical task name of the given endpoint. */
PRIVATE char *taskname(endpoint_t endpt)
{
struct pstat *ps;
ps = findtask(endpt);
return ps ? ps->ps_name : "???";
}
/* Prrecv prints the RECV field for process with pstat buffer pointer ps.
* This is either "ANY", "taskname", or "(blockreason) taskname".
*/
PRIVATE char *prrecv(struct pstat *bufp)
PRIVATE char *prrecv(struct pstat *ps)
{
char *blkstr, *task; /* reason for blocking and task */
static char recvstr[20];
if (bufp->ps_recv == ANY) return "ANY";
if (ps->ps_recv == ANY) return "ANY";
task = taskname(bufp->ps_recv);
if (bufp->ps_state != S_STATE) return task;
task = taskname(ps->ps_recv);
if (ps->ps_state != STATE_SLEEP) return task;
blkstr = "?";
if (bufp->ps_recv == PM_PROC_NR) {
if (bufp->ps_mflags & PAUSED)
blkstr = "pause";
else if (bufp->ps_mflags & WAITING)
blkstr = "wait";
else if (bufp->ps_mflags & SIGSUSPENDED)
blkstr = "sigsusp";
} else if (bufp->ps_recv == VFS_PROC_NR) {
switch(bufp->ps_blocked_on) {
case FP_BLOCKED_ON_PIPE:
blkstr = "pipe";
break;
case FP_BLOCKED_ON_POPEN:
blkstr = "popen";
break;
case FP_BLOCKED_ON_DOPEN:
blkstr = "dopen";
break;
case FP_BLOCKED_ON_LOCK:
blkstr = "flock";
break;
case FP_BLOCKED_ON_SELECT:
blkstr = "select";
break;
case FP_BLOCKED_ON_OTHER:
blkstr = taskname(bufp->ps_ftask);
break;
case FP_BLOCKED_ON_NONE:
blkstr = "??";
break;
}
if (ps->ps_recv == PM_PROC_NR) {
switch (ps->ps_pstate) {
case PSTATE_PAUSED: blkstr = "pause"; break;
case PSTATE_WAITING: blkstr = "wait"; break;
case PSTATE_SIGSUSP: blkstr = "sigsusp"; break;
}
} else if (ps->ps_recv == VFS_PROC_NR) {
switch (ps->ps_fstate) {
case FSTATE_PIPE: blkstr = "pipe"; break;
case FSTATE_LOCK: blkstr = "flock"; break;
case FSTATE_POPEN: blkstr = "popen"; break;
case FSTATE_SELECT: blkstr = "select"; break;
case FSTATE_DOPEN: blkstr = "dopen"; break;
case FSTATE_TASK: blkstr = taskname(ps->ps_ftask); break;
default: blkstr = "??"; break;
}
}
(void) sprintf(recvstr, "(%s) %s", blkstr, task);
return recvstr;
}
/* If disaster is called some of the system parameters imported into ps are
* probably wrong. This tends to result in memory faults.
*/
void disaster(sig)
int sig;
PRIVATE void getkinfo(void)
{
fprintf(stderr, "Ooops, got signal %d\n", sig);
fprintf(stderr, "Was ps recompiled since the last kernel change?\n");
exit(3);
FILE *fp;
if ((fp = fopen("kinfo", "r")) == NULL)
err("Unable to open " _PATH_PROC "/kinfo");
if (fscanf(fp, "%u %u", &nr_procs, &nr_tasks) != 2)
err("Unable to read from " _PATH_PROC "/kinfo");
fclose(fp);
}
/* Main interprets arguments, gets system addresses, opens [k]mem, reads in
* process tables from kernel/pm/fs and calls pstat() for relevant entries.
/* Main interprets arguments, gathers information, and prints a process list.
*/
int main(argc, argv)
int argc;
char *argv[];
{
int i;
struct pstat buf;
int db_fd;
unsigned int n;
struct pstat *ps;
int uid = getuid(); /* real uid of caller */
char *opt;
int opt_all = FALSE; /* -a */
int opt_long = FALSE; /* -l */
int opt_notty = FALSE; /* -x */
int opt_endpoint = FALSE; /* -E */
char *ke_path; /* paths of kernel, */
char *mm_path; /* mm, */
char *fs_path; /* and fs used in ps -U */
char pid[2 + sizeof(pid_t) * 3];
unsigned long ustime;
char cpu[sizeof(clock_t) * 3 + 1 + 2];
struct kinfo kinfo;
int s;
u32_t system_hz;
if(getsysinfo_up(PM_PROC_NR, SIU_SYSTEMHZ, sizeof(system_hz), &system_hz) < 0) {
exit(1);
}
(void) signal(SIGSEGV, disaster); /* catch a common crash */
/* Parse arguments; a '-' need not be present (V7/BSD compatability) */
for (i = 1; i < argc; i++) {
@ -327,57 +271,34 @@ char *argv[];
}
}
/* Open memory devices and get PS info from the kernel */
if ((kmemfd = open(KMEM_PATH, O_RDONLY)) == -1) err(KMEM_PATH);
if ((memfd = open(MEM_PATH, O_RDONLY)) == -1) err(MEM_PATH);
if (gettynames() == -1) err("Can't get tty names");
getsysinfo(PM_PROC_NR, SI_KINFO, &kinfo);
if (chdir(_PATH_PROC) != 0) err("Can't chdir to /proc");
nr_tasks = kinfo.nr_tasks;
nr_procs = kinfo.nr_procs;
/* Get information from the proc file system */
system_hz = (u32_t) sysconf(_SC_CLK_TCK);
/* Allocate memory for process tables */
ps_proc = (struct proc *) malloc((nr_tasks + nr_procs) * sizeof(ps_proc[0]));
ps_mproc = (struct mproc *) malloc(nr_procs * sizeof(ps_mproc[0]));
ps_fproc = (struct fproc *) malloc(nr_procs * sizeof(ps_fproc[0]));
if (ps_proc == NULL || ps_mproc == NULL || ps_fproc == NULL)
err("Out of memory");
getkinfo();
if(minix_getkproctab(ps_proc, nr_tasks + nr_procs, 1) < 0) {
fprintf(stderr, "minix_getkproctab failed.\n");
exit(1);
}
if(getsysinfo(PM_PROC_NR, SI_PROC_TAB, ps_mproc) < 0) {
fprintf(stderr, "getsysinfo() for PM SI_PROC_TAB failed.\n");
exit(1);
}
if(getsysinfo(VFS_PROC_NR, SI_PROC_TAB, ps_fproc) < 0) {
fprintf(stderr, "getsysinfo() for VFS SI_PROC_TAB failed.\n");
exit(1);
}
/* We need to know where INIT hangs out. */
for (i = VFS_PROC_NR; i < nr_procs; i++) {
if (strcmp(ps_proc[nr_tasks + i].p_name, "init") == 0) break;
}
init_proc_nr = i;
plist();
/* Now loop through process table and handle each entry */
printf("%s", opt_long ? L_HEADER : S_HEADER);
for (i = -nr_tasks; i < nr_procs; i++) {
if (pstat(i, &buf, opt_endpoint) != -1 &&
(opt_all || buf.ps_euid == uid || buf.ps_ruid == uid) &&
(opt_notty || majdev(buf.ps_dev) == TTY_MAJ)) {
if (buf.ps_pid == 0 && i != PM_PROC_NR) {
sprintf(pid, "(%d)", i);
for (n = 0; n < nr_procs + nr_tasks; n++) {
ps = &ptable[n];
if (ps->ps_endpt == NONE)
continue;
if ((opt_all || ps->ps_euid == uid || ps->ps_ruid == uid) &&
(opt_notty || major(ps->ps_dev) == TTY_MAJOR)) {
if (ps->ps_task) {
sprintf(pid, "(%d)", ps->ps_pid);
} else {
sprintf(pid, "%d", buf.ps_pid);
sprintf(pid, "%d",
opt_endpoint ? ps->ps_endpt : ps->ps_pid);
}
ustime = (buf.ps_utime + buf.ps_stime) / system_hz;
ustime = (ps->ps_utime + ps->ps_stime) / system_hz;
if (ustime < 60 * 60) {
sprintf(cpu, "%2lu:%02lu", ustime / 60, ustime % 60);
} else
@ -389,196 +310,181 @@ char *argv[];
}
if (opt_long) printf(L_FORMAT,
buf.ps_flags, buf.ps_state,
buf.ps_euid, pid, buf.ps_ppid,
buf.ps_pgrp,
#if 0
off_to_k((buf.ps_tsize
+ buf.ps_stack - buf.ps_data
+ buf.ps_ssize)),
#else
0,
#endif
(buf.ps_flags & RTS_RECEIVING ?
prrecv(&buf) :
""),
tname((dev_t) buf.ps_dev),
ps->ps_state,
ps->ps_euid, pid, ps->ps_ppid,
ps->ps_pgrp,
off_to_k(ps->ps_memory),
(ps->ps_recv != NONE ? prrecv(ps) : ""),
tname((dev_t) ps->ps_dev),
cpu,
i <= init_proc_nr || buf.ps_args == NULL
? taskname(i) : buf.ps_args);
ps->ps_args != NULL ? ps->ps_args : ps->ps_name
);
else
printf(S_FORMAT,
pid, tname((dev_t) buf.ps_dev),
pid, tname((dev_t) ps->ps_dev),
cpu,
i <= init_proc_nr || buf.ps_args == NULL
? taskname(i) : buf.ps_args);
ps->ps_args != NULL ? ps->ps_args : ps->ps_name
);
}
}
return(0);
}
char *get_args(bufp)
struct pstat *bufp;
/* Get_args obtains the command line of a process. */
char *get_args(struct pstat *ps)
{
int nargv;
int cnt; /* # of bytes read from stack frame */
int neos; /* # of '\0's seen in argv string space */
phys_bytes iframe;
long l;
char *cp, *args;
static union stack {
vir_bytes stk_i;
char *stk_cp;
char stk_c;
} stk[ARG_MAX / sizeof(char *)];
union stack *sp;
char path[PATH_MAX], buf[4096];
ssize_t i, n;
int fd;
/* Phys address of the original stack frame. */
iframe = bufp->ps_procargs - bufp->ps_vstack + bufp->ps_stack;
/* Get a reasonable subset of the contents of the 'cmdline' file from procfs.
* It contains all arguments, separated and terminated by null characters.
*/
sprintf(path, "%d/cmdline", ps->ps_pid);
/* Calculate the number of bytes to read from user stack */
l = (phys_bytes) bufp->ps_ssize - (iframe - bufp->ps_stack);
if (l > ARG_MAX) l = ARG_MAX;
cnt = l;
fd = open(path, O_RDONLY);
if (fd < 0) return NULL;
/* Get cnt bytes from user initial stack to local stack buffer */
if (lseek(memfd, (off_t) iframe, 0) < 0)
return NULL;
n = read(fd, buf, sizeof(buf));
if (n <= 0) {
close(fd);
if ( read(memfd, (char *)stk, cnt) != cnt )
return NULL;
}
sp = stk;
nargv = (int) sp[0].stk_i; /* number of argv arguments */
close(fd);
/* See if argv[0] is with the bytes we read in */
l = (long) sp[1].stk_cp - (long) bufp->ps_procargs;
/* Replace all argument separating null characters with spaces. */
for (i = 0; i < n-1; i++)
if (buf[i] == '\0')
buf[i] = ' ';
if ( ( l < 0 ) || ( l > cnt ) )
return NULL;
/* l is the offset of the argv[0] argument */
/* change for concatenation the '\0' to space, for nargv elements */
args = &((char *) stk)[(int)l];
neos = 0;
for (cp = args; cp < &((char *) stk)[cnt]; cp++)
if (*cp == '\0')
if (++neos >= nargv)
break;
else
*cp = ' ';
if (cp == args) return NULL;
*cp = '\0';
return args;
/* The last character should already be null, except if it got cut off. */
buf[n-1] = '\0';
return strdup(buf);
}
/* Pstat collects info on process number p_nr and returns it in buf.
* It is assumed that tasks do not have entries in fproc/mproc.
/* Pstat obtains the actual information for the given process, and stores it
* in the pstat structure. The outside world may change while we are doing
* this, so nothing is reported in case any of the calls fail.
*/
int pstat(int p_nr, struct pstat *bufp, int endpoints)
int pstat(struct pstat *ps, pid_t pid)
{
int p_ki = p_nr + nr_tasks; /* kernel proc index */
FILE *fp;
int version, ruid, euid, dev;
char type, path[PATH_MAX], name[256];
if (p_nr < -nr_tasks || p_nr >= nr_procs) {
fprintf(stderr, "pstat: %d out of range\n", p_nr);
ps->ps_pid = pid;
ps->ps_next = NULL;
sprintf(path, "%d/psinfo", pid);
if ((fp = fopen(path, "r")) == NULL)
return -1;
if (fscanf(fp, "%d", &version) != 1) {
fclose(fp);
return -1;
}
if (isemptyp(&ps_proc[p_ki])
&& !(ps_mproc[p_nr].mp_flags & IN_USE)) {
/* The psinfo file's version must match what we expect. */
if (version != PSINFO_VERSION) {
fputs("procfs version mismatch!\n", stderr);
exit(1);
}
if (fscanf(fp, " %c %d %255s %c %d %*d %lu %lu %*u %*u",
&type, &ps->ps_endpt, name, &ps->ps_state,
&ps->ps_recv, &ps->ps_utime, &ps->ps_stime) != 7) {
fclose(fp);
return -1;
}
bufp->ps_flags = ps_proc[p_ki].p_rts_flags;
strncpy(ps->ps_name, name, sizeof(ps->ps_name)-1);
ps->ps_name[sizeof(ps->ps_name)-1] = 0;
if (p_nr >= low_user) {
bufp->ps_dev = ps_fproc[p_nr].fp_tty;
bufp->ps_ftask = ps_fproc[p_nr].fp_task;
bufp->ps_blocked_on = ps_fproc[p_nr].fp_blocked_on;
} else {
bufp->ps_dev = 0;
bufp->ps_ftask = 0;
bufp->ps_blocked_on = FP_BLOCKED_ON_NONE;
}
ps->ps_task = type == TYPE_TASK;
if (p_nr >= 0) {
bufp->ps_ruid = ps_mproc[p_nr].mp_realuid;
bufp->ps_euid = ps_mproc[p_nr].mp_effuid;
if(endpoints) bufp->ps_pid = ps_proc[p_ki].p_endpoint;
else bufp->ps_pid = ps_mproc[p_nr].mp_pid;
bufp->ps_ppid = ps_mproc[ps_mproc[p_nr].mp_parent].mp_pid;
/* Assume no parent when the parent and the child share the same pid.
* This is what PM currently assumes.
*/
if(bufp->ps_ppid == bufp->ps_pid) {
bufp->ps_ppid = NO_PID;
if (!ps->ps_task) {
if (fscanf(fp, " %lu %*u %*u %c %d %u %u %u %*d %c %d %u",
&ps->ps_memory, &ps->ps_pstate, &ps->ps_ppid,
&ruid, &euid, &ps->ps_pgrp, &ps->ps_fstate,
&ps->ps_ftask, &dev) != 9) {
fclose(fp);
return -1;
}
bufp->ps_pgrp = ps_mproc[p_nr].mp_procgrp;
bufp->ps_mflags = ps_mproc[p_nr].mp_flags;
ps->ps_ruid = ruid;
ps->ps_euid = euid;
ps->ps_dev = dev;
} else {
if(endpoints) bufp->ps_pid = ps_proc[p_ki].p_endpoint;
else bufp->ps_pid = NO_PID;
bufp->ps_ppid = NO_PID;
bufp->ps_ruid = bufp->ps_euid = 0;
bufp->ps_pgrp = 0;
bufp->ps_mflags = 0;
ps->ps_memory = 0L;
ps->ps_pstate = PSTATE_NONE;
ps->ps_ppid = 0;
ps->ps_ruid = 0;
ps->ps_euid = 0;
ps->ps_pgrp = 0;
ps->ps_fstate = FSTATE_NONE;
ps->ps_ftask = NONE;
ps->ps_dev = NO_DEV;
}
/* State is interpretation of combined kernel/mm flags for non-tasks */
if (p_nr >= low_user) { /* non-tasks */
if (ps_mproc[p_nr].mp_flags & ZOMBIE)
bufp->ps_state = Z_STATE; /* zombie */
else if (ps_mproc[p_nr].mp_flags & STOPPED)
bufp->ps_state = T_STATE; /* stopped (traced) */
else if (ps_proc[p_ki].p_rts_flags == 0)
bufp->ps_state = R_STATE; /* in run-queue */
else if (ps_mproc[p_nr].mp_flags & (WAITING | PAUSED | SIGSUSPENDED) ||
fp_is_blocked(&ps_fproc[p_nr]))
bufp->ps_state = S_STATE; /* sleeping */
else
bufp->ps_state = W_STATE; /* a short wait */
} else { /* tasks are simple */
if (ps_proc[p_ki].p_rts_flags == 0)
bufp->ps_state = R_STATE; /* in run-queue */
else
bufp->ps_state = W_STATE; /* other i.e. waiting */
}
fclose(fp);
bufp->ps_tsize = (size_t) ps_proc[p_ki].p_memmap[T].mem_len << CLICK_SHIFT;
bufp->ps_dsize = (size_t) ps_proc[p_ki].p_memmap[D].mem_len << CLICK_SHIFT;
bufp->ps_ssize = (size_t) ps_proc[p_ki].p_memmap[S].mem_len << CLICK_SHIFT;
bufp->ps_vtext = (off_t) ps_proc[p_ki].p_memmap[T].mem_vir << CLICK_SHIFT;
bufp->ps_vdata = (off_t) ps_proc[p_ki].p_memmap[D].mem_vir << CLICK_SHIFT;
bufp->ps_vstack = (off_t) ps_proc[p_ki].p_memmap[S].mem_vir << CLICK_SHIFT;
bufp->ps_text = (off_t) ps_proc[p_ki].p_memmap[T].mem_phys << CLICK_SHIFT;
bufp->ps_data = (off_t) ps_proc[p_ki].p_memmap[D].mem_phys << CLICK_SHIFT;
bufp->ps_stack = (off_t) ps_proc[p_ki].p_memmap[S].mem_phys << CLICK_SHIFT;
bufp->ps_recv = _ENDPOINT_P(ps_proc[p_ki].p_getfrom_e);
bufp->ps_utime = ps_proc[p_ki].p_user_time;
bufp->ps_stime = ps_proc[p_ki].p_sys_time;
bufp->ps_procargs = ps_mproc[p_nr].mp_frame_addr;
if (bufp->ps_state == Z_STATE)
bufp->ps_args = "<defunct>";
else if (p_nr > init_proc_nr)
bufp->ps_args = get_args(bufp);
if (ps->ps_state == STATE_ZOMBIE)
ps->ps_args = "<defunct>";
else if (!ps->ps_task)
ps->ps_args = get_args(ps);
else
ps->ps_args = NULL;
return 0;
}
/* Addrread reads nbytes from offset addr to click base of fd into buf. */
int addrread(int fd, phys_clicks base, vir_bytes addr, char *buf, int nbytes)
/* Plist creates a list of processes with status information. */
void plist(void)
{
if (lseek(fd, ((off_t) base << CLICK_SHIFT) + addr, 0) < 0)
return -1;
DIR *p_dir;
struct dirent *p_ent;
struct pstat pbuf;
pid_t pid;
char *end;
unsigned int slot;
return read(fd, buf, nbytes);
/* Allocate a table for process information. Initialize all slots' endpoints
* to NONE, indicating those slots are not used.
*/
if ((ptable = malloc((nr_tasks + nr_procs) * sizeof(struct pstat))) == NULL)
err("Out of memory!");
for (slot = 0; slot < nr_tasks + nr_procs; slot++)
ptable[slot].ps_endpt = NONE;
/* Fill in the table slots for all existing processes, by retrieving all PID
* entries from the /proc directory.
*/
p_dir = opendir(".");
if (p_dir == NULL) err("Can't open " _PATH_PROC);
p_ent = readdir(p_dir);
while (p_ent != NULL) {
pid = strtol(p_ent->d_name, &end, 10);
if (!end[0] && pid != 0 && !pstat(&pbuf, pid)) {
slot = SLOT_NR(pbuf.ps_endpt);
if (slot < nr_tasks + nr_procs)
memcpy(&ptable[slot], &pbuf, sizeof(pbuf));
}
p_ent = readdir(p_dir);
}
closedir(p_dir);
}
void usage(const char *pname)
@ -605,7 +511,7 @@ int gettynames(void)
static char dev_path[] = "/dev/";
struct stat statbuf;
static char path[sizeof(dev_path) + NAME_MAX];
int index;
unsigned int index;
struct ttyent *ttyp;
index = 0;

View file

@ -29,17 +29,7 @@ ps \- process status
processes are listed in short format (the PID, TTY, TIME and CMD fields as
explained below). The long listing contains:
.PP
.ta 0.5i 1.0i
F Kernel flags:
001: free slot
002: no memory map
004: sending;
010: receiving
020: inform on pending signals
040: pending signals
100: being traced.
.PP
S
ST
State:
R: runnable
W: waiting (on a message)