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