ford@kenobi.UUCP (Mike Ditto) (10/26/87)
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@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 # This archive created: Sun Oct 25 18:27:56 1987 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