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