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