hack.unix.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  1. /* $NetBSD: hack.unix.c,v 1.9 2003/04/02 18:36:41 jsm Exp $ */
  2. /*
  3. * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica,
  4. * Amsterdam
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions are
  9. * met:
  10. *
  11. * - Redistributions of source code must retain the above copyright notice,
  12. * this list of conditions and the following disclaimer.
  13. *
  14. * - Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in the
  16. * documentation and/or other materials provided with the distribution.
  17. *
  18. * - Neither the name of the Stichting Centrum voor Wiskunde en
  19. * Informatica, nor the names of its contributors may be used to endorse or
  20. * promote products derived from this software without specific prior
  21. * written permission.
  22. *
  23. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  24. * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  25. * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
  26. * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
  27. * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  28. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  29. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  30. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  31. * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  32. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  33. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  34. */
  35. /*
  36. * Copyright (c) 1982 Jay Fenlason <hack@gnu.org>
  37. * All rights reserved.
  38. *
  39. * Redistribution and use in source and binary forms, with or without
  40. * modification, are permitted provided that the following conditions
  41. * are met:
  42. * 1. Redistributions of source code must retain the above copyright
  43. * notice, this list of conditions and the following disclaimer.
  44. * 2. Redistributions in binary form must reproduce the above copyright
  45. * notice, this list of conditions and the following disclaimer in the
  46. * documentation and/or other materials provided with the distribution.
  47. * 3. The name of the author may not be used to endorse or promote products
  48. * derived from this software without specific prior written permission.
  49. *
  50. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
  51. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  52. * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
  53. * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  54. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  55. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  56. * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  57. * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  58. * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  59. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  60. */
  61. #include <sys/cdefs.h>
  62. #ifndef lint
  63. __RCSID("$NetBSD: hack.unix.c,v 1.9 2003/04/02 18:36:41 jsm Exp $");
  64. #endif /* not lint */
  65. /* This file collects some Unix dependencies; hack.pager.c contains some more */
  66. /*
  67. * The time is used for:
  68. * - seed for random()
  69. * - year on tombstone and yymmdd in record file
  70. * - phase of the moon (various monsters react to NEW_MOON or FULL_MOON)
  71. * - night and midnight (the undead are dangerous at midnight)
  72. * - determination of what files are "very old"
  73. */
  74. #include <errno.h>
  75. #include <sys/types.h> /* for time_t and stat */
  76. #include <sys/stat.h>
  77. #ifdef BSD
  78. #include <sys/time.h>
  79. #else
  80. #include <time.h>
  81. #endif /* BSD */
  82. #include <stdlib.h>
  83. #include <unistd.h>
  84. #include <signal.h>
  85. #include <fcntl.h>
  86. #include "hack.h" /* mainly for strchr() which depends on BSD */
  87. #include "extern.h"
  88. extern int locknum;
  89. void
  90. setrandom()
  91. {
  92. (void) srandom((int) time((time_t *) 0));
  93. }
  94. struct tm *
  95. getlt()
  96. {
  97. time_t date;
  98. (void) time(&date);
  99. return (localtime(&date));
  100. }
  101. int
  102. getyear()
  103. {
  104. return (1900 + getlt()->tm_year);
  105. }
  106. char *
  107. getdate()
  108. {
  109. static char datestr[7];
  110. struct tm *lt = getlt();
  111. (void) sprintf(datestr, "%02d%02d%02d",
  112. lt->tm_year % 100, lt->tm_mon + 1, lt->tm_mday);
  113. return (datestr);
  114. }
  115. int
  116. phase_of_the_moon()
  117. { /* 0-7, with 0: new, 4: full *//* moon
  118. * period: 29.5306 days */
  119. /* year: 365.2422 days */
  120. struct tm *lt = getlt();
  121. int epact, diy, golden;
  122. diy = lt->tm_yday;
  123. golden = (lt->tm_year % 19) + 1;
  124. epact = (11 * golden + 18) % 30;
  125. if ((epact == 25 && golden > 11) || epact == 24)
  126. epact++;
  127. return ((((((diy + epact) * 6) + 11) % 177) / 22) & 7);
  128. }
  129. int
  130. night()
  131. {
  132. int hour = getlt()->tm_hour;
  133. return (hour < 6 || hour > 21);
  134. }
  135. int
  136. midnight()
  137. {
  138. return (getlt()->tm_hour == 0);
  139. }
  140. struct stat buf, hbuf;
  141. void
  142. gethdate(name)
  143. char *name;
  144. {
  145. #if 0
  146. /* old version - for people short of space */
  147. char *np;
  148. if(stat(name, &hbuf))
  149. error("Cannot get status of %s.",
  150. (np = strrchr(name, '/')) ? np+1 : name);
  151. #else
  152. /* version using PATH from: seismo!gregc@ucsf-cgl.ARPA (Greg Couch) */
  153. /*
  154. * The problem with #include <sys/param.h> is that this include file
  155. * does not exist on all systems, and moreover, that it sometimes includes
  156. * <sys/types.h> again, so that the compiler sees these typedefs twice.
  157. */
  158. #define MAXPATHLEN 1024
  159. const char *np, *path;
  160. char filename[MAXPATHLEN + 1];
  161. if (strchr(name, '/') != NULL || (path = getenv("PATH")) == NULL)
  162. path = "";
  163. for (;;) {
  164. if ((np = strchr(path, ':')) == NULL)
  165. np = path + strlen(path); /* point to end str */
  166. if (np - path <= 1) /* %% */
  167. (void) strcpy(filename, name);
  168. else {
  169. (void) strncpy(filename, path, np - path);
  170. filename[np - path] = '/';
  171. (void) strcpy(filename + (np - path) + 1, name);
  172. }
  173. if (stat(filename, &hbuf) == 0)
  174. return;
  175. if (*np == '\0')
  176. break;
  177. path = np + 1;
  178. }
  179. error("Cannot get status of %s.",
  180. (np = strrchr(name, '/')) ? np + 1 : name);
  181. #endif
  182. }
  183. int
  184. uptodate(int fd)
  185. {
  186. if (fstat(fd, &buf)) {
  187. pline("Cannot get status of saved level? ");
  188. return (0);
  189. }
  190. if (buf.st_mtime < hbuf.st_mtime) {
  191. pline("Saved level is out of date. ");
  192. return (0);
  193. }
  194. return (1);
  195. }
  196. /* see whether we should throw away this xlock file */
  197. int
  198. veryold(fd)
  199. int fd;
  200. {
  201. int i;
  202. time_t date;
  203. if (fstat(fd, &buf))
  204. return (0); /* cannot get status */
  205. if (buf.st_size != sizeof(int))
  206. return (0); /* not an xlock file */
  207. (void) time(&date);
  208. if (date - buf.st_mtime < 3L * 24L * 60L * 60L) { /* recent */
  209. int lockedpid; /* should be the same size as
  210. * hackpid */
  211. if (read(fd, (char *) &lockedpid, sizeof(lockedpid)) !=
  212. sizeof(lockedpid))
  213. /* strange ... */
  214. return (0);
  215. /*
  216. * From: Rick Adams <seismo!rick> This will work on
  217. * 4.1cbsd, 4.2bsd and system 3? & 5. It will do nothing
  218. * on V7 or 4.1bsd.
  219. */
  220. if (!(kill(lockedpid, 0) == -1 && errno == ESRCH))
  221. return (0);
  222. }
  223. (void) close(fd);
  224. for (i = 1; i <= MAXLEVEL; i++) { /* try to remove all */
  225. glo(i);
  226. (void) unlink(lock);
  227. }
  228. glo(0);
  229. if (unlink(lock))
  230. return (0); /* cannot remove it */
  231. return (1); /* success! */
  232. }
  233. void
  234. getlock()
  235. {
  236. int i = 0, fd;
  237. (void) fflush(stdout);
  238. /* we ignore QUIT and INT at this point */
  239. if (link(HLOCK, LLOCK) == -1) {
  240. int errnosv = errno;
  241. perror(HLOCK);
  242. printf("Cannot link %s to %s\n", LLOCK, HLOCK);
  243. switch (errnosv) {
  244. case ENOENT:
  245. printf("Perhaps there is no (empty) file %s ?\n", HLOCK);
  246. break;
  247. case EACCES:
  248. printf("It seems you don't have write permission here.\n");
  249. break;
  250. case EEXIST:
  251. printf("(Try again or rm %s.)\n", LLOCK);
  252. break;
  253. default:
  254. printf("I don't know what is wrong.");
  255. }
  256. getret();
  257. error("%s", "");
  258. /* NOTREACHED */
  259. }
  260. regularize(lock);
  261. glo(0);
  262. if (locknum > 25)
  263. locknum = 25;
  264. do {
  265. if (locknum)
  266. lock[0] = 'a' + i++;
  267. if ((fd = open(lock, O_RDONLY)) == -1) {
  268. if (errno == ENOENT)
  269. goto gotlock; /* no such file */
  270. perror(lock);
  271. (void) unlink(LLOCK);
  272. error("Cannot open %s", lock);
  273. }
  274. if (veryold(fd))/* if true, this closes fd and unlinks lock */
  275. goto gotlock;
  276. (void) close(fd);
  277. } while (i < locknum);
  278. (void) unlink(LLOCK);
  279. error(locknum ? "Too many hacks running now."
  280. : "There is a game in progress under your name.");
  281. gotlock:
  282. fd = creat(lock, FMASK);
  283. if (unlink(LLOCK) == -1)
  284. error("Cannot unlink %s.", LLOCK);
  285. if (fd == -1) {
  286. error("cannot creat lock file.");
  287. } else {
  288. if (write(fd, (char *) &hackpid, sizeof(hackpid))
  289. != sizeof(hackpid)) {
  290. error("cannot write lock");
  291. }
  292. if (close(fd) == -1) {
  293. error("cannot close lock");
  294. }
  295. }
  296. }
  297. #ifdef MAIL
  298. /*
  299. * Notify user when new mail has arrived. [Idea from Merlyn Leroy, but
  300. * I don't know the details of his implementation.]
  301. * { Later note: he disliked my calling a general mailreader and felt that
  302. * hack should do the paging itself. But when I get mail, I want to put it
  303. * in some folder, reply, etc. - it would be unreasonable to put all these
  304. * functions in hack. }
  305. * The mail daemon '2' is at present not a real monster, but only a visual
  306. * effect. Thus, makemon() is superfluous. This might become otherwise,
  307. * however. The motion of '2' is less restrained than usual: diagonal moves
  308. * from a DOOR are possible. He might also use SDOOR's. Also, '2' is visible
  309. * in a ROOM, even when you are Blind.
  310. * Its path should be longer when you are Telepat-hic and Blind.
  311. *
  312. * Interesting side effects:
  313. * - You can get rich by sending yourself a lot of mail and selling
  314. * it to the shopkeeper. Unfortunately mail isn't very valuable.
  315. * - You might die in case '2' comes along at a critical moment during
  316. * a fight and delivers a scroll the weight of which causes you to
  317. * collapse.
  318. *
  319. * Possible extensions:
  320. * - Open the file MAIL and do fstat instead of stat for efficiency.
  321. * (But sh uses stat, so this cannot be too bad.)
  322. * - Examine the mail and produce a scroll of mail called "From somebody".
  323. * - Invoke MAILREADER in such a way that only this single letter is read.
  324. *
  325. * - Make him lose his mail when a Nymph steals the letter.
  326. * - Do something to the text when the scroll is enchanted or cancelled.
  327. */
  328. #include "def.mkroom.h"
  329. static struct stat omstat, nmstat;
  330. static char *mailbox;
  331. static long laststattime;
  332. void
  333. getmailstatus()
  334. {
  335. if (!(mailbox = getenv("MAIL")))
  336. return;
  337. if (stat(mailbox, &omstat)) {
  338. #ifdef PERMANENT_MAILBOX
  339. pline("Cannot get status of MAIL=%s .", mailbox);
  340. mailbox = 0;
  341. #else
  342. omstat.st_mtime = 0;
  343. #endif /* PERMANENT_MAILBOX */
  344. }
  345. }
  346. void
  347. ckmailstatus()
  348. {
  349. if (!mailbox
  350. #ifdef MAILCKFREQ
  351. || moves < laststattime + MAILCKFREQ
  352. #endif /* MAILCKFREQ */
  353. )
  354. return;
  355. laststattime = moves;
  356. if (stat(mailbox, &nmstat)) {
  357. #ifdef PERMANENT_MAILBOX
  358. pline("Cannot get status of MAIL=%s anymore.", mailbox);
  359. mailbox = 0;
  360. #else
  361. nmstat.st_mtime = 0;
  362. #endif /* PERMANENT_MAILBOX */
  363. } else if (nmstat.st_mtime > omstat.st_mtime) {
  364. if (nmstat.st_size)
  365. newmail();
  366. getmailstatus();/* might be too late ... */
  367. }
  368. }
  369. void
  370. newmail()
  371. {
  372. /* produce a scroll of mail */
  373. struct obj *obj;
  374. struct monst *md;
  375. obj = mksobj(SCR_MAIL);
  376. if (md = makemon(&pm_mail_daemon, u.ux, u.uy)) /* always succeeds */
  377. mdrush(md, 0);
  378. pline("\"Hello, %s! I have some mail for you.\"", plname);
  379. if (md) {
  380. if (dist(md->mx, md->my) > 2)
  381. pline("\"Catch!\"");
  382. more();
  383. /* let him disappear again */
  384. mdrush(md, 1);
  385. mondead(md);
  386. }
  387. obj = addinv(obj);
  388. (void) identify(obj); /* set known and do prinv() */
  389. }
  390. /* make md run through the cave */
  391. void
  392. mdrush(md, away)
  393. struct monst *md;
  394. boolean away;
  395. {
  396. int uroom = inroom(u.ux, u.uy);
  397. if (uroom >= 0) {
  398. int tmp = rooms[uroom].fdoor;
  399. int cnt = rooms[uroom].doorct;
  400. int fx = u.ux, fy = u.uy;
  401. while (cnt--) {
  402. if (dist(fx, fy) < dist(doors[tmp].x, doors[tmp].y)) {
  403. fx = doors[tmp].x;
  404. fy = doors[tmp].y;
  405. }
  406. tmp++;
  407. }
  408. tmp_at(-1, md->data->mlet); /* open call */
  409. if (away) { /* interchange origin and destination */
  410. unpmon(md);
  411. tmp = fx;
  412. fx = md->mx;
  413. md->mx = tmp;
  414. tmp = fy;
  415. fy = md->my;
  416. md->my = tmp;
  417. }
  418. while (fx != md->mx || fy != md->my) {
  419. int dx, dy, nfx = fx, nfy = fy, d1,
  420. d2;
  421. tmp_at(fx, fy);
  422. d1 = DIST(fx, fy, md->mx, md->my);
  423. for (dx = -1; dx <= 1; dx++)
  424. for (dy = -1; dy <= 1; dy++)
  425. if (dx || dy) {
  426. d2 = DIST(fx + dx, fy + dy, md->mx, md->my);
  427. if (d2 < d1) {
  428. d1 = d2;
  429. nfx = fx + dx;
  430. nfy = fy + dy;
  431. }
  432. }
  433. if (nfx != fx || nfy != fy) {
  434. fx = nfx;
  435. fy = nfy;
  436. } else {
  437. if (!away) {
  438. md->mx = fx;
  439. md->my = fy;
  440. }
  441. break;
  442. }
  443. }
  444. tmp_at(-1, -1); /* close call */
  445. }
  446. if (!away)
  447. pmon(md);
  448. }
  449. void
  450. readmail()
  451. {
  452. #ifdef DEF_MAILREADER /* This implies that UNIX is defined */
  453. char *mr = 0;
  454. more();
  455. if (!(mr = getenv("MAILREADER")))
  456. mr = DEF_MAILREADER;
  457. if (child(1)) {
  458. execl(mr, mr, (char *) 0);
  459. exit(1);
  460. }
  461. #else /* DEF_MAILREADER */
  462. (void) page_file(mailbox, FALSE);
  463. #endif /* DEF_MAILREADER */
  464. /*
  465. * get new stat; not entirely correct: there is a small time window
  466. * where we do not see new mail
  467. */
  468. getmailstatus();
  469. }
  470. #endif /* MAIL */
  471. void
  472. regularize(s) /* normalize file name - we don't like ..'s
  473. * or /'s */
  474. char *s;
  475. {
  476. char *lp;
  477. while ((lp = strchr(s, '.')) || (lp = strchr(s, '/')))
  478. *lp = '_';
  479. }