29 |
Created 2002/03/22, by Colin Walters <walters@debian.org> |
Created 2002/03/22, by Colin Walters <walters@debian.org> |
30 |
*/ |
*/ |
31 |
|
|
|
#define _GNU_SOURCE |
|
|
|
|
32 |
#include <config.h> |
#include <config.h> |
33 |
|
|
34 |
|
#ifdef HAVE_UNISTD_H |
35 |
#include <unistd.h> |
#include <unistd.h> |
36 |
|
#endif |
37 |
#include <errno.h> |
#include <errno.h> |
38 |
|
#ifdef HAVE_STRING_H |
39 |
#include <string.h> |
#include <string.h> |
40 |
|
#endif |
41 |
|
#ifdef HAVE_STDLIB_H |
42 |
#include <stdlib.h> |
#include <stdlib.h> |
43 |
|
#endif |
44 |
#include <stdio.h> |
#include <stdio.h> |
45 |
#include <time.h> |
#include <time.h> |
46 |
#include <pwd.h> |
#include <pwd.h> |
47 |
#include <ctype.h> |
#include <ctype.h> |
48 |
|
#ifdef HAVE_FCNTL_H |
49 |
#include <fcntl.h> |
#include <fcntl.h> |
50 |
|
#endif |
51 |
|
#ifdef STDC_HEADERS |
52 |
#include <stdarg.h> |
#include <stdarg.h> |
53 |
|
#endif |
54 |
#include <sys/stat.h> |
#include <sys/stat.h> |
55 |
|
|
56 |
|
/* Needed for SunOS4, for instance. */ |
57 |
|
extern char *optarg; |
58 |
|
extern int optind, opterr; |
59 |
|
|
60 |
#define MAX_ATTEMPTS 5 |
#define MAX_ATTEMPTS 5 |
61 |
#define MAX_SCORES 200 |
#define MAX_SCORES 200 |
62 |
#define MAX_DATA_LEN 1024 |
#define MAX_DATA_LEN 1024 |
63 |
|
|
64 |
#if !defined (__GNUC__) || __GNUC__ < 2 |
/* Declare the prototype for a general external function. */ |
65 |
#define __attribute__(x) |
#if defined (PROTOTYPES) || defined (WINDOWSNT) |
66 |
|
#define P_(proto) proto |
67 |
|
#else |
68 |
|
#define P_(proto) () |
69 |
#endif |
#endif |
70 |
|
|
71 |
int |
int |
72 |
usage(int err) |
usage (err) |
73 |
|
int err; |
74 |
{ |
{ |
75 |
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"); |
76 |
fprintf(stdout, " update-game-score -h\n"); |
fprintf (stdout, " update-game-score -h\n"); |
77 |
fprintf(stdout, " -h\t\tDisplay this help.\n"); |
fprintf (stdout, " -h\t\tDisplay this help.\n"); |
78 |
fprintf(stdout, " -m MAX\t\tLimit the maximum number of scores to MAX.\n"); |
fprintf (stdout, " -m MAX\t\tLimit the maximum number of scores to MAX.\n"); |
79 |
fprintf(stdout, " -r\t\tSort the scores in increasing order.\n"); |
fprintf (stdout, " -r\t\tSort the scores in increasing order.\n"); |
80 |
fprintf(stdout, " -d DIR\t\tStore scores in DIR (only if not setuid).\n"); |
fprintf (stdout, " -d DIR\t\tStore scores in DIR (only if not setuid).\n"); |
81 |
exit(err); |
exit (err); |
82 |
} |
} |
83 |
|
|
84 |
int |
int lock_file P_ ((const char *filename, void **state)); |
85 |
lock_file(const char *filename, void **state); |
int unlock_file P_ ((const char *filename, void *state)); |
|
int |
|
|
unlock_file(const char *filename, void *state); |
|
86 |
|
|
87 |
struct score_entry |
struct score_entry |
88 |
{ |
{ |
91 |
char *data; |
char *data; |
92 |
}; |
}; |
93 |
|
|
94 |
int |
int read_scores P_ ((const char *filename, struct score_entry **scores, |
95 |
read_scores(const char *filename, struct score_entry **scores, |
int *count)); |
96 |
int *count); |
int push_score P_ ((struct score_entry **scores, int *count, |
97 |
int |
int newscore, char *username, char *newdata)); |
98 |
push_score(struct score_entry **scores, int *count, |
void sort_scores P_ ((struct score_entry *scores, int count, int reverse)); |
99 |
int newscore, char *username, char *newdata); |
int write_scores P_ ((const char *filename, const struct score_entry *scores, |
100 |
|
int count)); |
101 |
|
|
102 |
|
void lose P_ ((const char *msg)) NO_RETURN; |
103 |
|
|
104 |
void |
void |
105 |
sort_scores(struct score_entry *scores, int count, int reverse); |
lose (msg) |
106 |
int |
const char *msg; |
107 |
write_scores(const char *filename, const struct score_entry *scores, |
{ |
108 |
int count); |
fprintf (stderr, "%s\n", msg); |
109 |
|
exit (1); |
110 |
|
} |
111 |
|
|
112 |
void lose(const char *msg, ...) |
void lose_syserr P_ ((const char *msg)) NO_RETURN; |
|
__attribute__ ((format (printf,1,0), noreturn)); |
|
113 |
|
|
114 |
void lose(const char *msg, ...) |
void |
115 |
|
lose_syserr (msg) |
116 |
|
const char *msg; |
117 |
{ |
{ |
118 |
va_list ap; |
fprintf (stderr, "%s: %s\n", msg, strerror (errno)); |
119 |
va_start(ap, msg); |
exit (1); |
|
vfprintf(stderr, msg, ap); |
|
|
va_end(ap); |
|
|
exit(1); |
|
120 |
} |
} |
121 |
|
|
122 |
char * |
char * |
123 |
get_user_id(void) |
get_user_id P_ ((void)) |
124 |
{ |
{ |
125 |
char *name; |
char *name; |
126 |
struct passwd *buf = getpwuid(getuid()); |
struct passwd *buf = getpwuid (getuid ()); |
127 |
if (!buf) |
if (!buf) |
128 |
{ |
{ |
129 |
int count = 1; |
int count = 1; |
130 |
int uid = (int) getuid(); |
int uid = (int) getuid (); |
131 |
int tuid = uid; |
int tuid = uid; |
132 |
while (tuid /= 10) |
while (tuid /= 10) |
133 |
count++; |
count++; |
134 |
name = malloc(count+1); |
name = malloc (count+1); |
135 |
if (!name) |
if (!name) |
136 |
return NULL; |
return NULL; |
137 |
sprintf(name, "%d", uid); |
sprintf (name, "%d", uid); |
138 |
return name; |
return name; |
139 |
} |
} |
140 |
return buf->pw_name; |
return buf->pw_name; |
141 |
} |
} |
142 |
|
|
143 |
char * |
char * |
144 |
get_prefix(int running_suid, char *user_prefix) |
get_prefix (running_suid, user_prefix) |
145 |
|
int running_suid; |
146 |
|
char *user_prefix; |
147 |
{ |
{ |
148 |
if (!running_suid && user_prefix == NULL) |
if (!running_suid && user_prefix == NULL) |
149 |
lose("Not using a shared game directory, and no prefix given.\n"); |
lose ("Not using a shared game directory, and no prefix given."); |
150 |
if (running_suid) |
if (running_suid) |
151 |
{ |
{ |
152 |
#ifdef HAVE_SHARED_GAME_DIR |
#ifdef HAVE_SHARED_GAME_DIR |
153 |
return HAVE_SHARED_GAME_DIR; |
return HAVE_SHARED_GAME_DIR; |
154 |
#else |
#else |
155 |
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."); |
156 |
#endif |
#endif |
157 |
} |
} |
158 |
return user_prefix; |
return user_prefix; |
159 |
} |
} |
160 |
|
|
161 |
int |
int |
162 |
main(int argc, char **argv) |
main (argc, argv) |
163 |
|
int argc; |
164 |
|
char **argv; |
165 |
{ |
{ |
166 |
int c, running_suid; |
int c, running_suid; |
167 |
void *lockstate; |
void *lockstate; |
171 |
int newscore, scorecount, reverse = 0, max = MAX_SCORES; |
int newscore, scorecount, reverse = 0, max = MAX_SCORES; |
172 |
char *newdata; |
char *newdata; |
173 |
|
|
174 |
srand(time(0)); |
srand (time (0)); |
175 |
|
|
176 |
while ((c = getopt(argc, argv, "hrm:d:")) != -1) |
while ((c = getopt (argc, argv, "hrm:d:")) != -1) |
177 |
switch (c) |
switch (c) |
178 |
{ |
{ |
179 |
case 'h': |
case 'h': |
180 |
usage(0); |
usage (0); |
181 |
break; |
break; |
182 |
case 'd': |
case 'd': |
183 |
user_prefix = optarg; |
user_prefix = optarg; |
186 |
reverse = 1; |
reverse = 1; |
187 |
break; |
break; |
188 |
case 'm': |
case 'm': |
189 |
max = atoi(optarg); |
max = atoi (optarg); |
190 |
if (max > MAX_SCORES) |
if (max > MAX_SCORES) |
191 |
max = MAX_SCORES; |
max = MAX_SCORES; |
192 |
break; |
break; |
193 |
default: |
default: |
194 |
usage(1); |
usage (1); |
195 |
} |
} |
196 |
|
|
197 |
if (optind+3 != argc) |
if (optind+3 != argc) |
198 |
usage(1); |
usage (1); |
199 |
|
|
200 |
running_suid = (getuid() != geteuid()); |
running_suid = (getuid () != geteuid ()); |
201 |
|
|
202 |
prefix = get_prefix(running_suid, user_prefix); |
prefix = get_prefix (running_suid, user_prefix); |
203 |
|
|
204 |
scorefile = malloc(strlen(prefix) + strlen(argv[optind]) + 2); |
scorefile = malloc (strlen (prefix) + strlen (argv[optind]) + 2); |
205 |
if (!scorefile) |
if (!scorefile) |
206 |
lose("Couldn't create score file name: %s\n", strerror(errno)); |
lose_syserr ("Couldn't allocate score file"); |
207 |
|
|
208 |
strcpy(scorefile, prefix); |
strcpy (scorefile, prefix); |
209 |
strcat(scorefile, "/"); |
strcat (scorefile, "/"); |
210 |
strcat(scorefile, argv[optind]); |
strcat (scorefile, argv[optind]); |
211 |
newscore = atoi(argv[optind+1]); |
newscore = atoi (argv[optind+1]); |
212 |
newdata = argv[optind+2]; |
newdata = argv[optind+2]; |
213 |
if (strlen(newdata) > MAX_DATA_LEN) |
if (strlen (newdata) > MAX_DATA_LEN) |
214 |
newdata[MAX_DATA_LEN] = '\0'; |
newdata[MAX_DATA_LEN] = '\0'; |
215 |
|
|
216 |
if ((user_id = get_user_id()) == NULL) |
user_id = get_user_id (); |
217 |
lose("Couldn't determine user id: %s\n", strerror(errno)); |
if (user_id == NULL) |
218 |
|
lose_syserr ("Couldn't determine user id"); |
219 |
if (stat(scorefile, &buf) < 0) |
|
220 |
lose("Failed to access scores file \"%s\": %s\n", scorefile, |
if (stat (scorefile, &buf) < 0) |
221 |
strerror(errno)); |
lose_syserr ("Failed to access scores file"); |
222 |
if (lock_file(scorefile, &lockstate) < 0) |
|
223 |
lose("Failed to lock scores file \"%s\": %s\n", |
if (lock_file (scorefile, &lockstate) < 0) |
224 |
scorefile, strerror(errno)); |
lose_syserr ("Failed to lock scores file"); |
225 |
if (read_scores(scorefile, &scores, &scorecount) < 0) |
|
226 |
|
if (read_scores (scorefile, &scores, &scorecount) < 0) |
227 |
{ |
{ |
228 |
unlock_file(scorefile, lockstate); |
unlock_file (scorefile, lockstate); |
229 |
lose("Failed to read scores file \"%s\": %s\n", scorefile, |
lose_syserr ("Failed to read scores file"); |
|
strerror(errno)); |
|
230 |
} |
} |
231 |
push_score(&scores, &scorecount, newscore, user_id, newdata); |
push_score (&scores, &scorecount, newscore, user_id, newdata); |
232 |
/* Limit the number of scores. If we're using reverse sorting, then |
/* Limit the number of scores. If we're using reverse sorting, then |
233 |
we should increment the beginning of the array, to skip over the |
we should increment the beginning of the array, to skip over the |
234 |
*smallest* scores. Otherwise, we just decrement the number of |
*smallest* scores. Otherwise, we just decrement the number of |
237 |
scorecount -= (scorecount - MAX_SCORES); |
scorecount -= (scorecount - MAX_SCORES); |
238 |
if (reverse) |
if (reverse) |
239 |
scores += (scorecount - MAX_SCORES); |
scores += (scorecount - MAX_SCORES); |
240 |
sort_scores(scores, scorecount, reverse); |
sort_scores (scores, scorecount, reverse); |
241 |
if (write_scores(scorefile, scores, scorecount) < 0) |
if (write_scores (scorefile, scores, scorecount) < 0) |
242 |
{ |
{ |
243 |
unlock_file(scorefile, lockstate); |
unlock_file (scorefile, lockstate); |
244 |
lose("Failed to write scores file \"%s\": %s\n", scorefile, |
lose_syserr ("Failed to write scores file"); |
|
strerror(errno)); |
|
245 |
} |
} |
246 |
unlock_file(scorefile, lockstate); |
unlock_file (scorefile, lockstate); |
247 |
exit(0); |
exit (0); |
248 |
} |
} |
249 |
|
|
250 |
int |
int |
251 |
read_score(FILE *f, struct score_entry *score) |
read_score (f, score) |
252 |
|
FILE *f; |
253 |
|
struct score_entry *score; |
254 |
{ |
{ |
255 |
int c; |
int c; |
256 |
if (feof(f)) |
if (feof (f)) |
257 |
return 1; |
return 1; |
258 |
while ((c = getc(f)) != EOF |
while ((c = getc (f)) != EOF |
259 |
&& isdigit(c)) |
&& isdigit (c)) |
260 |
{ |
{ |
261 |
score->score *= 10; |
score->score *= 10; |
262 |
score->score += (c-48); |
score->score += (c-48); |
263 |
} |
} |
264 |
while ((c = getc(f)) != EOF |
while ((c = getc (f)) != EOF |
265 |
&& isspace(c)) |
&& isspace (c)) |
266 |
; |
; |
267 |
if (c == EOF) |
if (c == EOF) |
268 |
return -1; |
return -1; |
269 |
ungetc(c, f); |
ungetc (c, f); |
270 |
#ifdef HAVE_GETDELIM |
#ifdef HAVE_GETDELIM |
271 |
{ |
{ |
272 |
size_t count = 0; |
size_t count = 0; |
273 |
if (getdelim(&score->username, &count, ' ', f) < 1 |
if (getdelim (&score->username, &count, ' ', f) < 1 |
274 |
|| score->username == NULL) |
|| score->username == NULL) |
275 |
return -1; |
return -1; |
276 |
/* Trim the space */ |
/* Trim the space */ |
277 |
score->username[strlen(score->username)-1] = '\0'; |
score->username[strlen (score->username)-1] = '\0'; |
278 |
} |
} |
279 |
#else |
#else |
280 |
{ |
{ |
281 |
int unameread = 0; |
int unameread = 0; |
282 |
int unamelen = 30; |
int unamelen = 30; |
283 |
char *username = malloc(unamelen); |
char *username = malloc (unamelen); |
284 |
if (!username) |
if (!username) |
285 |
return -1; |
return -1; |
286 |
|
|
287 |
while ((c = getc(f)) != EOF |
while ((c = getc (f)) != EOF |
288 |
&& !isspace(c)) |
&& !isspace (c)) |
289 |
{ |
{ |
290 |
if (unameread >= unamelen-1) |
if (unameread >= unamelen-1) |
291 |
if (!(username = realloc(username, unamelen *= 2))) |
if (!(username = realloc (username, unamelen *= 2))) |
292 |
return -1; |
return -1; |
293 |
username[unameread] = c; |
username[unameread] = c; |
294 |
unameread++; |
unameread++; |
295 |
} |
} |
296 |
if (c == EOF) |
if (c == EOF) |
297 |
return -1; |
return -1; |
298 |
username[unameread] = '\0'; |
username[unameread] = '\0'; |
299 |
score->username = username; |
score->username = username; |
304 |
errno = 0; |
errno = 0; |
305 |
{ |
{ |
306 |
size_t len; |
size_t len; |
307 |
if (getline(&score->data, &len, f) < 0) |
if (getline (&score->data, &len, f) < 0) |
308 |
return -1; |
return -1; |
309 |
score->data[strlen(score->data)-1] = '\0'; |
score->data[strlen (score->data)-1] = '\0'; |
310 |
} |
} |
311 |
#else |
#else |
312 |
{ |
{ |
313 |
int cur = 0; |
int cur = 0; |
314 |
int len = 16; |
int len = 16; |
315 |
char *buf = malloc(len); |
char *buf = malloc (len); |
316 |
if (!buf) |
if (!buf) |
317 |
return -1; |
return -1; |
318 |
while ((c = getc(f)) != EOF |
while ((c = getc (f)) != EOF |
319 |
&& c != '\n') |
&& c != '\n') |
320 |
{ |
{ |
321 |
if (cur >= len-1) |
if (cur >= len-1) |
322 |
{ |
{ |
323 |
if (!(buf = realloc(buf, len *= 2))) |
if (!(buf = realloc (buf, len *= 2))) |
324 |
return -1; |
return -1; |
325 |
} |
} |
326 |
buf[cur] = c; |
buf[cur] = c; |
334 |
} |
} |
335 |
|
|
336 |
int |
int |
337 |
read_scores(const char *filename, struct score_entry **scores, |
read_scores (filename, scores, count) |
338 |
int *count) |
const char *filename; |
339 |
|
struct score_entry **scores; |
340 |
|
int *count; |
341 |
{ |
{ |
342 |
int readval, scorecount, cursize; |
int readval, scorecount, cursize; |
343 |
struct score_entry *ret; |
struct score_entry *ret; |
344 |
FILE *f = fopen(filename, "r"); |
FILE *f = fopen (filename, "r"); |
345 |
if (!f) |
if (!f) |
346 |
return -1; |
return -1; |
347 |
scorecount = 0; |
scorecount = 0; |
348 |
cursize = 16; |
cursize = 16; |
349 |
ret = malloc(sizeof(struct score_entry) * cursize); |
ret = (struct score_entry *) malloc (sizeof (struct score_entry) * cursize); |
350 |
if (!ret) |
if (!ret) |
351 |
return -1; |
return -1; |
352 |
while ((readval = read_score(f, &ret[scorecount])) == 0) |
while ((readval = read_score (f, &ret[scorecount])) == 0) |
353 |
{ |
{ |
354 |
/* We encoutered an error */ |
/* We encoutered an error */ |
355 |
if (readval < 0) |
if (readval < 0) |
357 |
scorecount++; |
scorecount++; |
358 |
if (scorecount >= cursize) |
if (scorecount >= cursize) |
359 |
{ |
{ |
360 |
ret = realloc(ret, cursize *= 2); |
ret = (struct score_entry *) realloc (ret, cursize *= 2); |
361 |
if (!ret) |
if (!ret) |
362 |
return -1; |
return -1; |
363 |
} |
} |
368 |
} |
} |
369 |
|
|
370 |
int |
int |
371 |
score_compare(const void *a, const void *b) |
score_compare (a, b) |
372 |
|
const void *a; |
373 |
|
const void *b; |
374 |
{ |
{ |
375 |
const struct score_entry *sa = (const struct score_entry *) a; |
const struct score_entry *sa = (const struct score_entry *) a; |
376 |
const struct score_entry *sb = (const struct score_entry *) b; |
const struct score_entry *sb = (const struct score_entry *) b; |
378 |
} |
} |
379 |
|
|
380 |
int |
int |
381 |
score_compare_reverse(const void *a, const void *b) |
score_compare_reverse (a, b) |
382 |
|
const void *a; |
383 |
|
const void *b; |
384 |
{ |
{ |
385 |
const struct score_entry *sa = (const struct score_entry *) a; |
const struct score_entry *sa = (const struct score_entry *) a; |
386 |
const struct score_entry *sb = (const struct score_entry *) b; |
const struct score_entry *sb = (const struct score_entry *) b; |
388 |
} |
} |
389 |
|
|
390 |
int |
int |
391 |
push_score(struct score_entry **scores, int *count, |
push_score (scores, count, newscore, username, newdata) |
392 |
int newscore, char *username, char *newdata) |
struct score_entry **scores; |
393 |
{ |
int *count; int newscore; |
394 |
struct score_entry *newscores = realloc(*scores, |
char *username; |
395 |
sizeof(struct score_entry) * ((*count) + 1)); |
char *newdata; |
396 |
|
{ |
397 |
|
struct score_entry *newscores |
398 |
|
= (struct score_entry *) realloc (*scores, |
399 |
|
sizeof (struct score_entry) * ((*count) + 1)); |
400 |
if (!newscores) |
if (!newscores) |
401 |
return -1; |
return -1; |
402 |
newscores[*count].score = newscore; |
newscores[*count].score = newscore; |
406 |
*scores = newscores; |
*scores = newscores; |
407 |
return 0; |
return 0; |
408 |
} |
} |
409 |
|
|
410 |
void |
void |
411 |
sort_scores(struct score_entry *scores, int count, int reverse) |
sort_scores (scores, count, reverse) |
412 |
|
struct score_entry *scores; |
413 |
|
int count; |
414 |
|
int reverse; |
415 |
{ |
{ |
416 |
qsort(scores, count, sizeof(struct score_entry), |
qsort (scores, count, sizeof (struct score_entry), |
417 |
reverse ? score_compare_reverse : score_compare); |
reverse ? score_compare_reverse : score_compare); |
418 |
} |
} |
419 |
|
|
420 |
int |
int |
421 |
write_scores(const char *filename, const struct score_entry *scores, |
write_scores (filename, scores, count) |
422 |
int count) |
const char *filename; |
423 |
|
const struct score_entry * scores; |
424 |
|
int count; |
425 |
{ |
{ |
426 |
FILE *f; |
FILE *f; |
427 |
int i; |
int i; |
428 |
char *tempfile = malloc(strlen(filename) + strlen(".tempXXXXXX") + 1); |
char *tempfile = malloc (strlen (filename) + strlen (".tempXXXXXX") + 1); |
429 |
if (!tempfile) |
if (!tempfile) |
430 |
return -1; |
return -1; |
431 |
strcpy(tempfile, filename); |
strcpy (tempfile, filename); |
432 |
strcat(tempfile, ".tempXXXXXX"); |
strcat (tempfile, ".tempXXXXXX"); |
433 |
#ifdef HAVE_MKSTEMP |
#ifdef HAVE_MKSTEMP |
434 |
if (mkstemp(tempfile) < 0 |
if (mkstemp (tempfile) < 0 |
435 |
#else |
#else |
436 |
if (mktemp(tempfile) != tempfile |
if (mktemp (tempfile) != tempfile |
437 |
#endif |
#endif |
438 |
|| !(f = fopen(tempfile, "w"))) |
|| !(f = fopen (tempfile, "w"))) |
439 |
return -1; |
return -1; |
440 |
for (i = 0; i < count; i++) |
for (i = 0; i < count; i++) |
441 |
if (fprintf(f, "%ld %s %s\n", scores[i].score, scores[i].username, |
if (fprintf (f, "%ld %s %s\n", scores[i].score, scores[i].username, |
442 |
scores[i].data) < 0) |
scores[i].data) < 0) |
443 |
return -1; |
return -1; |
444 |
fclose(f); |
fclose (f); |
445 |
if (rename(tempfile, filename) < 0) |
if (rename (tempfile, filename) < 0) |
446 |
return -1; |
return -1; |
447 |
if (chmod(filename, 0644) < 0) |
if (chmod (filename, 0644) < 0) |
448 |
return -1; |
return -1; |
449 |
return 0; |
return 0; |
450 |
} |
} |
451 |
|
|
452 |
int |
int |
453 |
lock_file(const char *filename, void **state) |
lock_file (filename, state) |
454 |
|
const char *filename; |
455 |
|
void **state; |
456 |
{ |
{ |
457 |
int fd; |
int fd; |
458 |
struct stat buf; |
struct stat buf; |
459 |
int attempts = 0; |
int attempts = 0; |
460 |
char *lockext = ".lockfile"; |
char *lockext = ".lockfile"; |
461 |
char *lockpath = malloc(strlen(filename) + strlen(lockext) + 60); |
char *lockpath = malloc (strlen (filename) + strlen (lockext) + 60); |
462 |
if (!lockpath) |
if (!lockpath) |
463 |
return -1; |
return -1; |
464 |
strcpy(lockpath, filename); |
strcpy (lockpath, filename); |
465 |
strcat(lockpath, lockext); |
strcat (lockpath, lockext); |
466 |
*state = lockpath; |
*state = lockpath; |
467 |
trylock: |
trylock: |
468 |
attempts++; |
attempts++; |
469 |
/* If the lock is over an hour old, delete it. */ |
/* If the lock is over an hour old, delete it. */ |
470 |
if (stat(lockpath, &buf) == 0 |
if (stat (lockpath, &buf) == 0 |
471 |
&& (difftime(buf.st_ctime, time(NULL) > 60*60))) |
&& (difftime (buf.st_ctime, time (NULL) > 60*60))) |
472 |
unlink(lockpath); |
unlink (lockpath); |
473 |
if ((fd = open(lockpath, O_CREAT | O_EXCL, 0600)) < 0) |
fd = open (lockpath, O_CREAT | O_EXCL, 0600); |
474 |
|
if (fd < 0) |
475 |
{ |
{ |
476 |
if (errno == EEXIST) |
if (errno == EEXIST) |
477 |
{ |
{ |
479 |
lose some scores. */ |
lose some scores. */ |
480 |
if (attempts > MAX_ATTEMPTS) |
if (attempts > MAX_ATTEMPTS) |
481 |
{ |
{ |
482 |
unlink(lockpath); |
unlink (lockpath); |
483 |
attempts = 0; |
attempts = 0; |
484 |
} |
} |
485 |
sleep((rand() % 2)+1); |
sleep ((rand () % 2)+1); |
486 |
goto trylock; |
goto trylock; |
487 |
} |
} |
488 |
else |
else |
489 |
return -1; |
return -1; |
490 |
} |
} |
491 |
close(fd); |
close (fd); |
492 |
return 0; |
return 0; |
493 |
} |
} |
494 |
|
|
495 |
int |
int |
496 |
unlock_file(const char *filename, void *state) |
unlock_file (filename, state) |
497 |
|
const char *filename; |
498 |
|
void *state; |
499 |
{ |
{ |
500 |
char *lockpath = (char *) state; |
char *lockpath = (char *) state; |
501 |
int ret = unlink(lockpath); |
int ret = unlink (lockpath); |
502 |
int saved_errno = errno; |
int saved_errno = errno; |
503 |
free(lockpath); |
free (lockpath); |
504 |
errno = saved_errno; |
errno = saved_errno; |
505 |
return ret; |
return ret; |
506 |
} |
} |