2 * Copyright (c) 2016, 2019, 2020-2021 Tracey Emery <tracey@traceyemery.net>
3 * Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org>
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 #include <sys/param.h>
19 #include <sys/queue.h>
20 #include <sys/socket.h>
22 #include <sys/cdefs.h>
25 #include <netinet/in.h>
41 #include "got_compat.h"
42 #include "got_opentemp.h"
43 #include "got_reference.h"
48 __dead void usage(void);
50 int main(int, char **);
51 int gotwebd_configure(struct gotwebd *);
52 void gotwebd_configure_done(struct gotwebd *);
53 void gotwebd_sighdlr(int sig, short event, void *arg);
54 void gotwebd_shutdown(void);
55 int gotwebd_dispatch_sockets(int, struct privsep_proc *, struct imsg *);
57 struct gotwebd *gotwebd_env;
59 static struct privsep_proc procs[] = {
60 { "sockets", PROC_SOCKS, gotwebd_dispatch_sockets, sockets,
65 gotwebd_dispatch_sockets(int fd, struct privsep_proc *p, struct imsg *imsg)
67 struct privsep *ps = p->p_ps;
68 struct gotwebd *env = ps->ps_env;
70 switch (imsg->hdr.type) {
72 gotwebd_configure_done(env);
82 gotwebd_sighdlr(int sig, short event, void *arg)
84 /* struct privsep *ps = arg; */
86 if (privsep_process != PROC_GOTWEBD)
91 log_info("%s: ignoring SIGHUP", __func__);
94 log_info("%s: ignoring SIGPIPE", __func__);
97 log_info("%s: ignoring SIGUSR1", __func__);
104 fatalx("unexpected signal");
111 fprintf(stderr, "usage: %s [-dnv] [-D macro=value] [-f file]\n",
117 main(int argc, char **argv)
123 const char *conffile = GOTWEBD_CONF;
124 enum privsep_procid proc_id = PROC_GOTWEBD;
125 int proc_instance = 0;
126 const char *errp, *title = NULL;
129 env = calloc(1, sizeof(*env));
131 fatal("%s: calloc", __func__);
133 /* XXX: add s and S for both sockets */
134 while ((ch = getopt(argc, argv, "D:df:I:nP:v")) != -1) {
137 if (cmdline_symset(optarg) < 0)
138 log_warnx("could not parse macro definition %s",
142 env->gotwebd_debug = 2;
148 proc_instance = strtonum(optarg, 0,
149 PROC_MAX_INSTANCES, &errp);
151 fatalx("invalid process instance");
154 env->gotwebd_debug = 2;
155 env->gotwebd_noaction = 1;
159 proc_id = proc_getid(procs, nitems(procs), title);
160 if (proc_id == PROC_MAX)
161 fatalx("invalid process name");
164 env->gotwebd_verbose++;
171 /* log to stderr until daemonized */
172 log_init(env->gotwebd_debug ? env->gotwebd_debug : 1, LOG_DAEMON);
178 ps = calloc(1, sizeof(*ps));
180 fatal("%s: calloc:", __func__);
183 env->gotwebd_ps = ps;
185 env->gotwebd_conffile = conffile;
187 if (parse_config(env->gotwebd_conffile, env) == -1)
190 if (env->gotwebd_noaction && !env->gotwebd_debug)
191 env->gotwebd_debug = 1;
193 /* check for root privileges */
194 if (env->gotwebd_noaction == 0) {
196 fatalx("need root privileges");
199 ps->ps_pw = getpwnam(GOTWEBD_USER);
200 if (ps->ps_pw == NULL)
201 fatalx("unknown user %s", GOTWEBD_USER);
203 log_init(env->gotwebd_debug, LOG_DAEMON);
204 log_setverbose(env->gotwebd_verbose);
206 if (env->gotwebd_noaction)
209 ps->ps_instances[PROC_SOCKS] = env->prefork_gotwebd;
210 ps->ps_instance = proc_instance;
212 ps->ps_title[proc_id] = title;
214 for (proc = 0; proc < nitems(procs); proc++)
215 procs[proc].p_chroot = env->httpd_chroot;
217 /* only the gotwebd returns */
218 proc_init(ps, procs, nitems(procs), argc0, argv, proc_id);
220 log_procinit("gotwebd");
221 if (!env->gotwebd_debug && daemon(0, 0) == -1)
222 fatal("can't daemonize");
224 if (ps->ps_noaction == 0)
225 log_info("%s startup", getprogname());
229 signal_set(&ps->ps_evsigint, SIGINT, gotwebd_sighdlr, ps);
230 signal_set(&ps->ps_evsigterm, SIGTERM, gotwebd_sighdlr, ps);
231 signal_set(&ps->ps_evsighup, SIGHUP, gotwebd_sighdlr, ps);
232 signal_set(&ps->ps_evsigpipe, SIGPIPE, gotwebd_sighdlr, ps);
233 signal_set(&ps->ps_evsigusr1, SIGUSR1, gotwebd_sighdlr, ps);
235 signal_add(&ps->ps_evsigint, NULL);
236 signal_add(&ps->ps_evsigterm, NULL);
237 signal_add(&ps->ps_evsighup, NULL);
238 signal_add(&ps->ps_evsigpipe, NULL);
239 signal_add(&ps->ps_evsigusr1, NULL);
241 if (!env->gotwebd_noaction)
244 if (gotwebd_configure(env) == -1)
245 fatalx("configuration failed");
248 if (unveil("gmon.out", "rwc") != 0)
252 if (unveil(env->httpd_chroot, "rwc") == -1)
255 if (unveil(GOT_TMPDIR_STR, "rw") == -1)
258 if (unveil(GOTWEBD_CONF, "r") == -1)
261 if (unveil(NULL, NULL) != 0)
265 if (pledge("stdio rpath wpath cpath inet unix", NULL) == -1)
271 log_debug("%s gotwebd exiting", getprogname());
277 gotwebd_configure(struct gotwebd *env)
283 if (env->gotwebd_noaction) {
284 fprintf(stderr, "configuration OK\n");
285 proc_kill(env->gotwebd_ps);
289 /* gotweb need to reload its config. */
290 env->gotwebd_reload = env->prefork_gotwebd;
292 /* send our gotweb servers */
293 TAILQ_FOREACH(srv, &env->servers, entry) {
294 if (config_setserver(env, srv) == -1)
295 fatalx("%s: send server error", __func__);
298 /* send our sockets */
299 TAILQ_FOREACH(sock, &env->sockets, entry) {
300 if (config_setsock(env, sock) == -1)
301 fatalx("%s: send socket error", __func__);
302 if (config_setfd(env, sock) == -1)
303 fatalx("%s: send priv_fd error", __func__);
306 for (id = 0; id < PROC_MAX; id++) {
307 if (id == privsep_process)
309 proc_compose(env->gotwebd_ps, id, IMSG_CFG_DONE, NULL, 0);
316 gotwebd_configure_done(struct gotwebd *env)
320 if (env->gotwebd_reload == 0) {
321 log_warnx("%s: configuration already finished", __func__);
325 env->gotwebd_reload--;
326 if (env->gotwebd_reload == 0) {
327 for (id = 0; id < PROC_MAX; id++) {
328 if (id == privsep_process)
330 proc_compose(env->gotwebd_ps, id, IMSG_CTL_START,
337 gotwebd_shutdown(void)
339 proc_kill(gotwebd_env->gotwebd_ps);
341 /* unlink(gotwebd_env->gotweb->gotweb_conf.gotweb_unix_socket_name); */
342 /* free(gotwebd_env->gotweb); */
345 log_warnx("gotwebd terminating");