tvote.c: add function to perform safe vote increments - vote - simple cgi votin… | |
git clone git://src.adamsgaard.dk/vote | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
commit d5823861bfb88b89fc65a8844cd7e9a623bb0690 | |
parent c214ae3ad448784c1da35ec3b14dec92fc92fccd | |
Author: Anders Damsgaard <[email protected]> | |
Date: Mon, 28 Sep 2020 13:17:43 +0200 | |
vote.c: add function to perform safe vote increments | |
Diffstat: | |
M vote.c | 152 +++++++++++++++++++----------… | |
1 file changed, 96 insertions(+), 56 deletions(-) | |
--- | |
diff --git a/vote.c b/vote.c | |
t@@ -15,6 +15,7 @@ | |
#define OUT(s) (fputs((s), stdout)) | |
#define POLLS_DIR "polls" | |
+static char fname[PATH_MAX]; | |
static char poll[1024]; | |
static char create[2]; | |
static char question[4096]; | |
t@@ -39,6 +40,23 @@ http_status(int statuscode) | |
} | |
} | |
+char * | |
+pollfile(const char *poll_name, const char *postfix) | |
+{ | |
+ char buf[PATH_MAX]; | |
+ | |
+ strlcpy(buf, poll_name, sizeof(buf)); | |
+ escapechars(buf); | |
+ if (snprintf(fname, sizeof(fname), "%s/%s%s", | |
+ POLLS_DIR, buf, postfix) < 0) { | |
+ http_status(500); | |
+ err(1, "show_poll: snprintf fname %s/%s%s", | |
+ POLLS_DIR, buf, postfix); | |
+ } | |
+ | |
+ return fname; | |
+} | |
+ | |
void | |
print_html_head() | |
{ | |
t@@ -55,31 +73,31 @@ print_html_foot() | |
"</html>\n"); | |
} | |
-void | |
-print_poll_line(char *line) | |
+int | |
+print_poll_line(char *line, int intable) | |
{ | |
- printf("<tr><td>"); | |
- while (*line) { | |
- switch(*line) { | |
- case '\t': | |
- printf("</td><td>"); | |
- break; | |
- default: | |
- putchar(*line); | |
- break; | |
- } | |
- (void)*line++; | |
+ size_t c; | |
+ | |
+ if (sscanf(line, "%ld\t%s", &c, options) == 2) { | |
+ if (!intable) | |
+ puts("<br><table>"); | |
+ printf("<tr><td>%ld</td><td>%s</td></tr>\n", c, options); | |
+ return 1; | |
+ } else { | |
+ if (intable) | |
+ puts("</table>"); | |
+ printf("%s<br>\n", line); | |
+ return 0; | |
} | |
- puts("</td></tr>"); | |
} | |
void | |
-print_poll_file(FILE *fp, const char *poll_name) | |
+print_poll_file(FILE *fp) | |
{ | |
char *line = NULL; | |
- size_t linesize = 0; | |
+ size_t linesize = 0, lineno = 0; | |
ssize_t linelen; | |
- unsigned int lineno = 0; | |
+ int intable = 0; | |
while ((linelen = getline(&line, &linesize, fp)) != -1) { | |
lineno++; | |
t@@ -87,18 +105,18 @@ print_poll_file(FILE *fp, const char *poll_name) | |
line[--linelen] = '\0'; | |
if (lineno == 1) { | |
- printf("<h1>%s: <i>", poll_name); | |
+ printf("<h2>"); | |
fwrite(line, linelen, 1, stdout); | |
- printf("</i></h1>"); | |
- printf("<table>\n"); | |
+ printf("</h2>\n"); | |
} else { | |
- print_poll_line(line); | |
+ intable = print_poll_line(line, intable); | |
} | |
- /* puts("<br>"); */ | |
} | |
free(line); | |
- if (ferror(fp)) | |
+ if (ferror(fp)) { | |
+ http_status(500); | |
err(1, "print_poll_file: getline"); | |
+ } | |
puts("</table>"); | |
} | |
t@@ -106,16 +124,9 @@ int | |
create_poll_file(const char *name, const char *question, const char *options) | |
{ | |
FILE *fp; | |
- char fname[PATH_MAX], buf[PATH_MAX]; | |
struct stat sb; | |
size_t col; | |
- | |
- strlcpy(buf, name, sizeof(buf)); | |
- escapechars(buf); | |
- if (snprintf(fname, sizeof(fname), "%s/%s", POLLS_DIR, buf) < 0) { | |
- http_status(500); | |
- err(1, "create_poll_file: snprintf fname %s/%s", POLLS_DIR, bu… | |
- } | |
+ char *fname; | |
if (!*name || !*question || !*options) { | |
puts("<p><b>Error: Could not create poll</b></p>"); | |
t@@ -130,6 +141,7 @@ create_poll_file(const char *name, const char *question, c… | |
return -1; | |
} | |
+ fname = pollfile(name, ""); | |
if (stat(fname, &sb) == 0) { | |
printf("<p>Poll '%s' already exists</p>", name); | |
return -1; | |
t@@ -163,7 +175,7 @@ create_poll_file(const char *name, const char *question, c… | |
break; | |
} | |
} | |
- /* fputc('\n', fp); */ | |
+ fputc('\n', fp); | |
fclose(fp); | |
} | |
} | |
t@@ -171,24 +183,15 @@ create_poll_file(const char *name, const char *question,… | |
} | |
void | |
-show_poll(const char *poll_name) | |
+show_poll(const char *poll) | |
{ | |
FILE *fp; | |
- char fname[PATH_MAX]; | |
- char buf[PATH_MAX]; | |
- strlcpy(buf, poll_name, sizeof(buf)); | |
- escapechars(buf); | |
- if (snprintf(fname, sizeof(fname), "%s/%s", POLLS_DIR, buf) < 0) { | |
- http_status(500); | |
- err(1, "show_poll: snprintf fname %s/%s", POLLS_DIR, buf); | |
- } | |
- | |
- if (!(fp = fopen(fname, "r"))) { | |
+ if (!(fp = fopen(pollfile(poll, ""), "r"))) { | |
http_status(404); | |
exit(1); | |
} else { | |
- print_poll_file(fp, poll_name); | |
+ print_poll_file(fp); | |
fclose(fp); | |
} | |
} | |
t@@ -199,12 +202,10 @@ list_polls() | |
FTS *ftsp; | |
FTSENT *p; | |
int fts_options = FTS_COMFOLLOW | FTS_LOGICAL | FTS_NOCHDIR; | |
- /* int fts_options = FTS_NOCHDIR | FTS_PHYSICAL; */ | |
- /* char *path = POLLS_DIR; */ | |
char *paths[] = { (char*)POLLS_DIR, NULL }; | |
if ((ftsp = fts_open(paths, fts_options, NULL)) == NULL) { | |
- fprintf(stderr, "could not fts_open"); | |
+ http_status(500); | |
err(1, "list_polls: fts_open"); | |
} | |
t@@ -226,19 +227,55 @@ list_polls() | |
puts("</ul>"); | |
} | |
-/* | |
void | |
-increment_option(FILE *fp) | |
+increment_option(char *poll, size_t n) | |
{ | |
- while ((ch = fgetc(ft)) != EOF) { | |
- if (ch == 'i') { | |
- fseek(ft, -1, SEEK_CUR); | |
- fputc('a',ft); | |
- fseek(ft, 0, SEEK_CUR); | |
+ FILE *fp, *fp_tmp; | |
+ size_t v, lineno = 0; | |
+ char *line = NULL, *fname = NULL; | |
+ static char fname_tmp[PATH_MAX]; | |
+ size_t linesize = 0; | |
+ ssize_t linelen; | |
+ struct stat sb; | |
+ | |
+ fname = pollfile(poll, "_lock"); | |
+ strlcpy(fname_tmp, fname, sizeof(fname_tmp)); | |
+ while (stat(fname_tmp, &sb) == 0) | |
+ usleep(100); | |
+ if (!(fp_tmp = fopen(fname_tmp, "w"))) { | |
+ http_status(500); | |
+ err(1, "increment_option: fopen fp_tmp"); | |
+ } | |
+ | |
+ fname = pollfile(poll, ""); | |
+ if (!(fp = fopen(fname, "r"))) { | |
+ http_status(404); | |
+ err(1, "increment_option: fopen fp"); | |
+ } | |
+ | |
+ while ((linelen = getline(&line, &linesize, fp)) != -1) { | |
+ if (sscanf(line, "%ld\t%s", &v, options) != 2) | |
+ fputs(line, fp_tmp); | |
+ else { | |
+ if (++lineno == n) | |
+ v++; | |
+ fprintf(fp_tmp, "%ld\t%s\n", v, options); | |
} | |
} | |
+ | |
+ free(line); | |
+ if (ferror(fp) || ferror(fp_tmp)) { | |
+ http_status(500); | |
+ err(1, "increment_option: getline"); | |
+ } | |
+ fclose(fp); | |
+ fclose(fp_tmp); | |
+ | |
+ if (rename(fname_tmp, fname) != 0) { | |
+ http_status(500); | |
+ err(1, "increment_option: rename"); | |
+ } | |
} | |
-*/ | |
void | |
print_poll_create_form() | |
t@@ -281,8 +318,10 @@ parse_query() | |
{ | |
char *query, *p; | |
- if (!(query = getenv("QUERY_STRING"))) | |
+ if (!(query = getenv("QUERY_STRING"))) { | |
query = ""; | |
+ return; | |
+ } | |
if ((p = getparam(query, "create"))) { | |
if (decodeparam(create, sizeof(create), p) == -1) { | |
t@@ -345,6 +384,7 @@ main() | |
show_poll(poll); | |
} else if (*poll) { | |
show_poll(poll); | |
+ increment_option(poll, 2); | |
} else { | |
list_polls(); | |
print_poll_create_form(); |