118589Sarnold /*
221461Smckusick * Copyright (c) 1980 Regents of the University of California.
321461Smckusick * All rights reserved. The Berkeley software License Agreement
421461Smckusick * specifies the terms and conditions for redistribution.
521461Smckusick */
621461Smckusick
721461Smckusick #ifndef lint
821461Smckusick char copyright[] =
921461Smckusick "@(#) Copyright (c) 1980 Regents of the University of California.\n\
1021461Smckusick All rights reserved.\n";
1121461Smckusick #endif not lint
1221461Smckusick
1321461Smckusick #ifndef lint
14*38198Smckusick static char sccsid[] = "@(#)machdep.c 5.3 (Berkeley) 05/29/89";
1521461Smckusick #endif not lint
1621461Smckusick
1721461Smckusick /*
1818589Sarnold * Various installation dependent routines
1918589Sarnold *
2018589Sarnold * $Revision: 1.7 $, $Date: 85/04/05 11:33:30 $
2118589Sarnold */
2218589Sarnold
2318589Sarnold /*
2418589Sarnold * The various tuneable defines are:
2518589Sarnold *
2618589Sarnold * SCOREFILE Where/if the score file should live.
2718589Sarnold * ALLSCORES Score file is top ten scores, not top ten
2818589Sarnold * players. This is only useful when only a few
2918589Sarnold * people will be playing; otherwise the score file
3018589Sarnold * gets hogged by just a few people.
3118589Sarnold * NUMSCORES Number of scores in the score file (default 10).
3218589Sarnold * NUMNAME String version of NUMSCORES (first character
3318589Sarnold * should be capitalized) (default "Ten").
3418589Sarnold * MAXLOAD What (if any) the maximum load average should be
3518589Sarnold * when people are playing.
3618589Sarnold * LOADAV Should it use it's own routine to get
3718589Sarnold * the load average?
3818589Sarnold * NAMELIST If so, where does the system namelist
3918589Sarnold * hide?
4018589Sarnold * MAXUSERS What (if any) the maximum user count should be
4118589Sarnold * when people are playing. If defined, then
4218589Sarnold * UCOUNT Should it use it's own routine to count
4318589Sarnold * users?
4418589Sarnold * UTMP If so, where does the user list hide?
4518589Sarnold * CHECKTIME How often/if it should check during the game
4618589Sarnold * for high load average.
4718589Sarnold * WARNTIME How much time between warnings when load gets
4818589Sarnold * too high (if not defined, it is the same as
4918589Sarnold * CHECKTIME).
5018589Sarnold */
5118589Sarnold
5218589Sarnold # include <curses.h>
5325786Smckusick # include "machdep.h"
5418589Sarnold # include <signal.h>
5518589Sarnold # include <sys/types.h>
5618589Sarnold # include <sys/stat.h>
5718589Sarnold # include <sys/file.h>
5818589Sarnold
59*38198Smckusick # undef LOADAV /* use getloadavg() by default */
60*38198Smckusick
6118589Sarnold # ifdef SCOREFILE
6218589Sarnold
6318589Sarnold static char *Lockfile = "/tmp/.fredlock";
6418589Sarnold
6518589Sarnold # ifndef NUMSCORES
6618589Sarnold # define NUMSCORES 10
6718589Sarnold # define NUMNAME "Ten"
6818589Sarnold # endif NUMSCORES
6918589Sarnold
7018589Sarnold unsigned int Numscores = NUMSCORES;
7118589Sarnold
7218589Sarnold char *Numname = NUMNAME;
7318589Sarnold
7418589Sarnold # ifdef ALLSCORES
7518589Sarnold bool Allscore = TRUE;
7618589Sarnold # else ALLSCORES
7718589Sarnold bool Allscore = FALSE;
7818589Sarnold # endif ALLSCORES
7918589Sarnold
8018589Sarnold # endif SCOREFILE
8118589Sarnold
8218589Sarnold # ifdef CHECKTIME
8318589Sarnold static int Num_checks; /* times we've gone over in checkout() */
8418589Sarnold
8518589Sarnold # ifndef WARNTIME
8618589Sarnold # define WARNTIME CHECKTIME
8718589Sarnold # endif
8818589Sarnold # endif CHECKTIME
8918589Sarnold
9018589Sarnold /*
9118589Sarnold * init_check:
9218589Sarnold * Check out too see if it is proper to play the game now
9318589Sarnold */
init_check()9418589Sarnold init_check()
9518589Sarnold {
9618589Sarnold # if defined(MAXLOAD) || defined(MAXUSERS)
9718589Sarnold if (too_much()) {
9818589Sarnold printf("Sorry, %s, but the system is too loaded now.\n",
9918589Sarnold Whoami);
10018589Sarnold printf("Try again later. Meanwhile, why not enjoy a%s %s?\n",
10118589Sarnold vowelstr(Fruit), Fruit);
10218589Sarnold if (author())
10318589Sarnold printf("However, since you're a good guy, it's up to you\n");
10418589Sarnold else
10518589Sarnold exit(1);
10618589Sarnold }
10718589Sarnold # endif defined(MAXLOAD) || defined(MAXUSERS)
10818589Sarnold }
10918589Sarnold
11018589Sarnold /*
11118589Sarnold * open_score:
11218589Sarnold * Open up the score file for future use, and then
11318589Sarnold * setuid(getuid()) in case we are running setuid.
11418589Sarnold */
open_score()11518589Sarnold open_score()
11618589Sarnold {
11718589Sarnold # ifdef SCOREFILE
11818589Sarnold Fd = open(SCOREFILE, 2);
11918589Sarnold # else SCOREFILE
12018589Sarnold Fd = -1;
12118589Sarnold # endif SCOREFILE
12218589Sarnold setuid(getuid());
12318589Sarnold setgid(getgid());
12418589Sarnold }
12518589Sarnold
12618589Sarnold /*
12718589Sarnold * setup:
12818589Sarnold * Get starting setup for all games
12918589Sarnold */
setup()13018589Sarnold setup()
13118589Sarnold {
13218589Sarnold extern int auto_save(), quit(), endit(), tstp();
13318589Sarnold # ifdef CHECKTIME
13418589Sarnold extern int heckout();
13518589Sarnold # endif CHECKTIME
13618589Sarnold
13718589Sarnold signal(SIGHUP, auto_save);
13818589Sarnold # ifndef DUMP
13918589Sarnold signal(SIGILL, auto_save);
14018589Sarnold signal(SIGTRAP, auto_save);
14118589Sarnold signal(SIGIOT, auto_save);
14218589Sarnold signal(SIGEMT, auto_save);
14318589Sarnold signal(SIGFPE, auto_save);
14418589Sarnold signal(SIGBUS, auto_save);
14518589Sarnold signal(SIGSEGV, auto_save);
14618589Sarnold signal(SIGSYS, auto_save);
14718589Sarnold signal(SIGTERM, auto_save);
14818589Sarnold # endif DUMP
14918589Sarnold
15018589Sarnold signal(SIGINT, quit);
15118589Sarnold # ifndef DUMP
15218589Sarnold signal(SIGQUIT, endit);
15318589Sarnold # endif DUMP
15418589Sarnold # ifdef CHECKTIME
15518589Sarnold signal(SIGALRM, checkout);
15618589Sarnold alarm(CHECKTIME * 60);
15718589Sarnold Num_checks = 0;
15818589Sarnold # endif CHECKTIME
15918589Sarnold crmode(); /* Cbreak mode */
16018589Sarnold noecho(); /* Echo off */
16118589Sarnold nonl();
16218589Sarnold # ifdef TIOCGLTC
16318589Sarnold getltchars(); /* get the local tty chars */
16418589Sarnold # endif TIOCGLTC
16518589Sarnold }
16618589Sarnold
16718589Sarnold /*
16818589Sarnold * getltchars:
16918589Sarnold * Get the local tty chars for later use
17018589Sarnold */
getltchars()17118589Sarnold getltchars()
17218589Sarnold {
17318589Sarnold # ifdef TIOCGLTC
17418589Sarnold ioctl(1, TIOCGLTC, &Ltc);
17518589Sarnold Got_ltc = TRUE;
17618589Sarnold Orig_dsusp = Ltc.t_dsuspc;
17725786Smckusick if (Orig_dsusp == CTRL(Y)) {
17825786Smckusick Ltc.t_dsuspc = Ltc.t_suspc;
17925786Smckusick ioctl(1, TIOCSLTC, &Ltc);
18025786Smckusick }
18118589Sarnold # endif TIOCGLTC
18218589Sarnold }
18318589Sarnold
18418589Sarnold /*
18518589Sarnold * start_score:
18618589Sarnold * Start the scoring sequence
18718589Sarnold */
start_score()18818589Sarnold start_score()
18918589Sarnold {
19018589Sarnold # ifdef CHECKTIME
19118589Sarnold signal(SIGALRM, SIG_IGN); /* NOSTRICT */
19218589Sarnold # endif CHECKTIME
19318589Sarnold }
19418589Sarnold
19518589Sarnold /*
19618589Sarnold * symlink:
19718589Sarnold * See if the file has a symbolic link
19818589Sarnold */
symlink(sp)19918589Sarnold symlink(sp)
20018589Sarnold char *sp;
20118589Sarnold {
20218589Sarnold # ifdef S_IFLNK
20318589Sarnold struct stat sbuf2;
20418589Sarnold
20518589Sarnold if (lstat(sp, &sbuf2) < 0)
20618589Sarnold return FALSE;
20718589Sarnold else
20818589Sarnold return ((sbuf2.st_mode & S_IFMT) != S_IFREG);
20918589Sarnold # else S_IFLNK
21018589Sarnold return FALSE;
21118589Sarnold # endif S_IFLNK
21218589Sarnold }
21318589Sarnold
21418589Sarnold # if defined(MAXLOAD) || defined(MAXUSERS)
21518589Sarnold /*
21618589Sarnold * too_much:
21718589Sarnold * See if the system is being used too much for this game
21818589Sarnold */
too_much()21918589Sarnold too_much()
22018589Sarnold {
22118589Sarnold # ifdef MAXLOAD
22218589Sarnold double avec[3];
22318589Sarnold # endif MAXLOAD
22418589Sarnold # ifdef MAXUSERS
22518589Sarnold register int cnt;
22618589Sarnold # endif MAXUSERS
22718589Sarnold
22818589Sarnold # ifdef MAXLOAD
229*38198Smckusick # ifdef LOADAV
23018589Sarnold loadav(avec);
231*38198Smckusick # else
232*38198Smckusick if (getloadavg(avec, sizeof(avec)/sizeof(avec[0])) < 0)
233*38198Smckusick avec[0] = avec[1] = avec[2] = 0.0;
234*38198Smckusick # endif
23518589Sarnold if (avec[1] > MAXLOAD)
23618589Sarnold return TRUE;
23718589Sarnold # endif MAXLOAD
23818589Sarnold # ifdef MAXUSERS
23918589Sarnold if (ucount() > MAXUSERS)
24018589Sarnold return TRUE;
24118589Sarnold # endif MAXUSERS
24218589Sarnold return FALSE;
24318589Sarnold }
24418589Sarnold
24518589Sarnold /*
24618589Sarnold * author:
24718589Sarnold * See if a user is an author of the program
24818589Sarnold */
author()24918589Sarnold author()
25018589Sarnold {
25118589Sarnold # ifdef MASTER
25218589Sarnold if (Wizard)
25318589Sarnold return TRUE;
25418589Sarnold # endif MASTER
25518589Sarnold switch (getuid())
25618589Sarnold {
25718589Sarnold case -1:
25818589Sarnold return TRUE;
25918589Sarnold default:
26018589Sarnold return FALSE;
26118589Sarnold }
26218589Sarnold }
26318589Sarnold # endif defined(MAXLOAD) || defined(MAXUSERS)
26418589Sarnold
26518589Sarnold # ifdef CHECKTIME
26618589Sarnold /*
26718589Sarnold * checkout:
26818589Sarnold * Check each CHECKTIME seconds to see if the load is too high
26918589Sarnold */
checkout()27018589Sarnold checkout()
27118589Sarnold {
27218589Sarnold int checktime;
27318589Sarnold static char *msgs[] = {
27418589Sarnold "The load is too high to be playing. Please leave in %.2f minutes",
27518589Sarnold "Please save your game. You have %.2f minutes",
27618589Sarnold "Last warning. You have %.2f minutes to leave",
27718589Sarnold };
27818589Sarnold
27918589Sarnold signal(SIGALRM, checkout);
28018589Sarnold if (too_much()) {
28118589Sarnold if (author()) {
28218589Sarnold Num_checks = 1;
28318589Sarnold chmsg("The load is rather high, O exaulted one");
28418589Sarnold }
28518589Sarnold else if (Num_checks++ == 3)
28618589Sarnold fatal("Sorry. You took too long. You are dead\n");
28718589Sarnold checktime = (WARNTIME * 60) / Num_checks;
28818589Sarnold alarm(checktime);
28918589Sarnold chmsg(msgs[Num_checks - 1], ((double) checktime / 60.0));
29018589Sarnold }
29118589Sarnold else {
29218589Sarnold if (Num_checks) {
29318589Sarnold Num_checks = 0;
29418589Sarnold chmsg("The load has dropped back down. You have a reprieve");
29518589Sarnold }
29618589Sarnold alarm(CHECKTIME * 60);
29718589Sarnold }
29818589Sarnold }
29918589Sarnold
30018589Sarnold /*
30118589Sarnold * chmsg:
30218589Sarnold * checkout()'s version of msg. If we are in the middle of a
30318589Sarnold * shell, do a printf instead of a msg to avoid the refresh.
30418589Sarnold */
30518589Sarnold /* VARARGS1 */
chmsg(fmt,arg)30618589Sarnold chmsg(fmt, arg)
30718589Sarnold char *fmt;
30818589Sarnold int arg;
30918589Sarnold {
31018589Sarnold if (!In_shell)
31118589Sarnold msg(fmt, arg);
31218589Sarnold else {
31318589Sarnold printf(fmt, arg);
31418589Sarnold putchar('\n');
31518589Sarnold fflush(stdout);
31618589Sarnold }
31718589Sarnold }
31818589Sarnold # endif defined(MAXLOAD) || defined(MAXUSERS)
31918589Sarnold
32018589Sarnold # ifdef LOADAV
32118589Sarnold /*
32218589Sarnold * loadav:
32318589Sarnold * Looking up load average in core (for system where the loadav()
32418589Sarnold * system call isn't defined
32518589Sarnold */
32618589Sarnold
32718589Sarnold # include <nlist.h>
32818589Sarnold
32918589Sarnold struct nlist avenrun = {
33018589Sarnold "_avenrun"
33118589Sarnold };
33218589Sarnold
33318589Sarnold # ifndef NAMELIST
33418589Sarnold # define NAMELIST "/vmunix"
33518589Sarnold # endif
33618589Sarnold
loadav(avg)33718589Sarnold loadav(avg)
33818589Sarnold register double *avg;
33918589Sarnold {
34018589Sarnold register int kmem;
34118589Sarnold
34218589Sarnold if ((kmem = open("/dev/kmem", 0)) < 0)
34318589Sarnold goto bad;
34418589Sarnold nlist(NAMELIST, &avenrun);
34518589Sarnold if (avenrun.n_type == 0) {
34618589Sarnold close(kmem);
34718589Sarnold bad:
34818589Sarnold avg[0] = 0.0;
34918589Sarnold avg[1] = 0.0;
35018589Sarnold avg[2] = 0.0;
35118589Sarnold return;
35218589Sarnold }
35318589Sarnold
35418589Sarnold lseek(kmem, (long) avenrun.n_value, 0);
35518589Sarnold read(kmem, (char *) avg, 3 * sizeof (double));
35618589Sarnold close(kmem);
35718589Sarnold }
35818589Sarnold # endif LOADAV
35918589Sarnold
36018589Sarnold # ifdef UCOUNT
36118589Sarnold /*
36218589Sarnold * ucount:
36318589Sarnold * Count number of users on the system
36418589Sarnold */
36518589Sarnold # include <utmp.h>
36618589Sarnold
36718589Sarnold struct utmp buf;
36818589Sarnold
ucount()36918589Sarnold ucount()
37018589Sarnold {
37118589Sarnold register struct utmp *up;
37218589Sarnold register FILE *utmp;
37318589Sarnold register int count;
37418589Sarnold
37518589Sarnold if ((utmp = fopen(UTMP, "r")) == NULL)
37618589Sarnold return 0;
37718589Sarnold
37818589Sarnold up = &buf;
37918589Sarnold count = 0;
38018589Sarnold
38118589Sarnold while (fread(up, 1, sizeof (*up), utmp) > 0)
38218589Sarnold if (buf.ut_name[0] != '\0')
38318589Sarnold count++;
38418589Sarnold fclose(utmp);
38518589Sarnold return count;
38618589Sarnold }
38718589Sarnold # endif UCOUNT
38818589Sarnold
38918589Sarnold /*
39018589Sarnold * lock_sc:
39118589Sarnold * lock the score file. If it takes too long, ask the user if
39218589Sarnold * they care to wait. Return TRUE if the lock is successful.
39318589Sarnold */
lock_sc()39418589Sarnold lock_sc()
39518589Sarnold {
39618589Sarnold # ifdef SCOREFILE
39718589Sarnold # ifdef LOCK_EX
39818589Sarnold return (flock(Fd, LOCK_EX) >= 0);
39918589Sarnold # else LOCK_EX
40018589Sarnold register int cnt;
40118589Sarnold static struct stat sbuf;
40218589Sarnold
40318589Sarnold over:
40418589Sarnold close(8); /* just in case there are no files left */
40518589Sarnold if (creat(Lockfile, 0000) >= 0)
40618589Sarnold return TRUE;
40718589Sarnold for (cnt = 0; cnt < 5; cnt++) {
40818589Sarnold sleep(1);
40918589Sarnold if (creat(Lockfile, 0000) >= 0)
41018589Sarnold return TRUE;
41118589Sarnold }
41218589Sarnold if (stat(Lockfile, &sbuf) < 0) {
41318589Sarnold creat(Lockfile, 0000);
41418589Sarnold return TRUE;
41518589Sarnold }
41618589Sarnold if (time(NULL) - sbuf.st_mtime > 10) {
41718589Sarnold if (unlink(Lockfile) < 0)
41818589Sarnold return FALSE;
41918589Sarnold goto over;
42018589Sarnold }
42118589Sarnold else {
42218589Sarnold printf("The score file is very busy. Do you want to wait longer\n");
42318589Sarnold printf("for it to become free so your score can get posted?\n");
42418589Sarnold printf("If so, type \"y\"\n");
42518589Sarnold fgets(Prbuf, MAXSTR, stdin);
42618589Sarnold if (Prbuf[0] == 'y')
42718589Sarnold for (;;) {
42818589Sarnold if (creat(Lockfile, 0000) >= 0)
42918589Sarnold return TRUE;
43018589Sarnold if (stat(Lockfile, &sbuf) < 0) {
43118589Sarnold creat(Lockfile, 0000);
43218589Sarnold return TRUE;
43318589Sarnold }
43418589Sarnold if (time(NULL) - sbuf.st_mtime > 10)
43518589Sarnold if (unlink(Lockfile) < 0)
43618589Sarnold return FALSE;
43718589Sarnold sleep(1);
43818589Sarnold }
43918589Sarnold else
44018589Sarnold return FALSE;
44118589Sarnold }
44218589Sarnold # endif LOCK_EX
44318589Sarnold # endif SCOREFILE
44418589Sarnold }
44518589Sarnold
44618589Sarnold /*
44718589Sarnold * unlock_sc:
44818589Sarnold * Unlock the score file
44918589Sarnold */
unlock_sc()45018589Sarnold unlock_sc()
45118589Sarnold {
45218589Sarnold # ifdef SCOREFILE
45318589Sarnold # ifdef LOCK_EX
45418589Sarnold flock(Fd, LOCK_UN);
45518589Sarnold #else
45618589Sarnold unlink(Lockfile);
45718589Sarnold # endif
45818589Sarnold # endif
45918589Sarnold }
460