53 |
#define __attribute__(x) |
#define __attribute__(x) |
54 |
#endif |
#endif |
55 |
|
|
56 |
|
/* Declare the prototype for a general external function. */ |
57 |
|
#if defined (PROTOTYPES) || defined (WINDOWSNT) |
58 |
|
#define P_(proto) proto |
59 |
|
#else |
60 |
|
#define P_(proto) () |
61 |
|
#endif |
62 |
|
|
63 |
int |
int |
64 |
usage(int err) |
usage(err) |
65 |
|
int err; |
66 |
{ |
{ |
67 |
fprintf(stdout, "Usage: update-game-score [-m MAX ] [ -r ] game/scorefile SCORE DATA\n"); |
fprintf(stdout, "Usage: update-game-score [-m MAX ] [ -r ] game/scorefile SCORE DATA\n"); |
68 |
fprintf(stdout, " update-game-score -h\n"); |
fprintf(stdout, " update-game-score -h\n"); |
74 |
} |
} |
75 |
|
|
76 |
int |
int |
77 |
lock_file(const char *filename, void **state); |
lock_file P_((const char *filename, void **state)); |
78 |
int |
int |
79 |
unlock_file(const char *filename, void *state); |
unlock_file P_((const char *filename, void *state)); |
80 |
|
|
81 |
struct score_entry |
struct score_entry |
82 |
{ |
{ |
86 |
}; |
}; |
87 |
|
|
88 |
int |
int |
89 |
read_scores(const char *filename, struct score_entry **scores, |
read_scores P_((const char *filename, struct score_entry **scores, |
90 |
int *count); |
int *count)); |
91 |
int |
int |
92 |
push_score(struct score_entry **scores, int *count, |
push_score P_((struct score_entry **scores, int *count, |
93 |
int newscore, char *username, char *newdata); |
int newscore, char *username, char *newdata)); |
94 |
void |
void |
95 |
sort_scores(struct score_entry *scores, int count, int reverse); |
sort_scores P_((struct score_entry *scores, int count, int reverse)); |
96 |
int |
int |
97 |
write_scores(const char *filename, const struct score_entry *scores, |
write_scores P_((const char *filename, const struct score_entry *scores, |
98 |
int count); |
int count)); |
99 |
|
|
100 |
|
void lose P_((const char *msg)) |
101 |
|
__attribute__ ((noreturn)); |
102 |
|
|
103 |
|
void lose(msg) |
104 |
|
const char *msg; |
105 |
|
{ |
106 |
|
fprintf(stderr, "%s\n", msg); |
107 |
|
exit(1); |
108 |
|
} |
109 |
|
|
110 |
void lose(const char *msg, ...) |
void lose_syserr P_((const char *msg)) |
111 |
__attribute__ ((format (printf,1,0), noreturn)); |
__attribute__ ((noreturn)); |
112 |
|
|
113 |
void lose(const char *msg, ...) |
void lose_syserr(msg) |
114 |
|
const char *msg; |
115 |
{ |
{ |
116 |
va_list ap; |
fprintf(stderr, "%s: %s\n", msg, strerror(errno)); |
117 |
va_start(ap, msg); |
exit(1); |
|
vfprintf(stderr, msg, ap); |
|
|
va_end(ap); |
|
|
exit(1); |
|
118 |
} |
} |
119 |
|
|
120 |
char * |
char * |
139 |
} |
} |
140 |
|
|
141 |
char * |
char * |
142 |
get_prefix(int running_suid, char *user_prefix) |
get_prefix(running_suid, user_prefix) |
143 |
|
int running_suid; |
144 |
|
char *user_prefix; |
145 |
{ |
{ |
146 |
if (!running_suid && user_prefix == NULL) |
if (!running_suid && user_prefix == NULL) |
147 |
lose("Not using a shared game directory, and no prefix given.\n"); |
lose("Not using a shared game directory, and no prefix given."); |
148 |
if (running_suid) |
if (running_suid) |
149 |
{ |
{ |
150 |
#ifdef HAVE_SHARED_GAME_DIR |
#ifdef HAVE_SHARED_GAME_DIR |
151 |
return HAVE_SHARED_GAME_DIR; |
return HAVE_SHARED_GAME_DIR; |
152 |
#else |
#else |
153 |
lose("This program was compiled without HAVE_SHARED_GAME_DIR,\n and should not be suid.\n"); |
lose("This program was compiled without HAVE_SHARED_GAME_DIR,\n and should not be suid."); |
154 |
#endif |
#endif |
155 |
} |
} |
156 |
return user_prefix; |
return user_prefix; |
157 |
} |
} |
158 |
|
|
159 |
int |
int |
160 |
main(int argc, char **argv) |
main(argc, argv) |
161 |
|
int argc; |
162 |
|
char **argv; |
163 |
{ |
{ |
164 |
int c, running_suid; |
int c, running_suid; |
165 |
void *lockstate; |
void *lockstate; |
201 |
|
|
202 |
scorefile = malloc(strlen(prefix) + strlen(argv[optind]) + 2); |
scorefile = malloc(strlen(prefix) + strlen(argv[optind]) + 2); |
203 |
if (!scorefile) |
if (!scorefile) |
204 |
lose("Couldn't create score file name: %s\n", strerror(errno)); |
lose_syserr("Couldn't allocate score file"); |
205 |
|
|
206 |
strcpy(scorefile, prefix); |
strcpy(scorefile, prefix); |
207 |
strcat(scorefile, "/"); |
strcat(scorefile, "/"); |
212 |
newdata[MAX_DATA_LEN] = '\0'; |
newdata[MAX_DATA_LEN] = '\0'; |
213 |
|
|
214 |
if ((user_id = get_user_id()) == NULL) |
if ((user_id = get_user_id()) == NULL) |
215 |
lose("Couldn't determine user id: %s\n", strerror(errno)); |
lose_syserr("Couldn't determine user id"); |
216 |
|
|
217 |
if (stat(scorefile, &buf) < 0) |
if (stat(scorefile, &buf) < 0) |
218 |
lose("Failed to access scores file \"%s\": %s\n", scorefile, |
lose_syserr("Failed to access scores file"); |
219 |
strerror(errno)); |
|
220 |
if (lock_file(scorefile, &lockstate) < 0) |
if (lock_file(scorefile, &lockstate) < 0) |
221 |
lose("Failed to lock scores file \"%s\": %s\n", |
lose_syserr("Failed to lock scores file"); |
222 |
scorefile, strerror(errno)); |
|
223 |
if (read_scores(scorefile, &scores, &scorecount) < 0) |
if (read_scores(scorefile, &scores, &scorecount) < 0) |
224 |
{ |
{ |
225 |
unlock_file(scorefile, lockstate); |
unlock_file(scorefile, lockstate); |
226 |
lose("Failed to read scores file \"%s\": %s\n", scorefile, |
lose_syserr("Failed to read scores file"); |
|
strerror(errno)); |
|
227 |
} |
} |
228 |
push_score(&scores, &scorecount, newscore, user_id, newdata); |
push_score(&scores, &scorecount, newscore, user_id, newdata); |
229 |
/* Limit the number of scores. If we're using reverse sorting, then |
/* Limit the number of scores. If we're using reverse sorting, then |
238 |
if (write_scores(scorefile, scores, scorecount) < 0) |
if (write_scores(scorefile, scores, scorecount) < 0) |
239 |
{ |
{ |
240 |
unlock_file(scorefile, lockstate); |
unlock_file(scorefile, lockstate); |
241 |
lose("Failed to write scores file \"%s\": %s\n", scorefile, |
lose_syserr("Failed to write scores file"); |
|
strerror(errno)); |
|
242 |
} |
} |
243 |
unlock_file(scorefile, lockstate); |
unlock_file(scorefile, lockstate); |
244 |
exit(0); |
exit(0); |
245 |
} |
} |
246 |
|
|
247 |
int |
int |
248 |
read_score(FILE *f, struct score_entry *score) |
read_score(f, score) |
249 |
|
FILE *f; |
250 |
|
struct score_entry *score; |
251 |
{ |
{ |
252 |
int c; |
int c; |
253 |
if (feof(f)) |
if (feof(f)) |
331 |
} |
} |
332 |
|
|
333 |
int |
int |
334 |
read_scores(const char *filename, struct score_entry **scores, |
read_scores(filename, scores, count) |
335 |
int *count) |
const char *filename; |
336 |
|
struct score_entry **scores; |
337 |
|
int *count; |
338 |
{ |
{ |
339 |
int readval, scorecount, cursize; |
int readval, scorecount, cursize; |
340 |
struct score_entry *ret; |
struct score_entry *ret; |
365 |
} |
} |
366 |
|
|
367 |
int |
int |
368 |
score_compare(const void *a, const void *b) |
score_compare(a, b) |
369 |
|
const void *a; |
370 |
|
const void *b; |
371 |
{ |
{ |
372 |
const struct score_entry *sa = (const struct score_entry *) a; |
const struct score_entry *sa = (const struct score_entry *) a; |
373 |
const struct score_entry *sb = (const struct score_entry *) b; |
const struct score_entry *sb = (const struct score_entry *) b; |
375 |
} |
} |
376 |
|
|
377 |
int |
int |
378 |
score_compare_reverse(const void *a, const void *b) |
score_compare_reverse(a, b) |
379 |
|
const void *a; |
380 |
|
const void *b; |
381 |
{ |
{ |
382 |
const struct score_entry *sa = (const struct score_entry *) a; |
const struct score_entry *sa = (const struct score_entry *) a; |
383 |
const struct score_entry *sb = (const struct score_entry *) b; |
const struct score_entry *sb = (const struct score_entry *) b; |
385 |
} |
} |
386 |
|
|
387 |
int |
int |
388 |
push_score(struct score_entry **scores, int *count, |
push_score(scores, count, newscore, username, newdata) |
389 |
int newscore, char *username, char *newdata) |
struct score_entry **scores; |
390 |
|
int *count; int newscore; |
391 |
|
char *username; |
392 |
|
char *newdata; |
393 |
{ |
{ |
394 |
struct score_entry *newscores = realloc(*scores, |
struct score_entry *newscores = realloc(*scores, |
395 |
sizeof(struct score_entry) * ((*count) + 1)); |
sizeof(struct score_entry) * ((*count) + 1)); |
404 |
} |
} |
405 |
|
|
406 |
void |
void |
407 |
sort_scores(struct score_entry *scores, int count, int reverse) |
sort_scores(scores, count, reverse) |
408 |
|
struct score_entry *scores; |
409 |
|
int count; |
410 |
|
int reverse; |
411 |
{ |
{ |
412 |
qsort(scores, count, sizeof(struct score_entry), |
qsort(scores, count, sizeof(struct score_entry), |
413 |
reverse ? score_compare_reverse : score_compare); |
reverse ? score_compare_reverse : score_compare); |
414 |
} |
} |
415 |
|
|
416 |
int |
int |
417 |
write_scores(const char *filename, const struct score_entry *scores, |
write_scores(filename, scores, count) |
418 |
int count) |
const char *filename; |
419 |
|
const struct score_entry * scores; |
420 |
|
int count; |
421 |
{ |
{ |
422 |
FILE *f; |
FILE *f; |
423 |
int i; |
int i; |
444 |
return -1; |
return -1; |
445 |
return 0; |
return 0; |
446 |
} |
} |
447 |
|
|
448 |
int |
int |
449 |
lock_file(const char *filename, void **state) |
lock_file(filename, state) |
450 |
|
const char *filename; |
451 |
|
void **state; |
452 |
{ |
{ |
453 |
int fd; |
int fd; |
454 |
struct stat buf; |
struct stat buf; |
486 |
close(fd); |
close(fd); |
487 |
return 0; |
return 0; |
488 |
} |
} |
489 |
|
|
490 |
int |
int |
491 |
unlock_file(const char *filename, void *state) |
unlock_file(filename, state) |
492 |
|
const char *filename; |
493 |
|
void *state; |
494 |
{ |
{ |
495 |
char *lockpath = (char *) state; |
char *lockpath = (char *) state; |
496 |
int ret = unlink(lockpath); |
int ret = unlink(lockpath); |