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