From: coolidge@cs.uiuc.edu (John Coolidge)
Subject: Re: accessing system proc struct
Summary: Fun with /dev/kmem
Reply-To: coolidge@cs.uiuc.edu
Organization: University of Illinois, Dept. of Comp. Sci., Urbana, IL
Date: Fri, 10 Apr 1992 06:35:11 GMT

palermo@woody.Jpl.Nasa.Gov (Bob Palermo) writes:
>I need to know how to access the system process structures from C
>under A/UX.

>This is trivial under SunOS, they provide kvm_open, kvm_getproc, 
>kvm_nextproc,...
>These routines apparently do not exist under A/UX.

This is true. I now know enough to be able to write them (and I might
sometime if a nice block of time presents itself :-)). I've written a
simple program which stomps through the process table and the u areas
and prints out ps-like information. It needs to be run as root or bin
or setgid to the /dev/kmem group (so that it can open /dev/kmem). I
assume programs using kvm_* have the same restriction.

kvm_* seems to be a SunOS/4.4BSD-ism. The 4.3BSD (well, UMAX 4.3, which
is a pretty bletcherous 4.3BSD port) and Ultrix 4.2 do not seem to have
it.

There are two programs in the shar archive attached to this post. The
first, proctest.c, is my simple mini-ps program. It fetches the number
of processes available on the machine, finds the address of proc in
/dev/kmem, and then runs through proc looking at processes and printing
out info. To find the arguments, it looks up the u area and prints out
the psargs variable.

The second program, renice.c, provides a simple BSD-ish renice command
(with no bells or whistles). You can 'renice [priority] [pid]', where
priority is the new priority (not an offset) and pid is the process
whose priority is to be changed. Note that A/UX does not use BSD-style
priorities (-20 to 20); it uses 0 to 39 instead. NOTE: this program
does no authentication, and must be run as root or bin or setgid to sys
(/dev/kmem's group). It's not suitable for general use without doing
some checking to make sure users are only increasing their priority. I
wrote it as proof-of-concept that such a thing could be done under A/UX.

Enjoy,
--John

        It's so fast, it can do an infinite loop in 30 seconds.
                -- Brian Bechtel, when the Mac IIfx came out

+++John L. Coolidge++til May:coolidge@cs.uiuc.edu++May:coolidge@apple.com++
I speak for myself, not the UofI or Apple. Copyright 1992 John L. Coolidge.
Copying allowed only if attributed and if all copies may be further copied.

#! /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 shell archive."
# Contents:  proctest.c renice.c
# Wrapped by coolidge@barnabas.cs.uiuc.edu on Fri Apr 10 01:11:49 1992
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'proctest.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'proctest.c'\"
else
echo shar: Extracting \"'proctest.c'\" \(1756 characters\)
sed "s/^X//" >'proctest.c' <<'END_OF_FILE'
X#include <stdio.h>
X#include <fcntl.h>
X#include <nlist.h>
X#include <sys/proc.h>
X#include <sys/user.h>
X#include <sys/var.h>
X
Xstruct nlist Nl[] = {
X  { "proc" },
X  0
X};
X
Xmain()
X{
X    long i;
X    int proc_fd, u_fd; /* Use two copies of /dev/kmem for convenience */
X    int count;
X    struct proc curproc;
X    struct user curuser;
X
X    struct var sys_vars;
X    int nproc;
X
X    /* How many processes do we have max? */
X    i = uvar(&sys_vars);
X    if( i < 0 ) perror("uvar");
X    nproc = sys_vars.v_proc;
X    printf("This machine supports %d procs\n", nproc);
X    
X    i = nlist("/unix", Nl);
X    if (i < 0) perror("nlist");
X
X    proc_fd = open("/dev/kmem", O_RDONLY);
X    if( proc_fd < 0 ) perror("proc_fd");
X    u_fd = open("/dev/kmem", O_RDONLY);
X    if( proc_fd < 0 ) perror("u_fd");
X
X    count =lseek(proc_fd, Nl[0].n_value, 0);
X    if( count != Nl[0].n_value ) perror("seek to proc");
X    count = read(proc_fd, &i, sizeof(long));
X    if( count != sizeof(long) ) perror("read proc addr");
X    count =lseek(proc_fd, i, 0);
X    if( count != i ) perror("seek to proc array");
X
X    for(i=0; i < nproc; i++)
X    {
X        count = read(proc_fd, &curproc, sizeof(curproc));
X        if( count != sizeof(curproc) ) perror("reading proc");
X
X	if(curproc.p_stat != 0)
X	{
X	    printf("Pid %d: ruid %d euid %d ppid %d nice %d flag %x stat %x\n",
X	    	curproc.p_pid, curproc.p_uid, curproc.p_suid,
X	    	curproc.p_ppid, curproc.p_nice,  curproc.p_flag,
X		curproc.p_stat);
X	    count = lseek(u_fd, curproc.p_addr, 0);
X	    if( count != curproc.p_addr ) perror("seek to u area");
X            count = read(u_fd, &curuser, sizeof(curuser));
X	    if( count != sizeof(curuser) ) perror("read u area");
X            printf("User args %s\n", curuser.u_psargs);
X        }
X    }
X}
X
END_OF_FILE
if test 1756 -ne `wc -c <'proctest.c'`; then
    echo shar: \"'proctest.c'\" unpacked with wrong size!
fi
# end of 'proctest.c'
fi
if test -f 'renice.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'renice.c'\"
else
echo shar: Extracting \"'renice.c'\" \(1508 characters\)
sed "s/^X//" >'renice.c' <<'END_OF_FILE'
X#include <stdio.h>
X#include <fcntl.h>
X#include <nlist.h>
X#include <sys/proc.h>
X#include <sys/user.h>
X#include <sys/var.h>
X#include <stddef.h>
X
Xstruct nlist Nl[] = {
X  { "proc" },
X  0
X};
X
Xmain(int argc, char** argv)
X{
X    long i;
X    int proc_fd;
X    int count;
X    struct proc curproc;
X    int target, newprio;
X    
X    struct var sys_vars;
X    int nproc;
X
X    if( argc != 3 )
X    {
X    	printf("usage: renice [priority] [pid]\n");
X    	exit(1);
X    }
X
X    target = atoi(argv[2]);
X    newprio = atoi(argv[1]);
X
X    if(target < 0) exit(0);
X    
X    /* How many processes do we have max? */
X    i = uvar(&sys_vars);
X    if( i < 0 ) perror("uvar");
X    nproc = sys_vars.v_proc;
X    
X    i = nlist("/unix", Nl);
X    if (i < 0) perror("nlist");
X
X    proc_fd = open("/dev/kmem", O_RDWR);
X    if( proc_fd < 0 ) perror("proc_fd");
X
X    count =lseek(proc_fd, Nl[0].n_value, 0);
X    if( count != Nl[0].n_value ) perror("seek to proc");
X    count = read(proc_fd, &i, sizeof(long));
X    if( count != sizeof(long) ) perror("read proc addr");
X    count =lseek(proc_fd, i, 0);
X    if( count != i ) perror("seek to proc array");
X
X    for(i=0; i < nproc; i++)
X    {
X        count = read(proc_fd, &curproc, sizeof(curproc));
X        if( count != sizeof(curproc) ) perror("reading proc");
X	
X        if(curproc.p_pid == target)
X        {
X	    curproc.p_nice = newprio;
X	    lseek(proc_fd, (-1*sizeof(curproc))+offsetof(proc_t, p_nice), 1);
X            write(proc_fd, &curproc.p_nice, sizeof(curproc.p_nice));
X        }
X    }
X}
X
END_OF_FILE
if test 1508 -ne `wc -c <'renice.c'`; then
    echo shar: \"'renice.c'\" unpacked with wrong size!
fi
# end of 'renice.c'
fi
echo shar: End of shell archive.
exit 0