4.4BSD/usr/src/old/rogue/machdep.c

Compare this file to the similar file:
Show the results in this format:

/*
 * Copyright (c) 1980 Regents of the University of California.
 * All rights reserved.  The Berkeley software License Agreement
 * specifies the terms and conditions for redistribution.
 */

#ifndef lint
char copyright[] =
"@(#) Copyright (c) 1980 Regents of the University of California.\n\
 All rights reserved.\n";
#endif not lint

#ifndef lint
static char sccsid[] = "@(#)machdep.c	5.3 (Berkeley) 5/29/89";
#endif not lint

/*
 * Various installation dependent routines
 *
 * $Revision: 1.7 $, $Date: 85/04/05 11:33:30 $
 */

/*
 * The various tuneable defines are:
 *
 *	SCOREFILE	Where/if the score file should live.
 *	ALLSCORES	Score file is top ten scores, not top ten
 *			players.  This is only useful when only a few
 *			people will be playing; otherwise the score file
 *			gets hogged by just a few people.
 *	NUMSCORES	Number of scores in the score file (default 10).
 *	NUMNAME		String version of NUMSCORES (first character
 *			should be capitalized) (default "Ten").
 *	MAXLOAD		What (if any) the maximum load average should be
 *			when people are playing.
 *		LOADAV		Should it use 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 it use it's own routine to count
 *				users?
 *		UTMP		If so, where does the user list hide?
 *	CHECKTIME	How often/if it should check during the game
 *			for high load average.
 *	WARNTIME	How much time between warnings when load gets
 *			too high (if not defined, it is the same as
 *			CHECKTIME).
 */

# include	<curses.h>
# include	"machdep.h"
# include	<signal.h>
# include	<sys/types.h>
# include	<sys/stat.h>
# include	<sys/file.h>

# undef LOADAV		/* use getloadavg() by default */

# ifdef	SCOREFILE

static char	*Lockfile = "/tmp/.fredlock";

# ifndef	NUMSCORES
# 	define	NUMSCORES	10
# 	define	NUMNAME		"Ten"
# endif		NUMSCORES

unsigned int	Numscores = NUMSCORES;

char		*Numname = NUMNAME;

# ifdef ALLSCORES
bool	Allscore = TRUE;
# else	ALLSCORES
bool	Allscore = FALSE;
# endif ALLSCORES

# endif	SCOREFILE

# ifdef	CHECKTIME
static int	Num_checks;	/* times we've gone over in checkout() */

# ifndef WARNTIME
# define	WARNTIME	CHECKTIME
# endif
# endif	CHECKTIME

/*
 * init_check:
 *	Check out too see if it is proper to play the game now
 */
init_check()
{
# if	defined(MAXLOAD) || defined(MAXUSERS)
	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);
	}
# endif	defined(MAXLOAD) || defined(MAXUSERS)
}

/*
 * open_score:
 *	Open up the score file for future use, and then
 *	setuid(getuid()) in case we are running setuid.
 */
open_score()
{
# ifdef SCOREFILE
	Fd = open(SCOREFILE, 2);
# else	SCOREFILE
	Fd = -1;
# endif	SCOREFILE
	setuid(getuid());
	setgid(getgid());
}

/*
 * setup:
 *	Get starting setup for all games
 */
setup()
{
	extern int	auto_save(), quit(), endit(), tstp();
# ifdef CHECKTIME
	extern int 	heckout();
# endif	CHECKTIME

	signal(SIGHUP, auto_save);
# ifndef DUMP
	signal(SIGILL, auto_save);
	signal(SIGTRAP, auto_save);
	signal(SIGIOT, auto_save);
	signal(SIGEMT, auto_save);
	signal(SIGFPE, auto_save);
	signal(SIGBUS, auto_save);
	signal(SIGSEGV, auto_save);
	signal(SIGSYS, auto_save);
	signal(SIGTERM, auto_save);
# endif	DUMP

	signal(SIGINT, quit);
# ifndef DUMP
	signal(SIGQUIT, endit);
# endif	DUMP
# ifdef CHECKTIME
	signal(SIGALRM, checkout);
	alarm(CHECKTIME * 60);
	Num_checks = 0;
# endif	CHECKTIME
	crmode();				/* Cbreak mode */
	noecho();				/* Echo off */
	nonl();
# ifdef TIOCGLTC
	getltchars();			/* get the local tty chars */
# endif	TIOCGLTC
}

/*
 * getltchars:
 *	Get the local tty chars for later use
 */
getltchars()
{
# ifdef TIOCGLTC
	ioctl(1, TIOCGLTC, &Ltc);
	Got_ltc = TRUE;
	Orig_dsusp = Ltc.t_dsuspc;
	if (Orig_dsusp == CTRL(Y)) {
		Ltc.t_dsuspc = Ltc.t_suspc;
		ioctl(1, TIOCSLTC, &Ltc);
	}
# endif	TIOCGLTC
}

/*
 * start_score:
 *	Start the scoring sequence
 */
start_score()
{
# ifdef CHECKTIME
	signal(SIGALRM, SIG_IGN);	/* NOSTRICT */
# endif	CHECKTIME
}

/*
 * symlink:
 *	See if the file has a symbolic link
 */
symlink(sp)
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	S_IFLNK
	return FALSE;
# endif	S_IFLNK
}

# if	defined(MAXLOAD) || defined(MAXUSERS)
/*
 * too_much:
 *	See if the system is being used too much for this game
 */
too_much()
{
# ifdef MAXLOAD
	double		avec[3];
# endif	MAXLOAD
# ifdef	MAXUSERS
	register int	cnt;
# endif	MAXUSERS

# ifdef MAXLOAD
# ifdef LOADAV
	loadav(avec);
# else
	if (getloadavg(avec, sizeof(avec)/sizeof(avec[0])) < 0)
		avec[0] = avec[1] = avec[2] = 0.0;
# endif
	if (avec[1] > MAXLOAD)
		return TRUE;
# endif	MAXLOAD
# ifdef MAXUSERS
	if (ucount() > MAXUSERS)
		return TRUE;
# endif	MAXUSERS
	return FALSE;
}

/*
 * author:
 *	See if a user is an author of the program
 */
author()
{
# ifdef MASTER
	if (Wizard)
		return TRUE;
# endif	MASTER
	switch (getuid())
	{
	  case -1:
		return TRUE;
	  default:
		return FALSE;
	}
}
# endif	defined(MAXLOAD) || defined(MAXUSERS)

# ifdef	CHECKTIME
/*
 * checkout:
 *	Check each CHECKTIME seconds to see if the load is too high
 */
checkout()
{
	int		checktime;
	static char	*msgs[] = {
		"The load is too high to be playing.  Please leave in %.2f minutes",
		"Please save your game.  You have %.2f minutes",
		"Last warning.  You have %.2f minutes to leave",
	};

	signal(SIGALRM, checkout);
	if (too_much()) {
		if (author()) {
			Num_checks = 1;
			chmsg("The load is rather high, O exaulted one");
		}
		else if (Num_checks++ == 3)
			fatal("Sorry.  You took too long.  You are dead\n");
		checktime = (WARNTIME * 60) / Num_checks;
		alarm(checktime);
		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");
		}
		alarm(CHECKTIME * 60);
	}
}

/*
 * 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.
 */
/* VARARGS1 */
chmsg(fmt, arg)
char	*fmt;
int	arg;
{
	if (!In_shell)
		msg(fmt, arg);
	else {
		printf(fmt, arg);
		putchar('\n');
		fflush(stdout);
	}
}
# endif	defined(MAXLOAD) || defined(MAXUSERS)

# ifdef	LOADAV
/*
 * loadav:
 *	Looking up load average in core (for system where the loadav()
 *	system call isn't defined
 */

# include	<nlist.h>

struct nlist	avenrun = {
	    "_avenrun"
};

# ifndef	NAMELIST
# define	NAMELIST	"/vmunix"
# endif

loadav(avg)
register double	*avg;
{
	register int	kmem;

	if ((kmem = open("/dev/kmem", 0)) < 0)
		goto bad;
	nlist(NAMELIST, &avenrun);
	if (avenrun.n_type == 0) {
		close(kmem);
		bad:
		avg[0] = 0.0;
		avg[1] = 0.0;
		avg[2] = 0.0;
		return;
	}

	lseek(kmem, (long) avenrun.n_value, 0);
	read(kmem, (char *) avg, 3 * sizeof (double));
	close(kmem);
}
# endif	LOADAV

# ifdef UCOUNT
/*
 * ucount:
 *	Count number of users on the system
 */
# include	<utmp.h>

struct utmp	buf;

ucount()
{
	register struct utmp	*up;
	register FILE		*utmp;
	register int		count;

	if ((utmp = fopen(UTMP, "r")) == NULL)
		return 0;

	up = &buf;
	count = 0;

	while (fread(up, 1, sizeof (*up), utmp) > 0)
		if (buf.ut_name[0] != '\0')
			count++;
	fclose(utmp);
	return count;
}
# endif	UCOUNT

/*
 * 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.
 */
lock_sc()
{
# ifdef SCOREFILE
# ifdef	LOCK_EX
	return (flock(Fd, LOCK_EX) >= 0);
# else	LOCK_EX
	register int		cnt;
	static struct stat	sbuf;

over:
	close(8);	/* just in case there are no files left */
	if (creat(Lockfile, 0000) >= 0)
		return TRUE;
	for (cnt = 0; cnt < 5; cnt++) {
		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 (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 (unlink(Lockfile) < 0)
						return FALSE;
				sleep(1);
			}
		else
			return FALSE;
	}
# endif	LOCK_EX
# endif	SCOREFILE
}

/*
 * unlock_sc:
 *	Unlock the score file
 */
unlock_sc()
{
# ifdef SCOREFILE
# ifdef	LOCK_EX
	flock(Fd, LOCK_UN);
#else
	unlink(Lockfile);
# endif
# endif
}