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