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