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