/*
* Various installation dependent routines
*
* @(#)mach_dep.c 4.23 (Berkeley) 5/19/82
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980, 1981, 1982 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
/*
* The various tuneable defines are:
*
* SCOREFILE Where/if the score file should live.
* MAXLOAD What (if any) the maximum load average should be
* when people are playing. If defined, then
* LOADAV Should rogue define it's own routine to
* get the load average?
* NAMELIST If so, where does the system namelist hide?
* MAXUSERS What (if any) the maximum user count should be
* when people are playing. If defined, then
* UCOUNT Should rogue define it's own routine to
* count users?
* UTMP If so, where does the user list hide?
* CHECKTIME How often/if rogue should check during the game
* for high load average.
*/
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
#include <curses.h>
#include <time.h>
#include <signal.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#ifdef CHECKTIME
#include <unistd.h>
#endif
#include "rogue.h"
int num_checks; /* times we've gone over in checkout() */
#ifdef SCOREFILE
#ifdef LOCKFILE
static char *lockfile = LOCKFILE;
#endif
#endif
int too_much(void);
bool author(void);
void checkout(int s);
void chmsg(char *fmt, int arg);
/*
* init_check:
* Check out too see if it is proper to play the game now
*/
void
init_check(void)
{
if (too_much())
{
printf("Sorry, %s, but the system is too loaded now.\n", whoami);
printf("Try again later. Meanwhile, why not enjoy a%s %s?\n",
vowelstr(fruit), fruit);
if (author())
printf("However, since you're a good guy, it's up to you\n");
else
exit(1);
}
}
/*
* open_score:
* Open up the score file for future use, and then
* setuid(getuid()) in case we are running setuid.
*/
void
open_score(void)
{
#ifdef SCOREFILE
score_file = fopen(SCOREFILE, "r+");
if ((score_file == NULL) && (errno == ENOENT)) {
score_file = fopen(SCOREFILE, "w+");
}
#else
score_file = NULL;
#endif
if (!use_savedir)
md_normaluser();
return;
}
void
open_log(void)
{
#ifdef LOGFILE
log_file = fopen(LOGFILE, "a");
#else
log_file = NULL;
#endif
return;
}
/*
* setup:
* Get starting setup for all games
*/
void
setup(void)
{
void auto_save(), quit(), endit(), tstp();
/*
* make sure that large terminals don't overflow the bounds
* of the program
*/
if (LINES > MAXLINES)
LINES = MAXLINES;
if (COLS > MAXCOLS)
COLS = MAXCOLS;
#ifdef SIGHUP
signal(SIGHUP, auto_save);
#endif
#ifndef DUMP
signal(SIGILL, auto_save);
#ifdef SIGTRAP
signal(SIGTRAP, auto_save);
#endif
#ifdef SIGIOT
signal(SIGIOT, auto_save);
#endif
#ifdef SIGEMT
signal(SIGEMT, auto_save);
#endif
signal(SIGFPE, auto_save);
#ifdef SIGBUS
signal(SIGBUS, auto_save);
#endif
/* Don't bother saving a game that segfaulted. */
signal(SIGSEGV, SIG_DFL);
#ifdef SIGSYS
signal(SIGSYS, auto_save);
#endif
signal(SIGTERM, auto_save);
#endif
signal(SIGINT, quit);
#ifndef DUMP
#ifdef SIGQUIT
signal(SIGQUIT, endit);
#endif
#endif
#ifdef CHECKTIME
signal(SIGALRM, checkout);
alarm(CHECKTIME * 60);
num_checks = 0;
#endif
nonl();
crmode(); /* Cbreak mode */
noecho(); /* Echo off */
}
/*
* start_score:
* Start the scoring sequence
*/
void
start_score(void)
{
#ifdef SIGALRM
signal(SIGALRM, SIG_IGN);
#endif
}
/*
* issymlink:
* See if the file has a symbolic link
*/
bool
issymlink(char *sp)
{
#ifdef S_IFLNK
struct stat sbuf2;
if (lstat(sp, &sbuf2) < 0)
return FALSE;
else
return ((sbuf2.st_mode & S_IFMT) != S_IFREG);
#else
return FALSE;
#endif
}
/*
* too_much:
* See if the system is being used too much for this game
*/
int
too_much(void)
{
#ifdef MAXLOAD
double avec[3];
if (md_getloadavg(avec) == 0)
if (avec[2] > (MAXLOAD / 10.0))
return(1);
#endif
#ifdef MAXUSERS
if (md_ucount() > MAXUSERS)
return(1) ;
#endif
return(0);
}
/*
* author:
* See if a user is an author of the program
*/
bool
author(void)
{
#ifdef WIZARD
if (wizard)
return TRUE;
#endif
switch (md_getuid())
{
case 0:
return TRUE;
default:
return FALSE;
}
}
/*
* checkout:
* Check each CHECKTIME seconds to see if the load is too high
*/
void
checkout(int s)
{
static char *msgs[] = {
"The load is too high to be playing. Please leave in %0.1f minutes",
"Please save your game. You have %0.1f minutes",
"Last warning. You have %0.1f minutes to leave",
};
int checktime = 0;
#ifdef SIGALRM
signal(SIGALRM, checkout);
#endif
if (too_much())
{
if (author())
{
num_checks = 1;
chmsg("The load is rather high, O exaulted one", 0);
}
else if (num_checks++ == 3)
fatal("Sorry. You took to long. You are dead\n");
#ifdef CHECKTIME
checktime = (CHECKTIME * 60) / num_checks;
#ifdef SIGALRM
alarm(checktime);
#endif
#endif
chmsg(msgs[num_checks - 1], ((double) checktime / 60.0));
}
else
{
if (num_checks)
{
num_checks = 0;
chmsg("The load has dropped back down. You have a reprieve", 0);
}
#ifdef CHECKTIME
#ifdef SIGALRM
alarm(CHECKTIME * 60);
#endif
#endif
}
}
/*
* chmsg:
* checkout()'s version of msg. If we are in the middle of a
* shell, do a printf instead of a msg to avoid the refresh.
*/
void
chmsg(char *fmt, int arg)
{
if (in_shell)
{
printf(fmt, arg);
putchar('\n');
fflush(stdout);
}
else
msg(fmt, arg);
}
/*
* lock_sc:
* lock the score file. If it takes too long, ask the user if
* they care to wait. Return TRUE if the lock is successful.
*/
bool
lock_sc(void)
{
#ifdef SCOREFILE
#ifdef LOCKFILE
register int cnt;
static struct stat sbuf;
over:
if (creat(lockfile, 0000) > 0)
return TRUE;
for (cnt = 0; cnt < 5; cnt++)
{
md_sleep(1);
if (creat(lockfile, 0000) > 0)
return TRUE;
}
if (stat(lockfile, &sbuf) < 0)
{
creat(lockfile, 0000);
return TRUE;
}
if (time(NULL) - sbuf.st_mtime > 10)
{
if (md_unlink(lockfile) < 0)
return FALSE;
goto over;
}
else
{
printf("The score file is very busy. Do you want to wait longer\n");
printf("for it to become free so your score can get posted?\n");
printf("If so, type \"y\"\n");
fgets(prbuf, MAXSTR, stdin);
if (prbuf[0] == 'y')
for (;;)
{
if (creat(lockfile, 0000) > 0)
return TRUE;
if (stat(lockfile, &sbuf) < 0)
{
creat(lockfile, 0000);
return TRUE;
}
if (time(NULL) - sbuf.st_mtime > 10)
{
if (md_unlink(lockfile) < 0)
return FALSE;
}
md_sleep(1);
}
else
return FALSE;
}
#endif
#endif
return TRUE;
}
/*
* unlock_sc:
* Unlock the score file
*/
void
unlock_sc(void)
{
#ifdef SCOREFILE
#ifdef LOCKFILE
md_unlink(lockfile);
#endif
#endif
}
/*
* flush_type:
* Flush typeahead for traps, etc.
*/
void
flush_type(void)
{
flushinp();
}