xref: /csrg-svn/old/rogue/machdep.c (revision 38198)
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