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