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) 1/9/86"; 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: }