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