1 /* NetHack 3.6 unixunix.c $NHDT-Date: 1432512788 2015/05/25 00:13:08 $ $NHDT-Branch: master $:$NHDT-Revision: 1.22 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
5 /* This file collects some Unix dependencies */
7 #include "hack.h" /* mainly for index() which depends on BSD */
11 #if defined(NO_FILE_LINKS) || defined(SUNOS4) || defined(POSIX_TYPES)
17 extern void NDECL(sco_mapon);
18 extern void NDECL(sco_mapoff);
21 extern void NDECL(linux_mapon);
22 extern void NDECL(linux_mapoff);
29 static struct stat buf;
31 /* see whether we should throw away this xlock file */
39 return (0); /* cannot get status */
41 if (buf.st_size != sizeof(int))
42 return (0); /* not an xlock file */
44 #if defined(BSD) && !defined(POSIX_TYPES)
45 (void) time((long *) (&date));
49 if (date - buf.st_mtime < 3L * 24L * 60L * 60L) { /* recent */
50 int lockedpid; /* should be the same size as hackpid */
52 if (read(fd, (genericptr_t) &lockedpid, sizeof(lockedpid))
57 /* From: Rick Adams <seismo!rick> */
58 /* This will work on 4.1cbsd, 4.2bsd and system 3? & 5. */
59 /* It will do nothing on V7 or 4.1bsd. */
61 /* It will do a VERY BAD THING if the playground is shared
62 by more than one machine! -pem */
63 if (!(kill(lockedpid, 0) == -1 && errno == ESRCH))
76 program_state.preserve_locks = 0; /* not required but shows intent */
77 /* cannot use maxledgerno() here, because we need to find a lock name
78 * before starting everything (including the dungeon initialization
79 * that sets astral_level, needed for maxledgerno()) up
81 for (i = 1; i <= MAXDUNGEON * MAXLEVEL + 1; i++) {
82 /* try to remove all */
83 set_levelfile_name(lock, i);
84 (void) unlink(fqname(lock, LEVELPREFIX, 0));
86 set_levelfile_name(lock, 0);
87 if (unlink(fqname(lock, LEVELPREFIX, 0)))
88 return (0); /* cannot remove it */
89 return (1); /* success! */
95 register int i = 0, fd, c;
99 /* idea from rpick%ucqais@uccba.uc.edu
100 * prevent automated rerolling of characters
101 * test input (fd0) so that tee'ing output to get a screen dump still
103 * also incidentally prevents development of any hack-o-matic programs
105 /* added check for window-system type -dlc */
106 if (!strcmp(windowprocs.name, "tty"))
108 error("You must play from a terminal.");
111 /* we ignore QUIT and INT at this point */
112 if (!lock_file(HLOCK, LOCKPREFIX, 10)) {
117 /* default value of lock[] is "1lock" where '1' gets changed to
118 'a','b',&c below; override the default and use <uid><charname>
119 if we aren't restricting the number of simultaneous games */
121 Sprintf(lock, "%u%s", (unsigned) getuid(), plname);
124 set_levelfile_name(lock, 0);
132 fq_lock = fqname(lock, LEVELPREFIX, 0);
134 if ((fd = open(fq_lock, 0)) == -1) {
136 goto gotlock; /* no such file */
139 error("Cannot open %s", fq_lock);
142 if (veryold(fd) /* closes fd if true */
146 } while (i < locknum);
149 error("Too many hacks running now.");
151 fq_lock = fqname(lock, LEVELPREFIX, 0);
152 if ((fd = open(fq_lock, 0)) == -1) {
154 goto gotlock; /* no such file */
157 error("Cannot open %s", fq_lock);
160 if (veryold(fd) /* closes fd if true */ && eraseoldlocks())
164 if (iflags.window_inited) {
166 c = yn("There is already a game in progress under your name. "
167 "Destroy old game?");
169 c = yn("
\82 \82È
\82½
\82Ì
\96¼
\91O
\82Å
\95s
\90³
\8fI
\97¹
\82µ
\82½
\83Q
\81[
\83\80\82ª
\8ec
\82Á
\82Ä
\82¢
\82Ü
\82·
\81D"
170 "
\94j
\8aü
\82µ
\82Ü
\82·
\82©
\81H");
175 "\nThere is already a game in progress under your name.");
176 (void) printf(" Destroy old game? [yn] ");
179 "\n
\82 \82È
\82½
\82Ì
\96¼
\91O
\82Å
\95s
\90³
\8fI
\97¹
\82µ
\82½
\83Q
\81[
\83\80\82ª
\8ec
\82Á
\82Ä
\82¢
\82Ü
\82·
\81D");
180 (void) printf("
\94j
\8aü
\82µ
\82Ü
\82·
\82©
\81H[yn] ");
182 (void) fflush(stdout);
183 if ((c = getchar()) != EOF) {
187 (void) fflush(stdout);
188 while ((tmp = getchar()) != '\n' && tmp != EOF)
189 ; /* eat rest of line and newline */
192 if (c == 'y' || c == 'Y') {
197 error("Couldn't destroy old game.");
206 fd = creat(fq_lock, FCMASK);
209 error("cannot creat lock file (%s).", fq_lock);
211 if (write(fd, (genericptr_t) &hackpid, sizeof(hackpid))
212 != sizeof(hackpid)) {
213 error("cannot write lock (%s)", fq_lock);
215 if (close(fd) == -1) {
216 error("cannot close lock (%s)", fq_lock);
221 void regularize(s) /* normalize file name - we don't like .'s, /'s, spaces */
226 while ((lp = index(s, '.')) || (lp = index(s, '/'))
227 || (lp = index(s, ' ')))
229 #if defined(SYSV) && !defined(AIX_31) && !defined(SVR4) && !defined(LINUX) \
230 && !defined(__APPLE__)
231 /* avoid problems with 14 character file name limit */
233 /* leave room for .e from error and .Z from compress appended to
236 #ifdef COMPRESS_EXTENSION
237 int i = 12 - strlen(COMPRESS_EXTENSION);
239 int i = 10; /* should never happen... */
246 /* leave room for .nn appended to level files */
252 #if defined(TIMED_DELAY) && !defined(msleep) && defined(SYSV)
257 unsigned msec; /* milliseconds */
259 struct pollfd unused;
260 int msecs = msec; /* poll API is signed */
263 msecs = 0; /* avoid infinite sleep */
264 (void) poll(&unused, (unsigned long) 0, msecs);
266 #endif /* TIMED_DELAY for SYSV */
274 if (!sysopt.shellers || !sysopt.shellers[0]
275 || !check_user_string(sysopt.shellers)) {
276 Norep("Unknown command '!'.");
281 if ((str = getenv("SHELL")) != (char *) 0)
282 (void) execl(str, str, (char *) 0);
284 (void) execl("/bin/sh", "sh", (char *) 0);
285 raw_print("sh: cannot execute.");
292 #if defined(SHELL) || defined(DEF_PAGER) || defined(DEF_MAILREADER)
298 suspend_nhwindows((char *) 0); /* also calls end_screen() */
305 if ((f = fork()) == 0) { /* child */
306 #pragma GCC diagnostic push
307 #pragma GCC diagnostic ignored "-Wunused-result"
308 (void) setgid(getgid());
309 (void) setuid(getuid());
311 (void) chdir(getenv("HOME"));
313 #pragma GCC diagnostic pop
316 if (f == -1) { /* cannot fork */
317 pline("Fork failed. Try again.");
320 /* fork succeeded; wait for child to exit */
322 (void) signal(SIGINT, SIG_IGN);
323 (void) signal(SIGQUIT, SIG_IGN);
325 (void) wait((int *) 0);
333 (void) signal(SIGINT, (SIG_RET_TYPE) done1);
335 (void) signal(SIGQUIT, SIG_DFL);
346 #ifdef GETRES_SUPPORT
348 extern int FDECL(nh_getresuid, (uid_t *, uid_t *, uid_t *));
349 extern uid_t NDECL(nh_getuid);
350 extern uid_t NDECL(nh_geteuid);
351 extern int FDECL(nh_getresgid, (gid_t *, gid_t *, gid_t *));
352 extern gid_t NDECL(nh_getgid);
353 extern gid_t NDECL(nh_getegid);
355 int(getresuid)(ruid, euid, suid)
356 uid_t *ruid, *euid, *suid;
358 return nh_getresuid(ruid, euid, suid);
371 int(getresgid)(rgid, egid, sgid)
372 gid_t *rgid, *egid, *sgid;
374 return nh_getresgid(rgid, egid, sgid);
387 #endif /* GETRES_SUPPORT */
389 /* XXX should be ifdef PANICTRACE_GDB, but there's no such symbol yet */
392 file_exists(const char *path)
394 /* Just see if it's there - trying to figure out if we can actually
395 * execute it in all cases is too hard - we really just want to
396 * catch typos in SYSCF. */
398 if (stat(path, &sb)) {