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
= strlen(env
->httpd_chroot
) ?
216 env
->httpd_chroot
: D_HTTPD_CHROOT
;
218 /* only the gotwebd returns */
219 proc_init(ps
, procs
, nitems(procs
), argc0
, argv
, proc_id
);
221 log_procinit("gotwebd");
222 if (!env
->gotwebd_debug
&& daemon(0, 0) == -1)
223 fatal("can't daemonize");
225 if (ps
->ps_noaction
== 0)
226 log_info("%s startup", getprogname());
230 signal_set(&ps
->ps_evsigint
, SIGINT
, gotwebd_sighdlr
, ps
);
231 signal_set(&ps
->ps_evsigterm
, SIGTERM
, gotwebd_sighdlr
, ps
);
232 signal_set(&ps
->ps_evsighup
, SIGHUP
, gotwebd_sighdlr
, ps
);
233 signal_set(&ps
->ps_evsigpipe
, SIGPIPE
, gotwebd_sighdlr
, ps
);
234 signal_set(&ps
->ps_evsigusr1
, SIGUSR1
, gotwebd_sighdlr
, ps
);
236 signal_add(&ps
->ps_evsigint
, NULL
);
237 signal_add(&ps
->ps_evsigterm
, NULL
);
238 signal_add(&ps
->ps_evsighup
, NULL
);
239 signal_add(&ps
->ps_evsigpipe
, NULL
);
240 signal_add(&ps
->ps_evsigusr1
, NULL
);
242 if (!env
->gotwebd_noaction
)
245 if (gotwebd_configure(env
) == -1)
246 fatalx("configuration failed");
249 if (unveil("gmon.out", "rwc") != 0)
253 if (unveil(strlen(env
->httpd_chroot
) > 0 ? env
->httpd_chroot
:
254 D_HTTPD_CHROOT
, "rwc") == -1)
257 if (unveil(GOT_TMPDIR_STR
, "rw") == -1)
260 if (unveil(GOTWEBD_CONF
, "r") == -1)
263 if (unveil(NULL
, NULL
) != 0)
267 if (pledge("stdio rpath wpath cpath inet unix", NULL
) == -1)
273 log_debug("%s gotwebd exiting", getprogname());
279 gotwebd_configure(struct gotwebd
*env
)
285 if (env
->gotwebd_noaction
) {
286 fprintf(stderr
, "configuration OK\n");
287 proc_kill(env
->gotwebd_ps
);
291 /* gotweb need to reload its config. */
292 env
->gotwebd_reload
= env
->prefork_gotwebd
;
294 /* send our gotweb servers */
295 TAILQ_FOREACH(srv
, &env
->servers
, entry
) {
296 if (config_setserver(env
, srv
) == -1)
297 fatalx("%s: send server error", __func__
);
300 /* send our sockets */
301 TAILQ_FOREACH(sock
, &env
->sockets
, entry
) {
302 if (config_setsock(env
, sock
) == -1)
303 fatalx("%s: send socket error", __func__
);
304 if (config_setfd(env
, sock
) == -1)
305 fatalx("%s: send priv_fd error", __func__
);
308 for (id
= 0; id
< PROC_MAX
; id
++) {
309 if (id
== privsep_process
)
311 proc_compose(env
->gotwebd_ps
, id
, IMSG_CFG_DONE
, NULL
, 0);
318 gotwebd_configure_done(struct gotwebd
*env
)
322 if (env
->gotwebd_reload
== 0) {
323 log_warnx("%s: configuration already finished", __func__
);
327 env
->gotwebd_reload
--;
328 if (env
->gotwebd_reload
== 0) {
329 for (id
= 0; id
< PROC_MAX
; id
++) {
330 if (id
== privsep_process
)
332 proc_compose(env
->gotwebd_ps
, id
, IMSG_CTL_START
,
339 gotwebd_shutdown(void)
341 proc_kill(gotwebd_env
->gotwebd_ps
);
343 /* unlink(gotwebd_env->gotweb->gotweb_conf.gotweb_unix_socket_name); */
344 /* free(gotwebd_env->gotweb); */
347 log_warnx("gotwebd terminating");