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