Download raw body.
gotwebd fcgi/gotweb process split
On Thu, Apr 10, 2025 at 10:52:59AM +0200, Stefan Sperling wrote:
> On Wed, Apr 09, 2025 at 06:31:42PM +0200, Stefan Sperling wrote:
> > This patch is still work-in-progress. It lacks documentation updates,
> > and one TODO is mentioned in the code.
>
> updated patch which resolves remaining TODOs and updates docs, too.
Another update which fixes the two issues found by me so far:
1) We need to do polling writes in fcgi_forward to avoid:
fcgi_forward_response: wrote -1 of 1024 bytes: \
Resource temporarily unavailable
2) fix hang during '/etc/rc.d/gotwebd restart', causing rc to kill gotwebd
M gotwebd/Makefile | 0+ 2-
M gotwebd/Makefile.inc | 1+ 1-
M gotwebd/config.c | 9+ 15-
M gotwebd/fcgi.c | 104+ 7-
M gotwebd/gotweb.c | 384+ 14-
M gotwebd/gotwebd.8 | 8+ 10-
M gotwebd/gotwebd.c | 242+ 80-
M gotwebd/gotwebd.conf.5 | 29+ 13-
M gotwebd/gotwebd.h | 30+ 10-
D gotwebd/libexec/Makefile | 0+ 4-
D gotwebd/libexec/Makefile.inc | 0+ 11-
D gotwebd/libexec/got-read-blob/Makefile | 0+ 15-
D gotwebd/libexec/got-read-commit/Makefile | 0+ 15-
D gotwebd/libexec/got-read-gitconfig/Makefile | 0+ 16-
D gotwebd/libexec/got-read-gotconfig/Makefile | 0+ 19-
D gotwebd/libexec/got-read-object/Makefile | 0+ 15-
D gotwebd/libexec/got-read-pack/Makefile | 0+ 16-
D gotwebd/libexec/got-read-tag/Makefile | 0+ 15-
D gotwebd/libexec/got-read-tree/Makefile | 0+ 15-
M gotwebd/parse.y | 24+ 3-
M gotwebd/sockets.c | 223+ 40-
M regress/gotwebd/Makefile | 1+ 7-
22 files changed, 1055 insertions(+), 343 deletions(-)
commit - 1fefee5fcecc39a1b50ab7c21b82b751ba1e7d30
commit + 4774f2e2fe6130bd3e9d719dd399e5a25170904c
blob - 6b6e9e1815bb7b6d738165292b522056eee96e22
blob + 545a13d2e5aba6dc9df486f7300af0acf23c4df7
--- gotwebd/Makefile
+++ gotwebd/Makefile
@@ -1,8 +1,6 @@
.PATH:${.CURDIR}/../lib
.PATH:${.CURDIR}/../template
-SUBDIR = libexec
-
.include "../got-version.mk"
.include "Makefile.inc"
blob - 8140d7d3e8b25972b9b347173294bd3b671a0da1
blob + 22466be67cc8ab44489af620bed8558a24ed17c9
--- gotwebd/Makefile.inc
+++ gotwebd/Makefile.inc
@@ -1,9 +1,9 @@
LDADD += -lz -lutil
PREFIX ?= /usr/local
BINDIR ?= ${PREFIX}/sbin
+LIBEXECDIR ?= ${PREFIX}/libexec
CHROOT_DIR ?= /var/www
GOTWEB_DIR = /bin/gotwebd
-LIBEXECDIR = ${GOTWEB_DIR}/libexec
HTTPD_DIR = ${CHROOT_DIR}/htdocs
PROG_DIR = ${HTTPD_DIR}/${PROG}
WWWUSR ?= www
blob - 980ecf25520da4497a36f585459ebecbf7b1d3f5
blob + 90eb143afce8e50c7ba53d141294ca8616d7a074
--- gotwebd/config.c
+++ gotwebd/config.c
@@ -74,15 +74,6 @@ config_getcfg(struct gotwebd *env, struct imsg *imsg)
}
int
-config_setserver(struct gotwebd *env, struct server *srv)
-{
- if (main_compose_sockets(env, GOTWEBD_IMSG_CFG_SRV,
- -1, srv, sizeof(*srv)) == -1)
- fatal("main_compose_sockets GOTWEBD_IMSG_CFG_SRV");
- return 0;
-}
-
-int
config_getserver(struct gotwebd *env, struct imsg *imsg)
{
struct server *srv;
@@ -106,17 +97,20 @@ config_getserver(struct gotwebd *env, struct imsg *ims
}
int
-config_setsock(struct gotwebd *env, struct socket *sock)
+config_setsock(struct gotwebd *env, struct socket *sock, uid_t uid, gid_t gid)
{
/* open listening sockets */
- if (sockets_privinit(env, sock) == -1)
+ if (sockets_privinit(env, sock, uid, gid) == -1)
return -1;
if (main_compose_sockets(env, GOTWEBD_IMSG_CFG_SOCK, sock->fd,
&sock->conf, sizeof(sock->conf)) == -1)
fatal("main_compose_sockets GOTWEBD_IMSG_CFG_SOCK");
- sock->fd = -1;
+ if (main_compose_gotweb(env, GOTWEBD_IMSG_CFG_SOCK, sock->fd,
+ &sock->conf, sizeof(sock->conf)) == -1)
+ fatal("main_compose_gotweb GOTWEBD_IMSG_CFG_SOCK");
+
return 0;
}
@@ -172,13 +166,13 @@ config_setfd(struct gotwebd *env)
fd = got_opentempfd();
if (fd == -1)
fatal("got_opentemp");
- if (imsg_compose_event(&env->iev_server[j],
+ if (imsg_compose_event(&env->iev_gotweb[j],
GOTWEBD_IMSG_CFG_FD, 0, -1, fd, NULL, 0) == -1)
fatal("imsg_compose_event GOTWEBD_IMSG_CFG_FD");
- if (imsgbuf_flush(&env->iev_server[j].ibuf) == -1)
+ if (imsgbuf_flush(&env->iev_gotweb[j].ibuf) == -1)
fatal("imsgbuf_flush");
- imsg_event_add(&env->iev_server[j]);
+ imsg_event_add(&env->iev_gotweb[j]);
}
}
blob - fe58b1f12ab25d401bc5d3c10aaecf29d138f7bd
blob + 3ec4aee067d2084604a4b3ca1fa315b83811ccc3
--- gotwebd/fcgi.c
+++ gotwebd/fcgi.c
@@ -35,6 +35,8 @@
#include "got_error.h"
#include "got_reference.h"
+#include "got_lib_poll.h"
+
#include "gotwebd.h"
#include "log.h"
#include "tmpl.h"
@@ -53,7 +55,7 @@ void dump_fcgi_end_request_body(const char *,
struct fcgi_end_request_body *);
extern int cgi_inflight;
-extern volatile int client_cnt;
+extern struct requestlist requests;
void
fcgi_request(int fd, short events, void *arg)
@@ -142,6 +144,7 @@ fcgi_parse_record(uint8_t *buf, size_t n, struct reque
ntohs(h->content_len), c, ntohs(h->id));
break;
case FCGI_STDIN:
+ return 0;
case FCGI_ABORT_REQUEST:
fcgi_create_end_record(c);
fcgi_cleanup_request(c);
@@ -175,6 +178,89 @@ fcgi_parse_begin_request(uint8_t *buf, uint16_t n,
c->id = id;
}
+static void
+fcgi_forward_response(int fd, short event, void *arg)
+{
+ const struct got_error *err = NULL;
+ struct request *c = arg;
+ uint8_t outbuf[GOTWEBD_CACHESIZE];
+ ssize_t r;
+
+ if ((event & EV_READ) == 0)
+ return;
+
+ r = read(fd, outbuf, sizeof(outbuf));
+ if (r == 0)
+ return;
+
+ if (r == -1) {
+ log_warn("read response");
+ } else {
+ err = got_poll_write_full(c->fd, outbuf, r);
+ if (err) {
+ log_warnx("forward response: %s", err->msg);
+ fcgi_cleanup_request(c);
+ return;
+ }
+ }
+
+ event_add(c->resp_event, NULL);
+}
+
+static void
+process_request(struct request *c)
+{
+ struct gotwebd *env = gotwebd_env;
+ int ret, i, pipe[2];
+ struct request ic;
+ struct event *resp_event = NULL;
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe) == -1) {
+ log_warn("socketpair");
+ return;
+ }
+
+ memcpy(&ic, c, sizeof(ic));
+
+ /* Don't leak pointers from our address space to another process. */
+ ic.sock = NULL;
+ ic.srv = NULL;
+ ic.t = NULL;
+ ic.tp = NULL;
+ ic.buf = NULL;
+ ic.outbuf = NULL;
+
+ /* Other process will use its own set of temp files. */
+ for (i = 0; i < nitems(c->priv_fd); i++)
+ ic.priv_fd[i] = -1;
+ ic.fd = -1;
+ ic.resp_fd = -1;
+
+ resp_event = calloc(1, sizeof(*resp_event));
+ if (resp_event == NULL) {
+ log_warn("calloc");
+ close(pipe[0]);
+ close(pipe[1]);
+ return;
+ }
+
+ ret = imsg_compose_event(env->iev_gotweb, GOTWEBD_IMSG_REQ_PROCESS,
+ GOTWEBD_PROC_SERVER, getpid(), pipe[0], &ic, sizeof(ic));
+ if (ret == -1) {
+ log_warn("imsg_compose_event");
+ close(pipe[0]);
+ close(pipe[1]);
+ free(resp_event);
+ return;
+ }
+
+ event_set(resp_event, pipe[1], EV_READ, fcgi_forward_response, c);
+ event_add(resp_event, NULL);
+
+ c->resp_fd = pipe[1];
+ c->resp_event = resp_event;
+}
+
void
fcgi_parse_params(uint8_t *buf, uint16_t n, struct request *c, uint16_t id)
{
@@ -192,8 +278,7 @@ fcgi_parse_params(uint8_t *buf, uint16_t n, struct req
}
if (n == 0) {
- gotweb_process_request(c);
- template_flush(c->tp);
+ process_request(c);
return;
}
@@ -399,16 +484,28 @@ void
fcgi_cleanup_request(struct request *c)
{
cgi_inflight--;
- client_cnt--;
- evtimer_del(&c->tmo);
+ sockets_del_request(c);
+
+ if (evtimer_initialized(&c->tmo))
+ evtimer_del(&c->tmo);
if (event_initialized(&c->ev))
event_del(&c->ev);
- close(c->fd);
- template_free(c->tp);
+ if (c->fd != -1)
+ close(c->fd);
+ if (c->resp_fd != -1)
+ close(c->resp_fd);
+ if (c->tp != NULL)
+ template_free(c->tp);
if (c->t != NULL)
gotweb_free_transport(c->t);
+ if (c->resp_event) {
+ event_del(c->resp_event);
+ free(c->resp_event);
+ }
+ free(c->buf);
+ free(c->outbuf);
free(c);
}
blob - 1a1a8770b26108d09399eb43a781fa0e4d63c1b9
blob + 91799176b5f93d034ae4014bd3a97128c31aeee4
--- gotwebd/gotweb.c
+++ gotwebd/gotweb.c
@@ -33,6 +33,7 @@
#include <imsg.h>
#include <sha1.h>
#include <sha2.h>
+#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -142,11 +143,124 @@ gotweb_reply_file(struct request *c, const char *ctype
return gotweb_reply(c, 200, ctype, NULL);
}
+static void
+free_request(struct request *c)
+{
+ if (c->fd != -1)
+ close(c->fd);
+ if (c->tp != NULL)
+ template_free(c->tp);
+ if (c->t != NULL)
+ gotweb_free_transport(c->t);
+ free(c->buf);
+ free(c->outbuf);
+ free(c);
+}
+
+static struct socket *
+gotweb_get_socket(int sock_id)
+{
+ struct socket *sock;
+
+ TAILQ_FOREACH(sock, &gotwebd_env->sockets, entry) {
+ if (sock->conf.id == sock_id)
+ return sock;
+ }
+
+ return NULL;
+}
+
+static struct request *
+recv_request(struct imsg *imsg)
+{
+ const struct got_error *error;
+ struct request *c;
+ struct server *srv;
+ size_t datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
+ int fd = -1;
+ uint8_t *outbuf = NULL;
+
+ if (datalen != sizeof(*c)) {
+ log_warnx("bad request size received over imsg");
+ return NULL;
+ }
+
+ fd = imsg_get_fd(imsg);
+ if (fd == -1) {
+ log_warnx("no client file descriptor");
+ return NULL;
+ }
+
+ c = calloc(1, sizeof(*c));
+ if (c == NULL) {
+ log_warn("calloc");
+ return NULL;
+ }
+
+ outbuf = calloc(1, GOTWEBD_CACHESIZE);
+ if (outbuf == NULL) {
+ log_warn("calloc");
+ free(c);
+ return NULL;
+ }
+
+ memcpy(c, imsg->data, sizeof(*c));
+
+ /* Non-NULL pointers, if any, are not from our address space. */
+ c->sock = NULL;
+ c->srv = NULL;
+ c->t = NULL;
+ c->tp = NULL;
+ c->buf = NULL;
+ c->outbuf = outbuf;
+
+ memset(&c->ev, 0, sizeof(c->ev));
+ memset(&c->tmo, 0, sizeof(c->tmo));
+
+ /* Use our own temporary file descriptors. */
+ memcpy(c->priv_fd, gotwebd_env->priv_fd, sizeof(c->priv_fd));
+
+ c->fd = fd;
+
+ c->tp = template(c, fcgi_write, c->outbuf, GOTWEBD_CACHESIZE);
+ if (c->tp == NULL) {
+ log_warn("gotweb init template");
+ free_request(c);
+ return NULL;
+ }
+
+ c->sock = gotweb_get_socket(c->sock_id);
+ if (c->sock == NULL) {
+ log_warn("socket id '%d' not found", c->sock_id);
+ free_request(c);
+ return NULL;
+ }
+
+ /* init the transport */
+ error = gotweb_init_transport(&c->t);
+ if (error) {
+ log_warnx("gotweb init transport: %s", error->msg);
+ free_request(c);
+ return NULL;
+ }
+
+ /* get the gotwebd server */
+ srv = gotweb_get_server(c->server_name);
+ if (srv == NULL) {
+ log_warnx("server '%s' not found", c->server_name);
+ free_request(c);
+ return NULL;
+ }
+ c->srv = srv;
+
+ return c;
+}
+
void
gotweb_process_request(struct request *c)
{
const struct got_error *error = NULL;
- struct server *srv = NULL;
+ struct server *srv = c->srv;;
struct querystring *qs = NULL;
struct repo_dir *repo_dir = NULL;
struct repo_commit *commit;
@@ -155,19 +269,6 @@ gotweb_process_request(struct request *c)
size_t len;
int r, binary = 0;
- /* init the transport */
- error = gotweb_init_transport(&c->t);
- if (error) {
- log_warnx("%s: %s", __func__, error->msg);
- return;
- }
- /* get the gotwebd server */
- srv = gotweb_get_server(c->server_name);
- if (srv == NULL) {
- log_warnx("%s: error server is NULL", __func__);
- goto err;
- }
- c->srv = srv;
/* parse our querystring */
error = gotweb_init_querystring(&qs);
if (error) {
@@ -1297,3 +1398,272 @@ gotweb_render_age(struct template *tp, time_t committe
}
return 0;
}
+
+static void
+gotweb_shutdown(void)
+{
+ imsgbuf_clear(&gotwebd_env->iev_parent->ibuf);
+ free(gotwebd_env->iev_parent);
+ free(gotwebd_env);
+
+ exit(0);
+}
+
+static void
+gotweb_sighdlr(int sig, short event, void *arg)
+{
+ switch (sig) {
+ case SIGHUP:
+ log_info("%s: ignoring SIGHUP", __func__);
+ break;
+ case SIGPIPE:
+ log_info("%s: ignoring SIGPIPE", __func__);
+ break;
+ case SIGUSR1:
+ log_info("%s: ignoring SIGUSR1", __func__);
+ break;
+ case SIGCHLD:
+ break;
+ case SIGINT:
+ case SIGTERM:
+ gotweb_shutdown();
+ break;
+ default:
+ log_warn("unhandled signal %d", sig);
+ }
+}
+
+static void
+gotweb_launch(struct gotwebd *env)
+{
+ struct server *srv;
+ const struct got_error *error;
+
+ if (env->iev_server == NULL)
+ fatal("server process not connected");
+
+#ifndef PROFILE
+ if (pledge("stdio rpath recvfd sendfd proc exec unveil", NULL) == -1)
+ fatal("pledge");
+#endif
+
+ TAILQ_FOREACH(srv, &gotwebd_env->servers, entry) {
+ if (unveil(srv->repos_path, "r") == -1)
+ fatal("unveil %s", srv->repos_path);
+ }
+
+ error = got_privsep_unveil_exec_helpers();
+ if (error)
+ fatalx("%s", error->msg);
+
+ if (unveil(NULL, NULL) == -1)
+ fatal("unveil");
+
+ event_add(&env->iev_server->ev, NULL);
+}
+
+static void
+send_request_done(struct imsgev *iev, int request_id)
+{
+ struct gotwebd *env = gotwebd_env;
+
+ if (imsg_compose_event(env->iev_server, GOTWEBD_IMSG_REQ_DONE,
+ GOTWEBD_PROC_GOTWEB, getpid(), -1,
+ &request_id, sizeof(request_id)) == -1)
+ log_warn("imsg_compose_event");
+}
+
+static void
+gotweb_dispatch_server(int fd, short event, void *arg)
+{
+ struct imsgev *iev = arg;
+ struct imsgbuf *ibuf;
+ struct imsg imsg;
+ struct request *c;
+ ssize_t n;
+ int shut = 0;
+
+ ibuf = &iev->ibuf;
+
+ if (event & EV_READ) {
+ if ((n = imsgbuf_read(ibuf)) == -1)
+ fatal("imsgbuf_read error");
+ if (n == 0) /* Connection closed */
+ shut = 1;
+ }
+ if (event & EV_WRITE) {
+ if (imsgbuf_write(ibuf) == -1)
+ fatal("imsgbuf_write");
+ }
+
+ for (;;) {
+ if ((n = imsg_get(ibuf, &imsg)) == -1)
+ fatal("imsg_get");
+ if (n == 0) /* No more messages. */
+ break;
+
+ switch (imsg.hdr.type) {
+ case GOTWEBD_IMSG_REQ_PROCESS:
+ c = recv_request(&imsg);
+ if (c) {
+ int request_id = c->request_id;
+ gotweb_process_request(c);
+ template_flush(c->tp);
+ free_request(c);
+ send_request_done(iev, request_id);
+ }
+ break;
+ default:
+ fatalx("%s: unknown imsg type %d", __func__,
+ imsg.hdr.type);
+ }
+
+ imsg_free(&imsg);
+ }
+
+ if (!shut)
+ imsg_event_add(iev);
+ else {
+ /* This pipe is dead. Remove its event handler */
+ event_del(&iev->ev);
+ event_loopexit(NULL);
+ }
+}
+
+static void
+recv_server_pipe(struct gotwebd *env, struct imsg *imsg)
+{
+ struct imsgev *iev;
+ int fd;
+
+ if (env->iev_server != NULL) {
+ log_warn("server pipe already received");
+ return;
+ }
+
+ fd = imsg_get_fd(imsg);
+ if (fd == -1)
+ fatalx("invalid server pipe fd");
+
+ iev = calloc(1, sizeof(*iev));
+ if (iev == NULL)
+ fatal("calloc");
+
+ if (imsgbuf_init(&iev->ibuf, fd) == -1)
+ fatal("imsgbuf_init");
+ imsgbuf_allow_fdpass(&iev->ibuf);
+
+ iev->handler = gotweb_dispatch_server;
+ iev->data = iev;
+ event_set(&iev->ev, fd, EV_READ, gotweb_dispatch_server, iev);
+
+ env->iev_server = iev;
+}
+
+static void
+gotweb_dispatch_main(int fd, short event, void *arg)
+{
+ struct imsgev *iev = arg;
+ struct imsgbuf *ibuf;
+ struct imsg imsg;
+ struct gotwebd *env = gotwebd_env;
+ ssize_t n;
+ int shut = 0;
+
+ ibuf = &iev->ibuf;
+
+ if (event & EV_READ) {
+ if ((n = imsgbuf_read(ibuf)) == -1)
+ fatal("imsgbuf_read error");
+ if (n == 0) /* Connection closed */
+ shut = 1;
+ }
+ if (event & EV_WRITE) {
+ if (imsgbuf_write(ibuf) == -1)
+ fatal("imsgbuf_write");
+ }
+
+ for (;;) {
+ if ((n = imsg_get(ibuf, &imsg)) == -1)
+ fatal("imsg_get");
+ if (n == 0) /* No more messages. */
+ break;
+
+ switch (imsg.hdr.type) {
+ case GOTWEBD_IMSG_CFG_SRV:
+ config_getserver(env, &imsg);
+ break;
+ case GOTWEBD_IMSG_CFG_FD:
+ config_getfd(env, &imsg);
+ break;
+ case GOTWEBD_IMSG_CFG_SOCK:
+ config_getsock(env, &imsg);
+ break;
+ case GOTWEBD_IMSG_CFG_DONE:
+ config_getcfg(env, &imsg);
+ break;
+ case GOTWEBD_IMSG_CTL_PIPE:
+ recv_server_pipe(env, &imsg);
+ break;
+ case GOTWEBD_IMSG_CTL_START:
+ gotweb_launch(env);
+ break;
+ default:
+ fatalx("%s: unknown imsg type %d", __func__,
+ imsg.hdr.type);
+ }
+
+ imsg_free(&imsg);
+ }
+
+ if (!shut)
+ imsg_event_add(iev);
+ else {
+ /* This pipe is dead. Remove its event handler */
+ event_del(&iev->ev);
+ event_loopexit(NULL);
+ }
+}
+
+void
+gotweb(struct gotwebd *env, int fd)
+{
+ struct event sighup, sigint, sigusr1, sigchld, sigterm;
+ struct event_base *evb;
+
+ evb = event_init();
+
+ sockets_rlimit(-1);
+
+ if ((env->iev_parent = malloc(sizeof(*env->iev_parent))) == NULL)
+ fatal("malloc");
+ if (imsgbuf_init(&env->iev_parent->ibuf, fd) == -1)
+ fatal("imsgbuf_init");
+ imsgbuf_allow_fdpass(&env->iev_parent->ibuf);
+ env->iev_parent->handler = gotweb_dispatch_main;
+ env->iev_parent->data = env->iev_parent;
+ event_set(&env->iev_parent->ev, fd, EV_READ, gotweb_dispatch_main,
+ env->iev_parent);
+ event_add(&env->iev_parent->ev, NULL);
+
+ signal(SIGPIPE, SIG_IGN);
+
+ signal_set(&sighup, SIGHUP, gotweb_sighdlr, env);
+ signal_add(&sighup, NULL);
+ signal_set(&sigint, SIGINT, gotweb_sighdlr, env);
+ signal_add(&sigint, NULL);
+ signal_set(&sigusr1, SIGUSR1, gotweb_sighdlr, env);
+ signal_add(&sigusr1, NULL);
+ signal_set(&sigchld, SIGCHLD, gotweb_sighdlr, env);
+ signal_add(&sigchld, NULL);
+ signal_set(&sigterm, SIGTERM, gotweb_sighdlr, env);
+ signal_add(&sigterm, NULL);
+
+#ifndef PROFILE
+ if (pledge("stdio rpath recvfd sendfd proc exec unveil", NULL) == -1)
+ fatal("pledge");
+#endif
+ event_dispatch();
+ event_base_free(evb);
+ gotweb_shutdown();
+}
blob - 8413e78f48a48cfc92e794fff34a97a8765976e7
blob + f6353254aaee1f21a9dd7e56f1aff9a4d95f47af
--- gotwebd/gotwebd.8
+++ gotwebd/gotwebd.8
@@ -85,24 +85,22 @@ can be configured via the
.Xr gotwebd.conf 5
configuration file.
.It
-Git repositories must be created at a suitable location inside the
-web server's
-.Xr chroot 2
-environment.
-These repositories should
+Git repositories must be created.
+These repositories may reside anywhere in the filesystem and must
+be readable, but should
.Em not
-be writable by the user ID shared between
+be writable, by the user
.Nm
-and
-.Xr httpd 8 .
+runs as.
The default location for repositories published by
.Nm
is
.Pa /var/www/got/public .
.It
-Git repositories served by
+If the Git repositories served by
.Nm
-should be kept up-to-date with a mechanism such as
+do not receive changes from committers directly, they need to be kept
+up-to-date with a mechanism such as
.Cm got fetch ,
.Xr git-fetch 1 ,
or
blob - 61a08a5b8aa69b071a02be23f9794bab66c345fc
blob + d738c5a52b29d013687fb03ff5f2e55f4a9a512d
--- gotwebd/gotwebd.c
+++ gotwebd/gotwebd.c
@@ -48,11 +48,12 @@
__dead void usage(void);
int main(int, char **);
-int gotwebd_configure(struct gotwebd *);
+int gotwebd_configure(struct gotwebd *, uid_t, gid_t);
void gotwebd_configure_done(struct gotwebd *);
void gotwebd_sighdlr(int sig, short event, void *arg);
void gotwebd_shutdown(void);
-void gotwebd_dispatch_sockets(int, short, void *);
+void gotwebd_dispatch_server(int, short, void *);
+void gotwebd_dispatch_gotweb(int, short, void *);
struct gotwebd *gotwebd_env;
@@ -75,7 +76,7 @@ imsg_event_add(struct imsgev *iev)
int
imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid,
- pid_t pid, int fd, const void *data, uint16_t datalen)
+ pid_t pid, int fd, const void *data, size_t datalen)
{
int ret;
@@ -86,42 +87,67 @@ imsg_compose_event(struct imsgev *iev, uint16_t type,
return (ret);
}
-int
-main_compose_sockets(struct gotwebd *env, uint32_t type, int fd,
- const void *data, uint16_t len)
+static int
+send_imsg(struct imsgev *iev, uint32_t type, int fd, const void *data,
+ uint16_t len)
{
- size_t i;
- int ret, d;
+ int ret, d = -1;
- for (i = 0; i < env->nserver; ++i) {
+ if (fd != -1 && (d = dup(fd)) == -1)
+ goto err;
+
+ ret = imsg_compose_event(iev, type, 0, -1, d, data, len);
+ if (ret == -1)
+ goto err;
+
+ if (d != -1) {
d = -1;
- if (fd != -1 && (d = dup(fd)) == -1)
+ /* Flush imsg to prevent fd exhaustion. 'd' will be closed. */
+ if (imsgbuf_flush(&iev->ibuf) == -1)
goto err;
-
- ret = imsg_compose_event(&env->iev_server[i], type, 0, -1,
- d, data, len);
- if (ret == -1)
- goto err;
-
- /* prevent fd exhaustion */
- if (d != -1) {
- if (imsgbuf_flush(&env->iev_server[i].ibuf) == -1)
- goto err;
- imsg_event_add(&env->iev_server[i]);
- }
+ imsg_event_add(iev);
}
- if (fd != -1)
- close(fd);
return 0;
-
err:
- if (fd != -1)
- close(fd);
+ if (d != -1)
+ close(d);
return -1;
}
int
+main_compose_sockets(struct gotwebd *env, uint32_t type, int fd,
+ const void *data, uint16_t len)
+{
+ size_t i;
+ int ret = 0;
+
+ for (i = 0; i < env->nserver; ++i) {
+ ret = send_imsg(&env->iev_server[i], type, fd, data, len);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+
+int
+main_compose_gotweb(struct gotwebd *env, uint32_t type, int fd,
+ const void *data, uint16_t len)
+{
+ size_t i;
+ int ret = 0;
+
+ for (i = 0; i < env->nserver; ++i) {
+ ret = send_imsg(&env->iev_gotweb[i], type, fd, data, len);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+
+int
sockets_compose_main(struct gotwebd *env, uint32_t type, const void *d,
uint16_t len)
{
@@ -129,7 +155,7 @@ sockets_compose_main(struct gotwebd *env, uint32_t typ
}
void
-gotwebd_dispatch_sockets(int fd, short event, void *arg)
+gotwebd_dispatch_server(int fd, short event, void *arg)
{
struct imsgev *iev = arg;
struct imsgbuf *ibuf;
@@ -179,6 +205,56 @@ gotwebd_dispatch_sockets(int fd, short event, void *ar
}
void
+gotwebd_dispatch_gotweb(int fd, short event, void *arg)
+{
+ struct imsgev *iev = arg;
+ struct imsgbuf *ibuf;
+ struct imsg imsg;
+ struct gotwebd *env = gotwebd_env;
+ ssize_t n;
+ int shut = 0;
+
+ ibuf = &iev->ibuf;
+
+ if (event & EV_READ) {
+ if ((n = imsgbuf_read(ibuf)) == -1)
+ fatal("imsgbuf_read error");
+ if (n == 0) /* Connection closed */
+ shut = 1;
+ }
+ if (event & EV_WRITE) {
+ if (imsgbuf_write(ibuf) == -1)
+ fatal("imsgbuf_write");
+ }
+
+ for (;;) {
+ if ((n = imsg_get(ibuf, &imsg)) == -1)
+ fatal("imsg_get");
+ if (n == 0) /* No more messages. */
+ break;
+
+ switch (imsg.hdr.type) {
+ case GOTWEBD_IMSG_CFG_DONE:
+ gotwebd_configure_done(env);
+ break;
+ default:
+ fatalx("%s: unknown imsg type %d", __func__,
+ imsg.hdr.type);
+ }
+
+ imsg_free(&imsg);
+ }
+
+ if (!shut)
+ imsg_event_add(iev);
+ else {
+ /* This pipe is dead. Remove its event handler */
+ event_del(&iev->ev);
+ event_loopexit(NULL);
+ }
+}
+
+void
gotwebd_sighdlr(int sig, short event, void *arg)
{
/* struct privsep *ps = arg; */
@@ -203,10 +279,11 @@ gotwebd_sighdlr(int sig, short event, void *arg)
}
}
-static int
-spawn_socket_process(struct gotwebd *env, const char *argv0, int n)
+static void
+spawn_process(struct gotwebd *env, const char *argv0, struct imsgev *iev,
+ enum gotwebd_proc_type proc_type, void (*handler)(int, short, void *))
{
- const char *argv[8];
+ const char *argv[9];
int argc = 0;
int p[2];
pid_t pid;
@@ -221,21 +298,26 @@ spawn_socket_process(struct gotwebd *env, const char *
break;
default: /* parent */
close(p[0]);
- if (imsgbuf_init(&env->iev_server[n].ibuf, p[1]) == -1)
+ if (imsgbuf_init(&iev->ibuf, p[1]) == -1)
fatal("imsgbuf_init");
- imsgbuf_allow_fdpass(&env->iev_server[n].ibuf);
- env->iev_server[n].handler = gotwebd_dispatch_sockets;
- env->iev_server[n].data = &env->iev_server[n];
- event_set(&env->iev_server[n].ev, p[1], EV_READ,
- gotwebd_dispatch_sockets, &env->iev_server[n]);
- event_add(&env->iev_server[n].ev, NULL);
- return 0;
+ imsgbuf_allow_fdpass(&iev->ibuf);
+ iev->handler = handler;
+ iev->data = iev;
+ event_set(&iev->ev, p[1], EV_READ, handler, iev);
+ event_add(&iev->ev, NULL);
+ return;
}
close(p[1]);
argv[argc++] = argv0;
- argv[argc++] = "-S";
+ if (proc_type == GOTWEBD_PROC_SERVER) {
+ argv[argc++] = "-S";
+ argv[argc++] = env->user;
+ } else if (proc_type == GOTWEBD_PROC_GOTWEB) {
+ argv[argc++] = "-G";
+ argv[argc++] = env->user;
+ }
if (strcmp(env->gotwebd_conffile, GOTWEBD_CONF) != 0) {
argv[argc++] = "-f";
argv[argc++] = env->gotwebd_conffile;
@@ -273,12 +355,12 @@ main(int argc, char **argv)
struct event sigint, sigterm, sighup, sigpipe, sigusr1;
struct event_base *evb;
struct gotwebd *env;
- struct passwd *pw;
+ struct passwd *pw_gotwebd;
int ch, i;
int no_action = 0;
- int server_proc = 0;
+ int proc_type = GOTWEBD_PROC_PARENT;
const char *conffile = GOTWEBD_CONF;
- const char *username = GOTWEBD_DEFAULT_USER;
+ const char *gotwebd_username = GOTWEBD_DEFAULT_USER;
const char *argv0;
if ((argv0 = argv[0]) == NULL)
@@ -292,7 +374,7 @@ main(int argc, char **argv)
fatal("%s: calloc", __func__);
config_init(env);
- while ((ch = getopt(argc, argv, "D:df:nSv")) != -1) {
+ while ((ch = getopt(argc, argv, "D:dG:f:nS:vW:")) != -1) {
switch (ch) {
case 'D':
if (cmdline_symset(optarg) < 0)
@@ -302,6 +384,10 @@ main(int argc, char **argv)
case 'd':
env->gotwebd_debug = 1;
break;
+ case 'G':
+ proc_type = GOTWEBD_PROC_GOTWEB;
+ gotwebd_username = optarg;
+ break;
case 'f':
conffile = optarg;
break;
@@ -309,7 +395,8 @@ main(int argc, char **argv)
no_action = 1;
break;
case 'S':
- server_proc = 1;
+ proc_type = GOTWEBD_PROC_SERVER;
+ gotwebd_username = optarg;
break;
case 'v':
if (env->gotwebd_verbose < 3)
@@ -327,29 +414,32 @@ main(int argc, char **argv)
gotwebd_env = env;
env->gotwebd_conffile = conffile;
- if (parse_config(env->gotwebd_conffile, env) == -1)
- exit(1);
+ if (proc_type == GOTWEBD_PROC_PARENT) {
+ if (parse_config(env->gotwebd_conffile, env) == -1)
+ exit(1);
- if (no_action) {
- fprintf(stderr, "configuration OK\n");
- exit(0);
+ if (no_action) {
+ fprintf(stderr, "configuration OK\n");
+ exit(0);
+ }
+
+ if (env->user)
+ gotwebd_username = env->user;
}
+ pw_gotwebd = getpwnam(gotwebd_username);
+ if (pw_gotwebd == NULL)
+ fatalx("unknown user %s", gotwebd_username);
+
/* check for root privileges */
if (geteuid())
fatalx("need root privileges");
- if (env->user)
- username = env->user;
- pw = getpwnam(username);
- if (pw == NULL)
- fatalx("unknown user %s", username);
- env->pw = pw;
-
log_init(env->gotwebd_debug, LOG_DAEMON);
log_setverbose(env->gotwebd_verbose);
- if (server_proc) {
+ switch (proc_type) {
+ case GOTWEBD_PROC_SERVER:
setproctitle("server");
log_procinit("server");
@@ -357,13 +447,31 @@ main(int argc, char **argv)
fatal("chroot %s", env->httpd_chroot);
if (chdir("/") == -1)
fatal("chdir /");
- if (setgroups(1, &pw->pw_gid) == -1 ||
- setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1 ||
- setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1)
+
+ if (setgroups(1, &pw_gotwebd->pw_gid) == -1 ||
+ setresgid(pw_gotwebd->pw_gid, pw_gotwebd->pw_gid,
+ pw_gotwebd->pw_gid) == -1 ||
+ setresuid(pw_gotwebd->pw_uid, pw_gotwebd->pw_uid,
+ pw_gotwebd->pw_uid) == -1)
fatal("failed to drop privileges");
sockets(env, GOTWEBD_SOCK_FILENO);
return 1;
+ case GOTWEBD_PROC_GOTWEB:
+ setproctitle("gotweb");
+ log_procinit("gotweb");
+
+ if (setgroups(1, &pw_gotwebd->pw_gid) == -1 ||
+ setresgid(pw_gotwebd->pw_gid, pw_gotwebd->pw_gid,
+ pw_gotwebd->pw_gid) == -1 ||
+ setresuid(pw_gotwebd->pw_uid, pw_gotwebd->pw_uid,
+ pw_gotwebd->pw_uid) == -1)
+ fatal("failed to drop privileges");
+
+ gotweb(env, GOTWEBD_SOCK_FILENO);
+ return 1;
+ default:
+ break;
}
if (!env->gotwebd_debug && daemon(1, 0) == -1)
@@ -375,12 +483,16 @@ main(int argc, char **argv)
env->iev_server = calloc(env->nserver, sizeof(*env->iev_server));
if (env->iev_server == NULL)
fatal("calloc");
+ env->iev_gotweb = calloc(env->nserver, sizeof(*env->iev_gotweb));
+ if (env->iev_gotweb == NULL)
+ fatal("calloc");
for (i = 0; i < env->nserver; ++i) {
- if (spawn_socket_process(env, argv0, i) == -1)
- fatal("spawn_socket_process");
+ spawn_process(env, argv0, &env->iev_server[i],
+ GOTWEBD_PROC_SERVER, gotwebd_dispatch_server);
+ spawn_process(env, argv0, &env->iev_gotweb[i],
+ GOTWEBD_PROC_GOTWEB, gotwebd_dispatch_gotweb);
}
-
if (chdir("/") == -1)
fatal("chdir /");
@@ -400,12 +512,15 @@ main(int argc, char **argv)
signal_add(&sigpipe, NULL);
signal_add(&sigusr1, NULL);
- if (gotwebd_configure(env) == -1)
+ if (gotwebd_configure(env,
+ pw_gotwebd->pw_uid, pw_gotwebd->pw_gid) == -1)
fatalx("configuration failed");
- if (setgroups(1, &pw->pw_gid) == -1 ||
- setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1 ||
- setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1)
+ if (setgroups(1, &pw_gotwebd->pw_gid) == -1 ||
+ setresgid(pw_gotwebd->pw_gid, pw_gotwebd->pw_gid,
+ pw_gotwebd->pw_gid) == -1 ||
+ setresuid(pw_gotwebd->pw_uid, pw_gotwebd->pw_uid,
+ pw_gotwebd->pw_uid) == -1)
fatal("failed to drop privileges");
#ifdef PROFILE
@@ -432,24 +547,54 @@ main(int argc, char **argv)
return (0);
}
+static void
+connect_children(struct gotwebd *env)
+{
+ struct imsgev *iev1, *iev2;
+ int pipe[2];
+ int i;
+
+ for (i = 0; i < env->nserver; i++) {
+ iev1 = &env->iev_server[i];
+ iev2 = &env->iev_gotweb[i];
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe) == -1)
+ fatal("socketpair");
+
+ if (send_imsg(iev1, GOTWEBD_IMSG_CTL_PIPE, pipe[0], NULL, 0))
+ fatal("send_imsg");
+
+ if (send_imsg(iev2, GOTWEBD_IMSG_CTL_PIPE, pipe[1], NULL, 0))
+ fatal("send_imsg");
+
+ close(pipe[0]);
+ close(pipe[1]);
+ }
+}
+
int
-gotwebd_configure(struct gotwebd *env)
+gotwebd_configure(struct gotwebd *env, uid_t uid, gid_t gid)
{
struct server *srv;
struct socket *sock;
/* gotweb need to reload its config. */
- env->gotwebd_reload = env->prefork_gotwebd;
+ env->servers_pending = env->prefork_gotwebd;
+ env->gotweb_pending = env->prefork_gotwebd;
/* send our gotweb servers */
TAILQ_FOREACH(srv, &env->servers, entry) {
- if (config_setserver(env, srv) == -1)
- fatalx("%s: send server error", __func__);
+ if (main_compose_sockets(env, GOTWEBD_IMSG_CFG_SRV,
+ -1, srv, sizeof(*srv)) == -1)
+ fatal("main_compose_sockets GOTWEBD_IMSG_CFG_SRV");
+ if (main_compose_gotweb(env, GOTWEBD_IMSG_CFG_SRV,
+ -1, srv, sizeof(*srv)) == -1)
+ fatal("main_compose_gotweb GOTWEBD_IMSG_CFG_SRV");
}
/* send our sockets */
TAILQ_FOREACH(sock, &env->sockets, entry) {
- if (config_setsock(env, sock) == -1)
+ if (config_setsock(env, sock, uid, gid) == -1)
fatalx("%s: send socket error", __func__);
}
@@ -457,6 +602,9 @@ gotwebd_configure(struct gotwebd *env)
if (config_setfd(env) == -1)
fatalx("%s: send priv_fd error", __func__);
+ /* Connect servers and gotwebs. */
+ connect_children(env);
+
if (main_compose_sockets(env, GOTWEBD_IMSG_CFG_DONE, -1, NULL, 0) == -1)
fatal("main_compose_sockets GOTWEBD_IMSG_CFG_DONE");
@@ -466,15 +614,21 @@ gotwebd_configure(struct gotwebd *env)
void
gotwebd_configure_done(struct gotwebd *env)
{
- if (env->gotwebd_reload == 0) {
- log_warnx("%s: configuration already finished", __func__);
- return;
+ if (env->servers_pending > 0) {
+ env->servers_pending--;
+ if (env->servers_pending == 0 &&
+ main_compose_sockets(env, GOTWEBD_IMSG_CTL_START,
+ -1, NULL, 0) == -1)
+ fatal("main_compose_sockets GOTWEBD_IMSG_CTL_START");
}
- env->gotwebd_reload--;
- if (env->gotwebd_reload == 0 &&
- main_compose_sockets(env, GOTWEBD_CTL_START, -1, NULL, 0) == -1)
- fatal("main_compose_sockets GOTWEBD_CTL_START");
+ if (env->gotweb_pending > 0) {
+ env->gotweb_pending--;
+ if (env->gotweb_pending == 0 &&
+ main_compose_gotweb(env, GOTWEBD_IMSG_CTL_START,
+ -1, NULL, 0) == -1)
+ fatal("main_compose_sockets GOTWEBD_IMSG_CTL_START");
+ }
}
void
@@ -492,6 +646,14 @@ gotwebd_shutdown(void)
}
free(env->iev_server);
+ for (i = 0; i < env->nserver; ++i) {
+ event_del(&env->iev_gotweb[i].ev);
+ imsgbuf_clear(&env->iev_gotweb[i].ibuf);
+ close(env->iev_gotweb[i].ibuf.fd);
+ env->iev_gotweb[i].ibuf.fd = -1;
+ }
+ free(env->iev_gotweb);
+
do {
pid = waitpid(WAIT_ANY, &status, 0);
if (pid <= 0)
blob - 2bbc2da98a42f54eda543a5d44e452364ab5402f
blob + df671fde047c618123e126aabe674ba02a5bccae
--- gotwebd/gotwebd.conf.5
+++ gotwebd/gotwebd.conf.5
@@ -44,15 +44,6 @@ For example:
lan_addr = "192.168.0.1"
listen on $lan_addr port 9090
.Ed
-.Pp
-Paths mentioned in
-.Nm
-must be relative to
-.Pa /var/www ,
-the
-.Xr chroot 2
-environment of
-.Xr httpd 8 .
.Sh GLOBAL CONFIGURATION
The available global configuration directives are as follows:
.Bl -tag -width Ds
@@ -64,6 +55,11 @@ environment of
If not specified, it defaults to
.Pa /var/www ,
the home directory of the www user.
+Setting the
+.Ar path
+to
+.Pa /
+effectively disables chroot.
.It Ic listen on Ar address Ic port Ar number
Configure an address and port for incoming FastCGI connections.
Valid
@@ -79,6 +75,11 @@ Configure a
.Ux Ns -domain
socket for incoming FastCGI connections.
May be specified multiple times to build up a list of listening sockets.
+.Pp
+While the specified
+.Ar path
+must be absolute, it should usually point inside the web server's chroot
+directory such that the web server can access the socket.
.It Ic prefork Ar number
Run the specified number of server processes.
.Xr gotwebd 8
@@ -88,7 +89,7 @@ Set the
.Ar user
which will run
.Xr gotwebd 8 .
-If not specified, the user www will be used.
+If not specified, the user _gotwebd will be used.
.El
.Pp
If no
@@ -123,10 +124,16 @@ Set the path to a custom Cascading Style Sheet (CSS) t
If this option is not specified then the default style sheet
.Sq gotweb.css
will be used.
+.Pp
+This path must be valid in the web server's URL space since browsers
+will attempt to fetch it.
.It Ic logo Ar path
Set the path to an image file containing a logo to be displayed.
Defaults to
.Sq got.png .
+.Pp
+This path must be valid in the web server's URL space since browsers
+will attempt to fetch it.
.It Ic logo_url Ar url
Set a hyperlink for the logo.
Defaults to
@@ -141,9 +148,17 @@ Set to zero to show all the repositories without pagin
.It Ic repos_path Ar path
Set the path to the directory which contains Git repositories that
the server should publish.
+This path is absolute.
+Repositories can be served even if they reside outside the web server's
+chroot directory.
+.Pp
Defaults to
.Pa /got/public
-under the chroot.
+inside the web server's chroot directory.
+The
+.Cm chroot
+directive must be used before the server declaration in order to
+take effect.
.It Ic respect_exportok Ar on | off
Set whether to display the repository only if it contains the magic
.Pa git-daemon-export-ok
@@ -231,13 +246,14 @@ server "localhost" {
Another example, this time listening on a local port instead of the
implicit
.Ux
-socket.
+socket, and serving repositories located outside the web server's chroot:
.Bd -literal -offset indent
listen on 127.0.0.1 port 9000
listen on ::1 port 9000
server "localhost" {
- site_name "my public repos"
+ site_name "my public repos"
+ repos_path "/var/git"
}
.Ed
.Sh SEE ALSO
blob - 7dd491f1a07f53e526bf9e5df13d9e0767649384
blob + 0610e995e02d69a510d070b3f7e4907b00c068e7
--- gotwebd/gotwebd.h
+++ gotwebd/gotwebd.h
@@ -32,7 +32,7 @@
#define GOTWEBD_CONF "/etc/gotwebd.conf"
#ifndef GOTWEBD_DEFAULT_USER
-#define GOTWEBD_DEFAULT_USER "www"
+#define GOTWEBD_DEFAULT_USER "_gotwebd"
#endif
#define GOTWEBD_MAXDESCRSZ 1024
@@ -117,12 +117,21 @@ struct got_blob_object;
struct got_tree_entry;
struct got_reflist_head;
+enum gotwebd_proc_type {
+ GOTWEBD_PROC_PARENT,
+ GOTWEBD_PROC_SERVER,
+ GOTWEBD_PROC_GOTWEB,
+};
+
enum imsg_type {
GOTWEBD_IMSG_CFG_SRV,
GOTWEBD_IMSG_CFG_SOCK,
GOTWEBD_IMSG_CFG_FD,
GOTWEBD_IMSG_CFG_DONE,
- GOTWEBD_CTL_START,
+ GOTWEBD_IMSG_CTL_PIPE,
+ GOTWEBD_IMSG_CTL_START,
+ GOTWEBD_IMSG_REQ_PROCESS,
+ GOTWEBD_IMSG_REQ_DONE,
};
struct imsgev {
@@ -229,6 +238,7 @@ enum socket_priv_fds {
struct template;
struct request {
+ TAILQ_ENTRY(request) entry;
struct socket *sock;
struct server *srv;
struct transport *t;
@@ -239,12 +249,16 @@ struct request {
uint16_t id;
int fd;
int priv_fd[PRIV_FDS__MAX];
+ int resp_fd;
+ struct event *resp_event;
+ int sock_id;
+ uint32_t request_id;
- uint8_t buf[FCGI_RECORD_SIZE];
+ uint8_t *buf;
size_t buf_pos;
size_t buf_len;
- uint8_t outbuf[GOTWEBD_CACHESIZE];
+ uint8_t *outbuf;
char querystring[MAX_QUERYSTRING];
char document_uri[MAX_DOCUMENT_URI];
@@ -253,6 +267,7 @@ struct request {
uint8_t request_started;
};
+TAILQ_HEAD(requestlist, request);
struct fcgi_begin_request_body {
uint16_t role;
@@ -349,12 +364,12 @@ struct gotwebd {
struct imsgev *iev_parent;
struct imsgev *iev_server;
+ struct imsgev *iev_gotweb;
size_t nserver;
- struct passwd *pw;
-
uint16_t prefork_gotwebd;
- int gotwebd_reload;
+ int servers_pending;
+ int gotweb_pending;
int server_cnt;
@@ -430,18 +445,22 @@ typedef int (*got_render_blame_line_cb)(struct templat
/* gotwebd.c */
void imsg_event_add(struct imsgev *);
int imsg_compose_event(struct imsgev *, uint16_t, uint32_t,
- pid_t, int, const void *, uint16_t);
+ pid_t, int, const void *, size_t);
int main_compose_sockets(struct gotwebd *, uint32_t, int,
const void *, uint16_t);
int sockets_compose_main(struct gotwebd *, uint32_t,
const void *, uint16_t);
+int main_compose_gotweb(struct gotwebd *, uint32_t, int,
+ const void *, uint16_t);
/* sockets.c */
void sockets(struct gotwebd *, int);
void sockets_parse_sockets(struct gotwebd *);
void sockets_socket_accept(int, short, void *);
-int sockets_privinit(struct gotwebd *, struct socket *);
+int sockets_privinit(struct gotwebd *, struct socket *, uid_t, gid_t);
void sockets_purge(struct gotwebd *);
+void sockets_rlimit(int);
+void sockets_del_request(struct request *);
/* gotweb.c */
void gotweb_index_navs(struct request *, struct gotweb_url *, int *,
@@ -455,6 +474,7 @@ void gotweb_free_repo_commit(struct repo_commit *);
void gotweb_free_repo_tag(struct repo_tag *);
void gotweb_process_request(struct request *);
void gotweb_free_transport(struct transport *);
+void gotweb(struct gotwebd *, int);
/* pages.tmpl */
int gotweb_render_page(struct template *, int (*)(struct template *));
@@ -507,7 +527,7 @@ const struct got_error *got_output_file_blame(struct r
/* config.c */
int config_setserver(struct gotwebd *, struct server *);
int config_getserver(struct gotwebd *, struct imsg *);
-int config_setsock(struct gotwebd *, struct socket *);
+int config_setsock(struct gotwebd *, struct socket *, uid_t, gid_t);
int config_getsock(struct gotwebd *, struct imsg *);
int config_setfd(struct gotwebd *);
int config_getfd(struct gotwebd *, struct imsg *);
blob - 5fd34708bd3654bc05060446ff5d55557747cfd3 (mode 644)
blob + /dev/null
--- gotwebd/libexec/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-SUBDIR = got-read-blob got-read-commit got-read-object got-read-tree \
- got-read-tag got-read-pack got-read-gitconfig got-read-gotconfig
-
-.include <bsd.subdir.mk>
blob - 85bee26728643214f5d4570f003572ac1fc36d05 (mode 644)
blob + /dev/null
--- gotwebd/libexec/Makefile.inc
+++ /dev/null
@@ -1,11 +0,0 @@
-.include "../Makefile.inc"
-
-realinstall:
- if [ ! -d ${DESTDIR}${CHROOT_DIR}${LIBEXECDIR}/. ]; then \
- ${INSTALL} -d -o root -g daemon -m 755 \
- ${DESTDIR}${CHROOT_DIR}${LIBEXECDIR}; \
- fi
- ${INSTALL} ${INSTALL_COPY} -o root -g daemon -m 755 ${PROG} \
- ${DESTDIR}${CHROOT_DIR}${LIBEXECDIR}/${PROG}
-
-NOMAN = Yes
blob - 9daacd33712bbd6a9ded56d7a03ed143ce6642d3 (mode 644)
blob + /dev/null
--- gotwebd/libexec/got-read-blob/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-.include "../../../got-version.mk"
-.include "../Makefile.inc"
-
-PROG= got-read-blob
-SRCS= got-read-blob.c error.c inflate.c object_parse.c \
- path.c privsep.c hash.c pollfd.c object_qid.c
-
-CPPFLAGS = -I${.CURDIR}/../../../include -I${.CURDIR}/../../../lib
-LDADD = -lutil -lz
-DPADD = ${LIBZ} ${LIBUTIL}
-LDSTATIC = ${STATIC}
-
-.PATH: ${.CURDIR}/../../../lib ${.CURDIR}/../../../libexec/got-read-blob
-
-.include <bsd.prog.mk>
blob - f45137c3ce56dbaadeaf0a5f0ffffd3b4204668c (mode 644)
blob + /dev/null
--- gotwebd/libexec/got-read-commit/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-.include "../../../got-version.mk"
-.include "../Makefile.inc"
-
-PROG= got-read-commit
-SRCS= got-read-commit.c error.c inflate.c object_parse.c \
- path.c privsep.c hash.c pollfd.c object_qid.c
-
-CPPFLAGS = -I${.CURDIR}/../../../include -I${.CURDIR}/../../../lib
-LDADD = -lutil -lz
-DPADD = ${LIBZ} ${LIBUTIL}
-LDSTATIC = ${STATIC}
-
-.PATH: ${.CURDIR}/../../../lib ${.CURDIR}/../../../libexec/got-read-commit
-
-.include <bsd.prog.mk>
blob - 44760613f030f1f1f62c831825d7bb85b07c9a46 (mode 644)
blob + /dev/null
--- gotwebd/libexec/got-read-gitconfig/Makefile
+++ /dev/null
@@ -1,16 +0,0 @@
-.include "../../../got-version.mk"
-.include "../Makefile.inc"
-
-PROG= got-read-gitconfig
-SRCS= got-read-gitconfig.c error.c inflate.c object_parse.c \
- path.c privsep.c hash.c gitconfig.c pollfd.c \
- object_qid.c
-
-CPPFLAGS = -I${.CURDIR}/../../../include -I${.CURDIR}/../../../lib
-LDADD = -lutil -lz
-DPADD = ${LIBZ} ${LIBUTIL}
-LDSTATIC = ${STATIC}
-
-.PATH: ${.CURDIR}/../../../lib ${.CURDIR}/../../../libexec/got-read-gitconfig
-
-.include <bsd.prog.mk>
blob - 26dec69ed1be0648baa16cabea96c54dc3731c54 (mode 644)
blob + /dev/null
--- gotwebd/libexec/got-read-gotconfig/Makefile
+++ /dev/null
@@ -1,19 +0,0 @@
-.include "../../../got-version.mk"
-.include "../Makefile.inc"
-
-PROG= got-read-gotconfig
-SRCS= got-read-gotconfig.c error.c inflate.c object_parse.c \
- path.c privsep.c hash.c parse.y pollfd.c object_qid.c
-
-CPPFLAGS = -I${.CURDIR}/../../../include -I${.CURDIR}/../../../lib \
- -I${.CURDIR}/../../../libexec/got-read-gotconfig
-YFLAGS =
-LDADD = -lutil -lz
-DPADD = ${LIBZ} ${LIBUTIL}
-LDSTATIC = ${STATIC}
-
-CLEANFILES = parse.h
-
-.PATH: ${.CURDIR}/../../../lib ${.CURDIR}/../../../libexec/got-read-gotconfig
-
-.include <bsd.prog.mk>
blob - 85841212056443f99c873f1089e3fef315ab7d2a (mode 644)
blob + /dev/null
--- gotwebd/libexec/got-read-object/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-.include "../../../got-version.mk"
-.include "../Makefile.inc"
-
-PROG= got-read-object
-SRCS= got-read-object.c error.c inflate.c object_parse.c \
- path.c privsep.c hash.c pollfd.c object_qid.c
-
-CPPFLAGS = -I${.CURDIR}/../../../include -I${.CURDIR}/../../../lib
-LDADD = -lutil -lz
-DPADD = ${LIBZ} ${LIBUTIL}
-LDSTATIC = ${STATIC}
-
-.PATH: ${.CURDIR}/../../../lib ${.CURDIR}/../../../libexec/got-read-object
-
-.include <bsd.prog.mk>
blob - 6ae7cd0c813fcc65f4256be6d06040df2d2880ba (mode 644)
blob + /dev/null
--- gotwebd/libexec/got-read-pack/Makefile
+++ /dev/null
@@ -1,16 +0,0 @@
-.include "../../../got-version.mk"
-.include "../Makefile.inc"
-
-PROG= got-read-pack
-SRCS= got-read-pack.c delta.c error.c inflate.c object_cache.c \
- object_idset.c object_parse.c opentemp.c pack.c path.c \
- privsep.c hash.c delta_cache.c pollfd.c object_qid.c
-
-CPPFLAGS = -I${.CURDIR}/../../../include -I${.CURDIR}/../../../lib
-LDADD = -lutil -lz
-DPADD = ${LIBZ} ${LIBUTIL}
-LDSTATIC = ${STATIC}
-
-.PATH: ${.CURDIR}/../../../lib ${.CURDIR}/../../../libexec/got-read-pack
-
-.include <bsd.prog.mk>
blob - eb7b682a069470aa6b445adfc142e1d7bdf7c4a4 (mode 644)
blob + /dev/null
--- gotwebd/libexec/got-read-tag/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-.include "../../../got-version.mk"
-.include "../Makefile.inc"
-
-PROG= got-read-tag
-SRCS= got-read-tag.c error.c inflate.c object_parse.c \
- path.c privsep.c hash.c pollfd.c object_qid.c
-
-CPPFLAGS = -I${.CURDIR}/../../../include -I${.CURDIR}/../../../lib
-LDADD = -lutil -lz
-DPADD = ${LIBZ} ${LIBUTIL}
-LDSTATIC = ${STATIC}
-
-.PATH: ${.CURDIR}/../../../lib ${.CURDIR}/../../../libexec/got-read-tag
-
-.include <bsd.prog.mk>
blob - 497d2ff1cd06d53bcc607653bb658219cd8ea982 (mode 644)
blob + /dev/null
--- gotwebd/libexec/got-read-tree/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-.include "../../../got-version.mk"
-.include "../Makefile.inc"
-
-PROG= got-read-tree
-SRCS= got-read-tree.c error.c inflate.c object_parse.c \
- path.c privsep.c hash.c pollfd.c object_qid.c
-
-CPPFLAGS = -I${.CURDIR}/../../../include -I${.CURDIR}/../../../lib
-LDADD = -lutil -lz
-DPADD = ${LIBZ} ${LIBUTIL}
-LDSTATIC = ${STATIC}
-
-.PATH: ${.CURDIR}/../../../lib ${.CURDIR}/../../../libexec/got-read-tree
-
-.include <bsd.prog.mk>
blob - ce616554e436816c2be0cd52555746f30ab943f9
blob + 5fc49003ef44e659fe3e1b31dc57eb30e8c6fe69
--- gotwebd/parse.y
+++ gotwebd/parse.y
@@ -197,10 +197,16 @@ main : PREFORK NUMBER {
n = strlcpy(gotwebd->httpd_chroot, $2,
sizeof(gotwebd->httpd_chroot));
if (n >= sizeof(gotwebd->httpd_chroot)) {
- yyerror("%s: httpd_chroot truncated", __func__);
+ yyerror("chroot path too long: %s", $2);
free($2);
YYERROR;
}
+ if (gotwebd->httpd_chroot[0] != '/') {
+ yyerror("chroot path must be an absolute path: "
+ "bad path %s", gotwebd->httpd_chroot);
+ free($2);
+ YYERROR;
+ }
free($2);
}
| LISTEN ON listen_addr PORT STRING {
@@ -832,7 +838,18 @@ parse_config(const char *filename, struct gotwebd *env
/* add the implicit listen on socket */
if (TAILQ_EMPTY(&gotwebd->addresses)) {
- const char *path = D_HTTPD_CHROOT D_UNIX_SOCKET;
+ char path[_POSIX_PATH_MAX];
+
+ if (strlcpy(path, gotwebd->httpd_chroot, sizeof(path))
+ >= sizeof(path)) {
+ yyerror("chroot path too long: %s",
+ gotwebd->httpd_chroot);
+ }
+ if (strlcat(path, D_UNIX_SOCKET, sizeof(path))
+ >= sizeof(path)) {
+ yyerror("chroot path too long: %s",
+ gotwebd->httpd_chroot);
+ }
if (get_unix_addr(path) == -1)
yyerror("can't listen on %s", path);
}
@@ -858,10 +875,14 @@ conf_new_server(const char *name)
n = strlcpy(srv->name, name, sizeof(srv->name));
if (n >= sizeof(srv->name))
fatalx("%s: strlcpy", __func__);
- n = strlcpy(srv->repos_path, D_GOTPATH,
+ n = strlcpy(srv->repos_path, gotwebd->httpd_chroot,
sizeof(srv->repos_path));
if (n >= sizeof(srv->repos_path))
fatalx("%s: strlcpy", __func__);
+ n = strlcat(srv->repos_path, D_GOTPATH,
+ sizeof(srv->repos_path));
+ if (n >= sizeof(srv->repos_path))
+ fatalx("%s: strlcat", __func__);
n = strlcpy(srv->site_name, D_SITENAME,
sizeof(srv->site_name));
if (n >= sizeof(srv->site_name))
blob - 4ca6de208a73860f721177a094834ffc846d1aaf
blob + fe41e8a1588f58c48515f05270570fa6735580c8
--- gotwebd/sockets.c
+++ gotwebd/sockets.c
@@ -42,6 +42,7 @@
#include <netdb.h>
#include <poll.h>
#include <pwd.h>
+#include <siphash.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
@@ -49,11 +50,7 @@
#include <unistd.h>
#include <util.h>
-#include "got_error.h"
-#include "got_opentemp.h"
#include "got_reference.h"
-#include "got_repository.h"
-#include "got_privsep.h"
#include "gotwebd.h"
#include "log.h"
@@ -62,18 +59,17 @@
#define SOCKS_BACKLOG 5
#define MAXIMUM(a, b) (((a) > (b)) ? (a) : (b))
-volatile int client_cnt;
+static volatile int client_cnt;
static struct timeval timeout = { TIMEOUT_DEFAULT, 0 };
static void sockets_sighdlr(int, short, void *);
static void sockets_shutdown(void);
-static void sockets_launch(void);
+static void sockets_launch(struct gotwebd *);
static void sockets_accept_paused(int, short, void *);
-static void sockets_rlimit(int);
static void sockets_dispatch_main(int, short, void *);
-static int sockets_unix_socket_listen(struct gotwebd *, struct socket *);
+static int sockets_unix_socket_listen(struct gotwebd *, struct socket *, uid_t, gid_t);
static int sockets_create_socket(struct address *);
static int sockets_accept_reserve(int, struct sockaddr *, socklen_t *,
int, volatile int *);
@@ -83,12 +79,94 @@ static struct socket *sockets_conf_new_socket(struct g
int cgi_inflight = 0;
+/* Request hash table needs some spare room to avoid collisions. */
+struct requestlist requests[GOTWEBD_MAXCLIENTS * 4];
+static SIPHASH_KEY requests_hash_key;
+
+static void
+requests_init(void)
+{
+ int i;
+
+ arc4random_buf(&requests_hash_key, sizeof(requests_hash_key));
+
+ for (i = 0; i < nitems(requests); i++)
+ TAILQ_INIT(&requests[i]);
+}
+
+static uint64_t
+request_hash(uint32_t request_id)
+{
+ return SipHash24(&requests_hash_key, &request_id, sizeof(request_id));
+}
+
+static void
+add_request(struct request *c)
+{
+ uint64_t slot = request_hash(c->request_id) % nitems(requests);
+ TAILQ_INSERT_HEAD(&requests[slot], c, entry);
+ client_cnt++;
+}
+
void
+sockets_del_request(struct request *c)
+{
+ uint64_t slot = request_hash(c->request_id) % nitems(requests);
+ TAILQ_REMOVE(&requests[slot], c, entry);
+ client_cnt--;
+}
+
+static struct request *
+find_request(uint32_t request_id)
+{
+ uint64_t slot;
+ struct request *c;
+
+ slot = request_hash(request_id) % nitems(requests);
+ TAILQ_FOREACH(c, &requests[slot], entry) {
+ if (c->request_id == request_id)
+ return c;
+ }
+
+ return NULL;
+}
+
+static void
+requests_purge(void)
+{
+ uint64_t slot;
+ struct request *c;
+
+ for (slot = 0; slot < nitems(requests); slot++) {
+ while (!TAILQ_EMPTY(&requests[slot])) {
+ c = TAILQ_FIRST(&requests[slot]);
+ fcgi_cleanup_request(c);
+ }
+ }
+}
+
+static uint32_t
+get_request_id(void)
+{
+ int duplicate = 0;
+ uint32_t id;
+
+ do {
+ id = arc4random();
+ duplicate = (find_request(id) != NULL);
+ } while (duplicate || id == 0);
+
+ return id;
+}
+
+void
sockets(struct gotwebd *env, int fd)
{
struct event sighup, sigint, sigusr1, sigchld, sigterm;
struct event_base *evb;
+ requests_init();
+
evb = event_init();
sockets_rlimit(-1);
@@ -118,8 +196,7 @@ sockets(struct gotwebd *env, int fd)
signal_add(&sigterm, NULL);
#ifndef PROFILE
- if (pledge("stdio rpath inet recvfd proc exec sendfd unveil",
- NULL) == -1)
+ if (pledge("stdio inet recvfd sendfd", NULL) == -1)
fatal("pledge");
#endif
@@ -190,12 +267,13 @@ sockets_conf_new_socket(struct gotwebd *env, int id, s
}
static void
-sockets_launch(void)
+sockets_launch(struct gotwebd *env)
{
struct socket *sock;
- struct server *srv;
- const struct got_error *error;
+ if (env->iev_gotweb == NULL)
+ fatal("gotweb process not connected");
+
TAILQ_FOREACH(sock, &gotwebd_env->sockets, entry) {
log_info("%s: configuring socket %d (%d)", __func__,
sock->conf.id, sock->fd);
@@ -212,17 +290,12 @@ sockets_launch(void)
sock->conf.id);
}
- TAILQ_FOREACH(srv, &gotwebd_env->servers, entry) {
- if (unveil(srv->repos_path, "r") == -1)
- fatal("unveil %s", srv->repos_path);
- }
+#ifndef PROFILE
+ if (pledge("stdio inet sendfd", NULL) == -1)
+ fatal("pledge");
+#endif
+ event_add(&env->iev_gotweb->ev, NULL);
- error = got_privsep_unveil_exec_helpers();
- if (error)
- fatal("%s", error->msg);
-
- if (unveil(NULL, NULL) == -1)
- fatal("unveil");
}
void
@@ -246,6 +319,110 @@ sockets_purge(struct gotwebd *env)
}
static void
+request_done(struct imsg *imsg)
+{
+ struct request *c;
+ uint32_t request_id;
+ size_t datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
+
+ if (datalen != sizeof(request_id)) {
+ log_warn("IMSG_REQ_DONE with bad data length");
+ return;
+ }
+
+ memcpy(&request_id, imsg->data, sizeof(request_id));
+
+ c = find_request(request_id);
+ if (c == NULL) {
+ log_warnx("no request to clean up found for ID '%d'",
+ request_id);
+ return;
+ }
+
+ fcgi_create_end_record(c);
+ fcgi_cleanup_request(c);
+}
+
+static void
+server_dispatch_gotweb(int fd, short event, void *arg)
+{
+ struct imsgev *iev = arg;
+ struct imsgbuf *ibuf;
+ struct imsg imsg;
+ ssize_t n;
+ int shut = 0;
+
+ ibuf = &iev->ibuf;
+
+ if (event & EV_READ) {
+ if ((n = imsgbuf_read(ibuf)) == -1)
+ fatal("imsgbuf_read error");
+ if (n == 0) /* Connection closed */
+ shut = 1;
+ }
+ if (event & EV_WRITE) {
+ if (imsgbuf_write(ibuf) == -1)
+ fatal("imsgbuf_write");
+ }
+
+ for (;;) {
+ if ((n = imsg_get(ibuf, &imsg)) == -1)
+ fatal("imsg_get");
+ if (n == 0) /* No more messages. */
+ break;
+
+ switch (imsg.hdr.type) {
+ case GOTWEBD_IMSG_REQ_DONE:
+ request_done(&imsg);
+ break;
+ default:
+ fatalx("%s: unknown imsg type %d", __func__,
+ imsg.hdr.type);
+ }
+
+ imsg_free(&imsg);
+ }
+
+ if (!shut)
+ imsg_event_add(iev);
+ else {
+ /* This pipe is dead. Remove its event handler */
+ event_del(&iev->ev);
+ event_loopexit(NULL);
+ }
+}
+
+static void
+recv_gotweb_pipe(struct gotwebd *env, struct imsg *imsg)
+{
+ struct imsgev *iev;
+ int fd;
+
+ if (env->iev_gotweb != NULL) {
+ log_warn("gotweb pipe already received");
+ return;
+ }
+
+ fd = imsg_get_fd(imsg);
+ if (fd == -1)
+ fatalx("invalid gotweb pipe fd");
+
+ iev = calloc(1, sizeof(*iev));
+ if (iev == NULL)
+ fatal("calloc");
+
+ if (imsgbuf_init(&iev->ibuf, fd) == -1)
+ fatal("imsgbuf_init");
+ imsgbuf_allow_fdpass(&iev->ibuf);
+
+ iev->handler = server_dispatch_gotweb;
+ iev->data = iev;
+ event_set(&iev->ev, fd, EV_READ, server_dispatch_gotweb, iev);
+
+ env->iev_gotweb = iev;
+}
+
+static void
sockets_dispatch_main(int fd, short event, void *arg)
{
struct imsgev *iev = arg;
@@ -281,15 +458,15 @@ sockets_dispatch_main(int fd, short event, void *arg)
case GOTWEBD_IMSG_CFG_SOCK:
config_getsock(env, &imsg);
break;
- case GOTWEBD_IMSG_CFG_FD:
- config_getfd(env, &imsg);
- break;
case GOTWEBD_IMSG_CFG_DONE:
config_getcfg(env, &imsg);
break;
- case GOTWEBD_CTL_START:
- sockets_launch();
+ case GOTWEBD_IMSG_CTL_PIPE:
+ recv_gotweb_pipe(env, &imsg);
break;
+ case GOTWEBD_IMSG_CTL_START:
+ sockets_launch(env);
+ break;
default:
fatalx("%s: unknown imsg type %d", __func__,
imsg.hdr.type);
@@ -354,6 +531,8 @@ sockets_shutdown(void)
free(h);
}
+ requests_purge();
+
imsgbuf_clear(&gotwebd_env->iev_parent->ibuf);
free(gotwebd_env->iev_parent);
free(gotwebd_env);
@@ -362,12 +541,12 @@ sockets_shutdown(void)
}
int
-sockets_privinit(struct gotwebd *env, struct socket *sock)
+sockets_privinit(struct gotwebd *env, struct socket *sock, uid_t uid, gid_t gid)
{
if (sock->conf.af_type == AF_UNIX) {
log_info("%s: initializing unix socket %s", __func__,
sock->conf.unix_socket_name);
- sock->fd = sockets_unix_socket_listen(env, sock);
+ sock->fd = sockets_unix_socket_listen(env, sock, uid, gid);
if (sock->fd == -1)
return -1;
}
@@ -385,7 +564,8 @@ sockets_privinit(struct gotwebd *env, struct socket *s
}
static int
-sockets_unix_socket_listen(struct gotwebd *env, struct socket *sock)
+sockets_unix_socket_listen(struct gotwebd *env, struct socket *sock,
+ uid_t uid, gid_t gid)
{
int u_fd = -1;
mode_t old_umask, mode;
@@ -425,8 +605,7 @@ sockets_unix_socket_listen(struct gotwebd *env, struct
return -1;
}
- if (chown(sock->conf.unix_socket_name, env->pw->pw_uid,
- env->pw->pw_gid) == -1) {
+ if (chown(sock->conf.unix_socket_name, uid, gid) == -1) {
log_warn("%s: chown", __func__);
close(u_fd);
(void)unlink(sock->conf.unix_socket_name);
@@ -521,6 +700,7 @@ sockets_socket_accept(int fd, short event, void *arg)
struct sockaddr_storage ss;
struct timeval backoff;
struct request *c = NULL;
+ uint8_t *buf = NULL;
socklen_t len;
int s;
@@ -557,28 +737,32 @@ sockets_socket_accept(int fd, short event, void *arg)
c = calloc(1, sizeof(struct request));
if (c == NULL) {
- log_warn("%s", __func__);
+ log_warn("%s: calloc", __func__);
close(s);
cgi_inflight--;
return;
}
- c->tp = template(c, &fcgi_write, c->outbuf, sizeof(c->outbuf));
- if (c->tp == NULL) {
- log_warn("%s", __func__);
+ buf = calloc(1, FCGI_RECORD_SIZE);
+ if (buf == NULL) {
+ log_warn("%s: calloc", __func__);
close(s);
cgi_inflight--;
free(c);
return;
}
+ c->buf = buf;
c->fd = s;
+ c->resp_fd = -1;
c->sock = sock;
memcpy(c->priv_fd, gotwebd_env->priv_fd, sizeof(c->priv_fd));
+ c->sock_id = sock->conf.id;
c->buf_pos = 0;
c->buf_len = 0;
c->request_started = 0;
c->sock->client_status = CLIENT_CONNECT;
+ c->request_id = get_request_id();
event_set(&c->ev, s, EV_READ|EV_PERSIST, fcgi_request, c);
event_add(&c->ev, NULL);
@@ -586,8 +770,7 @@ sockets_socket_accept(int fd, short event, void *arg)
evtimer_set(&c->tmo, fcgi_timeout, c);
evtimer_add(&c->tmo, &timeout);
- client_cnt++;
-
+ add_request(c);
return;
err:
cgi_inflight--;
@@ -596,7 +779,7 @@ err:
free(c);
}
-static void
+void
sockets_rlimit(int maxfd)
{
struct rlimit rl;
blob - 803eb4958024659ae980b5f51216764b4ebbe37b
blob + 9cb243fe1e217fa2ced376a1954ea7ba7faa879b
--- regress/gotwebd/Makefile
+++ regress/gotwebd/Makefile
@@ -59,14 +59,8 @@ ensure_root:
false; \
fi
-gotwebd_libexec:
- @su -m ${GOTWEBD_TEST_USER} -c \
- '${MAKE} -C ${.CURDIR}/../../gotwebd/libexec' >/dev/null 2>&1
-
-prepare_test_env: ensure_root gotwebd_libexec
+prepare_test_env: ensure_root
@mkdir -p "${GOTWEBD_TEST_CHROOT}"
- @DESTDIR=${GOTWEBD_TEST_ROOT} \
- ${MAKE} -C ${.CURDIR}/../../gotwebd/libexec install >/dev/null 2>&1
@chown ${GOTWEBD_TEST_USER} "${GOTWEBD_TEST_ROOT}" \
"${GOTWEBD_TEST_CHROOT}"
gotwebd fcgi/gotweb process split