blob: f3cf30ec9c9076aa3f29222184eb713e869da76e [file] [log] [blame]
Willy Tarreaubaaee002006-06-26 02:48:02 +02001/*
Willy Tarreaua5357cd2021-05-09 06:14:25 +02002 * HAProxy : High Availability-enabled HTTP/TCP proxy
Willy Tarreau2454d6e2022-02-01 18:06:59 +01003 * Copyright 2000-2022 Willy Tarreau <willy@haproxy.org>.
Willy Tarreaubaaee002006-06-26 02:48:02 +02004 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version
8 * 2 of the License, or (at your option) any later version.
9 *
Ilya Shipitsin46a030c2020-07-05 16:36:08 +050010 * Please refer to RFC7230 - RFC7235 information about HTTP protocol, and
11 * RFC6265 for information about cookies usage. More generally, the IETF HTTP
Willy Tarreaubaaee002006-06-26 02:48:02 +020012 * Working Group's web site should be consulted for protocol related changes :
13 *
14 * http://ftp.ics.uci.edu/pub/ietf/http/
15 *
16 * Pending bugs (may be not fixed because never reproduced) :
17 * - solaris only : sometimes, an HTTP proxy with only a dispatch address causes
18 * the proxy to terminate (no core) if the client breaks the connection during
19 * the response. Seen on 1.1.8pre4, but never reproduced. May not be related to
20 * the snprintf() bug since requests were simple (GET / HTTP/1.0), but may be
21 * related to missing setsid() (fixed in 1.1.15)
22 * - a proxy with an invalid config will prevent the startup even if disabled.
23 *
24 * ChangeLog has moved to the CHANGELOG file.
25 *
Willy Tarreaubaaee002006-06-26 02:48:02 +020026 */
27
David Carlier7ece0962015-12-08 21:43:09 +000028#define _GNU_SOURCE
Willy Tarreaubaaee002006-06-26 02:48:02 +020029#include <stdio.h>
30#include <stdlib.h>
31#include <unistd.h>
32#include <string.h>
33#include <ctype.h>
Maxime de Roucy379d9c72016-05-13 23:52:56 +020034#include <dirent.h>
Maxime de Roucy379d9c72016-05-13 23:52:56 +020035#include <sys/stat.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020036#include <sys/time.h>
37#include <sys/types.h>
38#include <sys/socket.h>
39#include <netinet/tcp.h>
40#include <netinet/in.h>
41#include <arpa/inet.h>
42#include <netdb.h>
43#include <fcntl.h>
44#include <errno.h>
45#include <signal.h>
46#include <stdarg.h>
47#include <sys/resource.h>
Tim Duesterhusdfad6a42020-04-18 16:02:47 +020048#include <sys/utsname.h>
Marc-Antoine Perennou992709b2013-02-12 10:53:52 +010049#include <sys/wait.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020050#include <time.h>
51#include <syslog.h>
Michael Schererab012dd2013-01-12 18:35:19 +010052#include <grp.h>
Willy Tarreaud10385a2021-10-06 22:22:40 +020053
Willy Tarreau5e03dfa2021-10-06 22:53:51 +020054#ifdef USE_THREAD
55#include <pthread.h>
56#endif
57
Willy Tarreaufc6c0322012-11-16 16:12:27 +010058#ifdef USE_CPU_AFFINITY
Willy Tarreaufc6c0322012-11-16 16:12:27 +010059#include <sched.h>
David Carlier42d9e5a2018-11-12 16:22:19 +000060#if defined(__FreeBSD__) || defined(__DragonFly__)
Pieter Baauwcaa6a1b2015-09-17 21:26:40 +020061#include <sys/param.h>
David Carlier42d9e5a2018-11-12 16:22:19 +000062#ifdef __FreeBSD__
Pieter Baauwcaa6a1b2015-09-17 21:26:40 +020063#include <sys/cpuset.h>
David Carlier42d9e5a2018-11-12 16:22:19 +000064#endif
David Carlier5e4c8e22019-09-13 05:12:58 +010065#endif
Willy Tarreaufc6c0322012-11-16 16:12:27 +010066#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +020067
Willy Tarreau636848a2019-04-15 19:38:50 +020068#if defined(USE_PRCTL)
69#include <sys/prctl.h>
70#endif
71
devnexen@gmail.com21185972021-08-21 09:13:10 +010072#if defined(USE_PROCCTL)
73#include <sys/procctl.h>
74#endif
75
Willy Tarreaubaaee002006-06-26 02:48:02 +020076#ifdef DEBUG_FULL
77#include <assert.h>
78#endif
Tim Duesterhusd6942c82017-11-20 15:58:35 +010079#if defined(USE_SYSTEMD)
80#include <systemd/sd-daemon.h>
81#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +020082
Willy Tarreau6c3a6812020-03-06 18:57:15 +010083#include <import/sha1.h>
84
Willy Tarreaub2551052020-06-09 09:07:15 +020085#include <haproxy/acl.h>
Amaury Denoyelle68fd7e42021-03-25 17:15:52 +010086#include <haproxy/action.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020087#include <haproxy/activity.h>
88#include <haproxy/api.h>
89#include <haproxy/arg.h>
90#include <haproxy/auth.h>
Willy Tarreau8d366972020-05-27 16:10:29 +020091#include <haproxy/base64.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020092#include <haproxy/capture-t.h>
Willy Tarreau66243b42021-07-16 15:39:28 +020093#include <haproxy/cfgcond.h>
Amaury Denoyelle5a6926d2021-03-30 17:34:24 +020094#include <haproxy/cfgdiag.h>
Willy Tarreau6be78492020-06-05 00:00:29 +020095#include <haproxy/cfgparse.h>
Willy Tarreauc13ed532020-06-02 10:22:45 +020096#include <haproxy/chunk.h>
Willy Tarreau83487a82020-06-04 20:19:54 +020097#include <haproxy/cli.h>
Willy Tarreau55542642021-10-08 09:33:24 +020098#include <haproxy/clock.h>
Willy Tarreau7ea393d2020-06-04 18:02:10 +020099#include <haproxy/connection.h>
Amaury Denoyellea6f9c5d2021-04-23 16:58:08 +0200100#ifdef USE_CPU_AFFINITY
Amaury Denoyelle982fb532021-04-21 18:39:58 +0200101#include <haproxy/cpuset.h>
Amaury Denoyellea6f9c5d2021-04-23 16:58:08 +0200102#endif
Willy Tarreaueb92deb2020-06-04 10:53:16 +0200103#include <haproxy/dns.h>
Willy Tarreau2741c8c2020-06-02 11:28:02 +0200104#include <haproxy/dynbuf.h>
Willy Tarreau8d366972020-05-27 16:10:29 +0200105#include <haproxy/errors.h>
Willy Tarreaub2551052020-06-09 09:07:15 +0200106#include <haproxy/fd.h>
Willy Tarreauc7babd82020-06-04 21:29:29 +0200107#include <haproxy/filters.h>
Willy Tarreaub2551052020-06-09 09:07:15 +0200108#include <haproxy/global.h>
Willy Tarreau86416052020-06-04 09:20:54 +0200109#include <haproxy/hlua.h>
Willy Tarreauc761f842020-06-04 11:40:28 +0200110#include <haproxy/http_rules.h>
Willy Tarreau853b2972020-05-27 18:01:47 +0200111#include <haproxy/list.h>
Willy Tarreau213e9902020-06-04 14:58:24 +0200112#include <haproxy/listener.h>
Willy Tarreauaeed4a82020-06-04 22:01:04 +0200113#include <haproxy/log.h>
Willy Tarreaub5abe5b2020-06-04 14:07:37 +0200114#include <haproxy/mworker.h>
Willy Tarreau7a00efb2020-06-02 17:02:59 +0200115#include <haproxy/namespace.h>
Willy Tarreau6131d6a2020-06-02 16:48:09 +0200116#include <haproxy/net_helper.h>
Willy Tarreau6019fab2020-05-27 16:26:00 +0200117#include <haproxy/openssl-compat.h>
Willy Tarreau225a90a2020-06-04 15:06:28 +0200118#include <haproxy/pattern.h>
Willy Tarreau3c2a7c22020-06-04 18:38:21 +0200119#include <haproxy/peers.h>
Willy Tarreaub2551052020-06-09 09:07:15 +0200120#include <haproxy/pool.h>
121#include <haproxy/protocol.h>
Willy Tarreaubf3b06b2020-08-26 10:23:40 +0200122#include <haproxy/proto_tcp.h>
Willy Tarreaua264d962020-06-04 22:29:18 +0200123#include <haproxy/proxy.h>
Willy Tarreau7cd8b6e2020-06-02 17:32:26 +0200124#include <haproxy/regex.h>
Willy Tarreaub2551052020-06-09 09:07:15 +0200125#include <haproxy/sample.h>
Willy Tarreau1e56f922020-06-04 23:20:13 +0200126#include <haproxy/server.h>
Willy Tarreau48d25b32020-06-04 18:58:52 +0200127#include <haproxy/session.h>
Willy Tarreau3727a8a2020-06-04 17:37:26 +0200128#include <haproxy/signal.h>
Willy Tarreau063d47d2020-08-28 16:29:53 +0200129#include <haproxy/sock.h>
Willy Tarreau25140cc2020-08-28 15:40:33 +0200130#include <haproxy/sock_inet.h>
Willy Tarreau209108d2020-06-04 20:30:20 +0200131#include <haproxy/ssl_sock.h>
Amaury Denoyelleee63d4b2020-10-05 11:49:42 +0200132#include <haproxy/stats-t.h>
Willy Tarreaudfd3de82020-06-04 23:46:14 +0200133#include <haproxy/stream.h>
Willy Tarreaucea0e1b2020-06-04 17:25:40 +0200134#include <haproxy/task.h>
Willy Tarreau3f567e42020-05-28 15:29:19 +0200135#include <haproxy/thread.h>
Willy Tarreaub2551052020-06-09 09:07:15 +0200136#include <haproxy/time.h>
137#include <haproxy/tools.h>
138#include <haproxy/uri_auth-t.h>
Willy Tarreaua1718922020-06-04 16:25:31 +0200139#include <haproxy/vars.h>
Willy Tarreaub2551052020-06-09 09:07:15 +0200140#include <haproxy/version.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +0200141
Willy Tarreaubaaee002006-06-26 02:48:02 +0200142
Willy Tarreau7b5654f2019-03-29 21:30:17 +0100143/* array of init calls for older platforms */
144DECLARE_INIT_STAGES;
145
Willy Tarreauf4596402021-04-10 16:53:05 +0200146/* create a read_mostly section to hold variables which are accessed a lot
147 * but which almost never change. The purpose is to isolate them in their
148 * own cache lines where they don't risk to be perturbated by write accesses
149 * to neighbor variables. We need to create an empty aligned variable for
150 * this. The fact that the variable is of size zero means that it will be
151 * eliminated at link time if no other variable uses it, but alignment will
152 * be respected.
153 */
154empty_t __read_mostly_align HA_SECTION("read_mostly") ALIGNED(64);
155
Willy Tarreauf0d3b732021-05-06 16:30:32 +0200156#ifdef BUILD_FEATURES
157const char *build_features = BUILD_FEATURES;
158#else
159const char *build_features = "";
160#endif
161
Willy Tarreau477ecd82010-01-03 21:12:30 +0100162/* list of config files */
163static struct list cfg_cfgfiles = LIST_HEAD_INIT(cfg_cfgfiles);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200164int pid; /* current process id */
165
Willy Tarreauf8ea00e2020-03-12 17:24:53 +0100166volatile unsigned long sleeping_thread_mask = 0; /* Threads that are about to sleep in poll() */
Willy Tarreau4b3f27b2020-03-12 17:28:01 +0100167volatile unsigned long stopping_thread_mask = 0; /* Threads acknowledged stopping */
Willy Tarreauf8ea00e2020-03-12 17:24:53 +0100168
Willy Tarreaubaaee002006-06-26 02:48:02 +0200169/* global options */
170struct global global = {
Cyril Bonté203ec5a2017-03-23 22:44:13 +0100171 .hard_stop_after = TICK_ETERNITY,
Remi Tricot-Le Bretonb5d968d2022-04-08 18:04:18 +0200172 .close_spread_time = TICK_ETERNITY,
173 .close_spread_end = TICK_ETERNITY,
Amaury Denoyelle0f50cb92021-03-26 18:50:33 +0100174 .numa_cpu_mapping = 1,
Willy Tarreau149ab772019-01-26 14:27:06 +0100175 .nbthread = 0,
William Lallemand5f232402012-04-05 18:02:55 +0200176 .req_count = 0,
William Lallemand0f99e342011-10-12 17:50:54 +0200177 .logsrvs = LIST_HEAD_INIT(global.logsrvs),
Willy Tarreau197715a2022-04-25 19:29:10 +0200178 .maxzlibmem = DEFAULT_MAXZLIBMEM * 1024U * 1024U,
William Lallemandd85f9172012-11-09 17:05:39 +0100179 .comp_rate_lim = 0,
Emeric Brun850efd52014-01-29 12:24:34 +0100180 .ssl_server_verify = SSL_SERVER_VERIFY_REQUIRED,
Emeric Bruned760922010-10-22 17:59:25 +0200181 .unix_bind = {
182 .ux = {
183 .uid = -1,
184 .gid = -1,
185 .mode = 0,
186 }
187 },
Willy Tarreau27a674e2009-08-17 07:23:33 +0200188 .tune = {
Willy Tarreau7ac908b2019-02-27 12:02:18 +0100189 .options = GTUNE_LISTENER_MQ,
Willy Tarreauc77d3642018-12-12 06:19:42 +0100190 .bufsize = (BUFSIZE + 2*sizeof(void *) - 1) & -(2*sizeof(void *)),
Christopher Faulet546c4692020-01-22 14:31:21 +0100191 .maxrewrite = MAXREWRITE,
Willy Tarreaua24adf02014-11-27 01:11:56 +0100192 .reserved_bufs = RESERVED_BUFS,
Willy Tarreauf3045d22015-04-29 16:24:50 +0200193 .pattern_cache = DEFAULT_PAT_LRU_SIZE,
Olivier Houchard88698d92019-04-16 19:07:22 +0200194 .pool_low_ratio = 20,
195 .pool_high_ratio = 25,
Christopher Faulet41ba36f2019-07-19 09:36:45 +0200196 .max_http_hdr = MAX_HTTP_HDR,
Emeric Brunfc32aca2012-09-03 12:10:29 +0200197#ifdef USE_OPENSSL
Emeric Brun46635772012-11-14 11:32:56 +0100198 .sslcachesize = SSLCACHESIZE,
Emeric Brunfc32aca2012-09-03 12:10:29 +0200199#endif
William Lallemandf3747832012-11-09 12:33:10 +0100200 .comp_maxlevel = 1,
Willy Tarreau7e312732014-02-12 16:35:14 +0100201#ifdef DEFAULT_IDLE_TIMER
202 .idle_timer = DEFAULT_IDLE_TIMER,
203#else
204 .idle_timer = 1000, /* 1 second */
205#endif
Amaury Denoyelle97e84c62022-04-19 18:26:55 +0200206#ifdef USE_QUIC
207 .quic_streams_buf = 30,
208#endif /* USE_QUIC */
Willy Tarreau27a674e2009-08-17 07:23:33 +0200209 },
Emeric Brun76d88952012-10-05 15:47:31 +0200210#ifdef USE_OPENSSL
211#ifdef DEFAULT_MAXSSLCONN
Willy Tarreau403edff2012-09-06 11:58:37 +0200212 .maxsslconn = DEFAULT_MAXSSLCONN,
213#endif
Emeric Brun76d88952012-10-05 15:47:31 +0200214#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +0200215 /* others NULL OK */
216};
217
218/*********************************************************************/
219
220int stopping; /* non zero means stopping in progress */
Cyril Bonté203ec5a2017-03-23 22:44:13 +0100221int killed; /* non zero means a hard-stop is triggered */
Willy Tarreauaf7ad002010-08-31 15:39:26 +0200222int jobs = 0; /* number of active jobs (conns, listeners, active tasks, ...) */
William Lallemanda7199262018-11-16 16:57:20 +0100223int unstoppable_jobs = 0; /* number of active jobs that can't be stopped during a soft stop */
Willy Tarreau199ad242018-11-05 16:31:22 +0100224int active_peers = 0; /* number of active peers (connection attempts and connected) */
Willy Tarreau2d372c22018-11-05 17:12:27 +0100225int connected_peers = 0; /* number of connected peers (verified ones) */
Willy Tarreau392524d2022-02-17 18:10:36 +0100226int arg_mode = 0; /* MODE_DEBUG etc as passed on command line ... */
227char *change_dir = NULL; /* set when -C is passed */
228char *check_condition = NULL; /* check condition passed to -cc */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200229
Ilya Shipitsin46a030c2020-07-05 16:36:08 +0500230/* Here we store information about the pids of the processes we may pause
Willy Tarreaubaaee002006-06-26 02:48:02 +0200231 * or kill. We will send them a signal every 10 ms until we can bind to all
232 * our ports. With 200 retries, that's about 2 seconds.
233 */
234#define MAX_START_RETRIES 200
Willy Tarreaubaaee002006-06-26 02:48:02 +0200235static int *oldpids = NULL;
236static int oldpids_sig; /* use USR1 or TERM */
237
Olivier Houchardf73629d2017-04-05 22:33:04 +0200238/* Path to the unix socket we use to retrieve listener sockets from the old process */
239static const char *old_unixsocket;
240
William Lallemandcb11fd22017-06-01 17:38:52 +0200241int atexit_flag = 0;
242
Willy Tarreaubb545b42010-08-25 12:58:59 +0200243int nb_oldpids = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200244const int zero = 0;
245const int one = 1;
Alexandre Cassen87ea5482007-10-11 20:48:58 +0200246const struct linger nolinger = { .l_onoff = 1, .l_linger = 0 };
Willy Tarreaubaaee002006-06-26 02:48:02 +0200247
Willy Tarreau1d21e0a2010-03-12 21:58:54 +0100248char hostname[MAX_HOSTNAME_LEN];
Dragan Dosen4f014152020-06-18 16:56:47 +0200249char *localpeer = NULL;
Willy Tarreau76871a42022-03-08 16:01:40 +0100250static char *kwd_dump = NULL; // list of keyword dumps to produce
Willy Tarreaubaaee002006-06-26 02:48:02 +0200251
William Lallemand00417412020-06-05 14:08:41 +0200252static char **old_argv = NULL; /* previous argv but cleaned up */
William Lallemand73b85e72017-06-01 17:38:51 +0200253
William Lallemandbc193052018-09-11 10:06:26 +0200254struct list proc_list = LIST_HEAD_INIT(proc_list);
255
256int master = 0; /* 1 if in master, 0 if in child */
Willy Tarreaubf696402019-03-01 10:09:28 +0100257unsigned int rlim_fd_cur_at_boot = 0;
258unsigned int rlim_fd_max_at_boot = 0;
William Lallemandbc193052018-09-11 10:06:26 +0200259
Willy Tarreau6c3a6812020-03-06 18:57:15 +0100260/* per-boot randomness */
261unsigned char boot_seed[20]; /* per-boot random seed (160 bits initially) */
262
Willy Tarreau43ab05b2021-09-28 09:43:11 +0200263/* takes the thread config in argument or NULL for any thread */
William Lallemandb3f2be32018-09-11 10:06:18 +0200264static void *run_thread_poll_loop(void *data);
265
Willy Tarreauff055502014-04-28 22:27:06 +0200266/* bitfield of a few warnings to emit just once (WARN_*) */
267unsigned int warned = 0;
268
Amaury Denoyelle484454d2021-05-05 16:18:45 +0200269/* set if experimental features have been used for the current process */
Willy Tarreauedd42682022-02-25 10:10:00 +0100270unsigned int tainted = 0;
Amaury Denoyelle484454d2021-05-05 16:18:45 +0200271
Amaury Denoyelled2e53cd2021-05-06 16:21:39 +0200272unsigned int experimental_directives_allowed = 0;
273
274int check_kw_experimental(struct cfg_keyword *kw, const char *file, int linenum,
275 char **errmsg)
276{
277 if (kw->flags & KWF_EXPERIMENTAL) {
278 if (!experimental_directives_allowed) {
Amaury Denoyelle86c1d0f2021-05-07 15:07:21 +0200279 memprintf(errmsg, "parsing [%s:%d] : '%s' directive is experimental, must be allowed via a global 'expose-experimental-directives'",
Amaury Denoyelled2e53cd2021-05-06 16:21:39 +0200280 file, linenum, kw->kw);
281 return 1;
282 }
283 mark_tainted(TAINTED_CONFIG_EXP_KW_DECLARED);
284 }
285
286 return 0;
287}
288
William Lallemande7361152018-10-26 14:47:36 +0200289/* master CLI configuration (-S flag) */
290struct list mworker_cli_conf = LIST_HEAD_INIT(mworker_cli_conf);
Willy Tarreaucdb737e2016-12-21 18:43:10 +0100291
292/* These are strings to be reported in the output of "haproxy -vv". They may
293 * either be constants (in which case must_free must be zero) or dynamically
294 * allocated strings to pass to free() on exit, and in this case must_free
295 * must be non-zero.
296 */
297struct list build_opts_list = LIST_HEAD_INIT(build_opts_list);
298struct build_opts_str {
299 struct list list;
300 const char *str;
301 int must_free;
302};
303
Willy Tarreaubaaee002006-06-26 02:48:02 +0200304/*********************************************************************/
305/* general purpose functions ***************************************/
306/*********************************************************************/
307
Willy Tarreaucdb737e2016-12-21 18:43:10 +0100308/* used to register some build option strings at boot. Set must_free to
309 * non-zero if the string must be freed upon exit.
310 */
311void hap_register_build_opts(const char *str, int must_free)
312{
313 struct build_opts_str *b;
314
315 b = calloc(1, sizeof(*b));
316 if (!b) {
317 fprintf(stderr, "out of memory\n");
318 exit(1);
319 }
320 b->str = str;
321 b->must_free = must_free;
Willy Tarreau2b718102021-04-21 07:32:39 +0200322 LIST_APPEND(&build_opts_list, &b->list);
Willy Tarreaucdb737e2016-12-21 18:43:10 +0100323}
324
Willy Tarreaua43dfda2021-05-06 07:43:35 +0200325#define VERSION_MAX_ELTS 7
326
327/* This function splits an haproxy version string into an array of integers.
328 * The syntax of the supported version string is the following:
329 *
330 * <a>[.<b>[.<c>[.<d>]]][-{dev,pre,rc}<f>][-*][-<g>]
331 *
332 * This validates for example:
333 * 1.2.1-pre2, 1.2.1, 1.2.10.1, 1.3.16-rc1, 1.4-dev3, 1.5-dev18, 1.5-dev18-43
334 * 2.4-dev18-f6818d-20
335 *
336 * The result is set in a array of <VERSION_MAX_ELTS> elements. Each letter has
337 * one fixed place in the array. The tags take a numeric value called <e> which
338 * defaults to 3. "dev" is 1, "rc" and "pre" are 2. Numbers not encountered are
339 * considered as zero (henxe 1.5 and 1.5.0 are the same).
340 *
341 * The resulting values are:
342 * 1.2.1-pre2 1, 2, 1, 0, 2, 2, 0
343 * 1.2.1 1, 2, 1, 0, 3, 0, 0
344 * 1.2.10.1 1, 2, 10, 1, 3, 0, 0
345 * 1.3.16-rc1 1, 3, 16, 0, 2, 1, 0
346 * 1.4-dev3 1, 4, 0, 0, 1, 3, 0
347 * 1.5-dev18 1, 5, 0, 0, 1, 18, 0
348 * 1.5-dev18-43 1, 5, 0, 0, 1, 18, 43
349 * 2.4-dev18-f6818d-20 2, 4, 0, 0, 1, 18, 20
350 *
351 * The function returns non-zero if the conversion succeeded, or zero if it
352 * failed.
353 */
354int split_version(const char *version, unsigned int *value)
355{
356 const char *p, *s;
357 char *error;
358 int nelts;
359
360 /* Initialize array with zeroes */
361 for (nelts = 0; nelts < VERSION_MAX_ELTS; nelts++)
362 value[nelts] = 0;
363 value[4] = 3;
364
365 p = version;
366
367 /* If the version number is empty, return false */
368 if (*p == '\0')
369 return 0;
370
371 /* Convert first number <a> */
372 value[0] = strtol(p, &error, 10);
373 p = error + 1;
374 if (*error == '\0')
375 return 1;
376 if (*error == '-')
377 goto split_version_tag;
378 if (*error != '.')
379 return 0;
380
381 /* Convert first number <b> */
382 value[1] = strtol(p, &error, 10);
383 p = error + 1;
384 if (*error == '\0')
385 return 1;
386 if (*error == '-')
387 goto split_version_tag;
388 if (*error != '.')
389 return 0;
390
391 /* Convert first number <c> */
392 value[2] = strtol(p, &error, 10);
393 p = error + 1;
394 if (*error == '\0')
395 return 1;
396 if (*error == '-')
397 goto split_version_tag;
398 if (*error != '.')
399 return 0;
400
401 /* Convert first number <d> */
402 value[3] = strtol(p, &error, 10);
403 p = error + 1;
404 if (*error == '\0')
405 return 1;
406 if (*error != '-')
407 return 0;
408
409 split_version_tag:
410 /* Check for commit number */
411 if (*p >= '0' && *p <= '9')
412 goto split_version_commit;
413
414 /* Read tag */
415 if (strncmp(p, "dev", 3) == 0) { value[4] = 1; p += 3; }
416 else if (strncmp(p, "rc", 2) == 0) { value[4] = 2; p += 2; }
417 else if (strncmp(p, "pre", 3) == 0) { value[4] = 2; p += 3; }
418 else
419 goto split_version_commit;
420
421 /* Convert tag number */
422 value[5] = strtol(p, &error, 10);
423 p = error + 1;
424 if (*error == '\0')
425 return 1;
426 if (*error != '-')
427 return 0;
428
429 split_version_commit:
430 /* Search the last "-" */
431 s = strrchr(p, '-');
432 if (s) {
433 s++;
434 if (*s == '\0')
435 return 0;
436 value[6] = strtol(s, &error, 10);
437 if (*error != '\0')
438 value[6] = 0;
439 return 1;
440 }
441
442 /* convert the version */
443 value[6] = strtol(p, &error, 10);
444 if (*error != '\0')
445 value[6] = 0;
446
447 return 1;
448}
449
450/* This function compares the current haproxy version with an arbitrary version
451 * string. It returns:
452 * -1 : the version in argument is older than the current haproxy version
453 * 0 : the version in argument is the same as the current haproxy version
454 * 1 : the version in argument is newer than the current haproxy version
455 *
456 * Or some errors:
457 * -2 : the current haproxy version is not parsable
458 * -3 : the version in argument is not parsable
459 */
460int compare_current_version(const char *version)
461{
462 unsigned int loc[VERSION_MAX_ELTS];
463 unsigned int mod[VERSION_MAX_ELTS];
464 int i;
465
466 /* split versions */
467 if (!split_version(haproxy_version, loc))
468 return -2;
469 if (!split_version(version, mod))
470 return -3;
471
472 /* compare versions */
473 for (i = 0; i < VERSION_MAX_ELTS; i++) {
474 if (mod[i] < loc[i])
475 return -1;
476 else if (mod[i] > loc[i])
477 return 1;
478 }
479 return 0;
480}
481
Willy Tarreau1b5af7c2016-12-21 18:19:57 +0100482static void display_version()
Willy Tarreaubaaee002006-06-26 02:48:02 +0200483{
Tim Duesterhusdfad6a42020-04-18 16:02:47 +0200484 struct utsname utsname;
485
Willy Tarreaua5357cd2021-05-09 06:14:25 +0200486 printf("HAProxy version %s %s - https://haproxy.org/\n"
Willy Tarreau08dd2022019-11-21 18:07:30 +0100487 PRODUCT_STATUS "\n", haproxy_version, haproxy_date);
Willy Tarreau47479eb2019-11-21 18:48:20 +0100488
489 if (strlen(PRODUCT_URL_BUGS) > 0) {
490 char base_version[20];
491 int dots = 0;
492 char *del;
493
494 /* only retrieve the base version without distro-specific extensions */
495 for (del = haproxy_version; *del; del++) {
496 if (*del == '.')
497 dots++;
498 else if (*del < '0' || *del > '9')
499 break;
500 }
501
502 strlcpy2(base_version, haproxy_version, del - haproxy_version + 1);
503 if (dots < 2)
504 printf("Known bugs: https://github.com/haproxy/haproxy/issues?q=is:issue+is:open\n");
505 else
506 printf("Known bugs: " PRODUCT_URL_BUGS "\n", base_version);
507 }
Tim Duesterhusdfad6a42020-04-18 16:02:47 +0200508
509 if (uname(&utsname) == 0) {
510 printf("Running on: %s %s %s %s\n", utsname.sysname, utsname.release, utsname.version, utsname.machine);
511 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200512}
513
Willy Tarreau1b5af7c2016-12-21 18:19:57 +0100514static void display_build_opts()
Willy Tarreau7b066db2007-12-02 11:28:59 +0100515{
Willy Tarreaucdb737e2016-12-21 18:43:10 +0100516 struct build_opts_str *item;
517
Willy Tarreau7b066db2007-12-02 11:28:59 +0100518 printf("Build options :"
519#ifdef BUILD_TARGET
Willy Tarreau9f2b7302008-01-02 20:48:34 +0100520 "\n TARGET = " BUILD_TARGET
Willy Tarreau7b066db2007-12-02 11:28:59 +0100521#endif
522#ifdef BUILD_CPU
Willy Tarreau9f2b7302008-01-02 20:48:34 +0100523 "\n CPU = " BUILD_CPU
Willy Tarreau7b066db2007-12-02 11:28:59 +0100524#endif
525#ifdef BUILD_CC
Willy Tarreau9f2b7302008-01-02 20:48:34 +0100526 "\n CC = " BUILD_CC
527#endif
528#ifdef BUILD_CFLAGS
529 "\n CFLAGS = " BUILD_CFLAGS
Willy Tarreau7b066db2007-12-02 11:28:59 +0100530#endif
Willy Tarreau9f2b7302008-01-02 20:48:34 +0100531#ifdef BUILD_OPTIONS
532 "\n OPTIONS = " BUILD_OPTIONS
Willy Tarreau7b066db2007-12-02 11:28:59 +0100533#endif
Tim Duesterhusc8d19702020-11-21 18:07:59 +0100534#ifdef BUILD_DEBUG
535 "\n DEBUG = " BUILD_DEBUG
536#endif
Willy Tarreau7728ed32019-03-27 13:20:08 +0100537#ifdef BUILD_FEATURES
538 "\n\nFeature list : " BUILD_FEATURES
539#endif
Willy Tarreau27a674e2009-08-17 07:23:33 +0200540 "\n\nDefault settings :"
Willy Tarreauca783d42019-03-13 10:03:07 +0100541 "\n bufsize = %d, maxrewrite = %d, maxpollevents = %d"
Willy Tarreau27a674e2009-08-17 07:23:33 +0200542 "\n\n",
Willy Tarreauca783d42019-03-13 10:03:07 +0100543 BUFSIZE, MAXREWRITE, MAX_POLL_EVENTS);
Willy Tarreaube5b6852009-10-03 18:57:08 +0200544
Willy Tarreaucdb737e2016-12-21 18:43:10 +0100545 list_for_each_entry(item, &build_opts_list, list) {
546 puts(item->str);
547 }
548
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +0100549 putchar('\n');
550
Willy Tarreaube5b6852009-10-03 18:57:08 +0200551 list_pollers(stdout);
552 putchar('\n');
Christopher Faulet98d9fe22018-04-10 14:37:32 +0200553 list_mux_proto(stdout);
554 putchar('\n');
Willy Tarreau679bba12019-03-19 08:08:10 +0100555 list_services(stdout);
556 putchar('\n');
Christopher Fauletb3f4e142016-03-07 12:46:38 +0100557 list_filters(stdout);
558 putchar('\n');
Willy Tarreau7b066db2007-12-02 11:28:59 +0100559}
560
Willy Tarreaubaaee002006-06-26 02:48:02 +0200561/*
562 * This function prints the command line usage and exits
563 */
Willy Tarreau1b5af7c2016-12-21 18:19:57 +0100564static void usage(char *name)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200565{
566 display_version();
567 fprintf(stderr,
Maxime de Roucy379d9c72016-05-13 23:52:56 +0200568 "Usage : %s [-f <cfgfile|cfgdir>]* [ -vdV"
Willy Tarreaubaaee002006-06-26 02:48:02 +0200569 "D ] [ -n <maxconn> ] [ -N <maxpconn> ]\n"
Willy Tarreaua088d312015-10-08 11:58:48 +0200570 " [ -p <pidfile> ] [ -m <max megs> ] [ -C <dir> ] [-- <cfgfile>*]\n"
Willy Tarreau7b066db2007-12-02 11:28:59 +0100571 " -v displays version ; -vv shows known build options.\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +0200572 " -d enters debug mode ; -db only disables background mode.\n"
Willy Tarreauf4b79c42022-02-23 15:20:53 +0100573 " -dM[<byte>,help,...] debug memory (default: poison with <byte>/0x50)\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +0200574 " -V enters verbose mode (disables quiet mode)\n"
Willy Tarreau576132e2011-09-10 19:26:56 +0200575 " -D goes daemon ; -C changes to <dir> before loading files.\n"
William Lallemand095ba4c2017-06-01 17:38:50 +0200576 " -W master-worker mode.\n"
Tim Duesterhusd6942c82017-11-20 15:58:35 +0100577#if defined(USE_SYSTEMD)
578 " -Ws master-worker mode with systemd notify support.\n"
579#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +0200580 " -q quiet mode : don't display messages\n"
Willy Tarreau5d01a632009-06-22 16:02:30 +0200581 " -c check mode : only check config files and exit\n"
Maximilian Maderfc0cceb2021-06-06 00:50:22 +0200582 " -cc check condition : evaluate a condition and exit\n"
Willy Tarreauca783d42019-03-13 10:03:07 +0100583 " -n sets the maximum total # of connections (uses ulimit -n)\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +0200584 " -m limits the usable amount of memory (in MB)\n"
585 " -N sets the default, per-proxy maximum # of connections (%d)\n"
Emeric Brun2b920a12010-09-23 18:30:22 +0200586 " -L set local peer name (default to hostname)\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +0200587 " -p writes pids of all children to this file\n"
Willy Tarreaue5733232019-05-22 19:24:06 +0200588#if defined(USE_EPOLL)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200589 " -de disables epoll() usage even when available\n"
590#endif
Willy Tarreaue5733232019-05-22 19:24:06 +0200591#if defined(USE_KQUEUE)
Willy Tarreau1e63130a2007-04-09 12:03:06 +0200592 " -dk disables kqueue() usage even when available\n"
593#endif
Willy Tarreaue5733232019-05-22 19:24:06 +0200594#if defined(USE_EVPORTS)
Emmanuel Hocdet0ba4f482019-04-08 16:53:32 +0000595 " -dv disables event ports usage even when available\n"
596#endif
Willy Tarreaue5733232019-05-22 19:24:06 +0200597#if defined(USE_POLL)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200598 " -dp disables poll() usage even when available\n"
599#endif
Willy Tarreaue5733232019-05-22 19:24:06 +0200600#if defined(USE_LINUX_SPLICE)
Willy Tarreau3ab68cf2009-01-25 16:03:28 +0100601 " -dS disables splice usage (broken on old kernels)\n"
602#endif
Nenad Merdanovic88afe032014-04-14 15:56:58 +0200603#if defined(USE_GETADDRINFO)
604 " -dG disables getaddrinfo() usage\n"
605#endif
Lukas Tribusa0bcbdc2016-09-12 21:42:20 +0000606#if defined(SO_REUSEPORT)
607 " -dR disables SO_REUSEPORT usage\n"
608#endif
Willy Tarreau654726d2021-12-28 15:43:11 +0100609#if defined(HA_HAVE_DUMP_LIBS)
610 " -dL dumps loaded object files after config checks\n"
611#endif
Willy Tarreau76871a42022-03-08 16:01:40 +0100612 " -dK{class[,...]} dump registered keywords (use 'help' for list)\n"
Willy Tarreau3eed10e2016-11-07 21:03:16 +0100613 " -dr ignores server address resolution failures\n"
Emeric Brun850efd52014-01-29 12:24:34 +0100614 " -dV disables SSL verify on servers side\n"
Willy Tarreau3eb10b82020-04-15 16:42:39 +0200615 " -dW fails if any warning is emitted\n"
Amaury Denoyelle7b01a8d2021-03-29 10:29:07 +0200616 " -dD diagnostic mode : warn about suspicious configuration statements\n"
Willy Tarreauc6ca1aa2015-10-08 11:32:32 +0200617 " -sf/-st [pid ]* finishes/terminates old pids.\n"
Olivier Houchardf73629d2017-04-05 22:33:04 +0200618 " -x <unix_socket> get listening sockets from a unix socket\n"
William Lallemand63329e32019-06-13 17:03:37 +0200619 " -S <bind>[,<bind options>...] new master CLI\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +0200620 "\n",
Willy Tarreauca783d42019-03-13 10:03:07 +0100621 name, cfg_maxpconn);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200622 exit(1);
623}
624
625
626
627/*********************************************************************/
628/* more specific functions ***************************************/
629/*********************************************************************/
630
William Lallemand73b85e72017-06-01 17:38:51 +0200631/* sends the signal <sig> to all pids found in <oldpids>. Returns the number of
632 * pids the signal was correctly delivered to.
633 */
William Lallemande25473c2019-04-01 11:29:56 +0200634int tell_old_pids(int sig)
William Lallemand73b85e72017-06-01 17:38:51 +0200635{
636 int p;
637 int ret = 0;
638 for (p = 0; p < nb_oldpids; p++)
639 if (kill(oldpids[p], sig) == 0)
640 ret++;
641 return ret;
642}
643
William Lallemand75ea0a02017-11-15 19:02:58 +0100644/*
William Lallemand73b85e72017-06-01 17:38:51 +0200645 * remove a pid forom the olpid array and decrease nb_oldpids
646 * return 1 pid was found otherwise return 0
647 */
648
649int delete_oldpid(int pid)
650{
651 int i;
652
653 for (i = 0; i < nb_oldpids; i++) {
654 if (oldpids[i] == pid) {
655 oldpids[i] = oldpids[nb_oldpids - 1];
656 oldpids[nb_oldpids - 1] = 0;
657 nb_oldpids--;
658 return 1;
659 }
660 }
661 return 0;
662}
663
William Lallemand85b0bd92017-06-01 17:38:53 +0200664
William Lallemand73b85e72017-06-01 17:38:51 +0200665/*
666 * When called, this function reexec haproxy with -sf followed by current
Joseph Herlant03420902018-11-15 10:41:50 -0800667 * children PIDs and possibly old children PIDs if they didn't leave yet.
William Lallemand73b85e72017-06-01 17:38:51 +0200668 */
William Lallemandfab0fdc2021-11-09 18:01:22 +0100669static void mworker_reexec()
William Lallemand73b85e72017-06-01 17:38:51 +0200670{
William Lallemand00417412020-06-05 14:08:41 +0200671 char **next_argv = NULL;
672 int old_argc = 0; /* previous number of argument */
William Lallemand73b85e72017-06-01 17:38:51 +0200673 int next_argc = 0;
William Lallemand00417412020-06-05 14:08:41 +0200674 int i = 0;
William Lallemand73b85e72017-06-01 17:38:51 +0200675 char *msg = NULL;
Willy Tarreau8dca1952019-03-01 10:21:55 +0100676 struct rlimit limit;
William Lallemand2be557f2021-11-24 18:45:37 +0100677 struct mworker_proc *current_child = NULL;
William Lallemand73b85e72017-06-01 17:38:51 +0200678
679 mworker_block_signals();
Tim Duesterhusd6942c82017-11-20 15:58:35 +0100680#if defined(USE_SYSTEMD)
681 if (global.tune.options & GTUNE_USE_SYSTEMD)
682 sd_notify(0, "RELOADING=1");
683#endif
William Lallemand73b85e72017-06-01 17:38:51 +0200684 setenv("HAPROXY_MWORKER_REEXEC", "1", 1);
685
William Lallemand55a921c2022-01-28 21:17:30 +0100686 mworker_cleanup_proc();
William Lallemandbc193052018-09-11 10:06:26 +0200687 mworker_proc_list_to_env(); /* put the children description in the env */
688
William Lallemandc4810b82021-11-18 10:51:30 +0100689 /* ensure that we close correctly every listeners before reexecuting */
690 mworker_cleanlisteners();
691
William Lallemand7c756a82018-11-26 11:53:40 +0100692 /* during the reload we must ensure that every FDs that can't be
693 * reuse (ie those that are not referenced in the proc_list)
694 * are closed or they will leak. */
695
696 /* close the listeners FD */
697 mworker_cli_proxy_stop();
William Lallemand16866672019-06-24 17:40:48 +0200698
William Lallemand67e371e2021-11-25 10:03:44 +0100699 if (fdtab)
700 deinit_pollers();
William Lallemandefd95472021-11-26 14:43:57 +0100701
Ilya Shipitsin98a9e1b2021-02-19 23:42:53 +0500702#ifdef HAVE_SSL_RAND_KEEP_RANDOM_DEVICES_OPEN
William Lallemand5fdb5b32019-10-15 14:04:08 +0200703 /* close random device FDs */
704 RAND_keep_random_devices_open(0);
Rob Allen56996da2019-05-03 09:11:32 +0100705#endif
William Lallemand7c756a82018-11-26 11:53:40 +0100706
Willy Tarreau8dca1952019-03-01 10:21:55 +0100707 /* restore the initial FD limits */
708 limit.rlim_cur = rlim_fd_cur_at_boot;
709 limit.rlim_max = rlim_fd_max_at_boot;
710 if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
711 getrlimit(RLIMIT_NOFILE, &limit);
712 ha_warning("Failed to restore initial FD limits (cur=%u max=%u), using cur=%u max=%u\n",
713 rlim_fd_cur_at_boot, rlim_fd_max_at_boot,
714 (unsigned int)limit.rlim_cur, (unsigned int)limit.rlim_max);
715 }
716
William Lallemand73b85e72017-06-01 17:38:51 +0200717 /* compute length */
William Lallemand00417412020-06-05 14:08:41 +0200718 while (old_argv[old_argc])
719 old_argc++;
William Lallemand73b85e72017-06-01 17:38:51 +0200720
William Lallemand85b0bd92017-06-01 17:38:53 +0200721 /* 1 for haproxy -sf, 2 for -x /socket */
William Lallemandaba7f8b2021-04-21 16:55:34 +0200722 next_argv = calloc(old_argc + 1 + 2 + mworker_child_nb() + 1,
Tim Duesterhuse52b6e52020-09-12 20:26:43 +0200723 sizeof(*next_argv));
William Lallemand73b85e72017-06-01 17:38:51 +0200724 if (next_argv == NULL)
725 goto alloc_error;
726
William Lallemand00417412020-06-05 14:08:41 +0200727 /* copy the program name */
728 next_argv[next_argc++] = old_argv[0];
729
730 /* insert the new options just after argv[0] in case we have a -- */
731
William Lallemandbefab9e2021-11-25 00:49:19 +0100732 if (getenv("HAPROXY_MWORKER_WAIT_ONLY") == NULL) {
733 /* add -sf <PID>* to argv */
734 if (mworker_child_nb() > 0) {
735 struct mworker_proc *child;
William Lallemand3f128872019-04-01 11:29:59 +0200736
William Lallemandbefab9e2021-11-25 00:49:19 +0100737 next_argv[next_argc++] = "-sf";
William Lallemand3f128872019-04-01 11:29:59 +0200738
William Lallemandbefab9e2021-11-25 00:49:19 +0100739 list_for_each_entry(child, &proc_list, list) {
740 if (!(child->options & PROC_O_LEAVING) && (child->options & PROC_O_TYPE_WORKER))
741 current_child = child;
William Lallemand2be557f2021-11-24 18:45:37 +0100742
William Lallemandbefab9e2021-11-25 00:49:19 +0100743 if (!(child->options & (PROC_O_TYPE_WORKER|PROC_O_TYPE_PROG)) || child->pid <= -1)
744 continue;
745 if ((next_argv[next_argc++] = memprintf(&msg, "%d", child->pid)) == NULL)
746 goto alloc_error;
747 msg = NULL;
748 }
William Lallemand73b85e72017-06-01 17:38:51 +0200749 }
William Lallemand2be557f2021-11-24 18:45:37 +0100750
751 if (current_child) {
752 /* add the -x option with the socketpair of the current worker */
753 next_argv[next_argc++] = "-x";
754 if ((next_argv[next_argc++] = memprintf(&msg, "sockpair@%d", current_child->ipc_fd[0])) == NULL)
755 goto alloc_error;
756 msg = NULL;
757 }
William Lallemand85b0bd92017-06-01 17:38:53 +0200758 }
759
William Lallemand00417412020-06-05 14:08:41 +0200760 /* copy the previous options */
761 for (i = 1; i < old_argc; i++)
762 next_argv[next_argc++] = old_argv[i];
763
Willy Tarreaue0d86e22019-08-26 10:37:39 +0200764 signal(SIGPROF, SIG_IGN);
Tim Duesterhus0436ab72017-11-12 17:39:18 +0100765 execvp(next_argv[0], next_argv);
Christopher Faulet767a84b2017-11-24 16:50:31 +0100766 ha_warning("Failed to reexecute the master process [%d]: %s\n", pid, strerror(errno));
Willy Tarreau61cfdf42021-02-20 10:46:51 +0100767 ha_free(&next_argv);
William Lallemand722d4ca2017-11-15 19:02:55 +0100768 return;
769
William Lallemand73b85e72017-06-01 17:38:51 +0200770alloc_error:
Willy Tarreau61cfdf42021-02-20 10:46:51 +0100771 ha_free(&next_argv);
Joseph Herlant07a08342018-11-15 10:43:05 -0800772 ha_warning("Failed to reexecute the master process [%d]: Cannot allocate memory\n", pid);
William Lallemand73b85e72017-06-01 17:38:51 +0200773 return;
774}
775
William Lallemandfab0fdc2021-11-09 18:01:22 +0100776/* reexec haproxy in waitmode */
777static void mworker_reexec_waitmode()
778{
779 setenv("HAPROXY_MWORKER_WAIT_ONLY", "1", 1);
780 mworker_reexec();
781}
782
783/* reload haproxy and emit a warning */
784void mworker_reload()
785{
William Lallemandad221f42021-11-09 18:43:59 +0100786 struct mworker_proc *child;
William Lallemandefd95472021-11-26 14:43:57 +0100787 struct per_thread_deinit_fct *ptdf;
William Lallemandad221f42021-11-09 18:43:59 +0100788
William Lallemand836bda22021-11-09 18:16:47 +0100789 ha_notice("Reloading HAProxy\n");
William Lallemandad221f42021-11-09 18:43:59 +0100790
William Lallemandefd95472021-11-26 14:43:57 +0100791 /* close the poller FD and the thread waker pipe FD */
792 list_for_each_entry(ptdf, &per_thread_deinit_list, list)
793 ptdf->fct();
794
William Lallemandad221f42021-11-09 18:43:59 +0100795 /* increment the number of reloads */
796 list_for_each_entry(child, &proc_list, list) {
797 child->reloads++;
798 }
799
William Lallemandfab0fdc2021-11-09 18:01:22 +0100800 mworker_reexec();
801}
802
William Lallemandb3f2be32018-09-11 10:06:18 +0200803static void mworker_loop()
804{
805
806#if defined(USE_SYSTEMD)
807 if (global.tune.options & GTUNE_USE_SYSTEMD)
808 sd_notifyf(0, "READY=1\nMAINPID=%lu", (unsigned long)getpid());
809#endif
Willy Tarreaud83b6c12019-04-18 11:31:36 +0200810 /* Busy polling makes no sense in the master :-) */
811 global.tune.options &= ~GTUNE_BUSY_POLLING;
William Lallemandb3f2be32018-09-11 10:06:18 +0200812
William Lallemandbc193052018-09-11 10:06:26 +0200813
Willy Tarreaud26c9f92019-12-11 14:24:07 +0100814 signal_unregister(SIGTTIN);
815 signal_unregister(SIGTTOU);
William Lallemand0564d412018-11-20 17:36:53 +0100816 signal_unregister(SIGUSR1);
817 signal_unregister(SIGHUP);
818 signal_unregister(SIGQUIT);
819
William Lallemandb3f2be32018-09-11 10:06:18 +0200820 signal_register_fct(SIGTERM, mworker_catch_sigterm, SIGTERM);
821 signal_register_fct(SIGUSR1, mworker_catch_sigterm, SIGUSR1);
Willy Tarreaud26c9f92019-12-11 14:24:07 +0100822 signal_register_fct(SIGTTIN, mworker_broadcast_signal, SIGTTIN);
823 signal_register_fct(SIGTTOU, mworker_broadcast_signal, SIGTTOU);
William Lallemandb3f2be32018-09-11 10:06:18 +0200824 signal_register_fct(SIGINT, mworker_catch_sigterm, SIGINT);
825 signal_register_fct(SIGHUP, mworker_catch_sighup, SIGHUP);
826 signal_register_fct(SIGUSR2, mworker_catch_sighup, SIGUSR2);
827 signal_register_fct(SIGCHLD, mworker_catch_sigchld, SIGCHLD);
828
829 mworker_unblock_signals();
William Lallemand27f3fa52018-12-06 14:05:20 +0100830 mworker_cleantasks();
William Lallemandb3f2be32018-09-11 10:06:18 +0200831
William Lallemandbc193052018-09-11 10:06:26 +0200832 mworker_catch_sigchld(NULL); /* ensure we clean the children in case
833 some SIGCHLD were lost */
834
William Lallemandb3f2be32018-09-11 10:06:18 +0200835 global.nbthread = 1;
William Lallemandb3f2be32018-09-11 10:06:18 +0200836
William Lallemand2672eb92018-12-14 15:52:39 +0100837#ifdef USE_THREAD
838 tid_bit = 1;
839 all_threads_mask = 1;
840#endif
841
William Lallemandb3f2be32018-09-11 10:06:18 +0200842 jobs++; /* this is the "master" job, we want to take care of the
843 signals even if there is no listener so the poll loop don't
844 leave */
845
846 fork_poller();
Willy Tarreau43ab05b2021-09-28 09:43:11 +0200847 run_thread_poll_loop(NULL);
William Lallemandb3f2be32018-09-11 10:06:18 +0200848}
William Lallemandcb11fd22017-06-01 17:38:52 +0200849
850/*
851 * Reexec the process in failure mode, instead of exiting
852 */
853void reexec_on_failure()
854{
William Lallemand68836742021-11-10 10:49:06 +0100855 struct mworker_proc *child;
856
William Lallemandcb11fd22017-06-01 17:38:52 +0200857 if (!atexit_flag)
858 return;
William Lallemand68836742021-11-10 10:49:06 +0100859
860 /* get the info of the children in the env */
861 if (mworker_env_to_proc_list() < 0) {
862 exit(EXIT_FAILURE);
863 }
864
865 /* increment the number of failed reloads */
866 list_for_each_entry(child, &proc_list, list) {
867 child->failedreloads++;
868 }
869
Willy Tarreaue08acae2022-01-28 18:40:06 +0100870 /* do not keep unused FDs retrieved from the previous process */
871 sock_drop_unused_old_sockets();
872
William Lallemandfab0fdc2021-11-09 18:01:22 +0100873 usermsgs_clr(NULL);
William Lallemand836bda22021-11-09 18:16:47 +0100874 ha_warning("Loading failure!\n");
William Lallemandfab0fdc2021-11-09 18:01:22 +0100875 mworker_reexec_waitmode();
William Lallemandcb11fd22017-06-01 17:38:52 +0200876}
William Lallemand73b85e72017-06-01 17:38:51 +0200877
878
879/*
Willy Tarreaud0807c32010-08-27 18:26:11 +0200880 * upon SIGUSR1, let's have a soft stop. Note that soft_stop() broadcasts
881 * a signal zero to all subscribers. This means that it's as easy as
882 * subscribing to signal 0 to get informed about an imminent shutdown.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200883 */
Willy Tarreau1b5af7c2016-12-21 18:19:57 +0100884static void sig_soft_stop(struct sig_handler *sh)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200885{
886 soft_stop();
Willy Tarreau24f4efa2010-08-27 17:56:48 +0200887 signal_unregister_handler(sh);
Willy Tarreaubafbe012017-11-24 17:34:44 +0100888 pool_gc(NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200889}
890
891/*
892 * upon SIGTTOU, we pause everything
893 */
Willy Tarreau1b5af7c2016-12-21 18:19:57 +0100894static void sig_pause(struct sig_handler *sh)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200895{
Willy Tarreau775e0012020-09-24 16:36:26 +0200896 if (protocol_pause_all() & ERR_FATAL) {
897 const char *msg = "Some proxies refused to pause, performing soft stop now.\n";
Willy Tarreau0a002df2020-10-09 19:26:27 +0200898 ha_warning("%s", msg);
899 send_log(NULL, LOG_WARNING, "%s", msg);
Willy Tarreau775e0012020-09-24 16:36:26 +0200900 soft_stop();
901 }
Willy Tarreaubafbe012017-11-24 17:34:44 +0100902 pool_gc(NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200903}
904
905/*
906 * upon SIGTTIN, let's have a soft stop.
907 */
Willy Tarreau1b5af7c2016-12-21 18:19:57 +0100908static void sig_listen(struct sig_handler *sh)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200909{
Willy Tarreau775e0012020-09-24 16:36:26 +0200910 if (protocol_resume_all() & ERR_FATAL) {
911 const char *msg = "Some proxies refused to resume, probably due to a conflict on a listening port. You may want to try again after the conflicting application is stopped, otherwise a restart might be needed to resume safe operations.\n";
Willy Tarreau0a002df2020-10-09 19:26:27 +0200912 ha_warning("%s", msg);
913 send_log(NULL, LOG_WARNING, "%s", msg);
Willy Tarreau775e0012020-09-24 16:36:26 +0200914 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200915}
916
917/*
918 * this function dumps every server's state when the process receives SIGHUP.
919 */
Willy Tarreau1b5af7c2016-12-21 18:19:57 +0100920static void sig_dump_state(struct sig_handler *sh)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200921{
Olivier Houchardfbc74e82017-11-24 16:54:05 +0100922 struct proxy *p = proxies_list;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200923
Christopher Faulet767a84b2017-11-24 16:50:31 +0100924 ha_warning("SIGHUP received, dumping servers states.\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +0200925 while (p) {
926 struct server *s = p->srv;
927
928 send_log(p, LOG_NOTICE, "SIGHUP received, dumping servers states for proxy %s.\n", p->id);
929 while (s) {
Willy Tarreau19d14ef2012-10-29 16:51:55 +0100930 chunk_printf(&trash,
931 "SIGHUP: Server %s/%s is %s. Conn: %d act, %d pend, %lld tot.",
932 p->id, s->id,
Emeric Brun52a91d32017-08-31 14:41:55 +0200933 (s->cur_state != SRV_ST_STOPPED) ? "UP" : "DOWN",
Willy Tarreaua0570452021-06-18 09:30:30 +0200934 s->cur_sess, s->queue.length, s->counters.cum_sess);
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200935 ha_warning("%s\n", trash.area);
936 send_log(p, LOG_NOTICE, "%s\n", trash.area);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200937 s = s->next;
938 }
939
Willy Tarreau5fcc8f12007-09-17 11:27:09 +0200940 /* FIXME: those info are a bit outdated. We should be able to distinguish between FE and BE. */
941 if (!p->srv) {
Willy Tarreau19d14ef2012-10-29 16:51:55 +0100942 chunk_printf(&trash,
943 "SIGHUP: Proxy %s has no servers. Conn: act(FE+BE): %d+%d, %d pend (%d unass), tot(FE+BE): %lld+%lld.",
944 p->id,
Willy Tarreau7f3c1df2021-06-18 09:22:21 +0200945 p->feconn, p->beconn, p->totpend, p->queue.length, p->fe_counters.cum_conn, p->be_counters.cum_conn);
Willy Tarreau5fcc8f12007-09-17 11:27:09 +0200946 } else if (p->srv_act == 0) {
Willy Tarreau19d14ef2012-10-29 16:51:55 +0100947 chunk_printf(&trash,
948 "SIGHUP: Proxy %s %s ! Conn: act(FE+BE): %d+%d, %d pend (%d unass), tot(FE+BE): %lld+%lld.",
949 p->id,
950 (p->srv_bck) ? "is running on backup servers" : "has no server available",
Willy Tarreau7f3c1df2021-06-18 09:22:21 +0200951 p->feconn, p->beconn, p->totpend, p->queue.length, p->fe_counters.cum_conn, p->be_counters.cum_conn);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200952 } else {
Willy Tarreau19d14ef2012-10-29 16:51:55 +0100953 chunk_printf(&trash,
954 "SIGHUP: Proxy %s has %d active servers and %d backup servers available."
955 " Conn: act(FE+BE): %d+%d, %d pend (%d unass), tot(FE+BE): %lld+%lld.",
956 p->id, p->srv_act, p->srv_bck,
Willy Tarreau7f3c1df2021-06-18 09:22:21 +0200957 p->feconn, p->beconn, p->totpend, p->queue.length, p->fe_counters.cum_conn, p->be_counters.cum_conn);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200958 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200959 ha_warning("%s\n", trash.area);
960 send_log(p, LOG_NOTICE, "%s\n", trash.area);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200961
962 p = p->next;
963 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200964}
965
Willy Tarreau1b5af7c2016-12-21 18:19:57 +0100966static void dump(struct sig_handler *sh)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200967{
Willy Tarreauc6ca1a02007-05-13 19:43:47 +0200968 /* dump memory usage then free everything possible */
969 dump_pools();
Willy Tarreaubafbe012017-11-24 17:34:44 +0100970 pool_gc(NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200971}
972
William Lallemande1340412017-12-28 16:09:36 +0100973/*
974 * This function dup2 the stdio FDs (0,1,2) with <fd>, then closes <fd>
975 * If <fd> < 0, it opens /dev/null and use it to dup
976 *
977 * In the case of chrooting, you have to open /dev/null before the chroot, and
978 * pass the <fd> to this function
979 */
980static void stdio_quiet(int fd)
981{
982 if (fd < 0)
983 fd = open("/dev/null", O_RDWR, 0);
984
985 if (fd > -1) {
986 fclose(stdin);
987 fclose(stdout);
988 fclose(stderr);
989
990 dup2(fd, 0);
991 dup2(fd, 1);
992 dup2(fd, 2);
993 if (fd > 2)
994 close(fd);
995 return;
996 }
997
998 ha_alert("Cannot open /dev/null\n");
999 exit(EXIT_FAILURE);
1000}
1001
1002
Joseph Herlant03420902018-11-15 10:41:50 -08001003/* This function checks if cfg_cfgfiles contains directories.
1004 * If it finds one, it adds all the files (and only files) it contains
1005 * in cfg_cfgfiles in place of the directory (and removes the directory).
1006 * It adds the files in lexical order.
1007 * It adds only files with .cfg extension.
Maxime de Roucy379d9c72016-05-13 23:52:56 +02001008 * It doesn't add files with name starting with '.'
1009 */
Willy Tarreau1b5af7c2016-12-21 18:19:57 +01001010static void cfgfiles_expand_directories(void)
Maxime de Roucy379d9c72016-05-13 23:52:56 +02001011{
1012 struct wordlist *wl, *wlb;
1013 char *err = NULL;
1014
1015 list_for_each_entry_safe(wl, wlb, &cfg_cfgfiles, list) {
1016 struct stat file_stat;
1017 struct dirent **dir_entries = NULL;
1018 int dir_entries_nb;
1019 int dir_entries_it;
1020
1021 if (stat(wl->s, &file_stat)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001022 ha_alert("Cannot open configuration file/directory %s : %s\n",
1023 wl->s,
1024 strerror(errno));
Maxime de Roucy379d9c72016-05-13 23:52:56 +02001025 exit(1);
1026 }
1027
1028 if (!S_ISDIR(file_stat.st_mode))
1029 continue;
1030
1031 /* from this point wl->s is a directory */
1032
1033 dir_entries_nb = scandir(wl->s, &dir_entries, NULL, alphasort);
1034 if (dir_entries_nb < 0) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001035 ha_alert("Cannot open configuration directory %s : %s\n",
1036 wl->s,
1037 strerror(errno));
Maxime de Roucy379d9c72016-05-13 23:52:56 +02001038 exit(1);
1039 }
1040
1041 /* for each element in the directory wl->s */
1042 for (dir_entries_it = 0; dir_entries_it < dir_entries_nb; dir_entries_it++) {
1043 struct dirent *dir_entry = dir_entries[dir_entries_it];
1044 char *filename = NULL;
1045 char *d_name_cfgext = strstr(dir_entry->d_name, ".cfg");
1046
1047 /* don't add filename that begin with .
Joseph Herlant03420902018-11-15 10:41:50 -08001048 * only add filename with .cfg extension
Maxime de Roucy379d9c72016-05-13 23:52:56 +02001049 */
1050 if (dir_entry->d_name[0] == '.' ||
1051 !(d_name_cfgext && d_name_cfgext[4] == '\0'))
1052 goto next_dir_entry;
1053
1054 if (!memprintf(&filename, "%s/%s", wl->s, dir_entry->d_name)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001055 ha_alert("Cannot load configuration files %s : out of memory.\n",
1056 filename);
Maxime de Roucy379d9c72016-05-13 23:52:56 +02001057 exit(1);
1058 }
1059
1060 if (stat(filename, &file_stat)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001061 ha_alert("Cannot open configuration file %s : %s\n",
1062 wl->s,
1063 strerror(errno));
Maxime de Roucy379d9c72016-05-13 23:52:56 +02001064 exit(1);
1065 }
1066
1067 /* don't add anything else than regular file in cfg_cfgfiles
1068 * this way we avoid loops
1069 */
1070 if (!S_ISREG(file_stat.st_mode))
1071 goto next_dir_entry;
1072
1073 if (!list_append_word(&wl->list, filename, &err)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001074 ha_alert("Cannot load configuration files %s : %s\n",
1075 filename,
1076 err);
Maxime de Roucy379d9c72016-05-13 23:52:56 +02001077 exit(1);
1078 }
1079
1080next_dir_entry:
1081 free(filename);
1082 free(dir_entry);
1083 }
1084
1085 free(dir_entries);
1086
1087 /* remove the current directory (wl) from cfg_cfgfiles */
1088 free(wl->s);
Willy Tarreau2b718102021-04-21 07:32:39 +02001089 LIST_DELETE(&wl->list);
Maxime de Roucy379d9c72016-05-13 23:52:56 +02001090 free(wl);
1091 }
1092
1093 free(err);
1094}
1095
Willy Tarreaubaaee002006-06-26 02:48:02 +02001096/*
William Lallemand73b85e72017-06-01 17:38:51 +02001097 * copy and cleanup the current argv
William Lallemanddf6c5a82020-06-04 17:40:23 +02001098 * Remove the -sf /-st / -x parameters
William Lallemand73b85e72017-06-01 17:38:51 +02001099 * Return an allocated copy of argv
1100 */
1101
1102static char **copy_argv(int argc, char **argv)
1103{
William Lallemanddf6c5a82020-06-04 17:40:23 +02001104 char **newargv, **retargv;
William Lallemand73b85e72017-06-01 17:38:51 +02001105
Tim Duesterhuse52b6e52020-09-12 20:26:43 +02001106 newargv = calloc(argc + 2, sizeof(*newargv));
William Lallemand73b85e72017-06-01 17:38:51 +02001107 if (newargv == NULL) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001108 ha_warning("Cannot allocate memory\n");
William Lallemand73b85e72017-06-01 17:38:51 +02001109 return NULL;
1110 }
William Lallemanddf6c5a82020-06-04 17:40:23 +02001111 retargv = newargv;
William Lallemand73b85e72017-06-01 17:38:51 +02001112
William Lallemanddf6c5a82020-06-04 17:40:23 +02001113 /* first copy argv[0] */
1114 *newargv++ = *argv++;
1115 argc--;
1116
1117 while (argc > 0) {
1118 if (**argv != '-') {
1119 /* non options are copied but will fail in the argument parser */
1120 *newargv++ = *argv++;
1121 argc--;
1122
1123 } else {
1124 char *flag;
1125
1126 flag = *argv + 1;
1127
1128 if (flag[0] == '-' && flag[1] == 0) {
1129 /* "--\0" copy every arguments till the end of argv */
1130 *newargv++ = *argv++;
1131 argc--;
1132
1133 while (argc > 0) {
1134 *newargv++ = *argv++;
1135 argc--;
1136 }
1137 } else {
1138 switch (*flag) {
1139 case 's':
1140 /* -sf / -st and their parameters are ignored */
1141 if (flag[1] == 'f' || flag[1] == 't') {
1142 argc--;
1143 argv++;
1144 /* The list can't contain a negative value since the only
1145 way to know the end of this list is by looking for the
1146 next option or the end of the options */
1147 while (argc > 0 && argv[0][0] != '-') {
1148 argc--;
1149 argv++;
1150 }
William Lallemand398da622020-09-02 16:12:23 +02001151 } else {
1152 argc--;
1153 argv++;
1154
William Lallemanddf6c5a82020-06-04 17:40:23 +02001155 }
1156 break;
1157
1158 case 'x':
1159 /* this option and its parameter are ignored */
1160 argc--;
1161 argv++;
1162 if (argc > 0) {
1163 argc--;
1164 argv++;
1165 }
1166 break;
1167
1168 case 'C':
1169 case 'n':
1170 case 'm':
1171 case 'N':
1172 case 'L':
1173 case 'f':
1174 case 'p':
1175 case 'S':
1176 /* these options have only 1 parameter which must be copied and can start with a '-' */
1177 *newargv++ = *argv++;
1178 argc--;
1179 if (argc == 0)
1180 goto error;
1181 *newargv++ = *argv++;
1182 argc--;
1183 break;
1184 default:
1185 /* for other options just copy them without parameters, this is also done
1186 * for options like "--foo", but this will fail in the argument parser.
1187 * */
1188 *newargv++ = *argv++;
1189 argc--;
1190 break;
1191 }
William Lallemand73b85e72017-06-01 17:38:51 +02001192 }
1193 }
William Lallemand73b85e72017-06-01 17:38:51 +02001194 }
William Lallemand2bf6d622017-06-20 11:20:23 +02001195
William Lallemanddf6c5a82020-06-04 17:40:23 +02001196 return retargv;
1197
1198error:
1199 free(retargv);
1200 return NULL;
William Lallemand73b85e72017-06-01 17:38:51 +02001201}
1202
Willy Tarreau6c3a6812020-03-06 18:57:15 +01001203
1204/* Performs basic random seed initialization. The main issue with this is that
1205 * srandom_r() only takes 32 bits and purposely provides a reproducible sequence,
1206 * which means that there will only be 4 billion possible random sequences once
1207 * srandom() is called, regardless of the internal state. Not calling it is
1208 * even worse as we'll always produce the same randoms sequences. What we do
1209 * here is to create an initial sequence from various entropy sources, hash it
1210 * using SHA1 and keep the resulting 160 bits available globally.
1211 *
1212 * We initialize the current process with the first 32 bits before starting the
1213 * polling loop, where all this will be changed to have process specific and
1214 * thread specific sequences.
Willy Tarreau52bf8392020-03-08 00:42:37 +01001215 *
1216 * Before starting threads, it's still possible to call random() as srandom()
1217 * is initialized from this, but after threads and/or processes are started,
1218 * only ha_random() is expected to be used to guarantee distinct sequences.
Willy Tarreau6c3a6812020-03-06 18:57:15 +01001219 */
1220static void ha_random_boot(char *const *argv)
1221{
1222 unsigned char message[256];
1223 unsigned char *m = message;
1224 struct timeval tv;
1225 blk_SHA_CTX ctx;
1226 unsigned long l;
1227 int fd;
1228 int i;
1229
1230 /* start with current time as pseudo-random seed */
1231 gettimeofday(&tv, NULL);
1232 write_u32(m, tv.tv_sec); m += 4;
1233 write_u32(m, tv.tv_usec); m += 4;
1234
1235 /* PID and PPID add some OS-based randomness */
1236 write_u16(m, getpid()); m += 2;
1237 write_u16(m, getppid()); m += 2;
1238
1239 /* take up to 160 bits bytes from /dev/urandom if available (non-blocking) */
1240 fd = open("/dev/urandom", O_RDONLY);
1241 if (fd >= 0) {
1242 i = read(fd, m, 20);
1243 if (i > 0)
1244 m += i;
1245 close(fd);
1246 }
1247
1248 /* take up to 160 bits bytes from openssl (non-blocking) */
1249#ifdef USE_OPENSSL
1250 if (RAND_bytes(m, 20) == 1)
1251 m += 20;
1252#endif
1253
1254 /* take 160 bits from existing random in case it was already initialized */
1255 for (i = 0; i < 5; i++) {
1256 write_u32(m, random());
1257 m += 4;
1258 }
1259
1260 /* stack address (benefit form operating system's ASLR) */
1261 l = (unsigned long)&m;
1262 memcpy(m, &l, sizeof(l)); m += sizeof(l);
1263
1264 /* argv address (benefit form operating system's ASLR) */
1265 l = (unsigned long)&argv;
1266 memcpy(m, &l, sizeof(l)); m += sizeof(l);
1267
1268 /* use tv_usec again after all the operations above */
1269 gettimeofday(&tv, NULL);
1270 write_u32(m, tv.tv_usec); m += 4;
1271
1272 /*
1273 * At this point, ~84-92 bytes have been used
1274 */
1275
1276 /* finish with the hostname */
1277 strncpy((char *)m, hostname, message + sizeof(message) - m);
1278 m += strlen(hostname);
1279
1280 /* total message length */
1281 l = m - message;
1282
1283 memset(&ctx, 0, sizeof(ctx));
1284 blk_SHA1_Init(&ctx);
1285 blk_SHA1_Update(&ctx, message, l);
1286 blk_SHA1_Final(boot_seed, &ctx);
1287
1288 srandom(read_u32(boot_seed));
Willy Tarreau52bf8392020-03-08 00:42:37 +01001289 ha_random_seed(boot_seed, sizeof(boot_seed));
Willy Tarreau6c3a6812020-03-06 18:57:15 +01001290}
1291
Willy Tarreau5a023f02019-03-01 14:19:31 +01001292/* considers splicing proxies' maxconn, computes the ideal global.maxpipes
1293 * setting, and returns it. It may return -1 meaning "unlimited" if some
1294 * unlimited proxies have been found and the global.maxconn value is not yet
1295 * set. It may also return a value greater than maxconn if it's not yet set.
1296 * Note that a value of zero means there is no need for pipes. -1 is never
1297 * returned if global.maxconn is valid.
1298 */
1299static int compute_ideal_maxpipes()
1300{
1301 struct proxy *cur;
1302 int nbfe = 0, nbbe = 0;
1303 int unlimited = 0;
1304 int pipes;
1305 int max;
1306
1307 for (cur = proxies_list; cur; cur = cur->next) {
1308 if (cur->options2 & (PR_O2_SPLIC_ANY)) {
1309 if (cur->cap & PR_CAP_FE) {
1310 max = cur->maxconn;
1311 nbfe += max;
1312 if (!max) {
1313 unlimited = 1;
1314 break;
1315 }
1316 }
1317 if (cur->cap & PR_CAP_BE) {
1318 max = cur->fullconn ? cur->fullconn : global.maxconn;
1319 nbbe += max;
1320 if (!max) {
1321 unlimited = 1;
1322 break;
1323 }
1324 }
1325 }
1326 }
1327
1328 pipes = MAX(nbfe, nbbe);
1329 if (global.maxconn) {
1330 if (pipes > global.maxconn || unlimited)
1331 pipes = global.maxconn;
1332 } else if (unlimited) {
1333 pipes = -1;
1334 }
1335
1336 return pipes >= 4 ? pipes / 4 : pipes;
1337}
1338
Willy Tarreauac350932019-03-01 15:43:14 +01001339/* considers global.maxsocks, global.maxpipes, async engines, SSL frontends and
1340 * rlimits and computes an ideal maxconn. It's meant to be called only when
1341 * maxsock contains the sum of listening FDs, before it is updated based on
Willy Tarreaudf23c0c2019-03-13 10:10:49 +01001342 * maxconn and pipes. If there are not enough FDs left, DEFAULT_MAXCONN (by
1343 * default 100) is returned as it is expected that it will even run on tight
1344 * environments, and will maintain compatibility with previous packages that
1345 * used to rely on this value as the default one. The system will emit a
1346 * warning indicating how many FDs are missing anyway if needed.
Willy Tarreauac350932019-03-01 15:43:14 +01001347 */
1348static int compute_ideal_maxconn()
1349{
1350 int ssl_sides = !!global.ssl_used_frontend + !!global.ssl_used_backend;
1351 int engine_fds = global.ssl_used_async_engines * ssl_sides;
1352 int pipes = compute_ideal_maxpipes();
Willy Tarreaub1beaa32020-03-06 10:25:31 +01001353 int remain = MAX(rlim_fd_cur_at_boot, rlim_fd_max_at_boot);
Willy Tarreauac350932019-03-01 15:43:14 +01001354 int maxconn;
1355
1356 /* we have to take into account these elements :
1357 * - number of engine_fds, which inflates the number of FD needed per
1358 * connection by this number.
1359 * - number of pipes per connection on average : for the unlimited
1360 * case, this is 0.5 pipe FDs per connection, otherwise it's a
1361 * fixed value of 2*pipes.
1362 * - two FDs per connection
1363 */
1364
Willy Tarreau2df1fbf2022-04-25 18:02:03 +02001365 if (global.fd_hard_limit && remain > global.fd_hard_limit)
1366 remain = global.fd_hard_limit;
1367
Willy Tarreauac350932019-03-01 15:43:14 +01001368 /* subtract listeners and checks */
1369 remain -= global.maxsock;
1370
Willy Tarreau3f200852019-03-14 19:13:17 +01001371 /* one epoll_fd/kqueue_fd per thread */
1372 remain -= global.nbthread;
1373
1374 /* one wake-up pipe (2 fd) per thread */
1375 remain -= 2 * global.nbthread;
1376
Willy Tarreauac350932019-03-01 15:43:14 +01001377 /* Fixed pipes values : we only subtract them if they're not larger
1378 * than the remaining FDs because pipes are optional.
1379 */
1380 if (pipes >= 0 && pipes * 2 < remain)
1381 remain -= pipes * 2;
1382
1383 if (pipes < 0) {
1384 /* maxsock = maxconn * 2 + maxconn/4 * 2 + maxconn * engine_fds.
1385 * = maxconn * (2 + 0.5 + engine_fds)
1386 * = maxconn * (4 + 1 + 2*engine_fds) / 2
1387 */
1388 maxconn = 2 * remain / (5 + 2 * engine_fds);
1389 } else {
1390 /* maxsock = maxconn * 2 + maxconn * engine_fds.
1391 * = maxconn * (2 + engine_fds)
1392 */
1393 maxconn = remain / (2 + engine_fds);
1394 }
1395
Willy Tarreaudf23c0c2019-03-13 10:10:49 +01001396 return MAX(maxconn, DEFAULT_MAXCONN);
Willy Tarreauac350932019-03-01 15:43:14 +01001397}
1398
Willy Tarreaua409f302020-03-10 17:08:53 +01001399/* computes the estimated maxsock value for the given maxconn based on the
1400 * possibly set global.maxpipes and existing partial global.maxsock. It may
1401 * temporarily change global.maxconn for the time needed to propagate the
1402 * computations, and will reset it.
1403 */
1404static int compute_ideal_maxsock(int maxconn)
1405{
1406 int maxpipes = global.maxpipes;
1407 int maxsock = global.maxsock;
1408
1409
1410 if (!maxpipes) {
1411 int old_maxconn = global.maxconn;
1412
1413 global.maxconn = maxconn;
1414 maxpipes = compute_ideal_maxpipes();
1415 global.maxconn = old_maxconn;
1416 }
1417
1418 maxsock += maxconn * 2; /* each connection needs two sockets */
1419 maxsock += maxpipes * 2; /* each pipe needs two FDs */
1420 maxsock += global.nbthread; /* one epoll_fd/kqueue_fd per thread */
1421 maxsock += 2 * global.nbthread; /* one wake-up pipe (2 fd) per thread */
1422
1423 /* compute fd used by async engines */
1424 if (global.ssl_used_async_engines) {
1425 int sides = !!global.ssl_used_frontend + !!global.ssl_used_backend;
1426
1427 maxsock += maxconn * sides * global.ssl_used_async_engines;
1428 }
1429 return maxsock;
1430}
1431
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07001432/* Tests if it is possible to set the current process's RLIMIT_NOFILE to
Willy Tarreau304e17e2020-03-10 17:54:54 +01001433 * <maxsock>, then sets it back to the previous value. Returns non-zero if the
1434 * value is accepted, non-zero otherwise. This is used to determine if an
1435 * automatic limit may be applied or not. When it is not, the caller knows that
1436 * the highest we can do is the rlim_max at boot. In case of error, we return
1437 * that the setting is possible, so that we defer the error processing to the
1438 * final stage in charge of enforcing this.
1439 */
1440static int check_if_maxsock_permitted(int maxsock)
1441{
1442 struct rlimit orig_limit, test_limit;
1443 int ret;
1444
Willy Tarreau2df1fbf2022-04-25 18:02:03 +02001445 if (global.fd_hard_limit && maxsock > global.fd_hard_limit)
1446 return 0;
1447
Willy Tarreau304e17e2020-03-10 17:54:54 +01001448 if (getrlimit(RLIMIT_NOFILE, &orig_limit) != 0)
1449 return 1;
1450
1451 /* don't go further if we can't even set to what we have */
1452 if (setrlimit(RLIMIT_NOFILE, &orig_limit) != 0)
1453 return 1;
1454
1455 test_limit.rlim_max = MAX(maxsock, orig_limit.rlim_max);
1456 test_limit.rlim_cur = test_limit.rlim_max;
1457 ret = setrlimit(RLIMIT_NOFILE, &test_limit);
1458
1459 if (setrlimit(RLIMIT_NOFILE, &orig_limit) != 0)
1460 return 1;
1461
1462 return ret == 0;
1463}
1464
Willy Tarreau34527d52022-02-17 17:45:58 +01001465/* This performs th every basic early initialization at the end of the PREPARE
1466 * init stage. It may only assume that list heads are initialized, but not that
1467 * anything else is correct. It will initialize a number of variables that
1468 * depend on command line and will pre-parse the command line. If it fails, it
1469 * directly exits.
Willy Tarreaubaaee002006-06-26 02:48:02 +02001470 */
Willy Tarreau34527d52022-02-17 17:45:58 +01001471static void init_early(int argc, char **argv)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001472{
Kevinm48936af2010-12-22 16:08:21 +00001473 char *progname;
Willy Tarreau34527d52022-02-17 17:45:58 +01001474 char *tmp;
1475 int len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001476
Willy Tarreau34527d52022-02-17 17:45:58 +01001477 /* First, let's initialize most global variables */
1478 totalconn = actconn = listeners = stopping = 0;
1479 killed = pid = 0;
1480
1481 global.maxsock = 10; /* reserve 10 fds ; will be incremented by socket eaters */
1482 global.rlimit_memmax_all = HAPROXY_MEMMAX;
Christopher Faulete3a5e352017-10-24 13:53:54 +02001483 global.mode = MODE_STARTING;
William Lallemand73b85e72017-06-01 17:38:51 +02001484
Willy Tarreau34527d52022-02-17 17:45:58 +01001485 /* if we were in mworker mode, we should restart in mworker mode */
1486 if (getenv("HAPROXY_MWORKER_REEXEC") != NULL)
1487 global.mode |= MODE_MWORKER;
David du Colombier7af46052012-05-16 14:16:48 +02001488
Willy Tarreau34527d52022-02-17 17:45:58 +01001489 /* initialize date, time, and pid */
1490 tzset();
1491 clock_init_process_date();
1492 start_date = now;
1493 pid = getpid();
1494
1495 /* Set local host name and adjust some environment variables.
1496 * NB: POSIX does not make it mandatory for gethostname() to
1497 * NULL-terminate the string in case of truncation, and at least
1498 * FreeBSD appears not to do it.
Emeric Brun2b920a12010-09-23 18:30:22 +02001499 */
1500 memset(hostname, 0, sizeof(hostname));
1501 gethostname(hostname, sizeof(hostname) - 1);
Dragan Dosen4f014152020-06-18 16:56:47 +02001502
Willy Tarreau34527d52022-02-17 17:45:58 +01001503 /* preset some environment variables */
1504 localpeer = strdup(hostname);
1505 if (!localpeer || setenv("HAPROXY_LOCALPEER", localpeer, 1) < 0) {
Dragan Dosen4f014152020-06-18 16:56:47 +02001506 ha_alert("Cannot allocate memory for local peer.\n");
1507 exit(EXIT_FAILURE);
1508 }
Emeric Brun2b920a12010-09-23 18:30:22 +02001509
Willy Tarreau34527d52022-02-17 17:45:58 +01001510 /* Some CPU affinity stuff may have to be initialized */
1511#ifdef USE_CPU_AFFINITY
1512 {
1513 int i;
1514 ha_cpuset_zero(&cpu_map.proc);
1515 ha_cpuset_zero(&cpu_map.proc_t1);
1516 for (i = 0; i < MAX_THREADS; ++i) {
1517 ha_cpuset_zero(&cpu_map.thread[i]);
1518 }
1519 }
1520#endif
Christopher Fauletcd7879a2017-10-27 13:53:47 +02001521
Willy Tarreau34527d52022-02-17 17:45:58 +01001522 /* extract the program name from argv[0], it will be used for the logs
1523 * and error messages.
1524 */
1525 progname = *argv;
1526 while ((tmp = strchr(progname, '/')) != NULL)
1527 progname = tmp + 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001528
Willy Tarreau34527d52022-02-17 17:45:58 +01001529 len = strlen(progname);
1530 progname = strdup(progname);
1531 if (!progname) {
1532 ha_alert("Cannot allocate memory for log_tag.\n");
1533 exit(EXIT_FAILURE);
1534 }
Willy Tarreau84310e22014-02-14 11:59:04 +01001535
Willy Tarreau34527d52022-02-17 17:45:58 +01001536 chunk_initlen(&global.log_tag, progname, len, len);
1537}
Willy Tarreaub6b3df32018-11-26 16:31:20 +01001538
Willy Tarreau392524d2022-02-17 18:10:36 +01001539/* handles program arguments. Very minimal parsing is performed, variables are
1540 * fed with some values, and lists are completed with other ones. In case of
1541 * error, it will exit.
Willy Tarreau34527d52022-02-17 17:45:58 +01001542 */
Willy Tarreau392524d2022-02-17 18:10:36 +01001543static void init_args(int argc, char **argv)
Willy Tarreau34527d52022-02-17 17:45:58 +01001544{
Willy Tarreau34527d52022-02-17 17:45:58 +01001545 char *progname = global.log_tag.area;
Willy Tarreau392524d2022-02-17 18:10:36 +01001546 char *err_msg = NULL;
Thierry FOURNIER6f1fd482015-01-23 14:06:13 +01001547
Willy Tarreau34527d52022-02-17 17:45:58 +01001548 /* pre-fill in the global tuning options before we let the cmdline
1549 * change them.
1550 */
Willy Tarreau43b78992009-01-25 15:42:27 +01001551 global.tune.options |= GTUNE_USE_SELECT; /* select() is always available */
Willy Tarreaue5733232019-05-22 19:24:06 +02001552#if defined(USE_POLL)
Willy Tarreau43b78992009-01-25 15:42:27 +01001553 global.tune.options |= GTUNE_USE_POLL;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001554#endif
Willy Tarreaue5733232019-05-22 19:24:06 +02001555#if defined(USE_EPOLL)
Willy Tarreau43b78992009-01-25 15:42:27 +01001556 global.tune.options |= GTUNE_USE_EPOLL;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001557#endif
Willy Tarreaue5733232019-05-22 19:24:06 +02001558#if defined(USE_KQUEUE)
Willy Tarreau43b78992009-01-25 15:42:27 +01001559 global.tune.options |= GTUNE_USE_KQUEUE;
Willy Tarreau1e63130a2007-04-09 12:03:06 +02001560#endif
Willy Tarreaue5733232019-05-22 19:24:06 +02001561#if defined(USE_EVPORTS)
Emmanuel Hocdet0ba4f482019-04-08 16:53:32 +00001562 global.tune.options |= GTUNE_USE_EVPORTS;
1563#endif
Willy Tarreaue5733232019-05-22 19:24:06 +02001564#if defined(USE_LINUX_SPLICE)
Willy Tarreau3ab68cf2009-01-25 16:03:28 +01001565 global.tune.options |= GTUNE_USE_SPLICE;
1566#endif
Nenad Merdanovic88afe032014-04-14 15:56:58 +02001567#if defined(USE_GETADDRINFO)
1568 global.tune.options |= GTUNE_USE_GAI;
1569#endif
Lukas Tribusa0bcbdc2016-09-12 21:42:20 +00001570#if defined(SO_REUSEPORT)
1571 global.tune.options |= GTUNE_USE_REUSEPORT;
1572#endif
Willy Tarreau76cc6992020-07-01 18:49:24 +02001573#ifdef USE_THREAD
1574 global.tune.options |= GTUNE_IDLE_POOL_SHARED;
1575#endif
William Dauchya5194602020-03-28 19:29:58 +01001576 global.tune.options |= GTUNE_STRICT_LIMITS;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001577
Willy Tarreau392524d2022-02-17 18:10:36 +01001578 /* keep a copy of original arguments for the master process */
1579 old_argv = copy_argv(argc, argv);
1580 if (!old_argv) {
1581 ha_alert("failed to copy argv.\n");
1582 exit(EXIT_FAILURE);
1583 }
1584
1585 /* skip program name and start */
Willy Tarreaubaaee002006-06-26 02:48:02 +02001586 argc--; argv++;
1587 while (argc > 0) {
1588 char *flag;
1589
1590 if (**argv == '-') {
1591 flag = *argv+1;
1592
1593 /* 1 arg */
1594 if (*flag == 'v') {
1595 display_version();
Willy Tarreau7b066db2007-12-02 11:28:59 +01001596 if (flag[1] == 'v') /* -vv */
1597 display_build_opts();
Tim Duesterhus77b3db02022-04-27 00:08:11 +02001598 deinit_and_exit(0);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001599 }
Willy Tarreaue5733232019-05-22 19:24:06 +02001600#if defined(USE_EPOLL)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001601 else if (*flag == 'd' && flag[1] == 'e')
Willy Tarreau43b78992009-01-25 15:42:27 +01001602 global.tune.options &= ~GTUNE_USE_EPOLL;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001603#endif
Willy Tarreaue5733232019-05-22 19:24:06 +02001604#if defined(USE_POLL)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001605 else if (*flag == 'd' && flag[1] == 'p')
Willy Tarreau43b78992009-01-25 15:42:27 +01001606 global.tune.options &= ~GTUNE_USE_POLL;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001607#endif
Willy Tarreaue5733232019-05-22 19:24:06 +02001608#if defined(USE_KQUEUE)
Willy Tarreau1e63130a2007-04-09 12:03:06 +02001609 else if (*flag == 'd' && flag[1] == 'k')
Willy Tarreau43b78992009-01-25 15:42:27 +01001610 global.tune.options &= ~GTUNE_USE_KQUEUE;
Willy Tarreau1e63130a2007-04-09 12:03:06 +02001611#endif
Willy Tarreaue5733232019-05-22 19:24:06 +02001612#if defined(USE_EVPORTS)
Emmanuel Hocdet0ba4f482019-04-08 16:53:32 +00001613 else if (*flag == 'd' && flag[1] == 'v')
1614 global.tune.options &= ~GTUNE_USE_EVPORTS;
1615#endif
Willy Tarreaue5733232019-05-22 19:24:06 +02001616#if defined(USE_LINUX_SPLICE)
Willy Tarreau3ab68cf2009-01-25 16:03:28 +01001617 else if (*flag == 'd' && flag[1] == 'S')
1618 global.tune.options &= ~GTUNE_USE_SPLICE;
1619#endif
Nenad Merdanovic88afe032014-04-14 15:56:58 +02001620#if defined(USE_GETADDRINFO)
1621 else if (*flag == 'd' && flag[1] == 'G')
1622 global.tune.options &= ~GTUNE_USE_GAI;
1623#endif
Lukas Tribusa0bcbdc2016-09-12 21:42:20 +00001624#if defined(SO_REUSEPORT)
1625 else if (*flag == 'd' && flag[1] == 'R')
1626 global.tune.options &= ~GTUNE_USE_REUSEPORT;
1627#endif
Emeric Brun850efd52014-01-29 12:24:34 +01001628 else if (*flag == 'd' && flag[1] == 'V')
1629 global.ssl_server_verify = SSL_SERVER_VERIFY_NONE;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001630 else if (*flag == 'V')
1631 arg_mode |= MODE_VERBOSE;
1632 else if (*flag == 'd' && flag[1] == 'b')
1633 arg_mode |= MODE_FOREGROUND;
Amaury Denoyelle7b01a8d2021-03-29 10:29:07 +02001634 else if (*flag == 'd' && flag[1] == 'D')
1635 arg_mode |= MODE_DIAG;
Willy Tarreau3eb10b82020-04-15 16:42:39 +02001636 else if (*flag == 'd' && flag[1] == 'W')
1637 arg_mode |= MODE_ZERO_WARNING;
Willy Tarreauef301b72022-02-23 14:15:18 +01001638 else if (*flag == 'd' && flag[1] == 'M') {
Willy Tarreau1408b1f2022-02-18 18:54:40 +01001639 int ret = pool_parse_debugging(flag + 2, &err_msg);
1640
1641 if (ret <= -1) {
1642 if (ret < -1)
1643 ha_alert("-dM: %s\n", err_msg);
1644 else
1645 printf("%s\n", err_msg);
1646 ha_free(&err_msg);
1647 exit(ret < -1 ? EXIT_FAILURE : 0);
1648 } else if (ret == 0) {
1649 ha_warning("-dM: %s\n", err_msg);
1650 ha_free(&err_msg);
1651 }
Willy Tarreauef301b72022-02-23 14:15:18 +01001652 }
Willy Tarreau3eed10e2016-11-07 21:03:16 +01001653 else if (*flag == 'd' && flag[1] == 'r')
1654 global.tune.options |= GTUNE_RESOLVE_DONTFAIL;
Willy Tarreau654726d2021-12-28 15:43:11 +01001655#if defined(HA_HAVE_DUMP_LIBS)
1656 else if (*flag == 'd' && flag[1] == 'L')
1657 arg_mode |= MODE_DUMP_LIBS;
1658#endif
Willy Tarreau76871a42022-03-08 16:01:40 +01001659 else if (*flag == 'd' && flag[1] == 'K') {
1660 arg_mode |= MODE_DUMP_KWD;
1661 kwd_dump = flag + 2;
1662 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001663 else if (*flag == 'd')
1664 arg_mode |= MODE_DEBUG;
Maximilian Maderfc0cceb2021-06-06 00:50:22 +02001665 else if (*flag == 'c' && flag[1] == 'c') {
1666 arg_mode |= MODE_CHECK_CONDITION;
1667 argv++;
1668 argc--;
1669 check_condition = *argv;
1670 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001671 else if (*flag == 'c')
1672 arg_mode |= MODE_CHECK;
William Lallemand095ba4c2017-06-01 17:38:50 +02001673 else if (*flag == 'D')
Willy Tarreau6bde87b2009-05-18 16:29:51 +02001674 arg_mode |= MODE_DAEMON;
Tim Duesterhusd6942c82017-11-20 15:58:35 +01001675 else if (*flag == 'W' && flag[1] == 's') {
Lukas Tribusf46bf952017-11-21 12:39:34 +01001676 arg_mode |= MODE_MWORKER | MODE_FOREGROUND;
Tim Duesterhusd6942c82017-11-20 15:58:35 +01001677#if defined(USE_SYSTEMD)
1678 global.tune.options |= GTUNE_USE_SYSTEMD;
1679#else
Christopher Faulet767a84b2017-11-24 16:50:31 +01001680 ha_alert("master-worker mode with systemd support (-Ws) requested, but not compiled. Use master-worker mode (-W) if you are not using Type=notify in your unit file or recompile with USE_SYSTEMD=1.\n\n");
Tim Duesterhusd6942c82017-11-20 15:58:35 +01001681 usage(progname);
1682#endif
1683 }
William Lallemand095ba4c2017-06-01 17:38:50 +02001684 else if (*flag == 'W')
1685 arg_mode |= MODE_MWORKER;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001686 else if (*flag == 'q')
1687 arg_mode |= MODE_QUIET;
Olivier Houchardf73629d2017-04-05 22:33:04 +02001688 else if (*flag == 'x') {
William Lallemand4f71d302020-06-04 23:41:29 +02001689 if (argc <= 1) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001690 ha_alert("Unix socket path expected with the -x flag\n\n");
William Lallemand45eff442017-06-19 15:57:55 +02001691 usage(progname);
Olivier Houchardf73629d2017-04-05 22:33:04 +02001692 }
William Lallemand4fc09692017-06-19 16:37:19 +02001693 if (old_unixsocket)
Christopher Faulet767a84b2017-11-24 16:50:31 +01001694 ha_warning("-x option already set, overwriting the value\n");
Olivier Houchardf73629d2017-04-05 22:33:04 +02001695 old_unixsocket = argv[1];
William Lallemand4fc09692017-06-19 16:37:19 +02001696
Olivier Houchardf73629d2017-04-05 22:33:04 +02001697 argv++;
1698 argc--;
1699 }
William Lallemande7361152018-10-26 14:47:36 +02001700 else if (*flag == 'S') {
1701 struct wordlist *c;
1702
William Lallemanda6b32492020-06-04 23:49:20 +02001703 if (argc <= 1) {
William Lallemande7361152018-10-26 14:47:36 +02001704 ha_alert("Socket and optional bind parameters expected with the -S flag\n");
1705 usage(progname);
1706 }
1707 if ((c = malloc(sizeof(*c))) == NULL || (c->s = strdup(argv[1])) == NULL) {
1708 ha_alert("Cannot allocate memory\n");
1709 exit(EXIT_FAILURE);
1710 }
Willy Tarreau2b718102021-04-21 07:32:39 +02001711 LIST_INSERT(&mworker_cli_conf, &c->list);
William Lallemande7361152018-10-26 14:47:36 +02001712
1713 argv++;
1714 argc--;
1715 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001716 else if (*flag == 's' && (flag[1] == 'f' || flag[1] == 't')) {
1717 /* list of pids to finish ('f') or terminate ('t') */
1718
1719 if (flag[1] == 'f')
1720 oldpids_sig = SIGUSR1; /* finish then exit */
1721 else
1722 oldpids_sig = SIGTERM; /* terminate immediately */
Willy Tarreauc6ca1aa2015-10-08 11:32:32 +02001723 while (argc > 1 && argv[1][0] != '-') {
Chris Lane236062f2018-02-05 23:15:44 +00001724 char * endptr = NULL;
Willy Tarreauc6ca1aa2015-10-08 11:32:32 +02001725 oldpids = realloc(oldpids, (nb_oldpids + 1) * sizeof(int));
1726 if (!oldpids) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001727 ha_alert("Cannot allocate old pid : out of memory.\n");
Willy Tarreauc6ca1aa2015-10-08 11:32:32 +02001728 exit(1);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001729 }
Willy Tarreauc6ca1aa2015-10-08 11:32:32 +02001730 argc--; argv++;
Chris Lane236062f2018-02-05 23:15:44 +00001731 errno = 0;
1732 oldpids[nb_oldpids] = strtol(*argv, &endptr, 10);
1733 if (errno) {
1734 ha_alert("-%2s option: failed to parse {%s}: %s\n",
1735 flag,
1736 *argv, strerror(errno));
1737 exit(1);
1738 } else if (endptr && strlen(endptr)) {
Willy Tarreau90807112020-02-25 08:16:33 +01001739 while (isspace((unsigned char)*endptr)) endptr++;
Aurélien Nephtali39b89882018-02-17 20:53:11 +01001740 if (*endptr != 0) {
Chris Lane236062f2018-02-05 23:15:44 +00001741 ha_alert("-%2s option: some bytes unconsumed in PID list {%s}\n",
1742 flag, endptr);
1743 exit(1);
Aurélien Nephtali39b89882018-02-17 20:53:11 +01001744 }
Chris Lane236062f2018-02-05 23:15:44 +00001745 }
Willy Tarreauc6ca1aa2015-10-08 11:32:32 +02001746 if (oldpids[nb_oldpids] <= 0)
1747 usage(progname);
1748 nb_oldpids++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001749 }
1750 }
Willy Tarreaua088d312015-10-08 11:58:48 +02001751 else if (flag[0] == '-' && flag[1] == 0) { /* "--" */
1752 /* now that's a cfgfile list */
1753 argv++; argc--;
1754 while (argc > 0) {
Maxime de Roucy0f503922016-05-13 23:52:55 +02001755 if (!list_append_word(&cfg_cfgfiles, *argv, &err_msg)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001756 ha_alert("Cannot load configuration file/directory %s : %s\n",
1757 *argv,
1758 err_msg);
Willy Tarreaua088d312015-10-08 11:58:48 +02001759 exit(1);
1760 }
Willy Tarreaua088d312015-10-08 11:58:48 +02001761 argv++; argc--;
1762 }
1763 break;
1764 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001765 else { /* >=2 args */
1766 argv++; argc--;
1767 if (argc == 0)
Willy Tarreau3bafcdc2011-09-10 19:20:23 +02001768 usage(progname);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001769
1770 switch (*flag) {
Willy Tarreau576132e2011-09-10 19:26:56 +02001771 case 'C' : change_dir = *argv; break;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001772 case 'n' : cfg_maxconn = atol(*argv); break;
Willy Tarreau70060452015-12-14 12:46:07 +01001773 case 'm' : global.rlimit_memmax_all = atol(*argv); break;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001774 case 'N' : cfg_maxpconn = atol(*argv); break;
William Lallemanddaf4cd22018-04-17 16:46:13 +02001775 case 'L' :
Dragan Dosen4f014152020-06-18 16:56:47 +02001776 free(localpeer);
1777 if ((localpeer = strdup(*argv)) == NULL) {
1778 ha_alert("Cannot allocate memory for local peer.\n");
1779 exit(EXIT_FAILURE);
1780 }
William Lallemanddaf4cd22018-04-17 16:46:13 +02001781 setenv("HAPROXY_LOCALPEER", localpeer, 1);
Dragan Dosen13cd54c2020-06-18 18:24:05 +02001782 global.localpeer_cmdline = 1;
William Lallemanddaf4cd22018-04-17 16:46:13 +02001783 break;
Willy Tarreau5d01a632009-06-22 16:02:30 +02001784 case 'f' :
Maxime de Roucy0f503922016-05-13 23:52:55 +02001785 if (!list_append_word(&cfg_cfgfiles, *argv, &err_msg)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001786 ha_alert("Cannot load configuration file/directory %s : %s\n",
1787 *argv,
1788 err_msg);
Willy Tarreau5d01a632009-06-22 16:02:30 +02001789 exit(1);
1790 }
Willy Tarreau5d01a632009-06-22 16:02:30 +02001791 break;
Willy Tarreau392524d2022-02-17 18:10:36 +01001792 case 'p' :
1793 free(global.pidfile);
1794 if ((global.pidfile = strdup(*argv)) == NULL) {
1795 ha_alert("Cannot allocate memory for pidfile.\n");
1796 exit(EXIT_FAILURE);
1797 }
1798 break;
Willy Tarreau3bafcdc2011-09-10 19:20:23 +02001799 default: usage(progname);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001800 }
1801 }
1802 }
1803 else
Willy Tarreau3bafcdc2011-09-10 19:20:23 +02001804 usage(progname);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001805 argv++; argc--;
1806 }
Willy Tarreau392524d2022-02-17 18:10:36 +01001807 free(err_msg);
1808}
1809
Willy Tarreau76871a42022-03-08 16:01:40 +01001810/* call the various keyword dump functions based on the comma-delimited list of
1811 * classes in kwd_dump.
1812 */
1813static void dump_registered_keywords(void)
1814{
1815 char *end;
1816 int all __maybe_unused = 0;
1817
1818 for (; kwd_dump && *kwd_dump; kwd_dump = end) {
1819 end = strchr(kwd_dump, ',');
1820 if (end)
1821 *(end++) = 0;
1822
1823 if (strcmp(kwd_dump, "help") == 0) {
1824 printf("# List of supported keyword classes:\n");
1825 printf("all: list all keywords\n");
Willy Tarreau6ff7d1b2022-03-29 15:36:56 +02001826 printf("acl: ACL keywords\n");
Willy Tarreauca1acd62022-03-29 15:02:44 +02001827 printf("cfg: configuration keywords\n");
Willy Tarreau06d0e2e2022-03-29 15:25:30 +02001828 printf("cli: CLI keywords\n");
Willy Tarreau29d799d2022-03-29 16:59:49 +02001829 printf("cnv: sample converter keywords\n");
Willy Tarreau3b65e142022-03-29 15:03:09 +02001830 printf("flt: filter names\n");
Willy Tarreauf78813f2022-03-29 16:51:29 +02001831 printf("smp: sample fetch functions\n");
Willy Tarreau5fcc1002022-03-29 15:10:44 +02001832 printf("svc: service names\n");
Willy Tarreau76871a42022-03-08 16:01:40 +01001833 continue;
1834 }
1835 else if (strcmp(kwd_dump, "all") == 0) {
1836 all = 1;
1837 }
Willy Tarreauca1acd62022-03-29 15:02:44 +02001838
Willy Tarreau6ff7d1b2022-03-29 15:36:56 +02001839 if (all || strcmp(kwd_dump, "acl") == 0) {
1840 printf("# List of registered ACL keywords:\n");
1841 acl_dump_kwd();
1842 }
1843
Willy Tarreauca1acd62022-03-29 15:02:44 +02001844 if (all || strcmp(kwd_dump, "cfg") == 0) {
1845 printf("# List of registered configuration keywords:\n");
1846 cfg_dump_registered_keywords();
1847 }
Willy Tarreau3b65e142022-03-29 15:03:09 +02001848
Willy Tarreau06d0e2e2022-03-29 15:25:30 +02001849 if (all || strcmp(kwd_dump, "cli") == 0) {
1850 printf("# List of registered CLI keywords:\n");
1851 cli_list_keywords();
1852 }
1853
Willy Tarreau29d799d2022-03-29 16:59:49 +02001854 if (all || strcmp(kwd_dump, "cnv") == 0) {
1855 printf("# List of registered sample converter functions:\n");
1856 smp_dump_conv_kw();
1857 }
1858
Willy Tarreau3b65e142022-03-29 15:03:09 +02001859 if (all || strcmp(kwd_dump, "flt") == 0) {
1860 printf("# List of registered filter names:\n");
1861 flt_dump_kws(NULL);
1862 }
Willy Tarreau5fcc1002022-03-29 15:10:44 +02001863
Willy Tarreauf78813f2022-03-29 16:51:29 +02001864 if (all || strcmp(kwd_dump, "smp") == 0) {
1865 printf("# List of registered sample fetch functions:\n");
1866 smp_dump_fetch_kw();
1867 }
1868
Willy Tarreau5fcc1002022-03-29 15:10:44 +02001869 if (all || strcmp(kwd_dump, "svc") == 0) {
1870 printf("# List of registered service names:\n");
1871 list_services(NULL);
1872 }
Willy Tarreau76871a42022-03-08 16:01:40 +01001873 }
1874}
1875
Willy Tarreau392524d2022-02-17 18:10:36 +01001876/*
1877 * This function initializes all the necessary variables. It only returns
1878 * if everything is OK. If something fails, it exits.
1879 */
1880static void init(int argc, char **argv)
1881{
1882 char *progname = global.log_tag.area;
1883 int err_code = 0;
1884 struct wordlist *wl;
1885 struct proxy *px;
1886 struct post_check_fct *pcf;
William Lallemandb53eb872022-04-21 18:02:53 +02001887 struct pre_check_fct *prcf;
Willy Tarreau392524d2022-02-17 18:10:36 +01001888 int ideal_maxconn;
1889
1890 if (!init_trash_buffers(1)) {
1891 ha_alert("failed to initialize trash buffers.\n");
1892 exit(1);
1893 }
1894
1895 if (init_acl() != 0)
1896 exit(1);
1897
1898 /* Initialise lua. */
1899 hlua_init();
Willy Tarreaubaaee002006-06-26 02:48:02 +02001900
Christopher Faulete3a5e352017-10-24 13:53:54 +02001901 global.mode |= (arg_mode & (MODE_DAEMON | MODE_MWORKER | MODE_FOREGROUND | MODE_VERBOSE
Amaury Denoyelle7b01a8d2021-03-29 10:29:07 +02001902 | MODE_QUIET | MODE_CHECK | MODE_DEBUG | MODE_ZERO_WARNING
Willy Tarreau76871a42022-03-08 16:01:40 +01001903 | MODE_DIAG | MODE_CHECK_CONDITION | MODE_DUMP_LIBS | MODE_DUMP_KWD));
Willy Tarreaubaaee002006-06-26 02:48:02 +02001904
William Lallemand944e6192018-11-21 15:48:31 +01001905 if (getenv("HAPROXY_MWORKER_WAIT_ONLY")) {
William Lallemandcb11fd22017-06-01 17:38:52 +02001906 unsetenv("HAPROXY_MWORKER_WAIT_ONLY");
William Lallemand944e6192018-11-21 15:48:31 +01001907 global.mode |= MODE_MWORKER_WAIT;
1908 global.mode &= ~MODE_MWORKER;
William Lallemandcb11fd22017-06-01 17:38:52 +02001909 }
1910
Willy Tarreau26146192021-07-21 10:01:36 +02001911 if ((global.mode & (MODE_MWORKER | MODE_CHECK | MODE_CHECK_CONDITION)) == MODE_MWORKER &&
1912 (getenv("HAPROXY_MWORKER_REEXEC") != NULL)) {
William Lallemandcb11fd22017-06-01 17:38:52 +02001913 atexit_flag = 1;
1914 atexit(reexec_on_failure);
1915 }
1916
Willy Tarreau576132e2011-09-10 19:26:56 +02001917 if (change_dir && chdir(change_dir) < 0) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001918 ha_alert("Could not change to directory %s : %s\n", change_dir, strerror(errno));
Willy Tarreau576132e2011-09-10 19:26:56 +02001919 exit(1);
1920 }
1921
Amaury Denoyelle11124302021-06-04 18:22:08 +02001922 usermsgs_clr("config");
1923
Maximilian Maderfc0cceb2021-06-06 00:50:22 +02001924 if (global.mode & MODE_CHECK_CONDITION) {
1925 int result;
1926
1927 uint32_t err;
1928 const char *errptr;
1929 char *errmsg = NULL;
1930
1931 char *args[MAX_LINE_ARGS+1];
1932 int arg = sizeof(args) / sizeof(*args);
William Lallemand89e236f2022-05-06 17:22:36 +02001933 size_t outlen;
Willy Tarreauc8194c32021-07-16 16:38:58 +02001934 char *w;
Maximilian Maderfc0cceb2021-06-06 00:50:22 +02001935
William Lallemand89e236f2022-05-06 17:22:36 +02001936 if (!check_condition)
1937 usage(progname);
1938
1939 outlen = strlen(check_condition) + 1;
Maximilian Maderfc0cceb2021-06-06 00:50:22 +02001940 err = parse_line(check_condition, check_condition, &outlen, args, &arg,
Willy Tarreaua87e7822021-07-16 19:14:54 +02001941 PARSE_OPT_ENV | PARSE_OPT_WORD_EXPAND | PARSE_OPT_DQUOTE | PARSE_OPT_SQUOTE | PARSE_OPT_BKSLASH,
Maximilian Maderfc0cceb2021-06-06 00:50:22 +02001942 &errptr);
1943
1944 if (err & PARSE_ERR_QUOTE) {
1945 ha_alert("Syntax Error in condition: Unmatched quote.\n");
1946 exit(2);
1947 }
1948
1949 if (err & PARSE_ERR_HEX) {
1950 ha_alert("Syntax Error in condition: Truncated or invalid hexadecimal sequence.\n");
1951 exit(2);
1952 }
1953
1954 if (err & (PARSE_ERR_TOOLARGE|PARSE_ERR_OVERLAP)) {
1955 ha_alert("Error in condition: Line too long.\n");
1956 exit(2);
1957 }
1958
Willy Tarreauc8194c32021-07-16 16:38:58 +02001959 if (err & PARSE_ERR_TOOMANY) {
Maximilian Maderfc0cceb2021-06-06 00:50:22 +02001960 ha_alert("Error in condition: Too many words.\n");
1961 exit(2);
1962 }
1963
1964 if (err) {
1965 ha_alert("Unhandled error in condition, please report this to the developers.\n");
1966 exit(2);
1967 }
1968
Willy Tarreauc8194c32021-07-16 16:38:58 +02001969 /* remerge all words into a single expression */
1970 for (w = *args; (w += strlen(w)) < check_condition + outlen - 1; *w = ' ')
1971 ;
1972
Maximilian Maderfc0cceb2021-06-06 00:50:22 +02001973 result = cfg_eval_condition(args, &errmsg, &errptr);
1974
1975 if (result < 0) {
1976 if (errmsg)
1977 ha_alert("Failed to evaluate condition: %s\n", errmsg);
1978
1979 exit(2);
1980 }
1981
1982 exit(result ? 0 : 1);
1983 }
1984
William Lallemand944e6192018-11-21 15:48:31 +01001985 /* in wait mode, we don't try to read the configuration files */
1986 if (!(global.mode & MODE_MWORKER_WAIT)) {
Christopher Faulet4e366822021-01-12 18:57:38 +01001987 char *env_cfgfiles = NULL;
1988 int env_err = 0;
Willy Tarreauc4382422009-12-06 13:10:44 +01001989
William Lallemand944e6192018-11-21 15:48:31 +01001990 /* handle cfgfiles that are actually directories */
1991 cfgfiles_expand_directories();
1992
1993 if (LIST_ISEMPTY(&cfg_cfgfiles))
1994 usage(progname);
1995
1996
1997 list_for_each_entry(wl, &cfg_cfgfiles, list) {
1998 int ret;
1999
Christopher Faulet4e366822021-01-12 18:57:38 +01002000 if (env_err == 0) {
2001 if (!memprintf(&env_cfgfiles, "%s%s%s",
2002 (env_cfgfiles ? env_cfgfiles : ""),
2003 (env_cfgfiles ? ";" : ""), wl->s))
2004 env_err = 1;
2005 }
William Lallemand7b302d82019-05-20 11:15:37 +02002006
William Lallemand944e6192018-11-21 15:48:31 +01002007 ret = readcfgfile(wl->s);
2008 if (ret == -1) {
2009 ha_alert("Could not open configuration file %s : %s\n",
2010 wl->s, strerror(errno));
Christopher Faulet4e366822021-01-12 18:57:38 +01002011 free(env_cfgfiles);
William Lallemand944e6192018-11-21 15:48:31 +01002012 exit(1);
2013 }
2014 if (ret & (ERR_ABORT|ERR_FATAL))
2015 ha_alert("Error(s) found in configuration file : %s\n", wl->s);
2016 err_code |= ret;
Christopher Faulet4e366822021-01-12 18:57:38 +01002017 if (err_code & ERR_ABORT) {
2018 free(env_cfgfiles);
William Lallemand944e6192018-11-21 15:48:31 +01002019 exit(1);
Christopher Faulet4e366822021-01-12 18:57:38 +01002020 }
Willy Tarreauc4382422009-12-06 13:10:44 +01002021 }
Krzysztof Oledzkib304dc72007-10-14 23:40:01 +02002022
William Lallemand944e6192018-11-21 15:48:31 +01002023 /* do not try to resolve arguments nor to spot inconsistencies when
2024 * the configuration contains fatal errors caused by files not found
2025 * or failed memory allocations.
2026 */
2027 if (err_code & (ERR_ABORT|ERR_FATAL)) {
2028 ha_alert("Fatal errors found in configuration.\n");
Christopher Faulet4e366822021-01-12 18:57:38 +01002029 free(env_cfgfiles);
William Lallemand944e6192018-11-21 15:48:31 +01002030 exit(1);
2031 }
Christopher Faulet4e366822021-01-12 18:57:38 +01002032 if (env_err) {
2033 ha_alert("Could not allocate memory for HAPROXY_CFGFILES env variable\n");
2034 exit(1);
2035 }
2036 setenv("HAPROXY_CFGFILES", env_cfgfiles, 1);
2037 free(env_cfgfiles);
William Lallemand7b302d82019-05-20 11:15:37 +02002038
Willy Tarreaub83dc3d2017-04-19 11:24:07 +02002039 }
William Lallemandce83b4a2018-10-26 14:47:30 +02002040 if (global.mode & MODE_MWORKER) {
William Lallemand16dd1b32018-11-19 18:46:18 +01002041 struct mworker_proc *tmproc;
2042
William Lallemand482f9a92019-04-12 16:15:00 +02002043 setenv("HAPROXY_MWORKER", "1", 1);
2044
William Lallemand16dd1b32018-11-19 18:46:18 +01002045 if (getenv("HAPROXY_MWORKER_REEXEC") == NULL) {
2046
William Lallemand56be0e02022-01-28 21:11:41 +01002047 tmproc = mworker_proc_new();
William Lallemand16dd1b32018-11-19 18:46:18 +01002048 if (!tmproc) {
2049 ha_alert("Cannot allocate process structures.\n");
2050 exit(EXIT_FAILURE);
2051 }
William Lallemand8f7069a2019-04-12 16:09:23 +02002052 tmproc->options |= PROC_O_TYPE_MASTER; /* master */
William Lallemand16dd1b32018-11-19 18:46:18 +01002053 tmproc->pid = pid;
2054 tmproc->timestamp = start_date.tv_sec;
William Lallemand16dd1b32018-11-19 18:46:18 +01002055 proc_self = tmproc;
2056
Willy Tarreau2b718102021-04-21 07:32:39 +02002057 LIST_APPEND(&proc_list, &tmproc->list);
William Lallemand16dd1b32018-11-19 18:46:18 +01002058 }
William Lallemandce83b4a2018-10-26 14:47:30 +02002059
William Lallemand56be0e02022-01-28 21:11:41 +01002060 tmproc = mworker_proc_new();
Willy Tarreau6185a032021-06-15 08:02:06 +02002061 if (!tmproc) {
2062 ha_alert("Cannot allocate process structures.\n");
2063 exit(EXIT_FAILURE);
2064 }
Willy Tarreau6185a032021-06-15 08:02:06 +02002065 tmproc->options |= PROC_O_TYPE_WORKER; /* worker */
William Lallemandce83b4a2018-10-26 14:47:30 +02002066
Willy Tarreau6185a032021-06-15 08:02:06 +02002067 if (mworker_cli_sockpair_new(tmproc, 0) < 0) {
2068 exit(EXIT_FAILURE);
William Lallemandce83b4a2018-10-26 14:47:30 +02002069 }
Willy Tarreau6185a032021-06-15 08:02:06 +02002070
2071 LIST_APPEND(&proc_list, &tmproc->list);
William Lallemand944e6192018-11-21 15:48:31 +01002072 }
2073 if (global.mode & (MODE_MWORKER|MODE_MWORKER_WAIT)) {
2074 struct wordlist *it, *c;
2075
Remi Tricot-Le Breton1f4fa902021-05-19 10:45:12 +02002076 /* get the info of the children in the env */
2077 if (mworker_env_to_proc_list() < 0) {
2078 exit(EXIT_FAILURE);
2079 }
William Lallemande7361152018-10-26 14:47:36 +02002080
William Lallemand550db6d2018-11-06 17:37:12 +01002081 if (!LIST_ISEMPTY(&mworker_cli_conf)) {
William Lallemande7361152018-10-26 14:47:36 +02002082
William Lallemand550db6d2018-11-06 17:37:12 +01002083 if (mworker_cli_proxy_create() < 0) {
William Lallemande7361152018-10-26 14:47:36 +02002084 ha_alert("Can't create the master's CLI.\n");
2085 exit(EXIT_FAILURE);
2086 }
William Lallemande7361152018-10-26 14:47:36 +02002087
William Lallemand550db6d2018-11-06 17:37:12 +01002088 list_for_each_entry_safe(c, it, &mworker_cli_conf, list) {
2089
2090 if (mworker_cli_proxy_new_listener(c->s) < 0) {
2091 ha_alert("Can't create the master's CLI.\n");
2092 exit(EXIT_FAILURE);
2093 }
Willy Tarreau2b718102021-04-21 07:32:39 +02002094 LIST_DELETE(&c->list);
William Lallemand550db6d2018-11-06 17:37:12 +01002095 free(c->s);
2096 free(c);
2097 }
2098 }
William Lallemandce83b4a2018-10-26 14:47:30 +02002099 }
2100
Eric Salama5ba83352021-03-16 15:11:17 +01002101 if (!LIST_ISEMPTY(&mworker_cli_conf) && !(arg_mode & MODE_MWORKER)) {
2102 ha_warning("a master CLI socket was defined, but master-worker mode (-W) is not enabled.\n");
2103 }
2104
Christopher Faulet27c8d202021-10-13 09:50:53 +02002105 /* destroy unreferenced defaults proxies */
2106 proxy_destroy_all_unref_defaults();
2107
William Lallemandb53eb872022-04-21 18:02:53 +02002108 list_for_each_entry(prcf, &pre_check_list, list)
2109 err_code |= prcf->fct();
Willy Tarreaue90904d2021-02-12 14:08:31 +01002110
William Lallemand8b9a2df2022-05-04 14:29:46 +02002111 if (err_code & (ERR_ABORT|ERR_FATAL)) {
2112 ha_alert("Fatal errors found in configuration.\n");
2113 exit(1);
2114 }
2115
Willy Tarreaubb925012009-07-23 13:36:36 +02002116 err_code |= check_config_validity();
Christopher Fauletc1692962019-08-12 09:51:07 +02002117 for (px = proxies_list; px; px = px->next) {
2118 struct server *srv;
2119 struct post_proxy_check_fct *ppcf;
2120 struct post_server_check_fct *pscf;
2121
Christopher Fauletdfd10ab2021-10-06 14:24:19 +02002122 if (px->flags & (PR_FL_DISABLED|PR_FL_STOPPED))
Christopher Fauletd5bd8242020-11-02 16:20:13 +01002123 continue;
2124
Christopher Fauletc1692962019-08-12 09:51:07 +02002125 list_for_each_entry(pscf, &post_server_check_list, list) {
2126 for (srv = px->srv; srv; srv = srv->next)
2127 err_code |= pscf->fct(srv);
2128 }
2129 list_for_each_entry(ppcf, &post_proxy_check_list, list)
2130 err_code |= ppcf->fct(px);
2131 }
Willy Tarreaubb925012009-07-23 13:36:36 +02002132 if (err_code & (ERR_ABORT|ERR_FATAL)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01002133 ha_alert("Fatal errors found in configuration.\n");
Willy Tarreau915e1eb2009-06-22 15:48:36 +02002134 exit(1);
2135 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002136
Carl Henrik Lundef91ac192020-02-27 16:45:50 +01002137 err_code |= pattern_finalize_config();
2138 if (err_code & (ERR_ABORT|ERR_FATAL)) {
2139 ha_alert("Failed to finalize pattern config.\n");
2140 exit(1);
2141 }
Willy Tarreau0f936722019-04-11 14:47:08 +02002142
Willy Tarreau79c9bdf2021-07-17 12:31:08 +02002143 if (global.rlimit_memmax_all)
2144 global.rlimit_memmax = global.rlimit_memmax_all;
2145
Willy Tarreaue5733232019-05-22 19:24:06 +02002146#ifdef USE_NS
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +01002147 err_code |= netns_init();
2148 if (err_code & (ERR_ABORT|ERR_FATAL)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01002149 ha_alert("Failed to initialize namespace support.\n");
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +01002150 exit(1);
2151 }
2152#endif
2153
Baptiste Assmann4215d7d2016-11-02 15:33:15 +01002154 /* Apply server states */
2155 apply_server_state();
2156
Olivier Houchardfbc74e82017-11-24 16:54:05 +01002157 for (px = proxies_list; px; px = px->next)
Baptiste Assmann4215d7d2016-11-02 15:33:15 +01002158 srv_compute_all_admin_states(px);
2159
Baptiste Assmann83cbaa52016-11-02 15:34:05 +01002160 /* Apply servers' configured address */
2161 err_code |= srv_init_addr();
2162 if (err_code & (ERR_ABORT|ERR_FATAL)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01002163 ha_alert("Failed to initialize server(s) addr.\n");
Baptiste Assmann83cbaa52016-11-02 15:34:05 +01002164 exit(1);
2165 }
2166
Willy Tarreau3eb10b82020-04-15 16:42:39 +02002167 if (warned & WARN_ANY && global.mode & MODE_ZERO_WARNING) {
2168 ha_alert("Some warnings were found and 'zero-warning' is set. Aborting.\n");
2169 exit(1);
2170 }
2171
Willy Tarreau654726d2021-12-28 15:43:11 +01002172#if defined(HA_HAVE_DUMP_LIBS)
2173 if (global.mode & MODE_DUMP_LIBS) {
2174 qfprintf(stdout, "List of loaded object files:\n");
2175 chunk_reset(&trash);
2176 if (dump_libs(&trash, 0))
2177 printf("%s", trash.area);
2178 }
2179#endif
2180
Willy Tarreau76871a42022-03-08 16:01:40 +01002181 if (global.mode & MODE_DUMP_KWD)
2182 dump_registered_keywords();
2183
Willy Tarreaubaaee002006-06-26 02:48:02 +02002184 if (global.mode & MODE_CHECK) {
Willy Tarreau8b15ba12012-02-02 17:48:18 +01002185 struct peers *pr;
2186 struct proxy *px;
2187
Willy Tarreaubebd2122020-04-15 16:06:11 +02002188 if (warned & WARN_ANY)
2189 qfprintf(stdout, "Warnings were found.\n");
2190
Frédéric Lécailleed2b4a62017-07-13 09:07:09 +02002191 for (pr = cfg_peers; pr; pr = pr->next)
Willy Tarreau8b15ba12012-02-02 17:48:18 +01002192 if (pr->peers_fe)
2193 break;
2194
Olivier Houchardfbc74e82017-11-24 16:54:05 +01002195 for (px = proxies_list; px; px = px->next)
Christopher Fauletdfd10ab2021-10-06 14:24:19 +02002196 if (!(px->flags & (PR_FL_DISABLED|PR_FL_STOPPED)) && px->li_all)
Willy Tarreau8b15ba12012-02-02 17:48:18 +01002197 break;
2198
Emeric Brunbc5c8212021-08-13 09:32:50 +02002199 if (!px) {
2200 /* We may only have log-forward section */
2201 for (px = cfg_log_forward; px; px = px->next)
Christopher Fauletdfd10ab2021-10-06 14:24:19 +02002202 if (!(px->flags & (PR_FL_DISABLED|PR_FL_STOPPED)) && px->li_all)
Emeric Brunbc5c8212021-08-13 09:32:50 +02002203 break;
2204 }
2205
Willy Tarreau8b15ba12012-02-02 17:48:18 +01002206 if (pr || px) {
2207 /* At least one peer or one listener has been found */
2208 qfprintf(stdout, "Configuration file is valid\n");
Tim Duesterhus0a3b43d2020-06-14 00:37:42 +02002209 deinit_and_exit(0);
Willy Tarreau8b15ba12012-02-02 17:48:18 +01002210 }
2211 qfprintf(stdout, "Configuration file has no error but will not start (no listener) => exit(2).\n");
2212 exit(2);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002213 }
Willy Tarreaue9b26022011-08-01 20:57:55 +02002214
Amaury Denoyelle5a6926d2021-03-30 17:34:24 +02002215 if (global.mode & MODE_DIAG) {
2216 cfg_run_diagnostics();
2217 }
2218
Remi Tricot-Le Breton51944462022-05-16 16:24:31 +02002219 /* Initialize the random generators */
2220#ifdef USE_OPENSSL
2221 /* Initialize SSL random generator. Must be called before chroot for
2222 * access to /dev/urandom, and before ha_random_boot() which may use
2223 * RAND_bytes().
2224 */
2225 if (!ssl_initialize_random()) {
2226 ha_alert("OpenSSL random data generator initialization failed.\n");
2227 exit(EXIT_FAILURE);
2228 }
2229#endif
2230 ha_random_boot(argv); // the argv pointer brings some kernel-fed entropy
2231
Willy Tarreau8263d2b2012-08-28 00:06:31 +02002232 /* now we know the buffer size, we can initialize the channels and buffers */
Willy Tarreau9b28e032012-10-12 23:49:43 +02002233 init_buffer();
Willy Tarreau8280d642009-09-23 23:37:52 +02002234
Willy Tarreaue6945732016-12-21 19:57:00 +01002235 list_for_each_entry(pcf, &post_check_list, list) {
2236 err_code |= pcf->fct();
2237 if (err_code & (ERR_ABORT|ERR_FATAL))
2238 exit(1);
2239 }
2240
Willy Tarreaubaaee002006-06-26 02:48:02 +02002241 if (cfg_maxconn > 0)
2242 global.maxconn = cfg_maxconn;
2243
Willy Tarreau4975d142021-03-13 11:00:33 +01002244 if (global.cli_fe)
2245 global.maxsock += global.cli_fe->maxconn;
Willy Tarreau8d687d82019-03-01 09:39:42 +01002246
2247 if (cfg_peers) {
2248 /* peers also need to bypass global maxconn */
2249 struct peers *p = cfg_peers;
2250
2251 for (p = cfg_peers; p; p = p->next)
2252 if (p->peers_fe)
2253 global.maxsock += p->peers_fe->maxconn;
2254 }
2255
Willy Tarreaud0256482015-01-15 21:45:22 +01002256 /* Now we want to compute the maxconn and possibly maxsslconn values.
Willy Tarreauac350932019-03-01 15:43:14 +01002257 * It's a bit tricky. Maxconn defaults to the pre-computed value based
2258 * on rlim_fd_cur and the number of FDs in use due to the configuration,
2259 * and maxsslconn defaults to DEFAULT_MAXSSLCONN. On top of that we can
2260 * enforce a lower limit based on memmax.
Willy Tarreaud0256482015-01-15 21:45:22 +01002261 *
2262 * If memmax is set, then it depends on which values are set. If
2263 * maxsslconn is set, we use memmax to determine how many cleartext
2264 * connections may be added, and set maxconn to the sum of the two.
2265 * If maxconn is set and not maxsslconn, maxsslconn is computed from
2266 * the remaining amount of memory between memmax and the cleartext
2267 * connections. If neither are set, then it is considered that all
2268 * connections are SSL-capable, and maxconn is computed based on this,
2269 * then maxsslconn accordingly. We need to know if SSL is used on the
2270 * frontends, backends, or both, because when it's used on both sides,
2271 * we need twice the value for maxsslconn, but we only count the
2272 * handshake once since it is not performed on the two sides at the
2273 * same time (frontend-side is terminated before backend-side begins).
2274 * The SSL stack is supposed to have filled ssl_session_cost and
Willy Tarreau474b96a2015-01-28 19:03:21 +01002275 * ssl_handshake_cost during its initialization. In any case, if
2276 * SYSTEM_MAXCONN is set, we still enforce it as an upper limit for
2277 * maxconn in order to protect the system.
Willy Tarreaud0256482015-01-15 21:45:22 +01002278 */
Willy Tarreauac350932019-03-01 15:43:14 +01002279 ideal_maxconn = compute_ideal_maxconn();
2280
Willy Tarreaud0256482015-01-15 21:45:22 +01002281 if (!global.rlimit_memmax) {
2282 if (global.maxconn == 0) {
Willy Tarreauac350932019-03-01 15:43:14 +01002283 global.maxconn = ideal_maxconn;
Willy Tarreaud0256482015-01-15 21:45:22 +01002284 if (global.mode & (MODE_VERBOSE|MODE_DEBUG))
2285 fprintf(stderr, "Note: setting global.maxconn to %d.\n", global.maxconn);
2286 }
2287 }
2288#ifdef USE_OPENSSL
2289 else if (!global.maxconn && !global.maxsslconn &&
2290 (global.ssl_used_frontend || global.ssl_used_backend)) {
2291 /* memmax is set, compute everything automatically. Here we want
2292 * to ensure that all SSL connections will be served. We take
2293 * care of the number of sides where SSL is used, and consider
2294 * the worst case : SSL used on both sides and doing a handshake
2295 * simultaneously. Note that we can't have more than maxconn
2296 * handshakes at a time by definition, so for the worst case of
2297 * two SSL conns per connection, we count a single handshake.
2298 */
2299 int sides = !!global.ssl_used_frontend + !!global.ssl_used_backend;
2300 int64_t mem = global.rlimit_memmax * 1048576ULL;
Willy Tarreau304e17e2020-03-10 17:54:54 +01002301 int retried = 0;
Willy Tarreaud0256482015-01-15 21:45:22 +01002302
2303 mem -= global.tune.sslcachesize * 200; // about 200 bytes per SSL cache entry
2304 mem -= global.maxzlibmem;
2305 mem = mem * MEM_USABLE_RATIO;
2306
Willy Tarreau304e17e2020-03-10 17:54:54 +01002307 /* Principle: we test once to set maxconn according to the free
2308 * memory. If it results in values the system rejects, we try a
2309 * second time by respecting rlim_fd_max. If it fails again, we
2310 * go back to the initial value and will let the final code
2311 * dealing with rlimit report the error. That's up to 3 attempts.
2312 */
2313 do {
2314 global.maxconn = mem /
2315 ((STREAM_MAX_COST + 2 * global.tune.bufsize) + // stream + 2 buffers per stream
2316 sides * global.ssl_session_max_cost + // SSL buffers, one per side
2317 global.ssl_handshake_max_cost); // 1 handshake per connection max
Willy Tarreaud0256482015-01-15 21:45:22 +01002318
Willy Tarreau304e17e2020-03-10 17:54:54 +01002319 if (retried == 1)
2320 global.maxconn = MIN(global.maxconn, ideal_maxconn);
2321 global.maxconn = round_2dig(global.maxconn);
Willy Tarreau474b96a2015-01-28 19:03:21 +01002322#ifdef SYSTEM_MAXCONN
Willy Tarreau304e17e2020-03-10 17:54:54 +01002323 if (global.maxconn > SYSTEM_MAXCONN)
2324 global.maxconn = SYSTEM_MAXCONN;
Willy Tarreau474b96a2015-01-28 19:03:21 +01002325#endif /* SYSTEM_MAXCONN */
Willy Tarreau304e17e2020-03-10 17:54:54 +01002326 global.maxsslconn = sides * global.maxconn;
2327
2328 if (check_if_maxsock_permitted(compute_ideal_maxsock(global.maxconn)))
2329 break;
2330 } while (retried++ < 2);
2331
Willy Tarreaud0256482015-01-15 21:45:22 +01002332 if (global.mode & (MODE_VERBOSE|MODE_DEBUG))
2333 fprintf(stderr, "Note: setting global.maxconn to %d and global.maxsslconn to %d.\n",
2334 global.maxconn, global.maxsslconn);
2335 }
2336 else if (!global.maxsslconn &&
2337 (global.ssl_used_frontend || global.ssl_used_backend)) {
2338 /* memmax and maxconn are known, compute maxsslconn automatically.
2339 * maxsslconn being forced, we don't know how many of it will be
2340 * on each side if both sides are being used. The worst case is
2341 * when all connections use only one SSL instance because
2342 * handshakes may be on two sides at the same time.
2343 */
2344 int sides = !!global.ssl_used_frontend + !!global.ssl_used_backend;
2345 int64_t mem = global.rlimit_memmax * 1048576ULL;
2346 int64_t sslmem;
2347
2348 mem -= global.tune.sslcachesize * 200; // about 200 bytes per SSL cache entry
2349 mem -= global.maxzlibmem;
2350 mem = mem * MEM_USABLE_RATIO;
2351
Willy Tarreau87b09662015-04-03 00:22:06 +02002352 sslmem = mem - global.maxconn * (int64_t)(STREAM_MAX_COST + 2 * global.tune.bufsize);
Willy Tarreaud0256482015-01-15 21:45:22 +01002353 global.maxsslconn = sslmem / (global.ssl_session_max_cost + global.ssl_handshake_max_cost);
2354 global.maxsslconn = round_2dig(global.maxsslconn);
2355
2356 if (sslmem <= 0 || global.maxsslconn < sides) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01002357 ha_alert("Cannot compute the automatic maxsslconn because global.maxconn is already too "
2358 "high for the global.memmax value (%d MB). The absolute maximum possible value "
2359 "without SSL is %d, but %d was found and SSL is in use.\n",
2360 global.rlimit_memmax,
2361 (int)(mem / (STREAM_MAX_COST + 2 * global.tune.bufsize)),
2362 global.maxconn);
Willy Tarreaud0256482015-01-15 21:45:22 +01002363 exit(1);
2364 }
2365
2366 if (global.maxsslconn > sides * global.maxconn)
2367 global.maxsslconn = sides * global.maxconn;
2368
2369 if (global.mode & (MODE_VERBOSE|MODE_DEBUG))
2370 fprintf(stderr, "Note: setting global.maxsslconn to %d\n", global.maxsslconn);
2371 }
2372#endif
2373 else if (!global.maxconn) {
2374 /* memmax and maxsslconn are known/unused, compute maxconn automatically */
2375 int sides = !!global.ssl_used_frontend + !!global.ssl_used_backend;
2376 int64_t mem = global.rlimit_memmax * 1048576ULL;
2377 int64_t clearmem;
Willy Tarreau304e17e2020-03-10 17:54:54 +01002378 int retried = 0;
Willy Tarreaud0256482015-01-15 21:45:22 +01002379
2380 if (global.ssl_used_frontend || global.ssl_used_backend)
2381 mem -= global.tune.sslcachesize * 200; // about 200 bytes per SSL cache entry
2382
2383 mem -= global.maxzlibmem;
2384 mem = mem * MEM_USABLE_RATIO;
2385
2386 clearmem = mem;
2387 if (sides)
2388 clearmem -= (global.ssl_session_max_cost + global.ssl_handshake_max_cost) * (int64_t)global.maxsslconn;
2389
Willy Tarreau304e17e2020-03-10 17:54:54 +01002390 /* Principle: we test once to set maxconn according to the free
2391 * memory. If it results in values the system rejects, we try a
2392 * second time by respecting rlim_fd_max. If it fails again, we
2393 * go back to the initial value and will let the final code
2394 * dealing with rlimit report the error. That's up to 3 attempts.
2395 */
2396 do {
2397 global.maxconn = clearmem / (STREAM_MAX_COST + 2 * global.tune.bufsize);
2398 if (retried == 1)
2399 global.maxconn = MIN(global.maxconn, ideal_maxconn);
2400 global.maxconn = round_2dig(global.maxconn);
Willy Tarreau474b96a2015-01-28 19:03:21 +01002401#ifdef SYSTEM_MAXCONN
Willy Tarreau304e17e2020-03-10 17:54:54 +01002402 if (global.maxconn > SYSTEM_MAXCONN)
2403 global.maxconn = SYSTEM_MAXCONN;
Willy Tarreau474b96a2015-01-28 19:03:21 +01002404#endif /* SYSTEM_MAXCONN */
Willy Tarreaud0256482015-01-15 21:45:22 +01002405
Willy Tarreau304e17e2020-03-10 17:54:54 +01002406 if (clearmem <= 0 || !global.maxconn) {
2407 ha_alert("Cannot compute the automatic maxconn because global.maxsslconn is already too "
2408 "high for the global.memmax value (%d MB). The absolute maximum possible value "
2409 "is %d, but %d was found.\n",
2410 global.rlimit_memmax,
Christopher Faulet767a84b2017-11-24 16:50:31 +01002411 (int)(mem / (global.ssl_session_max_cost + global.ssl_handshake_max_cost)),
Willy Tarreau304e17e2020-03-10 17:54:54 +01002412 global.maxsslconn);
2413 exit(1);
2414 }
2415
2416 if (check_if_maxsock_permitted(compute_ideal_maxsock(global.maxconn)))
2417 break;
2418 } while (retried++ < 2);
Willy Tarreaud0256482015-01-15 21:45:22 +01002419
2420 if (global.mode & (MODE_VERBOSE|MODE_DEBUG)) {
2421 if (sides && global.maxsslconn > sides * global.maxconn) {
2422 fprintf(stderr, "Note: global.maxsslconn is forced to %d which causes global.maxconn "
2423 "to be limited to %d. Better reduce global.maxsslconn to get more "
2424 "room for extra connections.\n", global.maxsslconn, global.maxconn);
2425 }
2426 fprintf(stderr, "Note: setting global.maxconn to %d\n", global.maxconn);
2427 }
Willy Tarreau66aa61f2009-01-18 21:44:07 +01002428 }
2429
Willy Tarreaua409f302020-03-10 17:08:53 +01002430 global.maxsock = compute_ideal_maxsock(global.maxconn);
2431 global.hardmaxconn = global.maxconn;
Willy Tarreaua4818db2020-06-19 16:20:59 +02002432 if (!global.maxpipes)
2433 global.maxpipes = compute_ideal_maxpipes();
Willy Tarreaubaaee002006-06-26 02:48:02 +02002434
Olivier Houchard88698d92019-04-16 19:07:22 +02002435 /* update connection pool thresholds */
2436 global.tune.pool_low_count = ((long long)global.maxsock * global.tune.pool_low_ratio + 99) / 100;
2437 global.tune.pool_high_count = ((long long)global.maxsock * global.tune.pool_high_ratio + 99) / 100;
2438
Willy Tarreauc8d5b952019-02-27 17:25:52 +01002439 proxy_adjust_all_maxconn();
2440
Willy Tarreau1db37712007-06-03 17:16:49 +02002441 if (global.tune.maxpollevents <= 0)
2442 global.tune.maxpollevents = MAX_POLL_EVENTS;
2443
Willy Tarreau060a7612021-03-10 11:06:26 +01002444 if (global.tune.runqueue_depth <= 0) {
2445 /* tests on various thread counts from 1 to 64 have shown an
2446 * optimal queue depth following roughly 1/sqrt(threads).
2447 */
2448 int s = my_flsl(global.nbthread);
2449 s += (global.nbthread / s); // roughly twice the sqrt.
2450 global.tune.runqueue_depth = RUNQUEUE_DEPTH * 2 / s;
2451 }
Olivier Houchard1599b802018-05-24 18:59:04 +02002452
Willy Tarreau6f4a82c2009-03-21 20:43:57 +01002453 if (global.tune.recv_enough == 0)
2454 global.tune.recv_enough = MIN_RECV_AT_ONCE_ENOUGH;
2455
Willy Tarreau27a674e2009-08-17 07:23:33 +02002456 if (global.tune.maxrewrite >= global.tune.bufsize / 2)
2457 global.tune.maxrewrite = global.tune.bufsize / 2;
2458
Amaury Denoyelle11124302021-06-04 18:22:08 +02002459 usermsgs_clr(NULL);
2460
Willy Tarreaubaaee002006-06-26 02:48:02 +02002461 if (arg_mode & (MODE_DEBUG | MODE_FOREGROUND)) {
2462 /* command line debug mode inhibits configuration mode */
William Lallemand095ba4c2017-06-01 17:38:50 +02002463 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
Willy Tarreau772f0dd2012-10-26 16:04:28 +02002464 global.mode |= (arg_mode & (MODE_DEBUG | MODE_FOREGROUND));
2465 }
2466
William Lallemand095ba4c2017-06-01 17:38:50 +02002467 if (arg_mode & MODE_DAEMON) {
Willy Tarreau772f0dd2012-10-26 16:04:28 +02002468 /* command line daemon mode inhibits foreground and debug modes mode */
2469 global.mode &= ~(MODE_DEBUG | MODE_FOREGROUND);
William Lallemand095ba4c2017-06-01 17:38:50 +02002470 global.mode |= arg_mode & MODE_DAEMON;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002471 }
Willy Tarreau772f0dd2012-10-26 16:04:28 +02002472
2473 global.mode |= (arg_mode & (MODE_QUIET | MODE_VERBOSE));
Willy Tarreaubaaee002006-06-26 02:48:02 +02002474
William Lallemand095ba4c2017-06-01 17:38:50 +02002475 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01002476 ha_warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
William Lallemand095ba4c2017-06-01 17:38:50 +02002477 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002478 }
2479
Christopher Fauletbe0faa22017-08-29 15:37:10 +02002480 if (global.nbthread < 1)
2481 global.nbthread = 1;
2482
Christopher Faulet3ef26392017-08-29 16:46:57 +02002483 /* Realloc trash buffers because global.tune.bufsize may have changed */
Christopher Fauletcd7879a2017-10-27 13:53:47 +02002484 if (!init_trash_buffers(0)) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01002485 ha_alert("failed to initialize trash buffers.\n");
Christopher Faulet3ef26392017-08-29 16:46:57 +02002486 exit(1);
2487 }
2488
Christopher Faulet96d44832017-11-14 22:02:30 +01002489 if (!init_log_buffers()) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01002490 ha_alert("failed to initialize log buffers.\n");
Christopher Faulet96d44832017-11-14 22:02:30 +01002491 exit(1);
2492 }
2493
Willy Tarreauef1d1f82007-04-16 00:25:25 +02002494 /*
2495 * Note: we could register external pollers here.
2496 * Built-in pollers have been registered before main().
2497 */
Willy Tarreau4f60f162007-04-08 16:39:58 +02002498
Willy Tarreau43b78992009-01-25 15:42:27 +01002499 if (!(global.tune.options & GTUNE_USE_KQUEUE))
Willy Tarreau1e63130a2007-04-09 12:03:06 +02002500 disable_poller("kqueue");
2501
Emmanuel Hocdet0ba4f482019-04-08 16:53:32 +00002502 if (!(global.tune.options & GTUNE_USE_EVPORTS))
2503 disable_poller("evports");
2504
Willy Tarreau43b78992009-01-25 15:42:27 +01002505 if (!(global.tune.options & GTUNE_USE_EPOLL))
Willy Tarreau4f60f162007-04-08 16:39:58 +02002506 disable_poller("epoll");
2507
Willy Tarreau43b78992009-01-25 15:42:27 +01002508 if (!(global.tune.options & GTUNE_USE_POLL))
Willy Tarreau4f60f162007-04-08 16:39:58 +02002509 disable_poller("poll");
2510
Willy Tarreau43b78992009-01-25 15:42:27 +01002511 if (!(global.tune.options & GTUNE_USE_SELECT))
Willy Tarreau4f60f162007-04-08 16:39:58 +02002512 disable_poller("select");
2513
2514 /* Note: we could disable any poller by name here */
2515
Christopher Fauletb3f4e142016-03-07 12:46:38 +01002516 if (global.mode & (MODE_VERBOSE|MODE_DEBUG)) {
Willy Tarreau2ff76222007-04-09 19:29:56 +02002517 list_pollers(stderr);
Christopher Fauletb3f4e142016-03-07 12:46:38 +01002518 fprintf(stderr, "\n");
2519 list_filters(stderr);
2520 }
Willy Tarreau2ff76222007-04-09 19:29:56 +02002521
Willy Tarreau4f60f162007-04-08 16:39:58 +02002522 if (!init_pollers()) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01002523 ha_alert("No polling mechanism available.\n"
2524 " It is likely that haproxy was built with TARGET=generic and that FD_SETSIZE\n"
2525 " is too low on this platform to support maxconn and the number of listeners\n"
2526 " and servers. You should rebuild haproxy specifying your system using TARGET=\n"
2527 " in order to support other polling systems (poll, epoll, kqueue) or reduce the\n"
2528 " global maxconn setting to accommodate the system's limitation. For reference,\n"
2529 " FD_SETSIZE=%d on this system, global.maxconn=%d resulting in a maximum of\n"
2530 " %d file descriptors. You should thus reduce global.maxconn by %d. Also,\n"
2531 " check build settings using 'haproxy -vv'.\n\n",
2532 FD_SETSIZE, global.maxconn, global.maxsock, (global.maxsock + 1 - FD_SETSIZE) / 2);
Willy Tarreau4f60f162007-04-08 16:39:58 +02002533 exit(1);
2534 }
Willy Tarreau2ff76222007-04-09 19:29:56 +02002535 if (global.mode & (MODE_VERBOSE|MODE_DEBUG)) {
2536 printf("Using %s() as the polling mechanism.\n", cur_poller.name);
Willy Tarreau4f60f162007-04-08 16:39:58 +02002537 }
2538
Krzysztof Piotr Oledzki48cb2ae2009-10-02 22:51:14 +02002539 if (!global.node)
2540 global.node = strdup(hostname);
2541
Willy Tarreau02b092f2020-10-07 18:36:54 +02002542 /* stop disabled proxies */
2543 for (px = proxies_list; px; px = px->next) {
Christopher Fauletdfd10ab2021-10-06 14:24:19 +02002544 if (px->flags & (PR_FL_DISABLED|PR_FL_STOPPED))
Willy Tarreau02b092f2020-10-07 18:36:54 +02002545 stop_proxy(px);
2546 }
2547
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01002548 if (!hlua_post_init())
2549 exit(1);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002550}
2551
Cyril Bonté203ec5a2017-03-23 22:44:13 +01002552void deinit(void)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002553{
Olivier Houchardfbc74e82017-11-24 16:54:05 +01002554 struct proxy *p = proxies_list, *p0;
Willy Tarreaudeb9ed82010-01-03 21:03:22 +01002555 struct wordlist *wl, *wlb;
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +02002556 struct uri_auth *uap, *ua = NULL;
William Lallemand0f99e342011-10-12 17:50:54 +02002557 struct logsrv *log, *logb;
Willy Tarreaucdb737e2016-12-21 18:43:10 +01002558 struct build_opts_str *bol, *bolb;
Tim Duesterhusfdf904a2020-07-04 11:49:48 +02002559 struct post_deinit_fct *pdf, *pdfb;
Tim Duesterhus17e363f2020-07-04 11:49:47 +02002560 struct proxy_deinit_fct *pxdf, *pxdfb;
Tim Duesterhus0837eb12020-07-04 11:49:49 +02002561 struct server_deinit_fct *srvdf, *srvdfb;
Tim Duesterhusf0c25d22020-09-10 19:46:41 +02002562 struct per_thread_init_fct *tif, *tifb;
2563 struct per_thread_deinit_fct *tdf, *tdfb;
2564 struct per_thread_alloc_fct *taf, *tafb;
2565 struct per_thread_free_fct *tff, *tffb;
Tim Duesterhus34bef072020-07-04 11:49:50 +02002566 struct post_server_check_fct *pscf, *pscfb;
Tim Duesterhusfc854942020-09-10 19:46:42 +02002567 struct post_check_fct *pcf, *pcfb;
Tim Duesterhus53508d62020-09-10 19:46:40 +02002568 struct post_proxy_check_fct *ppcf, *ppcfb;
Willy Tarreau65009eb2022-04-27 18:02:54 +02002569 struct pre_check_fct *prcf, *prcfb;
Willy Tarreau226866e2022-04-27 18:07:24 +02002570 struct cfg_postparser *pprs, *pprsb;
Willy Tarreauae7bc4a2020-09-23 16:46:22 +02002571 int cur_fd;
2572
2573 /* At this point the listeners state is weird:
2574 * - most listeners are still bound and referenced in their protocol
2575 * - some might be zombies that are not in their proto anymore, but
2576 * still appear in their proxy's listeners with a valid FD.
2577 * - some might be stopped and still appear in their proxy as FD #-1
2578 * - among all of them, some might be inherited hence shared and we're
2579 * not allowed to pause them or whatever, we must just close them.
2580 * - finally some are not listeners (pipes, logs, stdout, etc) and
2581 * must be left intact.
2582 *
2583 * The safe way to proceed is to unbind (and close) whatever is not yet
2584 * unbound so that no more receiver/listener remains alive. Then close
2585 * remaining listener FDs, which correspond to zombie listeners (those
2586 * belonging to disabled proxies that were in another process).
2587 * objt_listener() would be cleaner here but not converted yet.
2588 */
2589 protocol_unbind_all();
2590
2591 for (cur_fd = 0; cur_fd < global.maxsock; cur_fd++) {
Willy Tarreau1a3770c2020-10-14 12:13:51 +02002592 if (!fdtab || !fdtab[cur_fd].owner)
Willy Tarreauae7bc4a2020-09-23 16:46:22 +02002593 continue;
2594
Willy Tarreaua74cb382020-10-15 21:29:49 +02002595 if (fdtab[cur_fd].iocb == &sock_accept_iocb) {
Willy Tarreauae7bc4a2020-09-23 16:46:22 +02002596 struct listener *l = fdtab[cur_fd].owner;
2597
2598 BUG_ON(l->state != LI_INIT);
2599 unbind_listener(l);
2600 }
2601 }
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +02002602
Willy Tarreau24f4efa2010-08-27 17:56:48 +02002603 deinit_signals();
Willy Tarreaubaaee002006-06-26 02:48:02 +02002604 while (p) {
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +02002605 /* build a list of unique uri_auths */
2606 if (!ua)
2607 ua = p->uri_auth;
2608 else {
2609 /* check if p->uri_auth is unique */
2610 for (uap = ua; uap; uap=uap->next)
2611 if (uap == p->uri_auth)
2612 break;
2613
Willy Tarreauaccc4e12008-06-24 11:14:45 +02002614 if (!uap && p->uri_auth) {
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +02002615 /* add it, if it is */
2616 p->uri_auth->next = ua;
2617 ua = p->uri_auth;
2618 }
William Lallemand0f99e342011-10-12 17:50:54 +02002619 }
2620
Willy Tarreau4d2d0982007-05-14 00:39:29 +02002621 p0 = p;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002622 p = p->next;
Amaury Denoyelle27fefa12021-03-24 16:13:20 +01002623 free_proxy(p0);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002624 }/* end while(p) */
Willy Tarreaudd815982007-10-16 12:25:14 +02002625
Christopher Faulet27c8d202021-10-13 09:50:53 +02002626 /* destroy all referenced defaults proxies */
2627 proxy_destroy_all_unref_defaults();
2628
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +02002629 while (ua) {
Tim Duesterhus00f00cf2020-09-10 19:46:38 +02002630 struct stat_scope *scope, *scopep;
2631
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +02002632 uap = ua;
2633 ua = ua->next;
2634
Willy Tarreaua534fea2008-08-03 12:19:50 +02002635 free(uap->uri_prefix);
2636 free(uap->auth_realm);
Krzysztof Piotr Oledzki48cb2ae2009-10-02 22:51:14 +02002637 free(uap->node);
2638 free(uap->desc);
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +02002639
Krzysztof Piotr Oledzki8c8bd452010-01-29 19:29:32 +01002640 userlist_free(uap->userlist);
Amaury Denoyelle68fd7e42021-03-25 17:15:52 +01002641 free_act_rules(&uap->http_req_rules);
Krzysztof Piotr Oledzki8c8bd452010-01-29 19:29:32 +01002642
Tim Duesterhus00f00cf2020-09-10 19:46:38 +02002643 scope = uap->scope;
2644 while (scope) {
2645 scopep = scope;
2646 scope = scope->next;
2647
2648 free(scopep->px_id);
2649 free(scopep);
2650 }
2651
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +02002652 free(uap);
2653 }
2654
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +01002655 userlist_free(userlist);
2656
David Carlier834cb2e2015-09-25 12:02:25 +01002657 cfg_unregister_sections();
2658
Christopher Faulet0132d062017-07-26 15:33:35 +02002659 deinit_log_buffers();
David Carlier834cb2e2015-09-25 12:02:25 +01002660
Willy Tarreau05554e62016-12-21 20:46:26 +01002661 list_for_each_entry(pdf, &post_deinit_list, list)
2662 pdf->fct();
2663
Willy Tarreau61cfdf42021-02-20 10:46:51 +01002664 ha_free(&global.log_send_hostname);
Dragan Dosen43885c72015-10-01 13:18:13 +02002665 chunk_destroy(&global.log_tag);
Willy Tarreau61cfdf42021-02-20 10:46:51 +01002666 ha_free(&global.chroot);
Frédéric Lécaille372508c2022-05-06 08:53:16 +02002667 ha_free(&global.cluster_secret);
Willy Tarreau61cfdf42021-02-20 10:46:51 +01002668 ha_free(&global.pidfile);
2669 ha_free(&global.node);
2670 ha_free(&global.desc);
2671 ha_free(&oldpids);
2672 ha_free(&old_argv);
2673 ha_free(&localpeer);
2674 ha_free(&global.server_state_base);
2675 ha_free(&global.server_state_file);
Olivier Houchard3f795f72019-04-17 22:51:06 +02002676 task_destroy(idle_conn_task);
Olivier Houchard9ea5d362019-02-14 18:29:09 +01002677 idle_conn_task = NULL;
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +02002678
William Lallemand0f99e342011-10-12 17:50:54 +02002679 list_for_each_entry_safe(log, logb, &global.logsrvs, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002680 LIST_DELETE(&log->list);
Amaury Denoyelled688e012021-04-20 17:05:47 +02002681 free(log->conf.file);
William Lallemand0f99e342011-10-12 17:50:54 +02002682 free(log);
2683 }
Willy Tarreau477ecd82010-01-03 21:12:30 +01002684 list_for_each_entry_safe(wl, wlb, &cfg_cfgfiles, list) {
Maxime de Roucy0f503922016-05-13 23:52:55 +02002685 free(wl->s);
Willy Tarreau2b718102021-04-21 07:32:39 +02002686 LIST_DELETE(&wl->list);
Willy Tarreau477ecd82010-01-03 21:12:30 +01002687 free(wl);
2688 }
2689
Willy Tarreaucdb737e2016-12-21 18:43:10 +01002690 list_for_each_entry_safe(bol, bolb, &build_opts_list, list) {
2691 if (bol->must_free)
2692 free((void *)bol->str);
Willy Tarreau2b718102021-04-21 07:32:39 +02002693 LIST_DELETE(&bol->list);
Willy Tarreaucdb737e2016-12-21 18:43:10 +01002694 free(bol);
2695 }
2696
Tim Duesterhus17e363f2020-07-04 11:49:47 +02002697 list_for_each_entry_safe(pxdf, pxdfb, &proxy_deinit_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002698 LIST_DELETE(&pxdf->list);
Tim Duesterhus17e363f2020-07-04 11:49:47 +02002699 free(pxdf);
2700 }
2701
Tim Duesterhusfdf904a2020-07-04 11:49:48 +02002702 list_for_each_entry_safe(pdf, pdfb, &post_deinit_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002703 LIST_DELETE(&pdf->list);
Tim Duesterhusfdf904a2020-07-04 11:49:48 +02002704 free(pdf);
2705 }
2706
Tim Duesterhus0837eb12020-07-04 11:49:49 +02002707 list_for_each_entry_safe(srvdf, srvdfb, &server_deinit_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002708 LIST_DELETE(&srvdf->list);
Tim Duesterhus0837eb12020-07-04 11:49:49 +02002709 free(srvdf);
2710 }
2711
Tim Duesterhusfc854942020-09-10 19:46:42 +02002712 list_for_each_entry_safe(pcf, pcfb, &post_check_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002713 LIST_DELETE(&pcf->list);
Tim Duesterhusfc854942020-09-10 19:46:42 +02002714 free(pcf);
2715 }
2716
Tim Duesterhus34bef072020-07-04 11:49:50 +02002717 list_for_each_entry_safe(pscf, pscfb, &post_server_check_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002718 LIST_DELETE(&pscf->list);
Tim Duesterhus34bef072020-07-04 11:49:50 +02002719 free(pscf);
2720 }
2721
Tim Duesterhus53508d62020-09-10 19:46:40 +02002722 list_for_each_entry_safe(ppcf, ppcfb, &post_proxy_check_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002723 LIST_DELETE(&ppcf->list);
Tim Duesterhus53508d62020-09-10 19:46:40 +02002724 free(ppcf);
2725 }
2726
Willy Tarreau65009eb2022-04-27 18:02:54 +02002727 list_for_each_entry_safe(prcf, prcfb, &pre_check_list, list) {
2728 LIST_DELETE(&prcf->list);
2729 free(prcf);
2730 }
2731
Tim Duesterhusf0c25d22020-09-10 19:46:41 +02002732 list_for_each_entry_safe(tif, tifb, &per_thread_init_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002733 LIST_DELETE(&tif->list);
Tim Duesterhusf0c25d22020-09-10 19:46:41 +02002734 free(tif);
2735 }
2736
2737 list_for_each_entry_safe(tdf, tdfb, &per_thread_deinit_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002738 LIST_DELETE(&tdf->list);
Tim Duesterhusf0c25d22020-09-10 19:46:41 +02002739 free(tdf);
2740 }
2741
2742 list_for_each_entry_safe(taf, tafb, &per_thread_alloc_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002743 LIST_DELETE(&taf->list);
Tim Duesterhusf0c25d22020-09-10 19:46:41 +02002744 free(taf);
2745 }
2746
2747 list_for_each_entry_safe(tff, tffb, &per_thread_free_list, list) {
Willy Tarreau2b718102021-04-21 07:32:39 +02002748 LIST_DELETE(&tff->list);
Tim Duesterhusf0c25d22020-09-10 19:46:41 +02002749 free(tff);
2750 }
2751
Willy Tarreau226866e2022-04-27 18:07:24 +02002752 list_for_each_entry_safe(pprs, pprsb, &postparsers, list) {
2753 LIST_DELETE(&pprs->list);
2754 free(pprs);
2755 }
2756
Willy Tarreaucfc4f242021-05-08 11:41:28 +02002757 vars_prune(&proc_vars, NULL, NULL);
Willy Tarreau2455ceb2018-11-26 15:57:34 +01002758 pool_destroy_all();
Krzysztof Piotr Oledzkia643baf2008-05-29 23:53:44 +02002759 deinit_pollers();
Willy Tarreaubaaee002006-06-26 02:48:02 +02002760} /* end deinit() */
2761
Willy Tarreauf3ca5a02020-06-15 18:43:46 +02002762__attribute__((noreturn)) void deinit_and_exit(int status)
Tim Duesterhus26540552020-06-14 00:37:41 +02002763{
Amaury Denoyelle7afa5c12021-08-09 15:02:56 +02002764 global.mode |= MODE_STOPPING;
Tim Duesterhus26540552020-06-14 00:37:41 +02002765 deinit();
2766 exit(status);
2767}
William Lallemand72160322018-11-06 17:37:16 +01002768
Willy Tarreau918ff602011-07-25 16:33:49 +02002769/* Runs the polling loop */
Willy Tarreau3ebd55e2020-03-03 14:59:56 +01002770void run_poll_loop()
Willy Tarreau4f60f162007-04-08 16:39:58 +02002771{
Willy Tarreau2ae84e42019-05-28 16:44:05 +02002772 int next, wake;
Willy Tarreau4f60f162007-04-08 16:39:58 +02002773
Willy Tarreau55542642021-10-08 09:33:24 +02002774 clock_update_date(0,1);
Willy Tarreau4f60f162007-04-08 16:39:58 +02002775 while (1) {
Willy Tarreauc49ba522019-12-11 08:12:23 +01002776 wake_expired_tasks();
2777
William Lallemand1aab50b2018-06-07 09:46:01 +02002778 /* check if we caught some signals and process them in the
2779 first thread */
Willy Tarreaua7ad4ae2020-06-19 12:06:34 +02002780 if (signal_queue_len && tid == 0) {
2781 activity[tid].wake_signal++;
William Lallemand1aab50b2018-06-07 09:46:01 +02002782 signal_process_queue();
Willy Tarreaua7ad4ae2020-06-19 12:06:34 +02002783 }
2784
2785 /* Process a few tasks */
2786 process_runnable_tasks();
Willy Tarreau29857942009-05-10 09:01:21 +02002787
Willy Tarreau7067b3a2019-06-02 11:11:29 +02002788 /* also stop if we failed to cleanly stop all tasks */
2789 if (killed > 1)
2790 break;
2791
Willy Tarreau10146c92015-04-13 20:44:19 +02002792 /* expire immediately if events are pending */
Willy Tarreau2ae84e42019-05-28 16:44:05 +02002793 wake = 1;
Olivier Houchard305d5ab2019-07-24 18:07:06 +02002794 if (thread_has_tasks())
Willy Tarreaud80cb4e2018-01-20 19:30:13 +01002795 activity[tid].wake_tasks++;
Olivier Houchard79321b92018-07-26 17:55:11 +02002796 else {
Olivier Houchardb23a61f2019-03-08 18:51:17 +01002797 _HA_ATOMIC_OR(&sleeping_thread_mask, tid_bit);
2798 __ha_barrier_atomic_store();
Willy Tarreau95abd5b2020-03-23 09:33:32 +01002799 if (thread_has_tasks()) {
Olivier Houchard79321b92018-07-26 17:55:11 +02002800 activity[tid].wake_tasks++;
Olivier Houchardb23a61f2019-03-08 18:51:17 +01002801 _HA_ATOMIC_AND(&sleeping_thread_mask, ~tid_bit);
Olivier Houchard79321b92018-07-26 17:55:11 +02002802 } else
Willy Tarreau2ae84e42019-05-28 16:44:05 +02002803 wake = 0;
Olivier Houchard79321b92018-07-26 17:55:11 +02002804 }
Willy Tarreau10146c92015-04-13 20:44:19 +02002805
Willy Tarreau4f46a352020-03-23 09:27:28 +01002806 if (!wake) {
Willy Tarreaud7a6b2f2020-05-13 13:51:01 +02002807 int i;
2808
2809 if (stopping) {
Ilya Shipitsin3df59892021-05-10 12:50:00 +05002810 /* stop muxes before acknowledging stopping */
Amaury Denoyelled3a88c12021-05-03 10:47:51 +02002811 if (!(stopping_thread_mask & tid_bit)) {
2812 task_wakeup(mux_stopping_data[tid].task, TASK_WOKEN_OTHER);
2813 wake = 1;
2814 }
2815
Willy Tarreau1db42732021-04-06 11:44:07 +02002816 if (_HA_ATOMIC_OR_FETCH(&stopping_thread_mask, tid_bit) == tid_bit) {
Willy Tarreaud6455742020-05-13 14:30:25 +02002817 /* notify all threads that stopping was just set */
2818 for (i = 0; i < global.nbthread; i++)
Willy Tarreau369a2ef2020-06-29 19:23:19 +02002819 if (((all_threads_mask & ~stopping_thread_mask) >> i) & 1)
Willy Tarreaud6455742020-05-13 14:30:25 +02002820 wake_thread(i);
2821 }
Willy Tarreaud7a6b2f2020-05-13 13:51:01 +02002822 }
Willy Tarreau4f46a352020-03-23 09:27:28 +01002823
2824 /* stop when there's nothing left to do */
2825 if ((jobs - unstoppable_jobs) == 0 &&
Willy Tarreaud7a6b2f2020-05-13 13:51:01 +02002826 (stopping_thread_mask & all_threads_mask) == all_threads_mask) {
2827 /* wake all threads waiting on jobs==0 */
2828 for (i = 0; i < global.nbthread; i++)
2829 if (((all_threads_mask & ~tid_bit) >> i) & 1)
2830 wake_thread(i);
Willy Tarreau4f46a352020-03-23 09:27:28 +01002831 break;
Willy Tarreaud7a6b2f2020-05-13 13:51:01 +02002832 }
Willy Tarreau4f46a352020-03-23 09:27:28 +01002833 }
2834
Willy Tarreauc49ba522019-12-11 08:12:23 +01002835 /* If we have to sleep, measure how long */
2836 next = wake ? TICK_ETERNITY : next_timer_expiry();
2837
Willy Tarreau58b458d2008-06-29 22:40:23 +02002838 /* The poller will ensure it returns around <next> */
Willy Tarreau2ae84e42019-05-28 16:44:05 +02002839 cur_poller.poll(&cur_poller, next, wake);
Emeric Brun64cc49c2017-10-03 14:46:45 +02002840
Willy Tarreaud80cb4e2018-01-20 19:30:13 +01002841 activity[tid].loops++;
Willy Tarreau4f60f162007-04-08 16:39:58 +02002842 }
2843}
2844
Christopher Faulet1d17c102017-08-29 15:38:48 +02002845static void *run_thread_poll_loop(void *data)
2846{
Willy Tarreau082b6282019-05-22 14:42:12 +02002847 struct per_thread_alloc_fct *ptaf;
Christopher Faulet1d17c102017-08-29 15:38:48 +02002848 struct per_thread_init_fct *ptif;
2849 struct per_thread_deinit_fct *ptdf;
Willy Tarreau082b6282019-05-22 14:42:12 +02002850 struct per_thread_free_fct *ptff;
Willy Tarreau34a150c2019-06-11 09:16:41 +02002851 static int init_left = 0;
Willy Tarreauaf613e82020-06-05 08:40:51 +02002852 __decl_thread(static pthread_mutex_t init_mutex = PTHREAD_MUTEX_INITIALIZER);
2853 __decl_thread(static pthread_cond_t init_cond = PTHREAD_COND_INITIALIZER);
Christopher Faulet1d17c102017-08-29 15:38:48 +02002854
Willy Tarreau43ab05b2021-09-28 09:43:11 +02002855 ha_set_thread(data);
Willy Tarreaufb641d72021-09-28 10:15:47 +02002856 set_thread_cpu_affinity();
Willy Tarreau44c58da2021-10-08 12:27:54 +02002857 clock_set_local_source();
Willy Tarreau91e6df02019-05-03 17:21:18 +02002858
Willy Tarreau6ec902a2019-06-07 14:41:11 +02002859 /* Now, initialize one thread init at a time. This is better since
2860 * some init code is a bit tricky and may release global resources
2861 * after reallocating them locally. This will also ensure there is
2862 * no race on file descriptors allocation.
2863 */
Willy Tarreau34a150c2019-06-11 09:16:41 +02002864#ifdef USE_THREAD
2865 pthread_mutex_lock(&init_mutex);
2866#endif
2867 /* The first thread must set the number of threads left */
2868 if (!init_left)
2869 init_left = global.nbthread;
2870 init_left--;
Willy Tarreau91e6df02019-05-03 17:21:18 +02002871
Willy Tarreau55542642021-10-08 09:33:24 +02002872 clock_init_thread_date();
Christopher Faulet1d17c102017-08-29 15:38:48 +02002873
Willy Tarreau082b6282019-05-22 14:42:12 +02002874 /* per-thread alloc calls performed here are not allowed to snoop on
2875 * other threads, so they are free to initialize at their own rhythm
2876 * as long as they act as if they were alone. None of them may rely
2877 * on resources initialized by the other ones.
2878 */
2879 list_for_each_entry(ptaf, &per_thread_alloc_list, list) {
2880 if (!ptaf->fct()) {
2881 ha_alert("failed to allocate resources for thread %u.\n", tid);
Willy Tarreaub3c4a8f2021-07-22 14:42:32 +02002882#ifdef USE_THREAD
jenny-cheung048368e2021-07-18 16:40:57 +08002883 pthread_mutex_unlock(&init_mutex);
Willy Tarreaub3c4a8f2021-07-22 14:42:32 +02002884#endif
Willy Tarreau082b6282019-05-22 14:42:12 +02002885 exit(1);
2886 }
2887 }
2888
Willy Tarreau3078e9f2019-05-20 10:50:43 +02002889 /* per-thread init calls performed here are not allowed to snoop on
2890 * other threads, so they are free to initialize at their own rhythm
2891 * as long as they act as if they were alone.
2892 */
Christopher Faulet1d17c102017-08-29 15:38:48 +02002893 list_for_each_entry(ptif, &per_thread_init_list, list) {
2894 if (!ptif->fct()) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01002895 ha_alert("failed to initialize thread %u.\n", tid);
Willy Tarreaub3c4a8f2021-07-22 14:42:32 +02002896#ifdef USE_THREAD
jenny-cheung048368e2021-07-18 16:40:57 +08002897 pthread_mutex_unlock(&init_mutex);
Willy Tarreaub3c4a8f2021-07-22 14:42:32 +02002898#endif
Christopher Faulet1d17c102017-08-29 15:38:48 +02002899 exit(1);
2900 }
2901 }
2902
Willy Tarreau71092822019-06-10 09:51:04 +02002903 /* enabling protocols will result in fd_insert() calls to be performed,
2904 * we want all threads to have already allocated their local fd tables
Willy Tarreau34a150c2019-06-11 09:16:41 +02002905 * before doing so, thus only the last thread does it.
Willy Tarreau71092822019-06-10 09:51:04 +02002906 */
Willy Tarreau34a150c2019-06-11 09:16:41 +02002907 if (init_left == 0)
Willy Tarreaue4d7c9d2019-06-10 10:14:52 +02002908 protocol_enable_all();
Willy Tarreau6ec902a2019-06-07 14:41:11 +02002909
Willy Tarreau34a150c2019-06-11 09:16:41 +02002910#ifdef USE_THREAD
2911 pthread_cond_broadcast(&init_cond);
2912 pthread_mutex_unlock(&init_mutex);
2913
2914 /* now wait for other threads to finish starting */
2915 pthread_mutex_lock(&init_mutex);
2916 while (init_left)
2917 pthread_cond_wait(&init_cond, &init_mutex);
2918 pthread_mutex_unlock(&init_mutex);
2919#endif
Willy Tarreau3078e9f2019-05-20 10:50:43 +02002920
Willy Tarreaua45a8b52019-12-06 16:31:45 +01002921#if defined(PR_SET_NO_NEW_PRIVS) && defined(USE_PRCTL)
2922 /* Let's refrain from using setuid executables. This way the impact of
2923 * an eventual vulnerability in a library remains limited. It may
2924 * impact external checks but who cares about them anyway ? In the
2925 * worst case it's possible to disable the option. Obviously we do this
2926 * in workers only. We can't hard-fail on this one as it really is
2927 * implementation dependent though we're interested in feedback, hence
2928 * the warning.
2929 */
2930 if (!(global.tune.options & GTUNE_INSECURE_SETUID) && !master) {
2931 static int warn_fail;
Willy Tarreau18515722021-04-06 11:57:41 +02002932 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1 && !_HA_ATOMIC_FETCH_ADD(&warn_fail, 1)) {
Willy Tarreaua45a8b52019-12-06 16:31:45 +01002933 ha_warning("Failed to disable setuid, please report to developers with detailed "
2934 "information about your operating system. You can silence this warning "
2935 "by adding 'insecure-setuid-wanted' in the 'global' section.\n");
2936 }
2937 }
2938#endif
2939
Willy Tarreaud96f1122019-12-03 07:07:36 +01002940#if defined(RLIMIT_NPROC)
2941 /* all threads have started, it's now time to prevent any new thread
2942 * or process from starting. Obviously we do this in workers only. We
2943 * can't hard-fail on this one as it really is implementation dependent
2944 * though we're interested in feedback, hence the warning.
2945 */
2946 if (!(global.tune.options & GTUNE_INSECURE_FORK) && !master) {
2947 struct rlimit limit = { .rlim_cur = 0, .rlim_max = 0 };
2948 static int warn_fail;
2949
Willy Tarreau18515722021-04-06 11:57:41 +02002950 if (setrlimit(RLIMIT_NPROC, &limit) == -1 && !_HA_ATOMIC_FETCH_ADD(&warn_fail, 1)) {
Willy Tarreaud96f1122019-12-03 07:07:36 +01002951 ha_warning("Failed to disable forks, please report to developers with detailed "
2952 "information about your operating system. You can silence this warning "
2953 "by adding 'insecure-fork-wanted' in the 'global' section.\n");
2954 }
2955 }
2956#endif
Christopher Faulet1d17c102017-08-29 15:38:48 +02002957 run_poll_loop();
2958
2959 list_for_each_entry(ptdf, &per_thread_deinit_list, list)
2960 ptdf->fct();
2961
Willy Tarreau082b6282019-05-22 14:42:12 +02002962 list_for_each_entry(ptff, &per_thread_free_list, list)
2963 ptff->fct();
2964
Christopher Fauletcd7879a2017-10-27 13:53:47 +02002965#ifdef USE_THREAD
Olivier Houchardb23a61f2019-03-08 18:51:17 +01002966 _HA_ATOMIC_AND(&all_threads_mask, ~tid_bit);
Christopher Fauletcd7879a2017-10-27 13:53:47 +02002967 if (tid > 0)
2968 pthread_exit(NULL);
Christopher Faulet1d17c102017-08-29 15:38:48 +02002969#endif
Christopher Fauletcd7879a2017-10-27 13:53:47 +02002970 return NULL;
2971}
Christopher Faulet1d17c102017-08-29 15:38:48 +02002972
William Dauchyf9af9d72019-11-17 15:47:16 +01002973/* set uid/gid depending on global settings */
2974static void set_identity(const char *program_name)
2975{
2976 if (global.gid) {
2977 if (getgroups(0, NULL) > 0 && setgroups(0, NULL) == -1)
2978 ha_warning("[%s.main()] Failed to drop supplementary groups. Using 'gid'/'group'"
2979 " without 'uid'/'user' is generally useless.\n", program_name);
2980
2981 if (setgid(global.gid) == -1) {
2982 ha_alert("[%s.main()] Cannot set gid %d.\n", program_name, global.gid);
2983 protocol_unbind_all();
2984 exit(1);
2985 }
2986 }
2987
2988 if (global.uid && setuid(global.uid) == -1) {
2989 ha_alert("[%s.main()] Cannot set uid %d.\n", program_name, global.uid);
2990 protocol_unbind_all();
2991 exit(1);
2992 }
2993}
2994
Willy Tarreaubaaee002006-06-26 02:48:02 +02002995int main(int argc, char **argv)
2996{
2997 int err, retry;
2998 struct rlimit limit;
Willy Tarreau269ab312012-09-05 08:02:48 +02002999 int pidfd = -1;
Willy Tarreau1335da32021-07-14 17:54:01 +02003000 int intovf = (unsigned char)argc + 1; /* let the compiler know it's strictly positive */
3001
3002 /* Catch forced CFLAGS that miss 2-complement integer overflow */
3003 if (intovf + 0x7FFFFFFF >= intovf) {
3004 fprintf(stderr,
3005 "FATAL ERROR: invalid code detected -- cannot go further, please recompile!\n"
3006 "The source code was miscompiled by the compiler, which usually indicates that\n"
3007 "some of the CFLAGS needed to work around overzealous compiler optimizations\n"
3008 "were overwritten at build time. Please do not force CFLAGS, and read Makefile\n"
3009 "and INSTALL files to decide on the best way to pass your local build options.\n"
3010 "\nBuild options :"
3011#ifdef BUILD_TARGET
3012 "\n TARGET = " BUILD_TARGET
3013#endif
3014#ifdef BUILD_CPU
3015 "\n CPU = " BUILD_CPU
3016#endif
3017#ifdef BUILD_CC
3018 "\n CC = " BUILD_CC
3019#endif
3020#ifdef BUILD_CFLAGS
3021 "\n CFLAGS = " BUILD_CFLAGS
3022#endif
3023#ifdef BUILD_OPTIONS
3024 "\n OPTIONS = " BUILD_OPTIONS
3025#endif
3026#ifdef BUILD_DEBUG
3027 "\n DEBUG = " BUILD_DEBUG
3028#endif
3029 "\n\n");
3030 return 1;
3031 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003032
Olivier Houchard5fa300d2018-02-03 15:15:21 +01003033 setvbuf(stdout, NULL, _IONBF, 0);
Willy Tarreau5794fb02018-11-25 18:43:29 +01003034
Willy Tarreaubf696402019-03-01 10:09:28 +01003035 /* take a copy of initial limits before we possibly change them */
3036 getrlimit(RLIMIT_NOFILE, &limit);
Willy Tarreau2bd0f812020-10-13 15:36:08 +02003037
3038 if (limit.rlim_max == RLIM_INFINITY)
3039 limit.rlim_max = limit.rlim_cur;
Willy Tarreaubf696402019-03-01 10:09:28 +01003040 rlim_fd_cur_at_boot = limit.rlim_cur;
3041 rlim_fd_max_at_boot = limit.rlim_max;
3042
Willy Tarreau5794fb02018-11-25 18:43:29 +01003043 /* process all initcalls in order of potential dependency */
3044 RUN_INITCALLS(STG_PREPARE);
3045 RUN_INITCALLS(STG_LOCK);
Willy Tarreau3ebe4d92022-02-18 14:51:49 +01003046 RUN_INITCALLS(STG_REGISTER);
Willy Tarreau34527d52022-02-17 17:45:58 +01003047
3048 /* now's time to initialize early boot variables */
3049 init_early(argc, argv);
3050
Willy Tarreau18f96d02022-02-23 17:25:00 +01003051 /* handles argument parsing */
3052 init_args(argc, argv);
3053
Willy Tarreau5794fb02018-11-25 18:43:29 +01003054 RUN_INITCALLS(STG_ALLOC);
3055 RUN_INITCALLS(STG_POOL);
Willy Tarreau5794fb02018-11-25 18:43:29 +01003056 RUN_INITCALLS(STG_INIT);
3057
Willy Tarreau34527d52022-02-17 17:45:58 +01003058 /* this is the late init where the config is parsed */
Emeric Bruncf20bf12010-10-22 16:06:11 +02003059 init(argc, argv);
Willy Tarreau34527d52022-02-17 17:45:58 +01003060
Willy Tarreau24f4efa2010-08-27 17:56:48 +02003061 signal_register_fct(SIGQUIT, dump, SIGQUIT);
3062 signal_register_fct(SIGUSR1, sig_soft_stop, SIGUSR1);
3063 signal_register_fct(SIGHUP, sig_dump_state, SIGHUP);
William Lallemand73b85e72017-06-01 17:38:51 +02003064 signal_register_fct(SIGUSR2, NULL, 0);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003065
Willy Tarreaue437c442010-03-17 18:02:46 +01003066 /* Always catch SIGPIPE even on platforms which define MSG_NOSIGNAL.
3067 * Some recent FreeBSD setups report broken pipes, and MSG_NOSIGNAL
3068 * was defined there, so let's stay on the safe side.
Willy Tarreaubaaee002006-06-26 02:48:02 +02003069 */
Willy Tarreau24f4efa2010-08-27 17:56:48 +02003070 signal_register_fct(SIGPIPE, NULL, 0);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003071
Willy Tarreaudc23a922011-02-16 11:10:36 +01003072 /* ulimits */
3073 if (!global.rlimit_nofile)
3074 global.rlimit_nofile = global.maxsock;
3075
3076 if (global.rlimit_nofile) {
Willy Tarreaue5cfdac2019-03-01 10:32:05 +01003077 limit.rlim_cur = global.rlimit_nofile;
3078 limit.rlim_max = MAX(rlim_fd_max_at_boot, limit.rlim_cur);
3079
Willy Tarreau2df1fbf2022-04-25 18:02:03 +02003080 if ((global.fd_hard_limit && limit.rlim_cur > global.fd_hard_limit) ||
3081 setrlimit(RLIMIT_NOFILE, &limit) == -1) {
Willy Tarreauef635472016-06-21 11:48:18 +02003082 getrlimit(RLIMIT_NOFILE, &limit);
Willy Tarreau2df1fbf2022-04-25 18:02:03 +02003083 if (global.fd_hard_limit && limit.rlim_cur > global.fd_hard_limit)
3084 limit.rlim_cur = global.fd_hard_limit;
3085
William Dauchy0fec3ab2019-10-27 20:08:11 +01003086 if (global.tune.options & GTUNE_STRICT_LIMITS) {
3087 ha_alert("[%s.main()] Cannot raise FD limit to %d, limit is %d.\n",
3088 argv[0], global.rlimit_nofile, (int)limit.rlim_cur);
Jerome Magnin50f757c2021-01-12 20:19:38 +01003089 exit(1);
William Dauchy0fec3ab2019-10-27 20:08:11 +01003090 }
3091 else {
3092 /* try to set it to the max possible at least */
3093 limit.rlim_cur = limit.rlim_max;
Willy Tarreau2df1fbf2022-04-25 18:02:03 +02003094 if (global.fd_hard_limit && limit.rlim_cur > global.fd_hard_limit)
3095 limit.rlim_cur = global.fd_hard_limit;
3096
William Dauchy0fec3ab2019-10-27 20:08:11 +01003097 if (setrlimit(RLIMIT_NOFILE, &limit) != -1)
3098 getrlimit(RLIMIT_NOFILE, &limit);
Willy Tarreau164dd0b2016-06-21 11:51:59 +02003099
William Dauchya5194602020-03-28 19:29:58 +01003100 ha_warning("[%s.main()] Cannot raise FD limit to %d, limit is %d.\n",
William Dauchy0fec3ab2019-10-27 20:08:11 +01003101 argv[0], global.rlimit_nofile, (int)limit.rlim_cur);
3102 global.rlimit_nofile = limit.rlim_cur;
3103 }
Willy Tarreaudc23a922011-02-16 11:10:36 +01003104 }
3105 }
3106
3107 if (global.rlimit_memmax) {
3108 limit.rlim_cur = limit.rlim_max =
Willy Tarreau70060452015-12-14 12:46:07 +01003109 global.rlimit_memmax * 1048576ULL;
Willy Tarreaudc23a922011-02-16 11:10:36 +01003110#ifdef RLIMIT_AS
3111 if (setrlimit(RLIMIT_AS, &limit) == -1) {
William Dauchy0fec3ab2019-10-27 20:08:11 +01003112 if (global.tune.options & GTUNE_STRICT_LIMITS) {
3113 ha_alert("[%s.main()] Cannot fix MEM limit to %d megs.\n",
3114 argv[0], global.rlimit_memmax);
Jerome Magnin50f757c2021-01-12 20:19:38 +01003115 exit(1);
William Dauchy0fec3ab2019-10-27 20:08:11 +01003116 }
3117 else
William Dauchya5194602020-03-28 19:29:58 +01003118 ha_warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
William Dauchy0fec3ab2019-10-27 20:08:11 +01003119 argv[0], global.rlimit_memmax);
Willy Tarreaudc23a922011-02-16 11:10:36 +01003120 }
3121#else
3122 if (setrlimit(RLIMIT_DATA, &limit) == -1) {
William Dauchy0fec3ab2019-10-27 20:08:11 +01003123 if (global.tune.options & GTUNE_STRICT_LIMITS) {
3124 ha_alert("[%s.main()] Cannot fix MEM limit to %d megs.\n",
3125 argv[0], global.rlimit_memmax);
Jerome Magnin50f757c2021-01-12 20:19:38 +01003126 exit(1);
William Dauchy0fec3ab2019-10-27 20:08:11 +01003127 }
3128 else
William Dauchya5194602020-03-28 19:29:58 +01003129 ha_warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
William Dauchy0fec3ab2019-10-27 20:08:11 +01003130 argv[0], global.rlimit_memmax);
Willy Tarreaudc23a922011-02-16 11:10:36 +01003131 }
3132#endif
3133 }
3134
William Lallemandf82afbb2022-01-07 18:19:42 +01003135 /* Try to get the listeners FD from the previous process using
3136 * _getsocks on the stat socket, it must never been done in wait mode
3137 * and check mode
3138 */
3139 if (old_unixsocket &&
3140 !(global.mode & (MODE_MWORKER_WAIT|MODE_CHECK|MODE_CHECK_CONDITION))) {
William Lallemand85b0bd92017-06-01 17:38:53 +02003141 if (strcmp("/dev/null", old_unixsocket) != 0) {
Willy Tarreau42961742020-08-28 18:42:45 +02003142 if (sock_get_old_sockets(old_unixsocket) != 0) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01003143 ha_alert("Failed to get the sockets from the old process!\n");
William Lallemand85b0bd92017-06-01 17:38:53 +02003144 if (!(global.mode & MODE_MWORKER))
3145 exit(1);
3146 }
Olivier Houchardf73629d2017-04-05 22:33:04 +02003147 }
3148 }
William Lallemand85b0bd92017-06-01 17:38:53 +02003149
Willy Tarreaubaaee002006-06-26 02:48:02 +02003150 /* We will loop at most 100 times with 10 ms delay each time.
3151 * That's at most 1 second. We only send a signal to old pids
3152 * if we cannot grab at least one port.
3153 */
3154 retry = MAX_START_RETRIES;
3155 err = ERR_NONE;
3156 while (retry >= 0) {
3157 struct timeval w;
Willy Tarreaue91bff22020-09-02 11:11:43 +02003158 err = protocol_bind_all(retry == 0 || nb_oldpids == 0);
Willy Tarreaue13e9252007-12-20 23:05:50 +01003159 /* exit the loop on no error or fatal error */
3160 if ((err & (ERR_RETRYABLE|ERR_FATAL)) != ERR_RETRYABLE)
Willy Tarreaubaaee002006-06-26 02:48:02 +02003161 break;
Willy Tarreaubb545b42010-08-25 12:58:59 +02003162 if (nb_oldpids == 0 || retry == 0)
Willy Tarreaubaaee002006-06-26 02:48:02 +02003163 break;
3164
3165 /* FIXME-20060514: Solaris and OpenBSD do not support shutdown() on
3166 * listening sockets. So on those platforms, it would be wiser to
3167 * simply send SIGUSR1, which will not be undoable.
3168 */
Willy Tarreaubb545b42010-08-25 12:58:59 +02003169 if (tell_old_pids(SIGTTOU) == 0) {
3170 /* no need to wait if we can't contact old pids */
3171 retry = 0;
3172 continue;
3173 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003174 /* give some time to old processes to stop listening */
3175 w.tv_sec = 0;
3176 w.tv_usec = 10*1000;
3177 select(0, NULL, NULL, NULL, &w);
3178 retry--;
3179 }
3180
Willy Tarreaue91bff22020-09-02 11:11:43 +02003181 /* Note: protocol_bind_all() sends an alert when it fails. */
Willy Tarreau0a3b9d92009-02-04 17:05:23 +01003182 if ((err & ~ERR_WARN) != ERR_NONE) {
Willy Tarreaue91bff22020-09-02 11:11:43 +02003183 ha_alert("[%s.main()] Some protocols failed to start their listeners! Exiting.\n", argv[0]);
Willy Tarreauf68da462009-06-09 14:36:00 +02003184 if (retry != MAX_START_RETRIES && nb_oldpids) {
3185 protocol_unbind_all(); /* cleanup everything we can */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003186 tell_old_pids(SIGTTIN);
Willy Tarreauf68da462009-06-09 14:36:00 +02003187 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003188 exit(1);
3189 }
3190
William Lallemand944e6192018-11-21 15:48:31 +01003191 if (!(global.mode & MODE_MWORKER_WAIT) && listeners == 0) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01003192 ha_alert("[%s.main()] No enabled listener found (check for 'bind' directives) ! Exiting.\n", argv[0]);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003193 /* Note: we don't have to send anything to the old pids because we
3194 * never stopped them. */
3195 exit(1);
3196 }
3197
Willy Tarreaue91bff22020-09-02 11:11:43 +02003198 /* Ok, all listeners should now be bound, close any leftover sockets
Olivier Houchardf73629d2017-04-05 22:33:04 +02003199 * the previous process gave us, we don't need them anymore
3200 */
Willy Tarreaub5101162022-01-28 18:28:18 +01003201 sock_drop_unused_old_sockets();
Willy Tarreaudd815982007-10-16 12:25:14 +02003202
Willy Tarreaubaaee002006-06-26 02:48:02 +02003203 /* prepare pause/play signals */
Willy Tarreau24f4efa2010-08-27 17:56:48 +02003204 signal_register_fct(SIGTTOU, sig_pause, SIGTTOU);
3205 signal_register_fct(SIGTTIN, sig_listen, SIGTTIN);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003206
Willy Tarreaubaaee002006-06-26 02:48:02 +02003207 /* MODE_QUIET can inhibit alerts and warnings below this line */
3208
PiBa-NL149a81a2017-12-25 21:03:31 +01003209 if (getenv("HAPROXY_MWORKER_REEXEC") != NULL) {
3210 /* either stdin/out/err are already closed or should stay as they are. */
3211 if ((global.mode & MODE_DAEMON)) {
3212 /* daemon mode re-executing, stdin/stdout/stderr are already closed so keep quiet */
3213 global.mode &= ~MODE_VERBOSE;
3214 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
3215 }
3216 } else {
3217 if ((global.mode & MODE_QUIET) && !(global.mode & MODE_VERBOSE)) {
3218 /* detach from the tty */
William Lallemande1340412017-12-28 16:09:36 +01003219 stdio_quiet(-1);
PiBa-NL149a81a2017-12-25 21:03:31 +01003220 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003221 }
3222
3223 /* open log & pid files before the chroot */
William Lallemand7b820a62022-02-14 09:02:14 +01003224 if ((global.mode & MODE_DAEMON || global.mode & MODE_MWORKER) &&
3225 !(global.mode & MODE_MWORKER_WAIT) && global.pidfile != NULL) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003226 unlink(global.pidfile);
3227 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
3228 if (pidfd < 0) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01003229 ha_alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003230 if (nb_oldpids)
3231 tell_old_pids(SIGTTIN);
Willy Tarreaudd815982007-10-16 12:25:14 +02003232 protocol_unbind_all();
Willy Tarreaubaaee002006-06-26 02:48:02 +02003233 exit(1);
3234 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003235 }
3236
Willy Tarreaub38651a2007-03-24 17:24:39 +01003237 if ((global.last_checks & LSTCHK_NETADM) && global.uid) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01003238 ha_alert("[%s.main()] Some configuration options require full privileges, so global.uid cannot be changed.\n"
3239 "", argv[0]);
Willy Tarreaudd815982007-10-16 12:25:14 +02003240 protocol_unbind_all();
Willy Tarreaub38651a2007-03-24 17:24:39 +01003241 exit(1);
3242 }
3243
Jackie Tapia749f74c2020-07-22 18:59:40 -05003244 /* If the user is not root, we'll still let them try the configuration
3245 * but we inform them that unexpected behaviour may occur.
Willy Tarreau4e30ed72009-02-04 18:02:48 +01003246 */
3247 if ((global.last_checks & LSTCHK_NETADM) && getuid())
Christopher Faulet767a84b2017-11-24 16:50:31 +01003248 ha_warning("[%s.main()] Some options which require full privileges"
3249 " might not work well.\n"
3250 "", argv[0]);
Willy Tarreau4e30ed72009-02-04 18:02:48 +01003251
William Lallemand095ba4c2017-06-01 17:38:50 +02003252 if ((global.mode & (MODE_MWORKER|MODE_DAEMON)) == 0) {
3253
3254 /* chroot if needed */
3255 if (global.chroot != NULL) {
3256 if (chroot(global.chroot) == -1 || chdir("/") == -1) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01003257 ha_alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
William Lallemand095ba4c2017-06-01 17:38:50 +02003258 if (nb_oldpids)
3259 tell_old_pids(SIGTTIN);
3260 protocol_unbind_all();
3261 exit(1);
3262 }
Willy Tarreauf223cc02007-10-15 18:57:08 +02003263 }
Willy Tarreauf223cc02007-10-15 18:57:08 +02003264 }
3265
William Lallemand944e6192018-11-21 15:48:31 +01003266 if (nb_oldpids && !(global.mode & MODE_MWORKER_WAIT))
Willy Tarreaubb545b42010-08-25 12:58:59 +02003267 nb_oldpids = tell_old_pids(oldpids_sig);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003268
William Lallemand27edc4b2019-05-07 17:49:33 +02003269 /* send a SIGTERM to workers who have a too high reloads number */
3270 if ((global.mode & MODE_MWORKER) && !(global.mode & MODE_MWORKER_WAIT))
3271 mworker_kill_max_reloads(SIGTERM);
3272
Willy Tarreaubaaee002006-06-26 02:48:02 +02003273 /* Note that any error at this stage will be fatal because we will not
3274 * be able to restart the old pids.
3275 */
3276
William Dauchyf9af9d72019-11-17 15:47:16 +01003277 if ((global.mode & (MODE_MWORKER | MODE_DAEMON)) == 0)
3278 set_identity(argv[0]);
Willy Tarreau636848a2019-04-15 19:38:50 +02003279
Willy Tarreaubaaee002006-06-26 02:48:02 +02003280 /* check ulimits */
3281 limit.rlim_cur = limit.rlim_max = 0;
3282 getrlimit(RLIMIT_NOFILE, &limit);
3283 if (limit.rlim_cur < global.maxsock) {
William Dauchy0fec3ab2019-10-27 20:08:11 +01003284 if (global.tune.options & GTUNE_STRICT_LIMITS) {
3285 ha_alert("[%s.main()] FD limit (%d) too low for maxconn=%d/maxsock=%d. "
3286 "Please raise 'ulimit-n' to %d or more to avoid any trouble.\n",
3287 argv[0], (int)limit.rlim_cur, global.maxconn, global.maxsock,
3288 global.maxsock);
Jerome Magnin50f757c2021-01-12 20:19:38 +01003289 exit(1);
William Dauchy0fec3ab2019-10-27 20:08:11 +01003290 }
3291 else
3292 ha_alert("[%s.main()] FD limit (%d) too low for maxconn=%d/maxsock=%d. "
William Dauchya5194602020-03-28 19:29:58 +01003293 "Please raise 'ulimit-n' to %d or more to avoid any trouble.\n",
William Dauchy0fec3ab2019-10-27 20:08:11 +01003294 argv[0], (int)limit.rlim_cur, global.maxconn, global.maxsock,
3295 global.maxsock);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003296 }
3297
William Lallemand944e6192018-11-21 15:48:31 +01003298 if (global.mode & (MODE_DAEMON | MODE_MWORKER | MODE_MWORKER_WAIT)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003299 int ret = 0;
Willy Tarreaud67ff342021-06-15 07:58:09 +02003300 int in_parent = 0;
William Lallemande1340412017-12-28 16:09:36 +01003301 int devnullfd = -1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003302
William Lallemand095ba4c2017-06-01 17:38:50 +02003303 /*
3304 * if daemon + mworker: must fork here to let a master
3305 * process live in background before forking children
3306 */
William Lallemand73b85e72017-06-01 17:38:51 +02003307
3308 if ((getenv("HAPROXY_MWORKER_REEXEC") == NULL)
3309 && (global.mode & MODE_MWORKER)
3310 && (global.mode & MODE_DAEMON)) {
William Lallemand095ba4c2017-06-01 17:38:50 +02003311 ret = fork();
3312 if (ret < 0) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01003313 ha_alert("[%s.main()] Cannot fork.\n", argv[0]);
William Lallemand095ba4c2017-06-01 17:38:50 +02003314 protocol_unbind_all();
3315 exit(1); /* there has been an error */
William Lallemandbfd8eb52018-07-04 15:31:23 +02003316 } else if (ret > 0) { /* parent leave to daemonize */
William Lallemand095ba4c2017-06-01 17:38:50 +02003317 exit(0);
William Lallemandbfd8eb52018-07-04 15:31:23 +02003318 } else /* change the process group ID in the child (master process) */
3319 setsid();
William Lallemand095ba4c2017-06-01 17:38:50 +02003320 }
William Lallemande20b6a62017-06-01 17:38:55 +02003321
William Lallemande20b6a62017-06-01 17:38:55 +02003322
William Lallemanddeed7802017-11-06 11:00:04 +01003323 /* if in master-worker mode, write the PID of the father */
3324 if (global.mode & MODE_MWORKER) {
3325 char pidstr[100];
Willy Tarreau76a80c72019-06-22 07:41:38 +02003326 snprintf(pidstr, sizeof(pidstr), "%d\n", (int)getpid());
Willy Tarreau46ec48b2018-01-23 19:20:19 +01003327 if (pidfd >= 0)
Willy Tarreau2e8ab6b2020-03-14 11:03:20 +01003328 DISGUISE(write(pidfd, pidstr, strlen(pidstr)));
William Lallemanddeed7802017-11-06 11:00:04 +01003329 }
3330
Willy Tarreaubaaee002006-06-26 02:48:02 +02003331 /* the father launches the required number of processes */
William Lallemand944e6192018-11-21 15:48:31 +01003332 if (!(global.mode & MODE_MWORKER_WAIT)) {
William Lallemand9a1ee7a2019-04-01 11:30:02 +02003333 if (global.mode & MODE_MWORKER)
3334 mworker_ext_launch_all();
Willy Tarreaud67ff342021-06-15 07:58:09 +02003335
3336 ret = fork();
3337 if (ret < 0) {
3338 ha_alert("[%s.main()] Cannot fork.\n", argv[0]);
3339 protocol_unbind_all();
3340 exit(1); /* there has been an error */
3341 }
3342 else if (ret == 0) { /* child breaks here */
Willy Tarreau3c032f22021-07-21 10:17:02 +02003343 /* This one must not be exported, it's internal! */
3344 unsetenv("HAPROXY_MWORKER_REEXEC");
Willy Tarreaue8422bf2021-06-15 09:08:18 +02003345 ha_random_jump96(1);
Willy Tarreaud67ff342021-06-15 07:58:09 +02003346 }
3347 else { /* parent here */
3348 in_parent = 1;
3349
William Lallemand944e6192018-11-21 15:48:31 +01003350 if (pidfd >= 0 && !(global.mode & MODE_MWORKER)) {
3351 char pidstr[100];
3352 snprintf(pidstr, sizeof(pidstr), "%d\n", ret);
Willy Tarreau2e8ab6b2020-03-14 11:03:20 +01003353 DISGUISE(write(pidfd, pidstr, strlen(pidstr)));
William Lallemand944e6192018-11-21 15:48:31 +01003354 }
3355 if (global.mode & MODE_MWORKER) {
3356 struct mworker_proc *child;
William Lallemandce83b4a2018-10-26 14:47:30 +02003357
William Lallemand5d71a6b2021-11-09 15:25:31 +01003358 ha_notice("New worker (%d) forked\n", ret);
William Lallemand944e6192018-11-21 15:48:31 +01003359 /* find the right mworker_proc */
3360 list_for_each_entry(child, &proc_list, list) {
Willy Tarreaue8422bf2021-06-15 09:08:18 +02003361 if (child->reloads == 0 && child->options & PROC_O_TYPE_WORKER) {
William Lallemand944e6192018-11-21 15:48:31 +01003362 child->timestamp = now.tv_sec;
3363 child->pid = ret;
William Lallemand1dc69632019-06-12 19:11:33 +02003364 child->version = strdup(haproxy_version);
William Lallemand944e6192018-11-21 15:48:31 +01003365 break;
3366 }
William Lallemandce83b4a2018-10-26 14:47:30 +02003367 }
3368 }
William Lallemand944e6192018-11-21 15:48:31 +01003369 }
Willy Tarreaud67ff342021-06-15 07:58:09 +02003370
William Lallemand944e6192018-11-21 15:48:31 +01003371 } else {
3372 /* wait mode */
Willy Tarreaud67ff342021-06-15 07:58:09 +02003373 in_parent = 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003374 }
Willy Tarreaufc6c0322012-11-16 16:12:27 +01003375
3376#ifdef USE_CPU_AFFINITY
Willy Tarreau44ea6312021-06-15 08:57:56 +02003377 if (!in_parent && ha_cpuset_count(&cpu_map.proc)) { /* only do this if the process has a CPU map */
Olivier Houchard97148f62017-08-16 17:29:11 +02003378
David CARLIERdf91cbd2022-01-06 18:53:50 +00003379#if defined(CPUSET_USE_CPUSET) || defined(__DragonFly__)
David CARLIERbb10dad2022-01-08 09:59:38 +00003380 struct hap_cpuset *set = &cpu_map.proc;
Amaury Denoyelle982fb532021-04-21 18:39:58 +02003381 sched_setaffinity(0, sizeof(set->cpuset), &set->cpuset);
David CARLIERdf91cbd2022-01-06 18:53:50 +00003382#elif defined(__FreeBSD__)
David CARLIERbb10dad2022-01-08 09:59:38 +00003383 struct hap_cpuset *set = &cpu_map.proc;
David CARLIERdf91cbd2022-01-06 18:53:50 +00003384 ret = cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1, sizeof(set->cpuset), &set->cpuset);
Willy Tarreaufc6c0322012-11-16 16:12:27 +01003385#endif
Amaury Denoyelle982fb532021-04-21 18:39:58 +02003386 }
Pieter Baauwcaa6a1b2015-09-17 21:26:40 +02003387#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +02003388 /* close the pidfile both in children and father */
Willy Tarreau269ab312012-09-05 08:02:48 +02003389 if (pidfd >= 0) {
3390 //lseek(pidfd, 0, SEEK_SET); /* debug: emulate eglibc bug */
3391 close(pidfd);
3392 }
Willy Tarreaud137dd32010-08-25 12:49:05 +02003393
3394 /* We won't ever use this anymore */
Willy Tarreau61cfdf42021-02-20 10:46:51 +01003395 ha_free(&global.pidfile);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003396
Willy Tarreaud67ff342021-06-15 07:58:09 +02003397 if (in_parent) {
William Lallemand944e6192018-11-21 15:48:31 +01003398 if (global.mode & (MODE_MWORKER|MODE_MWORKER_WAIT)) {
William Lallemandfab0fdc2021-11-09 18:01:22 +01003399 master = 1;
PiBa-NLbaf6ea42017-11-28 23:26:08 +01003400
3401 if ((!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) &&
3402 (global.mode & MODE_DAEMON)) {
3403 /* detach from the tty, this is required to properly daemonize. */
William Lallemande1340412017-12-28 16:09:36 +01003404 if ((getenv("HAPROXY_MWORKER_REEXEC") == NULL))
3405 stdio_quiet(-1);
3406
PiBa-NLbaf6ea42017-11-28 23:26:08 +01003407 global.mode &= ~MODE_VERBOSE;
3408 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
PiBa-NLbaf6ea42017-11-28 23:26:08 +01003409 }
3410
William Lallemandfab0fdc2021-11-09 18:01:22 +01003411 if (global.mode & MODE_MWORKER_WAIT) {
3412 /* only the wait mode handles the master CLI */
3413 mworker_loop();
3414 } else {
3415
3416 /* if not in wait mode, reload in wait mode to free the memory */
William Lallemand836bda22021-11-09 18:16:47 +01003417 ha_notice("Loading success.\n");
William Lallemand68836742021-11-10 10:49:06 +01003418 proc_self->failedreloads = 0; /* reset the number of failure */
William Lallemandfab0fdc2021-11-09 18:01:22 +01003419 mworker_reexec_waitmode();
3420 }
William Lallemand1499b9b2017-06-07 15:04:47 +02003421 /* should never get there */
3422 exit(EXIT_FAILURE);
Willy Tarreauedaff0a2015-05-01 17:01:08 +02003423 }
William Lallemandcf4e4962017-06-08 19:05:48 +02003424#if defined(USE_OPENSSL) && !defined(OPENSSL_NO_DH)
Grant Zhang872f9c22017-01-21 01:10:18 +00003425 ssl_free_dh();
3426#endif
William Lallemand1499b9b2017-06-07 15:04:47 +02003427 exit(0); /* parent must leave */
Willy Tarreauedaff0a2015-05-01 17:01:08 +02003428 }
3429
William Lallemandcb11fd22017-06-01 17:38:52 +02003430 /* child must never use the atexit function */
3431 atexit_flag = 0;
3432
William Lallemandbc193052018-09-11 10:06:26 +02003433 /* close useless master sockets */
3434 if (global.mode & MODE_MWORKER) {
3435 struct mworker_proc *child, *it;
3436 master = 0;
3437
William Lallemand309dc9a2018-10-26 14:47:45 +02003438 mworker_cli_proxy_stop();
3439
William Lallemandbc193052018-09-11 10:06:26 +02003440 /* free proc struct of other processes */
3441 list_for_each_entry_safe(child, it, &proc_list, list) {
William Lallemandce83b4a2018-10-26 14:47:30 +02003442 /* close the FD of the master side for all
3443 * workers, we don't need to close the worker
3444 * side of other workers since it's done with
3445 * the bind_proc */
William Lallemand7e018782022-01-28 21:56:24 +01003446 if (child->ipc_fd[0] >= 0) {
Tim Duesterhus742e0f92018-11-25 20:03:39 +01003447 close(child->ipc_fd[0]);
William Lallemand7e018782022-01-28 21:56:24 +01003448 child->ipc_fd[0] = -1;
3449 }
Willy Tarreaue8422bf2021-06-15 09:08:18 +02003450 if (child->options & PROC_O_TYPE_WORKER &&
William Lallemandce83b4a2018-10-26 14:47:30 +02003451 child->reloads == 0) {
3452 /* keep this struct if this is our pid */
3453 proc_self = child;
William Lallemandbc193052018-09-11 10:06:26 +02003454 continue;
William Lallemandce83b4a2018-10-26 14:47:30 +02003455 }
Willy Tarreau2b718102021-04-21 07:32:39 +02003456 LIST_DELETE(&child->list);
Tim Duesterhus9b7a9762019-05-16 20:23:22 +02003457 mworker_free_child(child);
3458 child = NULL;
William Lallemandbc193052018-09-11 10:06:26 +02003459 }
3460 }
Willy Tarreau1605c7a2018-01-23 19:01:49 +01003461
William Lallemande1340412017-12-28 16:09:36 +01003462 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
3463 devnullfd = open("/dev/null", O_RDWR, 0);
3464 if (devnullfd < 0) {
3465 ha_alert("Cannot open /dev/null\n");
3466 exit(EXIT_FAILURE);
3467 }
3468 }
3469
William Lallemand095ba4c2017-06-01 17:38:50 +02003470 /* Must chroot and setgid/setuid in the children */
3471 /* chroot if needed */
3472 if (global.chroot != NULL) {
3473 if (chroot(global.chroot) == -1 || chdir("/") == -1) {
Willy Tarreaue34cf282021-06-15 08:59:19 +02003474 ha_alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
William Lallemand095ba4c2017-06-01 17:38:50 +02003475 if (nb_oldpids)
3476 tell_old_pids(SIGTTIN);
3477 protocol_unbind_all();
3478 exit(1);
3479 }
3480 }
3481
Willy Tarreau61cfdf42021-02-20 10:46:51 +01003482 ha_free(&global.chroot);
William Dauchyf9af9d72019-11-17 15:47:16 +01003483 set_identity(argv[0]);
William Lallemand095ba4c2017-06-01 17:38:50 +02003484
William Lallemand7f80eb22017-05-26 18:19:55 +02003485 /* pass through every cli socket, and check if it's bound to
3486 * the current process and if it exposes listeners sockets.
3487 * Caution: the GTUNE_SOCKET_TRANSFER is now set after the fork.
3488 * */
3489
Willy Tarreau4975d142021-03-13 11:00:33 +01003490 if (global.cli_fe) {
William Lallemand7f80eb22017-05-26 18:19:55 +02003491 struct bind_conf *bind_conf;
3492
Willy Tarreau4975d142021-03-13 11:00:33 +01003493 list_for_each_entry(bind_conf, &global.cli_fe->conf.bind, by_fe) {
William Lallemand7f80eb22017-05-26 18:19:55 +02003494 if (bind_conf->level & ACCESS_FD_LISTENERS) {
Willy Tarreau72faef32021-06-15 08:36:30 +02003495 global.tune.options |= GTUNE_SOCKET_TRANSFER;
3496 break;
William Lallemand7f80eb22017-05-26 18:19:55 +02003497 }
3498 }
Willy Tarreauf83d3fe2015-05-01 19:13:41 +02003499 }
3500
William Lallemand2e8fad92018-11-13 16:18:23 +01003501 /*
3502 * This is only done in daemon mode because we might want the
3503 * logs on stdout in mworker mode. If we're NOT in QUIET mode,
3504 * we should now close the 3 first FDs to ensure that we can
3505 * detach from the TTY. We MUST NOT do it in other cases since
3506 * it would have already be done, and 0-2 would have been
3507 * affected to listening sockets
Willy Tarreaubaaee002006-06-26 02:48:02 +02003508 */
William Lallemand2e8fad92018-11-13 16:18:23 +01003509 if ((global.mode & MODE_DAEMON) &&
3510 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003511 /* detach from the tty */
William Lallemande1340412017-12-28 16:09:36 +01003512 stdio_quiet(devnullfd);
Willy Tarreau106cb762008-11-16 07:40:34 +01003513 global.mode &= ~MODE_VERBOSE;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003514 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
3515 }
3516 pid = getpid(); /* update child's pid */
William Lallemandbfd8eb52018-07-04 15:31:23 +02003517 if (!(global.mode & MODE_MWORKER)) /* in mworker mode we don't want a new pgid for the children */
3518 setsid();
Willy Tarreau2ff76222007-04-09 19:29:56 +02003519 fork_poller();
Willy Tarreaubaaee002006-06-26 02:48:02 +02003520 }
3521
William Dauchye039f262019-11-17 15:47:15 +01003522 /* try our best to re-enable core dumps depending on system capabilities.
3523 * What is addressed here :
3524 * - remove file size limits
3525 * - remove core size limits
3526 * - mark the process dumpable again if it lost it due to user/group
3527 */
3528 if (global.tune.options & GTUNE_SET_DUMPABLE) {
3529 limit.rlim_cur = limit.rlim_max = RLIM_INFINITY;
3530
3531#if defined(RLIMIT_FSIZE)
3532 if (setrlimit(RLIMIT_FSIZE, &limit) == -1) {
3533 if (global.tune.options & GTUNE_STRICT_LIMITS) {
3534 ha_alert("[%s.main()] Failed to set the raise the maximum "
3535 "file size.\n", argv[0]);
Jerome Magnin50f757c2021-01-12 20:19:38 +01003536 exit(1);
William Dauchye039f262019-11-17 15:47:15 +01003537 }
3538 else
3539 ha_warning("[%s.main()] Failed to set the raise the maximum "
William Dauchya5194602020-03-28 19:29:58 +01003540 "file size.\n", argv[0]);
William Dauchye039f262019-11-17 15:47:15 +01003541 }
3542#endif
3543
3544#if defined(RLIMIT_CORE)
3545 if (setrlimit(RLIMIT_CORE, &limit) == -1) {
3546 if (global.tune.options & GTUNE_STRICT_LIMITS) {
3547 ha_alert("[%s.main()] Failed to set the raise the core "
3548 "dump size.\n", argv[0]);
Jerome Magnin50f757c2021-01-12 20:19:38 +01003549 exit(1);
William Dauchye039f262019-11-17 15:47:15 +01003550 }
3551 else
3552 ha_warning("[%s.main()] Failed to set the raise the core "
William Dauchya5194602020-03-28 19:29:58 +01003553 "dump size.\n", argv[0]);
William Dauchye039f262019-11-17 15:47:15 +01003554 }
3555#endif
3556
3557#if defined(USE_PRCTL)
3558 if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1)
3559 ha_warning("[%s.main()] Failed to set the dumpable flag, "
3560 "no core will be dumped.\n", argv[0]);
devnexen@gmail.com21185972021-08-21 09:13:10 +01003561#elif defined(USE_PROCCTL)
Willy Tarreau28345c62021-10-08 15:55:13 +02003562 {
3563 int traceable = PROC_TRACE_CTL_ENABLE;
3564 if (procctl(P_PID, getpid(), PROC_TRACE_CTL, &traceable) == -1)
3565 ha_warning("[%s.main()] Failed to set the traceable flag, "
3566 "no core will be dumped.\n", argv[0]);
3567 }
William Dauchye039f262019-11-17 15:47:15 +01003568#endif
3569 }
3570
Christopher Faulete3a5e352017-10-24 13:53:54 +02003571 global.mode &= ~MODE_STARTING;
Amaury Denoyelle6af81f82021-05-27 15:45:28 +02003572 reset_usermsgs_ctx();
3573
Willy Tarreau2d5d4e02021-09-28 10:36:57 +02003574 /* start threads 2 and above */
Willy Tarreaud10385a2021-10-06 22:22:40 +02003575 setup_extra_threads(&run_thread_poll_loop);
William Lallemand1aab50b2018-06-07 09:46:01 +02003576
Willy Tarreau2d5d4e02021-09-28 10:36:57 +02003577 /* when multithreading we need to let only the thread 0 handle the signals */
William Lallemandd3801c12018-09-11 10:06:23 +02003578 haproxy_unblock_signals();
Willy Tarreau2d5d4e02021-09-28 10:36:57 +02003579
3580 /* Finally, start the poll loop for the first thread */
Willy Tarreau43ab05b2021-09-28 09:43:11 +02003581 run_thread_poll_loop(&ha_thread_info[0]);
Willy Tarreau2d5d4e02021-09-28 10:36:57 +02003582
3583 /* wait for all threads to terminate */
3584 wait_for_threads_completion();
Christopher Faulet1d17c102017-08-29 15:38:48 +02003585
Tim Duesterhus0a3b43d2020-06-14 00:37:42 +02003586 deinit_and_exit(0);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003587}
3588
Willy Tarreaubaaee002006-06-26 02:48:02 +02003589/*
3590 * Local variables:
3591 * c-indent-level: 8
3592 * c-basic-offset: 8
3593 * End:
3594 */