xref: /openbsd/games/atc/log.c (revision 891d7ab6)
1 /*	$OpenBSD: log.c,v 1.17 2009/10/27 23:59:23 deraadt Exp $	*/
2 /*	$NetBSD: log.c,v 1.3 1995/03/21 15:04:21 cgd Exp $	*/
3 
4 /*-
5  * Copyright (c) 1990, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * Ed James.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 /*
37  * Copyright (c) 1987 by Ed James, UC Berkeley.  All rights reserved.
38  *
39  * Copy permission is hereby granted provided that this notice is
40  * retained on all partial or complete copies.
41  *
42  * For more info on this and all of my stuff, mail edjames@berkeley.edu.
43  */
44 
45 #include "include.h"
46 #include "pathnames.h"
47 
48 static FILE *score_fp;
49 
50 int
51 compar(const void *va, const void *vb)
52 {
53 	const SCORE *a, *b;
54 
55 	a = (const SCORE *)va;
56 	b = (const SCORE *)vb;
57 	if (b->planes == a->planes)
58 		return (b->time - a->time);
59 	else
60 		return (b->planes - a->planes);
61 }
62 
63 #define SECAMIN		60
64 #define MINAHOUR	60
65 #define HOURADAY	24
66 #define SECAHOUR	(SECAMIN * MINAHOUR)
67 #define SECADAY		(SECAHOUR * HOURADAY)
68 #define DAY(t)		((t) / SECADAY)
69 #define HOUR(t)		(((t) % SECADAY) / SECAHOUR)
70 #define MINUTES(t)		(((t) % SECAHOUR) / SECAMIN)
71 #define SEC(t)		((t) % SECAMIN)
72 
73 const char	*
74 timestr(int t)
75 {
76 	static char	s[80];
77 
78 	if (DAY(t) > 0)
79 		(void)snprintf(s, sizeof s, "%dd+%02dhrs", DAY(t), HOUR(t));
80 	else if (HOUR(t) > 0)
81 		(void)snprintf(s, sizeof s, "%d:%02d:%02d",
82 		    HOUR(t), MINUTES(t), SEC(t));
83 	else if (MINUTES(t) > 0)
84 		(void)snprintf(s, sizeof s, "%d:%02d", MINUTES(t), SEC(t));
85 	else if (SEC(t) > 0)
86 		(void)snprintf(s, sizeof s, ":%02d", SEC(t));
87 	else
88 		*s = '\0';
89 
90 	return (s);
91 }
92 
93 int
94 open_score_file(void)
95 {
96 	mode_t old_mode;
97 	int score_fd;
98 
99 	old_mode = umask(0);
100 	score_fd = open(_PATH_SCORE, O_CREAT|O_RDWR, 0664);
101 	if (score_fd < 0) {
102 		perror(_PATH_SCORE);
103 		return (-1);
104 	}
105 	/*
106 	 * This is done to take advantage of stdio, while still
107 	 * allowing a O_CREAT during the open(2) of the log file.
108 	 */
109 	score_fp = fdopen(score_fd, "r+");
110 	if (score_fp == NULL) {
111 		perror(_PATH_SCORE);
112 		return (-1);
113 	}
114 	umask(old_mode);
115 	return (0);
116 }
117 
118 int
119 log_score(int list_em)
120 {
121 	int		i, num_scores = 0, good, changed = 0, found = 0;
122 	struct passwd	*pw;
123 	char		*cp;
124 	char		scanstr[50];
125 	SCORE		score[NUM_SCORES], thisscore;
126 
127 	if (score_fp == NULL)
128 		return (-1);
129 #ifdef BSD
130 	if (flock(fileno(score_fp), LOCK_EX) < 0)
131 #endif
132 #ifdef SYSV
133 	while (lockf(fileno(score_fp), F_LOCK, 1) < 0)
134 #endif
135 	{
136 		perror("flock");
137 		return (-1);
138 	}
139 	snprintf(scanstr, 50, "%%%zus %%%zus %%d %%d %%d", sizeof(score[0].name)-1,
140 	    sizeof(score[0].game)-1);
141 	for (;;) {
142 		good = fscanf(score_fp, scanstr,
143 			score[num_scores].name,
144 			score[num_scores].game,
145 			&score[num_scores].planes,
146 			&score[num_scores].time,
147 			&score[num_scores].real_time);
148 		if (good != 5 || ++num_scores >= NUM_SCORES)
149 			break;
150 	}
151 	if (!test_mode && !list_em) {
152 		if ((pw = (struct passwd *) getpwuid(getuid())) == NULL) {
153 			fprintf(stderr,
154 				"getpwuid failed for uid %u.  Who are you?\n",
155 				getuid());
156 			return (-1);
157 		}
158 		strlcpy(thisscore.name, pw->pw_name, sizeof(thisscore.name));
159 
160 		cp = strrchr(file, '/');
161 		if (cp == NULL) {
162 			warnx("log: where's the '/' in %s?", file);
163 			return (-1);
164 		}
165 		cp++;
166 		strlcpy(thisscore.game, cp, sizeof(thisscore.game));
167 
168 		thisscore.time = clck;
169 		thisscore.planes = safe_planes;
170 		thisscore.real_time = time(0) - start_time;
171 
172 		for (i = 0; i < num_scores; i++) {
173 			if (strcmp(thisscore.name, score[i].name) == 0 &&
174 			    strcmp(thisscore.game, score[i].game) == 0) {
175 				if (thisscore.time > score[i].time) {
176 					score[i].time = thisscore.time;
177 					score[i].planes = thisscore.planes;
178 					score[i].real_time =
179 						thisscore.real_time;
180 					changed++;
181 				}
182 				found++;
183 				break;
184 			}
185 		}
186 		if (!found) {
187 			for (i = 0; i < num_scores; i++) {
188 				if (thisscore.time > score[i].time) {
189 					if (num_scores < NUM_SCORES)
190 						num_scores++;
191 					memcpy(&score[num_scores - 1],
192 						&score[i],
193 						sizeof (score[i]));
194 					memcpy(&score[i], &thisscore,
195 						sizeof (score[i]));
196 					changed++;
197 					break;
198 				}
199 			}
200 		}
201 		if (!found && !changed && num_scores < NUM_SCORES) {
202 			memcpy(&score[num_scores], &thisscore,
203 				sizeof (score[num_scores]));
204 			num_scores++;
205 			changed++;
206 		}
207 
208 		if (changed) {
209 			if (found)
210 				puts("You beat your previous score!");
211 			else
212 				puts("You made the top players list!");
213 			qsort(score, num_scores, sizeof (*score), compar);
214 			rewind(score_fp);
215 			for (i = 0; i < num_scores; i++)
216 				fprintf(score_fp, "%s %s %d %d %d\n",
217 					score[i].name,
218 					score[i].game, score[i].planes,
219 					score[i].time, score[i].real_time);
220 		} else {
221 			if (found)
222 				puts("You didn't beat your previous score.");
223 			else
224 				puts("You didn't make the top players list.");
225 		}
226 		putchar('\n');
227 	}
228 #ifdef BSD
229 	flock(fileno(score_fp), LOCK_UN);
230 #endif
231 #ifdef SYSV
232 	/* lock will evaporate upon close */
233 #endif
234 #if 0
235 	fclose(score_fp);
236 #else
237 	fflush(score_fp);
238 	fsync(fileno(score_fp));
239 	rewind(score_fp);
240 #endif
241 	printf("%2s:  %-31s  %-18s  %4s  %9s  %4s\n", "#", "name",
242 		"game", "time", "real time", "safe");
243 	puts("-------------------------------------------------------------------------------");
244 	for (i = 0; i < num_scores; i++) {
245 		printf("%2d:  %-31s  %-18s  %4d  %9s  %4d\n", i + 1,
246 			score[i].name, score[i].game,
247 			score[i].time, timestr(score[i].real_time),
248 			score[i].planes);
249 	}
250 	putchar('\n');
251 	return (0);
252 }
253 
254 void
255 log_score_quit(int dummy)
256 {
257 	(void)log_score(0);
258 	exit(0);
259 }
260