installing okay now

This commit is contained in:
Neale Pickett 2015-04-10 16:37:21 -06:00
parent e8ad4bccde
commit 5b2b19284a
10 changed files with 539 additions and 491 deletions

View File

@ -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

37
bin/new Executable file
View File

@ -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/

30
bin/once Executable file
View File

@ -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

View File

@ -40,7 +40,7 @@ EOF
if [ -z "$hash" ] || [ -z "$team" ]; then
echo "<p>Empty field, cannot complete request</p>"
elif ! grep -q "^$hash$" state/teams/assigned.txt; then
elif ! grep -q "^$hash$" assigned.txt; then
echo "<p>That hash has not been assigned.</p>"
elif [ -f state/teams/names/$hash ]; then
echo "<p>That hash has already been registered.</p>"

View File

@ -8,7 +8,7 @@
<h1>Credits</h1>
<section>
<p>Dirtbags King of the Hill was created by:</p>
<h2>Created By</h2>
<ul>
<li>Neale Pickett</li>
@ -26,18 +26,23 @@
<li>William Phillips</li>
<li>Should your name be here? Please remind me!</li>
</ul>
<p>Parts of this contest were inspired by contests from:</p>
</section>
<section>
<h2>Inspiration</h2>
<ul>
<li>DC949</li>
<li>Tube Warriors</li>
<li>Sandia National Laboratories</li>
</ul>
</section>
<section>
<h2>Thanks</h2>
<p>
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:
</p>
<ul>
<li>Busybox</li>

View File

@ -6,8 +6,16 @@
<link rel="stylesheet" href="css/style.css" type="text/css">
</head>
<body>
<h1>Tracer FIRE 6</h1>
<h1>Tracer FIRE</h1>
<nav>
<ul>
<li><a href="register.html">Register</a></li>
<li><a href="puzzles.html">Puzzles</a></li>
<li><a href="scoreboard.html">Scoreboard</a></li>
</ul>
</nav>
<section>
<h2>Getting Started</h2>
@ -42,7 +50,7 @@
<h2>Reading Material</h2>
<p>
Stuck? Need a break? In the bathroom?
Stuck? Taking a break?
Here are some things to read.
</p>
@ -57,12 +65,5 @@
</ul>
</section>
<nav>
<ul>
<li><a href="register.html">Register</a></li>
<li><a href="puzzles.html">Puzzles</a></li>
<li><a href="scoreboard.html">Scoreboard</a></li>
</ul>
</nav>
</body>
</html>

View File

@ -1,25 +1,28 @@
<!DOCTYPE html>
<html>
<head>
<title>Team Registration</title>
<link rel="stylesheet" href="ctf.css" type="text/css">
</head>
<body>
<h1>Team Registration</h1>
<p>
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.
</p>
<form method="get" action="register.cgi">
<label>Team Hash (Token):</label>
<input type="text" name="h">
<br>
<label>Team Name:</label>
<input type="text" name="n">
<br>
<input type="submit" value="Register">
</form>
</body>
<head>
<title>Team Registration</title>
<link rel="stylesheet" href="css/style.css" type="text/css">
</head>
<body>
<h1>Team Registration</h1>
<section>
<p>
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.
</p>
<form method="get" action="register.cgi">
<label>Team Hash (Token):</label>
<input type="text" name="h">
<br>
<label>Team Name:</label>
<input type="text" name="n">
<br>
<input type="submit" value="Register">
</form>
</section>
</body>
</html>

60
install
View File

@ -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 </dev/urandom | awk '{print $3 $4 $5 $6;}' | head -n 100 > 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

View File

@ -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(("<!DOCTYPE html>\n"
"<html>\n"
" <head>\n"
" <title>%s</title>\n"
" <link rel=\"stylesheet\" href=\"ctf.css\" type=\"text/css\">\n"
" </head>\n"
" <body>\n"
" <h1>%s</h1>\n"),
title, title);
if (is_cgi) {
printf("Content-type: text/html\r\n\r\n");
}
printf(("<!DOCTYPE html>\n"
"<html>\n"
" <head>\n"
" <title>%s</title>\n"
" <link rel=\"stylesheet\" href=\"css/style.css\">\n"
" </head>\n"
" <body><h1>%s</h1><section>\n"), title, title);
}
void
cgi_foot()
{
printf("\n"
" </body>\n"
"</html>\n");
printf("\n</section></body></html>\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", "<p>The server is unable to award your points at this time.</p>");
case ERR_NOTEAM:
cgi_result(409, "No such team", "<p>There is no team with that hash.</p>");
case ERR_CLAIMED:
cgi_result(409, "Already claimed", "<p>That is the correct answer, but your team has already claimed these points.</p>");
default:
cgi_result(409, "Failure", "<p>Failure code: %d</p>", err);
}
switch (err) {
case ERR_GENERAL:
cgi_result(500, "Points not awarded", "<p>The server is unable to award your points at this time.</p>");
case ERR_NOTEAM:
cgi_result(409, "No such team", "<p>There is no team with that hash.</p>");
case ERR_CLAIMED:
cgi_result(409, "Already claimed",
"<p>That is the correct answer, but your team has already claimed these points.</p>");
default:
cgi_result(409, "Failure", "<p>Failure code: %d</p>", 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", "<p>%s</p>", text);
cgi_result(500, "Internal error", "<p>%s</p>", 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;
}

View File

@ -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;
}