rogue

Ken Arnold's Rogue
git clone https://git.woozle.org/neale/rogue.git

Neale Pickett  ·  2013-07-18

find.c

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