[comp.unix.questions] Access to user process info.

dusan@osupyr.UUCP (Dusan Nedeljkovic) (12/18/86)

Briefly:  I need to get access to information about a certain (or
	  more generally, ALL) processes that are active and bound
	  to a terminal.  
	  (I also have read access to all pertinent files.)


Machine:  Pyramid 90x running BSD Unix 4.2

	  I've sent news out about this, and have gotten conflicting
	  suggestions...some people say to access <sys/user.h> in
	  /dev/kmem and /vmunix -- but I've had no success with this;
	  still others say that I am on the wrong track, because this
	  information varies across machines so that it can't be done
	  using the structures in <sys/user.h>.

	  I guess, what I'm really asking is how the unix utility "w"
	  gets its information from the system about active processes.

	  To refresh your memory, I've included some sample "w" output:

	User     tty       login@  idle   JCPU   PCPU  what
	dusan    ttyi02    7:24pm         1:06     28  w
	alden    ttyi03    5:29pm     2   7:03     22  emacs /etc/termcap
	gae      ttyi17    7:45pm            8      8  rn


	  How does "w" get all this useful info?  I can't imagine that
	  it doesn't use <sys/user.h>, etc.  

	  Any info would be GREATLY appreciated.  Thanks in advance.


Dusan.	(Ohio State Univ. -- Math/Sciences Computer Lab)
	(             Columbus, OH  43210	       )
	*	dusan%osupyr.uucp@osu-eddie.uucp       *
	*	       cbatt!osupyr!dusan	       *
-- 

Dusan.	(Ohio State Univ. -- Math/Sciences Computer Lab)
	(             Columbus, OH  43210	       )
	*	dusan%osupyr.uucp@osu-eddie.uucp       *
	*	       cbatt!osupyr!dusan	       *

mouse@mcgill-vision.UUCP (der Mouse) (12/21/86)

In article <99@osupyr.UUCP>, dusan@osupyr.UUCP (Dusan Nedeljkovic) writes:
> Briefly:  I need to get access to information about a certain (or
> more generally, ALL) processes that are active and bound to a
> terminal.

I would recommend creating a pipe and forking ps.

> I guess, what I'm really asking is how the unix utility "w" gets its
> information from the system about active processes.

You mention that some people say to use <sys/user.h> and /vmunix and
/dev/kmem, others say that you can't because it varies across machines
and <sys/user.h> doesn't have enough info.  Both are right.  This is
normally done in a machine- and system-specific manner using include
files such as <sys/user.h> and <sys/proc.h> (and others, depending on
the system).

> 	  To refresh your memory, I've included some sample "w" output:
> 	User     tty       login@  idle   JCPU   PCPU  what
> 	dusan    ttyi02    7:24pm         1:06     28  w
> 	alden    ttyi03    5:29pm     2   7:03     22  emacs /etc/termcap
> 	gae      ttyi17    7:45pm            8      8  rn
> 	  How does "w" get all this useful info?  I can't imagine that
> 	  it doesn't use <sys/user.h>, etc.

I can't speak for a Pyramid, but on a 4/[23] VAX, it gets

User, tty, and login@ from /etc/utmp
Idle time by groveling through the tty driver structures via /dev/kmem
 and the appropriate include files (I think)
JCPU and PCPU from the user and proc structs - <sys/user.h> and
 <sys/proc.h>
what from the process' argv[] vector - it's stored in the process'
 address space, which w knows how to fetch from /dev/mem or /dev/drum
 as necessary (more include files)

Really, forking ps is most likely the simplest, easiest, least buggy
solution (if your ps can be made to produce the information you want).

					der Mouse

USA: {ihnp4,decvax,akgua,utzoo,etc}!utcsri!mcgill-vision!mouse
     think!mosart!mcgill-vision!mouse
Europe: mcvax!decvax!utcsri!mcgill-vision!mouse
ARPAnet: think!mosart!mcgill-vision!mouse@harvard.harvard.edu

michael@orcisi.UUCP (12/22/86)

> In article <99@osupyr.UUCP>, dusan@osupyr.UUCP (Dusan Nedeljkovic) writes:
> > Briefly:  I need to get access to information about a certain (or
> > more generally, ALL) processes that are active and bound to a
> > terminal.

There was a public-domain version of a ps-like program called
"sps" that was posted some time ago.  It might give you some
pointers (no pun intended).

jsdy@hadron.UUCP (Joseph S. D. Yao) (01/04/87)

I can't give you off the top of my head any tricks to make sure
that all the data you get is consistent.  However,

First you read the elements of the proc table.  There are NPROC
of them: this is found in int nproc in /vmunix or /dev/kmem.  The
proc structures tell where in memory or page space one can find
the user memory, including the _u structure; and the _u structure
tells which tty the process is attached to.  You get the addresses
out of /vmunix using nlist(), and then read them from /dev/kmem.
Or from /dev/proc, if you are lucky enough to have it ...
-- 

	Joe Yao		hadron!jsdy@seismo.{CSS.GOV,ARPA,UUCP}
			jsdy@hadron.COM (not yet domainised)

joe@auspyr.UUCP (Joe Angelo) (01/05/87)

Looking up the process and user tables can be rots of fun.
Course, it's different on EVERY version of UNIX and the likes.
Ucb source programs w.c and ps.c are alot of help, but I don't 
think anyone is likely to post them ... I've enclosed a small
program to read the proc table and the user table -- programs
works on an NEC MS190 running SYSIII Unix and I assure you
it will not work on any other computer ... (That's why I didn't
post it in net.sources) ... But perhaps you can get an idea or
two from the program.

I'm working on a version of "ps with specified options (pss)",
a version of ps where the arguments specify the data fields you
want printed ... eg: pss '-UpPNC' will print only USERNAME,
PROCID, PPROCID, NAME_IN_USER_TABEL, and CPU time ... I'm trying
to make the program work on ALL version of UNIX/xenix. In about
20 years I'll post it ...

Anyways, hope this helps,

--- sloppy code follows, cut here and burn below portion of crt --

/*
** psmask.c -- print process table and process masks
**
** portion of this code MAY look like ucb/att code,
** since i've read it all a million times, there is a MINOR
** chance that my subconsience mind has been warped ...
**
*/
char	*DOIT();
#include <stdio.h>
#include <a.out.h>
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/dir.h>
#include <sys/user.h>
#include <sys/var.h>
#include <ctype.h>
#include <utmp.h>
#include <time.h>
#include <sys/stat.h>

/*
** assign tty major/minor numbers to a name, 
** forget looking them up in /dev, takes too long ...
*/

struct	{
	int	maj;
	int	min;
	char	*name;
}	TTY[] = {
	0,0,"co", 0,1,"01", 0,2,"02", 0,3,"03", 5,0,"h0",
	5,1,"h1", 5,2,"h2", 5,3,"h3", 5,4,"h4", 5,5,"h5",
	5,6,"h6", 5,7,"h7", 5,8,"h8", 5,9,"h9", 5,10,"ha",
	5,11,"hb", 5,12,"hc", 5,13,"hd", 5,14,"he", 5,15,"hf",
	5,16,"hg", 5,17,"hh", 5,18,"hi", 5,19,"hj", 5,20,"hk",
	5,21,"hl", 5,22,"hm", 5,23,"hn", 5,24,"ho", 5,25,"hp",
	5,26,"hq", 5,27,"hr", 5,28,"hs", 5,29,"ht", 5,30,"hu",
	5,31,"hv", 99,99,"nothing"
};

/*
** user table 
*/
struct	user	u;
/*
** process table
*/
struct	proc	p;
/*
** tuneable varaible table
*/
struct	var	v;
/*
** what symbols too look for in kernel a.out file
*/
struct	nlist	nl[  ] = {
	{ "_v" },
	{ "_proc" },
	{ "_swplo" }
};

#define	N_VARS		0
#define	N_PROC		1
#define	N_SWAPLO	2
int	file;

main()
{
	int	mem, swap, kmem, j, dead, alive, onswap, k, mn, mj;
	char	tty[4];
	long	addr;
	daddr_t	swplo;
	char	comm[50];
	char	ar[300];

	/*
	** get real addresses of kernel symbols
	*/
	nlist("/unix",nl);
	/*
	** open all things large and small
	*/
	if( (swap=open("/dev/swap",0)) == -1) {
		printf("No swap.\n"); 
		exit(-1);
	}
	if( (kmem=open("/dev/mem",0)) == -1) {
		printf("No kmem.\n"); 
		exit(-1);
	}
	if( (mem=open("/dev/mem",0)) == -1) {
		printf("No mem.\n"); 
		exit(-1);
	}

	/*
	** seek to and read var table
	*/
	lseek(kmem,(long)nl[ N_VARS ].n_value<<1,0);
	read(kmem,(char *)&v,sizeof(v));

	/* find base of swap */
	lseek(kmem,(long)nl[ N_SWAPLO ].n_value<<1,0);
	read(kmem,(char *)&swplo,sizeof(swplo));

	/* position to start of process table */
	lseek(kmem,(long)nl[ N_PROC ].n_value<<1,0);

	printf("    PID  PPID UID  GID TT MSK LIMIT  COMMAND\n");

	/* loop through process table */
	for(j=0; j< v.v_proc;++j) {

		/* read process entry */
		read(kmem,(char *)&p,sizeof(p));
		if( p.p_flag & SLOAD == 0) {
			/* information is out on swap */
			addr = ctow(p.p_addr + swplo);
			file = swap;
			onswap = 1;
		} else {
			addr = ctow((long) p.p_addr);
			file = mem;
			onswap = 0;
		}

		/* locate and read user entry */
		lseek(file,(long)addr<<1,0);
		read(file,(char *)&u,sizeof(u));

		/* interesting process ? */
		if( p.p_pid == 0) 
			++dead;
		else {
			++alive;

			/* get command name */
			strncpy(comm,u.u_comm,14);
			comm[14] = '\0';

			/* get args */
			addr += ctow( (long)u.u_dsize) + ctow((long)USIZE);
			lseek(file,addr<<1,0);
			strcpy(ar,DOIT(&comm));
			ar[41] = '\0';

			/* compare devive number of tty to tty table */
			mn = minor(u.u_ttyd);
			mj = major(u.u_ttyd);
			strcpy(tty,"??");
			for( k = 0; k <= 35; ++k) {
				if((TTY[k].min == mn) && (TTY[k].maj == mj)) {
					strcpy(tty,TTY[k].name);
					break;
				}
			}
			
			if( onswap) 
				putchar('s');
			else
				putchar(' ');
			putchar(' ');
			printf("%5d %5d %3d %4d %2s %03o %5ld  %s\n",
				p.p_pid, p.p_ppid, p.p_uid, u.u_gid, tty,
				u.u_cmask,u.u_limit, ar);
		}
	}
}
char *DOIT(was)
char	*was;
{
	int	nbad, c;
	char	*cp1, *cp2, *cp;
	char	**abuf[BSIZE/sizeof(char **)];

	if( read(file,(char *)abuf,sizeof(abuf)) != sizeof(abuf))
		return(was);
	cp = (char *) ((char *)abuf + 10);	
	nbad = 0;
	for(cp1=cp2=cp ; cp1 < (char *)(&abuf[BSIZE/sizeof(char **)])  ; cp1++) {
		c = *cp1 & 0177;
		if (c == 0) {
			*cp1 = ' ';
			cp2 = cp1 ;
		}
		else if ( c < ' ' || c > '~') {
			if (++nbad >=3) {
				*cp1-- = ' ';
				break ;
			}
			*cp1 = '?' ;
		}
		if (c == '=') {
			*cp2 = 0;
			break ;
		}
	}
	if ( nbad >= 3 || *cp == '\0' || cp1 >= (char *)(&abuf[BSIZE/sizeof(char **)]))
		return(was);
	return(cp);
}
-- 
"No matter      Joe Angelo, Sr. Sys. Engineer @ Austec, Inc. [408] 279-5533
where you go,   ^^ A True Klingon <TK0> ^^
there you       {styx,necntc,sdencore,dlb,cbosgd,amdahl,ptsfa,dana}!aussjo!joe
are ..."        {styx,necntc,sdencore,dlb,imagen,gould}!auspyr!joe

dennis@rlgvax.UUCP (Dennis Bednar) (01/15/87)

In article <587@mcgill-vision.UUCP>, mouse@mcgill-vision.UUCP (der Mouse) writes:
> In article <99@osupyr.UUCP>, dusan@osupyr.UUCP (Dusan Nedeljkovic) writes:
> > Briefly:  I need to get access to information about a certain (or
> > more generally, ALL) processes that are active and bound to a
> > terminal.

If you have the fuser(1M) command, it will do what you need.
It works nicely.  Given the output of fuser (the numerical process
ids), you can get more information by running:
	ps -p25645
assuming the output of of fuser had been 25646.
-- 
-Dennis Bednar
{decvax,ihnp4,harpo,allegra}!seismo!rlgvax!dennis	UUCP