v13i070: Change process priority on ATT PC

Rich Salz rsalz at bbn.com
Mon Feb 29 04:13:12 AEST 1988


Submitted-by: kenobi!fork (Mike Ditto)
Posting-number: Volume 13, Issue 70
Archive-name: attpc.renice

Here is the 'renice' command, which alters the priority ('nice' value) of
a running process.  The source as written is for the Unix PC, but is fairly
portable (see below).

This program is contributed primarily as an example of the methods used to
write to the kernel's internal tables.  In this case, a field in an element
of the 'proc' array inside the kernel is changed.

Verify that the macros in "Makefile" are correct for you (LBIN, for example
should be where you want the program to be installed), and run 'make' AS ROOT.
It is important to do the make as root so that the resulting program will
have the set-uid bit set, allowing it to read and write the kernel's memory.


Some notes to anyone who wants to port this program to something other
than the Unix PC:

The Unix PC has "tunable kernel parameters", which mean that things that
are constants on most older Unix systems are variable.  This version of
fuser reads the values of these variables from the kernel's memory.  I have
tried to make most of this transparent, for ease of porting to a more plain-
vanilla Unix.  For example, I have an 'int' variable called 'NPROC', which
emulates the #define present in 'standard' Unix.  To make renice run on such
systems, it should be possible to remove this variable and the code that sets
it, and the program will use the #define from <sys/*.h>.  Also get rid of the
<sys/tune.h> include and anything referencing 'tuhi'.


					-=] Ford [=-

"There's enough money here		(In Real Life:  Michael Ditto)
 to buy 5000 cans of Noodle-Roni!"	ford%kenobi at crash.CTS.COM
  -- Zippy the Pinhead			...!crash!kenobi!ford


Here's the shar file:

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	renice.1
#	Makefile
#	renice.c
export PATH; PATH=/bin:$PATH
echo shar: extracting "'renice.1'" '(1222 characters)'
if test -f 'renice.1'
then
	echo shar: will not over-write existing file "'renice.1'"
else
cat << \SHAR_EOF > 'renice.1'
.TH RENICE 1
.SH NAME
renice \- change the priority of a running program
.SH SYNOPSIS
.B renice
[{+-}inc] [=prio] pid ...
.SH DESCRIPTION
.I Renice
modifies the kernel's internal process table to change the 'nice' value
of the listed process IDs.  The priority may be increased,
decreased, or set to an absolute number.
.P
Only the super-user can increase the priority of a process, or change the
priority of another user's process.
.SH OPTIONS
Giving
.B -inc
causes the priority to decrease by `inc'.  Giving
.B +inc
causes the priority to increase by `inc'.  Giving
.B =prio
causes the priority to be set to `prio'.  
.P
The changes to the priority may be re-specified between process IDs.  The
default change is to add 5 to the 'niceness' of the processes (decrease its
priority by 5).
.SH EXAMPLES
$ nroff -man -T37 renice.1 > /tmp/renice.manpage &
.br
[1] 1234
.br
renice 1234
.br
.RS
These commands start a nroff in the background, and then change its priority
so that it will not slow down work done in the foreground.  The same effect
would have resulted from typing 'nice' before the nroff command, but this
example assumes that the user 'forgot' to lower the priority until the
program  was already running.
.RE
SHAR_EOF
if test 1222 -ne "`wc -c < 'renice.1'`"
then
	echo shar: error transmitting "'renice.1'" '(should have been 1222 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'Makefile'" '(171 characters)'
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
SHELL=/bin/sh
INSTALL=ln
LBIN=/usr/lbin
CFLAGS=-O

renice : renice.o
	$(CC) $(CFLAGS) -o renice renice.o
	chmod 4755 renice
	chown root renice
	$(INSTALL) renice $(LBIN)

SHAR_EOF
if test 171 -ne "`wc -c < 'Makefile'`"
then
	echo shar: error transmitting "'Makefile'" '(should have been 171 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'renice.c'" '(4916 characters)'
if test -f 'renice.c'
then
	echo shar: will not over-write existing file "'renice.c'"
else
cat << \SHAR_EOF > 'renice.c'
/************************************************************
 *
 * This program was written by me, Mike "Ford" Ditto, and
 * I hereby release it into the public domain in the interest
 * of promoting the development of free, quality software
 * for the hackers and users of the world.
 *
 * Feel free to use, copy, modify, improve, and redistribute
 * this program, but keep in mind the spirit of this
 * contribution; always provide source, and always allow
 * free redistribution (shareware is fine with me).  If
 * you use a significant part of this code in a program of
 * yours, I would appreciate being given the appropriate
 * amount of credit.
 *				-=] Ford [=-
 *
 ************************************************************/

#include <stdio.h>
#include <fcntl.h>
#include <ctype.h>
#include <errno.h>
#include <pwd.h>
#include <grp.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/tune.h>
#include <sys/proc.h>
#include <nlist.h>


extern long lseek();
extern void perror(), exit();


void kcopy(), kwrite();

char *progname;

#define tuhiaddr (mysyms[0].n_value)
#define procaddr (mysyms[1].n_value)

struct nlist mysyms[] =
{
    { "tuhi", },
    { "proc", },
    { (char *)0, },
};

char buf[BUFSIZ];

int kmem;
int myuid;
int NPROC;
static struct proc proc;


void usage()
{
    fprintf(stderr,
	    "usage:	%s [{+-}inc] [=prio] pid ...\n", progname);
    exit(-1);
}


main(argc, argv)
int argc;
char *argv[];
{
    int status=0;
    int pid, relative, value;

    progname = *argv;

    setup();

    relative = 1;
    value = 5;

    while (++argv,--argc)
	switch (argv[0][0])
	{
	case '-':
	    if (sscanf(argv[0]+1, "%d", &value) != 1)
		usage();
	    relative = 1;
	    break;
	case '+':
	    if (sscanf(argv[0]+1, "%d", &value) != 1)
		usage();
	    value = -value;
	    relative = 1;
	    break;
	case '=':
	    if (sscanf(argv[0]+1, "%d", &value) != 1)
		usage();
	    relative = 0;
	    break;
	default:
	    if (sscanf(argv[0], "%d", &pid) != 1)
		usage();
	    status += renice(pid, value, relative);
	}

    return status;
}


/* one-time setup of main data structures from the kernel */
setup()
{
    struct tunable tune;

    if ( (kmem=open("/dev/kmem", O_RDWR)) < 0 )
    {
	sprintf(buf, "%s: can't open /dev/kmem", progname);
	perror(buf);
	exit(1);
    }

    if (nlist("/unix", mysyms))
    {
	sprintf(buf, "%s: can't nlist /unix", progname);
	perror(buf);
	exit(1);
    }

    myuid = getuid();
    setuid(myuid);

#ifdef DEBUG
    fprintf(stderr, "tuhi:	0x%08lx\n", tuhiaddr);
#endif DEBUG
    kcopy((char *)&tune, tuhiaddr, (long) sizeof tune);

    /* do indirection on the proc address, since it */
    /* is just a pointer in the kernel */
    kcopy((char *)&procaddr, procaddr, (long) sizeof procaddr);

#ifdef DEBUG
    fprintf(stderr, "proc:	0x%08lx\n", procaddr);
#endif DEBUG

    NPROC = tune.nproc;

#ifdef DEBUG
    fprintf(stderr, "NPROC:	%d\n", NPROC);
#endif DEBUG
}


/* copy bytes from kernel address space to this process */
void kcopy(caddr, kaddr, nbytes)
char *caddr;
long kaddr;
long nbytes;
{
    if ( lseek(kmem, kaddr, 0)<0L ||
	read(kmem, caddr, (unsigned)nbytes) != nbytes )
    {
	sprintf(buf, "%s: can't read /dev/kmem", progname);
	perror(buf);
	exit(1);
    }
}


/* write bytes from this process' address space to the kernel's */
void kwrite(kaddr, caddr, nbytes)
long kaddr;
char *caddr;
long nbytes;
{
#ifdef DEBUG
    fprintf(stderr, "Writing %ld bytes to kernel address 0x%08lx\n",
	    nbytes, kaddr);
#endif

    if ( lseek(kmem, kaddr, 0)<0L ||
	write(kmem, caddr, (unsigned)nbytes) != nbytes )
    {
	sprintf(buf, "%s: can't write /dev/kmem", progname);
	perror(buf);
	exit(1);
    }
}


/* change the nice value of process `pid' based on 'value' and 'relative' */
renice(pid, value, relative)
int pid, value, relative;
{
    register i;
    int tmpnice;

    for ( i=0 ; i<NPROC ; ++i )
    {
	kcopy((char *)&proc,
	      (long)&((struct proc *)procaddr)[i],
	      (long)sizeof proc);
	if ( proc.p_pid == pid )
	{
#ifdef DEBUG
	    fprintf(stderr, "Found it!  proc[%d], p_uid is %d\n",
		   i, proc.p_uid);

	    fprintf(stderr, "Old p_nice was %d\n", proc.p_nice);
#endif DEBUG

	    tmpnice = proc.p_nice;

	    if (relative)
		tmpnice += value;
	    else
		tmpnice = value;

	    if (tmpnice >= 40)
		tmpnice = 40;
	    if (tmpnice < 0)
		tmpnice = 0;

#ifdef DEBUG
	    fprintf(stderr, "New p_nice is %d\n", tmpnice);
#endif DEBUG

	    if ( myuid && (myuid != proc.p_uid || tmpnice<proc.p_nice) )
	    {
		errno = EACCES;
		sprintf(buf, "%s: can't renice process %d", progname, pid);
		perror(buf);
		return 1;
	    }

	    proc.p_nice = tmpnice;

	    kwrite((long)&((struct proc *)procaddr)[i]
		   + ( ((char *)&proc.p_nice) - (char *)&proc ),
		   (char *)&proc.p_nice,
		   (long)sizeof proc.p_nice);
	    return 0;
	}
    }

    fprintf(stderr, "%s: process %d not found.\n", progname, pid);

    return 1;
}
SHAR_EOF
if test 4916 -ne "`wc -c < 'renice.c'`"
then
	echo shar: error transmitting "'renice.c'" '(should have been 4916 characters)'
fi
fi # end of overwriting check
#	End of shell archive
exit 0

-- 
For comp.sources.unix stuff, mail to rsalz at uunet.uu.net.



More information about the Comp.sources.unix mailing list