/[emacs]/emacs/lib-src/update-game-score.c
ViewVC logotype

Diff of /emacs/lib-src/update-game-score.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.10 by walters, Mon Apr 29 22:49:00 2002 UTC revision 1.10.2.1 by miles, Fri Apr 4 06:19:55 2003 UTC
# Line 29  Boston, MA 02111-1307, USA.  */ Line 29  Boston, MA 02111-1307, USA.  */
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  {  {
# Line 77  struct score_entry Line 91  struct score_entry
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;
# Line 149  main(int argc, char **argv) Line 171  main(int argc, char **argv)
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;
# Line 164  main(int argc, char **argv) Line 186  main(int argc, char **argv)
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
# Line 215  main(int argc, char **argv) Line 237  main(int argc, char **argv)
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;
# Line 281  read_score(FILE *f, struct score_entry * Line 304  read_score(FILE *f, struct score_entry *
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;
# Line 311  read_score(FILE *f, struct score_entry * Line 334  read_score(FILE *f, struct score_entry *
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)
# Line 332  read_scores(const char *filename, struct Line 357  read_scores(const char *filename, struct
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          }          }
# Line 343  read_scores(const char *filename, struct Line 368  read_scores(const char *filename, struct
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;
# Line 351  score_compare(const void *a, const void Line 378  score_compare(const void *a, const void
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;
# Line 359  score_compare_reverse(const void *a, con Line 388  score_compare_reverse(const void *a, con
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;
# Line 373  push_score(struct score_entry **scores, Line 406  push_score(struct score_entry **scores,
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          {          {
# Line 438  lock_file(const char *filename, void **s Line 479  lock_file(const char *filename, void **s
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  }  }

Legend:
Removed from v.1.10  
changed lines
  Added in v.1.10.2.1

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26