1 /* 2 * Various installation dependent routines 3 * 4 * $Revision: 1.7 $, $Date: 85/04/05 11:33:30 $ 5 */ 6 7 /* 8 * The various tuneable defines are: 9 * 10 * SCOREFILE Where/if the score file should live. 11 * ALLSCORES Score file is top ten scores, not top ten 12 * players. This is only useful when only a few 13 * people will be playing; otherwise the score file 14 * gets hogged by just a few people. 15 * NUMSCORES Number of scores in the score file (default 10). 16 * NUMNAME String version of NUMSCORES (first character 17 * should be capitalized) (default "Ten"). 18 * MAXLOAD What (if any) the maximum load average should be 19 * when people are playing. 20 * LOADAV Should it use it's own routine to get 21 * the load average? 22 * NAMELIST If so, where does the system namelist 23 * hide? 24 * MAXUSERS What (if any) the maximum user count should be 25 * when people are playing. If defined, then 26 * UCOUNT Should it use it's own routine to count 27 * users? 28 * UTMP If so, where does the user list hide? 29 * CHECKTIME How often/if it should check during the game 30 * for high load average. 31 * WARNTIME How much time between warnings when load gets 32 * too high (if not defined, it is the same as 33 * CHECKTIME). 34 */ 35 36 # include <curses.h> 37 # include "extern.h" 38 # include <signal.h> 39 # include <sys/types.h> 40 # include <sys/stat.h> 41 # include <sys/file.h> 42 43 # ifdef SCOREFILE 44 45 # ifndef LOCK_EX 46 static char *Lockfile = "/tmp/.fredlock"; 47 # endif 48 49 # ifndef NUMSCORES 50 # define NUMSCORES 10 51 # define NUMNAME "Ten" 52 # endif NUMSCORES 53 54 unsigned int Numscores = NUMSCORES; 55 56 char *Numname = NUMNAME; 57 58 # ifdef ALLSCORES 59 bool Allscore = TRUE; 60 # else ALLSCORES 61 bool Allscore = FALSE; 62 # endif ALLSCORES 63 64 # endif SCOREFILE 65 66 # ifdef CHECKTIME 67 static int Num_checks; /* times we've gone over in checkout() */ 68 69 # ifndef WARNTIME 70 # define WARNTIME CHECKTIME 71 # endif 72 # endif CHECKTIME 73 74 /* 75 * init_check: 76 * Check out too see if it is proper to play the game now 77 */ 78 init_check() 79 { 80 # if defined(MAXLOAD) || defined(MAXUSERS) 81 if (too_much()) { 82 printf("Sorry, %s, but the system is too loaded now.\n", 83 Whoami); 84 printf("Try again later. Meanwhile, why not enjoy a%s %s?\n", 85 vowelstr(Fruit), Fruit); 86 if (author()) 87 printf("However, since you're a good guy, it's up to you\n"); 88 else 89 exit(1); 90 } 91 # endif defined(MAXLOAD) || defined(MAXUSERS) 92 } 93 94 /* 95 * open_score: 96 * Open up the score file for future use, and then 97 * setuid(getuid()) in case we are running setuid. 98 */ 99 open_score() 100 { 101 # ifdef SCOREFILE 102 Fd = open(SCOREFILE, 2); 103 # else SCOREFILE 104 Fd = -1; 105 # endif SCOREFILE 106 setuid(getuid()); 107 setgid(getgid()); 108 } 109 110 /* 111 * setup: 112 * Get starting setup for all games 113 */ 114 setup() 115 { 116 extern int auto_save(), quit(), endit(), tstp(); 117 # ifdef CHECKTIME 118 extern int heckout(); 119 # endif CHECKTIME 120 121 signal(SIGHUP, auto_save); 122 # ifndef DUMP 123 signal(SIGILL, auto_save); 124 signal(SIGTRAP, auto_save); 125 signal(SIGIOT, auto_save); 126 signal(SIGEMT, auto_save); 127 signal(SIGFPE, auto_save); 128 signal(SIGBUS, auto_save); 129 signal(SIGSEGV, auto_save); 130 signal(SIGSYS, auto_save); 131 signal(SIGTERM, auto_save); 132 # endif DUMP 133 134 signal(SIGINT, quit); 135 # ifndef DUMP 136 signal(SIGQUIT, endit); 137 # endif DUMP 138 # ifdef CHECKTIME 139 signal(SIGALRM, checkout); 140 alarm(CHECKTIME * 60); 141 Num_checks = 0; 142 # endif CHECKTIME 143 crmode(); /* Cbreak mode */ 144 noecho(); /* Echo off */ 145 nonl(); 146 # ifdef TIOCGLTC 147 getltchars(); /* get the local tty chars */ 148 # endif TIOCGLTC 149 } 150 151 /* 152 * getltchars: 153 * Get the local tty chars for later use 154 */ 155 getltchars() 156 { 157 # ifdef TIOCGLTC 158 ioctl(1, TIOCGLTC, &Ltc); 159 Got_ltc = TRUE; 160 Orig_dsusp = Ltc.t_dsuspc; 161 Ltc.t_dsuspc = Ltc.t_suspc; 162 ioctl(1, TIOCSLTC, &Ltc); 163 # endif TIOCGLTC 164 } 165 166 /* 167 * start_score: 168 * Start the scoring sequence 169 */ 170 start_score() 171 { 172 # ifdef CHECKTIME 173 signal(SIGALRM, SIG_IGN); /* NOSTRICT */ 174 # endif CHECKTIME 175 } 176 177 /* 178 * symlink: 179 * See if the file has a symbolic link 180 */ 181 symlink(sp) 182 char *sp; 183 { 184 # ifdef S_IFLNK 185 struct stat sbuf2; 186 187 if (lstat(sp, &sbuf2) < 0) 188 return FALSE; 189 else 190 return ((sbuf2.st_mode & S_IFMT) != S_IFREG); 191 # else S_IFLNK 192 return FALSE; 193 # endif S_IFLNK 194 } 195 196 # if defined(MAXLOAD) || defined(MAXUSERS) 197 /* 198 * too_much: 199 * See if the system is being used too much for this game 200 */ 201 too_much() 202 { 203 # ifdef MAXLOAD 204 double avec[3]; 205 # endif MAXLOAD 206 # ifdef MAXUSERS 207 register int cnt; 208 # endif MAXUSERS 209 210 # ifdef MAXLOAD 211 loadav(avec); 212 if (avec[1] > MAXLOAD) 213 return TRUE; 214 # endif MAXLOAD 215 # ifdef MAXUSERS 216 if (ucount() > MAXUSERS) 217 return TRUE; 218 # endif MAXUSERS 219 return FALSE; 220 } 221 222 /* 223 * author: 224 * See if a user is an author of the program 225 */ 226 author() 227 { 228 # ifdef MASTER 229 if (Wizard) 230 return TRUE; 231 # endif MASTER 232 switch (getuid()) 233 { 234 case -1: 235 return TRUE; 236 default: 237 return FALSE; 238 } 239 } 240 # endif defined(MAXLOAD) || defined(MAXUSERS) 241 242 # ifdef CHECKTIME 243 /* 244 * checkout: 245 * Check each CHECKTIME seconds to see if the load is too high 246 */ 247 checkout() 248 { 249 int checktime; 250 static char *msgs[] = { 251 "The load is too high to be playing. Please leave in %.2f minutes", 252 "Please save your game. You have %.2f minutes", 253 "Last warning. You have %.2f minutes to leave", 254 }; 255 256 signal(SIGALRM, checkout); 257 if (too_much()) { 258 if (author()) { 259 Num_checks = 1; 260 chmsg("The load is rather high, O exaulted one"); 261 } 262 else if (Num_checks++ == 3) 263 fatal("Sorry. You took too long. You are dead\n"); 264 checktime = (WARNTIME * 60) / Num_checks; 265 alarm(checktime); 266 chmsg(msgs[Num_checks - 1], ((double) checktime / 60.0)); 267 } 268 else { 269 if (Num_checks) { 270 Num_checks = 0; 271 chmsg("The load has dropped back down. You have a reprieve"); 272 } 273 alarm(CHECKTIME * 60); 274 } 275 } 276 277 /* 278 * chmsg: 279 * checkout()'s version of msg. If we are in the middle of a 280 * shell, do a printf instead of a msg to avoid the refresh. 281 */ 282 /* VARARGS1 */ 283 chmsg(fmt, arg) 284 char *fmt; 285 int arg; 286 { 287 if (!In_shell) 288 msg(fmt, arg); 289 else { 290 printf(fmt, arg); 291 putchar('\n'); 292 fflush(stdout); 293 } 294 } 295 # endif defined(MAXLOAD) || defined(MAXUSERS) 296 297 # ifdef LOADAV 298 /* 299 * loadav: 300 * Looking up load average in core (for system where the loadav() 301 * system call isn't defined 302 */ 303 304 # include <nlist.h> 305 306 struct nlist avenrun = { 307 "_avenrun" 308 }; 309 310 # ifndef NAMELIST 311 # define NAMELIST "/vmunix" 312 # endif 313 314 loadav(avg) 315 register double *avg; 316 { 317 register int kmem; 318 319 if ((kmem = open("/dev/kmem", 0)) < 0) 320 goto bad; 321 nlist(NAMELIST, &avenrun); 322 if (avenrun.n_type == 0) { 323 close(kmem); 324 bad: 325 avg[0] = 0.0; 326 avg[1] = 0.0; 327 avg[2] = 0.0; 328 return; 329 } 330 331 lseek(kmem, (long) avenrun.n_value, 0); 332 read(kmem, (char *) avg, 3 * sizeof (double)); 333 close(kmem); 334 } 335 # endif LOADAV 336 337 # ifdef UCOUNT 338 /* 339 * ucount: 340 * Count number of users on the system 341 */ 342 # include <utmp.h> 343 344 struct utmp buf; 345 346 ucount() 347 { 348 register struct utmp *up; 349 register FILE *utmp; 350 register int count; 351 352 if ((utmp = fopen(UTMP, "r")) == NULL) 353 return 0; 354 355 up = &buf; 356 count = 0; 357 358 while (fread(up, 1, sizeof (*up), utmp) > 0) 359 if (buf.ut_name[0] != '\0') 360 count++; 361 fclose(utmp); 362 return count; 363 } 364 # endif UCOUNT 365 366 /* 367 * lock_sc: 368 * lock the score file. If it takes too long, ask the user if 369 * they care to wait. Return TRUE if the lock is successful. 370 */ 371 lock_sc() 372 { 373 # ifdef SCOREFILE 374 # ifdef LOCK_EX 375 return (flock(Fd, LOCK_EX) >= 0); 376 # else LOCK_EX 377 register int cnt; 378 static struct stat sbuf; 379 380 over: 381 close(8); /* just in case there are no files left */ 382 if (creat(Lockfile, 0000) >= 0) 383 return TRUE; 384 for (cnt = 0; cnt < 5; cnt++) { 385 sleep(1); 386 if (creat(Lockfile, 0000) >= 0) 387 return TRUE; 388 } 389 if (stat(Lockfile, &sbuf) < 0) { 390 creat(Lockfile, 0000); 391 return TRUE; 392 } 393 if (time(NULL) - sbuf.st_mtime > 10) { 394 if (unlink(Lockfile) < 0) 395 return FALSE; 396 goto over; 397 } 398 else { 399 printf("The score file is very busy. Do you want to wait longer\n"); 400 printf("for it to become free so your score can get posted?\n"); 401 printf("If so, type \"y\"\n"); 402 fgets(Prbuf, MAXSTR, stdin); 403 if (Prbuf[0] == 'y') 404 for (;;) { 405 if (creat(Lockfile, 0000) >= 0) 406 return TRUE; 407 if (stat(Lockfile, &sbuf) < 0) { 408 creat(Lockfile, 0000); 409 return TRUE; 410 } 411 if (time(NULL) - sbuf.st_mtime > 10) 412 if (unlink(Lockfile) < 0) 413 return FALSE; 414 sleep(1); 415 } 416 else 417 return FALSE; 418 } 419 # endif LOCK_EX 420 # endif SCOREFILE 421 } 422 423 /* 424 * unlock_sc: 425 * Unlock the score file 426 */ 427 unlock_sc() 428 { 429 # ifdef SCOREFILE 430 # ifdef LOCK_EX 431 flock(Fd, LOCK_UN); 432 #else 433 unlink(Lockfile); 434 # endif 435 # endif 436 } 437