|
|
1.1 root 1: /*
2: * Copyright (c) 1985 Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms are permitted
6: * provided that the above copyright notice and this paragraph are
7: * duplicated in all such forms and that any documentation,
8: * advertising materials, and other materials related to such
9: * distribution and use acknowledge that the software was developed
10: * by the University of California, Berkeley. The name of the
11: * University may not be used to endorse or promote products derived
12: * from this software without specific prior written permission.
13: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15: * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16: */
17:
18: #ifndef lint
19: static char sccsid[] = "@(#)hunt.c 5.3 (Berkeley) 6/27/88";
20: #endif /* not lint */
21:
22: /*
23: * Hunt
24: * Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold
25: * San Francisco, California
26: */
27:
28: # include <errno.h>
29: # include <curses.h>
30: # include "hunt.h"
31: # include <signal.h>
32: # include <ctype.h>
33: # include <sys/stat.h>
34:
35: FLAG Last_player = FALSE;
36: # ifdef MONITOR
37: FLAG Am_monitor = FALSE;
38: # endif MONITOR
39: FLAG Query_driver = FALSE;
40:
41: char Buf[BUFSIZ];
42:
43: int Master_pid;
44: int Socket;
45: # ifdef INTERNET
46: char *Sock_host;
47: # endif INTERNET
48:
49: SOCKET Daemon;
50: # ifdef INTERNET
51: # define DAEMON_SIZE (sizeof Daemon)
52: # else INTERNET
53: # define DAEMON_SIZE (sizeof Daemon - 1)
54: # endif INTERNET
55:
56: char map_key[256]; /* what to map keys to */
57:
58: static char name[NAMELEN];
59:
60: extern int cur_row, cur_col, _putchar();
61: extern char *tgoto();
62:
63: /*
64: * main:
65: * Main program for local process
66: */
67: main(ac, av)
68: int ac;
69: char **av;
70: {
71: char *term;
72: extern int errno;
73: extern int Otto_mode;
74: int dumpit(), intr(), sigterm(), sigemt(), tstp();
75:
76: for (ac--, av++; ac > 0 && av[0][0] == '-'; ac--, av++) {
77: switch (av[0][1]) {
78:
79: case 'l': /* rsh compatibility */
80: case 'n':
81: if (ac <= 1)
82: goto usage;
83: ac--, av++;
84: (void) strcpy(name, av[0]);
85: break;
86: case 'o':
87: # ifndef OTTO
88: fputs("The -o flag is reserved for future use.\n",
89: stderr);
90: goto usage;
91: # else OTTO
92: Otto_mode = TRUE;
93: break;
94: # endif OTTO
95: # ifdef MONITOR
96: case 'm':
97: Am_monitor = TRUE;
98: break;
99: # endif MONITOR
100: # ifdef INTERNET
101: case 'q': /* query whether hunt is running */
102: Query_driver = TRUE;
103: break;
104: case 'h':
105: if (ac <= 1)
106: goto usage;
107: ac--, av++;
108: Sock_host = av[0];
109: break;
110: # endif INTERNET
111: default:
112: usage:
113: # ifdef INTERNET
114: # ifdef MONITOR
115: # define USAGE "usage: hunt [-q] [-n name] [-h host] [-m]\n"
116: # else MONITOR
117: # define USAGE "usage: hunt [-q] [-n name] [-h host]\n"
118: # endif MONITOR
119: # else INTERNET
120: # ifdef MONITOR
121: # define USAGE "usage: hunt [-n name] [-m]\n"
122: # else MONITOR
123: # define USAGE "usage: hunt [-n name]\n"
124: # endif MONITOR
125: # endif INTERNET
126: fputs(USAGE, stderr);
127: # undef USAGE
128: exit(1);
129: }
130: }
131: # ifdef INTERNET
132: if (ac > 1)
133: goto usage;
134: else if (ac > 0)
135: Sock_host = av[0];
136: # else INTERNET
137: if (ac > 0)
138: goto usage;
139: # endif INTERNET
140:
141: # ifdef INTERNET
142: if (Query_driver) {
143: find_driver(FALSE);
144: if (Daemon.sin_port != 0) {
145: struct hostent *hp;
146:
147: hp = gethostbyaddr(&Daemon.sin_addr,
148: sizeof Daemon.sin_addr, AF_INET);
149: fprintf(stderr, "HUNT!! found on %s\n", hp != NULL
150: ? hp->h_name : inet_ntoa(Daemon.sin_addr));
151: }
152: exit(Daemon.sin_port == 0);
153: }
154: # endif INTERNET
155: # ifdef OTTO
156: if (Otto_mode)
157: (void) strcpy(name, "otto");
158: else
159: # endif OTTO
160: env_init();
161:
162: (void) fflush(stdout);
163: if (!isatty(0) || (term = getenv("TERM")) == NULL) {
164: fprintf(stderr, "no terminal type\n");
165: exit(1);
166: }
167: _tty_ch = 0;
168: gettmode();
169: setterm(term);
170: noecho();
171: cbreak();
172: _puts(TI);
173: _puts(VS);
174: clear_screen();
175: (void) signal(SIGINT, intr);
176: (void) signal(SIGTERM, sigterm);
177: (void) signal(SIGEMT, sigemt);
178: (void) signal(SIGQUIT, dumpit);
179: (void) signal(SIGPIPE, SIG_IGN);
180: (void) signal(SIGTSTP, tstp);
181:
182: do {
183: # ifdef INTERNET
184: find_driver(TRUE);
185:
186: do {
187: int msg;
188:
189: # ifndef OLDIPC
190: Socket = socket(SOCK_FAMILY, SOCK_STREAM, 0);
191: # else OLDIPC
192: Socket = socket(SOCK_STREAM, 0, 0, 0);
193: # endif OLDIPC
194: if (Socket < 0) {
195: perror("socket");
196: exit(1);
197: }
198: # ifndef OLDIPC
199: msg = 1;
200: if (setsockopt(Socket, SOL_SOCKET, SO_USELOOPBACK,
201: &msg, sizeof msg) < 0)
202: perror("setsockopt loopback");
203: # endif OLDIPC
204: errno = 0;
205: if (connect(Socket, (struct sockaddr *) &Daemon,
206: DAEMON_SIZE) < 0) {
207: if (errno != ECONNREFUSED) {
208: perror("connect");
209: leave(1, "connect");
210: }
211: }
212: else
213: break;
214: sleep(1);
215: } while (close(Socket) == 0);
216: # else INTERNET
217: /*
218: * set up a socket
219: */
220:
221: if ((Socket = socket(SOCK_FAMILY, SOCK_STREAM, 0)) < 0) {
222: perror("socket");
223: exit(1);
224: }
225:
226: /*
227: * attempt to connect the socket to a name; if it fails that
228: * usually means that the driver isn't running, so we start
229: * up the driver.
230: */
231:
232: Daemon.sun_family = SOCK_FAMILY;
233: (void) strcpy(Daemon.sun_path, Sock_name);
234: if (connect(Socket, &Daemon, DAEMON_SIZE) < 0) {
235: if (errno != ENOENT) {
236: perror("connect");
237: leave(1, "connect2");
238: }
239: start_driver();
240:
241: do {
242: (void) close(Socket);
243: if ((Socket = socket(SOCK_FAMILY, SOCK_STREAM, 0)) < 0) {
244: perror("socket");
245: exit(1);
246: }
247: sleep(2);
248: } while (connect(Socket, &Daemon, DAEMON_SIZE) < 0);
249: }
250: # endif INTERNET
251:
252: do_connect(name);
253: playit();
254: } while (!quit());
255: leave(0, NULL);
256: /* NOTREACHED */
257: }
258:
259: # ifdef INTERNET
260: # ifdef BROADCAST
261: broadcast_vec(s, vector)
262: int s; /* socket */
263: struct sockaddr **vector;
264: {
265: char if_buf[BUFSIZ];
266: struct ifconf ifc;
267: struct ifreq *ifr;
268: int n;
269: int vec_cnt;
270:
271: *vector = NULL;
272: ifc.ifc_len = sizeof if_buf;
273: ifc.ifc_buf = if_buf;
274: if (ioctl(s, SIOCGIFCONF, (char *) &ifc) < 0)
275: return 0;
276: vec_cnt = 0;
277: n = ifc.ifc_len / sizeof (struct ifreq);
278: *vector = (struct sockaddr *) malloc(n * sizeof (struct sockaddr));
279: for (ifr = ifc.ifc_req; n > 0; n--, ifr++)
280: if (ioctl(s, SIOCGIFBRDADDR, ifr) >= 0)
281: bcopy(&ifr->ifr_addr, &(*vector)[vec_cnt++],
282: sizeof (struct sockaddr));
283: return vec_cnt;
284: }
285: # endif BROADCAST
286:
287: find_driver(do_startup)
288: FLAG do_startup;
289: {
290: int msg;
291: static SOCKET test;
292: int test_socket;
293: int namelen;
294: char local_name[80];
295: static initial = TRUE;
296: static struct in_addr local_address;
297: register struct hostent *hp;
298: int (*oldsigalrm)(), sigalrm();
299: extern int errno;
300: # ifdef BROADCAST
301: static int brdc;
302: static SOCKET *brdv;
303: int i;
304: # endif BROADCAST
305:
306: if (Sock_host != NULL) {
307: if (!initial)
308: return; /* Daemon address already valid */
309: initial = FALSE;
310: if ((hp = gethostbyname(Sock_host)) == NULL) {
311: leave(1, "Unknown host");
312: /* NOTREACHED */
313: }
314: Daemon.sin_family = SOCK_FAMILY;
315: Daemon.sin_port = htons(Sock_port);
316: Daemon.sin_addr = *((struct in_addr *) hp->h_addr);
317: if (!Query_driver)
318: return;
319: }
320:
321:
322: if (initial) { /* do one time initialization */
323: # ifndef BROADCAST
324: sethostent(1); /* don't bother to close host file */
325: # endif BROADCAST
326: if (gethostname(local_name, sizeof local_name) < 0) {
327: leave(1, "Sorry, I have no name.");
328: /* NOTREACHED */
329: }
330: if ((hp = gethostbyname(local_name)) == NULL) {
331: leave(1, "Can't find myself.");
332: /* NOTREACHED */
333: }
334: local_address = * ((struct in_addr *) hp->h_addr);
335:
336: test.sin_family = SOCK_FAMILY;
337: test.sin_addr = local_address;
338: test.sin_port = htons(Test_port);
339: }
340:
341: # ifndef OLDIPC
342: test_socket = socket(SOCK_FAMILY, SOCK_DGRAM, 0);
343: # else OLDIPC
344: test_socket = socket(SOCK_DGRAM, 0, 0, 0);
345: # endif OLCIPC
346: if (test_socket < 0) {
347: perror("socket");
348: leave(1, "socket system call failed");
349: /* NOTREACHED */
350: }
351:
352: msg = 1;
353: if (Query_driver && Sock_host != NULL) {
354: test.sin_family = SOCK_FAMILY;
355: test.sin_addr = Daemon.sin_addr;
356: test.sin_port = htons(Test_port);
357: # ifndef OLDIPC
358: (void) sendto(test_socket, (char *) &msg, sizeof msg, 0,
359: (struct sockaddr *) &test, DAEMON_SIZE);
360: # else OLDIPC
361: (void) send(test_socket, (struct sockaddr *) &test,
362: (char *) &msg, sizeof msg);
363: # endif OLDIPC
364: goto get_response;
365: }
366:
367: if (!initial) {
368: /* favor host of previous session by broadcasting to it first */
369: test.sin_addr = Daemon.sin_addr;
370: test.sin_port = htons(Test_port);
371: (void) sendto(test_socket, (char *) &msg, sizeof msg, 0,
372: (struct sockaddr *) &test, DAEMON_SIZE);
373: }
374:
375:
376: # ifdef BROADCAST
377: if (initial)
378: brdc = broadcast_vec(test_socket, &brdv);
379:
380: if (brdc <= 0) {
381: Daemon.sin_family = SOCK_FAMILY;
382: Daemon.sin_addr = local_address;
383: Daemon.sin_port = htons(Sock_port);
384: initial = FALSE;
385: return;
386: }
387:
388: if (setsockopt(test_socket, SOL_SOCKET, SO_BROADCAST,
389: (int) &msg, sizeof msg) < 0) {
390: perror("setsockopt broadcast");
391: leave(1, "setsockopt broadcast");
392: /* NOTREACHED */
393: }
394:
395: /* send broadcast packets on all interfaces */
396: for (i = 0; i < brdc; i++) {
397: bcopy(&brdv[i], &test, sizeof (SOCKET));
398: test.sin_port = htons(Test_port);
399: if (sendto(test_socket, (char *) &msg, sizeof msg, 0,
400: (struct sockaddr *) &test, DAEMON_SIZE) < 0) {
401: perror("sendto");
402: leave(1, "sendto");
403: /* NOTREACHED */
404: }
405: }
406: # else BROADCAST
407: /* loop thru all hosts on local net and send msg to them. */
408: sethostent(0); /* rewind host file */
409: while (hp = gethostent()) {
410: if (inet_netof(test.sin_addr)
411: == inet_netof(* ((struct in_addr *) hp->h_addr))) {
412: test.sin_addr = * ((struct in_addr *) hp->h_addr);
413: # ifndef OLDIPC
414: (void) sendto(test_socket, (char *) &msg, sizeof msg, 0,
415: (struct sockaddr *) &test, DAEMON_SIZE);
416: # else OLDIPC
417: (void) send(test_socket, (struct sockaddr *) &test,
418: (char *) &msg, sizeof msg);
419: # endif OLDIPC
420: }
421: }
422: # endif BROADCAST
423:
424: get_response:
425: namelen = DAEMON_SIZE;
426: oldsigalrm = signal(SIGALRM, sigalrm);
427: errno = 0;
428: (void) alarm(1);
429: # ifndef OLDIPC
430: if (recvfrom(test_socket, (char *) &msg, sizeof msg, 0,
431: (struct sockaddr *) &Daemon, &namelen) < 0)
432: # else OLDIPC
433: if (receive(test_socket, (struct sockaddr *) &Daemon, &msg,
434: sizeof msg) < 0)
435: # endif OLDIPC
436: {
437: if (errno != EINTR) {
438: perror("recvfrom");
439: leave(1, "recvfrom");
440: /* NOTREACHED */
441: }
442: (void) alarm(0);
443: (void) signal(SIGALRM, oldsigalrm);
444: Daemon.sin_family = SOCK_FAMILY;
445: Daemon.sin_port = htons(Sock_port);
446: Daemon.sin_addr = local_address;
447: if (!do_startup)
448: Daemon.sin_port = 0;
449: else
450: start_driver();
451: }
452: else {
453: (void) alarm(0);
454: (void) signal(SIGALRM, oldsigalrm);
455: Daemon.sin_port = htons(Sock_port);
456: }
457: (void) close(test_socket);
458: initial = FALSE;
459: }
460: # endif INTERNET
461:
462: start_driver()
463: {
464: register int procid;
465:
466: # ifdef MONITOR
467: if (Am_monitor) {
468: leave(1, "No one playing.");
469: /* NOTREACHED */
470: }
471: # endif MONITOR
472:
473: # ifdef INTERNET
474: if (Sock_host != NULL) {
475: sleep(3);
476: return 0;
477: }
478: # endif INTERNET
479:
480: mvcur(cur_row, cur_col, 23, 0);
481: cur_row = 23;
482: cur_col = 0;
483: put_str("Starting...");
484: fflush(stdout);
485: procid = vfork();
486: if (procid == -1) {
487: perror("fork");
488: leave(1, "fork failed.");
489: }
490: if (procid == 0) {
491: (void) signal(SIGINT, SIG_IGN);
492: (void) close(Socket);
493: execl(Driver, "HUNT", NULL);
494: /* only get here if exec failed */
495: kill(getppid(), SIGEMT); /* tell mom */
496: _exit(1);
497: }
498: mvcur(cur_row, cur_col, 23, 0);
499: cur_row = 23;
500: cur_col = 0;
501: put_str("Connecting...");
502: fflush(stdout);
503: return 0;
504: }
505:
506: /*
507: * bad_con:
508: * We had a bad connection. For the moment we assume that this
509: * means the game is full.
510: */
511: bad_con()
512: {
513: leave(1, "The game is full. Sorry.");
514: /* NOTREACHED */
515: }
516:
517: /*
518: * dumpit:
519: * Handle a core dump signal by not dumping core, just leaving,
520: * so we end up with a core dump from the driver
521: */
522: dumpit()
523: {
524: (void) kill(Master_pid, SIGQUIT);
525: (void) chdir("coredump");
526: abort();
527: }
528:
529: /*
530: * sigterm:
531: * Handle a terminate signal
532: */
533: sigterm()
534: {
535: leave(0, NULL);
536: /* NOTREACHED */
537: }
538:
539:
540: /*
541: * sigemt:
542: * Handle a emt signal - shouldn't happen on vaxes(?)
543: */
544: sigemt()
545: {
546: leave(1, "Unable to start driver. Try again.");
547: /* NOTREACHED */
548: }
549:
550: # ifdef INTERNET
551: /*
552: * sigalrm:
553: * Handle an alarm signal
554: */
555: sigalrm()
556: {
557: return;
558: }
559: # endif INTERNET
560:
561: /*
562: * rmnl:
563: * Remove a '\n' at the end of a string if there is one
564: */
565: rmnl(s)
566: char *s;
567: {
568: register char *cp;
569: char *rindex();
570:
571: cp = rindex(s, '\n');
572: if (cp != NULL)
573: *cp = '\0';
574: }
575:
576: /*
577: * intr:
578: * Handle a interrupt signal
579: */
580: intr()
581: {
582: register int ch;
583: register int explained;
584: register int y, x;
585:
586: (void) signal(SIGINT, SIG_IGN);
587: y = cur_row;
588: x = cur_col;
589: mvcur(cur_row, cur_col, 23, 0);
590: cur_row = 23;
591: cur_col = 0;
592: put_str("Really quit? ");
593: clear_eol();
594: fflush(stdout);
595: explained = FALSE;
596: for (;;) {
597: ch = getchar();
598: if (isupper(ch))
599: ch = tolower(ch);
600: if (ch == 'y') {
601: (void) write(Socket, "q", 1);
602: (void) close(Socket);
603: leave(0, NULL);
604: }
605: else if (ch == 'n') {
606: (void) signal(SIGINT, intr);
607: mvcur(cur_row, cur_col, y, x);
608: cur_row = y;
609: cur_col = x;
610: fflush(stdout);
611: return;
612: }
613: if (!explained) {
614: put_str("(Y or N) ");
615: fflush(stdout);
616: explained = TRUE;
617: }
618: (void) putchar(CTRL('G'));
619: (void) fflush(stdout);
620: }
621: }
622:
623: /*
624: * leave:
625: * Leave the game somewhat gracefully, restoring all current
626: * tty stats.
627: */
628: leave(eval, mesg)
629: int eval;
630: char *mesg;
631: {
632: mvcur(cur_row, cur_col, 23, 0);
633: if (mesg == NULL)
634: clear_eol();
635: else {
636: put_str(mesg);
637: clear_eol();
638: putchar('\n');
639: fflush(stdout); /* flush in case VE changes pages */
640: }
641: resetty();
642: _puts(VE);
643: _puts(TE);
644: exit(eval);
645: }
646:
647: /*
648: * tstp:
649: * Handle stop and start signals
650: */
651: tstp()
652: {
653: static struct sgttyb tty;
654: int y, x;
655:
656: tty = _tty;
657: y = cur_row;
658: x = cur_col;
659: mvcur(cur_row, cur_col, 23, 0);
660: cur_row = 23;
661: cur_col = 0;
662: _puts(VE);
663: _puts(TE);
664: (void) fflush(stdout);
665: resetty();
666: (void) kill(getpid(), SIGSTOP);
667: (void) signal(SIGTSTP, tstp);
668: _tty = tty;
669: (void) stty(_tty_ch, &_tty);
670: _puts(TI);
671: _puts(VS);
672: cur_row = y;
673: cur_col = x;
674: _puts(tgoto(CM, cur_row, cur_col));
675: redraw_screen();
676: fflush(stdout);
677: }
678:
679: env_init()
680: {
681: register int i;
682: char *envp, *envname, *s, *index();
683:
684: for (i = 0; i < 256; i++)
685: map_key[i] = (char) i;
686:
687: envname = NULL;
688: if ((envp = getenv("HUNT")) != NULL) {
689: while ((s = index(envp, '=')) != NULL) {
690: if (strncmp(envp, "name=", s - envp + 1) == 0) {
691: envname = s + 1;
692: if ((s = index(envp, ',')) == NULL) {
693: *envp = '\0';
694: break;
695: }
696: *s = '\0';
697: envp = s + 1;
698: } /* must be last option */
699: else if (strncmp(envp, "mapkey=", s - envp + 1) == 0) {
700: for (s = s + 1; *s != '\0'; s += 2) {
701: map_key[(unsigned int) *s] = *(s + 1);
702: if (*(s + 1) == '\0') {
703: break;
704: }
705: }
706: *envp = '\0';
707: break;
708: } else {
709: *s = '\0';
710: printf("unknown option %s\n", envp);
711: if ((s = index(envp, ',')) == NULL) {
712: *envp = '\0';
713: break;
714: }
715: envp = s + 1;
716: }
717: }
718: if (*envp != '\0')
719: if (envname == NULL)
720: envname = envp;
721: else
722: printf("unknown option %s\n", envp);
723: }
724: if (envname != NULL) {
725: (void) strcpy(name, envname);
726: printf("Entering as '%s'\n", envname);
727: }
728: else if (name[0] == '\0') {
729: printf("Enter your code name: ");
730: if (fgets(name, sizeof name, stdin) == NULL)
731: exit(1);
732: }
733: rmnl(name);
734: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.