mirror of
https://codeberg.org/noisytoot/notnotdnethack.git
synced 2024-11-23 17:55:12 +00:00
516 lines
12 KiB
C
516 lines
12 KiB
C
/* SCCS Id: @(#)unixmain.c 3.4 1997/01/22 */
|
|
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
|
/* NetHack may be freely redistributed. See license for details. */
|
|
|
|
/* main.c - Unix NetHack */
|
|
|
|
#include "hack.h"
|
|
#include "dlb.h"
|
|
|
|
#include <sys/stat.h>
|
|
#include <signal.h>
|
|
#include <pwd.h>
|
|
#ifndef O_RDONLY
|
|
#include <fcntl.h>
|
|
#endif
|
|
|
|
extern struct passwd *getpwuid(uid_t);
|
|
extern struct passwd *getpwnam(const char *);
|
|
static void chdirx(const char *,boolean);
|
|
static boolean whoami(void);
|
|
#ifdef FUZZER_TIMEOUT
|
|
static void init_fuzzer_child(void);
|
|
#endif
|
|
static void process_options(int, char **);
|
|
|
|
#ifdef __linux__
|
|
extern void check_linux_console(void);
|
|
extern void init_linux_cons(void);
|
|
#endif
|
|
|
|
static void wd_message(void);
|
|
#ifdef WIZARD
|
|
static boolean wiz_error_flag = FALSE;
|
|
#endif
|
|
|
|
extern void check_utf8_console(void);
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
register int fd;
|
|
register char *dir;
|
|
boolean exact_username;
|
|
#ifdef SIMPLE_MAIL
|
|
char* e_simple = NULL;
|
|
#endif
|
|
#if defined(__APPLE__)
|
|
/* special hack to change working directory to a resource fork when
|
|
running from finder --sam */
|
|
#define MAC_PATH_VALUE ".app/Contents/MacOS/"
|
|
char mac_cwd[1024], *mac_exe = argv[0], *mac_tmp;
|
|
int arg0_len = strlen(mac_exe), mac_tmp_len, mac_lhs_len=0;
|
|
getcwd(mac_cwd, 1024);
|
|
if(mac_exe[0] == '/' && !strcmp(mac_cwd, "/")) {
|
|
if((mac_exe = strrchr(mac_exe, '/')))
|
|
mac_exe++;
|
|
else
|
|
mac_exe = argv[0];
|
|
mac_tmp_len = (strlen(mac_exe) * 2) + strlen(MAC_PATH_VALUE);
|
|
if(mac_tmp_len <= arg0_len) {
|
|
mac_tmp = malloc(mac_tmp_len + 1);
|
|
sprintf(mac_tmp, "%s%s%s", mac_exe, MAC_PATH_VALUE, mac_exe);
|
|
if(!strcmp(argv[0] + (arg0_len - mac_tmp_len), mac_tmp)) {
|
|
mac_lhs_len = (arg0_len - mac_tmp_len) + strlen(mac_exe) + 5;
|
|
if(mac_lhs_len > mac_tmp_len - 1)
|
|
mac_tmp = realloc(mac_tmp, mac_lhs_len);
|
|
strncpy(mac_tmp, argv[0], mac_lhs_len);
|
|
mac_tmp[mac_lhs_len] = '\0';
|
|
chdir(mac_tmp);
|
|
}
|
|
free(mac_tmp);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef SIMPLE_MAIL
|
|
/* figure this out early */
|
|
e_simple = nh_getenv("SIMPLEMAIL");
|
|
iflags.simplemail = (e_simple ? 1 : 0);
|
|
#endif
|
|
|
|
hname = argv[0];
|
|
hackpid = getpid();
|
|
(void) umask(0777 & ~FCMASK);
|
|
|
|
choose_windows(DEFAULT_WINDOW_SYS);
|
|
|
|
/*
|
|
* See if we must change directory to the playground.
|
|
* (Perhaps hack runs suid and playground is inaccessible
|
|
* for the player.)
|
|
* The environment variable HACKDIR is overridden by a
|
|
* -d command line option (must be the first option given)
|
|
*/
|
|
dir = nh_getenv("NETHACKDIR");
|
|
if (!dir) dir = nh_getenv("HACKDIR");
|
|
if(argc > 1) {
|
|
if (!strncmp(argv[1], "-d", 2) && argv[1][2] != 'e') {
|
|
/* avoid matching "-dec" for DECgraphics; since the man page
|
|
* says -d directory, hope nobody's using -desomething_else
|
|
*/
|
|
argc--;
|
|
argv++;
|
|
dir = argv[0]+2;
|
|
if(*dir == '=' || *dir == ':') dir++;
|
|
if(!*dir && argc > 1) {
|
|
argc--;
|
|
argv++;
|
|
dir = argv[0];
|
|
}
|
|
if(!*dir)
|
|
error("Flag -d must be followed by a directory name.");
|
|
}
|
|
if (argc > 1)
|
|
|
|
/*
|
|
* Now we know the directory containing 'record' and
|
|
* may do a prscore(). Exclude `-style' - it's a Qt option.
|
|
*/
|
|
if (!strncmp(argv[1], "-s", 2) && strncmp(argv[1], "-style", 6)) {
|
|
chdirx(dir,0);
|
|
prscore(argc, argv);
|
|
exit(EXIT_SUCCESS);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Change directories before we initialize the window system so
|
|
* we can find the tile file.
|
|
*/
|
|
chdirx(dir,1);
|
|
|
|
#ifdef __linux__
|
|
check_linux_console();
|
|
#endif
|
|
//check_utf8_console();
|
|
|
|
initoptions();
|
|
init_nhwindows(&argc,argv);
|
|
exact_username = whoami();
|
|
#ifdef __linux__
|
|
init_linux_cons();
|
|
#endif
|
|
|
|
/*
|
|
* It seems you really want to play.
|
|
*/
|
|
u.uhp = 1; /* prevent RIP on early quits */
|
|
|
|
process_options(argc, argv); /* command line options */
|
|
|
|
#ifdef DEF_PAGER
|
|
if(!(catmore = nh_getenv("HACKPAGER")) && !(catmore = nh_getenv("PAGER")))
|
|
catmore = DEF_PAGER;
|
|
#endif
|
|
#ifdef MAIL
|
|
getmailstatus();
|
|
#endif
|
|
/* #ifdef WIZARD
|
|
* if (wizard)
|
|
* Strcpy(plname, "wizard");
|
|
* else
|
|
* #endif */
|
|
if(!*plname /*|| !strncmp(plname, "player", 4)
|
|
|| !strncmp(plname, "games", 4)*/) {
|
|
askname();
|
|
} else if (exact_username) {
|
|
/* guard against user names with hyphens in them */
|
|
int len = strlen(plname);
|
|
/* append the current role, if any, so that last dash is ours */
|
|
if (++len < sizeof plname)
|
|
(void)strncat(strcat(plname, "-"),
|
|
pl_character, sizeof plname - len - 1);
|
|
}
|
|
plnamesuffix(); /* strip suffix from name; calls askname() */
|
|
/* again if suffix was whole name */
|
|
/* accepts any suffix */
|
|
#ifdef FUZZER_TIMEOUT
|
|
if(iflags.debug_fuzzer){
|
|
init_fuzzer_child();
|
|
}
|
|
#endif
|
|
#ifdef WIZARD
|
|
if(!wizard) {
|
|
#endif
|
|
/*
|
|
* check for multiple games under the same name
|
|
* (if !locknum) or check max nr of players (otherwise)
|
|
*/
|
|
(void) signal(SIGQUIT,SIG_IGN);
|
|
(void) signal(SIGINT,SIG_IGN);
|
|
(void) signal(SIGHUP,SIG_IGN);
|
|
if(!locknum)
|
|
Sprintf(lock, "%d%s", (int)getuid(), plname);
|
|
getlock();
|
|
#ifdef WIZARD
|
|
} else {
|
|
Sprintf(lock, "%d%s", (int)getuid(), plname);
|
|
getlock();
|
|
}
|
|
#endif /* WIZARD */
|
|
|
|
(void) signal(SIGHUP, (SIG_RET_TYPE) hangup);
|
|
#ifdef SIGXCPU
|
|
(void) signal(SIGXCPU, (SIG_RET_TYPE) hangup);
|
|
#endif
|
|
|
|
dlb_init(); /* must be before newgame() */
|
|
|
|
/*
|
|
* Initialization of the boundaries of the mazes
|
|
* Both boundaries have to be even.
|
|
*/
|
|
x_maze_max = COLNO-1;
|
|
if (x_maze_max % 2)
|
|
x_maze_max--;
|
|
y_maze_max = ROWNO-1;
|
|
if (y_maze_max % 2)
|
|
y_maze_max--;
|
|
|
|
/*
|
|
* Initialize the vision system. This must be before mklev() on a
|
|
* new game or before a level restore on a saved game.
|
|
*/
|
|
vision_init();
|
|
|
|
display_gamewindows();
|
|
|
|
if ((fd = restore_saved_game()) >= 0) {
|
|
#ifdef WIZARD
|
|
/* Since wizard is actually flags.debug, restoring might
|
|
* overwrite it.
|
|
*/
|
|
boolean remember_wiz_mode = wizard;
|
|
#endif
|
|
const char *fq_save = fqname(SAVEF, SAVEPREFIX, 1);
|
|
|
|
(void) chmod(fq_save,0); /* disallow parallel restores */
|
|
(void) signal(SIGINT, (SIG_RET_TYPE) done1);
|
|
#ifdef NEWS
|
|
if(iflags.news) {
|
|
display_file(NEWS, FALSE);
|
|
iflags.news = FALSE; /* in case dorecover() fails */
|
|
}
|
|
#endif
|
|
pline("Restoring save file...");
|
|
mark_synch(); /* flush output */
|
|
if(!dorecover(fd))
|
|
goto not_recovered;
|
|
#ifdef WIZARD
|
|
if(!wizard && remember_wiz_mode) wizard = TRUE;
|
|
#endif
|
|
check_special_room(FALSE);
|
|
wd_message();
|
|
|
|
if (discover || wizard) {
|
|
if(yn("Do you want to keep the save file?") == 'n')
|
|
(void) delete_savefile();
|
|
else {
|
|
(void) chmod(fq_save,FCMASK); /* back to readable */
|
|
compress(fq_save);
|
|
}
|
|
}
|
|
flags.move = 0;
|
|
} else {
|
|
not_recovered:
|
|
player_selection();
|
|
newgame();
|
|
wd_message();
|
|
|
|
flags.move = 0;
|
|
set_wear();
|
|
(void) pickup(1);
|
|
}
|
|
|
|
moveloop();
|
|
exit(EXIT_SUCCESS);
|
|
/*NOTREACHED*/
|
|
return(0);
|
|
}
|
|
|
|
#ifdef FUZZER_TIMEOUT
|
|
|
|
static void
|
|
init_fuzzer_child(void){
|
|
pid_t pid = getpid();
|
|
pid_t child_pid = fork();
|
|
int status;
|
|
if(!child_pid){
|
|
while(TRUE){
|
|
sleep(FUZZER_TIMEOUT);
|
|
//check shared memory, if the timestamp is in date, go back to sleep, otherwise raise a SIGHUP to the parent and exit
|
|
}
|
|
|
|
} else {
|
|
waitpid(child_pid, &status, WNOHANG);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static void
|
|
process_options(int argc, char *argv[])
|
|
{
|
|
int i;
|
|
|
|
|
|
/*
|
|
* Process options.
|
|
*/
|
|
while(argc > 1 && argv[1][0] == '-'){
|
|
argv++;
|
|
argc--;
|
|
switch(argv[0][1]){
|
|
case 'F':
|
|
iflags.debug_fuzzer = TRUE;
|
|
break;
|
|
case 'D':
|
|
#ifdef WIZARD
|
|
wizard = TRUE;
|
|
break;
|
|
#endif
|
|
case 'X':
|
|
discover = TRUE;
|
|
break;
|
|
#ifdef NEWS
|
|
case 'n':
|
|
iflags.news = FALSE;
|
|
break;
|
|
#endif
|
|
case 'u':
|
|
if(argv[0][2])
|
|
(void) strncpy(plname, argv[0]+2, sizeof(plname)-1);
|
|
else if(argc > 1) {
|
|
argc--;
|
|
argv++;
|
|
(void) strncpy(plname, argv[0], sizeof(plname)-1);
|
|
} else
|
|
raw_print("Player name expected after -u");
|
|
break;
|
|
case 'I':
|
|
case 'i':
|
|
if (!strncmpi(argv[0]+1, "IBM", 3))
|
|
switch_graphics(IBM_GRAPHICS);
|
|
break;
|
|
/* case 'D': */
|
|
case 'd':
|
|
if (!strncmpi(argv[0]+1, "DEC", 3))
|
|
switch_graphics(DEC_GRAPHICS);
|
|
break;
|
|
case 'p': /* profession (role) */
|
|
if (argv[0][2]) {
|
|
if ((i = str2role(&argv[0][2])) >= 0)
|
|
flags.initrole = i;
|
|
} else if (argc > 1) {
|
|
argc--;
|
|
argv++;
|
|
if ((i = str2role(argv[0])) >= 0)
|
|
flags.initrole = i;
|
|
}
|
|
break;
|
|
case 'r': /* race */
|
|
if (argv[0][2]) {
|
|
if ((i = str2race(&argv[0][2])) >= 0)
|
|
flags.initrace = i;
|
|
} else if (argc > 1) {
|
|
argc--;
|
|
argv++;
|
|
if ((i = str2race(argv[0])) >= 0)
|
|
flags.initrace = i;
|
|
}
|
|
break;
|
|
case '@':
|
|
flags.randomall = 1;
|
|
break;
|
|
default:
|
|
if ((i = str2role(&argv[0][1])) >= 0) {
|
|
flags.initrole = i;
|
|
break;
|
|
}
|
|
/* else raw_printf("Unknown option: %s", *argv); */
|
|
}
|
|
}
|
|
|
|
if(argc > 1)
|
|
locknum = atoi(argv[1]);
|
|
#ifdef MAX_NR_OF_PLAYERS
|
|
if(!locknum || locknum > MAX_NR_OF_PLAYERS)
|
|
locknum = MAX_NR_OF_PLAYERS;
|
|
#endif
|
|
}
|
|
|
|
static void
|
|
chdirx(const char *dir, boolean wr)
|
|
{
|
|
if (dir /* User specified directory? */
|
|
# ifdef HACKDIR
|
|
&& strcmp(dir, HACKDIR) /* and not the default? */
|
|
# endif
|
|
) {
|
|
# ifdef SECURE
|
|
(void) setgid(getgid());
|
|
(void) setuid(getuid()); /* Ron Wessels */
|
|
# endif
|
|
} else {
|
|
/* non-default data files is a sign that scores may not be
|
|
* compatible, or perhaps that a binary not fitting this
|
|
* system's layout is being used.
|
|
*/
|
|
# ifdef VAR_PLAYGROUND
|
|
int len = strlen(VAR_PLAYGROUND);
|
|
|
|
fqn_prefix[SCOREPREFIX] = (char *)alloc(len+2);
|
|
Strcpy(fqn_prefix[SCOREPREFIX], VAR_PLAYGROUND);
|
|
if (fqn_prefix[SCOREPREFIX][len-1] != '/') {
|
|
fqn_prefix[SCOREPREFIX][len] = '/';
|
|
fqn_prefix[SCOREPREFIX][len+1] = '\0';
|
|
}
|
|
# endif
|
|
}
|
|
|
|
# ifdef HACKDIR
|
|
if (dir == (const char *)0)
|
|
dir = HACKDIR;
|
|
# endif
|
|
|
|
if (dir && chdir(dir) < 0) {
|
|
perror(dir);
|
|
error("Cannot chdir to %s.", dir);
|
|
}
|
|
|
|
/* warn the player if we can't write the record file */
|
|
/* perhaps we should also test whether . is writable */
|
|
/* unfortunately the access system-call is worthless */
|
|
if (wr) {
|
|
# ifdef VAR_PLAYGROUND
|
|
fqn_prefix[LEVELPREFIX] = fqn_prefix[SCOREPREFIX];
|
|
fqn_prefix[SAVEPREFIX] = fqn_prefix[SCOREPREFIX];
|
|
fqn_prefix[BONESPREFIX] = fqn_prefix[SCOREPREFIX];
|
|
fqn_prefix[LOCKPREFIX] = fqn_prefix[SCOREPREFIX];
|
|
fqn_prefix[TROUBLEPREFIX] = fqn_prefix[SCOREPREFIX];
|
|
# endif
|
|
check_recordfile(dir);
|
|
}
|
|
}
|
|
|
|
static boolean
|
|
whoami(void) {
|
|
/*
|
|
* Who am i? Algorithm: 1. Use name as specified in NETHACKOPTIONS
|
|
* 2. Use $USER or $LOGNAME (if 1. fails)
|
|
* 3. Use getlogin() (if 2. fails)
|
|
* The resulting name is overridden by command line options.
|
|
* If everything fails, or if the resulting name is some generic
|
|
* account like "games", "play", "player", "hack" then eventually
|
|
* we'll ask him.
|
|
* Note that we trust the user here; it is possible to play under
|
|
* somebody else's name.
|
|
*/
|
|
register char *s;
|
|
|
|
if (*plname) return FALSE;
|
|
if(/* !*plname && */ (s = nh_getenv("USER")))
|
|
(void) strncpy(plname, s, sizeof(plname)-1);
|
|
if(!*plname && (s = nh_getenv("LOGNAME")))
|
|
(void) strncpy(plname, s, sizeof(plname)-1);
|
|
if(!*plname && (s = getlogin()))
|
|
(void) strncpy(plname, s, sizeof(plname)-1);
|
|
return TRUE;
|
|
}
|
|
|
|
#ifdef PORT_HELP
|
|
void
|
|
port_help(void)
|
|
{
|
|
/*
|
|
* Display unix-specific help. Just show contents of the helpfile
|
|
* named by PORT_HELP.
|
|
*/
|
|
display_file(PORT_HELP, TRUE);
|
|
}
|
|
#endif
|
|
|
|
static void
|
|
wd_message(void)
|
|
{
|
|
#ifdef WIZARD
|
|
if (wiz_error_flag) {
|
|
pline("Only user \"%s\" may access debug (wizard) mode.",
|
|
WIZARD);
|
|
pline("Entering discovery mode instead.");
|
|
} else
|
|
#endif
|
|
if (discover)
|
|
You("are in non-scoring discovery mode.");
|
|
}
|
|
|
|
/*
|
|
* Add a slash to any name not ending in /. There must
|
|
* be room for the /
|
|
*/
|
|
void
|
|
append_slash(char *name)
|
|
{
|
|
char *ptr;
|
|
|
|
if (!*name)
|
|
return;
|
|
ptr = name + (strlen(name) - 1);
|
|
if (*ptr != '/') {
|
|
*++ptr = '/';
|
|
*++ptr = '\0';
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*unixmain.c*/
|