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 } 461