From ee8569c6e692a56f96cd6717453270ce2a28fa39 Mon Sep 17 00:00:00 2001 From: Omar Polo Date: Sat, 6 Mar 2021 20:46:47 +0000 Subject: [PATCH] simplify cgi function Don't fork+execlp the script. There's no need to do so since on exec the new process will inherit our file descriptor table (and hence our stdout), so copying from its stdout to ours is just a waste of time. This allows to drop the ``proc'' pledge(2) promise and to (slightly) improve performance. --- main.c | 61 ++++++--------------------------------------------- tests/test.sh | 2 +- 2 files changed, 8 insertions(+), 55 deletions(-) diff --git a/main.c b/main.c index 4e3a147..1f038bb 100644 --- a/main.c +++ b/main.c @@ -99,8 +99,8 @@ drop_privileges(const char *user, const char *path) * write to stdio */ if (strlen(cgibin) > 0) { - /* cgi need execlp() (exec) and fork() (proc) */ - epledge("stdio rpath exec proc", NULL); + /* cgi need execlp() (exec) */ + epledge("stdio rpath exec", NULL); } else { epledge("stdio rpath", NULL); } @@ -270,58 +270,11 @@ autoindex(const char *path) void cgi(const char *cgicmd) { - - int pipedes[2] = {0}; - pid_t pid; - - /* get a pipe to get stdout */ - if (pipe(pipedes) != 0) { - status(42, "text/gemini"); - err(1, "pipe failed"); - } - - pid = fork(); - - if (pid < 0) { - close(pipedes[0]); - close(pipedes[1]); - status(42, "text/gemini"); - err(1, "fork failed"); - } - - if (pid > 0) { /* parent */ - char buf[3]; - size_t nread = 0; - FILE *output = NULL; - - close(pipedes[1]); /* make sure entry is closed so fread() gets EOF */ - - /* use fread/fwrite because are buffered */ - output = fdopen(pipedes[0], "r"); - if (output == NULL) { - status(42, "text/gemini"); - err(1, "fdopen failed"); - } - - /* read pipe output */ - while ((nread = fread(buf, 1, sizeof(buf), output)) != 0) { - fwrite(buf, 1, nread, stdout); - } - close(pipedes[0]); - fclose(output); - - wait(NULL); /* wait for child to terminate */ - - exit(0); - - } else if (pid == 0) { /* child */ - dup2(pipedes[1], STDOUT_FILENO); /* set pipe output equal to stdout */ - close(pipedes[1]); /* no need this file descriptor : it is now stdout */ - execlp(cgicmd, cgicmd, NULL); - /* if execlp is ok, this will never be reached */ - status(42, "text/gemini"); - errlog("error when trying to execlp %s", cgicmd); - } + execlp(cgicmd, cgicmd, NULL); + /* if execlp is ok, this will never be reached */ + status(42, "Couldn't execute CGI script"); + errlog("error when trying to execlp %s", cgicmd); + exit(1); } int diff --git a/tests/test.sh b/tests/test.sh index 6ffa703..011cf71 100644 --- a/tests/test.sh +++ b/tests/test.sh @@ -89,7 +89,7 @@ if ! [ $OUT = "fa065a67d1f7c973501d4a9e3ca2ea57" ] ; then echo "error" ; exit 1 # cgi with error OUT=$(printf "gemini://host.name/cgi-bin/nope\r\n" | ../vger -d var/gemini/ -c /cgi-bin | tee /dev/stderr | MD5) -if ! [ $OUT = "2c88347cfac44450035283a8508a29cb" ] ; then echo "error" ; exit 1 ; fi +if ! [ $OUT = "4156170c2aa8a6a8a0892ff5a61bf5f5" ] ; then echo "error" ; exit 1 ; fi # remove ?.* if any OUT=$(printf "gemini://host.name/main.gmi?anything-here\r\n" | ../vger -d var/gemini/ | tee /dev/stderr | MD5)