| 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) %G%"; |
| 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 | } |