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