OSDN Git Service

suppress GCC warnings
[jnethack/source.git] / sys / unix / unixunix.c
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. */
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
33 veryold(fd)
34 int fd;
35 {
36     time_t date;
37
38     if (fstat(fd, &buf))
39         return (0); /* cannot get status */
40 #ifndef INSURANCE
41     if (buf.st_size != sizeof(int))
42         return (0); /* not an xlock file */
43 #endif
44 #if defined(BSD) && !defined(POSIX_TYPES)
45     (void) time((long *) (&date));
46 #else
47     (void) time(&date);
48 #endif
49     if (date - buf.st_mtime < 3L * 24L * 60L * 60L) { /* recent */
50         int lockedpid; /* should be the same size as hackpid */
51
52         if (read(fd, (genericptr_t) &lockedpid, sizeof(lockedpid))
53             != sizeof(lockedpid))
54             /* strange ... */
55             return (0);
56
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. */
60 #ifndef NETWORK
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))
64 #endif
65             return (0);
66     }
67     (void) close(fd);
68     return (1);
69 }
70
71 static int
72 eraseoldlocks()
73 {
74     register int i;
75
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
80      */
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));
85     }
86     set_levelfile_name(lock, 0);
87     if (unlink(fqname(lock, LEVELPREFIX, 0)))
88         return (0); /* cannot remove it */
89     return (1);     /* success! */
90 }
91
92 void
93 getlock()
94 {
95     register int i = 0, fd, c;
96     const char *fq_lock;
97
98 #ifdef TTY_GRAPHICS
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
102      * works
103      * also incidentally prevents development of any hack-o-matic programs
104      */
105     /* added check for window-system type -dlc */
106     if (!strcmp(windowprocs.name, "tty"))
107         if (!isatty(0))
108             error("You must play from a terminal.");
109 #endif
110
111     /* we ignore QUIT and INT at this point */
112     if (!lock_file(HLOCK, LOCKPREFIX, 10)) {
113         wait_synch();
114         error("%s", "");
115     }
116
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 */
120     if (!locknum)
121         Sprintf(lock, "%u%s", (unsigned) getuid(), plname);
122
123     regularize(lock);
124     set_levelfile_name(lock, 0);
125
126     if (locknum) {
127         if (locknum > 25)
128             locknum = 25;
129
130         do {
131             lock[0] = 'a' + i++;
132             fq_lock = fqname(lock, LEVELPREFIX, 0);
133
134             if ((fd = open(fq_lock, 0)) == -1) {
135                 if (errno == ENOENT)
136                     goto gotlock; /* no such file */
137                 perror(fq_lock);
138                 unlock_file(HLOCK);
139                 error("Cannot open %s", fq_lock);
140             }
141
142             if (veryold(fd) /* closes fd if true */
143                 && eraseoldlocks())
144                 goto gotlock;
145             (void) close(fd);
146         } while (i < locknum);
147
148         unlock_file(HLOCK);
149         error("Too many hacks running now.");
150     } else {
151         fq_lock = fqname(lock, LEVELPREFIX, 0);
152         if ((fd = open(fq_lock, 0)) == -1) {
153             if (errno == ENOENT)
154                 goto gotlock; /* no such file */
155             perror(fq_lock);
156             unlock_file(HLOCK);
157             error("Cannot open %s", fq_lock);
158         }
159
160         if (veryold(fd) /* closes fd if true */ && eraseoldlocks())
161             goto gotlock;
162         (void) close(fd);
163
164         if (iflags.window_inited) {
165 #if 0 /*JP*/
166             c = yn("There is already a game in progress under your name.  "
167                    "Destroy old game?");
168 #else
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");
171 #endif
172         } else {
173 #if 0 /*JP*/
174             (void) printf(
175                 "\nThere is already a game in progress under your name.");
176             (void) printf("  Destroy old game? [yn] ");
177 #else
178             (void) printf(
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] ");
181 #endif
182             (void) fflush(stdout);
183             if ((c = getchar()) != EOF) {
184                 int tmp;
185
186                 (void) putchar(c);
187                 (void) fflush(stdout);
188                 while ((tmp = getchar()) != '\n' && tmp != EOF)
189                     ; /* eat rest of line and newline */
190             }
191         }
192         if (c == 'y' || c == 'Y') {
193             if (eraseoldlocks())
194                 goto gotlock;
195             else {
196                 unlock_file(HLOCK);
197                 error("Couldn't destroy old game.");
198             }
199         } else {
200             unlock_file(HLOCK);
201             error("%s", "");
202         }
203     }
204
205 gotlock:
206     fd = creat(fq_lock, FCMASK);
207     unlock_file(HLOCK);
208     if (fd == -1) {
209         error("cannot creat lock file (%s).", fq_lock);
210     } else {
211         if (write(fd, (genericptr_t) &hackpid, sizeof(hackpid))
212             != sizeof(hackpid)) {
213             error("cannot write lock (%s)", fq_lock);
214         }
215         if (close(fd) == -1) {
216             error("cannot close lock (%s)", fq_lock);
217         }
218     }
219 }
220
221 void regularize(s) /* normalize file name - we don't like .'s, /'s, spaces */
222 register char *s;
223 {
224     register char *lp;
225
226     while ((lp = index(s, '.')) || (lp = index(s, '/'))
227            || (lp = index(s, ' ')))
228         *lp = '_';
229 #if defined(SYSV) && !defined(AIX_31) && !defined(SVR4) && !defined(LINUX) \
230     && !defined(__APPLE__)
231 /* avoid problems with 14 character file name limit */
232 #ifdef COMPRESS
233     /* leave room for .e from error and .Z from compress appended to
234      * save files */
235     {
236 #ifdef COMPRESS_EXTENSION
237         int i = 12 - strlen(COMPRESS_EXTENSION);
238 #else
239         int i = 10; /* should never happen... */
240 #endif
241         if (strlen(s) > i)
242             s[i] = '\0';
243     }
244 #else
245     if (strlen(s) > 11)
246         /* leave room for .nn appended to level files */
247         s[11] = '\0';
248 #endif
249 #endif
250 }
251
252 #if defined(TIMED_DELAY) && !defined(msleep) && defined(SYSV)
253 #include <poll.h>
254
255 void
256 msleep(msec)
257 unsigned msec; /* milliseconds */
258 {
259     struct pollfd unused;
260     int msecs = msec; /* poll API is signed */
261
262     if (msecs < 0)
263         msecs = 0; /* avoid infinite sleep */
264     (void) poll(&unused, (unsigned long) 0, msecs);
265 }
266 #endif /* TIMED_DELAY for SYSV */
267
268 #ifdef SHELL
269 int
270 dosh()
271 {
272     register char *str;
273 #ifdef SYSCF
274     if (!sysopt.shellers || !sysopt.shellers[0]
275         || !check_user_string(sysopt.shellers)) {
276         Norep("Unknown command '!'.");
277         return 0;
278     }
279 #endif
280     if (child(0)) {
281         if ((str = getenv("SHELL")) != (char *) 0)
282             (void) execl(str, str, (char *) 0);
283         else
284             (void) execl("/bin/sh", "sh", (char *) 0);
285         raw_print("sh: cannot execute.");
286         exit(EXIT_FAILURE);
287     }
288     return 0;
289 }
290 #endif /* SHELL */
291
292 #if defined(SHELL) || defined(DEF_PAGER) || defined(DEF_MAILREADER)
293 int
294 child(wt)
295 int wt;
296 {
297     register int f;
298     suspend_nhwindows((char *) 0); /* also calls end_screen() */
299 #ifdef _M_UNIX
300     sco_mapon();
301 #endif
302 #ifdef __linux__
303     linux_mapon();
304 #endif
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());
310 #ifdef CHDIR
311         (void) chdir(getenv("HOME"));
312 #endif
313 #pragma GCC diagnostic pop
314         return (1);
315     }
316     if (f == -1) { /* cannot fork */
317         pline("Fork failed.  Try again.");
318         return (0);
319     }
320 /* fork succeeded; wait for child to exit */
321 #ifndef NO_SIGNAL
322     (void) signal(SIGINT, SIG_IGN);
323     (void) signal(SIGQUIT, SIG_IGN);
324 #endif
325     (void) wait((int *) 0);
326 #ifdef _M_UNIX
327     sco_mapoff();
328 #endif
329 #ifdef __linux__
330     linux_mapoff();
331 #endif
332 #ifndef NO_SIGNAL
333     (void) signal(SIGINT, (SIG_RET_TYPE) done1);
334     if (wizard)
335         (void) signal(SIGQUIT, SIG_DFL);
336 #endif
337     if (wt) {
338         raw_print("");
339         wait_synch();
340     }
341     resume_nhwindows();
342     return (0);
343 }
344 #endif
345
346 #ifdef GETRES_SUPPORT
347
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);
354
355 int(getresuid)(ruid, euid, suid)
356 uid_t *ruid, *euid, *suid;
357 {
358     return nh_getresuid(ruid, euid, suid);
359 }
360
361 uid_t(getuid)()
362 {
363     return nh_getuid();
364 }
365
366 uid_t(geteuid)()
367 {
368     return nh_geteuid();
369 }
370
371 int(getresgid)(rgid, egid, sgid)
372 gid_t *rgid, *egid, *sgid;
373 {
374     return nh_getresgid(rgid, egid, sgid);
375 }
376
377 gid_t(getgid)()
378 {
379     return nh_getgid();
380 }
381
382 gid_t(getegid)()
383 {
384     return nh_getegid();
385 }
386
387 #endif /* GETRES_SUPPORT */
388
389 /* XXX should be ifdef PANICTRACE_GDB, but there's no such symbol yet */
390 #ifdef PANICTRACE
391 boolean
392 file_exists(const char *path)
393 {
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. */
397     struct stat sb;
398     if (stat(path, &sb)) {
399         return FALSE;
400     }
401     return TRUE;
402 }
403 #endif