1 /* $OpenBSD: sync.c,v 1.16 2019/06/28 13:32:52 deraadt 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 <sys/stat.h>
34
35 #include <errno.h>
36 #ifdef LOCK_EX
37 #include <fcntl.h>
38 #endif
39 #include <signal.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <time.h>
43 #include <unistd.h>
44
45 #include "extern.h"
46 #include "machdep.h"
47 #include "pathnames.h"
48 #include "player.h"
49
50 #define BUFSIZE 4096
51
52 static const char SF[] = _PATH_SYNC;
53 static const char LF[] = _PATH_LOCK;
54 static char sync_buf[BUFSIZE];
55 static char *sync_bp = sync_buf;
56 static char sync_lock[sizeof SF];
57 static char sync_file[sizeof LF];
58 static long sync_seek;
59 static FILE *sync_fp;
60
61 void
fmtship(char * buf,size_t len,const char * fmt,struct ship * ship)62 fmtship(char *buf, size_t len, const char *fmt, struct ship *ship)
63 {
64 if (len == 0)
65 abort(); /* XXX */
66
67 while (*fmt && len > 1) {
68 if (*fmt == '$' && fmt[1] == '$') {
69 size_t l;
70 snprintf(buf, len, "%s (%c%c)",
71 ship->shipname, colours(ship), sterncolour(ship));
72 l = strlen(buf);
73 buf += l;
74 len -= l;
75 fmt += 2;
76 } else {
77 *buf++ = *fmt++;
78 len--;
79 }
80 }
81
82 *buf = '\0';
83 }
84
85
86 void
makesignal(struct ship * from,const char * fmt,struct ship * ship,...)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
makemsg(struct ship * from,const char * fmt,...)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
sync_exists(int game)113 sync_exists(int game)
114 {
115 char buf[sizeof sync_file];
116 struct stat s;
117 time_t t;
118
119 (void) snprintf(buf, sizeof buf, SF, game);
120 (void) time(&t);
121 setegid(egid);
122 if (stat(buf, &s) == -1) {
123 setegid(gid);
124 return 0;
125 }
126 if (s.st_mtime < t - 60*60*2) { /* 2 hours */
127 (void) unlink(buf);
128 (void) snprintf(buf, sizeof buf, LF, game);
129 (void) unlink(buf);
130 setegid(gid);
131 return 0;
132 }
133 setegid(gid);
134 return 1;
135 }
136
137 int
sync_open(void)138 sync_open(void)
139 {
140 struct stat tmp;
141
142 if (sync_fp != NULL)
143 (void) fclose(sync_fp);
144 (void) snprintf(sync_lock, sizeof sync_lock, LF, game);
145 (void) snprintf(sync_file, sizeof sync_file, SF, game);
146 setegid(egid);
147 if (stat(sync_file, &tmp) == -1) {
148 mode_t omask = umask(002);
149 sync_fp = fopen(sync_file, "w+");
150 (void) umask(omask);
151 } else
152 sync_fp = fopen(sync_file, "r+");
153 setegid(gid);
154 if (sync_fp == NULL)
155 return -1;
156 sync_seek = 0;
157 return 0;
158 }
159
160 void
sync_close(int remove)161 sync_close(int remove)
162 {
163 if (sync_fp != 0)
164 (void) fclose(sync_fp);
165 if (remove) {
166 setegid(egid);
167 (void) unlink(sync_file);
168 setegid(gid);
169 }
170 }
171
172 void
Write(int type,struct ship * ship,long a,long b,long c,long d)173 Write(int type, struct ship *ship, long a, long b, long c, long d)
174 {
175 (void) snprintf(sync_bp, sync_buf + sizeof sync_buf - sync_bp,
176 "%d %d 0 %ld %ld %ld %ld\n",
177 type, ship->file->index, a, b, c, d);
178 while (*sync_bp++)
179 ;
180 sync_bp--;
181 if (sync_bp >= &sync_buf[sizeof sync_buf])
182 abort();
183 (void) sync_update(type, ship, NULL, a, b, c, d);
184 }
185
186 void
Writestr(int type,struct ship * ship,const char * a)187 Writestr(int type, struct ship *ship, const char *a)
188 {
189 (void) snprintf(sync_bp, sync_buf + sizeof sync_buf - sync_bp,
190 "%d %d 1 %s\n",
191 type, ship->file->index, a);
192 while (*sync_bp++)
193 ;
194 sync_bp--;
195 if (sync_bp >= &sync_buf[sizeof sync_buf])
196 abort();
197 (void) sync_update(type, ship, a, 0, 0, 0, 0);
198 }
199
200 int
Sync(void)201 Sync(void)
202 {
203 sig_t sighup, sigint;
204 int n;
205 int type, shipnum, isstr;
206 char *astr;
207 long a, b, c, d;
208 char buf[80];
209 char erred = 0;
210
211 sighup = signal(SIGHUP, SIG_IGN);
212 sigint = signal(SIGINT, SIG_IGN);
213 for (n = TIMEOUT; --n >= 0;) {
214 #ifdef LOCK_EX
215 if (flock(fileno(sync_fp), LOCK_EX|LOCK_NB) >= 0)
216 break;
217 if (errno != EWOULDBLOCK)
218 return -1;
219 #else
220 setegid(egid);
221 if (link(sync_file, sync_lock) >= 0) {
222 setegid(gid);
223 break;
224 }
225 setegid(gid);
226 if (errno != EEXIST)
227 return -1;
228 #endif
229 sleep(1);
230 }
231 if (n <= 0)
232 return -1;
233 (void) fseek(sync_fp, sync_seek, SEEK_SET);
234 for (;;) {
235 switch (fscanf(sync_fp, "%d%d%d", &type, &shipnum, &isstr)) {
236 case 3:
237 break;
238 case EOF:
239 goto out;
240 default:
241 goto bad;
242 }
243 if (shipnum < 0 || shipnum >= cc->vessels)
244 goto bad;
245 if (isstr != 0 && isstr != 1)
246 goto bad;
247 if (isstr) {
248 int ch;
249 char *p;
250
251 for (p = buf;;) {
252 ch = getc(sync_fp);
253 switch (ch) {
254 case '\n':
255 case EOF:
256 break;
257 default:
258 if (p < buf + sizeof buf)
259 *p++ = ch;
260 continue;
261 }
262 break;
263 }
264 *p = 0;
265 for (p = buf; *p == ' '; p++)
266 ;
267 astr = p;
268 a = b = c = d = 0;
269 } else {
270 if (fscanf(sync_fp, "%ld%ld%ld%ld", &a, &b, &c, &d) != 4)
271 goto bad;
272 astr = NULL;
273 }
274 if (sync_update(type, SHIP(shipnum), astr, a, b, c, d) < 0)
275 goto bad;
276 }
277 bad:
278 erred++;
279 out:
280 if (!erred && sync_bp != sync_buf) {
281 (void) fseek(sync_fp, 0L, SEEK_END);
282 (void) fwrite(sync_buf, sizeof *sync_buf, sync_bp - sync_buf,
283 sync_fp);
284 (void) fflush(sync_fp);
285 sync_bp = sync_buf;
286 }
287 sync_seek = ftell(sync_fp);
288 #ifdef LOCK_EX
289 (void) flock(fileno(sync_fp), LOCK_UN);
290 #else
291 setegid(egid);
292 (void) unlink(sync_lock);
293 setegid(gid);
294 #endif
295 (void) signal(SIGHUP, sighup);
296 (void) signal(SIGINT, sigint);
297 return erred ? -1 : 0;
298 }
299
300 int
sync_update(int type,struct ship * ship,const char * astr,long a,long b,long c,long d)301 sync_update(int type, struct ship *ship, const char *astr, long a, long b,
302 long c, long d)
303 {
304 switch (type) {
305 case W_DBP: {
306 struct BP *p = &ship->file->DBP[a];
307 p->turnsent = b;
308 p->toship = SHIP(c);
309 p->mensent = d;
310 break;
311 }
312 case W_OBP: {
313 struct BP *p = &ship->file->OBP[a];
314 p->turnsent = b;
315 p->toship = SHIP(c);
316 p->mensent = d;
317 break;
318 }
319 case W_FOUL: {
320 struct snag *p = &ship->file->foul[a];
321 if (SHIP(a)->file->dir == 0)
322 break;
323 if (p->sn_count++ == 0)
324 p->sn_turn = turn;
325 ship->file->nfoul++;
326 break;
327 }
328 case W_GRAP: {
329 struct snag *p = &ship->file->grap[a];
330 if (SHIP(a)->file->dir == 0)
331 break;
332 if (p->sn_count++ == 0)
333 p->sn_turn = turn;
334 ship->file->ngrap++;
335 break;
336 }
337 case W_UNFOUL: {
338 struct snag *p = &ship->file->foul[a];
339 if (p->sn_count > 0) {
340 if (b) {
341 ship->file->nfoul -= p->sn_count;
342 p->sn_count = 0;
343 } else {
344 ship->file->nfoul--;
345 p->sn_count--;
346 }
347 }
348 break;
349 }
350 case W_UNGRAP: {
351 struct snag *p = &ship->file->grap[a];
352 if (p->sn_count > 0) {
353 if (b) {
354 ship->file->ngrap -= p->sn_count;
355 p->sn_count = 0;
356 } else {
357 ship->file->ngrap--;
358 p->sn_count--;
359 }
360 }
361 break;
362 }
363 case W_SIGNAL:
364 if (mode == MODE_PLAYER) {
365 if (nobells)
366 Signal("$$: %s", ship, astr);
367 else
368 Signal("\7$$: %s", ship, astr);
369 }
370 break;
371 case W_CREW: {
372 struct shipspecs *s = ship->specs;
373 s->crew1 = a;
374 s->crew2 = b;
375 s->crew3 = c;
376 break;
377 }
378 case W_CAPTAIN:
379 (void) strlcpy(ship->file->captain, astr,
380 sizeof ship->file->captain);
381 break;
382 case W_CAPTURED:
383 if (a < 0)
384 ship->file->captured = 0;
385 else
386 ship->file->captured = SHIP(a);
387 break;
388 case W_CLASS:
389 ship->specs->class = a;
390 break;
391 case W_DRIFT:
392 ship->file->drift = a;
393 break;
394 case W_EXPLODE:
395 if ((ship->file->explode = a) == 2)
396 ship->file->dir = 0;
397 break;
398 case W_FS:
399 ship->file->FS = a;
400 break;
401 case W_GUNL: {
402 struct shipspecs *s = ship->specs;
403 s->gunL = a;
404 s->carL = b;
405 break;
406 }
407 case W_GUNR: {
408 struct shipspecs *s = ship->specs;
409 s->gunR = a;
410 s->carR = b;
411 break;
412 }
413 case W_HULL:
414 ship->specs->hull = a;
415 break;
416 case W_MOVE:
417 (void) strlcpy(ship->file->movebuf, astr,
418 sizeof ship->file->movebuf);
419 break;
420 case W_PCREW:
421 ship->file->pcrew = a;
422 break;
423 case W_POINTS:
424 ship->file->points = a;
425 break;
426 case W_QUAL:
427 ship->specs->qual = a;
428 break;
429 case W_RIGG: {
430 struct shipspecs *s = ship->specs;
431 s->rig1 = a;
432 s->rig2 = b;
433 s->rig3 = c;
434 s->rig4 = d;
435 break;
436 }
437 case W_RIG1:
438 ship->specs->rig1 = a;
439 break;
440 case W_RIG2:
441 ship->specs->rig2 = a;
442 break;
443 case W_RIG3:
444 ship->specs->rig3 = a;
445 break;
446 case W_RIG4:
447 ship->specs->rig4 = a;
448 break;
449 case W_COL:
450 ship->file->col = a;
451 break;
452 case W_DIR:
453 ship->file->dir = a;
454 break;
455 case W_ROW:
456 ship->file->row = a;
457 break;
458 case W_SINK:
459 if ((ship->file->sink = a) == 2)
460 ship->file->dir = 0;
461 break;
462 case W_STRUCK:
463 ship->file->struck = a;
464 break;
465 case W_TA:
466 ship->specs->ta = a;
467 break;
468 case W_ALIVE:
469 alive = 1;
470 break;
471 case W_TURN:
472 turn = a;
473 break;
474 case W_WIND:
475 winddir = a;
476 windspeed = b;
477 break;
478 case W_BEGIN:
479 (void) strlcpy(ship->file->captain, "begin",
480 sizeof ship->file->captain);
481 people++;
482 break;
483 case W_END:
484 *ship->file->captain = 0;
485 ship->file->points = 0;
486 people--;
487 break;
488 case W_DDEAD:
489 hasdriver = 0;
490 break;
491 default:
492 fprintf(stderr, "sync_update: unknown type %d\r\n", type);
493 return -1;
494 }
495 return 0;
496 }
497