From russ@mist.cs.orst.edu Tue Feb 23 02:34:00 1988 Date: Mon, 22 Feb 88 22:53:16 PST Russell Ruby - Oregon State University --------------------cut here----------------------------- #! /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: # README # Makefile # team.c # team.man # This archive created: Mon Feb 22 22:37:50 1988 export PATH; PATH=/bin:$PATH echo shar: extracting "'README'" '(1963 characters)' if test -f 'README' then echo shar: will not over-write existing file "'README'" else cat << \SHAR_EOF > 'README' Team was motivated by requests for single user mode privileges for benchmarking purposes. Its predecessor was a shell script from Southern Methodist University. Russell Ruby - russ@cs.orst.edu - February 1988 - Oregon State University --------------- Installation steps: create a group for users of team - include yourself naturally adjust defines in Makefile TEAMGROUP is the group name for team users INIT is the quoted pathname of the "normal" vmtune values for reset LOCK is the quoted pathname of the lockfile RESET is the quoted pathname of the teamreset command "make team" "make install" <- this step has to be done running as root execute command "teamrsinit" <- saves "normal" values of vmtune "make installman" <- install man page head for cover until a policy is established to control abuse remember, civilized programs can be killed just by killing the main team process... if the user's program forks a child which changes its process group... happy hunting. TEAM runs with setuid root so that calls to setpriority and vm_ctl(VM_SETPARAM) can be made along with calls to proc_ctl, vm_ctl(parameters VM_PFFABLE,VM_SWAPABLE) (for these in case the kernel option for non-root access not set). The effective uid is restored to that of the user before the command argument to TEAM is exec'ed. Most privileges are bestowed only on the team process and its children (command and its children), however the system wide vmtune parameters RSexecmult and RSexecdiv are altered during the life span of the TEAM command. A file is used to keep a copy of the "normal" value of the vmtune data structure. This file, created by the command TEAMRSINIT, should be created at a time when the value of vmtune is known to be "normal", (check with /etc/vmtune). At the end of command execution or caught signal the vmtune structure is restored to its normal value. Execution access for TEAM is restricted to a site designated group. SHAR_EOF if test 1963 -ne "`wc -c < 'README'`" then echo shar: error transmitting "'README'" '(should have been 1963 characters)' fi fi # end of overwriting check echo shar: extracting "'Makefile'" '(751 characters)' if test -f 'Makefile' then echo shar: will not over-write existing file "'Makefile'" else cat << \SHAR_EOF > 'Makefile' BINDIR = /usr/local/bin MANDIR = /usr/local/man/man1 L = 1 CFLAGS = -g TEAMGROUP= pps INIT=-DSAVE_VMRS_FILE=\"/usr/local/lib/teamvmtune\" LOCK=-DLOCKFILE=\"/usr/spool/locks/team-lock\" RESET=-DTEAMRESET=\"/usr/local/bin/teamreset\" team: team.c Makefile cc $(CFLAGS) -o team $(INIT) $(LOCK) $(RESET) team.c install: team rm -f $(BINDIR)/team $(BINDIR)/teamrsinit $(BINDIR)/teamreset install -c -m 04710 -o root -g $(TEAMGROUP) team $(BINDIR) ln $(BINDIR)/team $(BINDIR)/teamrsinit ln $(BINDIR)/team $(BINDIR)/teamreset installman: cp team.man $(MANDIR)/team.$(L) chmod 644 $(MANDIR)/team.$(L) shar: Makefile README team.c team.man rm -f team.shar shar -c -v README Makefile team.c team.man > team.shar clean: rm -f *.o core Make.log SHAR_EOF if test 751 -ne "`wc -c < 'Makefile'`" then echo shar: error transmitting "'Makefile'" '(should have been 751 characters)' fi fi # end of overwriting check echo shar: extracting "'team.c'" '(5924 characters)' if test -f 'team.c' then echo shar: will not over-write existing file "'team.c'" else cat << \SHAR_EOF > 'team.c' /* team - run a command with high priority, For benchmarking * teamreset - reset vmtune RS parameters * teamrsinit - store image of "correct" vmtune parameters * * while under effective root uid, privileges are bestowed and taken away, * a lockfile prevents inadvertent multiple executions of team, * vfork and exec have to be done to regain root privilege for teamreset. * Oregon State University - February 1988 - Russell Ruby - russ@cs.orst.edu */ #include #include #include #include #include #include #include #include #include #include static int parentpid,childpid,error_exit(); static struct vm_tune vmtune; main(argc,argv) int argc; char *argv[]; { int lockdes,initdes; int realuid,forkpid; FILE *lockstream,*initptr; int status,i; unsigned long *lptr; char message[120]; realuid = getuid(); parentpid = getpid(); childpid = 0; if ( argc == 1 ){ /* teamreset, teamrsinit or usage statement */ if ( strcmp(argv[0],"teamreset")==0 ){ if ( (lockstream=fopen(LOCKFILE,"r"))!=NULL ){ fprintf(stderr,"\nteam already in use or lockfile is old\n"); fprintf(stderr,"lockfile %s\n", LOCKFILE); fgets(message,110,lockstream); fputs(message,stderr); exit(1);} if ( (initptr=fopen(SAVE_VMRS_FILE,"r")) == NULL){ perror("fopen-teamreset"); exit(1);} fread(&vmtune,sizeof(vmtune),1,initptr); fclose(initptr); if ( vm_ctl(VM_SETPARAM,&vmtune) ){ perror("vm_ctl-teamreset"); exit(1);}} else if ( strcmp(argv[0],"teamresetrs")==0 ){ if ( (initptr=fopen(SAVE_VMRS_FILE,"r")) == NULL){ perror("fopen-teamresetrs"); exit(1);} fread(&vmtune,sizeof(vmtune),1,initptr); fclose(initptr); if ( vm_ctl(VM_SETPARAM,&vmtune) ){ perror("vm_ctl-teamresetrs"); exit(1);}} else if ( strcmp(argv[0],"teamrsinit")==0 ){ if ((initdes=open(SAVE_VMRS_FILE,O_CREAT|O_EXCL|O_WRONLY,0444)) < 0){ fprintf(stderr,"%s already created\n", SAVE_VMRS_FILE); exit(1);} initptr=fdopen(initdes,"w"); if ( vm_ctl(VM_GETPARAM,&vmtune) ){ perror("vm_ctl"); exit(1);} printf("size of vmtune = %d\n", sizeof(vmtune) ); printf("chars written (should be the same) = %d\n", fwrite(&vmtune,sizeof(vmtune),1,initptr) ); lptr = (unsigned long *) &vmtune; for(i=1; i <=16; i++){ printf("%10lu ", *(lptr++)); if ( i%4 == 0 ) printf("\n");} fclose(initptr); } else{ fprintf(stderr,"Usage: team command args ...\n" ); fprintf(stderr,"runs program with exclusive rights to processors\n"); fprintf(stderr,"Degrades system significantly\n");} exit(0);} /* fprintf(stderr,"parent pid=%d\n", parentpid); */ if ( (initptr=fopen(SAVE_VMRS_FILE,"r")) == NULL){ perror("fopen-teamreset"); fprintf(stderr,"must execute teamrsinit once before running team\n"); exit(1);} /* if lockfile exists, quit - team already in use */ if ( (lockdes=open(LOCKFILE, O_CREAT|O_EXCL|O_WRONLY,0664)) < 0){ fprintf(stderr,"\nteam already in use or lockfile is old\n"); fprintf(stderr,"lockfile %s\n", LOCKFILE); if ( (lockstream=fopen(LOCKFILE,"r"))==NULL ) perror("fopen-lockfile"); else{ fgets(message,110,lockstream); fputs(message,stderr);} exit(1); } signal(SIGHUP ,error_exit); signal(SIGINT ,error_exit); signal(SIGQUIT,error_exit); signal(SIGALRM,error_exit); signal(SIGSEGV,error_exit); signal(SIGSYS ,error_exit); signal(SIGTERM,error_exit); lockstream=fdopen(lockdes,"w"); fprintf(lockstream,"Running - %s - by %s\n", argv[1], getpwuid(realuid)->pw_name); fclose(lockstream); chown(LOCKFILE,realuid,-1); /* disable priority ageing */ if ( proc_ctl(PROC_PRIOAGE,0,0) < 0 ){ perror("proc_ctl-age"); exit(1);} /* disable possible decrease of resident set size */ if ( vm_ctl(VM_PFFABLE,0) < 0 ){ perror("vm_ctl-pff"); exit(1);} /* make user's process non-swappable */ if ( vm_ctl(VM_SWAPABLE,0) < 0 ){ perror("vm_ctl-swap"); exit(1);} /* give team's processes top priority */ if ( setpriority(PRIO_PROCESS,parentpid,-20) < 0 ){ perror("setpriority"); exit(1);} if ( vm_ctl(VM_GETPARAM,&vmtune) ){ perror("vm_ctl"); exit(1);} /* make initial resident set size fraction = 1 */ vmtune.vt_RSexecmult = 1; vmtune.vt_RSexecdiv = 1; if ( vm_ctl(VM_SETPARAM,&vmtune) ){ perror("vm_ctl-RSmd"); exit(1);} setuid(realuid); if ( (childpid=vfork()) == 0 ){ execvp(argv[1], &argv[1]); perror(argv[1]); _exit(1);} if ( childpid == -1 ){ perror("team-vfork"); error_exit();} wait(&status); if (status) fprintf(stderr,"user command exit status = %x\n", status); if ( (forkpid=vfork()) == 0 ){ execl(TEAMRESET, "teamresetrs",0); perror("teamresetrs not execld"); _exit(1);} if ( forkpid == -1 ){ perror("resetrs-vfork"); fprintf(stderr,"vm_tune parameters RSmul and RSdiv not reset\n");} wait(0); if ( unlink(LOCKFILE) < 0 ) perror("unlink-lockfile"); } static int error_exit() { int forkpid; /* probably no longer have effective root uid, must fork and */ /* exec to gain effective root uid in order to call vm_ctl */ if ( (forkpid=vfork()) == 0 ){ execl(TEAMRESET, "teamresetrs",0); perror("teamresetrs"); fprintf(stderr,"vm_tune parameters RSmul and RSdiv not reset\n"); _exit(1);} if ( forkpid == -1 ){ perror("resetrs-vfork"); fprintf(stderr,"vm_tune parameters RSmul and RSdiv not reset\n");} wait(0); if ( unlink(LOCKFILE) < 0 ) perror("unlink-lockfile"); if ( childpid > 0 ) /* if child forks a child which changes */ /* its process group, this will miss... happy hunting */ killpg(getpgrp(childpid),SIGKILL); killpg(getpgrp(parentpid),SIGKILL); exit(1); } SHAR_EOF if test 5924 -ne "`wc -c < 'team.c'`" then echo shar: error transmitting "'team.c'" '(should have been 5924 characters)' fi fi # end of overwriting check echo shar: extracting "'team.man'" '(1882 characters)' if test -f 'team.man' then echo shar: will not over-write existing file "'team.man'" else cat << \SHAR_EOF > 'team.man' .TH TEAM 1 .SH NAME team,teamrsinit,teamreset \- usurp resources for benchmarking .SH SYNOPSIS .B team command args \&... .br .B teamrsinit .br .B teamreset .SH DESCRIPTION .I Team is an alternative to running in single user mode to acquire accurate benchmark running times of user programs. Team gives the highest priority to the command and disables swapping, page fault frequency adjustments and process ageing. These changes are local to the command and its children, however the system wide parameters RSexecmult and RSexecdiv are also changed for the life span of the .I team process. These privileges allow a user program to execute with a minimum of system overhead to distort benchmark times. .PP As it is possible for uncivilized programs to seize an excess of system resources, .I Team should only be run with well designed, debugged programs. Some protection is built-in. The user's command is run with the user's uid being the effective uid. Using a lock file, access to .I team is restricted to one user at a time amongst members of a site designated group. .PP In order to abort .I team, send SIGINT or SIGQUIT to the team process. Typically all processes will be killed and the appropriate cleanup will occur. .SH FILES /usr/local/lib/teamvmtune .br /usr/spool/locks/team-lock .SH SEE ALSO vmtune(8),vm_ctl(2),proc_ctl(2),setpriority(2) .SH BUGS Use of SIGKILL to terminate the .I team process will leave children, a lock file, and an incorrect vmtune structure. In this case: remove the lock file, use .I teamreset to correct the vmtune structure; and either wait for the children to die or kill them one by one. Preferably, kill the .I team process with a signal which is caught such as SIGINT or SIGQUIT. This allows appropriate cleanup to take place. In this case all children will be terminated unless a child of the command process changes its process group. SHAR_EOF if test 1882 -ne "`wc -c < 'team.man'`" then echo shar: error transmitting "'team.man'" '(should have been 1882 characters)' fi fi # end of overwriting check # End of shell archive exit 0