18abd06a7SGlenn Strauss #include "first.h"
28abd06a7SGlenn Strauss
3c8f96585SGlenn Strauss #include "base.h"
4bcdc6a3bSJan Kneschke #include "buffer.h"
5bcdc6a3bSJan Kneschke #include "network.h"
6bcdc6a3bSJan Kneschke #include "log.h"
77f4e156eSGlenn Strauss #include "rand.h"
8bcdc6a3bSJan Kneschke #include "chunk.h"
9869c778aSGlenn Strauss #include "h2.h" /* h2_send_1xx() */
1025f83b84SGlenn Strauss #include "http_range.h" /* http_range_config_allow_http10() */
11bcdc6a3bSJan Kneschke #include "fdevent.h"
12243510dbSGlenn Strauss #include "fdlog.h"
13bcdc6a3bSJan Kneschke #include "connections.h"
141367f606SGlenn Strauss #include "sock_addr.h"
155e134da0SJan Kneschke #include "stat_cache.h"
16bcdc6a3bSJan Kneschke #include "plugin.h"
1796557115SGlenn Strauss #include "plugins.h"
18869c778aSGlenn Strauss #include "plugin_config.h" /* config_plugin_value_tobool() */
1927e27e5eSGlenn Strauss #include "network_write.h" /* network_write_show_handlers() */
20878073d1SGlenn Strauss #include "reqpool.h" /* request_pool_init() request_pool_free() */
21869c778aSGlenn Strauss #include "response.h" /* http_response_send_1xx_cb_set() strftime_cache_reset() */
22daa94fceSGlenn Strauss
23daa94fceSGlenn Strauss #ifdef HAVE_VERSIONSTAMP_H
24daa94fceSGlenn Strauss # include "versionstamp.h"
25daa94fceSGlenn Strauss #else
26daa94fceSGlenn Strauss # define REPO_VERSION ""
27daa94fceSGlenn Strauss #endif
28daa94fceSGlenn Strauss
29daa94fceSGlenn Strauss #define PACKAGE_DESC PACKAGE_NAME "/" PACKAGE_VERSION REPO_VERSION
30a162fc70SGlenn Strauss static const buffer default_server_tag =
31a162fc70SGlenn Strauss { PACKAGE_DESC "\0server", sizeof(PACKAGE_DESC), 0 };
32bcdc6a3bSJan Kneschke
3322e8b456SStefan Bühler #include <sys/types.h>
3422e8b456SStefan Bühler #include <sys/stat.h>
356cd3b5f8SGlenn Strauss #include "sys-setjmp.h"
3613ea2d88SGlenn Strauss #include "sys-time.h"
3722e8b456SStefan Bühler
3822e8b456SStefan Bühler #include <string.h>
3922e8b456SStefan Bühler #include <errno.h>
4022e8b456SStefan Bühler #include <fcntl.h>
4122e8b456SStefan Bühler #include <unistd.h>
4222e8b456SStefan Bühler #include <stdlib.h>
4322e8b456SStefan Bühler #include <signal.h>
4422e8b456SStefan Bühler #include <locale.h>
4522e8b456SStefan Bühler
4622e8b456SStefan Bühler #include <stdio.h>
4722e8b456SStefan Bühler
48bcdc6a3bSJan Kneschke #ifdef HAVE_GETOPT_H
49bcdc6a3bSJan Kneschke # include <getopt.h>
50bcdc6a3bSJan Kneschke #endif
51bcdc6a3bSJan Kneschke
52bcdc6a3bSJan Kneschke #ifdef HAVE_VALGRIND_VALGRIND_H
53bcdc6a3bSJan Kneschke # include <valgrind/valgrind.h>
54bcdc6a3bSJan Kneschke #endif
55bcdc6a3bSJan Kneschke
56bcdc6a3bSJan Kneschke #ifdef HAVE_PWD_H
57bcdc6a3bSJan Kneschke # include <grp.h>
58bcdc6a3bSJan Kneschke # include <pwd.h>
59bcdc6a3bSJan Kneschke #endif
60bcdc6a3bSJan Kneschke
618c9b5480SNiclas Rosenvik #ifdef HAVE_SYS_LOADAVG_H
628c9b5480SNiclas Rosenvik # include <sys/loadavg.h>
638c9b5480SNiclas Rosenvik #endif
648c9b5480SNiclas Rosenvik
65bcdc6a3bSJan Kneschke #ifdef HAVE_SYS_RESOURCE_H
66bcdc6a3bSJan Kneschke # include <sys/resource.h>
67bcdc6a3bSJan Kneschke #endif
68bcdc6a3bSJan Kneschke
692fe31be5SJan Kneschke #ifdef HAVE_SYS_PRCTL_H
702fe31be5SJan Kneschke # include <sys/prctl.h>
712fe31be5SJan Kneschke #endif
72f36908deSGlenn Strauss #ifdef HAVE_SYS_PROCCTL_H
73f36908deSGlenn Strauss # include <sys/procctl.h>
74f36908deSGlenn Strauss #endif
75b6bd11c1SDavid Carlier #ifdef HAVE_PRIV_H
76b6bd11c1SDavid Carlier # include <priv.h>
77b6bd11c1SDavid Carlier #endif
782fe31be5SJan Kneschke
7943f0106fSGlenn Strauss #ifdef HAVE_MALLOC_H
8043f0106fSGlenn Strauss #ifndef LIGHTTPD_STATIC
8143f0106fSGlenn Strauss #ifdef HAVE_DLFCN_H
8243f0106fSGlenn Strauss #include <dlfcn.h>
8343f0106fSGlenn Strauss #endif
8443f0106fSGlenn Strauss #endif
8543f0106fSGlenn Strauss #include <malloc.h>
861a8d8e0cSGlenn Strauss #if defined(HAVE_MALLOC_TRIM)
871a8d8e0cSGlenn Strauss static int(*malloc_trim_fn)(size_t);
881a8d8e0cSGlenn Strauss static size_t malloc_top_pad;
891a8d8e0cSGlenn Strauss #endif
9043f0106fSGlenn Strauss #endif
9143f0106fSGlenn Strauss
92368630d9SGlenn Strauss #include "sys-crypto.h"
93cb753ec5SGlenn Strauss #if defined(USE_OPENSSL_CRYPTO) \
94bf4054f8SGlenn Strauss || defined(USE_MBEDTLS_CRYPTO) \
95e00deb55SGlenn Strauss || defined(USE_NSS_CRYPTO) \
9698a224a4SGlenn Strauss || defined(USE_GNUTLS_CRYPTO) \
9798a224a4SGlenn Strauss || defined(USE_WOLFTLS_CRYPTO)
988960633dSGlenn Strauss #define TEXT_SSL " (ssl)"
998960633dSGlenn Strauss #else
1008960633dSGlenn Strauss #define TEXT_SSL
1018960633dSGlenn Strauss #endif
1028960633dSGlenn Strauss
103bcdc6a3bSJan Kneschke #ifndef __sgi
104bcdc6a3bSJan Kneschke /* IRIX doesn't like the alarm based time() optimization */
105bcdc6a3bSJan Kneschke /* #define USE_ALARM */
106bcdc6a3bSJan Kneschke #endif
107bcdc6a3bSJan Kneschke
108ccb1f02bSGlenn Strauss static int oneshot_fd = 0;
109ed297e7eSGlenn Strauss static int oneshot_fdout = -1;
110ed297e7eSGlenn Strauss static fdnode *oneshot_fdn = NULL;
111ed297e7eSGlenn Strauss static int (*oneshot_read_cq)(connection *con, chunkqueue *cq, off_t max_bytes);
112fad841d6SGlenn Strauss static volatile int pid_fd = -2;
1136c1e6e66SGlenn Strauss static server_socket_array graceful_sockets;
114ce7b47c0SGlenn Strauss static server_socket_array inherited_sockets;
1156c1e6e66SGlenn Strauss static volatile sig_atomic_t graceful_restart = 0;
116d24262a0SJan Kneschke static volatile sig_atomic_t graceful_shutdown = 0;
1176c1e6e66SGlenn Strauss static volatile sig_atomic_t srv_shutdown = 0;
1189030cfaeSGlenn Strauss static volatile sig_atomic_t handle_sig_child = 0;
119c25cf5a0SJan Kneschke static volatile sig_atomic_t handle_sig_alarm = 1;
120c25cf5a0SJan Kneschke static volatile sig_atomic_t handle_sig_hup = 0;
121309c1693SGlenn Strauss static int idle_limit = 0;
122bcdc6a3bSJan Kneschke
123bcdc6a3bSJan Kneschke #if defined(HAVE_SIGACTION) && defined(SA_SIGINFO)
124ef19bacaSJan Kneschke static volatile siginfo_t last_sigterm_info;
125ef19bacaSJan Kneschke static volatile siginfo_t last_sighup_info;
126ef19bacaSJan Kneschke
sigaction_handler(int sig,siginfo_t * si,void * context)127bcdc6a3bSJan Kneschke static void sigaction_handler(int sig, siginfo_t *si, void *context) {
128f3437fb2SGlenn Strauss static const siginfo_t empty_siginfo;
129bcdc6a3bSJan Kneschke UNUSED(context);
130bcdc6a3bSJan Kneschke
131f3437fb2SGlenn Strauss if (!si) *(const siginfo_t **)&si = &empty_siginfo;
1324533af76SStefan Bühler
133bcdc6a3bSJan Kneschke switch (sig) {
134ef19bacaSJan Kneschke case SIGTERM:
135ef19bacaSJan Kneschke srv_shutdown = 1;
13622d8707eSStefan Bühler last_sigterm_info = *si;
137ef19bacaSJan Kneschke break;
1386c1e6e66SGlenn Strauss case SIGUSR1:
1396c1e6e66SGlenn Strauss if (!graceful_shutdown) {
1406c1e6e66SGlenn Strauss graceful_restart = 1;
1416c1e6e66SGlenn Strauss graceful_shutdown = 1;
1426c1e6e66SGlenn Strauss last_sigterm_info = *si;
1436c1e6e66SGlenn Strauss }
1446c1e6e66SGlenn Strauss break;
14594334e46SJan Kneschke case SIGINT:
146ef19bacaSJan Kneschke if (graceful_shutdown) {
1476c1e6e66SGlenn Strauss if (2 == graceful_restart)
1486c1e6e66SGlenn Strauss graceful_restart = 1;
1496c1e6e66SGlenn Strauss else
150ef19bacaSJan Kneschke srv_shutdown = 1;
151ef19bacaSJan Kneschke } else {
152ef19bacaSJan Kneschke graceful_shutdown = 1;
153ef19bacaSJan Kneschke }
15422d8707eSStefan Bühler last_sigterm_info = *si;
15594334e46SJan Kneschke
15694334e46SJan Kneschke break;
157ef19bacaSJan Kneschke case SIGALRM:
158ef19bacaSJan Kneschke handle_sig_alarm = 1;
159ef19bacaSJan Kneschke break;
160ef19bacaSJan Kneschke case SIGHUP:
161ef19bacaSJan Kneschke handle_sig_hup = 1;
16222d8707eSStefan Bühler last_sighup_info = *si;
163ef19bacaSJan Kneschke break;
164ef19bacaSJan Kneschke case SIGCHLD:
1659030cfaeSGlenn Strauss handle_sig_child = 1;
166ef19bacaSJan Kneschke break;
167bcdc6a3bSJan Kneschke }
168bcdc6a3bSJan Kneschke }
169bcdc6a3bSJan Kneschke #elif defined(HAVE_SIGNAL) || defined(HAVE_SIGACTION)
signal_handler(int sig)170bcdc6a3bSJan Kneschke static void signal_handler(int sig) {
171bcdc6a3bSJan Kneschke switch (sig) {
172bcdc6a3bSJan Kneschke case SIGTERM: srv_shutdown = 1; break;
17342ab331dSGlenn Strauss case SIGUSR1:
17442ab331dSGlenn Strauss if (!graceful_shutdown) {
17542ab331dSGlenn Strauss graceful_restart = 1;
17642ab331dSGlenn Strauss graceful_shutdown = 1;
17742ab331dSGlenn Strauss }
17842ab331dSGlenn Strauss break;
17994334e46SJan Kneschke case SIGINT:
1806c1e6e66SGlenn Strauss if (graceful_shutdown) {
1816c1e6e66SGlenn Strauss if (2 == graceful_restart)
1826c1e6e66SGlenn Strauss graceful_restart = 1;
1836c1e6e66SGlenn Strauss else
1846c1e6e66SGlenn Strauss srv_shutdown = 1;
1856c1e6e66SGlenn Strauss } else {
1866c1e6e66SGlenn Strauss graceful_shutdown = 1;
1876c1e6e66SGlenn Strauss }
18894334e46SJan Kneschke break;
189bcdc6a3bSJan Kneschke case SIGALRM: handle_sig_alarm = 1; break;
1906e668bfeSGlenn Strauss case SIGHUP: handle_sig_hup = 1; break;
1919030cfaeSGlenn Strauss case SIGCHLD: handle_sig_child = 1; break;
192bcdc6a3bSJan Kneschke }
193bcdc6a3bSJan Kneschke }
194bcdc6a3bSJan Kneschke #endif
195bcdc6a3bSJan Kneschke
196dd6b2645SGlenn Strauss
server_main_setup_signals(void)197dd6b2645SGlenn Strauss static void server_main_setup_signals (void) {
198dd6b2645SGlenn Strauss #ifdef HAVE_SIGACTION
199dd6b2645SGlenn Strauss struct sigaction act;
200dd6b2645SGlenn Strauss memset(&act, 0, sizeof(act));
201dd6b2645SGlenn Strauss sigemptyset(&act.sa_mask);
202dd6b2645SGlenn Strauss
203dd6b2645SGlenn Strauss act.sa_handler = SIG_IGN;
204dd6b2645SGlenn Strauss sigaction(SIGPIPE, &act, NULL);
205dd6b2645SGlenn Strauss
206dd6b2645SGlenn Strauss #ifndef _MSC_VER
207dd6b2645SGlenn Strauss act.sa_flags = SA_NODEFER;
208dd6b2645SGlenn Strauss act.sa_handler = sys_setjmp_sigbus;
209dd6b2645SGlenn Strauss sigaction(SIGBUS, &act, NULL);
210dd6b2645SGlenn Strauss act.sa_flags = 0;
211dd6b2645SGlenn Strauss #endif
212dd6b2645SGlenn Strauss
213dd6b2645SGlenn Strauss #if defined(SA_SIGINFO)
214dd6b2645SGlenn Strauss last_sighup_info.si_uid = 0,
215dd6b2645SGlenn Strauss last_sighup_info.si_pid = 0;
216dd6b2645SGlenn Strauss last_sigterm_info.si_uid = 0,
217dd6b2645SGlenn Strauss last_sigterm_info.si_pid = 0;
218dd6b2645SGlenn Strauss act.sa_sigaction = sigaction_handler;
219dd6b2645SGlenn Strauss act.sa_flags = SA_SIGINFO;
220dd6b2645SGlenn Strauss #else
221dd6b2645SGlenn Strauss act.sa_handler = signal_handler;
222dd6b2645SGlenn Strauss act.sa_flags = 0;
223dd6b2645SGlenn Strauss #endif
224dd6b2645SGlenn Strauss sigaction(SIGINT, &act, NULL);
225dd6b2645SGlenn Strauss sigaction(SIGTERM, &act, NULL);
226dd6b2645SGlenn Strauss sigaction(SIGHUP, &act, NULL);
227dd6b2645SGlenn Strauss sigaction(SIGALRM, &act, NULL);
228dd6b2645SGlenn Strauss sigaction(SIGUSR1, &act, NULL);
229dd6b2645SGlenn Strauss
230dd6b2645SGlenn Strauss /* it should be safe to restart syscalls after SIGCHLD */
231dd6b2645SGlenn Strauss act.sa_flags |= SA_RESTART | SA_NOCLDSTOP;
232dd6b2645SGlenn Strauss sigaction(SIGCHLD, &act, NULL);
233dd6b2645SGlenn Strauss #elif defined(HAVE_SIGNAL)
234dd6b2645SGlenn Strauss /* ignore the SIGPIPE from sendfile() */
235dd6b2645SGlenn Strauss signal(SIGPIPE, SIG_IGN);
236dd6b2645SGlenn Strauss signal(SIGALRM, signal_handler);
237dd6b2645SGlenn Strauss signal(SIGTERM, signal_handler);
238dd6b2645SGlenn Strauss signal(SIGHUP, signal_handler);
239dd6b2645SGlenn Strauss signal(SIGCHLD, signal_handler);
240dd6b2645SGlenn Strauss signal(SIGINT, signal_handler);
241dd6b2645SGlenn Strauss signal(SIGUSR1, signal_handler);
242dd6b2645SGlenn Strauss #ifndef _MSC_VER
243dd6b2645SGlenn Strauss signal(SIGBUS, sys_setjmp_sigbus);
244dd6b2645SGlenn Strauss #endif
245dd6b2645SGlenn Strauss #endif
246dd6b2645SGlenn Strauss }
247dd6b2645SGlenn Strauss
248dd6b2645SGlenn Strauss
249bcdc6a3bSJan Kneschke #ifdef HAVE_FORK
daemonize(void)250f11089edSGlenn Strauss static int daemonize(void) {
251f11089edSGlenn Strauss int pipefd[2];
252f11089edSGlenn Strauss pid_t pid;
253bcdc6a3bSJan Kneschke #ifdef SIGTTOU
254bcdc6a3bSJan Kneschke signal(SIGTTOU, SIG_IGN);
255bcdc6a3bSJan Kneschke #endif
256bcdc6a3bSJan Kneschke #ifdef SIGTTIN
257bcdc6a3bSJan Kneschke signal(SIGTTIN, SIG_IGN);
258bcdc6a3bSJan Kneschke #endif
259bcdc6a3bSJan Kneschke #ifdef SIGTSTP
260bcdc6a3bSJan Kneschke signal(SIGTSTP, SIG_IGN);
261bcdc6a3bSJan Kneschke #endif
262f11089edSGlenn Strauss
263cc2fcd3eSGlenn Strauss if (fdevent_pipe_cloexec(pipefd, 64) < 0) exit(-1);
264f11089edSGlenn Strauss
265f11089edSGlenn Strauss if (0 > (pid = fork())) exit(-1);
266f11089edSGlenn Strauss
267f11089edSGlenn Strauss if (0 < pid) {
268f11089edSGlenn Strauss char buf;
269f11089edSGlenn Strauss ssize_t bytes;
270f11089edSGlenn Strauss
271f11089edSGlenn Strauss close(pipefd[1]);
272f11089edSGlenn Strauss /* parent waits for grandchild to be ready */
273f11089edSGlenn Strauss do {
274f11089edSGlenn Strauss bytes = read(pipefd[0], &buf, sizeof(buf));
275f11089edSGlenn Strauss } while (bytes < 0 && EINTR == errno);
276f11089edSGlenn Strauss close(pipefd[0]);
277f11089edSGlenn Strauss
278f11089edSGlenn Strauss if (bytes <= 0) {
279f11089edSGlenn Strauss /* closed fd (without writing) == failure in grandchild */
280f11089edSGlenn Strauss fputs("daemonized server failed to start; check error log for details\n", stderr);
281f11089edSGlenn Strauss exit(-1);
282f11089edSGlenn Strauss }
283f11089edSGlenn Strauss
284f11089edSGlenn Strauss exit(0);
285f11089edSGlenn Strauss }
286f11089edSGlenn Strauss
287f11089edSGlenn Strauss close(pipefd[0]);
288bcdc6a3bSJan Kneschke
289319326b5SJan Kneschke if (-1 == setsid()) exit(0);
290bcdc6a3bSJan Kneschke
291bcdc6a3bSJan Kneschke signal(SIGHUP, SIG_IGN);
292bcdc6a3bSJan Kneschke
293319326b5SJan Kneschke if (0 != fork()) exit(0);
294bcdc6a3bSJan Kneschke
295319326b5SJan Kneschke if (0 != chdir("/")) exit(0);
296f11089edSGlenn Strauss
297f11089edSGlenn Strauss return pipefd[1];
298bcdc6a3bSJan Kneschke }
299bcdc6a3bSJan Kneschke #endif
300bcdc6a3bSJan Kneschke
30187b09d14SGlenn Strauss static int clockid_mono_coarse = 0;
30287b09d14SGlenn Strauss
303309c1693SGlenn Strauss static unix_time64_t
server_monotonic_secs(void)304dbe3e236SGlenn Strauss server_monotonic_secs (void)
305dbe3e236SGlenn Strauss {
306309c1693SGlenn Strauss unix_timespec64_t ts;
30787b09d14SGlenn Strauss return (0 == log_clock_gettime(clockid_mono_coarse, &ts))
308dbe3e236SGlenn Strauss ? ts.tv_sec
309dbe3e236SGlenn Strauss : log_monotonic_secs;
310dbe3e236SGlenn Strauss }
311dbe3e236SGlenn Strauss
312309c1693SGlenn Strauss static unix_time64_t
server_epoch_secs(server * const srv,unix_time64_t mono_ts_delta)313b68b805cSGlenn Strauss server_epoch_secs (server * const srv, unix_time64_t mono_ts_delta)
3140ee96426SGlenn Strauss {
315309c1693SGlenn Strauss const unix_time64_t cur_ts = log_epoch_secs;
316309c1693SGlenn Strauss const unix_time64_t new_ts = TIME64_CAST(time(NULL));
317b68b805cSGlenn Strauss const unix_time64_t new_ts_adj = new_ts - mono_ts_delta;
3180ee96426SGlenn Strauss /* attempt to detect large clock jump */
319b68b805cSGlenn Strauss if (new_ts_adj < cur_ts || new_ts_adj - cur_ts > 300) { /*(5 mins)*/
3200ee96426SGlenn Strauss log_error(srv->errh, __FILE__, __LINE__,
3210ee96426SGlenn Strauss "warning: clock jumped %lld secs",
322b68b805cSGlenn Strauss (long long)((int64_t)new_ts_adj - (int64_t)cur_ts));
3234d99d9b7SGlenn Strauss int delta = /*(30 mins default)*/
3244d99d9b7SGlenn Strauss config_feature_int(srv, "server.clock-jump-restart", 1800);
325b68b805cSGlenn Strauss if (delta && (new_ts_adj > cur_ts
326b68b805cSGlenn Strauss ? new_ts_adj-cur_ts
327b68b805cSGlenn Strauss : cur_ts-new_ts_adj) > delta) {
3280ee96426SGlenn Strauss log_error(srv->errh, __FILE__, __LINE__,
3290ee96426SGlenn Strauss "attempting graceful restart in < ~5 seconds, else hard restart");
3300ee96426SGlenn Strauss srv->graceful_expire_ts = log_monotonic_secs + 5;
3310ee96426SGlenn Strauss raise(SIGUSR1);
3320ee96426SGlenn Strauss }
3330ee96426SGlenn Strauss }
3340ee96426SGlenn Strauss return new_ts;
3350ee96426SGlenn Strauss }
3360ee96426SGlenn Strauss
337fb9b8ad8SGlenn Strauss __attribute_cold__
3386800b082SGlenn Strauss __attribute_noinline__
339b38817b6SGlenn Strauss __attribute_returns_nonnull__
server_init(void)340bcdc6a3bSJan Kneschke static server *server_init(void) {
3415e14db43SGlenn Strauss server *srv = ck_calloc(1, sizeof(*srv));
342bcdc6a3bSJan Kneschke
343dc2d1dfeSGlenn Strauss srv->tmp_buf = buffer_init();
344bcdc6a3bSJan Kneschke
34527e27e5eSGlenn Strauss strftime_cache_reset();
346bcdc6a3bSJan Kneschke
3477f4e156eSGlenn Strauss li_rand_reseed();
3487ad47923SStefan Bühler
349309c1693SGlenn Strauss srv->startup_ts = log_epoch_secs = TIME64_CAST(time(NULL));
35087b09d14SGlenn Strauss #ifdef HAVE_CLOCK_GETTIME
35187b09d14SGlenn Strauss unix_timespec64_t ts;
35287b09d14SGlenn Strauss UNUSED(&ts);
35387b09d14SGlenn Strauss #ifdef CLOCK_MONOTONIC_COARSE
35487b09d14SGlenn Strauss if (0 == log_clock_gettime(CLOCK_MONOTONIC_COARSE, &ts))
35587b09d14SGlenn Strauss clockid_mono_coarse = CLOCK_MONOTONIC_COARSE;
35687b09d14SGlenn Strauss else
35787b09d14SGlenn Strauss #endif
35887b09d14SGlenn Strauss #ifdef CLOCK_MONOTONIC_RAW_APPROX
35987b09d14SGlenn Strauss if (0 == log_clock_gettime(CLOCK_MONOTONIC_RAW_APPROX, &ts))
36087b09d14SGlenn Strauss clockid_mono_coarse = CLOCK_MONOTONIC_RAW_APPROX;
36187b09d14SGlenn Strauss else
36287b09d14SGlenn Strauss #endif
36387b09d14SGlenn Strauss #ifdef CLOCK_MONOTONIC_RAW
36487b09d14SGlenn Strauss if (0 == log_clock_gettime(CLOCK_MONOTONIC_RAW, &ts))
36587b09d14SGlenn Strauss clockid_mono_coarse = CLOCK_MONOTONIC_RAW;
36687b09d14SGlenn Strauss else
36787b09d14SGlenn Strauss #endif
36887b09d14SGlenn Strauss clockid_mono_coarse = CLOCK_MONOTONIC;
36987b09d14SGlenn Strauss #endif
370dbe3e236SGlenn Strauss log_monotonic_secs = server_monotonic_secs();
371bcdc6a3bSJan Kneschke
3720b6de090SGlenn Strauss srv->errh = log_set_global_errh(NULL, 0);
373cbad7517SGlenn Strauss
37465ef0a3dSGlenn Strauss config_init(srv);
375bcdc6a3bSJan Kneschke
376cb7ed136SGlenn Strauss srv->request_env = plugins_call_handle_request_env;
377cc65a21eSGlenn Strauss srv->plugins_request_reset = plugins_call_handle_request_reset;
378bcdc6a3bSJan Kneschke
379ed62e354SGlenn Strauss srv->loadavg[0] = 0.0;
380ed62e354SGlenn Strauss srv->loadavg[1] = 0.0;
381ed62e354SGlenn Strauss srv->loadavg[2] = 0.0;
382ea58cc6fSGlenn Strauss srv->stdin_fd = -1;
383beb029d6SGlenn Strauss srv->default_server_tag = &default_server_tag;
384ed62e354SGlenn Strauss
385dc2d1dfeSGlenn Strauss log_con_jqueue = (connection *)(uintptr_t)&log_con_jqueue;/*(sentinel)*/
386dc2d1dfeSGlenn Strauss
387bcdc6a3bSJan Kneschke return srv;
388bcdc6a3bSJan Kneschke }
389bcdc6a3bSJan Kneschke
390fb9b8ad8SGlenn Strauss __attribute_cold__
3916800b082SGlenn Strauss __attribute_noinline__
server_free(server * srv)392bcdc6a3bSJan Kneschke static void server_free(server *srv) {
393ccb1f02bSGlenn Strauss if (oneshot_fd > 0) {
394ed297e7eSGlenn Strauss if (oneshot_fdn) {
395ed297e7eSGlenn Strauss fdevent_fdnode_event_del(srv->ev, oneshot_fdn);
396*f0786a75SGlenn Strauss fdevent_unregister(srv->ev, oneshot_fdn);
397ed297e7eSGlenn Strauss oneshot_fdn = NULL;
398ed297e7eSGlenn Strauss }
399ccb1f02bSGlenn Strauss close(oneshot_fd);
400ccb1f02bSGlenn Strauss }
401ed297e7eSGlenn Strauss if (oneshot_fdout >= 0) {
402ed297e7eSGlenn Strauss close(oneshot_fdout);
403ed297e7eSGlenn Strauss }
404ea58cc6fSGlenn Strauss if (srv->stdin_fd >= 0) {
405ea58cc6fSGlenn Strauss close(srv->stdin_fd);
406ea58cc6fSGlenn Strauss }
407ccb1f02bSGlenn Strauss
408dc2d1dfeSGlenn Strauss buffer_free(srv->tmp_buf);
409bcdc6a3bSJan Kneschke
410bcdc6a3bSJan Kneschke fdevent_free(srv->ev);
411bcdc6a3bSJan Kneschke
41265ef0a3dSGlenn Strauss config_free(srv);
413bcdc6a3bSJan Kneschke
41468d8d4c5SGlenn Strauss stat_cache_free();
415bcdc6a3bSJan Kneschke
4167f4e156eSGlenn Strauss li_rand_cleanup();
417fccc7fc6SGlenn Strauss chunkqueue_chunk_pool_free();
4181398cb2eSJan Kneschke
4190b6de090SGlenn Strauss if (srv->errh != log_set_global_errh(NULL, 0))
4207b615d5dSGlenn Strauss fdlog_free(srv->errh);
421bcdc6a3bSJan Kneschke free(srv);
422bcdc6a3bSJan Kneschke }
423bcdc6a3bSJan Kneschke
424fb9b8ad8SGlenn Strauss __attribute_cold__
4256800b082SGlenn Strauss __attribute_noinline__
remove_pid_file(server * srv)4266c1e6e66SGlenn Strauss static void remove_pid_file(server *srv) {
427fad841d6SGlenn Strauss if (pid_fd <= -2) return;
428af3df29aSGlenn Strauss if (srv->srvconf.pid_file && 0 <= pid_fd) {
4296c1e6e66SGlenn Strauss if (0 != ftruncate(pid_fd, 0)) {
430010c2894SGlenn Strauss log_perror(srv->errh, __FILE__, __LINE__,
431010c2894SGlenn Strauss "ftruncate failed for: %s", srv->srvconf.pid_file->ptr);
432c92b1762SKyle J. McKay }
433c92b1762SKyle J. McKay }
4346c1e6e66SGlenn Strauss if (0 <= pid_fd) {
4356c1e6e66SGlenn Strauss close(pid_fd);
4366c1e6e66SGlenn Strauss pid_fd = -1;
437c92b1762SKyle J. McKay }
438af3df29aSGlenn Strauss if (srv->srvconf.pid_file && !srv->srvconf.changeroot) {
439c92b1762SKyle J. McKay if (0 != unlink(srv->srvconf.pid_file->ptr)) {
440c92b1762SKyle J. McKay if (errno != EACCES && errno != EPERM) {
441010c2894SGlenn Strauss log_perror(srv->errh, __FILE__, __LINE__,
442010c2894SGlenn Strauss "unlink failed for: %s", srv->srvconf.pid_file->ptr);
443c92b1762SKyle J. McKay }
444c92b1762SKyle J. McKay }
445c92b1762SKyle J. McKay }
446c92b1762SKyle J. McKay }
447c92b1762SKyle J. McKay
4481812f554SGlenn Strauss
449fb9b8ad8SGlenn Strauss __attribute_cold__
server_oneshot_getsock(server * srv,sock_addr * cnt_addr)4501812f554SGlenn Strauss static server_socket * server_oneshot_getsock(server *srv, sock_addr *cnt_addr) {
4511812f554SGlenn Strauss server_socket *srv_socket, *srv_socket_wild = NULL;
45262e97967SGlenn Strauss for (uint32_t i = 0; i < srv->srv_sockets.used; ++i) {
4531812f554SGlenn Strauss srv_socket = srv->srv_sockets.ptr[i];
4541367f606SGlenn Strauss if (!sock_addr_is_port_eq(&srv_socket->addr,cnt_addr)) continue;
4551367f606SGlenn Strauss if (sock_addr_is_addr_eq(&srv_socket->addr,cnt_addr)) return srv_socket;
4561367f606SGlenn Strauss
4571367f606SGlenn Strauss if (NULL != srv_socket_wild) continue;
4581367f606SGlenn Strauss if (sock_addr_is_addr_wildcard(&srv_socket->addr)) {
4591812f554SGlenn Strauss srv_socket_wild = srv_socket;
4601812f554SGlenn Strauss }
4611812f554SGlenn Strauss }
4621812f554SGlenn Strauss
4631812f554SGlenn Strauss if (NULL != srv_socket_wild) {
4641812f554SGlenn Strauss return srv_socket_wild;
4651812f554SGlenn Strauss } else if (srv->srv_sockets.used) {
4661812f554SGlenn Strauss return srv->srv_sockets.ptr[0];
4671812f554SGlenn Strauss } else {
468010c2894SGlenn Strauss log_error(srv->errh, __FILE__, __LINE__, "no sockets configured");
4691812f554SGlenn Strauss return NULL;
4701812f554SGlenn Strauss }
4711812f554SGlenn Strauss }
4721812f554SGlenn Strauss
4731812f554SGlenn Strauss
server_oneshot_read_cq(connection * con,chunkqueue * cq,off_t max_bytes)474ed297e7eSGlenn Strauss static int server_oneshot_read_cq(connection *con, chunkqueue *cq, off_t max_bytes) {
475ed297e7eSGlenn Strauss /* temporary set con->fd to oneshot_fd (fd input) rather than outshot_fdout
476ed297e7eSGlenn Strauss * (lighttpd generally assumes operation on sockets, so this is a kludge) */
477ed297e7eSGlenn Strauss int fd = con->fd;
478716e4d7aSGlenn Strauss con->fd = oneshot_fdn->fd;
479ed297e7eSGlenn Strauss int rc = oneshot_read_cq(con, cq, max_bytes);
480ed297e7eSGlenn Strauss con->fd = fd;
481ed297e7eSGlenn Strauss
482ed297e7eSGlenn Strauss /* note: optimistic reads (elsewhere) may or may not be enough to re-enable
483ed297e7eSGlenn Strauss * read interest after FDEVENT_IN interest was paused for other reasons */
484ed297e7eSGlenn Strauss
485ed297e7eSGlenn Strauss const int events = fdevent_fdnode_interest(oneshot_fdn);
486fcbfc083SGlenn Strauss int n = con->is_readable > 0 ? 0 : FDEVENT_IN;
487ed297e7eSGlenn Strauss if (events & FDEVENT_RDHUP)
488ed297e7eSGlenn Strauss n |= FDEVENT_RDHUP;
489ed297e7eSGlenn Strauss fdevent_fdnode_event_set(con->srv->ev, oneshot_fdn, n);
490ed297e7eSGlenn Strauss return rc;
491ed297e7eSGlenn Strauss }
492ed297e7eSGlenn Strauss
493ed297e7eSGlenn Strauss
server_oneshot_handle_fdevent(void * context,int revents)494ed297e7eSGlenn Strauss static handler_t server_oneshot_handle_fdevent(void *context, int revents) {
495ed297e7eSGlenn Strauss connection *con = context;
496ed297e7eSGlenn Strauss
497ed297e7eSGlenn Strauss /* note: not sync'd with con->fdn or connection_set_fdevent_interest() */
498ed297e7eSGlenn Strauss int rdhup = 0;
499ed297e7eSGlenn Strauss int n = fdevent_fdnode_interest(oneshot_fdn);
500ed297e7eSGlenn Strauss if (revents & FDEVENT_IN)
501ed297e7eSGlenn Strauss n &= ~FDEVENT_IN;
502ed297e7eSGlenn Strauss request_st * const r = &con->request;
503ed297e7eSGlenn Strauss if (r->state != CON_STATE_ERROR && (revents & (FDEVENT_HUP|FDEVENT_RDHUP))){
504ed297e7eSGlenn Strauss revents &= ~(FDEVENT_HUP|FDEVENT_RDHUP);
505ed297e7eSGlenn Strauss /* copied and modified from connection_handle_fdevent()
506ed297e7eSGlenn Strauss * fdevent_is_tcp_half_closed() will fail on pipe
507ed297e7eSGlenn Strauss * and, besides, read end of pipes should treat POLLHUP as POLLRDHUP */
508ed297e7eSGlenn Strauss n &= ~(FDEVENT_IN|FDEVENT_RDHUP);
509ed297e7eSGlenn Strauss rdhup = 1;
510ed297e7eSGlenn Strauss }
511ed297e7eSGlenn Strauss fdevent_fdnode_event_set(con->srv->ev, oneshot_fdn, n);
512ed297e7eSGlenn Strauss
513ed297e7eSGlenn Strauss fdnode * const fdn = con->fdn; /* fdn->ctx == con */
5145ca9eca8SGlenn Strauss handler_t rc = (fdn && (fdevent_handler)NULL != fdn->handler)
515ed297e7eSGlenn Strauss ? (*fdn->handler)(con, revents)
516ed297e7eSGlenn Strauss : HANDLER_FINISHED;
517ed297e7eSGlenn Strauss
518ed297e7eSGlenn Strauss if (rdhup) {
519ed297e7eSGlenn Strauss r->conf.stream_request_body &=
520ed297e7eSGlenn Strauss ~(FDEVENT_STREAM_REQUEST_BUFMIN|FDEVENT_STREAM_REQUEST_POLLIN);
521ed297e7eSGlenn Strauss r->conf.stream_request_body |= FDEVENT_STREAM_REQUEST_POLLRDHUP;
522ed297e7eSGlenn Strauss r->conf.stream_request_body |= FDEVENT_STREAM_REQUEST_TCP_FIN;
523ed297e7eSGlenn Strauss con->is_readable = 1; /*(can read 0 for end-of-stream)*/
524ed297e7eSGlenn Strauss if (chunkqueue_is_empty(con->read_queue)) r->keep_alive = 0;
525ed297e7eSGlenn Strauss if (r->reqbody_length < -1) /*(transparent proxy mode; no more data)*/
52681029b8bSGlenn Strauss r->reqbody_length = r->reqbody_queue.bytes_in;
527ed297e7eSGlenn Strauss }
528ed297e7eSGlenn Strauss
529ed297e7eSGlenn Strauss return rc;
530ed297e7eSGlenn Strauss }
531ed297e7eSGlenn Strauss
532ed297e7eSGlenn Strauss
533fb9b8ad8SGlenn Strauss __attribute_cold__
server_oneshot_init_pipe(server * srv,int fdin,int fdout)534ed297e7eSGlenn Strauss static int server_oneshot_init_pipe(server *srv, int fdin, int fdout) {
535ed297e7eSGlenn Strauss /* Note: attempt to work with netcat pipes though other code expects socket.
536ed297e7eSGlenn Strauss * netcat has different fds (pipes) for stdin and stdout. To support
537ed297e7eSGlenn Strauss * netcat, need to avoid S_ISSOCK(), getsockname(), and getpeername(),
538ed297e7eSGlenn Strauss * reconstructing addresses from environment variables:
5391812f554SGlenn Strauss * NCAT_LOCAL_ADDR NCAT_LOCAL_PORT
5401812f554SGlenn Strauss * NCAT_REMOTE_ADDR NCAT_REMOTE_PORT
541ed297e7eSGlenn Strauss * NCAT_PROTO (TCP, UDP, SCTP)
5421812f554SGlenn Strauss */
5431812f554SGlenn Strauss connection *con;
544924d3c9bSGlenn Strauss const server_socket *srv_socket;
5451812f554SGlenn Strauss sock_addr cnt_addr;
546ed297e7eSGlenn Strauss
547ed297e7eSGlenn Strauss /* detect if called from netcat or else fabricate localhost addrs */
548ed297e7eSGlenn Strauss const char * const ncat =
549ed297e7eSGlenn Strauss getenv("NCAT_LOCAL_ADDR");
550ed297e7eSGlenn Strauss const char * const ncat_local_addr =
551ed297e7eSGlenn Strauss ncat ? ncat : "127.0.0.1"; /*(fabricated)*/
552ed297e7eSGlenn Strauss const char * const ncat_local_port =
553ed297e7eSGlenn Strauss ncat ? getenv("NCAT_LOCAL_PORT") : "80"; /*(fabricated)*/
554ed297e7eSGlenn Strauss const char * const ncat_remote_addr =
555ed297e7eSGlenn Strauss ncat ? getenv("NCAT_REMOTE_ADDR") : "127.0.0.1"; /*(fabricated)*/
556ed297e7eSGlenn Strauss const char * const ncat_remote_port =
557ed297e7eSGlenn Strauss ncat ? getenv("NCAT_REMOTE_PORT") : "48080"; /*(fabricated)*/
558ed297e7eSGlenn Strauss if (NULL == ncat_local_addr || NULL == ncat_local_port) return 0;
559ed297e7eSGlenn Strauss if (NULL == ncat_remote_addr || NULL == ncat_remote_port) return 0;
560ed297e7eSGlenn Strauss
561ed297e7eSGlenn Strauss const int family = ncat && strchr(ncat_local_addr,':') ? AF_INET6 : AF_INET;
562ed297e7eSGlenn Strauss unsigned short port;
563ed297e7eSGlenn Strauss
564ed297e7eSGlenn Strauss port = (unsigned short)strtol(ncat_local_port, NULL, 10);
565ed297e7eSGlenn Strauss if (1 != sock_addr_inet_pton(&cnt_addr, ncat_local_addr, family, port)) {
566ed297e7eSGlenn Strauss log_error(srv->errh, __FILE__, __LINE__, "invalid local addr");
567ed297e7eSGlenn Strauss return 0;
568ed297e7eSGlenn Strauss }
569ed297e7eSGlenn Strauss
570ed297e7eSGlenn Strauss srv_socket = server_oneshot_getsock(srv, &cnt_addr);
571ed297e7eSGlenn Strauss if (NULL == srv_socket) return 0;
572ed297e7eSGlenn Strauss
573ed297e7eSGlenn Strauss port = (unsigned short)strtol(ncat_remote_port, NULL, 10);
574ed297e7eSGlenn Strauss if (1 != sock_addr_inet_pton(&cnt_addr, ncat_remote_addr, family, port)) {
575ed297e7eSGlenn Strauss log_error(srv->errh, __FILE__, __LINE__, "invalid remote addr");
576ed297e7eSGlenn Strauss return 0;
577ed297e7eSGlenn Strauss }
578ed297e7eSGlenn Strauss
579ed297e7eSGlenn Strauss /*(must set flags; fd did not pass through fdevent accept() logic)*/
580ed297e7eSGlenn Strauss if (-1 == fdevent_fcntl_set_nb_cloexec(fdin)) {
581ed297e7eSGlenn Strauss log_perror(srv->errh, __FILE__, __LINE__, "fcntl()");
582ed297e7eSGlenn Strauss return 0;
583ed297e7eSGlenn Strauss }
584ed297e7eSGlenn Strauss if (-1 == fdevent_fcntl_set_nb_cloexec(fdout)) {
585ed297e7eSGlenn Strauss log_perror(srv->errh, __FILE__, __LINE__, "fcntl()");
586ed297e7eSGlenn Strauss return 0;
587ed297e7eSGlenn Strauss }
588ed297e7eSGlenn Strauss
589ed297e7eSGlenn Strauss con = connection_accepted(srv, srv_socket, &cnt_addr, fdout);
590ed297e7eSGlenn Strauss if (NULL == con) return 0;
591ed297e7eSGlenn Strauss
592ed297e7eSGlenn Strauss /* note: existing routines assume socket, not pipe
593ed297e7eSGlenn Strauss * connections.c:connection_read_cq()
594ed297e7eSGlenn Strauss * uses recv() ifdef __WIN32
595ed297e7eSGlenn Strauss * passes S_IFSOCK to fdevent_ioctl_fionread()
596ed297e7eSGlenn Strauss * (The routine could be copied and modified, if required)
597ed297e7eSGlenn Strauss * This is unlikely to work if TLS is used over pipe since the SSL_CTX
598ed297e7eSGlenn Strauss * is associated with the other end of the pipe. However, if using
599ed297e7eSGlenn Strauss * pipes, using TLS is unexpected behavior.
600ed297e7eSGlenn Strauss */
601ed297e7eSGlenn Strauss
602ed297e7eSGlenn Strauss /*assert(oneshot_fd == fdin);*/
603ed297e7eSGlenn Strauss oneshot_read_cq = con->network_read;
604ed297e7eSGlenn Strauss con->network_read = server_oneshot_read_cq;
605ed297e7eSGlenn Strauss oneshot_fdn =
606ed297e7eSGlenn Strauss fdevent_register(srv->ev, fdin, server_oneshot_handle_fdevent, con);
607ed297e7eSGlenn Strauss fdevent_fdnode_event_set(srv->ev, oneshot_fdn, FDEVENT_RDHUP);
608ed297e7eSGlenn Strauss
609ed297e7eSGlenn Strauss connection_state_machine(con);
610ed297e7eSGlenn Strauss return 1;
611ed297e7eSGlenn Strauss }
612ed297e7eSGlenn Strauss
613ed297e7eSGlenn Strauss
614ed297e7eSGlenn Strauss __attribute_cold__
server_oneshot_init(server * srv,int fd)615ed297e7eSGlenn Strauss static int server_oneshot_init(server *srv, int fd) {
616ed297e7eSGlenn Strauss connection *con;
617924d3c9bSGlenn Strauss const server_socket *srv_socket;
618ed297e7eSGlenn Strauss sock_addr cnt_addr;
6191812f554SGlenn Strauss socklen_t cnt_len;
6201812f554SGlenn Strauss
6211812f554SGlenn Strauss cnt_len = sizeof(cnt_addr);
6221812f554SGlenn Strauss if (0 != getsockname(fd, (struct sockaddr *)&cnt_addr, &cnt_len)) {
623010c2894SGlenn Strauss log_perror(srv->errh, __FILE__, __LINE__, "getsockname()");
6241812f554SGlenn Strauss return 0;
6251812f554SGlenn Strauss }
6261812f554SGlenn Strauss
6271812f554SGlenn Strauss srv_socket = server_oneshot_getsock(srv, &cnt_addr);
6281812f554SGlenn Strauss if (NULL == srv_socket) return 0;
6291812f554SGlenn Strauss
63028f1867cSGlenn Strauss #ifdef __clang_analyzer__
63128f1867cSGlenn Strauss memset(&cnt_addr, 0, sizeof(cnt_addr));
63228f1867cSGlenn Strauss #endif
6331812f554SGlenn Strauss cnt_len = sizeof(cnt_addr);
6341812f554SGlenn Strauss if (0 != getpeername(fd, (struct sockaddr *)&cnt_addr, &cnt_len)) {
635010c2894SGlenn Strauss log_perror(srv->errh, __FILE__, __LINE__, "getpeername()");
6361812f554SGlenn Strauss return 0;
6371812f554SGlenn Strauss }
6381812f554SGlenn Strauss
639c23f8fddSGlenn Strauss /*(must set flags; fd did not pass through fdevent accept() logic)*/
64048004c6aSGlenn Strauss if (-1 == fdevent_fcntl_set_nb_cloexec(fd)) {
641010c2894SGlenn Strauss log_perror(srv->errh, __FILE__, __LINE__, "fcntl()");
6426def094cSGlenn Strauss return 0;
6436def094cSGlenn Strauss }
644c23f8fddSGlenn Strauss
6451367f606SGlenn Strauss if (sock_addr_get_family(&cnt_addr) != AF_UNIX) {
646416b5729SGlenn Strauss network_accept_tcp_nagle_disable(fd);
647416b5729SGlenn Strauss }
648416b5729SGlenn Strauss
6491812f554SGlenn Strauss con = connection_accepted(srv, srv_socket, &cnt_addr, fd);
6501812f554SGlenn Strauss if (NULL == con) return 0;
6511812f554SGlenn Strauss
652b5775b99SGlenn Strauss connection_state_machine(con);
6531812f554SGlenn Strauss return 1;
6541812f554SGlenn Strauss }
6551812f554SGlenn Strauss
6561812f554SGlenn Strauss
657fb9b8ad8SGlenn Strauss __attribute_cold__
show_version(void)658bcdc6a3bSJan Kneschke static void show_version (void) {
659638ee6caSStefan Bühler char *b = PACKAGE_DESC TEXT_SSL \
660cddc4814SGlenn Strauss " - a light and fast webserver\n"
661cddc4814SGlenn Strauss #ifdef NONREPRODUCIBLE_BUILD
662bcdc6a3bSJan Kneschke "Build-Date: " __DATE__ " " __TIME__ "\n";
663cddc4814SGlenn Strauss #endif
664bcdc6a3bSJan Kneschke ;
6650508bf67SStefan Bühler write_all(STDOUT_FILENO, b, strlen(b));
666bcdc6a3bSJan Kneschke }
667bcdc6a3bSJan Kneschke
668fb9b8ad8SGlenn Strauss __attribute_cold__
show_features(void)669cf252711SJan Kneschke static void show_features (void) {
670142971a8SGlenn Strauss static const char features[] =
671cf252711SJan Kneschke "\nFeatures:\n\n"
672cf252711SJan Kneschke #ifdef HAVE_IPV6
673cf252711SJan Kneschke "\t+ IPv6 support\n"
674cf252711SJan Kneschke #else
675cf252711SJan Kneschke "\t- IPv6 support\n"
676cf252711SJan Kneschke #endif
677cf252711SJan Kneschke #if defined HAVE_ZLIB_H && defined HAVE_LIBZ
678cf252711SJan Kneschke "\t+ zlib support\n"
679cf252711SJan Kneschke #else
680cf252711SJan Kneschke "\t- zlib support\n"
681cf252711SJan Kneschke #endif
6829211fb3dSGlenn Strauss #if defined HAVE_ZSTD_H && defined HAVE_ZSTD
6839211fb3dSGlenn Strauss "\t+ zstd support\n"
6849211fb3dSGlenn Strauss #else
6859211fb3dSGlenn Strauss "\t- zstd support\n"
6869211fb3dSGlenn Strauss #endif
687cf252711SJan Kneschke #if defined HAVE_BZLIB_H && defined HAVE_LIBBZ2
688cf252711SJan Kneschke "\t+ bzip2 support\n"
689cf252711SJan Kneschke #else
690cf252711SJan Kneschke "\t- bzip2 support\n"
691cf252711SJan Kneschke #endif
6928d5e237cSGlenn Strauss #if defined HAVE_BROTLI_ENCODE_H && defined HAVE_BROTLI
6938d5e237cSGlenn Strauss "\t+ brotli support\n"
6948d5e237cSGlenn Strauss #else
6958d5e237cSGlenn Strauss "\t- brotli support\n"
6968d5e237cSGlenn Strauss #endif
697c7c34201SGlenn Strauss #if defined(HAVE_CRYPT) || defined(HAVE_CRYPT_R)
698cf252711SJan Kneschke "\t+ crypt support\n"
699cf252711SJan Kneschke #else
700cf252711SJan Kneschke "\t- crypt support\n"
701cf252711SJan Kneschke #endif
702cb753ec5SGlenn Strauss #ifdef USE_OPENSSL_CRYPTO
703cb753ec5SGlenn Strauss "\t+ OpenSSL support\n"
704cf252711SJan Kneschke #else
705cb753ec5SGlenn Strauss "\t- OpenSSL support\n"
706cb753ec5SGlenn Strauss #endif
707cb753ec5SGlenn Strauss #ifdef USE_MBEDTLS_CRYPTO
708cb753ec5SGlenn Strauss "\t+ mbedTLS support\n"
709cb753ec5SGlenn Strauss #else
710cb753ec5SGlenn Strauss "\t- mbedTLS support\n"
711cf252711SJan Kneschke #endif
712e00deb55SGlenn Strauss #ifdef USE_NSS_CRYPTO
713e00deb55SGlenn Strauss "\t+ NSS crypto support\n"
714e00deb55SGlenn Strauss #else
715e00deb55SGlenn Strauss "\t- NSS crypto support\n"
716e00deb55SGlenn Strauss #endif
717bf4054f8SGlenn Strauss #ifdef USE_GNUTLS_CRYPTO
718bf4054f8SGlenn Strauss "\t+ GnuTLS support\n"
719bf4054f8SGlenn Strauss #else
720bf4054f8SGlenn Strauss "\t- GnuTLS support\n"
721bf4054f8SGlenn Strauss #endif
72298a224a4SGlenn Strauss #ifdef USE_WOLFSSL_CRYPTO
72398a224a4SGlenn Strauss "\t+ WolfSSL support\n"
72498a224a4SGlenn Strauss #else
72598a224a4SGlenn Strauss "\t- WolfSSL support\n"
72698a224a4SGlenn Strauss #endif
727bf4054f8SGlenn Strauss #ifdef USE_NETTLE_CRYPTO
728bf4054f8SGlenn Strauss "\t+ Nettle support\n"
729bf4054f8SGlenn Strauss #else
730bf4054f8SGlenn Strauss "\t- Nettle support\n"
731bf4054f8SGlenn Strauss #endif
7327512d82cSGlenn Strauss #ifdef HAVE_PCRE
733cf252711SJan Kneschke "\t+ PCRE support\n"
734cf252711SJan Kneschke #else
735cf252711SJan Kneschke "\t- PCRE support\n"
736cf252711SJan Kneschke #endif
737cf252711SJan Kneschke #ifdef HAVE_MYSQL
7381c1a6378SGlenn Strauss "\t+ MySQL support\n"
739cf252711SJan Kneschke #else
7401c1a6378SGlenn Strauss "\t- MySQL support\n"
7411c1a6378SGlenn Strauss #endif
7422f83aac9SGlenn Strauss #ifdef HAVE_PGSQL
7432f83aac9SGlenn Strauss "\t+ PgSQL support\n"
7442f83aac9SGlenn Strauss #else
7452f83aac9SGlenn Strauss "\t- PgSQL support\n"
7462f83aac9SGlenn Strauss #endif
7472f83aac9SGlenn Strauss #ifdef HAVE_DBI
7482f83aac9SGlenn Strauss "\t+ DBI support\n"
7492f83aac9SGlenn Strauss #else
7502f83aac9SGlenn Strauss "\t- DBI support\n"
7512f83aac9SGlenn Strauss #endif
7521c1a6378SGlenn Strauss #ifdef HAVE_KRB5
7531c1a6378SGlenn Strauss "\t+ Kerberos support\n"
7541c1a6378SGlenn Strauss #else
7551c1a6378SGlenn Strauss "\t- Kerberos support\n"
756cf252711SJan Kneschke #endif
757cf252711SJan Kneschke #if defined(HAVE_LDAP_H) && defined(HAVE_LBER_H) && defined(HAVE_LIBLDAP) && defined(HAVE_LIBLBER)
758cf252711SJan Kneschke "\t+ LDAP support\n"
759cf252711SJan Kneschke #else
760cf252711SJan Kneschke "\t- LDAP support\n"
761cf252711SJan Kneschke #endif
762df4812ecSGlenn Strauss #ifdef HAVE_PAM
763df4812ecSGlenn Strauss "\t+ PAM support\n"
764df4812ecSGlenn Strauss #else
765df4812ecSGlenn Strauss "\t- PAM support\n"
766df4812ecSGlenn Strauss #endif
767cf252711SJan Kneschke #ifdef HAVE_FAM_H
768cf252711SJan Kneschke "\t+ FAM support\n"
769cf252711SJan Kneschke #else
770cf252711SJan Kneschke "\t- FAM support\n"
771cf252711SJan Kneschke #endif
772cf252711SJan Kneschke #ifdef HAVE_LUA_H
773cf252711SJan Kneschke "\t+ LUA support\n"
774cf252711SJan Kneschke #else
775cf252711SJan Kneschke "\t- LUA support\n"
776cf252711SJan Kneschke #endif
777cf252711SJan Kneschke #ifdef HAVE_LIBXML_H
778cf252711SJan Kneschke "\t+ xml support\n"
779cf252711SJan Kneschke #else
780cf252711SJan Kneschke "\t- xml support\n"
781cf252711SJan Kneschke #endif
782cf252711SJan Kneschke #ifdef HAVE_SQLITE3_H
783cf252711SJan Kneschke "\t+ SQLite support\n"
784cf252711SJan Kneschke #else
785cf252711SJan Kneschke "\t- SQLite support\n"
786cf252711SJan Kneschke #endif
787142971a8SGlenn Strauss ;
788d9cb3878SMarcus Rückert show_version();
7893ce554e1SGlenn Strauss printf("%s%s%s%s\n",
7903ce554e1SGlenn Strauss fdevent_show_event_handlers(),
7913ce554e1SGlenn Strauss network_write_show_handlers(),
7923ce554e1SGlenn Strauss features,
7933ce554e1SGlenn Strauss sizeof(time_t) > 4 || (sizeof(time_t) == 4 && (time_t)-1 > (time_t)1)
7943ce554e1SGlenn Strauss ? "\t+ Y2038 support\n"
7953ce554e1SGlenn Strauss : "\t- Y2038 support (unsafe 32-bit signed time_t)\n");
796cf252711SJan Kneschke }
797cf252711SJan Kneschke
798fb9b8ad8SGlenn Strauss __attribute_cold__
show_help(void)799bcdc6a3bSJan Kneschke static void show_help (void) {
800cddc4814SGlenn Strauss char *b = PACKAGE_DESC TEXT_SSL
801cddc4814SGlenn Strauss #ifdef NONREPRODUCIBLE_BUILD
802cddc4814SGlenn Strauss " ("__DATE__ " " __TIME__ ")"
803cddc4814SGlenn Strauss #endif
804bcdc6a3bSJan Kneschke " - a light and fast webserver\n" \
805bcdc6a3bSJan Kneschke "usage:\n" \
806bcdc6a3bSJan Kneschke " -f <name> filename of the config-file\n" \
807c7ec5012SJan Kneschke " -m <name> module directory (default: "LIBRARY_DIR")\n" \
80806b87deeSGlenn Strauss " -i <secs> graceful shutdown after <secs> of inactivity\n" \
8091812f554SGlenn Strauss " -1 process single (one) request on stdin socket, then exit\n" \
810bcbafe63SJan Kneschke " -p print the parsed config-file in internal form, and exit\n" \
811a83bae5bSGlenn Strauss " -t test config-file syntax, then exit\n" \
812a83bae5bSGlenn Strauss " -tt test config-file syntax, load and init modules, then exit\n" \
813bcdc6a3bSJan Kneschke " -D don't go to background (default: go to background)\n" \
814bcdc6a3bSJan Kneschke " -v show version\n" \
815cf252711SJan Kneschke " -V show compile-time features\n" \
816bcdc6a3bSJan Kneschke " -h show this help\n" \
817bcdc6a3bSJan Kneschke "\n"
818bcdc6a3bSJan Kneschke ;
8190508bf67SStefan Bühler write_all(STDOUT_FILENO, b, strlen(b));
820bcdc6a3bSJan Kneschke }
821bcdc6a3bSJan Kneschke
822fb9b8ad8SGlenn Strauss __attribute_cold__
8236800b082SGlenn Strauss __attribute_noinline__
server_sockets_save(server * srv)8246c1e6e66SGlenn Strauss static void server_sockets_save (server *srv) { /* graceful_restart */
8253baef447SGlenn Strauss for (uint32_t i = 0; i < srv->srv_sockets.used; ++i)
8263baef447SGlenn Strauss srv->srv_sockets.ptr[i]->srv = NULL; /* srv will shortly be invalid */
8273baef447SGlenn Strauss for (uint32_t i = 0; i < srv->srv_sockets_inherited.used; ++i)
8283baef447SGlenn Strauss srv->srv_sockets_inherited.ptr[i]->srv = NULL; /* srv to be invalid */
8296c1e6e66SGlenn Strauss memcpy(&graceful_sockets, &srv->srv_sockets, sizeof(server_socket_array));
8306c1e6e66SGlenn Strauss memset(&srv->srv_sockets, 0, sizeof(server_socket_array));
831ce7b47c0SGlenn Strauss memcpy(&inherited_sockets, &srv->srv_sockets_inherited, sizeof(server_socket_array));
832ce7b47c0SGlenn Strauss memset(&srv->srv_sockets_inherited, 0, sizeof(server_socket_array));
8336c1e6e66SGlenn Strauss }
8346c1e6e66SGlenn Strauss
835fb9b8ad8SGlenn Strauss __attribute_cold__
8366800b082SGlenn Strauss __attribute_noinline__
server_sockets_restore(server * srv)8376c1e6e66SGlenn Strauss static void server_sockets_restore (server *srv) { /* graceful_restart */
8386c1e6e66SGlenn Strauss memcpy(&srv->srv_sockets, &graceful_sockets, sizeof(server_socket_array));
8396c1e6e66SGlenn Strauss memset(&graceful_sockets, 0, sizeof(server_socket_array));
840ce7b47c0SGlenn Strauss memcpy(&srv->srv_sockets_inherited, &inherited_sockets, sizeof(server_socket_array));
841ce7b47c0SGlenn Strauss memset(&inherited_sockets, 0, sizeof(server_socket_array));
842da8025fbSGlenn Strauss for (uint32_t i = 0; i < srv->srv_sockets.used; ++i) {
8433baef447SGlenn Strauss srv->srv_sockets.ptr[i]->srv = srv; /* update ptr */
844da8025fbSGlenn Strauss srv->srv_sockets.ptr[i]->sidx= (unsigned short)~0u;
845da8025fbSGlenn Strauss }
8463baef447SGlenn Strauss for (uint32_t i = 0; i < srv->srv_sockets_inherited.used; ++i)
8473baef447SGlenn Strauss srv->srv_sockets_inherited.ptr[i]->srv = srv; /* update ptr */
8486c1e6e66SGlenn Strauss }
8496c1e6e66SGlenn Strauss
850fb9b8ad8SGlenn Strauss __attribute_cold__
server_sockets_set_nb_cloexec(server * srv)8516c1e6e66SGlenn Strauss static int server_sockets_set_nb_cloexec (server *srv) {
8526c1e6e66SGlenn Strauss if (srv->sockets_disabled) return 0; /* lighttpd -1 (one-shot mode) */
85362e97967SGlenn Strauss for (uint32_t i = 0; i < srv->srv_sockets.used; ++i) {
8546c1e6e66SGlenn Strauss server_socket *srv_socket = srv->srv_sockets.ptr[i];
85548004c6aSGlenn Strauss if (-1 == fdevent_fcntl_set_nb_cloexec_sock(srv_socket->fd)) {
856010c2894SGlenn Strauss log_perror(srv->errh, __FILE__, __LINE__, "fcntl()");
8576c1e6e66SGlenn Strauss return -1;
8586c1e6e66SGlenn Strauss }
8596c1e6e66SGlenn Strauss }
8606c1e6e66SGlenn Strauss return 0;
8616c1e6e66SGlenn Strauss }
8626c1e6e66SGlenn Strauss
863fb9b8ad8SGlenn Strauss __attribute_cold__
server_sockets_set_event(server * srv,int event)8646c1e6e66SGlenn Strauss static void server_sockets_set_event (server *srv, int event) {
86562e97967SGlenn Strauss for (uint32_t i = 0; i < srv->srv_sockets.used; ++i) {
8666c1e6e66SGlenn Strauss server_socket *srv_socket = srv->srv_sockets.ptr[i];
8679113011dSGlenn Strauss fdevent_fdnode_event_set(srv->ev, srv_socket->fdn, event);
8686c1e6e66SGlenn Strauss }
8696c1e6e66SGlenn Strauss }
8706c1e6e66SGlenn Strauss
871fb9b8ad8SGlenn Strauss __attribute_cold__
server_sockets_unregister(server * srv)8726c1e6e66SGlenn Strauss static void server_sockets_unregister (server *srv) {
873800e9b73SGlenn Strauss if (2 == srv->sockets_disabled) return;
874800e9b73SGlenn Strauss srv->sockets_disabled = 2;
87562e97967SGlenn Strauss for (uint32_t i = 0; i < srv->srv_sockets.used; ++i)
8766c1e6e66SGlenn Strauss network_unregister_sock(srv, srv->srv_sockets.ptr[i]);
8776c1e6e66SGlenn Strauss }
8786c1e6e66SGlenn Strauss
879fb9b8ad8SGlenn Strauss __attribute_cold__
server_sockets_close(server * srv)8806c1e6e66SGlenn Strauss static void server_sockets_close (server *srv) {
8816c1e6e66SGlenn Strauss /* closing socket right away will make it possible for the next lighttpd
8826c1e6e66SGlenn Strauss * to take over (old-style graceful restart), but only if backends
8836c1e6e66SGlenn Strauss * (e.g. fastcgi, scgi, etc) are independent from lighttpd, rather
8846c1e6e66SGlenn Strauss * than started by lighttpd via "bin-path")
8856c1e6e66SGlenn Strauss */
886800e9b73SGlenn Strauss if (3 == srv->sockets_disabled) return;
88762e97967SGlenn Strauss for (uint32_t i = 0; i < srv->srv_sockets.used; ++i) {
8886c1e6e66SGlenn Strauss server_socket *srv_socket = srv->srv_sockets.ptr[i];
8896c1e6e66SGlenn Strauss if (-1 == srv_socket->fd) continue;
890800e9b73SGlenn Strauss if (2 != srv->sockets_disabled) network_unregister_sock(srv,srv_socket);
8916c1e6e66SGlenn Strauss close(srv_socket->fd);
8926c1e6e66SGlenn Strauss srv_socket->fd = -1;
8936c1e6e66SGlenn Strauss /* network_close() will cleanup after us */
8946c1e6e66SGlenn Strauss }
895800e9b73SGlenn Strauss srv->sockets_disabled = 3;
8966c1e6e66SGlenn Strauss }
8976c1e6e66SGlenn Strauss
898fb9b8ad8SGlenn Strauss __attribute_cold__
server_graceful_signal_prev_generation(void)899fc6612d7SGlenn Strauss static void server_graceful_signal_prev_generation (void)
900fc6612d7SGlenn Strauss {
901fc6612d7SGlenn Strauss const char * const prev_gen = getenv("LIGHTTPD_PREV_GEN");
902fc6612d7SGlenn Strauss if (NULL == prev_gen) return;
903fc6612d7SGlenn Strauss pid_t pid = (pid_t)strtol(prev_gen, NULL, 10);
904fc6612d7SGlenn Strauss unsetenv("LIGHTTPD_PREV_GEN");
905fc6612d7SGlenn Strauss if (pid <= 0) return; /*(should not happen)*/
90629f50bdeSGlenn Strauss if (pid == fdevent_waitpid(pid,NULL,1)) return; /*(pid exited; unexpected)*/
907fc6612d7SGlenn Strauss kill(pid, SIGINT); /* signal previous generation for graceful shutdown */
908fc6612d7SGlenn Strauss }
909fc6612d7SGlenn Strauss
910fc6612d7SGlenn Strauss __attribute_cold__
server_graceful_state_bg(server * srv)911352d5d77SGlenn Strauss static int server_graceful_state_bg (server *srv) {
912352d5d77SGlenn Strauss /*assert(graceful_restart);*/
913352d5d77SGlenn Strauss /*(SIGUSR1 set to SIG_IGN in workers, so should not reach here if worker)*/
914352d5d77SGlenn Strauss if (srv_shutdown) return 0;
915352d5d77SGlenn Strauss
916352d5d77SGlenn Strauss /* check if server should fork and background (bg) itself
917352d5d77SGlenn Strauss * to continue processing requests already in progress */
9184d99d9b7SGlenn Strauss if (!config_feature_bool(srv, "server.graceful-restart-bg", 0)) return 0;
9194d99d9b7SGlenn Strauss
9204d99d9b7SGlenn Strauss /*(set flag to false to avoid repeating)*/
921352d5d77SGlenn Strauss data_unset * const du =
9220045b9aaSGlenn Strauss array_get_data_unset(srv->srvconf.feature_flags,
923352d5d77SGlenn Strauss CONST_STR_LEN("server.graceful-restart-bg"));
924352d5d77SGlenn Strauss if (du->type == TYPE_STRING)
925352d5d77SGlenn Strauss buffer_copy_string_len(&((data_string *)du)->value,
926352d5d77SGlenn Strauss CONST_STR_LEN("false"));
927352d5d77SGlenn Strauss else /* (du->type == TYPE_INTEGER) */
928352d5d77SGlenn Strauss ((data_integer *)du)->value = 0;
929352d5d77SGlenn Strauss
930352d5d77SGlenn Strauss /* require exec'd via absolute path or daemon in foreground
931352d5d77SGlenn Strauss * and exec'd with path containing '/' (e.g. "./xxxxx") */
932352d5d77SGlenn Strauss char ** const argv = srv->argv;
933352d5d77SGlenn Strauss if (0 == srv->srvconf.dont_daemonize
934352d5d77SGlenn Strauss ? argv[0][0] != '/'
935352d5d77SGlenn Strauss : NULL == strchr(argv[0], '/')) return 0;
936352d5d77SGlenn Strauss
937352d5d77SGlenn Strauss /* flush log buffers to avoid potential duplication of entries
938352d5d77SGlenn Strauss * server_handle_sighup(srv) does the following, but skip logging */
939352d5d77SGlenn Strauss plugins_call_handle_sighup(srv);
9407b615d5dSGlenn Strauss fdlog_files_cycle(srv->errh); /* reopen log files, not pipes */
941352d5d77SGlenn Strauss
942352d5d77SGlenn Strauss /* backgrounding to continue processing requests in progress */
943352d5d77SGlenn Strauss /* re-exec lighttpd in original process
944352d5d77SGlenn Strauss * Note: using path in re-exec is portable and allows lighttpd upgrade.
945352d5d77SGlenn Strauss * OTOH, getauxval() AT_EXECFD and fexecve() could be used on Linux to
946352d5d77SGlenn Strauss * re-exec without access to original executable on disk, which might be
947352d5d77SGlenn Strauss * desirable in some situations, but is not implemented here.
948352d5d77SGlenn Strauss * Alternatively, if argv[] was not available, could use readlink() on
949352d5d77SGlenn Strauss * /proc/self/exe (Linux-specific), though there are ways on many other
950352d5d77SGlenn Strauss * platforms to achieve the same:
951352d5d77SGlenn Strauss * https://stackoverflow.com/questions/1023306/finding-current-executables-path-without-proc-self-exe
952352d5d77SGlenn Strauss */
9538e1394eaSGlenn Strauss #if defined(HAVE_KQUEUE)
9548e1394eaSGlenn Strauss #if defined(__FreeBSD__) || defined(__DragonFly__)
9558e1394eaSGlenn Strauss /*(must *exclude* rfork RFFDG flag for kqueue to work across rfork)*/
9568e1394eaSGlenn Strauss pid_t pid = rfork(RFPROC);
9578e1394eaSGlenn Strauss #else
9588e1394eaSGlenn Strauss pid_t pid = -1;
9598e1394eaSGlenn Strauss if (pid < 0) {
9608e1394eaSGlenn Strauss /* kqueue is not inherited across fork
9618e1394eaSGlenn Strauss * future: fdevent kqueue and stat_cache kqueue would need to be closed,
9628e1394eaSGlenn Strauss * re-opened, and active fds re-registered. Not current done.
9638e1394eaSGlenn Strauss * Need to create some routines like fdevent_reinit_after_fork*/
9648e1394eaSGlenn Strauss log_error(srv->errh, __FILE__, __LINE__,
9658e1394eaSGlenn Strauss "server.graceful-restart-bg ignored on OpenBSD and NetBSD "
9668e1394eaSGlenn Strauss "due to limitation in kqueue inheritance and lacking rfork");
9678e1394eaSGlenn Strauss return 0;
9688e1394eaSGlenn Strauss }
9698e1394eaSGlenn Strauss #endif
9708e1394eaSGlenn Strauss #else
971352d5d77SGlenn Strauss pid_t pid = fork();
9728e1394eaSGlenn Strauss #endif
973352d5d77SGlenn Strauss if (pid) { /* original process */
974352d5d77SGlenn Strauss if (pid < 0) return 0;
975352d5d77SGlenn Strauss network_socket_activation_to_env(srv);
976fc6612d7SGlenn Strauss /* save pid of original server in environment so that it can be
977fc6612d7SGlenn Strauss * signalled by restarted server once restarted server is ready
978fc6612d7SGlenn Strauss * to accept new connections */
979fc6612d7SGlenn Strauss server_graceful_signal_prev_generation();/*(expect no prev gen active)*/
980fc6612d7SGlenn Strauss if (0 == srv->srvconf.max_worker) {
981fc6612d7SGlenn Strauss buffer * const tb = srv->tmp_buf;
982fc6612d7SGlenn Strauss buffer_clear(tb);
983fc6612d7SGlenn Strauss buffer_append_int(tb, pid);
984fc6612d7SGlenn Strauss setenv("LIGHTTPD_PREV_GEN", tb->ptr, 1);
985fc6612d7SGlenn Strauss }
98629f50bdeSGlenn Strauss /*fdevent_waitpid(pid, NULL, 0);*//* detach? */
987352d5d77SGlenn Strauss execv(argv[0], argv);
988352d5d77SGlenn Strauss _exit(1);
989352d5d77SGlenn Strauss }
990352d5d77SGlenn Strauss /* else child/grandchild */
991352d5d77SGlenn Strauss
992352d5d77SGlenn Strauss /*if (-1 == setsid()) _exit(1);*//* should we detach? */
993fc6612d7SGlenn Strauss /* Note: restarted server will fail with socket-in-use error if
994fc6612d7SGlenn Strauss * server.systemd-socket-activation not enabled in restarted server */
995fc6612d7SGlenn Strauss if (0 != srv->srvconf.max_worker)
996352d5d77SGlenn Strauss server_sockets_close(srv);/*(close before parent reaps pid in waitpid)*/
997352d5d77SGlenn Strauss /*if (0 != fork()) _exit(0);*//* should we detach? */
998352d5d77SGlenn Strauss /*(grandchild is now backgrounded and detached from original process)*/
999352d5d77SGlenn Strauss
1000352d5d77SGlenn Strauss /* XXX: might extend code to have new server.feature-flags param specify
1001352d5d77SGlenn Strauss * max lifetime before aborting remaining connections */
1002352d5d77SGlenn Strauss
1003352d5d77SGlenn Strauss /* (reached if lighttpd workers or if sole process w/o workers)
1004352d5d77SGlenn Strauss * use same code as comment elsewhere in server.c:
1005352d5d77SGlenn Strauss * make sure workers do not muck with pid-file */
1006352d5d77SGlenn Strauss if (0 <= pid_fd) {
1007352d5d77SGlenn Strauss close(pid_fd);
1008352d5d77SGlenn Strauss pid_fd = -1;
1009352d5d77SGlenn Strauss }
1010feb9b0c4SGlenn Strauss srv->srvconf.pid_file = NULL;
1011352d5d77SGlenn Strauss
1012352d5d77SGlenn Strauss /* (original process is backgrounded -- even if no active connections --
1013352d5d77SGlenn Strauss * to allow graceful shutdown tasks to be run by server and by modules) */
1014352d5d77SGlenn Strauss log_error(srv->errh, __FILE__, __LINE__,
1015352d5d77SGlenn Strauss "[note] pid %lld continuing to handle %u connection(s) in progress",
10165a58f696SGlenn Strauss (long long)getpid(), srv->srvconf.max_conns - srv->lim_conns);
1017352d5d77SGlenn Strauss
1018fc6612d7SGlenn Strauss if (0 == srv->srvconf.max_worker) {
1019fc6612d7SGlenn Strauss /* reset graceful_shutdown; wait for signal from restarted server */
1020fc6612d7SGlenn Strauss srv->graceful_expire_ts = 0;
1021fc6612d7SGlenn Strauss graceful_shutdown = 0;
1022fc6612d7SGlenn Strauss }
1023352d5d77SGlenn Strauss graceful_restart = 0;
1024352d5d77SGlenn Strauss return 1;
1025352d5d77SGlenn Strauss }
1026352d5d77SGlenn Strauss
1027352d5d77SGlenn Strauss __attribute_cold__
10282d55953eSGlenn Strauss __attribute_noinline__
server_graceful_shutdown_maint(server * srv)10292d55953eSGlenn Strauss static void server_graceful_shutdown_maint (server *srv) {
10302d55953eSGlenn Strauss if (oneshot_fd) {
10312d55953eSGlenn Strauss /* permit keep-alive on one-shot connections until graceful_expire_ts */
10322d55953eSGlenn Strauss if (!srv->graceful_expire_ts) return;
1033dbe3e236SGlenn Strauss if (srv->graceful_expire_ts >= log_monotonic_secs) return;
10342d55953eSGlenn Strauss }
10352d55953eSGlenn Strauss connection_graceful_shutdown_maint(srv);
10362d55953eSGlenn Strauss }
10372d55953eSGlenn Strauss
10382d55953eSGlenn Strauss __attribute_cold__
103950a27431SGlenn Strauss __attribute_noinline__
server_graceful_state(server * srv)10406c1e6e66SGlenn Strauss static void server_graceful_state (server *srv) {
10416c1e6e66SGlenn Strauss
104294c4c637SGlenn Strauss if (!srv_shutdown) {
10434d99d9b7SGlenn Strauss if (0 == srv->graceful_expire_ts) {
10444d99d9b7SGlenn Strauss srv->graceful_expire_ts =
1045d5872659SGlenn Strauss config_feature_int(srv, "server.graceful-shutdown-timeout", 8);
104694c4c637SGlenn Strauss if (srv->graceful_expire_ts)
1047dbe3e236SGlenn Strauss srv->graceful_expire_ts += log_monotonic_secs;
104894c4c637SGlenn Strauss }
10492d55953eSGlenn Strauss server_graceful_shutdown_maint(srv);
105094c4c637SGlenn Strauss }
10516c1e6e66SGlenn Strauss
1052f279ae7dSGlenn Strauss if (2 == srv->sockets_disabled || 3 == srv->sockets_disabled) {
1053f279ae7dSGlenn Strauss if (oneshot_fd) graceful_restart = 0;
1054f279ae7dSGlenn Strauss return;
1055f279ae7dSGlenn Strauss }
10566c1e6e66SGlenn Strauss
1057010c2894SGlenn Strauss log_error(srv->errh,__FILE__,__LINE__,"[note] graceful shutdown started");
10586c1e6e66SGlenn Strauss
10596c1e6e66SGlenn Strauss /* no graceful restart if chroot()ed, if oneshot mode, or if idle timeout */
1060af3df29aSGlenn Strauss if (srv->srvconf.changeroot || oneshot_fd || 2 == graceful_shutdown)
10616c1e6e66SGlenn Strauss graceful_restart = 0;
10626c1e6e66SGlenn Strauss
10636c1e6e66SGlenn Strauss if (graceful_restart) {
1064352d5d77SGlenn Strauss if (!server_graceful_state_bg(srv))
10656c1e6e66SGlenn Strauss server_sockets_unregister(srv);
10666c1e6e66SGlenn Strauss if (pid_fd > 0) pid_fd = -pid_fd; /*(flag to skip removing pid file)*/
10676c1e6e66SGlenn Strauss }
10686c1e6e66SGlenn Strauss else {
10696c1e6e66SGlenn Strauss server_sockets_close(srv);
10706c1e6e66SGlenn Strauss remove_pid_file(srv);
1071ed62e354SGlenn Strauss /*(prevent more removal attempts)*/
1072feb9b0c4SGlenn Strauss srv->srvconf.pid_file = NULL;
10736c1e6e66SGlenn Strauss }
10746c1e6e66SGlenn Strauss }
10756c1e6e66SGlenn Strauss
1076fb9b8ad8SGlenn Strauss __attribute_cold__
107750a27431SGlenn Strauss __attribute_noinline__
server_sockets_enable(server * srv)10781a99aad1SGlenn Strauss static void server_sockets_enable (server *srv) {
10791a99aad1SGlenn Strauss server_sockets_set_event(srv, FDEVENT_IN);
10801a99aad1SGlenn Strauss srv->sockets_disabled = 0;
1081010c2894SGlenn Strauss log_error(srv->errh, __FILE__, __LINE__, "[note] sockets enabled again");
10821a99aad1SGlenn Strauss }
10831a99aad1SGlenn Strauss
10841a99aad1SGlenn Strauss __attribute_cold__
108550a27431SGlenn Strauss __attribute_noinline__
server_sockets_disable(server * srv)10861a99aad1SGlenn Strauss static void server_sockets_disable (server *srv) {
10871a99aad1SGlenn Strauss server_sockets_set_event(srv, 0);
10881a99aad1SGlenn Strauss srv->sockets_disabled = 1;
1089010c2894SGlenn Strauss log_error(srv->errh, __FILE__, __LINE__,
10905a58f696SGlenn Strauss (0 == srv->lim_conns)
10911a99aad1SGlenn Strauss ? "[note] sockets disabled, connection limit reached"
10921a99aad1SGlenn Strauss : "[note] sockets disabled, out-of-fds");
10931a99aad1SGlenn Strauss }
10941a99aad1SGlenn Strauss
10951a99aad1SGlenn Strauss __attribute_cold__
server_overload_check(server * srv)10961a99aad1SGlenn Strauss static void server_overload_check (server *srv) {
10975a58f696SGlenn Strauss if (srv->cur_fds < srv->max_fds_lowat && 0 != srv->lim_conns)
10981a99aad1SGlenn Strauss server_sockets_enable(srv);
10991a99aad1SGlenn Strauss }
11001a99aad1SGlenn Strauss
server_load_check(server * srv)11011a99aad1SGlenn Strauss static void server_load_check (server *srv) {
110262e97967SGlenn Strauss /* check if hit limits for num fds used or num connections */
11035a58f696SGlenn Strauss if (srv->cur_fds > srv->max_fds_hiwat || 0 == srv->lim_conns)
11041a99aad1SGlenn Strauss server_sockets_disable(srv);
11051a99aad1SGlenn Strauss }
11061a99aad1SGlenn Strauss
1107d46ae0ccSGlenn Strauss #ifdef HAVE_FORK
1108f39ed01cSGlenn Strauss __attribute_noinline__
server_main_setup_workers(server * const srv,const int npids)1109f39ed01cSGlenn Strauss static int server_main_setup_workers (server * const srv, const int npids) {
1110f39ed01cSGlenn Strauss pid_t pid;
1111f39ed01cSGlenn Strauss int num_childs = npids;
1112f39ed01cSGlenn Strauss int child = 0;
1113f39ed01cSGlenn Strauss unsigned int timer = 0;
1114f39ed01cSGlenn Strauss pid_t pids[npids];
1115f39ed01cSGlenn Strauss for (int n = 0; n < npids; ++n) pids[n] = -1;
1116f39ed01cSGlenn Strauss server_graceful_signal_prev_generation();
1117f39ed01cSGlenn Strauss while (!child && !srv_shutdown && !graceful_shutdown) {
1118f39ed01cSGlenn Strauss if (num_childs > 0) {
1119f39ed01cSGlenn Strauss switch ((pid = fork())) {
1120f39ed01cSGlenn Strauss case -1:
1121f39ed01cSGlenn Strauss return -1;
1122f39ed01cSGlenn Strauss case 0:
1123f39ed01cSGlenn Strauss child = 1;
1124f39ed01cSGlenn Strauss alarm(0);
1125f39ed01cSGlenn Strauss break;
1126f39ed01cSGlenn Strauss default:
1127f39ed01cSGlenn Strauss num_childs--;
1128f39ed01cSGlenn Strauss for (int n = 0; n < npids; ++n) {
1129f39ed01cSGlenn Strauss if (-1 == pids[n]) {
1130f39ed01cSGlenn Strauss pids[n] = pid;
1131f39ed01cSGlenn Strauss break;
1132f39ed01cSGlenn Strauss }
1133f39ed01cSGlenn Strauss }
1134f39ed01cSGlenn Strauss break;
1135f39ed01cSGlenn Strauss }
1136f39ed01cSGlenn Strauss }
1137f39ed01cSGlenn Strauss else {
1138f39ed01cSGlenn Strauss int status;
1139f39ed01cSGlenn Strauss unix_time64_t mono_ts;
1140f39ed01cSGlenn Strauss if (-1 != (pid = fdevent_waitpid_intr(-1, &status))) {
1141f39ed01cSGlenn Strauss mono_ts = log_monotonic_secs;
1142f39ed01cSGlenn Strauss log_monotonic_secs = server_monotonic_secs();
1143f39ed01cSGlenn Strauss log_epoch_secs =
1144f39ed01cSGlenn Strauss server_epoch_secs(srv, log_monotonic_secs - mono_ts);
1145f39ed01cSGlenn Strauss if (plugins_call_handle_waitpid(srv, pid, status)
1146f39ed01cSGlenn Strauss != HANDLER_GO_ON) {
1147f39ed01cSGlenn Strauss if (!timer) alarm((timer = 5));
1148f39ed01cSGlenn Strauss continue;
1149f39ed01cSGlenn Strauss }
1150f39ed01cSGlenn Strauss switch (fdlog_pipes_waitpid_cb(pid)) {
1151f39ed01cSGlenn Strauss default: break;
1152f39ed01cSGlenn Strauss case -1: if (!timer) alarm((timer = 5));
1153f39ed01cSGlenn Strauss __attribute_fallthrough__
1154f39ed01cSGlenn Strauss case 1: continue;
1155f39ed01cSGlenn Strauss }
1156f39ed01cSGlenn Strauss /**
1157f39ed01cSGlenn Strauss * check if one of our workers went away
1158f39ed01cSGlenn Strauss */
1159f39ed01cSGlenn Strauss for (int n = 0; n < npids; ++n) {
1160f39ed01cSGlenn Strauss if (pid == pids[n]) {
1161f39ed01cSGlenn Strauss pids[n] = -1;
1162f39ed01cSGlenn Strauss num_childs++;
1163f39ed01cSGlenn Strauss break;
1164f39ed01cSGlenn Strauss }
1165f39ed01cSGlenn Strauss }
1166f39ed01cSGlenn Strauss }
1167f39ed01cSGlenn Strauss else if (errno == EINTR) {
1168f39ed01cSGlenn Strauss mono_ts = log_monotonic_secs;
1169f39ed01cSGlenn Strauss log_monotonic_secs = server_monotonic_secs();
1170f39ed01cSGlenn Strauss log_epoch_secs =
1171f39ed01cSGlenn Strauss server_epoch_secs(srv, log_monotonic_secs - mono_ts);
1172f39ed01cSGlenn Strauss /* On SIGHUP, cycle logs (periodic maint runs in children) */
1173f39ed01cSGlenn Strauss if (handle_sig_hup) {
1174f39ed01cSGlenn Strauss handle_sig_hup = 0;
1175f39ed01cSGlenn Strauss fdlog_files_cycle(srv->errh);/*reopen log files, not pipes*/
1176f39ed01cSGlenn Strauss /* forward SIGHUP to workers */
1177f39ed01cSGlenn Strauss for (int n = 0; n < npids; ++n) {
1178f39ed01cSGlenn Strauss if (pids[n] > 0) kill(pids[n], SIGHUP);
1179f39ed01cSGlenn Strauss }
1180f39ed01cSGlenn Strauss }
1181f39ed01cSGlenn Strauss if (handle_sig_alarm) {
1182f39ed01cSGlenn Strauss handle_sig_alarm = 0;
1183f39ed01cSGlenn Strauss timer = 0;
1184f39ed01cSGlenn Strauss plugins_call_handle_trigger(srv);
1185f39ed01cSGlenn Strauss fdlog_pipes_restart(log_monotonic_secs);
1186f39ed01cSGlenn Strauss }
1187f39ed01cSGlenn Strauss }
1188f39ed01cSGlenn Strauss }
1189f39ed01cSGlenn Strauss }
1190f39ed01cSGlenn Strauss
1191f39ed01cSGlenn Strauss if (!child) {
1192f39ed01cSGlenn Strauss /* exit point for parent monitoring workers;
1193f39ed01cSGlenn Strauss * signal children, too */
1194f39ed01cSGlenn Strauss if (graceful_shutdown || graceful_restart) {
1195f39ed01cSGlenn Strauss /* flag to ignore one SIGINT if graceful_restart */
1196f39ed01cSGlenn Strauss if (graceful_restart) graceful_restart = 2;
1197f39ed01cSGlenn Strauss kill(0, SIGINT);
1198f39ed01cSGlenn Strauss server_graceful_state(srv);
1199f39ed01cSGlenn Strauss }
1200f39ed01cSGlenn Strauss else if (srv_shutdown)
1201f39ed01cSGlenn Strauss kill(0, SIGTERM);
1202f39ed01cSGlenn Strauss
1203f39ed01cSGlenn Strauss return 0;
1204f39ed01cSGlenn Strauss }
1205f39ed01cSGlenn Strauss
1206f39ed01cSGlenn Strauss /* ignore SIGUSR1 in workers; only parent directs graceful restart */
1207f39ed01cSGlenn Strauss #ifdef HAVE_SIGACTION
1208f39ed01cSGlenn Strauss struct sigaction actignore;
1209f39ed01cSGlenn Strauss memset(&actignore, 0, sizeof(actignore));
1210f39ed01cSGlenn Strauss actignore.sa_handler = SIG_IGN;
1211f39ed01cSGlenn Strauss sigaction(SIGUSR1, &actignore, NULL);
1212f39ed01cSGlenn Strauss #elif defined(HAVE_SIGNAL)
1213f39ed01cSGlenn Strauss signal(SIGUSR1, SIG_IGN);
1214f39ed01cSGlenn Strauss #endif
1215f39ed01cSGlenn Strauss
1216f39ed01cSGlenn Strauss /**
1217f39ed01cSGlenn Strauss * make sure workers do not muck with pid-file
1218f39ed01cSGlenn Strauss */
1219f39ed01cSGlenn Strauss if (0 <= pid_fd) {
1220f39ed01cSGlenn Strauss close(pid_fd);
1221f39ed01cSGlenn Strauss pid_fd = -1;
1222f39ed01cSGlenn Strauss }
1223f39ed01cSGlenn Strauss srv->srvconf.pid_file = NULL;
1224f39ed01cSGlenn Strauss
1225f39ed01cSGlenn Strauss fdlog_pipes_abandon_pids();
1226f39ed01cSGlenn Strauss srv->pid = getpid();
1227f39ed01cSGlenn Strauss li_rand_reseed();
1228f39ed01cSGlenn Strauss
1229f39ed01cSGlenn Strauss return 1; /* child worker */
1230f39ed01cSGlenn Strauss }
1231d46ae0ccSGlenn Strauss #endif
1232f39ed01cSGlenn Strauss
12331a99aad1SGlenn Strauss __attribute_cold__
12346800b082SGlenn Strauss __attribute_noinline__
server_main_setup(server * const srv,int argc,char ** argv)12356c1d57a2SGlenn Strauss static int server_main_setup (server * const srv, int argc, char **argv) {
1236bcbafe63SJan Kneschke int print_config = 0;
1237bcbafe63SJan Kneschke int test_config = 0;
12380a6eaf2eSGlenn Strauss int i_am_root = 0;
1239f11089edSGlenn Strauss #ifdef HAVE_FORK
1240f11089edSGlenn Strauss int parent_pipe_fd = -1;
1241f11089edSGlenn Strauss #endif
1242f11089edSGlenn Strauss
12430a6eaf2eSGlenn Strauss #ifdef HAVE_GETUID
12440a6eaf2eSGlenn Strauss i_am_root = (0 == getuid());
12450a6eaf2eSGlenn Strauss #endif
12460a6eaf2eSGlenn Strauss
1247b0c66266SGlenn Strauss /* initialize globals (including file-scoped static globals) */
1248b0c66266SGlenn Strauss oneshot_fd = 0;
1249ed297e7eSGlenn Strauss oneshot_fdout = -1;
1250b0c66266SGlenn Strauss srv_shutdown = 0;
1251b0c66266SGlenn Strauss graceful_shutdown = 0;
1252b0c66266SGlenn Strauss handle_sig_alarm = 1;
1253b0c66266SGlenn Strauss handle_sig_hup = 0;
1254413c0e55SGlenn Strauss idle_limit = 0;
1255b0c66266SGlenn Strauss chunkqueue_set_tempdirs_default_reset();
12566c1e6e66SGlenn Strauss /*graceful_restart = 0;*//*(reset below to avoid further daemonizing)*/
12576c1e6e66SGlenn Strauss /*(intentionally preserved)*/
12586c1e6e66SGlenn Strauss /*memset(graceful_sockets, 0, sizeof(graceful_sockets));*/
1259ce7b47c0SGlenn Strauss /*memset(inherited_sockets, 0, sizeof(inherited_sockets));*/
12606c1e6e66SGlenn Strauss /*pid_fd = -1;*/
1261352d5d77SGlenn Strauss srv->argv = argv;
1262bcdc6a3bSJan Kneschke
12639e47786eSGlenn Strauss for (int o; -1 != (o = getopt(argc, argv, "f:m:i:hvVD1pt")); ) {
1264bcdc6a3bSJan Kneschke switch(o) {
1265bcdc6a3bSJan Kneschke case 'f':
1266ed62e354SGlenn Strauss if (srv->config_data_base) {
1267010c2894SGlenn Strauss log_error(srv->errh, __FILE__, __LINE__,
12683a13ab8bSStefan Bühler "Can only read one config file. Use the include command to use multiple config files.");
12693a13ab8bSStefan Bühler return -1;
12703a13ab8bSStefan Bühler }
1271bcdc6a3bSJan Kneschke if (config_read(srv, optarg)) {
1272bcdc6a3bSJan Kneschke return -1;
1273bcdc6a3bSJan Kneschke }
1274bcdc6a3bSJan Kneschke break;
1275c7ec5012SJan Kneschke case 'm':
127610b307bdSGlenn Strauss srv->srvconf.modules_dir = optarg;
1277c7ec5012SJan Kneschke break;
127806b87deeSGlenn Strauss case 'i': {
127906b87deeSGlenn Strauss char *endptr;
128006b87deeSGlenn Strauss long timeout = strtol(optarg, &endptr, 0);
128106b87deeSGlenn Strauss if (!*optarg || *endptr || timeout < 0) {
1282010c2894SGlenn Strauss log_error(srv->errh, __FILE__, __LINE__,
1283010c2894SGlenn Strauss "Invalid idle timeout value: %s", optarg);
128406b87deeSGlenn Strauss return -1;
128506b87deeSGlenn Strauss }
1286309c1693SGlenn Strauss idle_limit = (int)timeout;
128706b87deeSGlenn Strauss break;
128806b87deeSGlenn Strauss }
1289bcbafe63SJan Kneschke case 'p': print_config = 1; break;
1290292309f8SGlenn Strauss case 't': ++test_config; break;
1291d5695721SGlenn Strauss case '1': if (0 == oneshot_fd) oneshot_fd = dup(STDIN_FILENO);
1292d5695721SGlenn Strauss break;
1293bcdc6a3bSJan Kneschke case 'D': srv->srvconf.dont_daemonize = 1; break;
12946c1e6e66SGlenn Strauss case 'v': show_version(); return 0;
12956c1e6e66SGlenn Strauss case 'V': show_features(); return 0;
12966c1e6e66SGlenn Strauss case 'h': show_help(); return 0;
1297bcdc6a3bSJan Kneschke default:
1298bcdc6a3bSJan Kneschke show_help();
1299bcdc6a3bSJan Kneschke return -1;
1300bcdc6a3bSJan Kneschke }
1301bcdc6a3bSJan Kneschke }
1302bcdc6a3bSJan Kneschke
13030bac13f6SGlenn Strauss #ifdef __CYGWIN__
1304ed62e354SGlenn Strauss if (!srv->config_data_base && NULL != getenv("NSSM_SERVICE_NAME")) {
13050bac13f6SGlenn Strauss char *dir = getenv("NSSM_SERVICE_DIR");
13060bac13f6SGlenn Strauss if (NULL != dir && 0 != chdir(dir)) {
1307010c2894SGlenn Strauss log_perror(srv->errh, __FILE__, __LINE__, "chdir %s failed", dir);
13080bac13f6SGlenn Strauss return -1;
13090bac13f6SGlenn Strauss }
13100bac13f6SGlenn Strauss srv->srvconf.dont_daemonize = 1;
131110b307bdSGlenn Strauss srv->srvconf.modules_dir = "modules";
13120bac13f6SGlenn Strauss if (config_read(srv, "conf/lighttpd.conf")) return -1;
13130bac13f6SGlenn Strauss }
13140bac13f6SGlenn Strauss #endif
13150bac13f6SGlenn Strauss
1316ed62e354SGlenn Strauss if (!srv->config_data_base) {
1317010c2894SGlenn Strauss log_error(srv->errh, __FILE__, __LINE__,
1318bcdc6a3bSJan Kneschke "No configuration available. Try using -f option.");
1319bcdc6a3bSJan Kneschke return -1;
1320bcdc6a3bSJan Kneschke }
1321bcdc6a3bSJan Kneschke
1322e0c1341cSGlenn Strauss if (1 == srv->srvconf.max_worker)
1323e0c1341cSGlenn Strauss srv->srvconf.max_worker = 0;
1324e0c1341cSGlenn Strauss
1325bcbafe63SJan Kneschke if (print_config) {
132665ef0a3dSGlenn Strauss config_print(srv);
1327fbe55825SGlenn Strauss puts(srv->tmp_buf->ptr);
1328bcbafe63SJan Kneschke }
1329bcbafe63SJan Kneschke
1330bcbafe63SJan Kneschke if (test_config) {
1331feb9b0c4SGlenn Strauss srv->srvconf.pid_file = NULL;
1332292309f8SGlenn Strauss if (1 == test_config) {
1333bcbafe63SJan Kneschke printf("Syntax OK\n");
1334292309f8SGlenn Strauss } else { /*(test_config > 1)*/
1335292309f8SGlenn Strauss test_config = 0;
1336292309f8SGlenn Strauss srv->srvconf.preflight_check = 1;
1337292309f8SGlenn Strauss srv->srvconf.dont_daemonize = 1;
1338292309f8SGlenn Strauss }
1339bcbafe63SJan Kneschke }
1340bcbafe63SJan Kneschke
1341bcbafe63SJan Kneschke if (test_config || print_config) {
1342bcbafe63SJan Kneschke return 0;
1343bcbafe63SJan Kneschke }
1344bcbafe63SJan Kneschke
1345a8998e0bSGlenn Strauss #if defined(HAVE_MALLOC_TRIM)
1346a8998e0bSGlenn Strauss if (srv->srvconf.max_conns <= 16 && malloc_top_pad == 524288)
1347a8998e0bSGlenn Strauss malloc_top_pad = 131072; /*(reduce memory use on small systems)*/
1348a8998e0bSGlenn Strauss #endif
1349a8998e0bSGlenn Strauss
13501812f554SGlenn Strauss if (oneshot_fd) {
13511812f554SGlenn Strauss if (oneshot_fd <= STDERR_FILENO) {
1352010c2894SGlenn Strauss log_error(srv->errh, __FILE__, __LINE__,
13531812f554SGlenn Strauss "Invalid fds at startup with lighttpd -1");
13541812f554SGlenn Strauss return -1;
13551812f554SGlenn Strauss }
13561812f554SGlenn Strauss graceful_shutdown = 1;
1357f279ae7dSGlenn Strauss srv->sockets_disabled = 2;
13581812f554SGlenn Strauss srv->srvconf.dont_daemonize = 1;
1359feb9b0c4SGlenn Strauss srv->srvconf.pid_file = NULL;
13601812f554SGlenn Strauss if (srv->srvconf.max_worker) {
13611812f554SGlenn Strauss srv->srvconf.max_worker = 0;
1362010c2894SGlenn Strauss log_error(srv->errh, __FILE__, __LINE__,
13631812f554SGlenn Strauss "server one-shot command line option disables server.max-worker config file option.");
13641812f554SGlenn Strauss }
1365ed297e7eSGlenn Strauss
1366ed297e7eSGlenn Strauss struct stat st;
1367ed297e7eSGlenn Strauss if (0 != fstat(oneshot_fd, &st)) {
1368ed297e7eSGlenn Strauss log_perror(srv->errh, __FILE__, __LINE__, "fstat()");
1369ed297e7eSGlenn Strauss return -1;
1370ed297e7eSGlenn Strauss }
1371ed297e7eSGlenn Strauss
1372ed297e7eSGlenn Strauss if (S_ISFIFO(st.st_mode)) {
1373ed297e7eSGlenn Strauss oneshot_fdout = dup(STDOUT_FILENO);
1374ed297e7eSGlenn Strauss if (oneshot_fdout <= STDERR_FILENO) {
1375ed297e7eSGlenn Strauss log_perror(srv->errh, __FILE__, __LINE__, "dup()");
1376ed297e7eSGlenn Strauss return -1;
1377ed297e7eSGlenn Strauss }
1378ed297e7eSGlenn Strauss }
1379ed297e7eSGlenn Strauss else if (!S_ISSOCK(st.st_mode)) {
1380ed297e7eSGlenn Strauss /* require that fd is a socket
1381ed297e7eSGlenn Strauss * (modules might expect STDIN_FILENO and STDOUT_FILENO opened to /dev/null) */
1382ed297e7eSGlenn Strauss log_error(srv->errh, __FILE__, __LINE__,
1383ed297e7eSGlenn Strauss "lighttpd -1 stdin is not a socket");
1384ed297e7eSGlenn Strauss return -1;
1385ed297e7eSGlenn Strauss }
13861812f554SGlenn Strauss }
13871812f554SGlenn Strauss
1388ed62e354SGlenn Strauss if (srv->srvconf.bindhost && buffer_is_equal_string(srv->srvconf.bindhost, CONST_STR_LEN("/dev/stdin"))) {
1389ea58cc6fSGlenn Strauss if (-1 == srv->stdin_fd)
1390ea58cc6fSGlenn Strauss srv->stdin_fd = dup(STDIN_FILENO);
1391ea58cc6fSGlenn Strauss if (srv->stdin_fd <= STDERR_FILENO) {
1392010c2894SGlenn Strauss log_error(srv->errh, __FILE__, __LINE__,
13935c25f629SGlenn Strauss "Invalid fds at startup");
13945c25f629SGlenn Strauss return -1;
13955c25f629SGlenn Strauss }
13965c25f629SGlenn Strauss }
13975c25f629SGlenn Strauss
1398bcdc6a3bSJan Kneschke /* close stdin and stdout, as they are not needed */
13996c1e6e66SGlenn Strauss {
14006c1e6e66SGlenn Strauss struct stat st;
1401a9970fecSGlenn Strauss int devnull;
1402a9970fecSGlenn Strauss int errfd;
1403a9970fecSGlenn Strauss do {
14049bc61f16SGlenn Strauss /* coverity[overwrite_var : FALSE] */
1405a9970fecSGlenn Strauss devnull = fdevent_open_devnull();
1406dadfb5fcSGlenn Strauss #ifdef __COVERITY__
1407dadfb5fcSGlenn Strauss __coverity_escape__(devnull);
1408dadfb5fcSGlenn Strauss #endif
1409a9970fecSGlenn Strauss } while (-1 != devnull && devnull <= STDERR_FILENO);
1410a9970fecSGlenn Strauss if (-1 == devnull) {
1411010c2894SGlenn Strauss log_perror(srv->errh, __FILE__, __LINE__,
1412010c2894SGlenn Strauss "opening /dev/null failed");
1413a9970fecSGlenn Strauss return -1;
1414a9970fecSGlenn Strauss }
1415a9970fecSGlenn Strauss errfd = (0 == fstat(STDERR_FILENO, &st)) ? -1 : devnull;
1416a9970fecSGlenn Strauss if (0 != fdevent_set_stdin_stdout_stderr(devnull, devnull, errfd)) {
1417010c2894SGlenn Strauss log_perror(srv->errh, __FILE__, __LINE__,
1418010c2894SGlenn Strauss "setting default fds failed");
1419a9970fecSGlenn Strauss #ifdef FD_CLOEXEC
1420a9970fecSGlenn Strauss if (-1 != errfd) close(errfd);
1421a9970fecSGlenn Strauss if (devnull != errfd) close(devnull);
1422a9970fecSGlenn Strauss #endif
1423a9970fecSGlenn Strauss return -1;
1424a9970fecSGlenn Strauss }
1425a9970fecSGlenn Strauss #ifdef FD_CLOEXEC
1426a9970fecSGlenn Strauss if (-1 != errfd) close(errfd);
1427a9970fecSGlenn Strauss if (devnull != errfd) close(devnull);
1428a9970fecSGlenn Strauss #endif
14296c1e6e66SGlenn Strauss }
1430bcdc6a3bSJan Kneschke
1431869c778aSGlenn Strauss http_response_send_1xx_cb_set(NULL, HTTP_VERSION_2);
14324d99d9b7SGlenn Strauss if (!config_feature_bool(srv, "server.h2-discard-backend-1xx", 0))
14334d99d9b7SGlenn Strauss http_response_send_1xx_cb_set(h2_send_1xx, HTTP_VERSION_2);
1434869c778aSGlenn Strauss
1435362be7b3SGlenn Strauss http_response_send_1xx_cb_set(NULL, HTTP_VERSION_1_1);
14364d99d9b7SGlenn Strauss if (!config_feature_bool(srv, "server.h1-discard-backend-1xx", 0))
14374d99d9b7SGlenn Strauss http_response_send_1xx_cb_set(connection_send_1xx, HTTP_VERSION_1_1);
1438362be7b3SGlenn Strauss
143925f83b84SGlenn Strauss http_range_config_allow_http10(config_feature_bool(srv, "http10.range", 0));
144025f83b84SGlenn Strauss
1441bcdc6a3bSJan Kneschke if (0 != config_set_defaults(srv)) {
1442010c2894SGlenn Strauss log_error(srv->errh, __FILE__, __LINE__,
1443bcdc6a3bSJan Kneschke "setting default values failed");
1444bcdc6a3bSJan Kneschke return -1;
1445bcdc6a3bSJan Kneschke }
1446bcdc6a3bSJan Kneschke
1447bcdc6a3bSJan Kneschke if (plugins_load(srv)) {
1448010c2894SGlenn Strauss log_error(srv->errh, __FILE__, __LINE__,
1449bcdc6a3bSJan Kneschke "loading plugins finally failed");
1450bcdc6a3bSJan Kneschke return -1;
1451bcdc6a3bSJan Kneschke }
1452bcdc6a3bSJan Kneschke
14538af9e71cSGlenn Strauss if (HANDLER_GO_ON != plugins_call_init(srv)) {
1454010c2894SGlenn Strauss log_error(srv->errh, __FILE__, __LINE__,
1455010c2894SGlenn Strauss "Initialization of plugins failed. Going down.");
14568af9e71cSGlenn Strauss return -1;
14578af9e71cSGlenn Strauss }
14588af9e71cSGlenn Strauss
1459b28f03b5SGlenn Strauss /* mod_indexfile should be listed in server.modules prior to dynamic handlers */
14609e47786eSGlenn Strauss uint32_t i = 0;
1461e2de4e58SGlenn Strauss for (const char *pname = NULL; i < srv->plugins.used; ++i) {
1462b28f03b5SGlenn Strauss plugin *p = ((plugin **)srv->plugins.ptr)[i];
14639e47786eSGlenn Strauss if (0 == strcmp(p->name, "indexfile")) {
14649e47786eSGlenn Strauss if (pname)
1465010c2894SGlenn Strauss log_error(srv->errh, __FILE__, __LINE__,
1466010c2894SGlenn Strauss "Warning: mod_indexfile should be listed in server.modules prior to mod_%s", pname);
1467a7bceb6bSGlenn Strauss break;
1468a7bceb6bSGlenn Strauss }
1469a7bceb6bSGlenn Strauss if (p->handle_subrequest_start && p->handle_subrequest) {
1470a7bceb6bSGlenn Strauss if (!pname) pname = p->name;
1471b28f03b5SGlenn Strauss }
1472b28f03b5SGlenn Strauss }
1473b28f03b5SGlenn Strauss
1474bcdc6a3bSJan Kneschke /* open pid file BEFORE chroot */
1475fad841d6SGlenn Strauss if (-2 == pid_fd) pid_fd = -1; /*(initial startup state)*/
1476af3df29aSGlenn Strauss if (-1 == pid_fd && srv->srvconf.pid_file) {
1477010c2894SGlenn Strauss const char *pidfile = srv->srvconf.pid_file->ptr;
1478010c2894SGlenn Strauss if (-1 == (pid_fd = fdevent_open_cloexec(pidfile, 0, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
1479bcdc6a3bSJan Kneschke struct stat st;
1480bcdc6a3bSJan Kneschke if (errno != EEXIST) {
1481010c2894SGlenn Strauss log_perror(srv->errh, __FILE__, __LINE__,
1482010c2894SGlenn Strauss "opening pid-file failed: %s", pidfile);
1483bcdc6a3bSJan Kneschke return -1;
1484bcdc6a3bSJan Kneschke }
1485bcdc6a3bSJan Kneschke
1486010c2894SGlenn Strauss if (0 != stat(pidfile, &st)) {
1487010c2894SGlenn Strauss log_perror(srv->errh, __FILE__, __LINE__,
1488010c2894SGlenn Strauss "stating existing pid-file failed: %s", pidfile);
1489bcdc6a3bSJan Kneschke }
1490bcdc6a3bSJan Kneschke
1491bcdc6a3bSJan Kneschke if (!S_ISREG(st.st_mode)) {
1492010c2894SGlenn Strauss log_error(srv->errh, __FILE__, __LINE__,
1493010c2894SGlenn Strauss "pid-file exists and isn't regular file: %s", pidfile);
1494bcdc6a3bSJan Kneschke return -1;
1495bcdc6a3bSJan Kneschke }
1496bcdc6a3bSJan Kneschke
1497010c2894SGlenn Strauss if (-1 == (pid_fd = fdevent_open_cloexec(pidfile, 0, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
1498010c2894SGlenn Strauss log_perror(srv->errh, __FILE__, __LINE__,
1499010c2894SGlenn Strauss "opening pid-file failed: %s", pidfile);
1500bcdc6a3bSJan Kneschke return -1;
1501bcdc6a3bSJan Kneschke }
1502bcdc6a3bSJan Kneschke }
1503bcdc6a3bSJan Kneschke }
1504bcdc6a3bSJan Kneschke
1505733fa06cSGlenn Strauss {
1506733fa06cSGlenn Strauss #ifdef HAVE_GETRLIMIT
1507d71c1d47SGlenn Strauss struct rlimit rlim = { 4096, 4096 };
1508bcdc6a3bSJan Kneschke int use_rlimit = 1;
1509bcdc6a3bSJan Kneschke #ifdef HAVE_VALGRIND_VALGRIND_H
1510bcdc6a3bSJan Kneschke if (RUNNING_ON_VALGRIND) use_rlimit = 0;
1511bcdc6a3bSJan Kneschke #endif
1512bcdc6a3bSJan Kneschke
1513bcdc6a3bSJan Kneschke if (0 != getrlimit(RLIMIT_NOFILE, &rlim)) {
1514010c2894SGlenn Strauss log_perror(srv->errh, __FILE__, __LINE__, "getrlimit()");
1515d71c1d47SGlenn Strauss use_rlimit = 0;
1516bcdc6a3bSJan Kneschke }
1517bcdc6a3bSJan Kneschke
1518733fa06cSGlenn Strauss /**
1519733fa06cSGlenn Strauss * if we are not root can can't increase the fd-limit above rlim_max, but we can reduce it
1520733fa06cSGlenn Strauss */
1521733fa06cSGlenn Strauss if (use_rlimit && srv->srvconf.max_fds
1522733fa06cSGlenn Strauss && (i_am_root || srv->srvconf.max_fds <= rlim.rlim_max)) {
1523bcdc6a3bSJan Kneschke /* set rlimits */
1524bcdc6a3bSJan Kneschke
15253551dd74SGlenn Strauss rlim_t rlim_cur = rlim.rlim_cur;
1526bcdc6a3bSJan Kneschke rlim.rlim_cur = srv->srvconf.max_fds;
1527733fa06cSGlenn Strauss if (i_am_root) rlim.rlim_max = srv->srvconf.max_fds;
1528bcdc6a3bSJan Kneschke
1529bcdc6a3bSJan Kneschke if (0 != setrlimit(RLIMIT_NOFILE, &rlim)) {
1530010c2894SGlenn Strauss log_perror(srv->errh, __FILE__, __LINE__, "setrlimit()");
15315a257fabSGlenn Strauss log_error(srv->errh, __FILE__, __LINE__, "setrlimit() may need root to run once: setsebool -P httpd_setrlimit on");
15325a257fabSGlenn Strauss use_rlimit = 0;
15333551dd74SGlenn Strauss if (srv->srvconf.max_fds > rlim_cur)
15343551dd74SGlenn Strauss srv->srvconf.max_fds = rlim_cur;
1535bcdc6a3bSJan Kneschke }
1536bcdc6a3bSJan Kneschke }
1537bcdc6a3bSJan Kneschke
15383399b0ddSGlenn Strauss /*(default upper limit of 4k if server.max-fds not specified)*/
15398588772cSGlenn Strauss if (0 == srv->srvconf.max_fds)
15408588772cSGlenn Strauss srv->srvconf.max_fds = (rlim.rlim_cur <= 4096)
15418588772cSGlenn Strauss ? (unsigned short)rlim.rlim_cur
15428588772cSGlenn Strauss : 4096;
15432fe31be5SJan Kneschke
15442fe31be5SJan Kneschke /* set core file rlimit, if enable_cores is set */
15452fe31be5SJan Kneschke if (use_rlimit && srv->srvconf.enable_cores && getrlimit(RLIMIT_CORE, &rlim) == 0) {
15462fe31be5SJan Kneschke rlim.rlim_cur = rlim.rlim_max;
15472fe31be5SJan Kneschke setrlimit(RLIMIT_CORE, &rlim);
15482fe31be5SJan Kneschke }
1549bcdc6a3bSJan Kneschke #endif
1550733fa06cSGlenn Strauss }
1551bcdc6a3bSJan Kneschke
1552733fa06cSGlenn Strauss /* we need root-perms for port < 1024 */
1553ea58cc6fSGlenn Strauss if (0 != network_init(srv, srv->stdin_fd)) {
1554733fa06cSGlenn Strauss return -1;
1555733fa06cSGlenn Strauss }
1556ea58cc6fSGlenn Strauss srv->stdin_fd = -1;
1557733fa06cSGlenn Strauss
1558733fa06cSGlenn Strauss if (i_am_root) {
1559bcdc6a3bSJan Kneschke #ifdef HAVE_PWD_H
1560bcdc6a3bSJan Kneschke /* set user and group */
1561733fa06cSGlenn Strauss struct group *grp = NULL;
1562733fa06cSGlenn Strauss struct passwd *pwd = NULL;
1563733fa06cSGlenn Strauss
1564af3df29aSGlenn Strauss if (srv->srvconf.groupname) {
1565558bfc4eSGlenn Strauss if (NULL == (grp = getgrnam(srv->srvconf.groupname->ptr))) {
1566010c2894SGlenn Strauss log_error(srv->errh, __FILE__, __LINE__,
1567010c2894SGlenn Strauss "can't find groupname %s", srv->srvconf.groupname->ptr);
1568558bfc4eSGlenn Strauss return -1;
1569558bfc4eSGlenn Strauss }
1570558bfc4eSGlenn Strauss }
1571558bfc4eSGlenn Strauss
1572af3df29aSGlenn Strauss if (srv->srvconf.username) {
1573bcdc6a3bSJan Kneschke if (NULL == (pwd = getpwnam(srv->srvconf.username->ptr))) {
1574010c2894SGlenn Strauss log_error(srv->errh, __FILE__, __LINE__,
1575010c2894SGlenn Strauss "can't find username %s", srv->srvconf.username->ptr);
1576bcdc6a3bSJan Kneschke return -1;
1577bcdc6a3bSJan Kneschke }
1578bcdc6a3bSJan Kneschke
1579bcdc6a3bSJan Kneschke if (pwd->pw_uid == 0) {
1580010c2894SGlenn Strauss log_error(srv->errh, __FILE__, __LINE__,
15812e7f0eb5SGlenn Strauss "I will not set uid to 0. Perhaps you should comment out server.username in lighttpd.conf\n");
1582bcdc6a3bSJan Kneschke return -1;
1583bcdc6a3bSJan Kneschke }
1584bcdc6a3bSJan Kneschke
1585558bfc4eSGlenn Strauss if (NULL == grp && NULL == (grp = getgrgid(pwd->pw_gid))) {
1586010c2894SGlenn Strauss log_error(srv->errh, __FILE__, __LINE__,
1587010c2894SGlenn Strauss "can't find group id %d", (int)pwd->pw_gid);
1588bcdc6a3bSJan Kneschke return -1;
1589bcdc6a3bSJan Kneschke }
1590558bfc4eSGlenn Strauss }
1591558bfc4eSGlenn Strauss
1592558bfc4eSGlenn Strauss if (NULL != grp) {
1593bcdc6a3bSJan Kneschke if (grp->gr_gid == 0) {
1594010c2894SGlenn Strauss log_error(srv->errh, __FILE__, __LINE__,
15952e7f0eb5SGlenn Strauss "I will not set gid to 0. Perhaps you should comment out server.groupname in lighttpd.conf\n");
1596bcdc6a3bSJan Kneschke return -1;
1597bcdc6a3bSJan Kneschke }
1598bcdc6a3bSJan Kneschke }
1599bcdc6a3bSJan Kneschke
16009ab9f176SElan Ruusamäe /*
16019ab9f176SElan Ruusamäe * Change group before chroot, when we have access
16029ab9f176SElan Ruusamäe * to /etc/group
16039ab9f176SElan Ruusamäe * */
16044df22f2aSStefan Bühler if (NULL != grp) {
160599cddff7SStefan Bühler if (-1 == setgid(grp->gr_gid)) {
1606010c2894SGlenn Strauss log_perror(srv->errh, __FILE__, __LINE__, "setgid()");
160799cddff7SStefan Bühler return -1;
160899cddff7SStefan Bühler }
160999cddff7SStefan Bühler if (-1 == setgroups(0, NULL)) {
1610010c2894SGlenn Strauss log_perror(srv->errh, __FILE__, __LINE__, "setgroups()");
161199cddff7SStefan Bühler return -1;
161299cddff7SStefan Bühler }
1613af3df29aSGlenn Strauss if (srv->srvconf.username) {
16149ab9f176SElan Ruusamäe initgroups(srv->srvconf.username->ptr, grp->gr_gid);
16159ab9f176SElan Ruusamäe }
16169ab9f176SElan Ruusamäe }
16179ab9f176SElan Ruusamäe #endif
1618bcdc6a3bSJan Kneschke #ifdef HAVE_CHROOT
1619af3df29aSGlenn Strauss if (srv->srvconf.changeroot) {
1620bcdc6a3bSJan Kneschke tzset();
1621bcdc6a3bSJan Kneschke
1622bcdc6a3bSJan Kneschke if (-1 == chroot(srv->srvconf.changeroot->ptr)) {
1623010c2894SGlenn Strauss log_perror(srv->errh, __FILE__, __LINE__, "chroot()");
1624bcdc6a3bSJan Kneschke return -1;
1625bcdc6a3bSJan Kneschke }
1626bcdc6a3bSJan Kneschke if (-1 == chdir("/")) {
1627010c2894SGlenn Strauss log_perror(srv->errh, __FILE__, __LINE__, "chdir()");
1628bcdc6a3bSJan Kneschke return -1;
1629bcdc6a3bSJan Kneschke }
1630bcdc6a3bSJan Kneschke }
1631bcdc6a3bSJan Kneschke #endif
1632bcdc6a3bSJan Kneschke #ifdef HAVE_PWD_H
1633bcdc6a3bSJan Kneschke /* drop root privs */
16344df22f2aSStefan Bühler if (NULL != pwd) {
163599cddff7SStefan Bühler if (-1 == setuid(pwd->pw_uid)) {
1636010c2894SGlenn Strauss log_perror(srv->errh, __FILE__, __LINE__, "setuid()");
163799cddff7SStefan Bühler return -1;
163899cddff7SStefan Bühler }
163968033b8eSJan Kneschke }
1640bcdc6a3bSJan Kneschke #endif
164129fdd34aSJan Kneschke #if defined(HAVE_SYS_PRCTL_H) && defined(PR_SET_DUMPABLE)
164229fdd34aSJan Kneschke /**
164329fdd34aSJan Kneschke * on IRIX 6.5.30 they have prctl() but no DUMPABLE
164429fdd34aSJan Kneschke */
16452fe31be5SJan Kneschke if (srv->srvconf.enable_cores) {
16462fe31be5SJan Kneschke prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
16472fe31be5SJan Kneschke }
1648f36908deSGlenn Strauss #elif defined(HAVE_SYS_PROCCTL_H) && defined(PROC_TRACE_CTL_ENABLE)
1649f36908deSGlenn Strauss /* (DragonFlyBSD has procctl(), but not PROC_TRACE_CTL_ENABLE) */
1650f36908deSGlenn Strauss if (srv->srvconf.enable_cores) {
1651f36908deSGlenn Strauss int dumpable = PROC_TRACE_CTL_ENABLE;
1652f36908deSGlenn Strauss procctl(P_PID, 0, PROC_TRACE_CTL, &dumpable);
1653f36908deSGlenn Strauss }
1654b6bd11c1SDavid Carlier #elif defined(HAVE_SETPFLAGS) && defined(__PROC_PROTECT)
1655b6bd11c1SDavid Carlier /**
1656b6bd11c1SDavid Carlier * setpflags seems uniquely a solaris/illumos feature
1657b6bd11c1SDavid Carlier * but just taking extra precautions clearing __PROC_PROTECT option
1658b6bd11c1SDavid Carlier */
1659b6bd11c1SDavid Carlier if (srv->srvconf.enable_cores) {
1660b6bd11c1SDavid Carlier setpflags(__PROC_PROTECT, 0);
1661b6bd11c1SDavid Carlier }
16622fe31be5SJan Kneschke #endif
1663bcdc6a3bSJan Kneschke }
1664bcdc6a3bSJan Kneschke
16655fa895e8SElan Ruusamäe #ifdef HAVE_FORK
16666c1e6e66SGlenn Strauss /* network is up, let's daemonize ourself */
16676c1e6e66SGlenn Strauss if (0 == srv->srvconf.dont_daemonize && 0 == graceful_restart) {
1668f11089edSGlenn Strauss parent_pipe_fd = daemonize();
1669f11089edSGlenn Strauss }
16705fa895e8SElan Ruusamäe #endif
16716c1e6e66SGlenn Strauss graceful_restart = 0;/*(reset here after avoiding further daemonizing)*/
16720e84df81SGlenn Strauss if (0 == oneshot_fd) graceful_shutdown = 0;
16735fa895e8SElan Ruusamäe
1674dd6b2645SGlenn Strauss server_main_setup_signals();
167529ff92d9SStefan Bühler
167652125c82SJan Kneschke srv->gid = getgid();
167752125c82SJan Kneschke srv->uid = getuid();
16789030cfaeSGlenn Strauss srv->pid = getpid();
16799a5cf4a2SJan Kneschke
16805fa895e8SElan Ruusamäe /* write pid file */
16816c1e6e66SGlenn Strauss if (pid_fd > 2) {
1682ca97505aSGlenn Strauss buffer * const tb = srv->tmp_buf;
16837c7f8c46SGlenn Strauss buffer_clear(tb);
16847c7f8c46SGlenn Strauss buffer_append_int(tb, srv->pid);
1685f2610d23SGlenn Strauss buffer_append_char(tb, '\n');
1686af3df29aSGlenn Strauss if (-1 == write_all(pid_fd, BUF_PTR_LEN(tb))) {
1687010c2894SGlenn Strauss log_perror(srv->errh, __FILE__, __LINE__, "Couldn't write pid file");
16880508bf67SStefan Bühler close(pid_fd);
16896c1e6e66SGlenn Strauss pid_fd = -1;
16900508bf67SStefan Bühler return -1;
16910508bf67SStefan Bühler }
16926c1e6e66SGlenn Strauss } else if (pid_fd < -2) {
16936c1e6e66SGlenn Strauss pid_fd = -pid_fd;
16945fa895e8SElan Ruusamäe }
16955fa895e8SElan Ruusamäe
16965fa895e8SElan Ruusamäe /* Close stderr ASAP in the child process to make sure that nothing
16975fa895e8SElan Ruusamäe * is being written to that fd which may not be valid anymore. */
1698bafe6abfSGlenn Strauss if (!srv->srvconf.preflight_check) {
1699fda01e33SGlenn Strauss if (-1 == config_log_error_open(srv)) {
1700010c2894SGlenn Strauss log_error(srv->errh, __FILE__, __LINE__, "Opening errorlog failed. Going down.");
17015fa895e8SElan Ruusamäe return -1;
17025fa895e8SElan Ruusamäe }
1703f279ae7dSGlenn Strauss if (!oneshot_fd)
1704010c2894SGlenn Strauss log_error(srv->errh, __FILE__, __LINE__, "server started (" PACKAGE_DESC ")");
1705bafe6abfSGlenn Strauss }
17065fa895e8SElan Ruusamäe
1707bcdc6a3bSJan Kneschke if (HANDLER_GO_ON != plugins_call_set_defaults(srv)) {
1708010c2894SGlenn Strauss log_error(srv->errh, __FILE__, __LINE__, "Configuration of plugins failed. Going down.");
1709bcdc6a3bSJan Kneschke return -1;
1710bcdc6a3bSJan Kneschke }
1711bcdc6a3bSJan Kneschke
171265ef0a3dSGlenn Strauss if (!config_finalize(srv, &default_server_tag)) {
1713bcdc6a3bSJan Kneschke return -1;
1714bcdc6a3bSJan Kneschke }
1715bcdc6a3bSJan Kneschke
1716292309f8SGlenn Strauss if (srv->srvconf.preflight_check) {
1717292309f8SGlenn Strauss /*printf("Preflight OK");*//*(stdout reopened to /dev/null)*/
17186c1e6e66SGlenn Strauss return 0;
1719292309f8SGlenn Strauss }
1720292309f8SGlenn Strauss
1721bcdc6a3bSJan Kneschke
1722bcdc6a3bSJan Kneschke #ifdef HAVE_FORK
1723f11089edSGlenn Strauss /**
1724f11089edSGlenn Strauss * notify daemonize-grandparent of successful startup
1725f11089edSGlenn Strauss * do this before any further forking is done (workers)
1726f11089edSGlenn Strauss */
17276c1e6e66SGlenn Strauss if (0 == srv->srvconf.dont_daemonize && -1 != parent_pipe_fd) {
1728f11089edSGlenn Strauss if (0 > write(parent_pipe_fd, "", 1)) return -1;
1729f11089edSGlenn Strauss close(parent_pipe_fd);
1730f11089edSGlenn Strauss }
1731f11089edSGlenn Strauss
173206b87deeSGlenn Strauss if (idle_limit && srv->srvconf.max_worker) {
173306b87deeSGlenn Strauss srv->srvconf.max_worker = 0;
1734010c2894SGlenn Strauss log_error(srv->errh, __FILE__, __LINE__,
173506b87deeSGlenn Strauss "server idle time limit command line option disables server.max-worker config file option.");
173606b87deeSGlenn Strauss }
173706b87deeSGlenn Strauss
1738bcdc6a3bSJan Kneschke /* start watcher and workers */
1739f39ed01cSGlenn Strauss if (srv->srvconf.max_worker > 0) {
1740f39ed01cSGlenn Strauss int rc = server_main_setup_workers(srv, srv->srvconf.max_worker);
1741f39ed01cSGlenn Strauss if (rc != 1) /* 1 for worker; 0 for worker parent done; -1 for error */
1742f39ed01cSGlenn Strauss return rc;
1743bcdc6a3bSJan Kneschke }
1744bcdc6a3bSJan Kneschke #endif
1745bcdc6a3bSJan Kneschke
17468588772cSGlenn Strauss srv->max_fds = (int)srv->srvconf.max_fds;
1747600dfba3SGlenn Strauss if (srv->max_fds < 32) /*(sanity check; not expected)*/
1748600dfba3SGlenn Strauss srv->max_fds = 32; /*(server load checks will fail if too low)*/
17498588772cSGlenn Strauss srv->ev = fdevent_init(srv->srvconf.event_handler, &srv->max_fds, &srv->cur_fds, srv->errh);
17508588772cSGlenn Strauss if (NULL == srv->ev) {
1751010c2894SGlenn Strauss log_error(srv->errh, __FILE__, __LINE__, "fdevent_init failed");
17525fa895e8SElan Ruusamäe return -1;
17535fa895e8SElan Ruusamäe }
1754761bedd7SStefan Bühler
1755aa2d0fb0SGlenn Strauss srv->max_fds_lowat = srv->max_fds * 8 / 10;
1756aa2d0fb0SGlenn Strauss srv->max_fds_hiwat = srv->max_fds * 9 / 10;
1757aa2d0fb0SGlenn Strauss
17588588772cSGlenn Strauss /* set max-conns */
17598588772cSGlenn Strauss if (srv->srvconf.max_conns > srv->max_fds/2) {
17608588772cSGlenn Strauss /* we can't have more connections than max-fds/2 */
17618588772cSGlenn Strauss log_error(srv->errh, __FILE__, __LINE__,
17628588772cSGlenn Strauss "can't have more connections than fds/2: %hu %d",
17638588772cSGlenn Strauss srv->srvconf.max_conns, srv->max_fds);
17645a58f696SGlenn Strauss srv->lim_conns = srv->srvconf.max_conns = srv->max_fds/2;
17658588772cSGlenn Strauss } else if (srv->srvconf.max_conns) {
17668588772cSGlenn Strauss /* otherwise respect the wishes of the user */
17675a58f696SGlenn Strauss srv->lim_conns = srv->srvconf.max_conns;
17688588772cSGlenn Strauss } else {
17698588772cSGlenn Strauss /* or use the default: we really don't want to hit max-fds */
17705a58f696SGlenn Strauss srv->lim_conns = srv->srvconf.max_conns = srv->max_fds/3;
17718588772cSGlenn Strauss }
17728588772cSGlenn Strauss
17735fa895e8SElan Ruusamäe /*
17745fa895e8SElan Ruusamäe * kqueue() is called here, select resets its internals,
17755fa895e8SElan Ruusamäe * all server sockets get their handlers
17765fa895e8SElan Ruusamäe *
17775fa895e8SElan Ruusamäe * */
17785fa895e8SElan Ruusamäe if (0 != network_register_fdevents(srv)) {
17795fa895e8SElan Ruusamäe return -1;
17805fa895e8SElan Ruusamäe }
17815fa895e8SElan Ruusamäe
17826e62b842SGlenn Strauss chunkqueue_internal_pipes(config_feature_bool(srv, "chunkqueue.splice", 1));
17836e62b842SGlenn Strauss
17845fa895e8SElan Ruusamäe /* might fail if user is using fam (not gamin) and famd isn't running */
178566bdd96dSGlenn Strauss if (!stat_cache_init(srv->ev, srv->errh)) {
1786010c2894SGlenn Strauss log_error(srv->errh, __FILE__, __LINE__,
1787c752d469SGlenn Strauss "stat-cache could not be setup, dying.");
17885fa895e8SElan Ruusamäe return -1;
17895fa895e8SElan Ruusamäe }
17905fa895e8SElan Ruusamäe
17913cd822b5SGlenn Strauss #ifdef USE_ALARM
17923cd822b5SGlenn Strauss {
17933cd822b5SGlenn Strauss /* setup periodic timer (1 second) */
17943cd822b5SGlenn Strauss struct itimerval interval;
17953cd822b5SGlenn Strauss interval.it_interval.tv_sec = 1;
17963cd822b5SGlenn Strauss interval.it_interval.tv_usec = 0;
17973cd822b5SGlenn Strauss interval.it_value.tv_sec = 1;
17983cd822b5SGlenn Strauss interval.it_value.tv_usec = 0;
17993cd822b5SGlenn Strauss if (setitimer(ITIMER_REAL, &interval, NULL)) {
1800010c2894SGlenn Strauss log_perror(srv->errh, __FILE__, __LINE__, "setitimer()");
18013cd822b5SGlenn Strauss return -1;
18023cd822b5SGlenn Strauss }
18033cd822b5SGlenn Strauss }
18043cd822b5SGlenn Strauss #endif
18053cd822b5SGlenn Strauss
18065fa895e8SElan Ruusamäe /* get the current number of FDs */
1807a9970fecSGlenn Strauss {
1808a9970fecSGlenn Strauss int fd = fdevent_open_devnull();
1809a9970fecSGlenn Strauss if (fd >= 0) {
1810a9970fecSGlenn Strauss srv->cur_fds = fd;
1811a9970fecSGlenn Strauss close(fd);
1812a9970fecSGlenn Strauss }
1813a9970fecSGlenn Strauss }
18145fa895e8SElan Ruusamäe
18156c1e6e66SGlenn Strauss if (0 != server_sockets_set_nb_cloexec(srv)) {
18165fa895e8SElan Ruusamäe return -1;
18175fa895e8SElan Ruusamäe }
18185fa895e8SElan Ruusamäe
1819f1e9bcb0SGlenn Strauss /* plugin hook for worker_init */
1820f1e9bcb0SGlenn Strauss if (HANDLER_GO_ON != plugins_call_worker_init(srv))
1821f1e9bcb0SGlenn Strauss return -1;
1822f1e9bcb0SGlenn Strauss
1823ed297e7eSGlenn Strauss if (oneshot_fdout > 0) {
1824ed297e7eSGlenn Strauss if (server_oneshot_init_pipe(srv, oneshot_fd, oneshot_fdout)) {
1825ed297e7eSGlenn Strauss oneshot_fd = -1;
1826ed297e7eSGlenn Strauss oneshot_fdout = -1;
1827ed297e7eSGlenn Strauss }
1828ed297e7eSGlenn Strauss }
1829ed297e7eSGlenn Strauss else if (oneshot_fd && server_oneshot_init(srv, oneshot_fd)) {
1830ccb1f02bSGlenn Strauss oneshot_fd = -1;
18311812f554SGlenn Strauss }
18321812f554SGlenn Strauss
1833fc6612d7SGlenn Strauss if (0 == srv->srvconf.max_worker)
1834fc6612d7SGlenn Strauss server_graceful_signal_prev_generation();
1835fc6612d7SGlenn Strauss
1836413c0e55SGlenn Strauss return 1;
1837413c0e55SGlenn Strauss }
1838bcdc6a3bSJan Kneschke
1839fb9b8ad8SGlenn Strauss __attribute_cold__
1840413c0e55SGlenn Strauss __attribute_noinline__
server_handle_sighup(server * const srv)18416c1d57a2SGlenn Strauss static void server_handle_sighup (server * const srv) {
1842bcdc6a3bSJan Kneschke
1843bcdc6a3bSJan Kneschke /* cycle logfiles */
1844bcdc6a3bSJan Kneschke
1845ba88ff0eSGlenn Strauss plugins_call_handle_sighup(srv);
18467b615d5dSGlenn Strauss fdlog_files_cycle(srv->errh); /* reopen log files, not pipes */
1847ef19bacaSJan Kneschke #ifdef HAVE_SIGACTION
1848010c2894SGlenn Strauss log_error(srv->errh, __FILE__, __LINE__,
1849010c2894SGlenn Strauss "logfiles cycled UID = %d PID = %d",
1850010c2894SGlenn Strauss (int)last_sighup_info.si_uid,
1851010c2894SGlenn Strauss (int)last_sighup_info.si_pid);
1852ef19bacaSJan Kneschke #else
1853010c2894SGlenn Strauss log_error(srv->errh, __FILE__, __LINE__,
1854ef19bacaSJan Kneschke "logfiles cycled");
1855ef19bacaSJan Kneschke #endif
1856bcdc6a3bSJan Kneschke }
1857413c0e55SGlenn Strauss
1858413c0e55SGlenn Strauss __attribute_noinline__
server_handle_sigalrm(server * const srv,unix_time64_t mono_ts,unix_time64_t last_active_ts)1859309c1693SGlenn Strauss static void server_handle_sigalrm (server * const srv, unix_time64_t mono_ts, unix_time64_t last_active_ts) {
1860bcdc6a3bSJan Kneschke
1861ba88ff0eSGlenn Strauss plugins_call_handle_trigger(srv);
1862bcdc6a3bSJan Kneschke
1863dbe3e236SGlenn Strauss log_monotonic_secs = mono_ts;
1864b68b805cSGlenn Strauss log_epoch_secs = server_epoch_secs(srv, 0);
1865bcdc6a3bSJan Kneschke
186606b87deeSGlenn Strauss /* check idle time limit, if enabled */
1867dbe3e236SGlenn Strauss if (idle_limit && idle_limit < mono_ts - last_active_ts && !graceful_shutdown) {
1868010c2894SGlenn Strauss log_error(srv->errh, __FILE__, __LINE__,
1869010c2894SGlenn Strauss "[note] idle timeout %ds exceeded, "
1870010c2894SGlenn Strauss "initiating graceful shutdown", (int)idle_limit);
187106b87deeSGlenn Strauss graceful_shutdown = 2; /* value 2 indicates idle timeout */
18726c1e6e66SGlenn Strauss if (graceful_restart) {
18736c1e6e66SGlenn Strauss graceful_restart = 0;
18746c1e6e66SGlenn Strauss if (pid_fd < -2) pid_fd = -pid_fd;
18756c1e6e66SGlenn Strauss server_sockets_close(srv);
18766c1e6e66SGlenn Strauss }
187706b87deeSGlenn Strauss }
187806b87deeSGlenn Strauss
18791f3ad401SGlenn Strauss #ifdef HAVE_GETLOADAVG
18801f3ad401SGlenn Strauss /* refresh loadavg data every 30 seconds */
1881dbe3e236SGlenn Strauss if (srv->loadts + 30 < mono_ts) {
1882ed62e354SGlenn Strauss if (-1 != getloadavg(srv->loadavg, 3)) {
1883dbe3e236SGlenn Strauss srv->loadts = mono_ts;
18841f3ad401SGlenn Strauss }
18851f3ad401SGlenn Strauss }
18861f3ad401SGlenn Strauss #endif
18871f3ad401SGlenn Strauss
1888dbe3e236SGlenn Strauss if (0 == (mono_ts & 0x3f)) { /*(once every 64 secs)*/
18897b615d5dSGlenn Strauss /* free logger buffers every 64 secs */
18907b615d5dSGlenn Strauss fdlog_flushall(srv->errh);
18913f7779d2SGlenn Strauss /* free excess chunkqueue buffers every 64 secs */
18923f7779d2SGlenn Strauss chunkqueue_chunk_pool_clear();
189362a9d5b7SGlenn Strauss /* clear request and connection pools every 64 secs */
189462a9d5b7SGlenn Strauss request_pool_free();
189562a9d5b7SGlenn Strauss connections_pool_clear(srv);
18961a8d8e0cSGlenn Strauss #if defined(HAVE_MALLOC_TRIM)
18971a8d8e0cSGlenn Strauss if (malloc_trim_fn) malloc_trim_fn(malloc_top_pad);
18981a8d8e0cSGlenn Strauss #endif
18993f7779d2SGlenn Strauss /* attempt to restart dead piped loggers every 64 secs */
19003f7779d2SGlenn Strauss if (0 == srv->srvconf.max_worker)
1901243510dbSGlenn Strauss fdlog_pipes_restart(mono_ts);
19023f7779d2SGlenn Strauss }
19035e134da0SJan Kneschke /* cleanup stat-cache */
190468d8d4c5SGlenn Strauss stat_cache_trigger_cleanup();
190565a6740fSGlenn Strauss /* reset global/aggregate rate limit counters */
1906ed62e354SGlenn Strauss config_reset_config_bytes_sec(srv->config_data_base);
19070f9b9242SGlenn Strauss /* if graceful_shutdown, accelerate cleanup of recently completed request/responses */
19082d55953eSGlenn Strauss if (graceful_shutdown && !srv_shutdown)
19092d55953eSGlenn Strauss server_graceful_shutdown_maint(srv);
1910dbe3e236SGlenn Strauss connection_periodic_maint(srv, mono_ts);
1911bcdc6a3bSJan Kneschke }
1912bcdc6a3bSJan Kneschke
1913413c0e55SGlenn Strauss __attribute_noinline__
server_handle_sigchld(server * const srv)1914413c0e55SGlenn Strauss static void server_handle_sigchld (server * const srv) {
19159030cfaeSGlenn Strauss pid_t pid;
19169030cfaeSGlenn Strauss do {
19179030cfaeSGlenn Strauss int status;
191829f50bdeSGlenn Strauss pid = fdevent_waitpid(-1, &status, 1);
19199030cfaeSGlenn Strauss if (pid > 0) {
19209030cfaeSGlenn Strauss if (plugins_call_handle_waitpid(srv, pid, status) != HANDLER_GO_ON) {
19219030cfaeSGlenn Strauss continue;
19229030cfaeSGlenn Strauss }
19239030cfaeSGlenn Strauss if (0 == srv->srvconf.max_worker) {
19249030cfaeSGlenn Strauss /* check piped-loggers and restart, even if shutting down */
1925243510dbSGlenn Strauss if (fdlog_pipes_waitpid_cb(pid)) {
19269030cfaeSGlenn Strauss continue;
19279030cfaeSGlenn Strauss }
19289030cfaeSGlenn Strauss }
19299030cfaeSGlenn Strauss }
19309030cfaeSGlenn Strauss } while (pid > 0 || (-1 == pid && errno == EINTR));
19319030cfaeSGlenn Strauss }
19329030cfaeSGlenn Strauss
1933413c0e55SGlenn Strauss __attribute_hot__
__attribute_nonnull__()1934575665adSGlenn Strauss __attribute_nonnull__()
1935dc2d1dfeSGlenn Strauss static void server_run_con_queue (connection * const restrict joblist, const connection * const sentinel) {
1936dc2d1dfeSGlenn Strauss for (connection *con = joblist, *jqnext; con != sentinel; con = jqnext) {
1937dc2d1dfeSGlenn Strauss jqnext = con->jqnext;
1938dc2d1dfeSGlenn Strauss con->jqnext = NULL;
1939dc2d1dfeSGlenn Strauss connection_state_machine(con);
194052d9b0daSGlenn Strauss }
194152d9b0daSGlenn Strauss }
194252d9b0daSGlenn Strauss
194352d9b0daSGlenn Strauss __attribute_hot__
1944413c0e55SGlenn Strauss __attribute_noinline__
server_main_loop(server * const srv)19456c1d57a2SGlenn Strauss static void server_main_loop (server * const srv) {
1946309c1693SGlenn Strauss unix_time64_t last_active_ts = server_monotonic_secs();
1947b68b805cSGlenn Strauss log_epoch_secs = server_epoch_secs(srv, 0);
1948413c0e55SGlenn Strauss
1949413c0e55SGlenn Strauss while (!srv_shutdown) {
1950413c0e55SGlenn Strauss
1951413c0e55SGlenn Strauss if (handle_sig_hup) {
1952413c0e55SGlenn Strauss handle_sig_hup = 0;
19536c1d57a2SGlenn Strauss server_handle_sighup(srv);
1954413c0e55SGlenn Strauss }
1955413c0e55SGlenn Strauss
1956b1cc0856SGlenn Strauss /*(USE_ALARM not used; fdevent_poll() is effective periodic timer)*/
1957413c0e55SGlenn Strauss #ifdef USE_ALARM
1958b1cc0856SGlenn Strauss if (handle_sig_alarm) {
1959413c0e55SGlenn Strauss handle_sig_alarm = 0;
1960413c0e55SGlenn Strauss #endif
1961309c1693SGlenn Strauss unix_time64_t mono_ts = server_monotonic_secs();
1962dbe3e236SGlenn Strauss if (mono_ts != log_monotonic_secs) {
1963dbe3e236SGlenn Strauss server_handle_sigalrm(srv, mono_ts, last_active_ts);
1964413c0e55SGlenn Strauss }
1965b1cc0856SGlenn Strauss #ifdef USE_ALARM
1966413c0e55SGlenn Strauss }
1967b1cc0856SGlenn Strauss #endif
1968413c0e55SGlenn Strauss
1969413c0e55SGlenn Strauss if (handle_sig_child) {
1970413c0e55SGlenn Strauss handle_sig_child = 0;
1971413c0e55SGlenn Strauss server_handle_sigchld(srv);
1972413c0e55SGlenn Strauss }
1973413c0e55SGlenn Strauss
19746c1e6e66SGlenn Strauss if (graceful_shutdown) {
19756c1e6e66SGlenn Strauss server_graceful_state(srv);
197681a107b4SGlenn Strauss if (NULL == srv->conns && graceful_shutdown) {
1977aa34dfd3SGlenn Strauss /* we are in graceful shutdown phase and all connections are closed
1978aa34dfd3SGlenn Strauss * we are ready to terminate without harming anyone */
1979aa34dfd3SGlenn Strauss srv_shutdown = 1;
1980aa34dfd3SGlenn Strauss break;
1981aa34dfd3SGlenn Strauss }
19826c1e6e66SGlenn Strauss } else if (srv->sockets_disabled) {
19831a99aad1SGlenn Strauss server_overload_check(srv);
19845c20c426SJan Kneschke } else {
19851a99aad1SGlenn Strauss server_load_check(srv);
19865c20c426SJan Kneschke }
1987bcdc6a3bSJan Kneschke
1988dc2d1dfeSGlenn Strauss static connection * const sentinel =
1989dc2d1dfeSGlenn Strauss (connection *)(uintptr_t)&log_con_jqueue;
1990dc2d1dfeSGlenn Strauss connection * const joblist = log_con_jqueue;
1991dc2d1dfeSGlenn Strauss log_con_jqueue = sentinel;
1992dc2d1dfeSGlenn Strauss server_run_con_queue(joblist, sentinel);
1993784f1ac1SGlenn Strauss
1994dc2d1dfeSGlenn Strauss if (fdevent_poll(srv->ev, log_con_jqueue != sentinel ? 0 : 1000) > 0)
1995dbe3e236SGlenn Strauss last_active_ts = log_monotonic_secs;
1996bcdc6a3bSJan Kneschke }
19976c1e6e66SGlenn Strauss }
19986c1e6e66SGlenn Strauss
1999413c0e55SGlenn Strauss __attribute_cold__
20006800b082SGlenn Strauss __attribute_noinline__
main_init_once(void)20016800b082SGlenn Strauss static int main_init_once (void) {
20026c1e6e66SGlenn Strauss #ifdef HAVE_GETUID
20036c1e6e66SGlenn Strauss #ifndef HAVE_ISSETUGID
20046c1e6e66SGlenn Strauss #define issetugid() (geteuid() != getuid() || getegid() != getgid())
20056c1e6e66SGlenn Strauss #endif
20066c1e6e66SGlenn Strauss if (0 != getuid() && issetugid()) { /*check as early as possible in main()*/
20076c1e6e66SGlenn Strauss fprintf(stderr,
20086c1e6e66SGlenn Strauss "Are you nuts ? Don't apply a SUID bit to this binary\n");
20096800b082SGlenn Strauss return 0;
20106c1e6e66SGlenn Strauss }
20116c1e6e66SGlenn Strauss #endif
20126c1e6e66SGlenn Strauss
201343f0106fSGlenn Strauss #if defined(HAVE_MALLOPT) && defined(M_ARENA_MAX)
201443f0106fSGlenn Strauss #ifdef LIGHTTPD_STATIC
201543f0106fSGlenn Strauss mallopt(M_ARENA_MAX, 2); /*(ignore error, if any)*/
201643f0106fSGlenn Strauss #else
201743f0106fSGlenn Strauss {
201843f0106fSGlenn Strauss int (*mallopt_fn)(int, int);
201943f0106fSGlenn Strauss mallopt_fn = (int (*)(int, int))(intptr_t)dlsym(RTLD_DEFAULT,"mallopt");
202043f0106fSGlenn Strauss if (mallopt_fn) mallopt_fn(M_ARENA_MAX, 2); /*(ignore error, if any)*/
202143f0106fSGlenn Strauss }
202243f0106fSGlenn Strauss #endif
202343f0106fSGlenn Strauss #endif
202443f0106fSGlenn Strauss
20251a8d8e0cSGlenn Strauss #if defined(HAVE_MALLOC_TRIM)
20261a8d8e0cSGlenn Strauss malloc_top_pad = 524288;
20271a8d8e0cSGlenn Strauss {
20281a8d8e0cSGlenn Strauss const char * const top_pad_str = getenv("MALLOC_TOP_PAD_");
20291a8d8e0cSGlenn Strauss if (top_pad_str) {
20301a8d8e0cSGlenn Strauss unsigned long top_pad = strtoul(top_pad_str, NULL, 10);
20311a8d8e0cSGlenn Strauss if (top_pad != ULONG_MAX) malloc_top_pad = (size_t)top_pad;
20321a8d8e0cSGlenn Strauss }
20331a8d8e0cSGlenn Strauss }
20341a8d8e0cSGlenn Strauss #ifdef LIGHTTPD_STATIC
20351a8d8e0cSGlenn Strauss malloc_trim_fn = malloc_trim;
20361a8d8e0cSGlenn Strauss #else
20371a8d8e0cSGlenn Strauss malloc_trim_fn =
20381a8d8e0cSGlenn Strauss (int (*)(size_t))(intptr_t)dlsym(RTLD_DEFAULT,"malloc_trim");
20391a8d8e0cSGlenn Strauss #endif
20401a8d8e0cSGlenn Strauss #endif
20411a8d8e0cSGlenn Strauss
20426c1e6e66SGlenn Strauss /* for nice %b handling in strftime() */
20436c1e6e66SGlenn Strauss setlocale(LC_TIME, "C");
2044f8cc9fb9SGlenn Strauss tzset();
20456c1e6e66SGlenn Strauss
20466800b082SGlenn Strauss return 1;
20476800b082SGlenn Strauss }
20486800b082SGlenn Strauss
20496800b082SGlenn Strauss __attribute_cold__
main(int argc,char ** argv)20506800b082SGlenn Strauss int main (int argc, char ** argv) {
20516800b082SGlenn Strauss if (!main_init_once()) return -1;
20526800b082SGlenn Strauss
20536800b082SGlenn Strauss int rc;
20546800b082SGlenn Strauss
20556c1e6e66SGlenn Strauss do {
20566c1e6e66SGlenn Strauss server * const srv = server_init();
20576c1e6e66SGlenn Strauss
20586c1e6e66SGlenn Strauss if (graceful_restart) {
20596c1e6e66SGlenn Strauss server_sockets_restore(srv);
20606c1e6e66SGlenn Strauss optind = 1;
20616c1e6e66SGlenn Strauss }
20626c1e6e66SGlenn Strauss
20636c1d57a2SGlenn Strauss rc = server_main_setup(srv, argc, argv);
20646c1d57a2SGlenn Strauss if (rc > 0) {
20656c1d57a2SGlenn Strauss
20666c1d57a2SGlenn Strauss server_main_loop(srv);
20676c1d57a2SGlenn Strauss
2068aa34dfd3SGlenn Strauss if (graceful_shutdown || graceful_restart) {
2069aa34dfd3SGlenn Strauss server_graceful_state(srv);
2070aa34dfd3SGlenn Strauss }
2071aa34dfd3SGlenn Strauss
207281a107b4SGlenn Strauss if (NULL == srv->conns) rc = 0;
2073aa34dfd3SGlenn Strauss if (2 == graceful_shutdown) { /* value 2 indicates idle timeout */
2074010c2894SGlenn Strauss log_error(srv->errh, __FILE__, __LINE__,
2075aa34dfd3SGlenn Strauss "server stopped after idle timeout");
2076f279ae7dSGlenn Strauss } else if (!oneshot_fd) {
2077aa34dfd3SGlenn Strauss #ifdef HAVE_SIGACTION
2078010c2894SGlenn Strauss log_error(srv->errh, __FILE__, __LINE__,
2079010c2894SGlenn Strauss "server stopped by UID = %d PID = %d",
2080010c2894SGlenn Strauss (int)last_sigterm_info.si_uid,
2081010c2894SGlenn Strauss (int)last_sigterm_info.si_pid);
2082aa34dfd3SGlenn Strauss #else
2083010c2894SGlenn Strauss log_error(srv->errh, __FILE__, __LINE__,
2084aa34dfd3SGlenn Strauss "server stopped");
2085aa34dfd3SGlenn Strauss #endif
2086aa34dfd3SGlenn Strauss }
2087aa34dfd3SGlenn Strauss }
20886c1e6e66SGlenn Strauss
2089bcdc6a3bSJan Kneschke /* clean-up */
20906e62b842SGlenn Strauss chunkqueue_internal_pipes(0);
20916c1e6e66SGlenn Strauss remove_pid_file(srv);
2092fda01e33SGlenn Strauss config_log_error_close(srv);
20936c1e6e66SGlenn Strauss if (graceful_restart)
20946c1e6e66SGlenn Strauss server_sockets_save(srv);
20956c1e6e66SGlenn Strauss else
2096bcdc6a3bSJan Kneschke network_close(srv);
2097878073d1SGlenn Strauss request_pool_free();
20984b63eae5SJan Kneschke connections_free(srv);
2099bcdc6a3bSJan Kneschke plugins_free(srv);
2100bcdc6a3bSJan Kneschke server_free(srv);
2101bcdc6a3bSJan Kneschke
21026c1d57a2SGlenn Strauss if (rc < 0 || !graceful_restart) break;
21036c1e6e66SGlenn Strauss
21046c1e6e66SGlenn Strauss /* wait for all children to exit before graceful restart */
210529f50bdeSGlenn Strauss while (fdevent_waitpid(-1, NULL, 0) > 0) ;
21066c1e6e66SGlenn Strauss } while (graceful_restart);
21076c1e6e66SGlenn Strauss
21086c1e6e66SGlenn Strauss return rc;
2109bcdc6a3bSJan Kneschke }
2110