From 40c8a7062c829d4e08868e11ed09859b07375bf4 Mon Sep 17 00:00:00 2001 From: David van Moolenbroek Date: Tue, 14 Sep 2010 21:29:40 +0000 Subject: [PATCH] make ps(1) use ProcFS --- commands/ps/Makefile | 2 - commands/ps/ps.c | 590 ++++++++++++++++++------------------------- man/man1/ps.1 | 12 +- 3 files changed, 249 insertions(+), 355 deletions(-) diff --git a/commands/ps/Makefile b/commands/ps/Makefile index 61ef3f684..8a91ff441 100644 --- a/commands/ps/Makefile +++ b/commands/ps/Makefile @@ -2,8 +2,6 @@ # PROG= ps -CPPFLAGS+= -I${MINIXSRCDIR} -I${MINIXSRCDIR}/servers -BINMODE= 4755 MAN= .include diff --git a/commands/ps/ps.c b/commands/ps/ps.c index bd6f10e71..797a43e7f 100644 --- a/commands/ps/ps.c +++ b/commands/ps/ps.c @@ -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 -#include -#include #include +#include +#include #include -#include #include #include #include -#include +#include #include #include #include -#include #include -#include #include #include -#include -#include #include #include -#include -#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 = ""; - else if (p_nr > init_proc_nr) - bufp->ps_args = get_args(bufp); + if (ps->ps_state == STATE_ZOMBIE) + ps->ps_args = ""; + 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; diff --git a/man/man1/ps.1 b/man/man1/ps.1 index e9951f946..b7c4f6ce4 100644 --- a/man/man1/ps.1 +++ b/man/man1/ps.1 @@ -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)