Mercurial > hg > early-roguelike
view rogue4/mach_dep.c @ 111:7f8f43943b1f
Fix some terribly depressing corruption during restore.
In rogue5/state.c, rs_read_daemons() zeroes out the argument and delay
if the daemon slot is empty. Unfortunately that code ended up on the
wrong side of the brace that closes the for loop, so instead of running
after each daemon, it got run once after the loop exited, when the
index was of course out of bounds.
This tended to manifest, when compiled with -O2, by overwriting hw and
setting it to NULL. When inventory() next ran, hw would be passed to
wgetch(), which returns ERR when it gets a NULL argument. This made
md_readchar() think something was wrong and autosave the game.
Upon investigation, rogue3 was found to commit the same mistake.
rogue4 and srogue don't zero the data. arogue5 already does it
properly.
Someday I am going to run all this through Valgrind. Someday when I
am a kinder person who will not be driven to invoke hordes of trolls
and centaurs upon the original authors.
author | John "Elwin" Edwards |
---|---|
date | Wed, 08 Jan 2014 16:44:16 -0500 |
parents | 5926ec314fd4 |
children | 1b73a8641b37 |
line wrap: on
line source
/* * 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 "rogue.h" int num_checks; /* times we've gone over in checkout() */ #ifdef SCOREFILE #ifdef LOCKFILE static char *lockfile = LOCKFILE; #endif #endif /* * init_check: * Check out too see if it is proper to play the game now */ init_check() { 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. */ open_score() { #ifdef SCOREFILE fd = open(SCOREFILE, O_RDWR | O_CREAT, 0666 ); #else fd = -1; #endif if (!use_savedir) md_normaluser(); return; } void open_log(void) { #ifdef LOGFILE lfd = open(LOGFILE, O_WRONLY | O_APPEND | O_CREAT, 0666); #else lfd = -1; #endif return; } /* * setup: * Get starting setup for all games */ setup() { void auto_save(), quit(), endit(), tstp(); #ifdef CHECKTIME int checkout(); #endif /* * 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 */ start_score() { #ifdef SIGALRM signal(SIGALRM, SIG_IGN); #endif } /* * issymlink: * See if the file has a symbolic link */ issymlink(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 return FALSE; #endif } /* * too_much: * See if the system is being used too much for this game */ too_much() { #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 */ author() { #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"); } else if (num_checks++ == 3) fatal("Sorry. You took to long. You are dead\n"); #ifdef CHECKTIME checktime = (CHECKTIME * 60) / num_checks; #endif #ifdef SIGALRM alarm(checktime); #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"); } #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. */ chmsg(fmt, arg) 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. */ lock_sc() { #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 */ unlock_sc() { #ifdef SCOREFILE #ifdef LOCKFILE md_unlink(lockfile); #endif #endif } /* * flush_type: * Flush typeahead for traps, etc. */ flush_type() { flushinp(); }