root@relay.eu.net (05/26/90)
While using the newly posted VirtCons diffs, I noticed that
PS(1) did not understand a thing about the new devices. Since
I _always_ use PS(1) instead of hitting the MAP key, this
bothered me a lot.
I therefore modified ps.c to use the VC-devices as well. All
changes to Ps.c have been marked with #if MUG_VC. I also changed
the name of the database to /etc/ps_data, since we also used
that on out V7 and BSD (2.8 and 2.9) systems.
Regards,
Fred van Kempen
MINIX User Group Holland.
-------------------------------------------------------------------------
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive"
# Contents:
# ps.c
#
# Wrapped by root@minixug on Thu May 24 13:33:29 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'ps.c' -a "${1}" != "-c"
then
echo "$0: Will not overwrite existing file: 'ps.c'"
else
echo "x - ps.c (19540 characters)"
sed 's/^X//' <<\END_OF_SHAR >ps.c
X/* ps - print status Author: Peter Valkenburg */
X
X/* ps.c, Peter Valkenburg (valke@psy.vu.nl), january 1990.
X *
X * This is a V7 ps(1) look-alike for MINIX 1.5.0. It can use a database with
X * information on system addresses as an extra, and has some additional fields.
X * It does not support the 'k' option (i.e. cannot read memory from core file).
X * If you want to compile this for non-IBM PC architectures, the header files
X * require that you have your CHIP, MACHINE etc. defined.
X *
X * VERY IMPORTANT NOTE:
X * To use ps, kernel/kernel, fs/fs, and mm/mm must be in the /usr/src
X * (or the #includes below must be changed). Furthermore, all of
X * must contain symbol tables. This can be arranged using the -s flag
X * and the ast program. For example in fs, one would have
X *
X * asld -s -i -o fs $l/head.s $(obj) $l/libc.a $l/end.s >symbol.out
X * ast -X fs # include symbol.out in fs
X *
X */
X
X/*
X * Most fields are similar to V7 ps(1), except for CPU, NICE, PRI which are
X * absent, RECV which replaces WCHAN, and RUID and PGRP that are extras.
X * The info is obtained from the following fields of proc, mproc and fproc:
X * F - kernel status field, p_flags
X * S - kernel status field, p_flags; mm status field, mp_flags (R if p_flags
X * is 0; Z if mp_flags == HANGING; T if mp_flags == STOPPED; else W).
X * UID - mm eff uid field, mp_effuid
X * RUID - mm real uid field, mp_realuid
X * PID - mm pid field, mp_pid
X * PPID - mm parent process index field, mp_parent (used as index in proc).
X * PGRP - mm process group id mp_procgrp
X * ADDR - kernel physical text address, p_map[T].mem_phys
X * SZ - kernel physical stack address + stack size - physical text address,
X * p_map[S].mem_phys + p_map[S].mem_len - p_map[T].mem_phys
X * RECV - kernel process index field for message receiving, p_getfrom
X * If sleeping, mm's mp_flags, or fs's fp_task are used for more info.
X * TTY - fs controlling tty device field, fs_tty.
X * TIME - kernel user + system times fields, user_time + sys_time
X * CMD - system process index (converted to mnemonic name obtained by reading
X * tasktab array from kmem), or user process argument list (obtained by
X * reading reading stack frame; the resulting address is used to get
X * the argument vector from user space and converted into a concatenated
X * argument list).
X */
X
X#include <minix/config.h>
X#include <limits.h>
X#include <sys/types.h>
X
X#include <minix/const.h>
X#undef EXTERN /* <minix/const.h> defined this */
X#define EXTERN /* so we get proc, mproc and fproc */
X#include <minix/type.h>
X
X#include "/usr/src/kernel/const.h"
X#include "/usr/src/kernel/type.h"
X#include "/usr/src/kernel/proc.h"
X#undef printf /* kernel's const.h defined this */
X
X#include "/usr/src/mm/mproc.h"
X#include "/usr/src/fs/fproc.h"
X#include "/usr/src/fs/const.h"
X#undef printf /* fs's const.h defined this */
X
X
X/*----- ps's local stuff below this line ------*/
X
X#include <minix/com.h>
X#include <fcntl.h>
X#include <a.out.h>
X#include <stdio.h>
X
X#define mindev(dev) (((dev)>>MINOR) & 0377) /* yield minor device */
X#define majdev(dev) (((dev)>>MAJOR) & 0377) /* yield major device */
X
X#define TTY_MAJ 4 /* fixed tty major device */
X
X/* macro to convert memory offsets to rounded kilo-units */
X#define off_to_k(off) ((unsigned) (((off) + 512) / 1024))
X
X/* what we think the relevant identifiers in the namelists are */
X#define ID_PROC "_proc" /* from kernel namelist */
X#define ID_MPROC "_mproc" /* from mm namelist */
X#define ID_FPROC "_fproc" /* from fs namelist */
X#define ID_TASKTAB "_tasktab" /* from kernel namelist */
X
X/*
X * Structure for system address info (also layout of ps's database).
X */
Xtypedef struct {
X struct nlist ke_proc[2], ke_tasktab[2];
X struct nlist mm_mproc[2];
X struct nlist fs_fproc[2];
X} sysinfo_t;
X
Xsysinfo_t sysinfo; /* sysinfo holds actual system info */
X
X#define NAME_SIZ (sizeof(sysinfo.ke_proc[0].n_name)) /* 8 chars */
X
X/* what we think the identfiers of the imported variables in this program are */
X#define PROC proc
X#define MPROC mproc
X#define FPROC fproc
X#define TASKTAB tasktab
X
X/* default paths for system binaries */
X#if (CHIP == M68000)
X#define KERNEL_PATH "/usr/src/kernel/kernel.mix"
X#define MM_PATH "/usr/src/mm/mm.mix"
X#define FS_PATH "/usr/src/fs/fs.mix"
X#else
X#define KERNEL_PATH "/usr/src/kernel/kernel"
X#define MM_PATH "/usr/src/mm/mm"
X#define FS_PATH "/usr/src/fs/fs"
X# endif
X
X#define KMEM_PATH "/dev/kmem" /* opened for kernel proc table */
X#define MEM_PATH "/dev/mem" /* opened for mm/fs + user processes */
X
Xint kmemfd, memfd; /* file descriptors of [k]mem */
X
X#if MUG
X#define DBASE_PATH "/etc/ps_data" /* path of ps's database */
X#else
X#define DBASE_PATH "/etc/psdatabase" /* path of ps's database */
X#endif
X#define DBASE_MODE 0644 /* mode for ps's database */
X
X/* paths for system binaries (not relevant if database is used) */
Xchar *kpath = KERNEL_PATH;
Xchar *mpath = MM_PATH;
Xchar *fpath = FS_PATH;
X
Xstruct tasktab tasktab[NR_TASKS + INIT_PROC_NR + 1]; /* task table */
X
X/*
X * Short and long listing formats:
X *
X * PID TTY TIME CMD
X * ppppp ttmmm:ss ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
X *
X * F S UID PID PPID PGRP ADDR SZ RECV TTY TIME CMD
X * fff s uuu ppppp ppppp ppppp aaaa sss rrrrrrrrrrr ttmmm:ss cccccccccccccccccccc
X * (RAMDSK) FS
X * or
X * (PAUSE) MM
X */
X#define S_HEADER " PID TTY TIME CMD\n"
X#define S_FORMAT "%5d %2s%3D:%02D %.63s\n"
X#define L_HEADER " F S UID PID PPID PGRP ADDR SZ RECV TTY TIME CMD\n"
X#define L_FORMAT "%3o %c %3d %5d %5d %5d %4d %3d %11s %2s%3D:%02D %.20s\n"
X
Xstruct pstat { /* structure filled by pstat() */
X dev_t ps_dev; /* major/minor of controlling tty */
X uid_t ps_ruid; /* real uid */
X uid_t ps_euid; /* effective uid */
X pid_t ps_pid; /* process id */
X pid_t ps_ppid; /* parent process id */
X int ps_pgrp; /* parent process id */
X int ps_flags; /* kernel flags */
X int ps_mflags; /* mm flags */
X int ps_ftask; /* (possibly pseudo) fs suspend task */
X char ps_state; /* process state */
X size_t ps_tsize; /* text size (in bytes) */
X size_t ps_dsize; /* data size (in bytes) */
X size_t ps_ssize; /* stack size (in bytes) */
X off_t ps_text; /* physical text offset */
X off_t ps_data; /* physical data offset */
X off_t ps_stack; /* physical stack offset */
X int ps_recv; /* process number to receive from */
X time_t ps_utime; /* accumulated user time */
X time_t ps_stime; /* accumulated system time */
X char *ps_args; /* concatenated argument string */
X};
X
X/* ps_state field values in pstat struct above */
X#define Z_STATE 'Z' /* Zombie */
X#define W_STATE 'W' /* Waiting */
X#define S_STATE 'S' /* Sleeping */
X#define R_STATE 'R' /* Runnable */
X#define T_STATE 'T' /* stopped (Trace) */
X
X/*
X * Tname returns mnemonic string for dev_nr. This is "?" for unknown maj/min
X * pairs. It is utterly rigid in this implementation...
X */
Xchar *tname(dev_nr)
X{
X#if MUG_VC
X static char *ttys[] = {"co", "t1", "t2", "t3", "t4"}; /* consoles */
X static char *sttys[] = {"t5", "t6"}; /* serial lines */
X int min;
X#else
X static char *ttys[] = {"co", "t1", "t2", "t3"};
X#endif
X
X#if MUG_VC
X min = mindev(dev_nr);
X if (min < 0 ||
X min > 64 + (sizeof(sttys) / sizeof(char *)) ||
X majdev(dev_nr) != TTY_MAJ) /* yuchhh! */
X#else
X if (majdev(dev_nr) != TTY_MAJ || /* yuchhh! */
X mindev(dev_nr) < 0 ||
X mindev(dev_nr) >= sizeof(ttys) / sizeof(char *))
X#endif
X return "? ";
X
X#if MUG_VC
X if (min >= 64) return(sttys[min - 64]);
X else return(ttys[min]);
X#else
X return ttys[mindev(dev_nr)];
X#endif
X}
X
X/* return canonical task name of task p_nr; overwritten on each call */
Xchar *taskname(p_nr)
X{
X char *cp;
X
X if (p_nr < -NR_TASKS || p_nr > INIT_PROC_NR)
X return "?";
X
X /* strip trailing blanks for right-adjusted output */
X for (cp = tasktab[p_nr + NR_TASKS].name; *cp != '\0'; cp++)
X if (*cp == ' ')
X break;
X *cp = '\0';
X
X return tasktab[p_nr + NR_TASKS].name;
X}
X
X/*
X * Prrecv prints the RECV field for process with pstat buffer pointer bufp.
X * This is either "ANY", "taskname", or "(blockreason) taskname".
X */
Xchar *prrecv(bufp)
Xstruct pstat *bufp;
X{
X char *blkstr, *task; /* reason for blocking and task */
X static char recvstr[20];
X
X if (bufp->ps_recv == ANY)
X return "ANY";
X
X task = taskname(bufp->ps_recv);
X if (bufp->ps_state != S_STATE)
X return task;
X
X blkstr = "?";
X if (bufp->ps_recv == MM_PROC_NR) {
X if (bufp->ps_mflags & PAUSED)
X blkstr = "pause";
X else if (bufp->ps_mflags & WAITING)
X blkstr = "wait";
X }
X else if (bufp->ps_recv == FS_PROC_NR) {
X if (-bufp->ps_ftask == XOPEN)
X blkstr = "xopen";
X else if (-bufp->ps_ftask == XPIPE)
X blkstr = "xpipe";
X else
X blkstr = taskname(-bufp->ps_ftask);
X }
X
X (void) sprintf(recvstr, "(%s) %s", blkstr, task);
X return recvstr;
X}
X
X/*
X * Main interprets arguments, gets system addresses, opens [k]mem, reads in
X * process tables from kernel/mm/fs and calls pstat() for relevant entries.
X */
Xmain(argc, argv)
Xchar *argv[];
X{
X int i;
X struct pstat buf;
X int db_fd;
X int uid = getuid(); /* real uid of caller */
X int opt_all = FALSE; /* -a */
X int opt_long = FALSE; /* -l */
X int opt_notty = FALSE; /* -x */
X int opt_update = FALSE; /* -U */
X
X /* parse arguments; a '-' need not be present (V7/BSD compatability) */
X switch (argc) {
X case 1: /* plain ps */
X break;
X case 2: /* ps <[-][alxU]> */
X case 5: /* ps <[-][alxU]> <kernel mm fs> */
X for (i = (argv[1][0] == '-' ? 1 : 0); argv[1][i] != '\0'; i++)
X switch (argv[1][i]) {
X case 'a':
X opt_all = TRUE;
X break;
X case 'l':
X opt_long = TRUE;
X break;
X case 'x':
X opt_notty = TRUE;
X break;
X case 'U':
X opt_update = TRUE;
X break;
X default:
X usage(argv[0]);
X }
X break;
X case 4: /* ps <kernel mm fs> */
X if (argv[1][0] != '-')
X break;
X default:
X usage(argv[0]);
X }
X
X if (argc >= 4) { /* ps [-][alxU] <kernel mm fs> */
X kpath = argv[argc - 3];
X mpath = argv[argc - 2];
X fpath = argv[argc - 1];
X }
X
X /* fill the sysinfo struct with system address information */
X if (opt_update || (db_fd = open(DBASE_PATH, O_RDONLY)) == -1) {
X strncpy(sysinfo.ke_proc[0].n_name, ID_PROC, NAME_SIZ);
X strncpy(sysinfo.ke_tasktab[0].n_name, ID_TASKTAB, NAME_SIZ);
X if (nlist(kpath, sysinfo.ke_proc) != 0 ||
X nlist(kpath, sysinfo.ke_tasktab) != 0)
X err("Can't read kernel namelist");
X strncpy(sysinfo.mm_mproc[0].n_name, ID_MPROC, NAME_SIZ);
X if (nlist(mpath, sysinfo.mm_mproc) != 0)
X err("Can't read mm namelist");
X strncpy(sysinfo.fs_fproc[0].n_name, ID_FPROC, NAME_SIZ);
X if (nlist(fpath, sysinfo.fs_fproc) != 0)
X err("Can't read fs namelist");
X if (opt_update) {
X if ((db_fd = creat(DBASE_PATH, DBASE_MODE)) == -1)
X err("Can't creat psdatabase");
X if (write(db_fd, (char *) &sysinfo,
X sizeof(sysinfo_t)) != sizeof(sysinfo_t))
X err("Can't write psdatabase");
X }
X }
X else {
X if (read(db_fd, (char *) &sysinfo,
X sizeof(sysinfo_t)) != sizeof(sysinfo_t))
X err("Can't read psdatabase");
X }
X (void) close (db_fd);
X
X /* get kernel tables */
X if ((kmemfd = open(KMEM_PATH, O_RDONLY)) == -1)
X err(KMEM_PATH);
X if (addrread(kmemfd, (phys_clicks) 0,
X (vir_bytes) sysinfo.ke_proc[0].n_value,
X (char *) PROC, sizeof(PROC)) != sizeof(PROC))
X err("Can't get kernel proc table from /dev/kmem");
X if (addrread(kmemfd, (phys_clicks) 0,
X (vir_bytes) sysinfo.ke_tasktab[0].n_value,
X (char *) TASKTAB, sizeof(TASKTAB)) != sizeof(TASKTAB))
X err("Can't get kernel task table from /dev/kmem");
X
X /* get mm/fs tables */
X if ((memfd = open(MEM_PATH, O_RDONLY)) == -1)
X err(MEM_PATH);
X if (addrread(memfd, PROC[NR_TASKS + MM_PROC_NR].p_map[D].mem_phys,
X (vir_bytes) sysinfo.mm_mproc[0].n_value,
X (char *) MPROC, sizeof(MPROC)) != sizeof(MPROC))
X err("Can't get mm proc table from /dev/mem");
X if (addrread(memfd, PROC[NR_TASKS + FS_PROC_NR].p_map[D].mem_phys,
X (vir_bytes) sysinfo.fs_fproc[0].n_value,
X (char *) FPROC, sizeof(FPROC)) != sizeof(FPROC))
X err("Can't get fs proc table from /dev/mem");
X
X /* now loop through process table and handle each entry */
X printf("%s", opt_long ? L_HEADER : S_HEADER);
X for (i = -NR_TASKS; i < NR_PROCS; i++) {
X if (pstat(i, &buf) != -1 &&
X (opt_all || buf.ps_euid == uid || buf.ps_ruid == uid) &&
X (opt_notty || majdev(buf.ps_dev) == TTY_MAJ))
X if (opt_long)
X printf(L_FORMAT,
X buf.ps_flags, buf.ps_state,
X buf.ps_euid, buf.ps_pid, buf.ps_ppid,
X buf.ps_pgrp,
X off_to_k(buf.ps_text),
X off_to_k((buf.ps_stack + buf.ps_ssize
X - buf.ps_text)),
X (buf.ps_flags & RECEIVING ?
X prrecv(&buf) :
X ""),
X tname(buf.ps_dev),
X (buf.ps_utime + buf.ps_stime) / HZ / 60,
X (buf.ps_utime + buf.ps_stime) / HZ % 60,
X i <= INIT_PROC_NR ? taskname(i) :
X (buf.ps_args == NULL ? "" :
X buf.ps_args));
X else
X printf(S_FORMAT,
X buf.ps_pid, tname(buf.ps_dev),
X (buf.ps_utime + buf.ps_stime) / HZ / 60,
X (buf.ps_utime + buf.ps_stime) / HZ % 60,
X i <= INIT_PROC_NR ? taskname(i) :
X (buf.ps_args == NULL ? "" :
X buf.ps_args));
X }
X}
X
X/*
X * Get_args inspects /dev/mem, using bufp, and tries to locate the initial
X * stack frame pointer, i.e. the place where the stack started at exec time.
X * It is assumed that the end of the stack frame looks as follows:
X * argc <-- initial stack frame starts here
X * argv[0]
X * ...
X * NULL (*)
X * envp[0]
X * ...
X * NULL (**)
X * argv[0][0] ... '\0'
X * ...
X * argv[argc - 1][0] ... '\0'
X * envp[0][0] ... '\0'
X * ...
X * [trailing '\0']
X * Where the total space occupied by this original stack frame <= ARG_MAX.
X * Get_args reads in the last ARG_MAX bytes of the process' data, and
X * searches back for two NULL ptrs (hopefully the (*) & (**) above).
X * If it finds such a portion, it continues backwards, counting ptrs until:
X * a) either a word is found that has as its value the count (supposedly argc),
X * b) another NULL word is found, in which case the algorithm is reiterated, or
X * c) we wind up before the start of the buffer and fail.
X * Upon success, get_args returns a pointer to the conactenated arg list.
X * Warning: this routine is inherently unreliable and probably doesn't work if
X * ptrs and ints have different sizes.
X */
Xchar *get_args(bufp)
Xstruct pstat *bufp;
X{
X union {
X#if (CHIP == M68000)
X long stk_i;
X#else
X int stk_i;
X#endif
X char *stk_cp;
X char stk_c;
X } stk[ARG_MAX / sizeof(char *)], *sp;
X enum {INITIAL, DONE, FAIL, NULL1, NULL2} state;
X int nargv; /* guessed # of (non-NULL) argv pointers seen */
X int cnt; /* # of bytes read from stack frame */
X int neos; /* # of '\0's seen in argv string space */
X off_t l;
X char *cp, *args;
X
X
X if (bufp->ps_ssize < ARG_MAX)
X cnt = bufp->ps_ssize;
X else
X cnt = ARG_MAX;
X /* get last cnt bytes from user stack */
X if (addrread(memfd, (phys_clicks) (bufp->ps_stack >> CLICK_SHIFT),
X (vir_bytes) (bufp->ps_ssize - cnt),
X (char *) stk, cnt) != cnt)
X return NULL;
X
X state = INITIAL;
X sp = &stk[cnt / sizeof(char *)];
X while (state != DONE && state != FAIL) {
X if (--sp < &stk[0])
X state = FAIL; /* wound up before start of buffer */
X switch(state) {
X case INITIAL: /* no NULL seen yet */
X if (sp[0].stk_cp == NULL)
X state = NULL1;
X break;
X case NULL1: /* one NULL seen */
X if (sp[0].stk_cp == NULL) {
X nargv = 0; /* start counting argv ptrs */
X state = NULL2;
X }
X /*
X * What follows is a dirty patch to recognize sh's
X * stack frame when it has assigned argv[0] to argv[1],
X * and has thus blown away its NULL pointer there.
X */
X else if (sp > &stk[0] && sp[0].stk_cp == sp[-1].stk_cp){
X nargv = 0;
X state = NULL2;
X }
X break;
X case NULL2: /* two NULLs seen */
X if (sp[0].stk_cp == NULL)
X nargv = 0; /* restart counting */
X else if (sp[0].stk_i == nargv)
X state = DONE; /* think i got it */
X /* next is same ugly patch as above */
X else if (sp > &stk[0] && sp[0].stk_cp == sp[-1].stk_cp)
X nargv = 0;
X else
X nargv++; /* ? some argv pointer ? */
X break;
X default: /* FAIL or DONE */
X break;
X }
X }
X
X if (state != DONE)
X return NULL;
X
X /* get a local version of argv[0]; l is offset back from end of stack */
X l = bufp->ps_stack + bufp->ps_ssize -
X#if (CHIP == INTEL)
X bufp->ps_data -
X#endif
X (vir_bytes) sp[1].stk_cp;
X if (l < 0 || l > cnt)
X return NULL;
X args = &((char *) stk)[cnt - (int) l];
X neos = 0;
X for (cp = args; cp < &((char *) stk)[cnt]; cp++)
X if (*cp == '\0')
X if (++neos >= sp[0].stk_i)
X break;
X else
X *cp = ' ';
X if (neos != sp[0].stk_i)
X return NULL;
X
X return args;
X}
X
X/*
X * Pstat collects info on process number p_nr and returns it in buf.
X * It is assumed that tasks do not have entries in fproc/mproc.
X */
Xint pstat(p_nr, bufp)
Xstruct pstat *bufp;
X{
X int p_ki = p_nr + NR_TASKS; /* kernel proc index */
X
X if (p_nr < -NR_TASKS || p_nr >= NR_PROCS)
X return -1;
X
X if ((PROC[p_ki].p_flags & P_SLOT_FREE) &&
X !(MPROC[p_nr].mp_flags & IN_USE))
X return -1;
X
X bufp->ps_flags = PROC[p_ki].p_flags;
X
X if (p_nr >= 0) {
X bufp->ps_dev = FPROC[p_nr].fs_tty;
X bufp->ps_ftask = FPROC[p_nr].fp_task;
X }
X else {
X bufp->ps_dev = 0;
X bufp->ps_ftask = 0;
X }
X
X if (p_nr >= 0) {
X bufp->ps_ruid = MPROC[p_nr].mp_realuid;
X bufp->ps_euid = MPROC[p_nr].mp_effuid;
X bufp->ps_pid = MPROC[p_nr].mp_pid;
X bufp->ps_ppid = MPROC[MPROC[p_nr].mp_parent].mp_pid;
X bufp->ps_pgrp = MPROC[p_nr].mp_procgrp;
X bufp->ps_mflags = MPROC[p_nr].mp_flags;
X }
X else {
X bufp->ps_pid = bufp->ps_ppid = 0;
X bufp->ps_ruid = bufp->ps_euid = 0;
X bufp->ps_pgrp = 0;
X bufp->ps_mflags = 0;
X }
X
X /* state is interpretation of combined kernel/mm flags for non-tasks */
X if (p_nr >= 0) { /* non-tasks */
X if (MPROC[p_nr].mp_flags & HANGING)
X bufp->ps_state = Z_STATE; /* zombie */
X else if (MPROC[p_nr].mp_flags & STOPPED)
X bufp->ps_state = T_STATE; /* stopped (traced) */
X else if (PROC[p_ki].p_flags == 0)
X bufp->ps_state = R_STATE; /* in run-queue */
X else if (MPROC[p_nr].mp_flags & (WAITING | PAUSED) ||
X FPROC[p_nr].fp_suspended == SUSPENDED)
X bufp->ps_state = S_STATE; /* sleeping */
X else
X bufp->ps_state = W_STATE; /* a short wait */
X }
X else { /* tasks are simple */
X if (PROC[p_ki].p_flags == 0)
X bufp->ps_state = R_STATE; /* in run-queue */
X else
X bufp->ps_state = W_STATE; /* other i.e. waiting */
X }
X
X bufp->ps_tsize = (size_t) PROC[p_ki].p_map[T].mem_len << CLICK_SHIFT;
X bufp->ps_dsize = (size_t) PROC[p_ki].p_map[D].mem_len << CLICK_SHIFT;
X bufp->ps_ssize = (size_t) PROC[p_ki].p_map[S].mem_len << CLICK_SHIFT;
X bufp->ps_text = (off_t) PROC[p_ki].p_map[T].mem_phys << CLICK_SHIFT;
X bufp->ps_data = (off_t) PROC[p_ki].p_map[D].mem_phys << CLICK_SHIFT;
X bufp->ps_stack = (off_t) PROC[p_ki].p_map[S].mem_phys << CLICK_SHIFT;
X
X bufp->ps_recv = PROC[p_ki].p_getfrom;
X
X bufp->ps_utime = PROC[p_ki].user_time;
X bufp->ps_stime = PROC[p_ki].sys_time;
X
X if (bufp->ps_state == Z_STATE)
X bufp->ps_args = "<defunct>";
X else if (p_nr > INIT_PROC_NR)
X bufp->ps_args = get_args(bufp);
X
X return 0;
X}
X
X/*
X * Addrread reads nbytes from offset addr to click base of fd into buf.
X */
Xint addrread(fd, base, addr, buf, nbytes)
Xphys_clicks base;
Xvir_bytes addr;
Xchar *buf;
X{
X extern long lseek();
X
X if (lseek(fd, ((long) base << CLICK_SHIFT) + (long) addr, 0) < 0)
X return -1;
X
X return read(fd, buf, nbytes);
X}
X
Xusage(pname)
Xchar *pname;
X{
X fprintf(stderr, "Usage: %s [-][alxU] [kernel mm fs]\n", pname);
X exit(1);
X}
X
Xerr(s)
Xchar *s;
X{
X perror(s);
X exit(2);
X}
END_OF_SHAR
if test 19540 -ne `wc -c <'ps.c'`
then
echo "$0: unpacked with wrong size: ps.c"
fi
fi
echo " End of archive"
exit 0
#
#
#