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.
This commit is contained in:
Omar Polo 2021-03-06 20:46:47 +00:00 committed by Solene Rapenne
parent 16a5ed7b30
commit ee8569c6e6
2 changed files with 8 additions and 55 deletions

61
main.c
View file

@ -99,8 +99,8 @@ drop_privileges(const char *user, const char *path)
* write to stdio * write to stdio
*/ */
if (strlen(cgibin) > 0) { if (strlen(cgibin) > 0) {
/* cgi need execlp() (exec) and fork() (proc) */ /* cgi need execlp() (exec) */
epledge("stdio rpath exec proc", NULL); epledge("stdio rpath exec", NULL);
} else { } else {
epledge("stdio rpath", NULL); epledge("stdio rpath", NULL);
} }
@ -270,58 +270,11 @@ autoindex(const char *path)
void void
cgi(const char *cgicmd) cgi(const char *cgicmd)
{ {
execlp(cgicmd, cgicmd, NULL);
int pipedes[2] = {0}; /* if execlp is ok, this will never be reached */
pid_t pid; status(42, "Couldn't execute CGI script");
errlog("error when trying to execlp %s", cgicmd);
/* get a pipe to get stdout */ exit(1);
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);
}
} }
int int

View file

@ -89,7 +89,7 @@ if ! [ $OUT = "fa065a67d1f7c973501d4a9e3ca2ea57" ] ; then echo "error" ; exit 1
# cgi with error # cgi with error
OUT=$(printf "gemini://host.name/cgi-bin/nope\r\n" | ../vger -d var/gemini/ -c /cgi-bin | tee /dev/stderr | MD5) 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 # remove ?.* if any
OUT=$(printf "gemini://host.name/main.gmi?anything-here\r\n" | ../vger -d var/gemini/ | tee /dev/stderr | MD5) OUT=$(printf "gemini://host.name/main.gmi?anything-here\r\n" | ../vger -d var/gemini/ | tee /dev/stderr | MD5)