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