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