Path: seismo!harvard!husc6!talcott!panda!sources-request From: sources-request@panda.UUCP Newsgroups: mod.sources Subject: GR - A Game Regulator Message-ID: <1849@panda.UUCP> Date: 11 May 86 13:43:33 GMT Sender: jpn@panda.UUCP Reply-To: mcooper@usc-oberon.arpa Lines: 668 Approved: jpn@panda.UUCP Mod.sources: Volume 4, Issue 113 Submitted by: talcott!usc-oberon.ARPA:mcooper #!/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 # gr.control # gr.c # gr.h # logfile.c # This archive created: Mon May 5 13:14:10 1986 # By: Michael A. Cooper (USC Computing Services, Los Angeles) export PATH; PATH=/bin:$PATH echo shar: extracting "'README'" '(1915 characters)' if test -f 'README' then echo shar: over-writing existing file "'README'" fi cat << \SHAR_EOF > 'README' G R - A G A M E R E G U L A T O R Revision 1.16 GR is used to regulate game playing. It checks various system facts such as the number of logged in users, and the system load average against a central control file to determine whether it is okay to play a requested game. It also lets you select a priority (see setpriority(2)) at which the game will run. See the (enclosed) manual for more details. GR was formerly called "gsh" from which the base code was written at Reed College by a person who wishes to remain anonymous. I "adopted" it and have extensively modified the code. We are currently running GR on 4 of our VAX 750's running 4.2BSD. I suspect that the code should run without problems under 4.3BSD. As for System V, I'm sure some minimal modifications will have to be made, but as yet, I have not tried porting it. To install GR, edit gr.h and Makefile to tailor to your system. The comments supplied therein, should suffice. Then run "make gr" to compile GR. You should have no errors. Now edit the "gr.control" file to set your local system parameters. Next run "make create" to create the appropriate directory and support files. Run "make dolink" if you wish to have most of the standard 4.2 games put under the regulator; otherwise, you can link them by hand. I'd appreciate any bugs/comments you wish to pass along. Mike Cooper +-----------------------------------------------------------------------------+ | Michael Cooper UUCP: ...!{uscvax, sdcrdcf, scgvaxd, | | University Computing Services engvax, smeagol}!usc-oberon!mcooper | | University of Southern Cal. BITNET: mcooper@uscvaxq, mcooper@jaxom | | Los Angeles, Ca. 90089-0251 ARPA: mcooper@usc-oberon.arpa, | | (213) 743-3462 mcooper@usc-eclc.arpa | +-----------------------------------------------------------------------------+ SHAR_EOF echo shar: extracting "'Makefile'" '(1506 characters)' if test -f 'Makefile' then echo shar: over-writing existing file "'Makefile'" fi cat << \SHAR_EOF > 'Makefile' # # Makefile for Game Regulator. # # $Header: Makefile,v 1.1 86/05/05 13:13:34 mcooper Exp $ # # # GAMEDIR - This is where the symbolic links are to be placed. # Should be /usr/games. # GAMEDIR = /usr/games # # HIDEDIR - Name of directory to hide the actual executables # HIDEDIR = $(GAMEDIR)/.hide # # GROUP - This group has read/execute permissions on HIDEDIR and owns # the Game Regulator which is setgid to GROUP. # GROUP = play # # NAME - Name of Game Regulator in GAMEDIR. I have it set to ".gr" # so it doesn't show up with ls(1) by default. # NAME = .gr # # GAMES - The games in the original GAMEDIR to be put under regulation. # GAMES = adventure backgammon btlgammon canfield chess cribbage fish\ hangman mille monop rain rogue sail snake teachgammon trek \ worm worms wump zork OBJS = gr.o logfile.o gr: $(OBJS) cc -s $(OBJS) -o gr dbx: $(OBJS) cc -g $(OBJS) -o gr -llocal .c.o: cc -c $*.c $(OBJS): gr.h install: gr install -m 2751 -g $(GROUP) gr $(GAMEDIR)/$(NAME) create: -mkdir $(HIDEDIR) chgrp $(GROUP) $(HIDEDIR) chmod 770 $(HIDEDIR) cp gr.control $(GAMEDIR)/lib touch $(GAMEDIR)/lib/gr.log chgrp $(GROUP) $(GAMEDIR)/lib/gr.control $(GAMEDIR)/lib/gr.log chmod 664 $(GAMEDIR)/lib/gr.control $(GAMEDIR)/lib/gr.log dolink: dolink.sh sed s#HIDEDIR#$(HIDEDIR)# dolink.sh |\ sed s#GAMEDIR#$(GAMEDIR)# |\ sed s#NAME#$(NAME)# > dolink chmod +x dolink dolink $(GAMES) clean: rm -f *.o log dolink shar: shar README Makefile gr.control *.[ch] > shar.out SHAR_EOF echo shar: extracting "'gr.control'" '(582 characters)' if test -f 'gr.control' then echo shar: over-writing existing file "'gr.control'" fi cat << \SHAR_EOF > 'gr.control' # # Game Regulator Control File # # Note - The last line contains the default parameters for any file NOT listed. # # Name - Name of game in /usr/games. (string) # Load - Maximum load average. (floating point) # Users - Maximum number of users. (integer) # Priority - Priority game will run at. # See setpriority(2). (integer) # # Maximum # Name Load Users Priority #-------------------------------------- rogue 4.0 8 0 arogue 4.0 8 0 srogue 4.0 8 0 urogue 4.0 8 0 ourogue 4.0 8 0 hack 4.0 8 5 sail 4.0 8 0 empire 4.0 8 0 default 5.0 8 0 SHAR_EOF echo shar: extracting "'gr.c'" '(5975 characters)' if test -f 'gr.c' then echo shar: over-writing existing file "'gr.c'" fi cat << \SHAR_EOF > 'gr.c' #ifndef lint static char *RCSid = "$Header: gr.c,v 1.16 86/04/26 17:30:53 mcooper Exp $"; #endif /* *------------------------------------------------------------------ * * $Source: /usr/src/local/gr/RCS/gr.c,v $ * $Revision: 1.16 $ * $Date: 86/04/26 17:30:53 $ * $State: Exp $ * $Author: mcooper $ * $Locker: mcooper $ * *------------------------------------------------------------------ * * Michael Cooper (mcooper@usc-oberon.arpa) * University Computing Services, * University of Southern California, * Los Angeles, California, 90089-0251 * (213) 743-3469 * *------------------------------------------------------------------ * $Log: gr.c,v $ * Revision 1.16 86/04/26 17:30:53 mcooper * This version adds a new field to the gr.control * file that specifies the priority that the game will * run at. * * Revision 1.15 86/03/25 18:50:08 mcooper * Added #ifdef LOGFILE. * * Revision 1.14 86/03/25 15:48:49 mcooper * New headers. * *------------------------------------------------------------------ */ #include #include #include #include #include #include #include #include #include #include "gr.h" static int ufd = 0; static int max_users; static int priority = 0; static lfd = 0; static double avenrun[3]; static double max_load; static struct utmp buf; static struct nlist nl[] = { { "_avenrun" }, { "" }, }; int was_tod; int was_load; int was_users; char *rindex(); long time(); main(argc, argv) int argc; char **argv; { char *game = rindex(argv[0], '/'); if (game == 0) game = argv[0]; else game++; /* Skip the '/' */ setup(game); if(checkfor(NOGAMING)) exit(2); if (tod() || users() || load()) { fprintf(stderr, "Sorry, no games now.\n"); if (was_load) fprintf(stderr, "The system load is greater than %.2lf.\n", max_load); if (was_users) fprintf(stderr, "There are more than %d users logged in.\n", max_users); if (was_tod) fprintf(stderr, "Game playing is not permitted between %d00 and %d00 hours on weekdays.\n", MORNING, EVENING); exit(1); } #ifdef LOGFILE logfile(game); #endif play(game, argv); } play(game, args) char *game; char **args; { int pid; char tmp[128]; switch (pid = fork()) { case -1: fprintf(stderr, "Cannot fork.\n"); exit(1); case 0: strcpy(tmp, HIDEDIR); strcat(tmp, "/"); strcat(tmp, game); signal(SIGINT, SIG_DFL); signal(SIGQUIT, SIG_DFL); signal(SIGTSTP, SIG_DFL); setuid(getuid()); if(setpriority(PRIO_PROCESS, 0, priority) < 0) { perror("setpriority"); exit(1); } execv(tmp, args); perror(tmp); exit(1); } for (;;) { sleep(60); if (load() || users() || tod()) { warn(0); sleep(60); if (reprieve()) continue; sleep(60); if (reprieve()) continue; warn(1); sleep(60); if (reprieve()) continue; warn(2); sleep(60); if (reprieve()) continue; blast(pid); } } } reprieve() { static char mess[] = "\rYou have a reprieve. Continue playing.\r\n"; if (load() || users() || tod()) return (0); write(2, mess, sizeof(mess)); return (1); } warn(which) int which; { static char buff[512]; static char *mesg = "to save your game. If you do not leave\r\n\ the game within this period, your game will be terminated.\r\n"; static char *t[3] = { "4 minutes ", "2 minutes ", "1 minute " }; if (was_load) sprintf(buff, "\rThe system load is greater than %.2lf.\r\n", max_load); if (was_users) sprintf(buff, "\rThere are more than %d users logged in.\r\n", max_users); if (was_tod) sprintf(buff, "\rGame time is over.\r\n"); strcat(buff, "You have "); strcat(buff, t[which]); strcat(buff, mesg); write(2, buff, strlen(buff)); } blast(pid) int pid; { static char mess[] = "\rYour game is forfeit.\r\n"; write(2, mess, sizeof(mess)); kill(pid, SIGHUP); sleep(60); kill(pid, SIGKILL); } death(n) int n; { union wait status; if (wait3(&status, WNOHANG | WUNTRACED, (char *)0) == 0) { return; } if (status.w_stopval == WSTOPPED) { signal(SIGTSTP, SIG_DFL); kill(getpid(), SIGTSTP); signal(SIGTSTP, SIG_IGN); return; } else exit(0); } setup(game) char *game; { char tmp[16]; char lbuf[BUFSIZ]; int n; FILE *list; if ((ufd = open("/etc/utmp", 0)) < 0) { perror("/etc/utmp"); exit(1); } if ((lfd = open("/dev/kmem", 0)) < 0) { perror("/dev/kmem"); exit(1); } nlist("/vmunix", nl); if (nl[0].n_type == 0) { perror("/vmunix"); exit(1); } if ((list = fopen(CONTROL, "r")) == NULL) { perror(CONTROL); exit(1); } while (fgets(lbuf, sizeof(lbuf), list)) { if(lbuf[0] == COMMENT) continue; sscanf(lbuf, "%s%lf%d%d", tmp, &max_load, &max_users, &priority); if (strcmp(tmp, game) == 0) break; } fclose(list); signal(SIGCHLD, death); signal(SIGINT, SIG_IGN); signal(SIGQUIT, SIG_IGN); signal(SIGTSTP, SIG_IGN); } load() { lseek(lfd, (long)nl[0].n_value, 0); read(lfd, avenrun, sizeof(avenrun)); return (was_load = (avenrun[1] >= max_load)); } users() { char tmp[32]; int count = 0; long l = time((long *)0); struct stat sbuf; lseek(ufd, (long)0, 0); while (read(ufd, &buf, sizeof(buf)) > 0) { if (buf.ut_name[0] != '\0') { count++; } } return (was_users = (count > max_users)); } tod() { #ifdef TOD long now; struct tm *localtime(); struct tm *ntime; time(&now); ntime = localtime(&now); if(ntime->tm_wday == 0 || ntime->tm_wday == 6) return(was_tod = FALSE);/* OK on Sat & Sun */ if(ntime->tm_hour < MORNING || ntime->tm_hour >= EVENING) return(was_tod = FALSE);/* OK during non working hours */ return(was_tod = TRUE); #endif } checkfor(file) char *file; { char buf[200]; FILE *fd, *fopen(); if((fd = fopen(file, "r")) != NULL) { fprintf(stderr, "Sorry, no games now...\n"); while(fgets(buf, sizeof(buf), fd)) fprintf(stderr, buf); fclose(fd); return(TRUE); } return(FALSE); } SHAR_EOF echo shar: extracting "'gr.h'" '(1771 characters)' if test -f 'gr.h' then echo shar: over-writing existing file "'gr.h'" fi cat << \SHAR_EOF > 'gr.h' /* * $Header: gr.h,v 1.3 86/03/25 15:50:31 mcooper Exp $ *------------------------------------------------------------------ * * $Source: /usr/src/local/gr/RCS/gr.h,v $ * $Revision: 1.3 $ * $Date: 86/03/25 15:50:31 $ * $State: Exp $ * $Author: mcooper $ * $Locker: mcooper $ * *------------------------------------------------------------------ * * Michael Cooper (mcooper@usc-oberon.arpa) * University Computing Services, * University of Southern California, * Los Angeles, California, 90089-0251 * (213) 743-3469 * *------------------------------------------------------------------ * $Log: gr.h,v $ * Revision 1.3 86/03/25 15:50:31 mcooper * Moved CONTROL back to normal place in /usr/games/lib. * * Revision 1.2 86/03/25 15:47:57 mcooper * Lines beginning with '#' are comment lines. * * Revision 1.1 86/02/12 17:49:54 mcooper * Initial revision * *------------------------------------------------------------------ */ /* * TOD - define if you wish to restrict game playing during a certain * time of day on weekdays. Use MORNING and EVENING as the time * period. */ /* #define TOD */ #define MORNING 8 /* stop playing games */ #define EVENING 17 /* game time starts */ /* * HIDEDIR - directory where the actual games are kept. */ #define HIDEDIR "/usr/games/.hide" /* * NOGAMING - If this file exists, it's contents are printed out and * gaming is not permitted. */ #define NOGAMING "/usr/games/nogames" /* * LOGFILE - Define to file name to log entries in. */ #define LOGFILE "/usr/games/lib/gr.log" /* * CONTROL - Master control file. */ #define CONTROL "/usr/games/lib/gr.control" /* * Misc. defines - Leave this alone! */ #define TRUE 1 #define FALSE 0 #define COMMENT '#' SHAR_EOF echo shar: extracting "'logfile.c'" '(1757 characters)' if test -f 'logfile.c' then echo shar: over-writing existing file "'logfile.c'" fi cat << \SHAR_EOF > 'logfile.c' #ifndef lint static char *RCSid = "$Header: logfile.c,v 1.3 86/03/25 15:44:35 mcooper Exp $"; #endif /* *------------------------------------------------------------------ * * $Source: /usr/src/local/gr/RCS/logfile.c,v $ * $Revision: 1.3 $ * $Date: 86/03/25 15:44:35 $ * $State: Exp $ * $Author: mcooper $ * $Locker: mcooper $ * *------------------------------------------------------------------ * * Michael Cooper (mcooper@usc-oberon.arpa) * University Computing Services, * University of Southern California, * Los Angeles, California, 90089-0251 * (213) 743-3469 * *------------------------------------------------------------------ * $Log: logfile.c,v $ * Revision 1.3 86/03/25 15:44:35 mcooper * more of same. * * Revision 1.2 86/03/25 15:35:43 mcooper * New headers... * *------------------------------------------------------------------ */ /* * logfile() -- log who is playing. If LOGFILE is defined (in gr.c) * then this function keeps track of users who play. */ #include #include #include "gr.h" #ifdef LOGFILE struct passwd *pw; struct passwd *getpwuid(); logfile(msg) char *msg; { char *fprintf(); char *strcmp(); char *getlogin(); char *time(), *ctime(); char buf[80]; char *str; char *user; double now; int diff = 0; FILE *fd, *fopen(); if ((pw = getpwuid(getuid())) != NULL) user = pw->pw_name; else user = "(unknown)"; if((str = getlogin()) != NULL) if(strcmp(str, user) != 0) { diff = 1; sprintf(buf, "(%s)", str); } time(&now); if((fd = fopen(LOGFILE, "a")) != NULL){ fprintf(fd, "%-10s%-12s%-7s%10.24s [ %s ]\n", user, diff ? buf : "", rindex(ttyname(0), '/') + 1, ctime(&now), msg); fclose(fd); } } #endif SHAR_EOF # End of shell archive exit 0