/[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.12 by fx, Mon Nov 18 15:35:07 2002 UTC revision 1.13 by rms, Tue Feb 4 12:00:09 2003 UTC
# Line 69  extern int optind, opterr; Line 69  extern int optind, opterr;
69  #endif  #endif
70    
71  int  int
72  usage(err)  usage (err)
73       int err;       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 P_((const char *filename, void **state));  int unlock_file P_ ((const char *filename, void *state));
 int  
 unlock_file P_((const char *filename, void *state));  
86    
87  struct score_entry  struct score_entry
88  {  {
# Line 93  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 P_((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 P_((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  void                        int count));
 sort_scores P_((struct score_entry *scores, int count, int reverse));  
 int  
 write_scores P_((const char *filename, const struct score_entry *scores,  
                  int count));  
101    
102  void lose P_((const char *msg)) NO_RETURN;  void lose P_ ((const char *msg)) NO_RETURN;
103    
104  void lose(msg)  void
105    lose (msg)
106       const char *msg;       const char *msg;
107  {  {
108    fprintf(stderr, "%s\n", msg);    fprintf (stderr, "%s\n", msg);
109    exit(1);    exit (1);
110  }  }
111    
112  void lose_syserr P_((const char *msg)) NO_RETURN;  void lose_syserr P_ ((const char *msg)) NO_RETURN;
113    
114  void lose_syserr(msg)  void
115    lose_syserr (msg)
116       const char *msg;       const char *msg;
117  {  {
118    fprintf(stderr, "%s: %s\n", msg, strerror(errno));    fprintf (stderr, "%s: %s\n", msg, strerror (errno));
119    exit(1);    exit (1);
120  }  }
121    
122  char *  char *
123  get_user_id P_ ((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(running_suid, user_prefix)  get_prefix (running_suid, user_prefix)
145       int running_suid;       int running_suid;
146       char *user_prefix;       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.");      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.");        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(argc, argv)  main (argc, argv)
163       int argc;       int argc;
164       char **argv;       char **argv;
165  {  {
# Line 175  main(argc, argv) Line 171  main(argc, 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 190  main(argc, argv) Line 186  main(argc, 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_syserr("Couldn't allocate score file");      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)    if ((user_id = get_user_id ()) == NULL)
217      lose_syserr("Couldn't determine user id");      lose_syserr ("Couldn't determine user id");
218        
219    if (stat(scorefile, &buf) < 0)    if (stat (scorefile, &buf) < 0)
220      lose_syserr("Failed to access scores file");      lose_syserr ("Failed to access scores file");
221                                    
222    if (lock_file(scorefile, &lockstate) < 0)    if (lock_file (scorefile, &lockstate) < 0)
223      lose_syserr("Failed to lock scores file");      lose_syserr ("Failed to lock scores file");
224                                        
225    if (read_scores(scorefile, &scores, &scorecount) < 0)    if (read_scores (scorefile, &scores, &scorecount) < 0)
226      {      {
227        unlock_file(scorefile, lockstate);        unlock_file (scorefile, lockstate);
228        lose_syserr("Failed to read scores file");        lose_syserr ("Failed to read scores file");
229      }      }
230    push_score(&scores, &scorecount, newscore, user_id, newdata);    push_score (&scores, &scorecount, newscore, user_id, newdata);
231    /* Limit the number of scores.  If we're using reverse sorting, then    /* Limit the number of scores.  If we're using reverse sorting, then
232       we should increment the beginning of the array, to skip over the       we should increment the beginning of the array, to skip over the
233       *smallest* scores.  Otherwise, we just decrement the number of       *smallest* scores.  Otherwise, we just decrement the number of
# Line 240  main(argc, argv) Line 236  main(argc, argv)
236      scorecount -= (scorecount - MAX_SCORES);      scorecount -= (scorecount - MAX_SCORES);
237      if (reverse)      if (reverse)
238        scores += (scorecount - MAX_SCORES);        scores += (scorecount - MAX_SCORES);
239    sort_scores(scores, scorecount, reverse);    sort_scores (scores, scorecount, reverse);
240    if (write_scores(scorefile, scores, scorecount) < 0)    if (write_scores (scorefile, scores, scorecount) < 0)
241      {      {
242        unlock_file(scorefile, lockstate);        unlock_file (scorefile, lockstate);
243        lose_syserr("Failed to write scores file");        lose_syserr ("Failed to write scores file");
244      }      }
245    unlock_file(scorefile, lockstate);    unlock_file (scorefile, lockstate);
246    exit(0);    exit (0);
247  }  }
248    
249  int  int
250  read_score(f, score)  read_score (f, score)
251       FILE *f;       FILE *f;
252       struct score_entry *score;       struct score_entry *score;
253  {  {
254    int c;    int c;
255    if (feof(f))    if (feof (f))
256      return 1;      return 1;
257    while ((c = getc(f)) != EOF    while ((c = getc (f)) != EOF
258           && isdigit(c))           && isdigit (c))
259      {      {
260        score->score *= 10;        score->score *= 10;
261        score->score += (c-48);        score->score += (c-48);
262      }      }
263    while ((c = getc(f)) != EOF    while ((c = getc (f)) != EOF
264           && isspace(c))           && isspace (c))
265      ;      ;
266    if (c == EOF)    if (c == EOF)
267      return -1;      return -1;
268    ungetc(c, f);    ungetc (c, f);
269  #ifdef HAVE_GETDELIM  #ifdef HAVE_GETDELIM
270    {    {
271      size_t count = 0;      size_t count = 0;
272      if (getdelim(&score->username, &count, ' ', f) < 1      if (getdelim (&score->username, &count, ' ', f) < 1
273          || score->username == NULL)          || score->username == NULL)
274        return -1;        return -1;
275      /* Trim the space */      /* Trim the space */
276      score->username[strlen(score->username)-1] = '\0';      score->username[strlen (score->username)-1] = '\0';
277    }    }
278  #else  #else
279    {    {
280      int unameread = 0;      int unameread = 0;
281      int unamelen = 30;      int unamelen = 30;
282      char *username = malloc(unamelen);      char *username = malloc (unamelen);
283      if (!username)      if (!username)
284        return -1;        return -1;
285            
286      while ((c = getc(f)) != EOF      while ((c = getc (f)) != EOF
287             && !isspace(c))             && !isspace (c))
288        {        {
289          if (unameread >= unamelen-1)          if (unameread >= unamelen-1)
290            if (!(username = realloc(username, unamelen *= 2)))            if (!(username = realloc (username, unamelen *= 2)))
291              return -1;              return -1;
292          username[unameread] = c;          username[unameread] = c;
293          unameread++;          unameread++;
# Line 307  read_score(f, score) Line 303  read_score(f, score)
303    errno = 0;    errno = 0;
304    {    {
305      size_t len;      size_t len;
306      if (getline(&score->data, &len, f) < 0)      if (getline (&score->data, &len, f) < 0)
307        return -1;        return -1;
308      score->data[strlen(score->data)-1] = '\0';      score->data[strlen (score->data)-1] = '\0';
309    }    }
310  #else  #else
311    {    {
312      int cur = 0;      int cur = 0;
313      int len = 16;      int len = 16;
314      char *buf = malloc(len);      char *buf = malloc (len);
315      if (!buf)      if (!buf)
316        return -1;        return -1;
317      while ((c = getc(f)) != EOF      while ((c = getc (f)) != EOF
318             && c != '\n')             && c != '\n')
319        {        {
320          if (cur >= len-1)          if (cur >= len-1)
321            {            {
322              if (!(buf = realloc(buf, len *= 2)))              if (!(buf = realloc (buf, len *= 2)))
323                return -1;                return -1;
324            }            }
325          buf[cur] = c;          buf[cur] = c;
# Line 337  read_score(f, score) Line 333  read_score(f, score)
333  }  }
334    
335  int  int
336  read_scores(filename, scores, count)  read_scores (filename, scores, count)
337       const char *filename;       const char *filename;
338       struct score_entry **scores;       struct score_entry **scores;
339       int *count;       int *count;
340  {  {
341    int readval, scorecount, cursize;    int readval, scorecount, cursize;
342    struct score_entry *ret;    struct score_entry *ret;
343    FILE *f = fopen(filename, "r");    FILE *f = fopen (filename, "r");
344    if (!f)    if (!f)
345      return -1;      return -1;
346    scorecount = 0;    scorecount = 0;
347    cursize = 16;    cursize = 16;
348    ret = malloc(sizeof(struct score_entry) * cursize);    ret = malloc (sizeof (struct score_entry) * cursize);
349    if (!ret)    if (!ret)
350      return -1;      return -1;
351    while ((readval = read_score(f, &ret[scorecount])) == 0)    while ((readval = read_score (f, &ret[scorecount])) == 0)
352      {      {
353        /* We encoutered an error */        /* We encoutered an error */
354        if (readval < 0)        if (readval < 0)
# Line 360  read_scores(filename, scores, count) Line 356  read_scores(filename, scores, count)
356        scorecount++;        scorecount++;
357        if (scorecount >= cursize)        if (scorecount >= cursize)
358          {          {
359            ret = realloc(ret, cursize *= 2);            ret = realloc (ret, cursize *= 2);
360            if (!ret)            if (!ret)
361              return -1;              return -1;
362          }          }
# Line 371  read_scores(filename, scores, count) Line 367  read_scores(filename, scores, count)
367  }  }
368    
369  int  int
370  score_compare(a, b)  score_compare (a, b)
371       const void *a;       const void *a;
372       const void *b;       const void *b;
373  {  {
# Line 381  score_compare(a, b) Line 377  score_compare(a, b)
377  }  }
378    
379  int  int
380  score_compare_reverse(a, b)  score_compare_reverse (a, b)
381       const void *a;       const void *a;
382       const void *b;       const void *b;
383  {  {
# Line 391  score_compare_reverse(a, b) Line 387  score_compare_reverse(a, b)
387  }  }
388    
389  int  int
390  push_score(scores, count, newscore, username, newdata)  push_score (scores, count, newscore, username, newdata)
391       struct score_entry **scores;       struct score_entry **scores;
392       int *count; int newscore;       int *count; int newscore;
393       char *username;       char *username;
394       char *newdata;       char *newdata;
395  {  {
396   struct score_entry *newscores = realloc(*scores,   struct score_entry *newscores
397                                           sizeof(struct score_entry) * ((*count) + 1));     = realloc (*scores,
398                  sizeof (struct score_entry) * ((*count) + 1));
399    if (!newscores)    if (!newscores)
400      return -1;      return -1;
401    newscores[*count].score = newscore;    newscores[*count].score = newscore;
# Line 410  push_score(scores, count, newscore, user Line 407  push_score(scores, count, newscore, user
407  }  }
408        
409  void  void
410  sort_scores(scores, count, reverse)  sort_scores (scores, count, reverse)
411       struct score_entry *scores;       struct score_entry *scores;
412       int count;       int count;
413       int reverse;       int reverse;
414  {  {
415    qsort(scores, count, sizeof(struct score_entry),    qsort (scores, count, sizeof (struct score_entry),
416          reverse ? score_compare_reverse : score_compare);          reverse ? score_compare_reverse : score_compare);
417  }  }
418    
419  int  int
420  write_scores(filename, scores, count)  write_scores (filename, scores, count)
421       const char *filename;       const char *filename;
422       const struct score_entry * scores;       const struct score_entry * scores;
423       int count;       int count;
424  {  {
425    FILE *f;      FILE *f;  
426    int i;    int i;
427    char *tempfile = malloc(strlen(filename) + strlen(".tempXXXXXX") + 1);    char *tempfile = malloc (strlen (filename) + strlen (".tempXXXXXX") + 1);
428    if (!tempfile)    if (!tempfile)
429      return -1;      return -1;
430    strcpy(tempfile, filename);    strcpy (tempfile, filename);
431    strcat(tempfile, ".tempXXXXXX");    strcat (tempfile, ".tempXXXXXX");
432  #ifdef HAVE_MKSTEMP  #ifdef HAVE_MKSTEMP
433    if (mkstemp(tempfile) < 0    if (mkstemp (tempfile) < 0
434  #else  #else
435    if (mktemp(tempfile) != tempfile    if (mktemp (tempfile) != tempfile
436  #endif  #endif
437        || !(f = fopen(tempfile, "w")))        || !(f = fopen (tempfile, "w")))
438      return -1;      return -1;
439    for (i = 0; i < count; i++)    for (i = 0; i < count; i++)
440      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,
441                  scores[i].data) < 0)                  scores[i].data) < 0)
442        return -1;        return -1;
443    fclose(f);    fclose (f);
444    if (rename(tempfile, filename) < 0)    if (rename (tempfile, filename) < 0)
445      return -1;      return -1;
446    if (chmod(filename, 0644) < 0)    if (chmod (filename, 0644) < 0)
447      return -1;      return -1;
448    return 0;    return 0;
449  }  }
450        
451  int  int
452  lock_file(filename, state)  lock_file (filename, state)
453    const char *filename;    const char *filename;
454    void **state;    void **state;
455  {  {
# Line 460  lock_file(filename, state) Line 457  lock_file(filename, state)
457    struct stat buf;    struct stat buf;
458    int attempts = 0;    int attempts = 0;
459    char *lockext = ".lockfile";    char *lockext = ".lockfile";
460    char *lockpath = malloc(strlen(filename) + strlen(lockext) + 60);    char *lockpath = malloc (strlen (filename) + strlen (lockext) + 60);
461    if (!lockpath)    if (!lockpath)
462      return -1;      return -1;
463    strcpy(lockpath, filename);    strcpy (lockpath, filename);
464    strcat(lockpath, lockext);    strcat (lockpath, lockext);
465    *state = lockpath;    *state = lockpath;
466   trylock:   trylock:
467    attempts++;    attempts++;
468    /* If the lock is over an hour old, delete it. */    /* If the lock is over an hour old, delete it. */
469    if (stat(lockpath, &buf) == 0    if (stat (lockpath, &buf) == 0
470        && (difftime(buf.st_ctime, time(NULL) > 60*60)))        && (difftime (buf.st_ctime, time (NULL) > 60*60)))
471      unlink(lockpath);      unlink (lockpath);
472    if ((fd = open(lockpath, O_CREAT | O_EXCL, 0600)) < 0)    if ((fd = open (lockpath, O_CREAT | O_EXCL, 0600)) < 0)
473      {      {
474        if (errno == EEXIST)        if (errno == EEXIST)
475          {          {
# Line 480  lock_file(filename, state) Line 477  lock_file(filename, state)
477               lose some scores. */               lose some scores. */
478            if (attempts > MAX_ATTEMPTS)            if (attempts > MAX_ATTEMPTS)
479              {              {
480                unlink(lockpath);                unlink (lockpath);
481                attempts = 0;                attempts = 0;
482              }              }
483            sleep((rand() % 2)+1);            sleep ((rand () % 2)+1);
484            goto trylock;            goto trylock;
485          }          }
486        else        else
487          return -1;          return -1;
488      }      }
489    close(fd);    close (fd);
490    return 0;    return 0;
491  }  }
492    
493  int  int
494  unlock_file(filename, state)  unlock_file (filename, state)
495    const char *filename;    const char *filename;
496   void *state;   void *state;
497  {  {
498    char *lockpath = (char *) state;    char *lockpath = (char *) state;
499    int ret = unlink(lockpath);    int ret = unlink (lockpath);
500    int saved_errno = errno;    int saved_errno = errno;
501    free(lockpath);    free (lockpath);
502    errno = saved_errno;    errno = saved_errno;
503    return ret;    return ret;
504  }  }

Legend:
Removed from v.1.12  
changed lines
  Added in v.1.13

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