]> Zhao Yanbai Git Server - minix.git/commitdiff
make ps(1) use ProcFS
authorDavid van Moolenbroek <david@minix3.org>
Tue, 14 Sep 2010 21:29:40 +0000 (21:29 +0000)
committerDavid van Moolenbroek <david@minix3.org>
Tue, 14 Sep 2010 21:29:40 +0000 (21:29 +0000)
commands/ps/Makefile
commands/ps/ps.c
man/man1/ps.1

index 61ef3f6847ee16932f880863f290c705a45bfe16..8a91ff441411468e422d7e4bb64065082d6038e8 100644 (file)
@@ -2,8 +2,6 @@
 #
 
 PROG=  ps
-CPPFLAGS+= -I${MINIXSRCDIR} -I${MINIXSRCDIR}/servers
-BINMODE= 4755
 MAN=
 
 .include <bsd.prog.mk>
index bd6f10e7169ad7d3a071312da6c09166011386c7..797a43e7f0e6cb75329058878f514baf13299c0b 100644 (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.
  *
  * 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
  */
 
 #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 */
 
-/* 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;
+u32_t system_hz;               /* system clock frequency */
+unsigned int nr_procs;                 /* maximum number of processes */
+unsigned int nr_tasks;         /* maximum number of tasks */
 
-/* Process tables of the kernel, PM, and VFS. */
-struct proc *ps_proc;
-struct mproc *ps_mproc;
-struct fproc *ps_fproc;
+struct pstat *ptable;          /* table with process information */
 
-/* Where is INIT? */
-int init_proc_nr;
-#define low_user init_proc_nr
+/* Macro to convert endpoints to slots into ptable */
+#define SLOT_NR(e) (_ENDPOINT_P(e) + nr_tasks)
 
-#define        KMEM_PATH       "/dev/kmem"     /* opened for kernel proc table */
-#define        MEM_PATH        "/dev/mem"      /* opened for pm/fs + user processes */
+/* Macro to convert memory offsets to rounded kilo-units */
+#define        off_to_k(off)   ((unsigned) (((off) + 512) / 1024))
 
-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;
-
-  /* Phys address of the original stack frame. */
-  iframe = bufp->ps_procargs - bufp->ps_vstack + bufp->ps_stack;
-
-  /* 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;
-
-  /* Get cnt bytes from user initial stack to local stack buffer */
-  if (lseek(memfd, (off_t) iframe, 0) < 0)
-       return NULL; 
-
-  if ( read(memfd, (char *)stk, cnt) != cnt ) 
-       return NULL;
+  char path[PATH_MAX], buf[4096];
+  ssize_t i, n;
+  int fd;
 
-  sp = stk;
-  nargv = (int) sp[0].stk_i;  /* number of argv arguments */
+  /* 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);
 
-  /* See if argv[0] is with the bytes we read in */
-  l = (long) sp[1].stk_cp - (long) bufp->ps_procargs;
+  fd = open(path, O_RDONLY);
+  if (fd < 0) return NULL;
+
+  n = read(fd, buf, sizeof(buf));
+  if (n <= 0) {
+       close(fd);
 
-  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 */
+  close(fd);
 
-  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';
+  /* Replace all argument separating null characters with spaces. */
+  for (i = 0; i < n-1; i++)
+       if (buf[i] == '\0')
+               buf[i] = ' ';
 
-  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];
+
+  ps->ps_pid = pid;
+  ps->ps_next = NULL;
 
-  if (p_nr < -nr_tasks || p_nr >= nr_procs) {
-       fprintf(stderr, "pstat: %d out of range\n", p_nr);
+  sprintf(path, "%d/psinfo", pid);
+
+  if ((fp = fopen(path, "r")) == NULL)
        return -1;
-  }
 
-  if (isemptyp(&ps_proc[p_ki])
-                               && !(ps_mproc[p_nr].mp_flags & IN_USE)) {
+  if (fscanf(fp, "%d", &version) != 1) {
+       fclose(fp);
        return -1;
   }
 
-  bufp->ps_flags = ps_proc[p_ki].p_rts_flags;
-
-  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;
+  /* The psinfo file's version must match what we expect. */
+  if (version != PSINFO_VERSION) {
+       fputs("procfs version mismatch!\n", stderr);
+       exit(1);
   }
 
-  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;
-       }
-       bufp->ps_pgrp = ps_mproc[p_nr].mp_procgrp;
-       bufp->ps_mflags = ps_mproc[p_nr].mp_flags;
-  } 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;
-  }
+  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) {
 
-  /* 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);
+       return -1;
   }
 
-  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;
+  strncpy(ps->ps_name, name, sizeof(ps->ps_name)-1);
+  ps->ps_name[sizeof(ps->ps_name)-1] = 0;
 
-  bufp->ps_recv = _ENDPOINT_P(ps_proc[p_ki].p_getfrom_e);
+  ps->ps_task = type == TYPE_TASK;
 
-  bufp->ps_utime = ps_proc[p_ki].p_user_time;
-  bufp->ps_stime = ps_proc[p_ki].p_sys_time;
+  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) {
 
-  bufp->ps_procargs = ps_mproc[p_nr].mp_frame_addr;
+               fclose(fp);
+               return -1;
+       }
 
-  if (bufp->ps_state == Z_STATE)
-       bufp->ps_args = "<defunct>";
-  else if (p_nr > init_proc_nr)
-       bufp->ps_args = get_args(bufp);
+       ps->ps_ruid = ruid;
+       ps->ps_euid = euid;
+       ps->ps_dev = dev;
+  } else {
+       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;
+  }
+
+  fclose(fp);
+
+  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;
+
+  /* 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);
+  }
 
-  return read(fd, buf, nbytes);
+  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;
index e9951f946e8faba4b4a68f8f2b3d916b6da1f39b..b7c4f6ce40b45413e45d1bf682645fcbec87d44e 100644 (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)