1 /* $NetBSD: sync.c,v 1.21 2003/08/07 09:37:45 agc Exp $ */ 2 3 /* 4 * Copyright (c) 1983, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 #if 0 35 static char sccsid[] = "@(#)sync.c 8.2 (Berkeley) 4/28/95"; 36 #else 37 __RCSID("$NetBSD: sync.c,v 1.21 2003/08/07 09:37:45 agc Exp $"); 38 #endif 39 #endif /* not lint */ 40 41 #include <fcntl.h> 42 #include <errno.h> 43 #include <signal.h> 44 #include <stdarg.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <time.h> 49 #include <unistd.h> 50 #include "extern.h" 51 #include "pathnames.h" 52 53 #define BUFSIZE 4096 54 55 static int sync_update(int, struct ship *, const char *, long, long, long, long); 56 57 static const char SF[] = _PATH_SYNC; 58 static const char LF[] = _PATH_LOCK; 59 static char sync_buf[BUFSIZE]; 60 static char *sync_bp = sync_buf; 61 static char sync_lock[sizeof SF]; 62 static char sync_file[sizeof LF]; 63 static long sync_seek; 64 static FILE *sync_fp; 65 66 void 67 fmtship(char *buf, size_t len, const char *fmt, struct ship *ship) 68 { 69 while (*fmt) { 70 if (len-- == 0) { 71 *buf = '\0'; 72 return; 73 } 74 if (*fmt == '$' && fmt[1] == '$') { 75 size_t l = snprintf(buf, len, "%s (%c%c)", 76 ship->shipname, colours(ship), sterncolour(ship)); 77 buf += l; 78 len -= l - 1; 79 fmt += 2; 80 } 81 else 82 *buf++ = *fmt++; 83 } 84 85 if (len > 0) 86 *buf = '\0'; 87 } 88 89 90 /*VARARGS3*/ 91 void 92 makesignal(struct ship *from, const char *fmt, struct ship *ship, ...) 93 { 94 char message[BUFSIZ]; 95 char format[BUFSIZ]; 96 va_list ap; 97 98 va_start(ap, ship); 99 fmtship(format, sizeof(format), fmt, ship); 100 vsprintf(message, format, ap); 101 va_end(ap); 102 Writestr(W_SIGNAL, from, message); 103 } 104 105 /*VARARGS2*/ 106 void 107 makemsg(struct ship *from, const char *fmt, ...) 108 { 109 char message[BUFSIZ]; 110 va_list ap; 111 112 va_start(ap, fmt); 113 vsprintf(message, fmt, ap); 114 va_end(ap); 115 Writestr(W_SIGNAL, from, message); 116 } 117 118 int 119 sync_exists(int game) 120 { 121 char buf[sizeof sync_file]; 122 struct stat s; 123 time_t t; 124 125 sprintf(buf, SF, game); 126 time(&t); 127 setegid(egid); 128 if (stat(buf, &s) < 0) { 129 setegid(gid); 130 return 0; 131 } 132 if (s.st_mtime < t - 60*60*2) { /* 2 hours */ 133 unlink(buf); 134 sprintf(buf, LF, game); 135 unlink(buf); 136 setegid(gid); 137 return 0; 138 } else { 139 setegid(gid); 140 return 1; 141 } 142 } 143 144 int 145 sync_open(void) 146 { 147 struct stat tmp; 148 if (sync_fp != NULL) 149 fclose(sync_fp); 150 sprintf(sync_lock, LF, game); 151 sprintf(sync_file, SF, game); 152 setegid(egid); 153 if (stat(sync_file, &tmp) < 0) { 154 mode_t omask = umask(002); 155 sync_fp = fopen(sync_file, "w+"); 156 umask(omask); 157 } else 158 sync_fp = fopen(sync_file, "r+"); 159 setegid(gid); 160 if (sync_fp == NULL) 161 return -1; 162 sync_seek = 0; 163 return 0; 164 } 165 166 void 167 sync_close(int remove) 168 { 169 if (sync_fp != 0) 170 fclose(sync_fp); 171 if (remove) { 172 setegid(egid); 173 unlink(sync_file); 174 setegid(gid); 175 } 176 } 177 178 void 179 Write(int type, struct ship *ship, long a, long b, long c, long d) 180 { 181 182 sprintf(sync_bp, "%d %d 0 %ld %ld %ld %ld\n", 183 type, ship->file->index, a, b, c, d); 184 while (*sync_bp++) 185 ; 186 sync_bp--; 187 if (sync_bp >= &sync_buf[sizeof sync_buf]) 188 abort(); 189 sync_update(type, ship, NULL, a, b, c, d); 190 } 191 192 void 193 Writestr(int type, struct ship *ship, const char *a) 194 { 195 sprintf(sync_bp, "%d %d 1 %s\n", type, ship->file->index, a); 196 while (*sync_bp++) 197 ; 198 sync_bp--; 199 if (sync_bp >= &sync_buf[sizeof sync_buf]) 200 abort(); 201 sync_update(type, ship, a, 0, 0, 0, 0); 202 } 203 204 int 205 Sync(void) 206 { 207 sig_t sighup, sigint; 208 int n; 209 int type, shipnum, isstr; 210 char *astr; 211 long a, b, c, d; 212 char buf[80]; 213 char erred = 0; 214 215 sighup = signal(SIGHUP, SIG_IGN); 216 sigint = signal(SIGINT, SIG_IGN); 217 for (n = TIMEOUT; --n >= 0;) { 218 #ifdef LOCK_EX 219 if (flock(fileno(sync_fp), LOCK_EX|LOCK_NB) >= 0) 220 break; 221 if (errno != EWOULDBLOCK) 222 return -1; 223 #else 224 setegid(egid); 225 if (link(sync_file, sync_lock) >= 0) { 226 setegid(gid); 227 break; 228 } 229 setegid(gid); 230 if (errno != EEXIST) 231 return -1; 232 #endif 233 sleep(1); 234 } 235 if (n <= 0) 236 return -1; 237 fseek(sync_fp, sync_seek, SEEK_SET); 238 for (;;) { 239 switch (fscanf(sync_fp, "%d%d%d", &type, &shipnum, &isstr)) { 240 case 3: 241 break; 242 case EOF: 243 goto out; 244 default: 245 goto bad; 246 } 247 if (shipnum < 0 || shipnum >= cc->vessels) 248 goto bad; 249 if (isstr != 0 && isstr != 1) 250 goto bad; 251 if (isstr) { 252 char *p; 253 for (p = buf;;) { 254 switch (*p++ = getc(sync_fp)) { 255 case '\n': 256 p--; 257 case EOF: 258 break; 259 default: 260 if (p >= buf + sizeof buf) 261 p--; 262 continue; 263 } 264 break; 265 } 266 *p = 0; 267 for (p = buf; *p == ' '; p++) 268 ; 269 astr = p; 270 a = b = c = d = 0; 271 } else { 272 if (fscanf(sync_fp, "%ld%ld%ld%ld", &a, &b, &c, &d) != 4) 273 goto bad; 274 astr = NULL; 275 } 276 if (sync_update(type, SHIP(shipnum), astr, a, b, c, d) < 0) 277 goto bad; 278 } 279 bad: 280 erred++; 281 out: 282 if (!erred && sync_bp != sync_buf) { 283 fseek(sync_fp, 0L, SEEK_END); 284 fwrite(sync_buf, sizeof *sync_buf, sync_bp - sync_buf, 285 sync_fp); 286 fflush(sync_fp); 287 sync_bp = sync_buf; 288 } 289 sync_seek = ftell(sync_fp); 290 #ifdef LOCK_EX 291 flock(fileno(sync_fp), LOCK_UN); 292 #else 293 setegid(egid); 294 unlink(sync_lock); 295 setegid(gid); 296 #endif 297 signal(SIGHUP, sighup); 298 signal(SIGINT, sigint); 299 return erred ? -1 : 0; 300 } 301 302 static int 303 sync_update(int type, struct ship *ship, const char *astr, long a, long b, long c, long d) 304 { 305 switch (type) { 306 case W_DBP: { 307 struct BP *p = &ship->file->DBP[a]; 308 p->turnsent = b; 309 p->toship = SHIP(c); 310 p->mensent = d; 311 break; 312 } 313 case W_OBP: { 314 struct BP *p = &ship->file->OBP[a]; 315 p->turnsent = b; 316 p->toship = SHIP(c); 317 p->mensent = d; 318 break; 319 } 320 case W_FOUL: { 321 struct snag *p = &ship->file->foul[a]; 322 if (SHIP(a)->file->dir == 0) 323 break; 324 if (p->sn_count++ == 0) 325 p->sn_turn = turn; 326 ship->file->nfoul++; 327 break; 328 } 329 case W_GRAP: { 330 struct snag *p = &ship->file->grap[a]; 331 if (SHIP(a)->file->dir == 0) 332 break; 333 if (p->sn_count++ == 0) 334 p->sn_turn = turn; 335 ship->file->ngrap++; 336 break; 337 } 338 case W_UNFOUL: { 339 struct snag *p = &ship->file->foul[a]; 340 if (p->sn_count > 0) { 341 if (b) { 342 ship->file->nfoul -= p->sn_count; 343 p->sn_count = 0; 344 } else { 345 ship->file->nfoul--; 346 p->sn_count--; 347 } 348 } 349 break; 350 } 351 case W_UNGRAP: { 352 struct snag *p = &ship->file->grap[a]; 353 if (p->sn_count > 0) { 354 if (b) { 355 ship->file->ngrap -= p->sn_count; 356 p->sn_count = 0; 357 } else { 358 ship->file->ngrap--; 359 p->sn_count--; 360 } 361 } 362 break; 363 } 364 case W_SIGNAL: 365 if (mode == MODE_PLAYER) { 366 if (nobells) 367 Signal("$$: %s", ship, astr); 368 else 369 Signal("\7$$: %s", ship, astr); 370 } 371 break; 372 case W_CREW: { 373 struct shipspecs *s = ship->specs; 374 s->crew1 = a; 375 s->crew2 = b; 376 s->crew3 = c; 377 break; 378 } 379 case W_CAPTAIN: 380 strncpy(ship->file->captain, astr, 381 sizeof ship->file->captain - 1); 382 ship->file->captain[sizeof ship->file->captain - 1] = 0; 383 break; 384 case W_CAPTURED: 385 if (a < 0) 386 ship->file->captured = 0; 387 else 388 ship->file->captured = SHIP(a); 389 break; 390 case W_CLASS: 391 ship->specs->class = a; 392 break; 393 case W_DRIFT: 394 ship->file->drift = a; 395 break; 396 case W_EXPLODE: 397 if ((ship->file->explode = a) == 2) 398 ship->file->dir = 0; 399 break; 400 case W_FS: 401 ship->file->FS = a; 402 break; 403 case W_GUNL: { 404 struct shipspecs *s = ship->specs; 405 s->gunL = a; 406 s->carL = b; 407 break; 408 } 409 case W_GUNR: { 410 struct shipspecs *s = ship->specs; 411 s->gunR = a; 412 s->carR = b; 413 break; 414 } 415 case W_HULL: 416 ship->specs->hull = a; 417 break; 418 case W_MOVE: 419 strncpy(ship->file->movebuf, astr, 420 sizeof ship->file->movebuf - 1); 421 ship->file->movebuf[sizeof ship->file->movebuf - 1] = 0; 422 break; 423 case W_PCREW: 424 ship->file->pcrew = a; 425 break; 426 case W_POINTS: 427 ship->file->points = a; 428 break; 429 case W_QUAL: 430 ship->specs->qual = a; 431 break; 432 case W_RIGG: { 433 struct shipspecs *s = ship->specs; 434 s->rig1 = a; 435 s->rig2 = b; 436 s->rig3 = c; 437 s->rig4 = d; 438 break; 439 } 440 case W_RIG1: 441 ship->specs->rig1 = a; 442 break; 443 case W_RIG2: 444 ship->specs->rig2 = a; 445 break; 446 case W_RIG3: 447 ship->specs->rig3 = a; 448 break; 449 case W_RIG4: 450 ship->specs->rig4 = a; 451 break; 452 case W_COL: 453 ship->file->col = a; 454 break; 455 case W_DIR: 456 ship->file->dir = a; 457 break; 458 case W_ROW: 459 ship->file->row = a; 460 break; 461 case W_SINK: 462 if ((ship->file->sink = a) == 2) 463 ship->file->dir = 0; 464 break; 465 case W_STRUCK: 466 ship->file->struck = a; 467 break; 468 case W_TA: 469 ship->specs->ta = a; 470 break; 471 case W_ALIVE: 472 alive = 1; 473 break; 474 case W_TURN: 475 turn = a; 476 break; 477 case W_WIND: 478 winddir = a; 479 windspeed = b; 480 break; 481 case W_BEGIN: 482 strcpy(ship->file->captain, "begin"); 483 people++; 484 break; 485 case W_END: 486 *ship->file->captain = 0; 487 ship->file->points = 0; 488 people--; 489 break; 490 case W_DDEAD: 491 hasdriver = 0; 492 break; 493 default: 494 fprintf(stderr, "sync_update: unknown type %d\r\n", type); 495 return -1; 496 } 497 return 0; 498 } 499