1 /*	SCCS Id: @(#)unixunix.c	3.4	1994/11/07	*/
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed.  See license for details. */
4 
5 /* This file collects some Unix dependencies */
6 
7 #include "hack.h"	/* mainly for index() which depends on BSD */
8 
9 #include <errno.h>
10 #include <sys/stat.h>
11 #if defined(NO_FILE_LINKS) || defined(SUNOS4) || defined(POSIX_TYPES)
12 #include <fcntl.h>
13 #endif
14 #include <signal.h>
15 
16 #ifdef _M_UNIX
17 extern void NDECL(sco_mapon);
18 extern void NDECL(sco_mapoff);
19 #endif
20 #ifdef __linux__
21 extern void NDECL(linux_mapon);
22 extern void NDECL(linux_mapoff);
23 #endif
24 
25 #ifndef NHSTDC
26 extern int errno;
27 #endif
28 
29 static struct stat buf;
30 
31 /* see whether we should throw away this xlock file */
32 static int
veryold(fd)33 veryold(fd)
34 int fd;
35 {
36 	time_t date;
37 
38 	if(fstat(fd, &buf)) return(0);			/* cannot get status */
39 #ifndef INSURANCE
40 	if(buf.st_size != sizeof(int)) return(0);	/* not an xlock file */
41 #endif
42 #if defined(BSD) && !defined(POSIX_TYPES)
43 	(void) time((long *)(&date));
44 #else
45 	(void) time(&date);
46 #endif
47 	if(date - buf.st_mtime < 3L*24L*60L*60L) {	/* recent */
48 		int lockedpid;	/* should be the same size as hackpid */
49 
50 		if(read(fd, (genericptr_t)&lockedpid, sizeof(lockedpid)) !=
51 			sizeof(lockedpid))
52 			/* strange ... */
53 			return(0);
54 
55 		/* From: Rick Adams <seismo!rick> */
56 		/* This will work on 4.1cbsd, 4.2bsd and system 3? & 5. */
57 		/* It will do nothing on V7 or 4.1bsd. */
58 #ifndef NETWORK
59 		/* It will do a VERY BAD THING if the playground is shared
60 		   by more than one machine! -pem */
61 		if(!(kill(lockedpid, 0) == -1 && errno == ESRCH))
62 #endif
63 			return(0);
64 	}
65 	(void) close(fd);
66 	return(1);
67 }
68 
69 static int
eraseoldlocks()70 eraseoldlocks()
71 {
72 	register int i;
73 
74 	/* cannot use maxledgerno() here, because we need to find a lock name
75 	 * before starting everything (including the dungeon initialization
76 	 * that sets astral_level, needed for maxledgerno()) up
77 	 */
78 	for(i = 1; i <= MAXDUNGEON*MAXLEVEL + 1; i++) {
79 		/* try to remove all */
80 		set_levelfile_name(lock, i);
81 		(void) unlink(fqname(lock, LEVELPREFIX, 0));
82 	}
83 	set_levelfile_name(lock, 0);
84 	if (unlink(fqname(lock, LEVELPREFIX, 0)))
85 		return(0);				/* cannot remove it */
86 	return(1);					/* success! */
87 }
88 
89 void
getlock()90 getlock()
91 {
92 	register int i = 0, fd, c;
93 	const char *fq_lock;
94 
95 #ifdef TTY_GRAPHICS
96 	/* idea from rpick%ucqais@uccba.uc.edu
97 	 * prevent automated rerolling of characters
98 	 * test input (fd0) so that tee'ing output to get a screen dump still
99 	 * works
100 	 * also incidentally prevents development of any hack-o-matic programs
101 	 */
102 	/* added check for window-system type -dlc */
103 	if (!strcmp(windowprocs.name, "tty"))
104 	    if (!isatty(0))
105 		error("You must play from a terminal.");
106 #endif
107 
108 	/* we ignore QUIT and INT at this point */
109 	if (!lock_file(HLOCK, LOCKPREFIX, 10)) {
110 		wait_synch();
111 		error("%s", "");
112 	}
113 
114 	regularize(lock);
115 	set_levelfile_name(lock, 0);
116 
117 	if(locknum) {
118 		if(locknum > 25) locknum = 25;
119 
120 		do {
121 			lock[0] = 'a' + i++;
122 			fq_lock = fqname(lock, LEVELPREFIX, 0);
123 
124 			if((fd = open(fq_lock, 0)) == -1) {
125 			    if(errno == ENOENT) goto gotlock; /* no such file */
126 			    perror(fq_lock);
127 			    unlock_file(HLOCK);
128 			    error("Cannot open %s", fq_lock);
129 			}
130 
131 			if(veryold(fd) /* closes fd if true */
132 							&& eraseoldlocks())
133 				goto gotlock;
134 			(void) close(fd);
135 		} while(i < locknum);
136 
137 		unlock_file(HLOCK);
138 		error("Too many hacks running now.");
139 	} else {
140 		fq_lock = fqname(lock, LEVELPREFIX, 0);
141 		if((fd = open(fq_lock, 0)) == -1) {
142 			if(errno == ENOENT) goto gotlock;    /* no such file */
143 			perror(fq_lock);
144 			unlock_file(HLOCK);
145 			error("Cannot open %s", fq_lock);
146 		}
147 
148 		if(veryold(fd) /* closes fd if true */ && eraseoldlocks())
149 			goto gotlock;
150 		(void) close(fd);
151 
152 		if(iflags.window_inited) {
153 		    c = yn("There is already a game in progress under your name.  Destroy old game?");
154 		} else {
155 		    (void) printf("\nThere is already a game in progress under your name.");
156 		    (void) printf("  Destroy old game? [yn] ");
157 		    (void) fflush(stdout);
158 		    c = getchar();
159 		    (void) putchar(c);
160 		    (void) fflush(stdout);
161 		    while (getchar() != '\n') ; /* eat rest of line and newline */
162 		}
163 		if(c == 'y' || c == 'Y')
164 			if(eraseoldlocks())
165 				goto gotlock;
166 			else {
167 				unlock_file(HLOCK);
168 				error("Couldn't destroy old game.");
169 			}
170 		else {
171 			unlock_file(HLOCK);
172 			error("%s", "");
173 		}
174 	}
175 
176 gotlock:
177 	fd = creat(fq_lock, FCMASK);
178 	unlock_file(HLOCK);
179 	if(fd == -1) {
180 		error("cannot creat lock file (%s).", fq_lock);
181 	} else {
182 		if(write(fd, (genericptr_t) &hackpid, sizeof(hackpid))
183 		    != sizeof(hackpid)){
184 			error("cannot write lock (%s)", fq_lock);
185 		}
186 		if(close(fd) == -1) {
187 			error("cannot close lock (%s)", fq_lock);
188 		}
189 	}
190 }
191 
192 void
regularize(s)193 regularize(s)	/* normalize file name - we don't like .'s, /'s, spaces */
194 register char *s;
195 {
196 	register char *lp;
197 
198 	while((lp=index(s, '.')) || (lp=index(s, '/')) || (lp=index(s,' ')))
199 		*lp = '_';
200 #if defined(SYSV) && !defined(AIX_31) && !defined(SVR4) && !defined(LINUX) && !defined(__APPLE__)
201 	/* avoid problems with 14 character file name limit */
202 # ifdef COMPRESS
203 	/* leave room for .e from error and .Z from compress appended to
204 	 * save files */
205 	{
206 #  ifdef COMPRESS_EXTENSION
207 	    int i = 12 - strlen(COMPRESS_EXTENSION);
208 #  else
209 	    int i = 10;		/* should never happen... */
210 #  endif
211 	    if(strlen(s) > i)
212 		s[i] = '\0';
213 	}
214 # else
215 	if(strlen(s) > 11)
216 		/* leave room for .nn appended to level files */
217 		s[11] = '\0';
218 # endif
219 #endif
220 }
221 
222 #if defined(TIMED_DELAY) && !defined(msleep) && defined(SYSV)
223 #include <poll.h>
224 
225 void
msleep(msec)226 msleep(msec)
227 unsigned msec;				/* milliseconds */
228 {
229 	struct pollfd unused;
230 	int msecs = msec;		/* poll API is signed */
231 
232 	if (msecs < 0) msecs = 0;	/* avoid infinite sleep */
233 	(void) poll(&unused, (unsigned long)0, msecs);
234 }
235 #endif /* TIMED_DELAY for SYSV */
236 
237 #ifdef SHELL
238 int
dosh()239 dosh()
240 {
241 	register char *str;
242 	if(child(0)) {
243 		if((str = getenv("SHELL")) != (char*)0)
244 			(void) execl(str, str, (char *)0);
245 		else
246 			(void) execl("/bin/sh", "sh", (char *)0);
247 		raw_print("sh: cannot execute.");
248 		exit(EXIT_FAILURE);
249 	}
250 	return 0;
251 }
252 #endif /* SHELL */
253 
254 #if defined(SHELL) || defined(DEF_PAGER) || defined(DEF_MAILREADER)
255 int
child(wt)256 child(wt)
257 int wt;
258 {
259 	register int f;
260 	suspend_nhwindows((char *)0);	/* also calls end_screen() */
261 #ifdef _M_UNIX
262 	sco_mapon();
263 #endif
264 #ifdef __linux__
265 	linux_mapon();
266 #endif
267 	if((f = fork()) == 0){		/* child */
268 		(void) setgid(getgid());
269 		(void) setuid(getuid());
270 #ifdef CHDIR
271 		(void) chdir(getenv("HOME"));
272 #endif
273 		return(1);
274 	}
275 	if(f == -1) {	/* cannot fork */
276 		pline("Fork failed.  Try again.");
277 		return(0);
278 	}
279 	/* fork succeeded; wait for child to exit */
280 	(void) signal(SIGINT,SIG_IGN);
281 	(void) signal(SIGQUIT,SIG_IGN);
282 	(void) wait( (int *) 0);
283 #ifdef _M_UNIX
284 	sco_mapoff();
285 #endif
286 #ifdef __linux__
287 	linux_mapoff();
288 #endif
289 	(void) signal(SIGINT, (SIG_RET_TYPE) done1);
290 #ifdef WIZARD
291 	if(wizard) (void) signal(SIGQUIT,SIG_DFL);
292 #endif
293 	if(wt) {
294 		raw_print("");
295 		wait_synch();
296 	}
297 	resume_nhwindows();
298 	return(0);
299 }
300 #endif
301 
302 #ifdef GETRES_SUPPORT
303 
304 extern int FDECL(nh_getresuid, (uid_t *, uid_t *, uid_t *));
305 extern uid_t NDECL(nh_getuid);
306 extern uid_t NDECL(nh_geteuid);
307 extern int FDECL(nh_getresgid, (gid_t *, gid_t *, gid_t *));
308 extern gid_t NDECL(nh_getgid);
309 extern gid_t NDECL(nh_getegid);
310 
311 int
312 (getresuid)(ruid, euid, suid)
313 uid_t *ruid, *euid, *suid;
314 {
315     return nh_getresuid(ruid, euid, suid);
316 }
317 
uid_t(getuid)318 uid_t
319 (getuid)()
320 {
321     return nh_getuid();
322 }
323 
uid_t(geteuid)324 uid_t
325 (geteuid)()
326 {
327     return nh_geteuid();
328 }
329 
330 int
331 (getresgid)(rgid, egid, sgid)
332 gid_t *rgid, *egid, *sgid;
333 {
334     return nh_getresgid(rgid, egid, sgid);
335 }
336 
gid_t(getgid)337 gid_t
338 (getgid)()
339 {
340     return nh_getgid();
341 }
342 
gid_t(getegid)343 gid_t
344 (getegid)()
345 {
346     return nh_getegid();
347 }
348 
349 #endif	/* GETRES_SUPPORT */
350