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