1 1.20 mbalmer /* $NetBSD: machdep.c,v 1.20 2012/12/01 11:37:27 mbalmer 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.20 mbalmer __RCSID("$NetBSD: machdep.c,v 1.20 2012/12/01 11:37:27 mbalmer 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.20 mbalmer * Appropriate variations of this are of course acceptable. 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.19 plunky 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