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