xref: /csrg-svn/old/rogue/machdep.c (revision 18589)
1*18589Sarnold /*
2*18589Sarnold  * Various installation dependent routines
3*18589Sarnold  *
4*18589Sarnold  * $Revision: 1.7 $, $Date: 85/04/05 11:33:30 $
5*18589Sarnold  */
6*18589Sarnold 
7*18589Sarnold /*
8*18589Sarnold  * The various tuneable defines are:
9*18589Sarnold  *
10*18589Sarnold  *	SCOREFILE	Where/if the score file should live.
11*18589Sarnold  *	ALLSCORES	Score file is top ten scores, not top ten
12*18589Sarnold  *			players.  This is only useful when only a few
13*18589Sarnold  *			people will be playing; otherwise the score file
14*18589Sarnold  *			gets hogged by just a few people.
15*18589Sarnold  *	NUMSCORES	Number of scores in the score file (default 10).
16*18589Sarnold  *	NUMNAME		String version of NUMSCORES (first character
17*18589Sarnold  *			should be capitalized) (default "Ten").
18*18589Sarnold  *	MAXLOAD		What (if any) the maximum load average should be
19*18589Sarnold  *			when people are playing.
20*18589Sarnold  *		LOADAV		Should it use it's own routine to get
21*18589Sarnold  *				the load average?
22*18589Sarnold  *		NAMELIST	If so, where does the system namelist
23*18589Sarnold  *				hide?
24*18589Sarnold  *	MAXUSERS	What (if any) the maximum user count should be
25*18589Sarnold  *			when people are playing.  If defined, then
26*18589Sarnold  *		UCOUNT		Should it use it's own routine to count
27*18589Sarnold  *				users?
28*18589Sarnold  *		UTMP		If so, where does the user list hide?
29*18589Sarnold  *	CHECKTIME	How often/if it should check during the game
30*18589Sarnold  *			for high load average.
31*18589Sarnold  *	WARNTIME	How much time between warnings when load gets
32*18589Sarnold  *			too high (if not defined, it is the same as
33*18589Sarnold  *			CHECKTIME).
34*18589Sarnold  */
35*18589Sarnold 
36*18589Sarnold # include	<curses.h>
37*18589Sarnold # include	"extern.h"
38*18589Sarnold # include	<signal.h>
39*18589Sarnold # include	<sys/types.h>
40*18589Sarnold # include	<sys/stat.h>
41*18589Sarnold # include	<sys/file.h>
42*18589Sarnold 
43*18589Sarnold # ifdef	SCOREFILE
44*18589Sarnold 
45*18589Sarnold # ifndef	LOCK_EX
46*18589Sarnold static char	*Lockfile = "/tmp/.fredlock";
47*18589Sarnold # endif
48*18589Sarnold 
49*18589Sarnold # ifndef	NUMSCORES
50*18589Sarnold # 	define	NUMSCORES	10
51*18589Sarnold # 	define	NUMNAME		"Ten"
52*18589Sarnold # endif		NUMSCORES
53*18589Sarnold 
54*18589Sarnold unsigned int	Numscores = NUMSCORES;
55*18589Sarnold 
56*18589Sarnold char		*Numname = NUMNAME;
57*18589Sarnold 
58*18589Sarnold # ifdef ALLSCORES
59*18589Sarnold bool	Allscore = TRUE;
60*18589Sarnold # else	ALLSCORES
61*18589Sarnold bool	Allscore = FALSE;
62*18589Sarnold # endif ALLSCORES
63*18589Sarnold 
64*18589Sarnold # endif	SCOREFILE
65*18589Sarnold 
66*18589Sarnold # ifdef	CHECKTIME
67*18589Sarnold static int	Num_checks;	/* times we've gone over in checkout() */
68*18589Sarnold 
69*18589Sarnold # ifndef WARNTIME
70*18589Sarnold # define	WARNTIME	CHECKTIME
71*18589Sarnold # endif
72*18589Sarnold # endif	CHECKTIME
73*18589Sarnold 
74*18589Sarnold /*
75*18589Sarnold  * init_check:
76*18589Sarnold  *	Check out too see if it is proper to play the game now
77*18589Sarnold  */
78*18589Sarnold init_check()
79*18589Sarnold {
80*18589Sarnold # if	defined(MAXLOAD) || defined(MAXUSERS)
81*18589Sarnold 	if (too_much()) {
82*18589Sarnold 		printf("Sorry, %s, but the system is too loaded now.\n",
83*18589Sarnold 		       Whoami);
84*18589Sarnold 		printf("Try again later.  Meanwhile, why not enjoy a%s %s?\n",
85*18589Sarnold 		       vowelstr(Fruit), Fruit);
86*18589Sarnold 		if (author())
87*18589Sarnold 			printf("However, since you're a good guy, it's up to you\n");
88*18589Sarnold 		else
89*18589Sarnold 			exit(1);
90*18589Sarnold 	}
91*18589Sarnold # endif	defined(MAXLOAD) || defined(MAXUSERS)
92*18589Sarnold }
93*18589Sarnold 
94*18589Sarnold /*
95*18589Sarnold  * open_score:
96*18589Sarnold  *	Open up the score file for future use, and then
97*18589Sarnold  *	setuid(getuid()) in case we are running setuid.
98*18589Sarnold  */
99*18589Sarnold open_score()
100*18589Sarnold {
101*18589Sarnold # ifdef SCOREFILE
102*18589Sarnold 	Fd = open(SCOREFILE, 2);
103*18589Sarnold # else	SCOREFILE
104*18589Sarnold 	Fd = -1;
105*18589Sarnold # endif	SCOREFILE
106*18589Sarnold 	setuid(getuid());
107*18589Sarnold 	setgid(getgid());
108*18589Sarnold }
109*18589Sarnold 
110*18589Sarnold /*
111*18589Sarnold  * setup:
112*18589Sarnold  *	Get starting setup for all games
113*18589Sarnold  */
114*18589Sarnold setup()
115*18589Sarnold {
116*18589Sarnold 	extern int	auto_save(), quit(), endit(), tstp();
117*18589Sarnold # ifdef CHECKTIME
118*18589Sarnold 	extern int 	heckout();
119*18589Sarnold # endif	CHECKTIME
120*18589Sarnold 
121*18589Sarnold 	signal(SIGHUP, auto_save);
122*18589Sarnold # ifndef DUMP
123*18589Sarnold 	signal(SIGILL, auto_save);
124*18589Sarnold 	signal(SIGTRAP, auto_save);
125*18589Sarnold 	signal(SIGIOT, auto_save);
126*18589Sarnold 	signal(SIGEMT, auto_save);
127*18589Sarnold 	signal(SIGFPE, auto_save);
128*18589Sarnold 	signal(SIGBUS, auto_save);
129*18589Sarnold 	signal(SIGSEGV, auto_save);
130*18589Sarnold 	signal(SIGSYS, auto_save);
131*18589Sarnold 	signal(SIGTERM, auto_save);
132*18589Sarnold # endif	DUMP
133*18589Sarnold 
134*18589Sarnold 	signal(SIGINT, quit);
135*18589Sarnold # ifndef DUMP
136*18589Sarnold 	signal(SIGQUIT, endit);
137*18589Sarnold # endif	DUMP
138*18589Sarnold # ifdef CHECKTIME
139*18589Sarnold 	signal(SIGALRM, checkout);
140*18589Sarnold 	alarm(CHECKTIME * 60);
141*18589Sarnold 	Num_checks = 0;
142*18589Sarnold # endif	CHECKTIME
143*18589Sarnold 	crmode();				/* Cbreak mode */
144*18589Sarnold 	noecho();				/* Echo off */
145*18589Sarnold 	nonl();
146*18589Sarnold # ifdef TIOCGLTC
147*18589Sarnold 	getltchars();			/* get the local tty chars */
148*18589Sarnold # endif	TIOCGLTC
149*18589Sarnold }
150*18589Sarnold 
151*18589Sarnold /*
152*18589Sarnold  * getltchars:
153*18589Sarnold  *	Get the local tty chars for later use
154*18589Sarnold  */
155*18589Sarnold getltchars()
156*18589Sarnold {
157*18589Sarnold # ifdef TIOCGLTC
158*18589Sarnold 	ioctl(1, TIOCGLTC, &Ltc);
159*18589Sarnold 	Got_ltc = TRUE;
160*18589Sarnold 	Orig_dsusp = Ltc.t_dsuspc;
161*18589Sarnold 	Ltc.t_dsuspc = Ltc.t_suspc;
162*18589Sarnold 	ioctl(1, TIOCSLTC, &Ltc);
163*18589Sarnold # endif	TIOCGLTC
164*18589Sarnold }
165*18589Sarnold 
166*18589Sarnold /*
167*18589Sarnold  * start_score:
168*18589Sarnold  *	Start the scoring sequence
169*18589Sarnold  */
170*18589Sarnold start_score()
171*18589Sarnold {
172*18589Sarnold # ifdef CHECKTIME
173*18589Sarnold 	signal(SIGALRM, SIG_IGN);	/* NOSTRICT */
174*18589Sarnold # endif	CHECKTIME
175*18589Sarnold }
176*18589Sarnold 
177*18589Sarnold /*
178*18589Sarnold  * symlink:
179*18589Sarnold  *	See if the file has a symbolic link
180*18589Sarnold  */
181*18589Sarnold symlink(sp)
182*18589Sarnold char	*sp;
183*18589Sarnold {
184*18589Sarnold # ifdef S_IFLNK
185*18589Sarnold 	struct stat sbuf2;
186*18589Sarnold 
187*18589Sarnold 	if (lstat(sp, &sbuf2) < 0)
188*18589Sarnold 		return FALSE;
189*18589Sarnold 	else
190*18589Sarnold 		return ((sbuf2.st_mode & S_IFMT) != S_IFREG);
191*18589Sarnold # else	S_IFLNK
192*18589Sarnold 	return FALSE;
193*18589Sarnold # endif	S_IFLNK
194*18589Sarnold }
195*18589Sarnold 
196*18589Sarnold # if	defined(MAXLOAD) || defined(MAXUSERS)
197*18589Sarnold /*
198*18589Sarnold  * too_much:
199*18589Sarnold  *	See if the system is being used too much for this game
200*18589Sarnold  */
201*18589Sarnold too_much()
202*18589Sarnold {
203*18589Sarnold # ifdef MAXLOAD
204*18589Sarnold 	double		avec[3];
205*18589Sarnold # endif	MAXLOAD
206*18589Sarnold # ifdef	MAXUSERS
207*18589Sarnold 	register int	cnt;
208*18589Sarnold # endif	MAXUSERS
209*18589Sarnold 
210*18589Sarnold # ifdef MAXLOAD
211*18589Sarnold 	loadav(avec);
212*18589Sarnold 	if (avec[1] > MAXLOAD)
213*18589Sarnold 		return TRUE;
214*18589Sarnold # endif	MAXLOAD
215*18589Sarnold # ifdef MAXUSERS
216*18589Sarnold 	if (ucount() > MAXUSERS)
217*18589Sarnold 		return TRUE;
218*18589Sarnold # endif	MAXUSERS
219*18589Sarnold 	return FALSE;
220*18589Sarnold }
221*18589Sarnold 
222*18589Sarnold /*
223*18589Sarnold  * author:
224*18589Sarnold  *	See if a user is an author of the program
225*18589Sarnold  */
226*18589Sarnold author()
227*18589Sarnold {
228*18589Sarnold # ifdef MASTER
229*18589Sarnold 	if (Wizard)
230*18589Sarnold 		return TRUE;
231*18589Sarnold # endif	MASTER
232*18589Sarnold 	switch (getuid())
233*18589Sarnold 	{
234*18589Sarnold 	  case -1:
235*18589Sarnold 		return TRUE;
236*18589Sarnold 	  default:
237*18589Sarnold 		return FALSE;
238*18589Sarnold 	}
239*18589Sarnold }
240*18589Sarnold # endif	defined(MAXLOAD) || defined(MAXUSERS)
241*18589Sarnold 
242*18589Sarnold # ifdef	CHECKTIME
243*18589Sarnold /*
244*18589Sarnold  * checkout:
245*18589Sarnold  *	Check each CHECKTIME seconds to see if the load is too high
246*18589Sarnold  */
247*18589Sarnold checkout()
248*18589Sarnold {
249*18589Sarnold 	int		checktime;
250*18589Sarnold 	static char	*msgs[] = {
251*18589Sarnold 		"The load is too high to be playing.  Please leave in %.2f minutes",
252*18589Sarnold 		"Please save your game.  You have %.2f minutes",
253*18589Sarnold 		"Last warning.  You have %.2f minutes to leave",
254*18589Sarnold 	};
255*18589Sarnold 
256*18589Sarnold 	signal(SIGALRM, checkout);
257*18589Sarnold 	if (too_much()) {
258*18589Sarnold 		if (author()) {
259*18589Sarnold 			Num_checks = 1;
260*18589Sarnold 			chmsg("The load is rather high, O exaulted one");
261*18589Sarnold 		}
262*18589Sarnold 		else if (Num_checks++ == 3)
263*18589Sarnold 			fatal("Sorry.  You took too long.  You are dead\n");
264*18589Sarnold 		checktime = (WARNTIME * 60) / Num_checks;
265*18589Sarnold 		alarm(checktime);
266*18589Sarnold 		chmsg(msgs[Num_checks - 1], ((double) checktime / 60.0));
267*18589Sarnold 	}
268*18589Sarnold 	else {
269*18589Sarnold 		if (Num_checks) {
270*18589Sarnold 			Num_checks = 0;
271*18589Sarnold 			chmsg("The load has dropped back down.  You have a reprieve");
272*18589Sarnold 		}
273*18589Sarnold 		alarm(CHECKTIME * 60);
274*18589Sarnold 	}
275*18589Sarnold }
276*18589Sarnold 
277*18589Sarnold /*
278*18589Sarnold  * chmsg:
279*18589Sarnold  *	checkout()'s version of msg.  If we are in the middle of a
280*18589Sarnold  *	shell, do a printf instead of a msg to avoid the refresh.
281*18589Sarnold  */
282*18589Sarnold /* VARARGS1 */
283*18589Sarnold chmsg(fmt, arg)
284*18589Sarnold char	*fmt;
285*18589Sarnold int	arg;
286*18589Sarnold {
287*18589Sarnold 	if (!In_shell)
288*18589Sarnold 		msg(fmt, arg);
289*18589Sarnold 	else {
290*18589Sarnold 		printf(fmt, arg);
291*18589Sarnold 		putchar('\n');
292*18589Sarnold 		fflush(stdout);
293*18589Sarnold 	}
294*18589Sarnold }
295*18589Sarnold # endif	defined(MAXLOAD) || defined(MAXUSERS)
296*18589Sarnold 
297*18589Sarnold # ifdef	LOADAV
298*18589Sarnold /*
299*18589Sarnold  * loadav:
300*18589Sarnold  *	Looking up load average in core (for system where the loadav()
301*18589Sarnold  *	system call isn't defined
302*18589Sarnold  */
303*18589Sarnold 
304*18589Sarnold # include	<nlist.h>
305*18589Sarnold 
306*18589Sarnold struct nlist	avenrun = {
307*18589Sarnold 	    "_avenrun"
308*18589Sarnold };
309*18589Sarnold 
310*18589Sarnold # ifndef	NAMELIST
311*18589Sarnold # define	NAMELIST	"/vmunix"
312*18589Sarnold # endif
313*18589Sarnold 
314*18589Sarnold loadav(avg)
315*18589Sarnold register double	*avg;
316*18589Sarnold {
317*18589Sarnold 	register int	kmem;
318*18589Sarnold 
319*18589Sarnold 	if ((kmem = open("/dev/kmem", 0)) < 0)
320*18589Sarnold 		goto bad;
321*18589Sarnold 	nlist(NAMELIST, &avenrun);
322*18589Sarnold 	if (avenrun.n_type == 0) {
323*18589Sarnold 		close(kmem);
324*18589Sarnold 		bad:
325*18589Sarnold 		avg[0] = 0.0;
326*18589Sarnold 		avg[1] = 0.0;
327*18589Sarnold 		avg[2] = 0.0;
328*18589Sarnold 		return;
329*18589Sarnold 	}
330*18589Sarnold 
331*18589Sarnold 	lseek(kmem, (long) avenrun.n_value, 0);
332*18589Sarnold 	read(kmem, (char *) avg, 3 * sizeof (double));
333*18589Sarnold 	close(kmem);
334*18589Sarnold }
335*18589Sarnold # endif	LOADAV
336*18589Sarnold 
337*18589Sarnold # ifdef UCOUNT
338*18589Sarnold /*
339*18589Sarnold  * ucount:
340*18589Sarnold  *	Count number of users on the system
341*18589Sarnold  */
342*18589Sarnold # include	<utmp.h>
343*18589Sarnold 
344*18589Sarnold struct utmp	buf;
345*18589Sarnold 
346*18589Sarnold ucount()
347*18589Sarnold {
348*18589Sarnold 	register struct utmp	*up;
349*18589Sarnold 	register FILE		*utmp;
350*18589Sarnold 	register int		count;
351*18589Sarnold 
352*18589Sarnold 	if ((utmp = fopen(UTMP, "r")) == NULL)
353*18589Sarnold 		return 0;
354*18589Sarnold 
355*18589Sarnold 	up = &buf;
356*18589Sarnold 	count = 0;
357*18589Sarnold 
358*18589Sarnold 	while (fread(up, 1, sizeof (*up), utmp) > 0)
359*18589Sarnold 		if (buf.ut_name[0] != '\0')
360*18589Sarnold 			count++;
361*18589Sarnold 	fclose(utmp);
362*18589Sarnold 	return count;
363*18589Sarnold }
364*18589Sarnold # endif	UCOUNT
365*18589Sarnold 
366*18589Sarnold /*
367*18589Sarnold  * lock_sc:
368*18589Sarnold  *	lock the score file.  If it takes too long, ask the user if
369*18589Sarnold  *	they care to wait.  Return TRUE if the lock is successful.
370*18589Sarnold  */
371*18589Sarnold lock_sc()
372*18589Sarnold {
373*18589Sarnold # ifdef SCOREFILE
374*18589Sarnold # ifdef	LOCK_EX
375*18589Sarnold 	return (flock(Fd, LOCK_EX) >= 0);
376*18589Sarnold # else	LOCK_EX
377*18589Sarnold 	register int		cnt;
378*18589Sarnold 	static struct stat	sbuf;
379*18589Sarnold 
380*18589Sarnold over:
381*18589Sarnold 	close(8);	/* just in case there are no files left */
382*18589Sarnold 	if (creat(Lockfile, 0000) >= 0)
383*18589Sarnold 		return TRUE;
384*18589Sarnold 	for (cnt = 0; cnt < 5; cnt++) {
385*18589Sarnold 		sleep(1);
386*18589Sarnold 		if (creat(Lockfile, 0000) >= 0)
387*18589Sarnold 			return TRUE;
388*18589Sarnold 	}
389*18589Sarnold 	if (stat(Lockfile, &sbuf) < 0) {
390*18589Sarnold 		creat(Lockfile, 0000);
391*18589Sarnold 		return TRUE;
392*18589Sarnold 	}
393*18589Sarnold 	if (time(NULL) - sbuf.st_mtime > 10) {
394*18589Sarnold 		if (unlink(Lockfile) < 0)
395*18589Sarnold 			return FALSE;
396*18589Sarnold 		goto over;
397*18589Sarnold 	}
398*18589Sarnold 	else {
399*18589Sarnold 		printf("The score file is very busy.  Do you want to wait longer\n");
400*18589Sarnold 		printf("for it to become free so your score can get posted?\n");
401*18589Sarnold 		printf("If so, type \"y\"\n");
402*18589Sarnold 		fgets(Prbuf, MAXSTR, stdin);
403*18589Sarnold 		if (Prbuf[0] == 'y')
404*18589Sarnold 			for (;;) {
405*18589Sarnold 				if (creat(Lockfile, 0000) >= 0)
406*18589Sarnold 					return TRUE;
407*18589Sarnold 				if (stat(Lockfile, &sbuf) < 0) {
408*18589Sarnold 					creat(Lockfile, 0000);
409*18589Sarnold 					return TRUE;
410*18589Sarnold 				}
411*18589Sarnold 				if (time(NULL) - sbuf.st_mtime > 10)
412*18589Sarnold 					if (unlink(Lockfile) < 0)
413*18589Sarnold 						return FALSE;
414*18589Sarnold 				sleep(1);
415*18589Sarnold 			}
416*18589Sarnold 		else
417*18589Sarnold 			return FALSE;
418*18589Sarnold 	}
419*18589Sarnold # endif	LOCK_EX
420*18589Sarnold # endif	SCOREFILE
421*18589Sarnold }
422*18589Sarnold 
423*18589Sarnold /*
424*18589Sarnold  * unlock_sc:
425*18589Sarnold  *	Unlock the score file
426*18589Sarnold  */
427*18589Sarnold unlock_sc()
428*18589Sarnold {
429*18589Sarnold # ifdef SCOREFILE
430*18589Sarnold # ifdef	LOCK_EX
431*18589Sarnold 	flock(Fd, LOCK_UN);
432*18589Sarnold #else
433*18589Sarnold 	unlink(Lockfile);
434*18589Sarnold # endif
435*18589Sarnold # endif
436*18589Sarnold }
437