Commit | Line | Data |
---|---|---|
e3325aaf KM |
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 | |
77c989a0 | 14 | static char sccsid[] = "@(#)machdep.c 5.2 (Berkeley) %G%"; |
e3325aaf KM |
15 | #endif not lint |
16 | ||
7a6f3a77 KA |
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> | |
77c989a0 | 53 | # include "machdep.h" |
7a6f3a77 KA |
54 | # include <signal.h> |
55 | # include <sys/types.h> | |
56 | # include <sys/stat.h> | |
57 | # include <sys/file.h> | |
58 | ||
59 | # ifdef SCOREFILE | |
60 | ||
7a6f3a77 | 61 | static char *Lockfile = "/tmp/.fredlock"; |
7a6f3a77 KA |
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; | |
77c989a0 KM |
175 | if (Orig_dsusp == CTRL(Y)) { |
176 | Ltc.t_dsuspc = Ltc.t_suspc; | |
177 | ioctl(1, TIOCSLTC, &Ltc); | |
178 | } | |
7a6f3a77 KA |
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 | } |