xref: /minix/games/rogue/machdep.c (revision 9f988b79)
1 /*	$NetBSD: machdep.c,v 1.20 2012/12/01 11:37:27 mbalmer Exp $	*/
2 
3 /*
4  * Copyright (c) 1988, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Timothy C. Stoehr.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 #include <sys/cdefs.h>
36 #ifndef lint
37 #if 0
38 static char sccsid[] = "@(#)machdep.c	8.1 (Berkeley) 5/31/93";
39 #else
40 __RCSID("$NetBSD: machdep.c,v 1.20 2012/12/01 11:37:27 mbalmer Exp $");
41 #endif
42 #endif /* not lint */
43 
44 /*
45  * machdep.c
46  *
47  * This source herein may be modified and/or distributed by anybody who
48  * so desires, with the following restrictions:
49  *    1.)  No portion of this notice shall be removed.
50  *    2.)  Credit shall not be taken for the creation of this source.
51  *    3.)  This code is not to be traded, sold, or used for personal
52  *         gain or profit.
53  *
54  */
55 
56 /* Included in this file are all system dependent routines.  Extensive use
57  * of #ifdef's will be used to compile the appropriate code on each system:
58  *
59  *    UNIX:        all UNIX systems.
60  *    UNIX_BSD4_2: UNIX BSD 4.2 and later, UTEK, (4.1 BSD too?)
61  *    UNIX_SYSV:   UNIX system V
62  *    UNIX_V7:     UNIX version 7
63  *
64  * All UNIX code should be included between the single "#ifdef UNIX" at the
65  * top of this file, and the "#endif" at the bottom.
66  *
67  * To change a routine to include a new UNIX system, simply #ifdef the
68  * existing routine, as in the following example:
69  *
70  *   To make a routine compatible with UNIX system 5, change the first
71  *   function to the second:
72  *
73  *      md_function()
74  *      {
75  *         code;
76  *      }
77  *
78  *      md_function()
79  *      {
80  *      #ifdef UNIX_SYSV
81  *         sys5code;
82  *      #else
83  *         code;
84  *      #endif
85  *      }
86  *
87  * Appropriate variations of this are of course acceptable.
88  * The use of "#elseif" is discouraged because of non-portability.
89  * If the correct #define doesn't exist, "UNIX_SYSV" in this case, make it up
90  * and insert it in the list at the top of the file.  Alter the CFLAGS
91  * in you Makefile appropriately.
92  *
93  */
94 
95 #ifdef UNIX
96 
97 #include <sys/types.h>
98 #include <sys/wait.h>
99 #include <sys/file.h>
100 #include <sys/stat.h>
101 #include <pwd.h>
102 
103 #ifdef UNIX_BSD4_2
104 #include <sys/time.h>
105 #endif
106 
107 #ifdef UNIX_SYSV
108 #include <time.h>
109 #endif
110 
111 #include <signal.h>
112 #include <stdlib.h>
113 #include <termios.h>
114 #include <unistd.h>
115 #include "rogue.h"
116 #include "pathnames.h"
117 
118 /* md_slurp:
119  *
120  * This routine throws away all keyboard input that has not
121  * yet been read.  It is used to get rid of input that the user may have
122  * typed-ahead.
123  *
124  * This function is not necessary, so it may be stubbed.  The might cause
125  * message-line output to flash by because the game has continued to read
126  * input without waiting for the user to read the message.  Not such a
127  * big deal.
128  */
129 
130 void
131 md_slurp(void)
132 {
133 	(void)fpurge(stdin);
134 }
135 
136 /* md_heed_signals():
137  *
138  * This routine tells the program to call particular routines when
139  * certain interrupts/events occur:
140  *
141  *      SIGINT: call onintr() to interrupt fight with monster or long rest.
142  *      SIGQUIT: call byebye() to check for game termination.
143  *      SIGHUP: call error_save() to save game when terminal hangs up.
144  *
145  *		On VMS, SIGINT and SIGQUIT correspond to ^C and ^Y.
146  *
147  * This routine is not strictly necessary and can be stubbed.  This will
148  * mean that the game cannot be interrupted properly with keyboard
149  * input, this is not usually critical.
150  */
151 
152 void
153 md_heed_signals(void)
154 {
155 	signal(SIGINT, onintr);
156 	signal(SIGQUIT, byebye);
157 	signal(SIGHUP, error_save);
158 }
159 
160 /* md_ignore_signals():
161  *
162  * This routine tells the program to completely ignore the events mentioned
163  * in md_heed_signals() above.  The event handlers will later be turned on
164  * by a future call to md_heed_signals(), so md_heed_signals() and
165  * md_ignore_signals() need to work together.
166  *
167  * This function should be implemented or the user risks interrupting
168  * critical sections of code, which could cause score file, or saved-game
169  * file, corruption.
170  */
171 
172 void
173 md_ignore_signals(void)
174 {
175 	signal(SIGQUIT, SIG_IGN);
176 	signal(SIGINT, SIG_IGN);
177 	signal(SIGHUP, SIG_IGN);
178 }
179 
180 /* md_get_file_id():
181  *
182  * This function returns an integer that uniquely identifies the specified
183  * file.  It need not check for the file's existence.  In UNIX, the inode
184  * number is used.
185  *
186  * This function is used to identify saved-game files.
187  */
188 
189 int
190 md_get_file_id(const char *fname)
191 {
192 	struct stat sbuf;
193 
194 	if (stat(fname, &sbuf)) {
195 		return(-1);
196 	}
197 	return((int)sbuf.st_ino);
198 }
199 
200 /* md_link_count():
201  *
202  * This routine returns the number of hard links to the specified file.
203  *
204  * This function is not strictly necessary.  On systems without hard links
205  * this routine can be stubbed by just returning 1.
206  */
207 
208 int
209 md_link_count(const char *fname)
210 {
211 	struct stat sbuf;
212 
213 	stat(fname, &sbuf);
214 	return((int)sbuf.st_nlink);
215 }
216 
217 /* md_gct(): (Get Current Time)
218  *
219  * This function returns the current year, month(1-12), day(1-31), hour(0-23),
220  * minute(0-59), and second(0-59).  This is used for identifying the time
221  * at which a game is saved.
222  *
223  * This function is not strictly necessary.  It can be stubbed by returning
224  * zeros instead of the correct year, month, etc.  If your operating
225  * system doesn't provide all of the time units requested here, then you
226  * can provide only those that it does, and return zeros for the others.
227  * If you cannot provide good time values, then users may be able to copy
228  * saved-game files and play them.
229  */
230 
231 void
232 md_gct(struct rogue_time *rt_buf)
233 {
234 	struct tm *t;
235 	time_t seconds;
236 
237 	time(&seconds);
238 	t = localtime(&seconds);
239 
240 	rt_buf->year = t->tm_year;
241 	rt_buf->month = t->tm_mon + 1;
242 	rt_buf->day = t->tm_mday;
243 	rt_buf->hour = t->tm_hour;
244 	rt_buf->minute = t->tm_min;
245 	rt_buf->second = t->tm_sec;
246 }
247 
248 /* md_gfmt: (Get File Modification Time)
249  *
250  * This routine returns a file's date of last modification in the same format
251  * as md_gct() above.
252  *
253  * This function is not strictly necessary.  It is used to see if saved-game
254  * files have been modified since they were saved.  If you have stubbed the
255  * routine md_gct() above by returning constant values, then you may do
256  * exactly the same here.
257  * Or if md_gct() is implemented correctly, but your system does not provide
258  * file modification dates, you may return some date far in the past so
259  * that the program will never know that a saved-game file being modified.
260  * You may also do this if you wish to be able to restore games from
261  * saved-games that have been modified.
262  */
263 
264 void
265 md_gfmt(const char *fname, struct rogue_time *rt_buf)
266 {
267 	struct stat sbuf;
268 	time_t seconds;
269 	struct tm *t;
270 
271 	stat(fname, &sbuf);
272 	seconds = sbuf.st_mtime;
273 	t = localtime(&seconds);
274 
275 	rt_buf->year = t->tm_year;
276 	rt_buf->month = t->tm_mon + 1;
277 	rt_buf->day = t->tm_mday;
278 	rt_buf->hour = t->tm_hour;
279 	rt_buf->minute = t->tm_min;
280 	rt_buf->second = t->tm_sec;
281 }
282 
283 /* md_df: (Delete File)
284  *
285  * This function deletes the specified file, and returns true (1) if the
286  * operation was successful.  This is used to delete saved-game files
287  * after restoring games from them.
288  *
289  * Again, this function is not strictly necessary, and can be stubbed
290  * by simply returning 1.  In this case, saved-game files will not be
291  * deleted and can be replayed.
292  */
293 
294 boolean
295 md_df(const char *fname)
296 {
297 	if (unlink(fname)) {
298 		return(0);
299 	}
300 	return(1);
301 }
302 
303 /* md_gln: (Get login name)
304  *
305  * This routine returns the login name of the user.  This string is
306  * used mainly for identifying users in score files.
307  *
308  * A dummy string may be returned if you are unable to implement this
309  * function, but then the score file would only have one name in it.
310  */
311 
312 const char *
313 md_gln(void)
314 {
315 	struct passwd *p;
316 
317 	if (!(p = getpwuid(getuid())))
318 		return NULL;
319 	return p->pw_name;
320 }
321 
322 /* md_sleep:
323  *
324  * This routine causes the game to pause for the specified number of
325  * seconds.
326  *
327  * This routine is not particularly necessary at all.  It is used for
328  * delaying execution, which is useful to this program at some times.
329  */
330 
331 void
332 md_sleep(int nsecs)
333 {
334 	(void)sleep(nsecs);
335 }
336 
337 /* md_getenv()
338  *
339  * This routine gets certain values from the user's environment.  These
340  * values are strings, and each string is identified by a name.  The names
341  * of the values needed, and their use, is as follows:
342  *
343  *   ROGUEOPTS
344  *     A string containing the various game options.  This need not be
345  *     defined.
346  *   HOME
347  *     The user's home directory.  This is only used when the user specifies
348  *     '~' as the first character of a saved-game file.  This string need
349  *     not be defined.
350  *   SHELL
351  *     The user's favorite shell.  If not found, "/bin/sh" is assumed.
352  *
353  * If your system does not provide a means of searching for these values,
354  * you will have to do it yourself.  None of the values above really need
355  * to be defined; you can get by with simply always returning zero.
356  * Returning zero indicates that their is no defined value for the
357  * given string.
358  */
359 
360 char *
361 md_getenv(const char *name)
362 {
363 	char *value;
364 
365 	value = getenv(name);
366 
367 	return(value);
368 }
369 
370 /* md_malloc()
371  *
372  * This routine allocates, and returns a pointer to, the specified number
373  * of bytes.  This routines absolutely MUST be implemented for your
374  * particular system or the program will not run at all.  Return zero
375  * when no more memory can be allocated.
376  */
377 
378 void *
379 md_malloc(size_t n)
380 {
381 	char *t;
382 
383 	t = malloc(n);
384 	return(t);
385 }
386 
387 /* md_gseed() (Get Seed)
388  *
389  * This function returns a seed for the random number generator (RNG).  This
390  * seed causes the RNG to begin generating numbers at some point in its
391  * sequence.  Without a random seed, the RNG will generate the same set
392  * of numbers, and every game will start out exactly the same way.  A good
393  * number to use is the process id, given by getpid() on most UNIX systems.
394  *
395  * You need to find some single random integer, such as:
396  *   process id.
397  *   current time (minutes + seconds) returned from md_gct(), if implemented.
398  *
399  * It will not help to return "get_rand()" or "rand()" or the return value of
400  * any pseudo-RNG.  If you don't have a random number, you can just return 1,
401  * but this means your games will ALWAYS start the same way, and will play
402  * exactly the same way given the same input.
403  */
404 
405 int
406 md_gseed(void)
407 {
408 	time_t seconds;
409 
410 	time(&seconds);
411 	return((int)seconds);
412 }
413 
414 /* md_exit():
415  *
416  * This function causes the program to discontinue execution and exit.
417  * This function must be implemented or the program will continue to
418  * hang when it should quit.
419  */
420 
421 void
422 md_exit(int status)
423 {
424 	exit(status);
425 }
426 
427 /* md_lock():
428  *
429  * This function is intended to give the user exclusive access to the score
430  * file.  It does so by flock'ing the score file.  The full path name of the
431  * score file should be defined for any particular site in rogue.h.  The
432  * constants _PATH_SCOREFILE defines this file name.
433  *
434  * When the parameter 'l' is non-zero (true), a lock is requested.  Otherwise
435  * the lock is released.
436  */
437 
438 void
439 md_lock(boolean l)
440 {
441 	static int fd = -1;
442 	short tries;
443 
444 	if (l) {
445 		setegid(egid);
446 		if ((fd = open(_PATH_SCOREFILE, O_RDONLY)) < 1) {
447 			setegid(gid);
448 			messagef(0, "cannot lock score file");
449 			return;
450 		}
451 		setegid(gid);
452 		for (tries = 0; tries < 5; tries++)
453 			if (!flock(fd, LOCK_EX|LOCK_NB))
454 				return;
455 	} else {
456 		(void)flock(fd, LOCK_UN|LOCK_NB);
457 		(void)close(fd);
458 	}
459 }
460 
461 /* md_shell():
462  *
463  * This function spawns a shell for the user to use.  When this shell is
464  * terminated, the game continues.
465  *
466  * It is important that the game not give the shell the privileges the
467  * game uses to access the scores file. This version of the game runs
468  * with privileges low by default; only the saved gid (if setgid) or uid
469  * (if setuid) will be privileged, but that privilege is discarded by
470  * exec().
471  */
472 
473 void
474 md_shell(const char *shell)
475 {
476 	int w;
477 	pid_t pid;
478 
479 	pid = fork();
480 	switch (pid) {
481 	case -1:
482 		break;
483 	case 0:
484 		execl(shell, shell, (char *)NULL);
485 		_exit(255);
486 	default:
487 		waitpid(pid, &w, 0);
488 		break;
489 	}
490 }
491 
492 #endif /* UNIX */
493