1*b65f9321Sderaadt /* $OpenBSD: log.c,v 1.26 2024/08/20 15:48:32 deraadt Exp $ */ 2df930be7Sderaadt /* $NetBSD: log.c,v 1.3 1995/03/21 15:04:21 cgd Exp $ */ 3df930be7Sderaadt 4df930be7Sderaadt /*- 5df930be7Sderaadt * Copyright (c) 1990, 1993 6df930be7Sderaadt * The Regents of the University of California. All rights reserved. 7df930be7Sderaadt * 8df930be7Sderaadt * This code is derived from software contributed to Berkeley by 9df930be7Sderaadt * Ed James. 10df930be7Sderaadt * 11df930be7Sderaadt * Redistribution and use in source and binary forms, with or without 12df930be7Sderaadt * modification, are permitted provided that the following conditions 13df930be7Sderaadt * are met: 14df930be7Sderaadt * 1. Redistributions of source code must retain the above copyright 15df930be7Sderaadt * notice, this list of conditions and the following disclaimer. 16df930be7Sderaadt * 2. Redistributions in binary form must reproduce the above copyright 17df930be7Sderaadt * notice, this list of conditions and the following disclaimer in the 18df930be7Sderaadt * documentation and/or other materials provided with the distribution. 197a09557bSmillert * 3. Neither the name of the University nor the names of its contributors 20df930be7Sderaadt * may be used to endorse or promote products derived from this software 21df930be7Sderaadt * without specific prior written permission. 22df930be7Sderaadt * 23df930be7Sderaadt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24df930be7Sderaadt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25df930be7Sderaadt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26df930be7Sderaadt * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27df930be7Sderaadt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28df930be7Sderaadt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29df930be7Sderaadt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30df930be7Sderaadt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31df930be7Sderaadt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32df930be7Sderaadt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33df930be7Sderaadt * SUCH DAMAGE. 34df930be7Sderaadt */ 35df930be7Sderaadt 36df930be7Sderaadt /* 37df930be7Sderaadt * Copyright (c) 1987 by Ed James, UC Berkeley. All rights reserved. 38df930be7Sderaadt * 39df930be7Sderaadt * Copy permission is hereby granted provided that this notice is 40df930be7Sderaadt * retained on all partial or complete copies. 41df930be7Sderaadt * 42df930be7Sderaadt * For more info on this and all of my stuff, mail edjames@berkeley.edu. 43df930be7Sderaadt */ 44df930be7Sderaadt 452317ec67Smestre #include <sys/stat.h> 462317ec67Smestre #include <sys/types.h> 472317ec67Smestre 482317ec67Smestre #include <err.h> 492317ec67Smestre #include <errno.h> 502317ec67Smestre #include <fcntl.h> 512317ec67Smestre #include <stdlib.h> 522317ec67Smestre #include <string.h> 53ee7acb09Stb #include <time.h> 542317ec67Smestre #include <unistd.h> 552317ec67Smestre 562317ec67Smestre #include "extern.h" 57df930be7Sderaadt #include "pathnames.h" 58df930be7Sderaadt 59f83b5105Skstailey static FILE *score_fp; 60f83b5105Skstailey 6131aab2a5Spjanzen int 623eb8c9edSjsg compar(const void *va, const void *vb) 63df930be7Sderaadt { 6431aab2a5Spjanzen const SCORE *a, *b; 6531aab2a5Spjanzen 665803e5dcSpjanzen a = (const SCORE *)va; 675803e5dcSpjanzen b = (const SCORE *)vb; 68df930be7Sderaadt if (b->planes == a->planes) 69df930be7Sderaadt return (b->time - a->time); 70df930be7Sderaadt else 71df930be7Sderaadt return (b->planes - a->planes); 72df930be7Sderaadt } 73df930be7Sderaadt 74df930be7Sderaadt #define SECAMIN 60 75df930be7Sderaadt #define MINAHOUR 60 76df930be7Sderaadt #define HOURADAY 24 77df930be7Sderaadt #define SECAHOUR (SECAMIN * MINAHOUR) 78df930be7Sderaadt #define SECADAY (SECAHOUR * HOURADAY) 79df930be7Sderaadt #define DAY(t) ((t) / SECADAY) 80df930be7Sderaadt #define HOUR(t) (((t) % SECADAY) / SECAHOUR) 81f0bac872Spjanzen #define MINUTES(t) (((t) % SECAHOUR) / SECAMIN) 82df930be7Sderaadt #define SEC(t) ((t) % SECAMIN) 83df930be7Sderaadt 8431aab2a5Spjanzen const char * 853eb8c9edSjsg timestr(int t) 86df930be7Sderaadt { 87df930be7Sderaadt static char s[80]; 88df930be7Sderaadt 89df930be7Sderaadt if (DAY(t) > 0) 9042ceebb3Sderaadt (void)snprintf(s, sizeof s, "%dd+%02dhrs", DAY(t), HOUR(t)); 91df930be7Sderaadt else if (HOUR(t) > 0) 9242ceebb3Sderaadt (void)snprintf(s, sizeof s, "%d:%02d:%02d", 9342ceebb3Sderaadt HOUR(t), MINUTES(t), SEC(t)); 94f0bac872Spjanzen else if (MINUTES(t) > 0) 9542ceebb3Sderaadt (void)snprintf(s, sizeof s, "%d:%02d", MINUTES(t), SEC(t)); 96df930be7Sderaadt else if (SEC(t) > 0) 9742ceebb3Sderaadt (void)snprintf(s, sizeof s, ":%02d", SEC(t)); 98df930be7Sderaadt else 99df930be7Sderaadt *s = '\0'; 100df930be7Sderaadt 101df930be7Sderaadt return (s); 102df930be7Sderaadt } 103df930be7Sderaadt 10431aab2a5Spjanzen int 1053eb8c9edSjsg open_score_file(void) 106df930be7Sderaadt { 107f83b5105Skstailey mode_t old_mode; 108bf2d3977Stb char *home; 109bf2d3977Stb char scorefile[PATH_MAX]; 110bf2d3977Stb int ret; 111f83b5105Skstailey int score_fd; 112df930be7Sderaadt 113bf2d3977Stb home = getenv("HOME"); 114bf2d3977Stb if (home == NULL || *home == '\0') 115bf2d3977Stb err(1, "getenv"); 116bf2d3977Stb ret = snprintf(scorefile, sizeof(scorefile), "%s/%s", home, 117bf2d3977Stb ".atc.scores"); 118bf2d3977Stb if (ret < 0 || ret >= PATH_MAX) 119bf2d3977Stb errc(1, ENAMETOOLONG, "%s/%s", home, ".atc.scores"); 120bf2d3977Stb 121f83b5105Skstailey old_mode = umask(0); 122bf2d3977Stb score_fd = open(scorefile, O_CREAT|O_RDWR, 0644); 123df69c215Sderaadt if (score_fd == -1) 124bf2d3977Stb err(1, "open"); 125df930be7Sderaadt /* 126df930be7Sderaadt * This is done to take advantage of stdio, while still 127df930be7Sderaadt * allowing a O_CREAT during the open(2) of the log file. 128df930be7Sderaadt */ 129f83b5105Skstailey score_fp = fdopen(score_fd, "r+"); 130bf2d3977Stb if (score_fp == NULL) 131bf2d3977Stb err(1, "fdopen"); 132f83b5105Skstailey umask(old_mode); 13331aab2a5Spjanzen return (0); 134f83b5105Skstailey } 135f83b5105Skstailey 13631aab2a5Spjanzen int 1373eb8c9edSjsg log_score(int list_em) 138f83b5105Skstailey { 139f83b5105Skstailey int i, num_scores = 0, good, changed = 0, found = 0; 140bf2d3977Stb const char *name; 141f83b5105Skstailey char *cp; 1427163d9d0Spjanzen char scanstr[50]; 143f0bac872Spjanzen SCORE score[NUM_SCORES], thisscore; 144f83b5105Skstailey 14531aab2a5Spjanzen if (score_fp == NULL) 14631aab2a5Spjanzen return (-1); 147df69c215Sderaadt if (flock(fileno(score_fp), LOCK_EX) == -1) 148bf2d3977Stb err(1, "flock"); 1491717b5a3Schl snprintf(scanstr, 50, "%%%zus %%%zus %%d %%d %%d", sizeof(score[0].name)-1, 150cd48ae86Sderaadt sizeof(score[0].game)-1); 151df930be7Sderaadt for (;;) { 1527163d9d0Spjanzen good = fscanf(score_fp, scanstr, 153df930be7Sderaadt score[num_scores].name, 154df930be7Sderaadt score[num_scores].game, 155df930be7Sderaadt &score[num_scores].planes, 156df930be7Sderaadt &score[num_scores].time, 157df930be7Sderaadt &score[num_scores].real_time); 158f0bac872Spjanzen if (good != 5 || ++num_scores >= NUM_SCORES) 159df930be7Sderaadt break; 160df930be7Sderaadt } 161df930be7Sderaadt if (!test_mode && !list_em) { 162bf2d3977Stb name = getenv("LOGNAME"); 163bf2d3977Stb if (name == NULL || *name == '\0') 164bf2d3977Stb name = getenv("USER"); 165bf2d3977Stb if (name == NULL || *name == '\0') 166bf2d3977Stb name = getlogin(); 167bf2d3977Stb if (name == NULL || *name == '\0') 168bf2d3977Stb name = " ???"; 169bf2d3977Stb strlcpy(thisscore.name, name, sizeof(thisscore.name)); 170df930be7Sderaadt 171180acc8fSmillert cp = strrchr(file, '/'); 172df930be7Sderaadt if (cp == NULL) { 173f0bac872Spjanzen warnx("log: where's the '/' in %s?", file); 174df930be7Sderaadt return (-1); 175df930be7Sderaadt } 176df930be7Sderaadt cp++; 177f0bac872Spjanzen strlcpy(thisscore.game, cp, sizeof(thisscore.game)); 178df930be7Sderaadt 179df930be7Sderaadt thisscore.time = clck; 180df930be7Sderaadt thisscore.planes = safe_planes; 181df930be7Sderaadt thisscore.real_time = time(0) - start_time; 182df930be7Sderaadt 183df930be7Sderaadt for (i = 0; i < num_scores; i++) { 184df930be7Sderaadt if (strcmp(thisscore.name, score[i].name) == 0 && 185df930be7Sderaadt strcmp(thisscore.game, score[i].game) == 0) { 186df930be7Sderaadt if (thisscore.time > score[i].time) { 187df930be7Sderaadt score[i].time = thisscore.time; 188df930be7Sderaadt score[i].planes = thisscore.planes; 189df930be7Sderaadt score[i].real_time = 190df930be7Sderaadt thisscore.real_time; 191df930be7Sderaadt changed++; 192df930be7Sderaadt } 193df930be7Sderaadt found++; 194df930be7Sderaadt break; 195df930be7Sderaadt } 196df930be7Sderaadt } 197df930be7Sderaadt if (!found) { 198df930be7Sderaadt for (i = 0; i < num_scores; i++) { 199df930be7Sderaadt if (thisscore.time > score[i].time) { 200df930be7Sderaadt if (num_scores < NUM_SCORES) 201df930be7Sderaadt num_scores++; 20231aab2a5Spjanzen memcpy(&score[num_scores - 1], 20331aab2a5Spjanzen &score[i], 204df930be7Sderaadt sizeof (score[i])); 20531aab2a5Spjanzen memcpy(&score[i], &thisscore, 206df930be7Sderaadt sizeof (score[i])); 207df930be7Sderaadt changed++; 208df930be7Sderaadt break; 209df930be7Sderaadt } 210df930be7Sderaadt } 211df930be7Sderaadt } 212df930be7Sderaadt if (!found && !changed && num_scores < NUM_SCORES) { 21331aab2a5Spjanzen memcpy(&score[num_scores], &thisscore, 214df930be7Sderaadt sizeof (score[num_scores])); 215df930be7Sderaadt num_scores++; 216df930be7Sderaadt changed++; 217df930be7Sderaadt } 218df930be7Sderaadt 219cceea54aSderaadt if (seeded) { 220cceea54aSderaadt puts("The high score list does not include '-r' seeded games."); 221cceea54aSderaadt } else if (changed) { 222df930be7Sderaadt if (found) 223df930be7Sderaadt puts("You beat your previous score!"); 224df930be7Sderaadt else 225df930be7Sderaadt puts("You made the top players list!"); 226df930be7Sderaadt qsort(score, num_scores, sizeof (*score), compar); 22745555366Smestre if (fseek(score_fp, 0L, SEEK_SET) == -1) 22845555366Smestre err(1, "fseek"); 229df930be7Sderaadt for (i = 0; i < num_scores; i++) 230f0bac872Spjanzen fprintf(score_fp, "%s %s %d %d %d\n", 231f0bac872Spjanzen score[i].name, 232df930be7Sderaadt score[i].game, score[i].planes, 233df930be7Sderaadt score[i].time, score[i].real_time); 234df930be7Sderaadt } else { 235df930be7Sderaadt if (found) 236df930be7Sderaadt puts("You didn't beat your previous score."); 237df930be7Sderaadt else 238df930be7Sderaadt puts("You didn't make the top players list."); 239df930be7Sderaadt } 240df930be7Sderaadt putchar('\n'); 241df930be7Sderaadt } 242f83b5105Skstailey flock(fileno(score_fp), LOCK_UN); 243f83b5105Skstailey fflush(score_fp); 244f83b5105Skstailey fsync(fileno(score_fp)); 24545555366Smestre if (fseek(score_fp, 0L, SEEK_SET) == -1) 24645555366Smestre err(1, "fseek"); 247f0bac872Spjanzen printf("%2s: %-31s %-18s %4s %9s %4s\n", "#", "name", 248f0bac872Spjanzen "game", "time", "real time", "safe"); 249df930be7Sderaadt puts("-------------------------------------------------------------------------------"); 250df930be7Sderaadt for (i = 0; i < num_scores; i++) { 251f0bac872Spjanzen printf("%2d: %-31s %-18s %4d %9s %4d\n", i + 1, 252f0bac872Spjanzen score[i].name, score[i].game, 253df930be7Sderaadt score[i].time, timestr(score[i].real_time), 254df930be7Sderaadt score[i].planes); 255df930be7Sderaadt } 256df930be7Sderaadt putchar('\n'); 257df930be7Sderaadt return (0); 258df930be7Sderaadt } 25931aab2a5Spjanzen 26031aab2a5Spjanzen void 2613eb8c9edSjsg log_score_quit(int dummy) 26231aab2a5Spjanzen { 263*b65f9321Sderaadt (void)log_score(0); /* XXX signal race */ 264*b65f9321Sderaadt exit(0); /* XXX signal race */ 26531aab2a5Spjanzen } 266