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();