1 /*	SCCS Id: @(#)unixmain.c	3.3	97/01/22	*/
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed.  See license for details. */
4 
5 /* main.c - Unix NetHack */
6 
7 #include "hack.h"
8 #include "dlb.h"
9 
10 #include <sys/stat.h>
11 #include <signal.h>
12 #include <pwd.h>
13 #ifndef O_RDONLY
14 #include <fcntl.h>
15 #endif
16 
17 #if !defined(_BULL_SOURCE) && !defined(__sgi) && !defined(_M_UNIX)
18 # if !defined(SUNOS4) && !(defined(ULTRIX) && defined(__GNUC__))
19 #  if defined(POSIX_TYPES) || defined(SVR4) || defined(HPUX)
20 extern struct passwd *FDECL(getpwuid,(uid_t));
21 #  else
22 extern struct passwd *FDECL(getpwuid,(int));
23 #  endif
24 # endif
25 #endif
26 extern struct passwd *FDECL(getpwnam,(const char *));
27 #ifdef CHDIR
28 static void FDECL(chdirx, (const char *,BOOLEAN_P));
29 #endif /* CHDIR */
30 static boolean NDECL(whoami);
31 static void FDECL(process_options, (int, char **));
32 
33 #ifdef _M_UNIX
34 extern void NDECL(check_sco_console);
35 extern void NDECL(init_sco_cons);
36 #endif
37 #ifdef __linux__
38 extern void NDECL(check_linux_console);
39 extern void NDECL(init_linux_cons);
40 #endif
41 
42 static void NDECL(wd_message);
43 #ifdef WIZARD
44 static boolean wiz_error_flag = FALSE;
45 #endif
46 
47 int
main(argc,argv)48 main(argc,argv)
49 int argc;
50 char *argv[];
51 {
52 	register int fd;
53 #ifdef CHDIR
54 	register char *dir;
55 #endif
56 	boolean exact_username;
57 
58 	/* printf("DEBUG 1: Starting NetHack - Falcon's Eye...\n"); */
59 	hname = argv[0];
60 	hackpid = getpid();
61 	(void) umask(0777 & ~FCMASK);
62 
63         /* printf("DEBUG 2: Choosing window port...\n"); */
64 	choose_windows(DEFAULT_WINDOW_SYS);
65 
66         /* printf("DEBUG 3: Window port chosen.\n"); */
67 #ifdef CHDIR			/* otherwise no chdir() */
68 	/*
69 	 * See if we must change directory to the playground.
70 	 * (Perhaps hack runs suid and playground is inaccessible
71 	 *  for the player.)
72 	 * The environment variable HACKDIR is overridden by a
73 	 *  -d command line option (must be the first option given)
74 	 */
75 	/* printf("DEBUG 4: Getting env variable NETHACKDIR ...\n"); */
76 	dir = nh_getenv("NETHACKDIR");
77 	if (!dir) dir = nh_getenv("HACKDIR");
78 	/* printf("DEBUG 5: NETHACKDIR is [%s].\n", dir); */
79 #endif
80 	/* printf("DEBUG 6: Checking for command line arguments...\n"); */
81 	if(argc > 1) {
82 	  /* printf("DEBUG 7: Processing command line arguments...\n"); */
83 #ifdef CHDIR
84 	    if (!strncmp(argv[1], "-d", 2) && argv[1][2] != 'e') {
85 		/* avoid matching "-dec" for DECgraphics; since the man page
86 		 * says -d directory, hope nobody's using -desomething_else
87 		 */
88 		argc--;
89 		argv++;
90 		dir = argv[0]+2;
91 		if(*dir == '=' || *dir == ':') dir++;
92 		if(!*dir && argc > 1) {
93 			argc--;
94 			argv++;
95 			dir = argv[0];
96 		}
97 		if(!*dir)
98 		    error("Flag -d must be followed by a directory name.");
99 	    }
100 	    if (argc > 1)
101 #endif /* CHDIR */
102 
103 	    /*
104 	     * Now we know the directory containing 'record' and
105 	     * may do a prscore().  Exclude `-style' - it's a Qt option.
106 	     */
107 	    if (!strncmp(argv[1], "-s", 2) && strncmp(argv[1], "-style", 6)) {
108 #ifdef CHDIR
109 		chdirx(dir,0);
110 #endif
111 		prscore(argc, argv);
112 		exit(EXIT_SUCCESS);
113 	    }
114 	}
115 
116 	/* printf("DEBUG 8: Checking creation date...\n"); */
117 	/*
118 	 * Find the creation date of this game,
119 	 * so as to avoid restoring outdated savefiles.
120 	 */
121 	gethdate(hname);
122 
123 	/* printf("DEBUG 9: Changing to game directory...\n"); */
124 	/*
125 	 * We cannot do chdir earlier, otherwise gethdate will fail.
126 	 * Change directories before we initialize the window system so
127 	 * we can find the tile file.
128 	 */
129 #ifdef CHDIR
130 	chdirx(dir,1);
131 #endif
132 
133 #ifdef _M_UNIX
134 	check_sco_console();
135 #endif
136 #ifdef __linux__
137 	check_linux_console();
138 #endif
139 	/* printf("DEBUG 10: Initializing options...\n"); */
140 	initoptions();
141 	/* printf("DEBUG 11: Initializing window port...\n"); */
142 	init_nhwindows(&argc,argv);
143 	/* printf("DEBUG 12: Window port initialized.\n"); */
144 	/* printf("DEBUG 13: Getting exact username...\n"); */
145 	exact_username = whoami();
146         /* printf("DEBUG 14: Username ready.\n"); */
147 #ifdef _M_UNIX
148 	init_sco_cons();
149 #endif
150 #ifdef __linux__
151 	init_linux_cons();
152 #endif
153 
154 	/*
155 	 * It seems you really want to play.
156 	 */
157 	u.uhp = 1;	/* prevent RIP on early quits */
158 	(void) signal(SIGHUP, (SIG_RET_TYPE) hangup);
159 #ifdef SIGXCPU
160 	(void) signal(SIGXCPU, (SIG_RET_TYPE) hangup);
161 #endif
162         /* printf("DEBUG 15: Processing command line options...\n"); */
163 	process_options(argc, argv);	/* command line options */
164         /* printf("DEBUG 15b: Command line options processed.\n"); */
165 
166 #ifdef DEF_PAGER
167 	if(!(catmore = nh_getenv("HACKPAGER")) && !(catmore = nh_getenv("PAGER")))
168 		catmore = DEF_PAGER;
169 #endif
170 #ifdef MAIL
171 	getmailstatus();
172 #endif
173 #ifdef WIZARD
174 	if (wizard)
175 		Strcpy(plname, "wizard");
176 	else
177 #endif
178 	  /* printf("DEBUG 15c: Comparing player name...\n"); */
179 	if(!*plname || !strncmp(plname, "player", 4)
180 		    || !strncmp(plname, "games", 4)) {
181 	  /* printf("DEBUG 15c2: Starting Askname...\n"); */
182 		askname();
183 	} else if (exact_username) {
184 		/* guard against user names with hyphens in them */
185 		int len = strlen(plname);
186 		/* printf("DEBUG 15c3: Formatting username...\n"); */
187 		/* append the current role, if any, so that last dash is ours */
188 		if (++len < sizeof plname)
189 			(void)strncat(strcat(plname, "-"),
190 				      pl_character, sizeof plname - len - 1);
191 	}
192         /* printf("DEBUG 15c4: Removing suffix...\n"); */
193 	plnamesuffix();		/* strip suffix from name; calls askname() */
194 				/* again if suffix was whole name */
195 				/* accepts any suffix */
196 	/* printf("DEBUG 15c5: Name ready.\n"); */
197 #ifdef WIZARD
198 	if(!wizard) {
199 #endif
200 	  /* printf("DEBUG 15c6: Getting locks...\n"); */
201 		/*
202 		 * check for multiple games under the same name
203 		 * (if !locknum) or check max nr of players (otherwise)
204 		 */
205 		(void) signal(SIGQUIT,SIG_IGN);
206 		(void) signal(SIGINT,SIG_IGN);
207 		/* printf("DEBUG 15c8: Signals ready...\n"); */
208 		if(!locknum)
209 			Sprintf(lock, "%d%s", (int)getuid(), plname);
210                 /* printf("DEBUG 15c9: Going to getlock...\n"); */
211 		getlock();
212 		/* printf("DEBUG 15c7: Locks ready.\n"); */
213 #ifdef WIZARD
214 	} else {
215 		Sprintf(lock, "%d%s", (int)getuid(), plname);
216 		getlock();
217 	}
218 #endif /* WIZARD */
219 
220         /* printf("DEBUG 15c: Initializing DLB...\n"); */
221 	dlb_init();	/* must be before newgame() */
222         /* printf("DEBUG 15d: DLB Initialized...\n"); */
223 
224 	/*
225 	 * Initialization of the boundaries of the mazes
226 	 * Both boundaries have to be even.
227 	 */
228 	x_maze_max = COLNO-1;
229 	if (x_maze_max % 2)
230 		x_maze_max--;
231 	y_maze_max = ROWNO-1;
232 	if (y_maze_max % 2)
233 		y_maze_max--;
234 
235         /* printf("DEBUG 15e: Initializing vision...\n"); */
236 	/*
237 	 *  Initialize the vision system.  This must be before mklev() on a
238 	 *  new game or before a level restore on a saved game.
239 	 */
240 	vision_init();
241         /* printf("DEBUG 16: Displaying game windows...\n"); */
242 	display_gamewindows();
243 
244 	if ((fd = restore_saved_game()) >= 0) {
245 #ifdef WIZARD
246 		/* Since wizard is actually flags.debug, restoring might
247 		 * overwrite it.
248 		 */
249 		boolean remember_wiz_mode = wizard;
250 #endif
251 		const char *fq_save = fqname(SAVEF, SAVEPREFIX, 0);
252 
253 		(void) chmod(fq_save,0);	/* disallow parallel restores */
254 		(void) signal(SIGINT, (SIG_RET_TYPE) done1);
255 #ifdef NEWS
256 		if(iflags.news) {
257 		    display_file(NEWS, FALSE);
258 		    iflags.news = FALSE; /* in case dorecover() fails */
259 		}
260 #endif
261 		pline("Restoring save file...");
262 		mark_synch();	/* flush output */
263 		if(!dorecover(fd))
264 			goto not_recovered;
265 #ifdef WIZARD
266 		if(!wizard && remember_wiz_mode) wizard = TRUE;
267 #endif
268 		check_special_room(FALSE);
269 		wd_message();
270 
271 		if (discover || wizard) {
272 			if(yn("Do you want to keep the save file?") == 'n')
273 			    (void) delete_savefile();
274 			else {
275 			    (void) chmod(fq_save,FCMASK); /* back to readable */
276 			    compress(fq_save);
277 			}
278 		}
279 		flags.move = 0;
280 	} else {
281 not_recovered:
282 	  /* printf("Debug 17: Player selection...\n"); */
283 		player_selection();
284 		/* printf("Debug 18: Starting New Game...\n"); */
285 		newgame();
286 		wd_message();
287 
288 		flags.move = 0;
289 		set_wear();
290 		(void) pickup(1);
291 	}
292 
293         /* printf("Debug 19: Starting movement loop...\n"); */
294 	moveloop();
295 	exit(EXIT_SUCCESS);
296 	/*NOTREACHED*/
297 	return(0);
298 }
299 
300 static void
process_options(argc,argv)301 process_options(argc, argv)
302 int argc;
303 char *argv[];
304 {
305 	int i;
306 
307 
308 	/*
309 	 * Process options.
310 	 */
311 	while(argc > 1 && argv[1][0] == '-'){
312 		argv++;
313 		argc--;
314 		switch(argv[0][1]){
315 		case 'D':
316 #ifdef WIZARD
317 			{
318 			  char *user;
319 			  int uid;
320 			  struct passwd *pw = (struct passwd *)0;
321 
322 			  uid = getuid();
323 			  user = getlogin();
324 			  if (user) {
325 			      pw = getpwnam(user);
326 			      if (pw && (pw->pw_uid != uid)) pw = 0;
327 			  }
328 			  if (pw == 0) {
329 			      user = nh_getenv("USER");
330 			      if (user) {
331 				  pw = getpwnam(user);
332 				  if (pw && (pw->pw_uid != uid)) pw = 0;
333 			      }
334 			      if (pw == 0) {
335 				  pw = getpwuid(uid);
336 			      }
337 			  }
338 			  if (pw && !strcmp(pw->pw_name,WIZARD)) {
339 			      wizard = TRUE;
340 			      break;
341 			  }
342 			}
343 			/* otherwise fall thru to discover */
344 			wiz_error_flag = TRUE;
345 #endif
346 		case 'X':
347 			discover = TRUE;
348 			break;
349 #ifdef NEWS
350 		case 'n':
351 			iflags.news = FALSE;
352 			break;
353 #endif
354 		case 'u':
355 			if(argv[0][2])
356 			  (void) strncpy(plname, argv[0]+2, sizeof(plname)-1);
357 			else if(argc > 1) {
358 			  argc--;
359 			  argv++;
360 			  (void) strncpy(plname, argv[0], sizeof(plname)-1);
361 			} else
362 				raw_print("Player name expected after -u");
363 			break;
364 		case 'I':
365 		case 'i':
366 			if (!strncmpi(argv[0]+1, "IBM", 3))
367 				switch_graphics(IBM_GRAPHICS);
368 			break;
369 	    /*  case 'D': */
370 		case 'd':
371 			if (!strncmpi(argv[0]+1, "DEC", 3))
372 				switch_graphics(DEC_GRAPHICS);
373 			break;
374 		case 'p': /* profession (role) */
375 			if (argv[0][2]) {
376 			    if ((i = str2role(&argv[0][2])) >= 0)
377 			    	flags.initrole = i;
378 			} else if (argc > 1) {
379 				argc--;
380 				argv++;
381 			    if ((i = str2role(argv[0])) >= 0)
382 			    	flags.initrole = i;
383 			}
384 			break;
385 		case 'r': /* race */
386 			if (argv[0][2]) {
387 			    if ((i = str2race(&argv[0][2])) >= 0)
388 			    	flags.initrace = i;
389 			} else if (argc > 1) {
390 				argc--;
391 				argv++;
392 			    if ((i = str2race(argv[0])) >= 0)
393 			    	flags.initrace = i;
394 			}
395 			break;
396 		default:
397 			if ((i = str2role(&argv[0][1])) >= 0) {
398 			    flags.initrole = i;
399 				break;
400 			}
401 			/* else raw_printf("Unknown option: %s", *argv); */
402 		}
403 	}
404 
405 	if(argc > 1)
406 		locknum = atoi(argv[1]);
407 #ifdef MAX_NR_OF_PLAYERS
408 	if(!locknum || locknum > MAX_NR_OF_PLAYERS)
409 		locknum = MAX_NR_OF_PLAYERS;
410 #endif
411 }
412 
413 #ifdef CHDIR
414 static void
chdirx(dir,wr)415 chdirx(dir, wr)
416 const char *dir;
417 boolean wr;
418 {
419 	if (dir					/* User specified directory? */
420 # ifdef HACKDIR
421 	       && strcmp(dir, HACKDIR)		/* and not the default? */
422 # endif
423 		) {
424 # ifdef SECURE
425 	  /* printf("DEBUG[unixmain.c/40]: Setting permissions...\n"); */
426 	    (void) setgid(getgid());
427 	    (void) setuid(getuid());		/* Ron Wessels */
428 # endif
429 	} else {
430 	    /* non-default data files is a sign that scores may not be
431 	     * compatible, or perhaps that a binary not fitting this
432 	     * system's layout is being used.
433 	     */
434 # ifdef VAR_PLAYGROUND
435 	    int len = strlen(VAR_PLAYGROUND);
436 
437 	    fqn_prefix[SCOREPREFIX] = (char *)alloc(len+2);
438 	    Strcpy(fqn_prefix[SCOREPREFIX], VAR_PLAYGROUND);
439 	    if (fqn_prefix[SCOREPREFIX][len-1] != '/') {
440 		fqn_prefix[SCOREPREFIX][len] = '/';
441 		fqn_prefix[SCOREPREFIX][len+1] = '\0';
442 	    }
443 # endif
444 	}
445 
446 # ifdef HACKDIR
447 	if (dir == (const char *)0)
448 	    dir = HACKDIR;
449 # endif
450 
451 	if (dir && chdir(dir) < 0) {
452 	    perror(dir);
453 	    error("Cannot chdir to %s.", dir);
454 	}
455 
456 	/* warn the player if we can't write the record file */
457 	/* perhaps we should also test whether . is writable */
458 	/* unfortunately the access system-call is worthless */
459 	if (wr) {
460 # ifdef VAR_PLAYGROUND
461 	    fqn_prefix[LEVELPREFIX] = fqn_prefix[SCOREPREFIX];
462 	    fqn_prefix[SAVEPREFIX] = fqn_prefix[SCOREPREFIX];
463 	    fqn_prefix[BONESPREFIX] = fqn_prefix[SCOREPREFIX];
464 	    fqn_prefix[LOCKPREFIX] = fqn_prefix[SCOREPREFIX];
465 # endif
466 	    check_recordfile(dir);
467 	}
468 }
469 #endif /* CHDIR */
470 
471 static boolean
whoami()472 whoami() {
473 	/*
474 	 * Who am i? Algorithm: 1. Use name as specified in NETHACKOPTIONS
475 	 *			2. Use $USER or $LOGNAME	(if 1. fails)
476 	 *			3. Use getlogin()		(if 2. fails)
477 	 * The resulting name is overridden by command line options.
478 	 * If everything fails, or if the resulting name is some generic
479 	 * account like "games", "play", "player", "hack" then eventually
480 	 * we'll ask him.
481 	 * Note that we trust the user here; it is possible to play under
482 	 * somebody else's name.
483 	 */
484 	register char *s;
485 
486 	if (*plname) return FALSE;
487 	if(/* !*plname && */ (s = nh_getenv("USER")))
488 		(void) strncpy(plname, s, sizeof(plname)-1);
489 	if(!*plname && (s = nh_getenv("LOGNAME")))
490 		(void) strncpy(plname, s, sizeof(plname)-1);
491 	if(!*plname && (s = getlogin()))
492 		(void) strncpy(plname, s, sizeof(plname)-1);
493 	return TRUE;
494 }
495 
496 #ifdef PORT_HELP
497 void
port_help()498 port_help()
499 {
500 	/*
501 	 * Display unix-specific help.   Just show contents of the helpfile
502 	 * named by PORT_HELP.
503 	 */
504 	display_file(PORT_HELP, TRUE);
505 }
506 #endif
507 
508 static void
wd_message()509 wd_message()
510 {
511 #ifdef WIZARD
512 	if (wiz_error_flag) {
513 		pline("Only user \"%s\" may access debug (wizard) mode.",
514 # ifndef KR1ED
515 			WIZARD);
516 # else
517 			WIZARD_NAME);
518 # endif
519 		pline("Entering discovery mode instead.");
520 	} else
521 #endif
522 	if (discover)
523 		You("are in non-scoring discovery mode.");
524 }
525 /*unixmain.c*/
526