Mercurial > emacs
annotate lib-src/update-game-score.c @ 44956:2b2fbd33a08c
*** empty log message ***
author | Stefan Monnier <monnier@iro.umontreal.ca> |
---|---|
date | Mon, 29 Apr 2002 04:02:22 +0000 |
parents | d095e59dc01d |
children | cc0ab9acdc46 |
rev | line source |
---|---|
44184 | 1 /* update-game-score.c --- Update a score file |
2 Copyright (C) 2002 Free Software Foundation, Inc. | |
3 | |
4 This file is part of GNU Emacs. | |
5 | |
6 GNU Emacs is free software; you can redistribute it and/or modify | |
7 it under the terms of the GNU General Public License as published by | |
8 the Free Software Foundation; either version 2, or (at your option) | |
9 any later version. | |
10 | |
11 GNU Emacs is distributed in the hope that it will be useful, | |
12 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 GNU General Public License for more details. | |
15 | |
16 You should have received a copy of the GNU General Public License | |
17 along with GNU Emacs; see the file COPYING. If not, write to | |
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
19 Boston, MA 02111-1307, USA. */ | |
20 | |
21 /* This program is allows a game to securely and atomically update a | |
44481
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
22 score file. It should be installed setuid, owned by an appropriate |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
23 user like `games'. |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
24 |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
25 Alternatively, it can be compiled without HAVE_SHARED_GAME_DIR |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
26 defined, and in that case it will store scores in the user's home |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
27 directory (it should NOT be setuid). |
44184 | 28 |
29 Created 2002/03/22, by Colin Walters <walters@debian.org> | |
30 */ | |
31 | |
32 #define _GNU_SOURCE | |
33 | |
44639
44995332ed1b
Move config.h before the other headers, to prevent compiler warnings
Eli Zaretskii <eliz@gnu.org>
parents:
44576
diff
changeset
|
34 #include <config.h> |
44995332ed1b
Move config.h before the other headers, to prevent compiler warnings
Eli Zaretskii <eliz@gnu.org>
parents:
44576
diff
changeset
|
35 |
44184 | 36 #include <unistd.h> |
37 #include <errno.h> | |
38 #include <string.h> | |
39 #include <stdlib.h> | |
40 #include <stdio.h> | |
41 #include <time.h> | |
44402
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
42 #include <pwd.h> |
44184 | 43 #include <ctype.h> |
44 #include <fcntl.h> | |
44481
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
45 #include <stdarg.h> |
44184 | 46 #include <sys/stat.h> |
47 | |
48 #define MAX_ATTEMPTS 5 | |
44481
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
49 #define MAX_SCORES 200 |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
50 #define MAX_DATA_LEN 1024 |
44419
16b3622178f9
update-game-score.c (SCORE_FILE_PREFIX): Don't hardcode.
Colin Walters <walters@gnu.org>
parents:
44404
diff
changeset
|
51 |
16b3622178f9
update-game-score.c (SCORE_FILE_PREFIX): Don't hardcode.
Colin Walters <walters@gnu.org>
parents:
44404
diff
changeset
|
52 #ifdef HAVE_SHARED_GAME_DIR |
16b3622178f9
update-game-score.c (SCORE_FILE_PREFIX): Don't hardcode.
Colin Walters <walters@gnu.org>
parents:
44404
diff
changeset
|
53 #define SCORE_FILE_PREFIX HAVE_SHARED_GAME_DIR |
16b3622178f9
update-game-score.c (SCORE_FILE_PREFIX): Don't hardcode.
Colin Walters <walters@gnu.org>
parents:
44404
diff
changeset
|
54 #else |
44481
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
55 #define SCORE_FILE_PREFIX "~/.emacs.d/games" |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
56 #endif |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
57 |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
58 #if !defined (__GNUC__) || __GNUC__ < 2 |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
59 #define __attribute__(x) |
44419
16b3622178f9
update-game-score.c (SCORE_FILE_PREFIX): Don't hardcode.
Colin Walters <walters@gnu.org>
parents:
44404
diff
changeset
|
60 #endif |
44184 | 61 |
62 int | |
63 usage(int err) | |
64 { | |
65 fprintf(stdout, "Usage: update-game-score [-m MAX ] [ -r ] game/scorefile SCORE DATA\n"); | |
66 fprintf(stdout, " update-game-score -h\n"); | |
67 fprintf(stdout, " -h\t\tDisplay this help.\n"); | |
68 fprintf(stdout, " -m MAX\t\tLimit the maximum number of scores to MAX.\n"); | |
69 fprintf(stdout, " -r\t\tSort the scores in increasing order.\n"); | |
70 exit(err); | |
71 } | |
72 | |
73 int | |
74 lock_file(const char *filename, void **state); | |
75 int | |
76 unlock_file(const char *filename, void *state); | |
77 | |
78 struct score_entry | |
79 { | |
80 long score; | |
44402
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
81 char *username; |
44184 | 82 char *data; |
83 }; | |
84 | |
85 int | |
86 read_scores(const char *filename, struct score_entry **scores, | |
87 int *count); | |
88 int | |
89 push_score(struct score_entry **scores, int *count, | |
44402
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
90 int newscore, char *username, char *newdata); |
44184 | 91 void |
92 sort_scores(struct score_entry *scores, int count, int reverse); | |
93 int | |
94 write_scores(const char *filename, const struct score_entry *scores, | |
95 int count); | |
96 | |
44402
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
97 char * |
44419
16b3622178f9
update-game-score.c (SCORE_FILE_PREFIX): Don't hardcode.
Colin Walters <walters@gnu.org>
parents:
44404
diff
changeset
|
98 get_user_id(struct passwd *buf) |
44402
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
99 { |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
100 char *name; |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
101 if (!buf) |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
102 { |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
103 int count = 1; |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
104 int uid = (int) getuid(); |
44481
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
105 int tuid = uid; |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
106 while (tuid /= 10) |
44402
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
107 count++; |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
108 name = malloc(count+1); |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
109 sprintf(name, "%d", uid); |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
110 return name; |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
111 } |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
112 return buf->pw_name; |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
113 } |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
114 |
44419
16b3622178f9
update-game-score.c (SCORE_FILE_PREFIX): Don't hardcode.
Colin Walters <walters@gnu.org>
parents:
44404
diff
changeset
|
115 char * |
16b3622178f9
update-game-score.c (SCORE_FILE_PREFIX): Don't hardcode.
Colin Walters <walters@gnu.org>
parents:
44404
diff
changeset
|
116 get_home_dir(struct passwd *buf) |
16b3622178f9
update-game-score.c (SCORE_FILE_PREFIX): Don't hardcode.
Colin Walters <walters@gnu.org>
parents:
44404
diff
changeset
|
117 { |
16b3622178f9
update-game-score.c (SCORE_FILE_PREFIX): Don't hardcode.
Colin Walters <walters@gnu.org>
parents:
44404
diff
changeset
|
118 if (!buf) |
16b3622178f9
update-game-score.c (SCORE_FILE_PREFIX): Don't hardcode.
Colin Walters <walters@gnu.org>
parents:
44404
diff
changeset
|
119 return NULL; |
16b3622178f9
update-game-score.c (SCORE_FILE_PREFIX): Don't hardcode.
Colin Walters <walters@gnu.org>
parents:
44404
diff
changeset
|
120 return buf->pw_dir; |
16b3622178f9
update-game-score.c (SCORE_FILE_PREFIX): Don't hardcode.
Colin Walters <walters@gnu.org>
parents:
44404
diff
changeset
|
121 } |
16b3622178f9
update-game-score.c (SCORE_FILE_PREFIX): Don't hardcode.
Colin Walters <walters@gnu.org>
parents:
44404
diff
changeset
|
122 |
44481
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
123 void lose(const char *msg, ...) |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
124 __attribute__ ((format (printf,1,0), noreturn)); |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
125 |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
126 void lose(const char *msg, ...) |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
127 { |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
128 va_list ap; |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
129 va_start(ap, msg); |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
130 vfprintf(stderr, msg, ap); |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
131 va_end(ap); |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
132 exit(1); |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
133 } |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
134 |
44184 | 135 int |
136 main(int argc, char **argv) | |
137 { | |
138 int c; | |
139 void *lockstate; | |
44419
16b3622178f9
update-game-score.c (SCORE_FILE_PREFIX): Don't hardcode.
Colin Walters <walters@gnu.org>
parents:
44404
diff
changeset
|
140 char *scorefile, *prefix; |
44184 | 141 struct stat buf; |
142 struct score_entry *scores; | |
44481
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
143 int newscore, scorecount, reverse = 0, max = MAX_SCORES; |
44184 | 144 char *newdata; |
44419
16b3622178f9
update-game-score.c (SCORE_FILE_PREFIX): Don't hardcode.
Colin Walters <walters@gnu.org>
parents:
44404
diff
changeset
|
145 struct passwd *passwdbuf; |
44184 | 146 |
147 srand(time(0)); | |
148 | |
149 while ((c = getopt(argc, argv, "hrm:")) != -1) | |
150 switch (c) | |
151 { | |
152 case 'h': | |
153 usage(0); | |
154 break; | |
155 case 'r': | |
156 reverse = 1; | |
157 break; | |
158 case 'm': | |
159 max = atoi(optarg); | |
44481
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
160 if (max > MAX_SCORES) |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
161 max = MAX_SCORES; |
44184 | 162 break; |
163 default: | |
164 usage(1); | |
165 } | |
166 | |
167 if (optind+3 != argc) | |
168 usage(1); | |
44419
16b3622178f9
update-game-score.c (SCORE_FILE_PREFIX): Don't hardcode.
Colin Walters <walters@gnu.org>
parents:
44404
diff
changeset
|
169 |
16b3622178f9
update-game-score.c (SCORE_FILE_PREFIX): Don't hardcode.
Colin Walters <walters@gnu.org>
parents:
44404
diff
changeset
|
170 passwdbuf = getpwuid(getuid()); |
16b3622178f9
update-game-score.c (SCORE_FILE_PREFIX): Don't hardcode.
Colin Walters <walters@gnu.org>
parents:
44404
diff
changeset
|
171 |
44481
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
172 if (!strncmp(SCORE_FILE_PREFIX, "~", 1)) |
44419
16b3622178f9
update-game-score.c (SCORE_FILE_PREFIX): Don't hardcode.
Colin Walters <walters@gnu.org>
parents:
44404
diff
changeset
|
173 { |
44481
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
174 char *homedir = get_home_dir(passwdbuf); |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
175 if (!homedir) |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
176 lose("Unable to determine home directory\n"); |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
177 prefix = malloc(strlen(homedir) + strlen(SCORE_FILE_PREFIX) + 1); |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
178 strcpy(prefix, homedir); |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
179 /* Skip over the '~'. */ |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
180 strcat(prefix, SCORE_FILE_PREFIX+1); |
44419
16b3622178f9
update-game-score.c (SCORE_FILE_PREFIX): Don't hardcode.
Colin Walters <walters@gnu.org>
parents:
44404
diff
changeset
|
181 } |
16b3622178f9
update-game-score.c (SCORE_FILE_PREFIX): Don't hardcode.
Colin Walters <walters@gnu.org>
parents:
44404
diff
changeset
|
182 else |
44481
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
183 prefix = strdup(SCORE_FILE_PREFIX); |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
184 |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
185 if (!prefix) |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
186 lose("Couldn't create score file name: %s\n", strerror(errno)); |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
187 |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
188 scorefile = malloc(strlen(prefix) + strlen(argv[optind]) + 2); |
44184 | 189 if (!scorefile) |
44481
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
190 lose("Couldn't create score file name: %s\n", strerror(errno)); |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
191 |
44419
16b3622178f9
update-game-score.c (SCORE_FILE_PREFIX): Don't hardcode.
Colin Walters <walters@gnu.org>
parents:
44404
diff
changeset
|
192 strcpy(scorefile, prefix); |
44481
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
193 free(prefix); |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
194 strcat(scorefile, "/"); |
44184 | 195 strcat(scorefile, argv[optind]); |
196 newscore = atoi(argv[optind+1]); | |
197 newdata = argv[optind+2]; | |
44481
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
198 if (strlen(newdata) > MAX_DATA_LEN) |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
199 newdata[MAX_DATA_LEN] = '\0'; |
44184 | 200 |
201 if (stat(scorefile, &buf) < 0) | |
44481
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
202 lose("Failed to access scores file \"%s\": %s\n", scorefile, |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
203 strerror(errno)); |
44184 | 204 if (lock_file(scorefile, &lockstate) < 0) |
44481
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
205 lose("Failed to lock scores file \"%s\": %s\n", |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
206 scorefile, strerror(errno)); |
44184 | 207 if (read_scores(scorefile, &scores, &scorecount) < 0) |
208 { | |
44481
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
209 unlock_file(scorefile, lockstate); |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
210 lose("Failed to read scores file \"%s\": %s\n", scorefile, |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
211 strerror(errno)); |
44184 | 212 } |
44419
16b3622178f9
update-game-score.c (SCORE_FILE_PREFIX): Don't hardcode.
Colin Walters <walters@gnu.org>
parents:
44404
diff
changeset
|
213 push_score(&scores, &scorecount, newscore, get_user_id(passwdbuf), newdata); |
44481
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
214 /* Limit the number of scores. If we're using reverse sorting, then |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
215 we should increment the beginning of the array, to skip over the |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
216 *smallest* scores. Otherwise, we just decrement the number of |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
217 scores, since the smallest will be at the end. */ |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
218 if (scorecount > MAX_SCORES) |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
219 scorecount -= (scorecount - MAX_SCORES); |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
220 if (reverse) |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
221 scores += (scorecount - MAX_SCORES); |
44184 | 222 sort_scores(scores, scorecount, reverse); |
223 if (write_scores(scorefile, scores, scorecount) < 0) | |
224 { | |
44481
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
225 unlock_file(scorefile, lockstate); |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
226 lose("Failed to write scores file \"%s\": %s\n", scorefile, |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
227 strerror(errno)); |
44184 | 228 } |
229 unlock_file(scorefile, lockstate); | |
230 exit(0); | |
231 } | |
232 | |
233 int | |
234 read_score(FILE *f, struct score_entry *score) | |
235 { | |
236 int c; | |
237 if (feof(f)) | |
238 return 1; | |
239 while ((c = getc(f)) != EOF | |
44402
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
240 && isdigit(c)) |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
241 { |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
242 score->score *= 10; |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
243 score->score += (c-48); |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
244 } |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
245 while ((c = getc(f)) != EOF |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
246 && isspace(c)) |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
247 ; |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
248 if (c == EOF) |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
249 return -1; |
44404
21e4d76a9e8a
Actually make previous changes work (oops).
Colin Walters <walters@gnu.org>
parents:
44402
diff
changeset
|
250 ungetc(c, f); |
44402
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
251 #ifdef HAVE_GETDELIM |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
252 { |
44566
7a0ad319b38f
(read_score): Fix type of second parameter
Andreas Schwab <schwab@suse.de>
parents:
44481
diff
changeset
|
253 size_t count = 0; |
44402
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
254 if (getdelim(&score->username, &count, ' ', f) < 1 |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
255 || score->username == NULL) |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
256 return -1; |
44789
d095e59dc01d
(read_score) [HAVE_GETDELIM]: Trim trailing space.
Colin Walters <walters@gnu.org>
parents:
44639
diff
changeset
|
257 /* Trim the space */ |
d095e59dc01d
(read_score) [HAVE_GETDELIM]: Trim trailing space.
Colin Walters <walters@gnu.org>
parents:
44639
diff
changeset
|
258 score->username[strlen(score->username)-1] = '\0'; |
44184 | 259 } |
44402
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
260 #else |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
261 { |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
262 int unameread = 0; |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
263 int unamelen = 30; |
44404
21e4d76a9e8a
Actually make previous changes work (oops).
Colin Walters <walters@gnu.org>
parents:
44402
diff
changeset
|
264 char *username = malloc(unamelen); |
21e4d76a9e8a
Actually make previous changes work (oops).
Colin Walters <walters@gnu.org>
parents:
44402
diff
changeset
|
265 if (!username) |
21e4d76a9e8a
Actually make previous changes work (oops).
Colin Walters <walters@gnu.org>
parents:
44402
diff
changeset
|
266 return -1; |
44402
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
267 |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
268 while ((c = getc(f)) != EOF |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
269 && !isspace(c)) |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
270 { |
44481
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
271 if (unameread >= unamelen-1) |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
272 if (!(username = realloc(username, unamelen *= 2))) |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
273 return -1; |
44402
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
274 username[unameread] = c; |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
275 unameread++; |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
276 } |
44404
21e4d76a9e8a
Actually make previous changes work (oops).
Colin Walters <walters@gnu.org>
parents:
44402
diff
changeset
|
277 if (c == EOF) |
21e4d76a9e8a
Actually make previous changes work (oops).
Colin Walters <walters@gnu.org>
parents:
44402
diff
changeset
|
278 return -1; |
21e4d76a9e8a
Actually make previous changes work (oops).
Colin Walters <walters@gnu.org>
parents:
44402
diff
changeset
|
279 username[unameread] = '\0'; |
44402
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
280 score->username = username; |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
281 } |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
282 #endif |
44184 | 283 #ifdef HAVE_GETLINE |
284 score->data = NULL; | |
44566
7a0ad319b38f
(read_score): Fix type of second parameter
Andreas Schwab <schwab@suse.de>
parents:
44481
diff
changeset
|
285 errno = 0; |
44184 | 286 { |
44566
7a0ad319b38f
(read_score): Fix type of second parameter
Andreas Schwab <schwab@suse.de>
parents:
44481
diff
changeset
|
287 size_t len; |
44184 | 288 if (getline(&score->data, &len, f) < 0) |
289 return -1; | |
44419
16b3622178f9
update-game-score.c (SCORE_FILE_PREFIX): Don't hardcode.
Colin Walters <walters@gnu.org>
parents:
44404
diff
changeset
|
290 score->data[strlen(score->data)-1] = '\0'; |
44184 | 291 } |
292 #else | |
44402
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
293 { |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
294 int cur = 0; |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
295 int len = 16; |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
296 char *buf = malloc(len); |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
297 if (!buf) |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
298 return -1; |
44404
21e4d76a9e8a
Actually make previous changes work (oops).
Colin Walters <walters@gnu.org>
parents:
44402
diff
changeset
|
299 while ((c = getc(f)) != EOF |
21e4d76a9e8a
Actually make previous changes work (oops).
Colin Walters <walters@gnu.org>
parents:
44402
diff
changeset
|
300 && c != '\n') |
44402
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
301 { |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
302 if (cur >= len-1) |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
303 { |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
304 if (!(buf = realloc(buf, len *= 2))) |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
305 return -1; |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
306 } |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
307 buf[cur] = c; |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
308 cur++; |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
309 } |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
310 score->data = buf; |
44419
16b3622178f9
update-game-score.c (SCORE_FILE_PREFIX): Don't hardcode.
Colin Walters <walters@gnu.org>
parents:
44404
diff
changeset
|
311 score->data[cur] = '\0'; |
44402
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
312 } |
44184 | 313 #endif |
314 return 0; | |
315 } | |
316 | |
317 int | |
318 read_scores(const char *filename, struct score_entry **scores, | |
319 int *count) | |
320 { | |
321 int readval, scorecount, cursize; | |
322 struct score_entry *ret; | |
323 FILE *f = fopen(filename, "r"); | |
324 if (!f) | |
325 return -1; | |
326 scorecount = 0; | |
327 cursize = 16; | |
328 ret = malloc(sizeof(struct score_entry) * cursize); | |
329 if (!ret) | |
330 return -1; | |
331 while ((readval = read_score(f, &ret[scorecount])) == 0) | |
332 { | |
333 /* We encoutered an error */ | |
334 if (readval < 0) | |
335 return -1; | |
336 scorecount++; | |
337 if (scorecount >= cursize) | |
338 { | |
339 ret = realloc(ret, cursize *= 2); | |
340 if (!ret) | |
341 return -1; | |
342 } | |
343 } | |
344 *count = scorecount; | |
345 *scores = ret; | |
346 return 0; | |
347 } | |
348 | |
349 int | |
350 score_compare(const void *a, const void *b) | |
351 { | |
352 const struct score_entry *sa = (const struct score_entry *) a; | |
353 const struct score_entry *sb = (const struct score_entry *) b; | |
354 return (sb->score > sa->score) - (sb->score < sa->score); | |
355 } | |
356 | |
357 int | |
358 score_compare_reverse(const void *a, const void *b) | |
359 { | |
360 const struct score_entry *sa = (const struct score_entry *) a; | |
361 const struct score_entry *sb = (const struct score_entry *) b; | |
362 return (sa->score > sb->score) - (sa->score < sb->score); | |
363 } | |
364 | |
365 int | |
366 push_score(struct score_entry **scores, int *count, | |
44402
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
367 int newscore, char *username, char *newdata) |
44184 | 368 { |
369 struct score_entry *newscores = realloc(*scores, | |
370 sizeof(struct score_entry) * ((*count) + 1)); | |
371 if (!newscores) | |
372 return -1; | |
373 newscores[*count].score = newscore; | |
44402
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
374 newscores[*count].username = username; |
44184 | 375 newscores[*count].data = newdata; |
376 (*count) += 1; | |
377 *scores = newscores; | |
378 return 0; | |
379 } | |
380 | |
381 void | |
382 sort_scores(struct score_entry *scores, int count, int reverse) | |
383 { | |
384 qsort(scores, count, sizeof(struct score_entry), | |
385 reverse ? score_compare_reverse : score_compare); | |
386 } | |
387 | |
388 int | |
389 write_scores(const char *filename, const struct score_entry *scores, | |
390 int count) | |
391 { | |
392 FILE *f; | |
393 int i; | |
394 char *tempfile = malloc(strlen(filename) + strlen(".tempXXXXXX") + 1); | |
395 if (!tempfile) | |
396 return -1; | |
397 strcpy(tempfile, filename); | |
398 strcat(tempfile, ".tempXXXXXX"); | |
44481
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
399 #ifdef HAVE_MKSTEMP |
44184 | 400 if (mkstemp(tempfile) < 0 |
44481
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
401 #else |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
402 if (mktemp(tempfile) != tempfile |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
403 #endif |
44184 | 404 || !(f = fopen(tempfile, "w"))) |
405 return -1; | |
406 for (i = 0; i < count; i++) | |
44402
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
407 if (fprintf(f, "%ld %s %s\n", scores[i].score, scores[i].username, |
968fd5ccea65
(toplevel): Include pwd.h.
Colin Walters <walters@gnu.org>
parents:
44184
diff
changeset
|
408 scores[i].data) < 0) |
44184 | 409 return -1; |
410 fclose(f); | |
44481
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
411 if (rename(tempfile, filename) < 0) |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
412 return -1; |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
413 if (chmod(filename, 0644) < 0) |
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
414 return -1; |
44184 | 415 return 0; |
416 } | |
417 | |
418 int | |
419 lock_file(const char *filename, void **state) | |
420 { | |
421 int fd; | |
44576
90866353c7bd
(lock_file): If the lock file is older than an hour, delete it. Reset
Colin Walters <walters@gnu.org>
parents:
44566
diff
changeset
|
422 struct stat buf; |
44184 | 423 int attempts = 0; |
424 char *lockext = ".lockfile"; | |
425 char *lockpath = malloc(strlen(filename) + strlen(lockext) + 60); | |
426 if (!lockpath) | |
427 return -1; | |
428 strcpy(lockpath, filename); | |
429 strcat(lockpath, lockext); | |
430 *state = lockpath; | |
431 trylock: | |
432 attempts++; | |
44576
90866353c7bd
(lock_file): If the lock file is older than an hour, delete it. Reset
Colin Walters <walters@gnu.org>
parents:
44566
diff
changeset
|
433 /* If the lock is over an hour old, delete it. */ |
90866353c7bd
(lock_file): If the lock file is older than an hour, delete it. Reset
Colin Walters <walters@gnu.org>
parents:
44566
diff
changeset
|
434 if (stat(lockpath, &buf) == 0 |
90866353c7bd
(lock_file): If the lock file is older than an hour, delete it. Reset
Colin Walters <walters@gnu.org>
parents:
44566
diff
changeset
|
435 && (difftime(buf.st_ctime, time(NULL) > 60*60))) |
90866353c7bd
(lock_file): If the lock file is older than an hour, delete it. Reset
Colin Walters <walters@gnu.org>
parents:
44566
diff
changeset
|
436 unlink(lockpath); |
44184 | 437 if ((fd = open(lockpath, O_CREAT | O_EXCL, 0600)) < 0) |
438 { | |
439 if (errno == EEXIST) | |
440 { | |
441 /* Break the lock; we won't corrupt the file, but we might | |
442 lose some scores. */ | |
443 if (attempts > MAX_ATTEMPTS) | |
44576
90866353c7bd
(lock_file): If the lock file is older than an hour, delete it. Reset
Colin Walters <walters@gnu.org>
parents:
44566
diff
changeset
|
444 { |
90866353c7bd
(lock_file): If the lock file is older than an hour, delete it. Reset
Colin Walters <walters@gnu.org>
parents:
44566
diff
changeset
|
445 unlink(lockpath); |
90866353c7bd
(lock_file): If the lock file is older than an hour, delete it. Reset
Colin Walters <walters@gnu.org>
parents:
44566
diff
changeset
|
446 attempts = 0; |
90866353c7bd
(lock_file): If the lock file is older than an hour, delete it. Reset
Colin Walters <walters@gnu.org>
parents:
44566
diff
changeset
|
447 } |
44481
a0dc261f564a
(toplevel): Include stdarg.h.
Colin Walters <walters@gnu.org>
parents:
44419
diff
changeset
|
448 sleep((rand() % 2)+1); |
44184 | 449 goto trylock; |
450 } | |
451 else | |
452 return -1; | |
453 } | |
454 close(fd); | |
455 return 0; | |
456 } | |
457 | |
458 int | |
459 unlock_file(const char *filename, void *state) | |
460 { | |
461 char *lockpath = (char *) state; | |
462 int ret = unlink(lockpath); | |
463 int saved_errno = errno; | |
464 free(lockpath); | |
465 errno = saved_errno; | |
466 return ret; | |
467 } |