diff --git a/bin/kothd b/bin/kothd deleted file mode 100755 index 6f2128f..0000000 --- a/bin/kothd +++ /dev/null @@ -1,58 +0,0 @@ -#! /bin/sh - -echo "Figuring out web user..." -for www in www-data http _; do - id $www && break -done - -if [ $www = _ ]; then - echo "Unable to determine httpd user on this system. Dying." - exit 1 -fi - -initialize () { - for i in points.new points.tmp teams; do - mkdir -p state/$i - setfacl -m ${www}:rwx state/$i - done - - >> state/points.log - hd < /dev/urandom | awk '{print $3 $4 $5 $6;}' | head -n 100 > state/teams/assigned.txt -} - -once () { - if [ -f disabled ]; then - return - fi - - if ! [ -d state ]; then - initialize $1 - fi - - # Collect new points - find state/points.new -type f | while read fn; do - cat $fn >> state/points.log - rm $fn - done - - # Generate new puzzles.html - if $KOTH_BASE/puzzles.cgi > www/puzzles.new; then - mv www/puzzles.new www/puzzles.html - fi - - # Generate new points.json - if $KOTH_BASE/points > www/points.new; then - mv www/points.new www/points.json - fi -} - -cd $(basename $0) -KOTH_BASE=$(pwd) - -while true; do - for dn in $KOTH_BASE/*; do - cd $dn - once - done - sleep 5 -done diff --git a/bin/new b/bin/new new file mode 100755 index 0000000..e765e88 --- /dev/null +++ b/bin/new @@ -0,0 +1,37 @@ +#! /bin/sh + +newdir=$1 +if [ -z "$newdir" ]; then + echo "Usage: $0 NEWDIR" + exit 1 +fi + +KOTH_BASE=$(cd $(dirname $0)/.. && pwd) + +echo "Figuring out web user..." +for www in www-data http _; do + id $www && break +done + +if [ $www = _ ]; then + echo "Unable to determine httpd user on this system. Dying." + exit 1 +fi + +mkdir -p $newdir +cd $newdir + +for i in points.new points.tmp teams; do + mkdir -p state/$i + setfacl -m ${www}:rwx state/$i +done + +>> state/points.log + +if ! [ -f assigned.txt ]; then + hd < /dev/urandom | awk '{print $3 $4 $5 $6;}' | head -n 100 > assigned.txt +fi + +mkdir -p www +cp -r $KOTH_BASE/html/* www/ +cp $KOTH_BASE/bin/*.cgi www/ diff --git a/bin/once b/bin/once new file mode 100755 index 0000000..87dfdc2 --- /dev/null +++ b/bin/once @@ -0,0 +1,30 @@ +#! /bin/sh + +cd $(dirname $0) + +# Do nothing if `disabled` is present +if [ -f disabled ]; then + exit +fi + +# Reset to initial state if `reset` is present +if [ -f reset ]; then + rm -f state/teams/* state/points.new/* state/points.tmp/* + > state/points.log +fi + +# Collect new points +find state/points.new -type f | while read fn; do + cat $fn >> state/points.log + rm $fn +done + +# Generate new puzzles.html +if $KOTH_BASE/puzzles.cgi > www/puzzles.new; then + mv www/puzzles.new www/puzzles.html +fi + +# Generate new points.json +if $KOTH_BASE/points > www/points.new; then + mv www/points.new www/points.json +fi diff --git a/html/register.cgi b/bin/register.cgi similarity index 95% rename from html/register.cgi rename to bin/register.cgi index c05f8fc..23ad37f 100755 --- a/html/register.cgi +++ b/bin/register.cgi @@ -40,7 +40,7 @@ EOF if [ -z "$hash" ] || [ -z "$team" ]; then echo "

Empty field, cannot complete request

" -elif ! grep -q "^$hash$" state/teams/assigned.txt; then +elif ! grep -q "^$hash$" assigned.txt; then echo "

That hash has not been assigned.

" elif [ -f state/teams/names/$hash ]; then echo "

That hash has already been registered.

" diff --git a/html/credits.html b/html/credits.html index 82481a4..d0c8756 100644 --- a/html/credits.html +++ b/html/credits.html @@ -8,7 +8,7 @@

Credits

-

Dirtbags King of the Hill was created by:

+

Created By

- -

Parts of this contest were inspired by contests from:

+
+ +
+

Inspiration

- +
+ +
+

Thanks

- Lastly, this contest would not exist were it not for hundreds of - thousands of lines of code from free software authors around the - world, including: + This contest would not exist were it not for hundreds of + thousands of lines of code from free software authors around the + world, including:

- diff --git a/html/register.html b/html/register.html index ec3948a..d9cc89c 100644 --- a/html/register.html +++ b/html/register.html @@ -1,25 +1,28 @@ - - Team Registration - - - -

Team Registration

-

- Before you can use a token, you must choose a team name. - You can only do this once per token, - so make sure it's the team name you actually want. - Staff are unable to make changes to team names. -

-
- - -
- - -
- -
- + + Team Registration + + + +

Team Registration

+ +
+

+ Before you can use a token, you must choose a team name. + You can only do this once per token, + so make sure it's the team name you actually want. + Staff are unable to make changes to team names. +

+
+ + +
+ + +
+ +
+
+ diff --git a/install b/install index c378c41..29afd5c 100755 --- a/install +++ b/install @@ -1,6 +1,11 @@ #! /bin/sh -DESTDIR=${1:-/opt/koth} +DESTDIR=$1 + +if [ -z "$DESTDIR" ]; then + echo "Usage: $0 DESTDIR" + exit +fi cd $(dirname $0) @@ -14,15 +19,6 @@ older () { return 1 } -html () { - target=$DESTDIR/${1%mdwn}html - if older $target $1 tmpl/*; then - echo "HTML $1" - mkdir -p $(dirname $target) - ./tmpl/mdwntohtml < $1 > $target - fi -} - copy () { target=$DESTDIR/$1 if older $target $1; then @@ -41,6 +37,41 @@ cc () { fi } +cgi () { + target=$DESTDIR/www/$(basename $1 .c) + if older $target $@; then + mkdir -p $(dirname $target) + src=$1; shift + echo "CC $src" + gcc -Wall -Werror -o $target $@ src/common.c $src + fi +} + +setup() { + echo "SETUP" + for i in points.new points.tmp teams; do + dir=$DESTDIR/state/$i + mkdir -p $dir + setfacl -m ${www}:rwx $dir + done + >> $DESTDIR/state/points.log + if ! [ -f $DESTDIR/assigned.txt ]; then + hd assigned.txt + fi +} + + +echo "Figuring out web user..." +for www in www-data http _; do + id $www && break +done +if [ $www = _ ]; then + echo "Unable to determine httpd user on this system. Dying." + exit 1 +fi + +mkdir -p $DESTDIR || exit 1 + git ls-files | while read fn; do case "$fn" in install|.*) @@ -53,8 +84,13 @@ git ls-files | while read fn; do bin/*) copy $fn ;; - src/*.cgi.c|src/pointscli.c) - cc src/common.c $fn + src/common.c) + ;; + src/pointscli.c) + cc $fn src/common.c + ;; + src/*.cgi.c) + cgi $fn ;; src/*.c) cc $fn diff --git a/src/common.c b/src/common.c index 59c872d..6d39628 100644 --- a/src/common.c +++ b/src/common.c @@ -12,9 +12,9 @@ #include "common.h" #ifdef NODUMP -# define DUMPf(fmt, args...) +#define DUMPf(fmt, args...) #else -# define DUMPf(fmt, args...) fprintf(stderr, "%s:%s:%d " fmt "\n", __FILE__, __FUNCTION__, __LINE__, ##args) +#define DUMPf(fmt, args...) fprintf(stderr, "%s:%s:%d " fmt "\n", __FILE__, __FUNCTION__, __LINE__, ##args) #endif #define DUMP() DUMPf("") #define DUMP_d(v) DUMPf("%s = %d", #v, v) @@ -29,237 +29,230 @@ /* * CGI */ -static int is_cgi = 0; -static char **argv = NULL; +static int is_cgi = 0; +static char **argv = NULL; static int read_char_argv() { - static int arg = 0; - static char *p; + static int arg = 0; + static char *p; - if (NULL == argv) { - return EOF; - } + if (NULL == argv) { + return EOF; + } - if (0 == arg) { - arg = 1; - p = argv[1]; - } + if (0 == arg) { + arg = 1; + p = argv[1]; + } - if (! p) { - return EOF; - } else if (! *p) { - arg += 1; - p = argv[arg]; - return '&'; - } + if (!p) { + return EOF; + } else if (!*p) { + arg += 1; + p = argv[arg]; + return '&'; + } - return *(p++); + return *(p++); } static int read_char_stdin() { - static int inlen = -1; + static int inlen = -1; - if (-1 == inlen) { - char *p = getenv("CONTENT_LENGTH"); - if (p) { - inlen = atoi(p); - if (inlen > POST_MAX) { - inlen = POST_MAX; - } - if (inlen < 0) { - inlen = 0; - } - } else { - inlen = 0; - } - } + if (-1 == inlen) { + char *p = getenv("CONTENT_LENGTH"); + if (p) { + inlen = atoi(p); + if (inlen > POST_MAX) { + inlen = POST_MAX; + } + if (inlen < 0) { + inlen = 0; + } + } else { + inlen = 0; + } + } - if (inlen) { - inlen -= 1; - return getchar(); - } - return EOF; + if (inlen) { + inlen -= 1; + return getchar(); + } + return EOF; } static int read_char_query_string() { - static char *p = (char *)-1; + static char *p = (char *) -1; - if ((char *)-1 == p) { - p = getenv("QUERY_STRING"); - } + if ((char *) -1 == p) { + p = getenv("QUERY_STRING"); + } - if (! p) { - return EOF; - } else if (! *p) { - return EOF; - } else { - return *(p++); - } + if (!p) { + return EOF; + } else if (!*p) { + return EOF; + } else { + return *(p++); + } } -static int (* read_char)() = read_char_argv; +static int (*read_char) () = read_char_argv; int cgi_init(char *global_argv[]) { - char *rm = getenv("REQUEST_METHOD"); + char *rm = getenv("REQUEST_METHOD"); - if (! rm) { - read_char = read_char_argv; - argv = global_argv; - } else if (0 == strcmp(rm, "POST")) { - read_char = read_char_stdin; - is_cgi = 1; - } else if (0 == strcmp(rm, "GET")) { - read_char = read_char_query_string; - is_cgi = 1; - } else { - printf(("405 Method not allowed\r\n" - "Allow: GET, POST\r\n" - "Content-type: text/plain\r\n" - "\r\n" - "%s is not allowed.\n"), - rm); - return -1; - } + if (!rm) { + read_char = read_char_argv; + argv = global_argv; + } else if (0 == strcmp(rm, "POST")) { + read_char = read_char_stdin; + is_cgi = 1; + } else if (0 == strcmp(rm, "GET")) { + read_char = read_char_query_string; + is_cgi = 1; + } else { + printf(("405 Method not allowed\r\n" + "Allow: GET, POST\r\n" "Content-type: text/plain\r\n" "\r\n" "%s is not allowed.\n"), rm); + return -1; + } - return 0; + return 0; } static char tonum(int c) { - if ((c >= '0') && (c <= '9')) { - return c - '0'; - } - if ((c >= 'a') && (c <= 'f')) { - return 10 + c - 'a'; - } - if ((c >= 'A') && (c <= 'F')) { - return 10 + c - 'A'; - } - return 0; + if ((c >= '0') && (c <= '9')) { + return c - '0'; + } + if ((c >= 'a') && (c <= 'f')) { + return 10 + c - 'a'; + } + if ((c >= 'A') && (c <= 'F')) { + return 10 + c - 'A'; + } + return 0; } static char read_hex() { - int a = read_char(); - int b = read_char(); + int a = read_char(); + int b = read_char(); - return tonum(a)*16 + tonum(b); + return tonum(a) * 16 + tonum(b); } -/* Read a key or a value. Since & and = aren't supposed to appear - outside of boundaries, we can use the same function for both. -*/ +/* + * Read a key or a value. Since & and = aren't supposed to appear outside of boundaries, we can use the same function for both. + */ size_t cgi_item(char *str, size_t maxlen) { - int c; - size_t pos = 0; + int c; + size_t pos = 0; - while (1) { - c = read_char(); - switch (c) { - case EOF: - case '=': - case '&': - str[pos] = '\0'; - return pos; - case '%': - c = read_hex(); - break; - case '+': - c = ' '; - break; - } - if (pos < maxlen - 1) { - str[pos] = c; - pos += 1; - } - } + while (1) { + c = read_char(); + switch (c) { + case EOF: + case '=': + case '&': + str[pos] = '\0'; + return pos; + case '%': + c = read_hex(); + break; + case '+': + c = ' '; + break; + } + if (pos < maxlen - 1) { + str[pos] = c; + pos += 1; + } + } } void cgi_head(char *title) { - if (is_cgi) { - printf("Content-type: text/html\r\n\r\n"); - } - printf(("\n" - "\n" - " \n" - " %s\n" - " \n" - " \n" - " \n" - "

%s

\n"), - title, title); + if (is_cgi) { + printf("Content-type: text/html\r\n\r\n"); + } + printf(("\n" + "\n" + " \n" + " %s\n" + " \n" + " \n" + "

%s

\n"), title, title); } void cgi_foot() { - printf("\n" - " \n" - "\n"); + printf("\n
\n"); } void cgi_result(int code, char *desc, char *fmt, ...) { - va_list ap; + va_list ap; - if (is_cgi) { - printf("Status: %d %s\r\n", code, desc); - } - cgi_head(desc); - va_start(ap, fmt); - vprintf(fmt, ap); - va_end(ap); - cgi_foot(); - exit(0); + if (is_cgi) { + printf("Status: %d %s\r\n", code, desc); + } + cgi_head(desc); + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + cgi_foot(); + exit(0); } void cgi_fail(int err) { - switch (err) { - case ERR_GENERAL: - cgi_result(500, "Points not awarded", "

The server is unable to award your points at this time.

"); - case ERR_NOTEAM: - cgi_result(409, "No such team", "

There is no team with that hash.

"); - case ERR_CLAIMED: - cgi_result(409, "Already claimed", "

That is the correct answer, but your team has already claimed these points.

"); - default: - cgi_result(409, "Failure", "

Failure code: %d

", err); - } + switch (err) { + case ERR_GENERAL: + cgi_result(500, "Points not awarded", "

The server is unable to award your points at this time.

"); + case ERR_NOTEAM: + cgi_result(409, "No such team", "

There is no team with that hash.

"); + case ERR_CLAIMED: + cgi_result(409, "Already claimed", + "

That is the correct answer, but your team has already claimed these points.

"); + default: + cgi_result(409, "Failure", "

Failure code: %d

", err); + } } void cgi_page(char *title, char *fmt, ...) { - va_list ap; + va_list ap; - cgi_head(title); - va_start(ap, fmt); - vprintf(fmt, ap); - va_end(ap); - cgi_foot(); - exit(0); + cgi_head(title); + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + cgi_foot(); + exit(0); } void cgi_error(char *text) { - cgi_result(500, "Internal error", "

%s

", text); + cgi_result(500, "Internal error", "

%s

", text); } @@ -267,276 +260,278 @@ cgi_error(char *text) * Common routines */ -/* cut -d$ANCHOR -f2- | grep -Fx "$NEEDLE" */ +/* + * cut -d$ANCHOR -f2- | grep -Fx "$NEEDLE" + */ int anchored_search(char const *filename, char const *needle, char const anchor) { - FILE *f = fopen(filename, "r"); - size_t nlen = strlen(needle); - char line[1024]; - int ret = 0; + FILE *f = fopen(filename, "r"); + size_t nlen = strlen(needle); + char line[1024]; + int ret = 0; - while (f) { - char *p; + while (f) { + char *p; - if (NULL == fgets(line, sizeof line, f)) { - break; - } + if (NULL == fgets(line, sizeof line, f)) { + break; + } - /* Find anchor */ - if (anchor) { - p = strchr(line, anchor); - if (! p) { - continue; - } - p += 1; - } else { - p = line; - } + /* + * Find anchor + */ + if (anchor) { + p = strchr(line, anchor); + if (!p) { + continue; + } + p += 1; + } else { + p = line; + } - /* Don't bother with strcmp if string lengths differ. - If this string is shorter than the previous, it's okay. This is - just a performance hack. - */ - if ((p[nlen] != '\n') && - (p[nlen] != '\0')) { - continue; - } - p[nlen] = 0; + /* + * Don't bother with strcmp if string lengths differ. If this string is shorter than the previous, it's okay. This + * is just a performance hack. + */ + if ((p[nlen] != '\n') && (p[nlen] != '\0')) { + continue; + } + p[nlen] = 0; - /* Okay, now we can compare! */ - if (0 == strcmp(p, needle)) { - ret = 1; - break; - } - } + /* + * Okay, now we can compare! + */ + if (0 == strcmp(p, needle)) { + ret = 1; + break; + } + } - if (f) { - fclose(f); - } + if (f) { + fclose(f); + } - return ret; + return ret; } void urandom(char *buf, size_t buflen) { - static int fd = -2; + static int fd = -2; - if (-2 == fd) { - srandom(time(NULL) * getpid()); - fd = open("/dev/urandom", O_RDONLY); - } - if (-1 != fd) { - int len; + if (-2 == fd) { + srandom(time(NULL) * getpid()); + fd = open("/dev/urandom", O_RDONLY); + } + if (-1 != fd) { + int len; - len = read(fd, buf, buflen); - if (len == buflen) { - return; - } - } + len = read(fd, buf, buflen); + if (len == buflen) { + return; + } + } - /* Fall back to libc's crappy thing */ - { - int i; + /* + * Fall back to libc's crappy thing + */ + { + int i; - for (i = 0; i < buflen; i += 1) { - buf[i] = (char)random(); - } - } + for (i = 0; i < buflen; i += 1) { + buf[i] = (char) random(); + } + } } int my_snprintf(char *buf, size_t buflen, char *fmt, ...) { - int len; - va_list ap; + int len; + va_list ap; - va_start(ap, fmt); - len = vsnprintf(buf, buflen - 1, fmt, ap); - va_end(ap); - buf[buflen - 1] = '\0'; - if (len >= buflen) { - return buflen - 1; - } else { - return len; - } + va_start(ap, fmt); + len = vsnprintf(buf, buflen - 1, fmt, ap); + va_end(ap); + buf[buflen - 1] = '\0'; + if (len >= buflen) { + return buflen - 1; + } else { + return len; + } } void ctf_chdir() { - static int initialized = 0; - int i; + static int initialized = 0; + int i; - if (initialized) { - return; - } - initialized = 1; + if (initialized) { + return; + } + initialized = 1; - /* chdir to $CTF_BASE */ - { - char const *ctf_base = getenv("CTF_BASE"); + /* + * chdir to $CTF_BASE + */ + { + char const *ctf_base = getenv("CTF_BASE"); - if (ctf_base) { - chdir(ctf_base); - } - } + if (ctf_base) { + chdir(ctf_base); + } + } - /* Keep going up one directory until there's a packages directory */ - for (i = 0; i < 5; i += 1) { - struct stat st; + /* + * Keep going up one directory until there's a packages directory + */ + for (i = 0; i < 5; i += 1) { + struct stat st; - if ((0 == stat("packages", &st)) && - S_ISDIR(st.st_mode)) { - return; - } - chdir(".."); - } - fprintf(stderr, "Can not determine CTF_BASE directory: exiting.\n"); - exit(66); + if ((0 == stat("packages", &st)) && S_ISDIR(st.st_mode)) { + return; + } + chdir(".."); + } + fprintf(stderr, "Can not determine CTF_BASE directory: exiting.\n"); + exit(66); } -static char * +static char * mkpath(char const *type, char const *fmt, va_list ap) { - char relpath[PATH_MAX]; - static char path[PATH_MAX]; + char relpath[PATH_MAX]; + static char path[PATH_MAX]; - ctf_chdir(); - vsnprintf(relpath, sizeof(relpath) - 1, fmt, ap); - relpath[sizeof(relpath) - 1] = '\0'; + ctf_chdir(); + vsnprintf(relpath, sizeof(relpath) - 1, fmt, ap); + relpath[sizeof(relpath) - 1] = '\0'; - /* $CTF_BASE/type/relpath */ - my_snprintf(path, sizeof(path), "%s/%s", type, relpath); - return path; + /* + * $CTF_BASE/type/relpath + */ + my_snprintf(path, sizeof(path), "%s/%s", type, relpath); + return path; } -char * +char * state_path(char const *fmt, ...) { - va_list ap; - char *ret; + va_list ap; + char *ret; - va_start(ap, fmt); - ret = mkpath("state", fmt, ap); - va_end(ap); - return ret; + va_start(ap, fmt); + ret = mkpath("state", fmt, ap); + va_end(ap); + return ret; } -char * +char * package_path(char const *fmt, ...) { - va_list ap; - char *ret; + va_list ap; + char *ret; - va_start(ap, fmt); - ret = mkpath("packages", fmt, ap); - va_end(ap); - return ret; + va_start(ap, fmt); + ret = mkpath("packages", fmt, ap); + va_end(ap); + return ret; } int team_exists(char const *teamhash) { - struct stat buf; - int ret; - int i; + struct stat buf; + int ret; + int i; - if ((! teamhash) || (! *teamhash)) { - return 0; - } + if ((!teamhash) || (!*teamhash)) { + return 0; + } - /* Check for invalid characters. */ - for (i = 0; teamhash[i]; i += 1) { - if (! isalnum(teamhash[i])) { - return 0; - } - } + /* + * Check for invalid characters. + */ + for (i = 0; teamhash[i]; i += 1) { + if (!isalnum(teamhash[i])) { + return 0; + } + } - /* stat seems to be the preferred way to check for existence. */ - ret = stat(state_path("teams/names/%s", teamhash), &buf); - if (-1 == ret) { - return 0; - } + /* + * stat seems to be the preferred way to check for existence. + */ + ret = stat(state_path("teams/names/%s", teamhash), &buf); + if (-1 == ret) { + return 0; + } - return 1; + return 1; } -/* Return values: - -1: general error - -2: no such team - -3: points already awarded +/* + * Return values: -1: general error -2: no such team -3: points already awarded */ int -award_points(char const *teamhash, - char const *category, - const long points, - char const *uid) +award_points(char const *teamhash, char const *category, const long points, char const *uid) { - char line[100]; - int linelen; - char *filename; - FILE *f; - time_t now = time(NULL); + char line[100]; + int linelen; + char *filename; + FILE *f; + time_t now = time(NULL); - if (! team_exists(teamhash)) { - return ERR_NOTEAM; - } + if (!team_exists(teamhash)) { + return ERR_NOTEAM; + } - linelen = snprintf(line, sizeof(line), - "%s %s %ld %s", - teamhash, category, points, uid); - if (sizeof(line) <= linelen) { - return ERR_GENERAL; - } + linelen = snprintf(line, sizeof(line), "%s %s %ld %s", teamhash, category, points, uid); + if (sizeof(line) <= linelen) { + return ERR_GENERAL; + } - if (anchored_search(state_path("points.log"), line, ' ')) { - return ERR_CLAIMED; - } + if (anchored_search(state_path("points.log"), line, ' ')) { + return ERR_CLAIMED; + } - /* At one time I had this writing to a single log file, using lockf. - This works, as long as nobody ever tries to edit the log file. - Editing the log file would require locking it, which would block - everything trying to score, effectively taking down the entire - contest. If you can't lock it first--and nothing in busybox lets - you do this--you have to bring down pretty much everything manually - anyway. + /* + * At one time I had this writing to a single log file, using lockf. This works, as long as nobody ever tries to edit the + * log file. Editing the log file would require locking it, which would block everything trying to score, effectively + * taking down the entire contest. If you can't lock it first--and nothing in busybox lets you do this--you have to bring + * down pretty much everything manually anyway. + * + * By putting new scores into new files and periodically appending those files to the main log file, it is possible to stop + * the thing that appends, edit the file at leisure, and then start the appender back up, all without affecting things + * trying to score: they're still able to record their score and move on. + */ - By putting new scores into new files and periodically appending - those files to the main log file, it is possible to stop the thing - that appends, edit the file at leisure, and then start the appender - back up, all without affecting things trying to score: they're - still able to record their score and move on. - */ + filename = state_path("points.tmp/%lu.%d.%s.%s.%ld", (unsigned long) now, getpid(), teamhash, category, points); + f = fopen(filename, "w"); + if (!f) { + return ERR_GENERAL; + } - filename = state_path("points.tmp/%lu.%d.%s.%s.%ld", - (unsigned long)now, getpid(), - teamhash, category, points); - f = fopen(filename, "w"); - if (! f) { - return ERR_GENERAL; - } + if (EOF == fprintf(f, "%lu %s\n", (unsigned long) now, line)) { + return ERR_GENERAL; + } - if (EOF == fprintf(f, "%lu %s\n", (unsigned long)now, line)) { - return ERR_GENERAL; - } + fclose(f); - fclose(f); + /* + * Rename into points.new + */ + { + char ofn[PATH_MAX]; - /* Rename into points.new */ - { - char ofn[PATH_MAX]; + strncpy(ofn, filename, sizeof(ofn)); + filename = state_path("points.new/%lu.%d.%s.%s.%ld", (unsigned long) now, getpid(), teamhash, category, points); + rename(ofn, filename); + } - strncpy(ofn, filename, sizeof(ofn)); - filename = state_path("points.new/%lu.%d.%s.%s.%ld", - (unsigned long)now, getpid(), - teamhash, category, points); - rename(ofn, filename); - } - - return 0; + return 0; } - diff --git a/src/pointscli.c b/src/pointscli.c index f0eace7..232b606 100644 --- a/src/pointscli.c +++ b/src/pointscli.c @@ -7,42 +7,41 @@ int main(int argc, char *argv[]) { - int points; - int ret; - char comment[512]; + int points; + int ret; + char comment[512]; - if (argc != 5) { - fprintf(stderr, - "Usage: pointscli TEAM CATEGORY POINTS 'COMMENT'\n"); - return EX_USAGE; - } - ctf_chdir(); + if (argc != 5) { + fprintf(stderr, "Usage: pointscli TEAM CATEGORY POINTS 'COMMENT'\n"); + return EX_USAGE; + } + ctf_chdir(); - points = atoi(argv[3]); - if (0 == points) { - fprintf(stderr, "Error: award 0 points?\n"); - return EX_USAGE; - } + points = atoi(argv[3]); + if (0 == points) { + fprintf(stderr, "Error: award 0 points?\n"); + return EX_USAGE; + } - snprintf(comment, sizeof comment, "--%s", argv[4]); + snprintf(comment, sizeof comment, "--%s", argv[4]); - ret = award_points(argv[1], argv[2], points, comment); - switch (ret) { - case 0: - return 0; - case ERR_GENERAL: - perror("General error"); - return EX_UNAVAILABLE; - case ERR_NOTEAM: - fprintf(stderr, "No such team\n"); - return EX_NOUSER; - case ERR_CLAIMED: - fprintf(stderr, "Duplicate entry\n"); - return EX_DATAERR; - default: - fprintf(stderr, "Error %d\n", ret); - return EX_SOFTWARE; - } + ret = award_points(argv[1], argv[2], points, comment); + switch (ret) { + case 0: + return 0; + case ERR_GENERAL: + perror("General error"); + return EX_UNAVAILABLE; + case ERR_NOTEAM: + fprintf(stderr, "No such team\n"); + return EX_NOUSER; + case ERR_CLAIMED: + fprintf(stderr, "Duplicate entry\n"); + return EX_DATAERR; + default: + fprintf(stderr, "Error %d\n", ret); + return EX_SOFTWARE; + } - return 0; + return 0; }