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