OSDN Git Service

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