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) 01/09/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 } 453