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