log.c 7.8 KB

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