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 | |
b02d33b6 | 14 | static char sccsid[] = "@(#)machdep.c 5.3 (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 | ||
b02d33b6 KM |
59 | # undef LOADAV /* use getloadavg() by default */ |
60 | ||
7a6f3a77 KA |
61 | # ifdef SCOREFILE |
62 | ||
7a6f3a77 | 63 | static char *Lockfile = "/tmp/.fredlock"; |
7a6f3a77 KA |
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; | |
77c989a0 KM |
177 | if (Orig_dsusp == CTRL(Y)) { |
178 | Ltc.t_dsuspc = Ltc.t_suspc; | |
179 | ioctl(1, TIOCSLTC, &Ltc); | |
180 | } | |
7a6f3a77 KA |
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 | |
b02d33b6 | 229 | # ifdef LOADAV |
7a6f3a77 | 230 | loadav(avec); |
b02d33b6 KM |
231 | # else |
232 | if (getloadavg(avec, sizeof(avec)/sizeof(avec[0])) < 0) | |
233 | avec[0] = avec[1] = avec[2] = 0.0; | |
234 | # endif | |
7a6f3a77 KA |
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 | } |