tvote.c: add function to perform safe vote increments - vote - simple cgi voting system for web and gopher (HTM) git clone git://src.adamsgaard.dk/vote (DIR) Log (DIR) Files (DIR) Refs (DIR) README (DIR) LICENSE --- (DIR) commit d5823861bfb88b89fc65a8844cd7e9a623bb0690 (DIR) parent c214ae3ad448784c1da35ec3b14dec92fc92fccd (HTM) Author: Anders Damsgaard <anders@adamsgaard.dk> 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(-) --- (DIR) 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, buf); - } + 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, const char *options) 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, const char *options) break; } } - /* fputc('\n', fp); */ + fputc('\n', fp); fclose(fp); } } t@@ -171,24 +183,15 @@ create_poll_file(const char *name, const char *question, const char *options) } 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();