[comp.os.minix] ps

rtregn@immd3.informatik.uni-erlangen.de (Robert Regn) (11/18/88)

ps from Monty Walls needs some information in maint.info which
is apparently extracted from files generated with a MS DOS compiler (.map).
But how to generate the maint.info when compiling the system under Minix ?
Has someone this numbers for the newest Version ?
In this case please post your maint.info !!


			Robert Regn							rtregn@faui32.uucp

pa1293@sdcc15.ucsd.edu (pa1293) (11/21/88)

In article <741@faui44.informatik.uni-erlangen.de>, rtregn@immd3.informatik.uni-erlangen.de (Robert Regn) writes:
> ps from Monty Walls needs some information in maint.info which

compile the operating system with the -s (symbol table) option in minix and
redirect the output to a .map file
example:
in makefile:
asld -s -o kernel $l/crtso.s $OBJ $l/libc.a $l/end.s > kernel.map
asld -s -o ms $l/head.s $OBJ $l/libc.a $l/end.s > mm.map
asld -s -o fs $l/crtso.s $OBJ $l/libc.a $l/end.s > fs.map

then run the file "maint.sh" to extract the needed info.
(make sure the path in the maint.sh is correct (/usr/src ...)

I hope this helps anyone who has this problem.

John J. Marco
pa1293@sdcc15.ucsd.edu    (iugrad2 may need to be subbed for sdcc15)
~!nosc!ucsd!sdcc15!pa1293
US Snail: Po Box 4559
|         La Jolla, CA 92037
|         U.S.A

bammi@dsrgsun.ces.cwru.edu (Jwahar R. Bammi) (11/21/88)

Does anyone know how to get  a .map file for MinixST and ACK cc.
cc -s does'nt seem to do much. ast -- how about distributing some
docs for ld, format of object file and other such useful info for
ACK CC for the atari. another question - why was cv written so that
it strips the symbol table, any special reason??
--
usenet: {decvax,sun}!cwjcc!dsrgsun!bammi	jwahar r. bammi
csnet:       bammi@dsrgsun.ces.CWRU.edu
arpa:        bammi@dsrgsun.ces.CWRU.edu
compuServe:  71515,155

frank@Morgan.COM (Frank Wortner) (11/21/88)

In article <741@faui44.informatik.uni-erlangen.de> rtregn@immd3.informatik.uni-erlangen.de (Robert Regn) writes:
>ps from Monty Walls needs some information in maint.info which
>is apparently extracted from files generated with a MS DOS compiler (.map).
>But how to generate the maint.info when compiling the system under Minix ?

The best way to do this is to add the "-s" option to the line which links
FS, MM, and KERNEL.  Just edit the makefile and add it to the line where asld
is invoked.  Save the result in mm.map, fs.map, and kernel.map, and you are
in business!

>Has someone this numbers for the newest Version ?
>In this case please post your maint.info !!

Unfortnately, the numbers can vary depending on the version of Minix, the
device drivers used, the local changes made to the OS, etc.  Using someone
else's maint.info probably will not work.



-- 
						Frank

"Computers are mistake amplifiers."

bill@uhccux.uhcc.hawaii.edu (William J. King) (11/24/88)

If I buy MINIX V 1.3 will I be getting a fully operational system?  Or
will I have to follow along this newsgroup to make corrections?

bill@uhccux.bitnet

rob@cs.vu.nl (02/03/90)

[I tried to post this a few days ago, but it didn't seem to make it.
This is a retry from a different site, using a friend's name]

	Hi there,

I have hacked together a ps for PC MINIX 1.5.0.  Its interface is modelled
after Version 7 ps(1), but it supports a database that makes it fast, and a
RECV field that is more informative than what you get when you hit 'F1' on
your MINIX console.

I have tested this on MINIX 1.5.0 on a 80386 PC.  It will need patching to
to work on other (i.e. non-PC or pre-1.5) systems.  If anyone feels like
porting it, go ahead - I am interested to see the results, but won't do this
myself.

The following is what "ps -alx" reports on a (carefully constructed :-) state
of my system:

  F S UID   PID  PPID  PGRP ADDR  SZ        RECV TTY  TIME CMD
 10 W   0     0     0     0    2  54         ANY  ?   0:14 TTY
  0 R   0     0     0     0    2  54              ? 227:40 IDLE
 10 W   0     0     0     0    2  54         ANY  ?   0:00 PRINTR
 10 W   0     0     0     0    2  54         ANY  ?   0:24 WINCHE
 10 W   0     0     0     0    2  54         ANY  ?   0:00 FLOPPY
  0 R   0     0     0     0    2  54              ?   0:01 RAMDSK
 10 W   0     0     0     0    2  54         ANY  ?   0:01 CLOCK
 10 W   0     0     0     0    2  54         ANY  ?   0:24 SYS
  0 R   0     0     0     0    2  54              ?   0:44 HARDWA
 10 W   0     0     0     3   55  18         ANY  ?   0:05 MM
 10 W   0     0     0     0   73  58      RAMDSK  ?   0:31 FS
 10 S   0     1     0     0  131   4   (wait) MM  ?   0:00 INIT
 10 S   2    34     1    34  136  40   (wait) MM  co  0:02 -
 10 S   0    32     1     3  186   2  (pause) MM  ?   0:00 /etc/update
 10 S   0    27     1     3  197  22  (pause) MM  ?   0:10 /bin/cron
 10 S   8   646     1   646  220  40   (wait) MM  t1  0:00 -
 10 S   8   775   646   646  259  24    (TTY) FS  t1  0:00 man 1 ps
 10 S   2   865    34    34  175   9  (pause) MM  co  0:00 sleep 2000
  1 Z   2   866   865    34  188   9              co  0:00 <defunct>
 10 S   2   895    34    34  283  20   (wait) MM  co  0:00 cc ps.c -o ps
  0 R   2   897   895    34  343  70              co  0:01 /usr/lib/cpp ps.c
 10 S   2   898   895    34  413 117  (xpipe) FS  co  0:00 /usr/lib/cem -L - /t
 10 W   2   900    34    34  529  64          FS  co  0:00 ps -alx

Since ps needs namelists from the kernel, mm and fs executables, I have written
an nlist(3) library routine as well.  It is contained (together with ps) in
the shell archive below.  Have fun with it!

			Peter Valkenburg (valke@psy.vu.nl).
			(I used someone else's account for this
			posting, but please reply to my address).

# This is a shar archive.  Extract with sh, not csh.
# This archive ends with exit, so do not worry about trailing junk.
# --------------------------- cut here --------------------------
#! /bin/sh
PATH=/bin:/usr/bin
if test -f \p\s
then	echo Removing   \p\s
	rm \p\s
fi
if test -d \p\s
then	:
else	echo Creating   \p\s
	mkdir \p\s
fi
chmod 'u=rwx,g=rx,o=rx' \p\s
: Now archive the contents of the directory.
echo Extracting \p\s\/\R\E\A\D\M\E
sed 's/^X//' > \p\s\/\R\E\A\D\M\E << '+ END-OF-FILE '\p\s\/\R\E\A\D\M\E
X		Ps(1) for PC MINIX 1.5.0
X
XThis directory contains the source for ps(1) and the (formatted) manual page.
X
XYou'll need the {kernel,mm,fs} include files in place when compiling ps.c.
XYou also need an nlist(3) library routine.  If you don't have it and it doesn't
Xcome along with this source you can get it from me.  I wrote one for this ps.
XNo further special action is needed to compile ps.c on PC MINIX 1.5.0.
X
XPs needs system addresses that are up-to-date.  It takes them (by default)
Xfrom /usr/src/kernel/kernel, /usr/src/mm/mm and /usr/src/fs/fs, which are
Xsupposed to be the *non*-stripped system executables, see the manual page.
XA "ps U" will create /etc/psdatabase, after which the system binaries are no
Xlonger needed and ps is very fast (less than one second for a "ps alx" on a
X80386).
X
XPs depends heavily on certain system addresses and data structures.  You have
Xto recompile it and perhaps even change some of its code when major changes
Xhave been made to the system.  The least thing to do is to update the file
X/etc/psdatabase when using a boot image with a new kernel, mm or fs.
X
XThis version runs on MINIX 1.5.0 for the PC.  It has been tested extensively on
Xan 80386 running protected mode.  I am very interested to hear of any ports to
Xnon-PC systems.
X
XBug reports & comments can be sent to:  Peter Valkenburg (valke@psy.vu.nl).
+ END-OF-FILE ps/README
chmod 'u=rw,g=r,o=r' \p\s\/\R\E\A\D\M\E
set `sum \p\s\/\R\E\A\D\M\E`
sum=$1
case $sum in
13539)	:;;
*)	echo 'Bad sum in '\p\s\/\R\E\A\D\M\E >&2
esac
echo Extracting \p\s\/\p\s\.\c
sed 's/^X//' > \p\s\/\p\s\.\c << '+ END-OF-FILE '\p\s\/\p\s\.\c
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 * This program assumes that kernel/fs/mm are non-stripped executables.
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 <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
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/*----- 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#define KERNEL_PATH	"/usr/src/kernel/kernel"
X#define MM_PATH		"/usr/src/mm/mm"
X#define FS_PATH		"/usr/src/fs/fs"
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#define DBASE_PATH	"/etc/psdatabase"	/* path of ps's database */
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	static char *ttys[] = {"co", "t1", "t2", "t3"};
X	
X	if (majdev(dev_nr) != TTY_MAJ ||		/* yuchhh! */
X	    mindev(dev_nr) < 0 ||
X	    mindev(dev_nr) >= sizeof(ttys) / sizeof(char *))
X		return "? ";
X	
X	return ttys[mindev(dev_nr)];	
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		int stk_i;
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		(bufp->ps_data + (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-FILE ps/ps.c
chmod 'u=rw,g=r,o=r' \p\s\/\p\s\.\c
set `sum \p\s\/\p\s\.\c`
sum=$1
case $sum in
12181)	:;;
*)	echo 'Bad sum in '\p\s\/\p\s\.\c >&2
esac
echo Extracting \p\s\/\p\s\.\m\a\n\1
sed 's/^X//' > \p\s\/\p\s\.\m\a\n\1 << '+ END-OF-FILE '\p\s\/\p\s\.\m\a\n\1
X#ps
XCommand:   ps - process status (MINIX 1.5.0)
XSyntax:    ps [-][alxU] [kernel mm fs]
XFlags:     -a  Print all processes with controlling terminals
X	   -l  Give long listing
X	   -x  Include processes without a terminal
X	   -U  Update ps's database from the system executables
XExample:  ps -axl	   	 # print all processes and tasks in long format
X	  ps -U /kernel /fs /mm  # update ps's database from system executables
X   Ps prints the status of active processes.  Normally only the caller's own
Xprocesses are listed in short format (the PID, TTY, TIME and CMD fields as
Xexplained below).  The long listing contains:
X  F	  Kernel flags.  001: free slot; 002: no memory map; 004: sending;
X  	  010: receiving; 020: inform on pending signals; 040: pending signals;
X  	  100: being traced.
X  S	  State.  R: runnable; W: waiting (on a message); S: sleeping (i.e.
X  	  suspended on MM or FS); Z: zombie; T: stopped.
X  UID, PID, PPID, PGRP
X	  The user, process, parent process and process group ID's.
X  ADDR, SZ
X	  Decimal address and size of the process in kilobytes.
X  RECV    Process/task on which a receiving process is waiting or sleeping.  If
X  	  sleeping, the suspending call to MM or (possibly pseudo) task in FS
X  	  is also given, e.g., "(xpipe) FS" means process is blocked on a pipe.
X  TTY	  Controlling tty for the process.
X  TIME    Process' cumulative (user + system) execution time.
X  CMD	  Command line arguments of the process.  System processes and tasks
X	  have a mnemonic name.
X   If extra arguments (the kernel, mm and fs non-stripped executables) are
Xgiven, these are used to obtain the system addresses from (instead of the
Xdefault system executables).  This applies to the -U option also.
X   The default system executables are /usr/src/{kernel/kernel,mm/mm,fs/fs};
Xthe database for system addresses is kept in /etc/psdatabase; /dev/{mem,kmem}
Xare used to read the system tables and command line arguments from.
X
+ END-OF-FILE ps/ps.man1
chmod 'u=rw,g=r,o=r' \p\s\/\p\s\.\m\a\n\1
set `sum \p\s\/\p\s\.\m\a\n\1`
sum=$1
case $sum in
24173)	:;;
*)	echo 'Bad sum in '\p\s\/\p\s\.\m\a\n\1 >&2
esac
if test -f \n\l\i\s\t
then	echo Removing   \n\l\i\s\t
	rm \n\l\i\s\t
fi
if test -d \n\l\i\s\t
then	:
else	echo Creating   \n\l\i\s\t
	mkdir \n\l\i\s\t
fi
chmod 'u=rwx,g=rx,o=rx' \n\l\i\s\t
: Now archive the contents of the directory.
echo Extracting \n\l\i\s\t\/\R\E\A\D\M\E
sed 's/^X//' > \n\l\i\s\t\/\R\E\A\D\M\E << '+ END-OF-FILE '\n\l\i\s\t\/\R\E\A\D\M\E
X		Nlist(3) for MINIX
X
XThis directory contains the library source for nlist(3) and the (formatted)
Xmanual page.
X
XIf you add nlist() to your library, then put it before fopen/fclose/fread,
Xsince it uses these library routines.
X
XThis version was written for ps(1) on PC MINIX 1.5.0.  I haven't tested it in
Xdetail in other applications, but it should do its work in any application,
Xif you have the proper /usr/include/a.out.h, i.e. that of MINIX (which is not
Xcompatible with other UNIX a.out.h's).
X
XBug reports & comments can be sent to:  Peter Valkenburg (valke@psy.vu.nl).
+ END-OF-FILE nlist/README
chmod 'u=rw,g=r,o=r' \n\l\i\s\t\/\R\E\A\D\M\E
set `sum \n\l\i\s\t\/\R\E\A\D\M\E`
sum=$1
case $sum in
21078)	:;;
*)	echo 'Bad sum in '\n\l\i\s\t\/\R\E\A\D\M\E >&2
esac
echo Extracting \n\l\i\s\t\/\n\l\i\s\t\.\c
sed 's/^X//' > \n\l\i\s\t\/\n\l\i\s\t\.\c << '+ END-OF-FILE '\n\l\i\s\t\/\n\l\i\s\t\.\c
X/*
X * "nlist.c", Peter Valkenburg, january 1989.
X */
X 
X#include <lib.h>
X#include <a.out.h>
X#include <stdio.h>
X#include <sys/types.h>
X#include <fcntl.h>
X#include <unistd.h>
X
X#define fail(fp)	(fclose(fp), -1)	/* ret. exp. when nlist fails */
X
X/*
X * Nlist fills fields n_sclass and n_value of array nl with values found in
X * non-stripped executable file.  Entries that are not found have their
X * n_value/n_sclass fields set to 0.  Nl ends with a 0 or nul string n_name.
X * The return value is -1 on failure, else the number of entries not found.
X */
Xint nlist(file, nl)
Xchar *file;
Xstruct nlist nl[];
X{
X	int nents, nsrch, nfound, i;
X	struct nlist nlent;
X	FILE *fp;
X	struct exec hd;
X
X	/* open executable with namelist */
X	if ((fp = fopen(file, "r")) == NULL)
X		return -1;
X		
X	/* get header and seek to start of namelist */	
X	if (fread((char *) &hd, sizeof(struct exec), 1, fp) != 1 ||
X	    BADMAG(hd) || fseek(fp, A_SYMPOS(hd), SEEK_SET) != 0)
X		return fail(fp);
X	
X	/* determine number of entries searched for & reset fields */
X	nsrch = 0;
X	while (nl[nsrch].n_name != NULL && *(nl[nsrch].n_name) != '\0') {
X		nl[nsrch].n_sclass = 0;
X		nl[nsrch].n_value = 0;
X		nl[nsrch].n_type = 0;		/* for compatability */
X		nsrch++;
X	}
X
X	/* loop through namelist & fill in user array */
X	nfound = 0;
X	for (nents = (hd.a_syms & 0xFFFF) / sizeof(struct nlist);
X	     nents > 0; nents--) {
X		if (nsrch == nfound)
X			break;			/* no need to look further */
X		if (fread((char *) &nlent, sizeof(struct nlist), 1, fp) != 1)
X			return fail(fp);	  
X		for (i = 0; i < nsrch; i++)
X			if (nl[i].n_sclass == 0 &&
X			    strncmp(nl[i].n_name, nlent.n_name,
X			    	    sizeof(nlent.n_name)) == 0) {
X				nl[i] = nlent;
X				nfound++;
X				break;
X			}
X	}
X	
X	return nsrch - nfound;
X}
+ END-OF-FILE nlist/nlist.c
chmod 'u=rw,g=r,o=r' \n\l\i\s\t\/\n\l\i\s\t\.\c
set `sum \n\l\i\s\t\/\n\l\i\s\t\.\c`
sum=$1
case $sum in
19931)	:;;
*)	echo 'Bad sum in '\n\l\i\s\t\/\n\l\i\s\t\.\c >&2
esac
echo Extracting \n\l\i\s\t\/\n\l\i\s\t\.\m\a\n\3
sed 's/^X//' > \n\l\i\s\t\/\n\l\i\s\t\.\m\a\n\3 << '+ END-OF-FILE '\n\l\i\s\t\/\n\l\i\s\t\.\m\a\n\3
X#nlist
XNAME
X	  nlist	- get namelist entries
XSYNTAX
X	  #include <a.out.h>
X
X	  int nlist(file, nl)
X	  char *file;
X	  struct nlist nl[];
XDESCRIPTION
X	  Nlist fills fields n_sclass and n_value of array nl with values
X	  found in the non-stripped executable file, whose n_name strings
X	  are identical to those in nl.  Entries in nl that are not found
X	  have their n_value/n_sclass fields set to 0.
X
X	  Nl ends with an entry with a null pointer or empty string n_name.
XSEE ALSO
X	  nm(1)
XDIAGNOSTICS
X	  The return value is -1 on failure, else the number of entries not
X	  found in file.
X
+ END-OF-FILE nlist/nlist.man3
chmod 'u=rw,g=r,o=r' \n\l\i\s\t\/\n\l\i\s\t\.\m\a\n\3
set `sum \n\l\i\s\t\/\n\l\i\s\t\.\m\a\n\3`
sum=$1
case $sum in
59564)	:;;
*)	echo 'Bad sum in '\n\l\i\s\t\/\n\l\i\s\t\.\m\a\n\3 >&2
esac
exit 0

cs00chs@unccvax.UUCP (charles spell) (05/07/90)

Whenever I use the ps(1) cmd, I keep getting the cannot read mm namelist 
error code. Is there a fix to this?

Thanx.

cs00chs@unccvax.UUCP (charles spell) (05/07/90)

In article <2029@unccvax.UUCP>, cs00chs@unccvax.UUCP (charles spell) writes:
> 
> Whenever I use the ps(1) cmd, I keep getting the cannot read mm namelist 
> error code. Is there a fix to this?
> 
> Thanx.


OOPS!!! I asked without thinking. I just found out in ps.c that the executable
must exist in the appropriate dir. It didnt. Now it does. Now it works.

Guess the constant flow of upgrades (no complaints here) has kept me too busy
to look at some of this source.