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.3 (Berkeley) 05/29/89"; 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 # undef LOADAV /* use getloadavg() by default */ 60 61 # ifdef SCOREFILE 62 63 static char *Lockfile = "/tmp/.fredlock"; 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; 177 if (Orig_dsusp == CTRL(Y)) { 178 Ltc.t_dsuspc = Ltc.t_suspc; 179 ioctl(1, TIOCSLTC, &Ltc); 180 } 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 229 # ifdef LOADAV 230 loadav(avec); 231 # else 232 if (getloadavg(avec, sizeof(avec)/sizeof(avec[0])) < 0) 233 avec[0] = avec[1] = avec[2] = 0.0; 234 # endif 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 } 460