xref: /openbsd/games/sail/sync.c (revision 898184e3)
1 /*	$OpenBSD: sync.c,v 1.10 2011/06/20 17:40:55 miod Exp $	*/
2 /*	$NetBSD: sync.c,v 1.9 1998/08/30 09:19:40 veego Exp $	*/
3 
4 /*
5  * Copyright (c) 1983, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 #include <fcntl.h>
34 #include <errno.h>
35 #include <stdarg.h>
36 #include <stdlib.h>
37 #include <unistd.h>
38 #include <sys/file.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <time.h>
42 #include "extern.h"
43 #include "pathnames.h"
44 
45 #define BUFSIZE 4096
46 
47 static const char SF[] = _PATH_SYNC;
48 static const char LF[] = _PATH_LOCK;
49 static char sync_buf[BUFSIZE];
50 static char *sync_bp = sync_buf;
51 static char sync_lock[sizeof SF];
52 static char sync_file[sizeof LF];
53 static long sync_seek;
54 static FILE *sync_fp;
55 
56 void
57 fmtship(buf, len, fmt, ship)
58 	char *buf;
59 	size_t len;
60 	const char *fmt;
61 	struct ship *ship;
62 {
63 	if (len == 0)
64 		abort();	/* XXX */
65 
66 	while (*fmt && len > 1) {
67 		if (*fmt == '$' && fmt[1] == '$') {
68 			size_t l;
69 			snprintf(buf, len, "%s (%c%c)",
70 			    ship->shipname, colours(ship), sterncolour(ship));
71 			l = strlen(buf);
72 			buf += l;
73 			len -= l;
74 			fmt += 2;
75 		} else {
76 			*buf++ = *fmt++;
77 			len--;
78 		}
79 	}
80 
81 	*buf = '\0';
82 }
83 
84 
85 /*VARARGS3*/
86 void
87 makesignal(struct ship *from, const char *fmt, struct ship *ship, ...)
88 {
89 	char message[BUFSIZ];
90 	char format[BUFSIZ];
91 	va_list ap;
92 
93 	va_start(ap, ship);
94 	fmtship(format, sizeof(format), fmt, ship);
95 	(void) vsnprintf(message, sizeof message, format, ap);
96 	va_end(ap);
97 	Writestr(W_SIGNAL, from, message);
98 }
99 
100 void
101 makemsg(struct ship *from, const char *fmt, ...)
102 {
103 	char message[BUFSIZ];
104 	va_list ap;
105 
106 	va_start(ap, fmt);
107 	(void) vsnprintf(message, sizeof message, fmt, ap);
108 	va_end(ap);
109 	Writestr(W_SIGNAL, from, message);
110 }
111 
112 int
113 sync_exists(game)
114 	int game;
115 {
116 	char buf[sizeof sync_file];
117 	struct stat s;
118 	time_t t;
119 
120 	(void) snprintf(buf, sizeof buf, SF, game);
121 	(void) time(&t);
122 	setegid(egid);
123 	if (stat(buf, &s) < 0) {
124 		setegid(gid);
125 		return 0;
126 	}
127 	if (s.st_mtime < t - 60*60*2) {		/* 2 hours */
128 		(void) unlink(buf);
129 		(void) snprintf(buf, sizeof buf, LF, game);
130 		(void) unlink(buf);
131 		setegid(gid);
132 		return 0;
133 	}
134 	setegid(gid);
135 	return 1;
136 }
137 
138 int
139 sync_open()
140 {
141 	struct stat tmp;
142 
143 	if (sync_fp != NULL)
144 		(void) fclose(sync_fp);
145 	(void) snprintf(sync_lock, sizeof sync_lock, LF, game);
146 	(void) snprintf(sync_file, sizeof sync_file, SF, game);
147 	setegid(egid);
148 	if (stat(sync_file, &tmp) < 0) {
149 		mode_t omask = umask(002);
150 		sync_fp = fopen(sync_file, "w+");
151 		(void) umask(omask);
152 	} else
153 		sync_fp = fopen(sync_file, "r+");
154 	setegid(gid);
155 	if (sync_fp == NULL)
156 		return -1;
157 	sync_seek = 0;
158 	return 0;
159 }
160 
161 void
162 sync_close(remove)
163 	char remove;
164 {
165 	if (sync_fp != 0)
166 		(void) fclose(sync_fp);
167 	if (remove) {
168 		setegid(egid);
169 		(void) unlink(sync_file);
170 		setegid(gid);
171 	}
172 }
173 
174 void
175 Write(type, ship, a, b, c, d)
176 	int type;
177 	struct ship *ship;
178 	long a, b, c, d;
179 {
180 	(void) snprintf(sync_bp, sync_buf + sizeof sync_buf - sync_bp,
181 		"%d %d 0 %ld %ld %ld %ld\n",
182 	       type, ship->file->index, a, b, c, d);
183 	while (*sync_bp++)
184 		;
185 	sync_bp--;
186 	if (sync_bp >= &sync_buf[sizeof sync_buf])
187 		abort();
188 	(void) sync_update(type, ship, NULL, a, b, c, d);
189 }
190 
191 void
192 Writestr(type, ship, a)
193 	int type;
194 	struct ship *ship;
195 	const char *a;
196 {
197 	(void) snprintf(sync_bp, sync_buf + sizeof sync_buf - sync_bp,
198 		"%d %d 1 %s\n",
199 		type, ship->file->index, a);
200 	while (*sync_bp++)
201 		;
202 	sync_bp--;
203 	if (sync_bp >= &sync_buf[sizeof sync_buf])
204 		abort();
205 	(void) sync_update(type, ship, a, 0, 0, 0, 0);
206 }
207 
208 int
209 Sync()
210 {
211 	sig_t sighup, sigint;
212 	int n;
213 	int type, shipnum, isstr;
214 	char *astr;
215 	long a, b, c, d;
216 	char buf[80];
217 	char erred = 0;
218 
219 	sighup = signal(SIGHUP, SIG_IGN);
220 	sigint = signal(SIGINT, SIG_IGN);
221 	for (n = TIMEOUT; --n >= 0;) {
222 #ifdef LOCK_EX
223 		if (flock(fileno(sync_fp), LOCK_EX|LOCK_NB) >= 0)
224 			break;
225 		if (errno != EWOULDBLOCK)
226 			return -1;
227 #else
228 		setegid(egid);
229 		if (link(sync_file, sync_lock) >= 0) {
230 			setegid(gid);
231 			break;
232 		}
233 		setegid(gid);
234 		if (errno != EEXIST)
235 			return -1;
236 #endif
237 		sleep(1);
238 	}
239 	if (n <= 0)
240 		return -1;
241 	(void) fseek(sync_fp, sync_seek, SEEK_SET);
242 	for (;;) {
243 		switch (fscanf(sync_fp, "%d%d%d", &type, &shipnum, &isstr)) {
244 		case 3:
245 			break;
246 		case EOF:
247 			goto out;
248 		default:
249 			goto bad;
250 		}
251 		if (shipnum < 0 || shipnum >= cc->vessels)
252 			goto bad;
253 		if (isstr != 0 && isstr != 1)
254 			goto bad;
255 		if (isstr) {
256 			int ch;
257 			char *p;
258 
259 			for (p = buf;;) {
260 				ch = getc(sync_fp);
261 				switch (ch) {
262 				case '\n':
263 				case EOF:
264 					break;
265 				default:
266 					if (p < buf + sizeof buf)
267 						*p++ = ch;
268 					continue;
269 				}
270 				break;
271 			}
272 			*p = 0;
273 			for (p = buf; *p == ' '; p++)
274 				;
275 			astr = p;
276 			a = b = c = d = 0;
277 		} else {
278 			if (fscanf(sync_fp, "%ld%ld%ld%ld", &a, &b, &c, &d) != 4)
279 				goto bad;
280 			astr = NULL;
281 		}
282 		if (sync_update(type, SHIP(shipnum), astr, a, b, c, d) < 0)
283 			goto bad;
284 	}
285 bad:
286 	erred++;
287 out:
288 	if (!erred && sync_bp != sync_buf) {
289 		(void) fseek(sync_fp, 0L, SEEK_END);
290 		(void) fwrite(sync_buf, sizeof *sync_buf, sync_bp - sync_buf,
291 			sync_fp);
292 		(void) fflush(sync_fp);
293 		sync_bp = sync_buf;
294 	}
295 	sync_seek = ftell(sync_fp);
296 #ifdef LOCK_EX
297 	(void) flock(fileno(sync_fp), LOCK_UN);
298 #else
299 	setegid(egid);
300 	(void) unlink(sync_lock);
301 	setegid(gid);
302 #endif
303 	(void) signal(SIGHUP, sighup);
304 	(void) signal(SIGINT, sigint);
305 	return erred ? -1 : 0;
306 }
307 
308 int
309 sync_update(type, ship, astr, a, b, c, d)
310 	int type;
311 	struct ship *ship;
312 	const char *astr;
313 	long a, b, c, d;
314 {
315 	switch (type) {
316 	case W_DBP: {
317 		struct BP *p = &ship->file->DBP[a];
318 		p->turnsent = b;
319 		p->toship = SHIP(c);
320 		p->mensent = d;
321 		break;
322 		}
323 	case W_OBP: {
324 		struct BP *p = &ship->file->OBP[a];
325 		p->turnsent = b;
326 		p->toship = SHIP(c);
327 		p->mensent = d;
328 		break;
329 		}
330 	case W_FOUL: {
331 		struct snag *p = &ship->file->foul[a];
332 		if (SHIP(a)->file->dir == 0)
333 			break;
334 		if (p->sn_count++ == 0)
335 			p->sn_turn = turn;
336 		ship->file->nfoul++;
337 		break;
338 		}
339 	case W_GRAP: {
340 		struct snag *p = &ship->file->grap[a];
341 		if (SHIP(a)->file->dir == 0)
342 			break;
343 		if (p->sn_count++ == 0)
344 			p->sn_turn = turn;
345 		ship->file->ngrap++;
346 		break;
347 		}
348 	case W_UNFOUL: {
349 		struct snag *p = &ship->file->foul[a];
350 		if (p->sn_count > 0) {
351 			if (b) {
352 				ship->file->nfoul -= p->sn_count;
353 				p->sn_count = 0;
354 			} else {
355 				ship->file->nfoul--;
356 				p->sn_count--;
357 			}
358 		}
359 		break;
360 		}
361 	case W_UNGRAP: {
362 		struct snag *p = &ship->file->grap[a];
363 		if (p->sn_count > 0) {
364 			if (b) {
365 				ship->file->ngrap -= p->sn_count;
366 				p->sn_count = 0;
367 			} else {
368 				ship->file->ngrap--;
369 				p->sn_count--;
370 			}
371 		}
372 		break;
373 		}
374 	case W_SIGNAL:
375 		if (mode == MODE_PLAYER) {
376 			if (nobells)
377 				Signal("$$: %s", ship, astr);
378 			else
379 				Signal("\7$$: %s", ship, astr);
380 		}
381 		break;
382 	case W_CREW: {
383 		struct shipspecs *s = ship->specs;
384 		s->crew1 = a;
385 		s->crew2 = b;
386 		s->crew3 = c;
387 		break;
388 		}
389 	case W_CAPTAIN:
390 		(void) strlcpy(ship->file->captain, astr,
391 			sizeof ship->file->captain);
392 		break;
393 	case W_CAPTURED:
394 		if (a < 0)
395 			ship->file->captured = 0;
396 		else
397 			ship->file->captured = SHIP(a);
398 		break;
399 	case W_CLASS:
400 		ship->specs->class = a;
401 		break;
402 	case W_DRIFT:
403 		ship->file->drift = a;
404 		break;
405 	case W_EXPLODE:
406 		if ((ship->file->explode = a) == 2)
407 			ship->file->dir = 0;
408 		break;
409 	case W_FS:
410 		ship->file->FS = a;
411 		break;
412 	case W_GUNL: {
413 		struct shipspecs *s = ship->specs;
414 		s->gunL = a;
415 		s->carL = b;
416 		break;
417 		}
418 	case W_GUNR: {
419 		struct shipspecs *s = ship->specs;
420 		s->gunR = a;
421 		s->carR = b;
422 		break;
423 		}
424 	case W_HULL:
425 		ship->specs->hull = a;
426 		break;
427 	case W_MOVE:
428 		(void) strlcpy(ship->file->movebuf, astr,
429 			sizeof ship->file->movebuf);
430 		break;
431 	case W_PCREW:
432 		ship->file->pcrew = a;
433 		break;
434 	case W_POINTS:
435 		ship->file->points = a;
436 		break;
437 	case W_QUAL:
438 		ship->specs->qual = a;
439 		break;
440 	case W_RIGG: {
441 		struct shipspecs *s = ship->specs;
442 		s->rig1 = a;
443 		s->rig2 = b;
444 		s->rig3 = c;
445 		s->rig4 = d;
446 		break;
447 		}
448 	case W_RIG1:
449 		ship->specs->rig1 = a;
450 		break;
451 	case W_RIG2:
452 		ship->specs->rig2 = a;
453 		break;
454 	case W_RIG3:
455 		ship->specs->rig3 = a;
456 		break;
457 	case W_RIG4:
458 		ship->specs->rig4 = a;
459 		break;
460 	case W_COL:
461 		ship->file->col = a;
462 		break;
463 	case W_DIR:
464 		ship->file->dir = a;
465 		break;
466 	case W_ROW:
467 		ship->file->row = a;
468 		break;
469 	case W_SINK:
470 		if ((ship->file->sink = a) == 2)
471 			ship->file->dir = 0;
472 		break;
473 	case W_STRUCK:
474 		ship->file->struck = a;
475 		break;
476 	case W_TA:
477 		ship->specs->ta = a;
478 		break;
479 	case W_ALIVE:
480 		alive = 1;
481 		break;
482 	case W_TURN:
483 		turn = a;
484 		break;
485 	case W_WIND:
486 		winddir = a;
487 		windspeed = b;
488 		break;
489 	case W_BEGIN:
490 		(void) strlcpy(ship->file->captain, "begin",
491 		    sizeof ship->file->captain);
492 		people++;
493 		break;
494 	case W_END:
495 		*ship->file->captain = 0;
496 		ship->file->points = 0;
497 		people--;
498 		break;
499 	case W_DDEAD:
500 		hasdriver = 0;
501 		break;
502 	default:
503 		fprintf(stderr, "sync_update: unknown type %d\r\n", type);
504 		return -1;
505 	}
506 	return 0;
507 }
508