Merge branch 'vendor/LIBARCHIVE'
[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. 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 }