blob: 5913cb1d509d909e14d3c93d9ecdb4837da7401d [file] [log] [blame]
William Lallemandeba6a542022-09-26 12:54:39 +02001#include <sys/mman.h>
2#include <sys/stat.h>
3#include <fcntl.h>
Amaury Denoyellece986e12021-06-04 11:20:32 +02004#include <stdarg.h>
5#include <stdio.h>
William Lallemandeba6a542022-09-26 12:54:39 +02006#include <stdlib.h>
Amaury Denoyellece986e12021-06-04 11:20:32 +02007#include <syslog.h>
8
9#include <haproxy/api.h>
10#include <haproxy/applet-t.h>
Amaury Denoyelle1833e432021-05-26 11:05:22 +020011#include <haproxy/buf.h>
Amaury Denoyellece986e12021-06-04 11:20:32 +020012#include <haproxy/cli.h>
13#include <haproxy/errors.h>
14#include <haproxy/global.h>
Amaury Denoyelle816281f2021-05-27 15:46:19 +020015#include <haproxy/obj_type.h>
Amaury Denoyellece986e12021-06-04 11:20:32 +020016#include <haproxy/ring.h>
17#include <haproxy/tools.h>
18#include <haproxy/version.h>
19
20/* A global buffer used to store all startup alerts/warnings. It will then be
21 * retrieve on the CLI. */
William Lallemandeba6a542022-09-26 12:54:39 +020022struct ring *startup_logs = NULL;
Willy Tarreau3c4a2972023-05-11 12:02:21 +020023uint tot_warnings = 0;
William Lallemandeba6a542022-09-26 12:54:39 +020024#ifdef USE_SHM_OPEN
25static struct ring *shm_startup_logs = NULL;
26#endif
Amaury Denoyellece986e12021-06-04 11:20:32 +020027
Amaury Denoyelle1833e432021-05-26 11:05:22 +020028/* A thread local buffer used to store all alerts/warnings. It can be used to
29 * retrieve them for CLI commands after startup.
30 */
31#define USER_MESSAGES_BUFSIZE 1024
32static THREAD_LOCAL struct buffer usermsgs_buf = BUF_NULL;
33
Amaury Denoyelle6af81f82021-05-27 15:45:28 +020034/* A thread local context used for stderr output via ha_alert/warning/notice/diag.
35 */
Amaury Denoyelle846830e2021-06-07 19:24:10 +020036#define USERMSGS_CTX_BUFSIZE PATH_MAX
37static THREAD_LOCAL struct usermsgs_ctx usermsgs_ctx = { .str = BUF_NULL, };
Amaury Denoyelle6af81f82021-05-27 15:45:28 +020038
William Lallemandeba6a542022-09-26 12:54:39 +020039#ifdef USE_SHM_OPEN
40
41/* initialise an SHM for the startup logs and return its fd */
42static int startup_logs_new_shm()
43{
44 char *path = NULL;
45 int fd = -1;
46 int flags;
47
48 /* create a unique path per PID so we don't collide with another
49 process */
50 memprintf(&path, "/haproxy_startup_logs_%d", getpid());
51 fd = shm_open(path, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
52 if (fd == -1)
53 goto error;
54 shm_unlink(path);
55 ha_free(&path);
56
57 if (ftruncate(fd, STARTUP_LOG_SIZE) == -1)
58 goto error;
59
60 flags = fcntl(fd, F_GETFD);
61 if (flags == -1)
62 goto error;
63 flags &= ~FD_CLOEXEC;
64 flags = fcntl(fd, F_SETFD, flags);
65 if (flags == -1)
66 goto error;
67
68 return fd;
69error:
70 if (fd != -1) {
71 close(fd);
72 fd = -1;
73 }
74 return fd;
75}
76
77/* mmap a startup-logs from a <fd>.
78 * if <new> is set to one, initialize the buffer.
79 * Returns the ring.
80 */
81static struct ring *startup_logs_from_fd(int fd, int new)
82{
83 char *area;
84 struct ring *r = NULL;
85
86 if (fd == -1)
87 goto error;
88
89 area = mmap(NULL, STARTUP_LOG_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
90 if (area == MAP_FAILED || area == NULL)
91 goto error;
92
93 if (new)
94 r = ring_make_from_area(area, STARTUP_LOG_SIZE);
95 else
96 r = ring_cast_from_area(area);
97
98 if (r == NULL)
99 goto error;
100
101 shm_startup_logs = r; /* save the ptr so we can unmap later */
102
103 return r;
104error:
105 return NULL;
106}
107
108/*
Ilya Shipitsin4a689da2022-10-29 09:34:32 +0500109 * Use a shm across reexec of the master.
William Lallemandeba6a542022-09-26 12:54:39 +0200110 *
111 * During the startup of the master, a shm_open must be done and the FD saved
112 * into the HAPROXY_STARTUPLOGS_FD environment variable.
113 *
114 * When forking workers, the child must use a copy of the shm, not the shm itself.
115 *
116 * Once in wait mode, the shm must be copied and closed.
117 *
118 */
119void startup_logs_init()
120{
121 struct ring *r = NULL;
122 char *str_fd, *endptr;
123 int fd = -1;
124
125 str_fd = getenv("HAPROXY_STARTUPLOGS_FD");
126 if (str_fd) {
127 fd = strtol(str_fd, &endptr, 10);
128 if (*endptr != '\0')
129 goto error;
130 unsetenv("HAPROXY_STARTUPLOGS_FD");
131 }
132
133 /* during startup, or just after a reload.
134 * Note: the WAIT_ONLY env variable must be
135 * check in case of an early call */
136 if (!(global.mode & MODE_MWORKER_WAIT) &&
137 getenv("HAPROXY_MWORKER_WAIT_ONLY") == NULL) {
138 if (fd != -1)
139 close(fd);
140
141 fd = startup_logs_new_shm();
142 if (fd == -1)
143 goto error;
144
145 r = startup_logs_from_fd(fd, 1);
146 if (!r)
147 goto error;
148
Aurelien DARRAGONb28ded12023-04-05 16:18:40 +0200149 str_fd = NULL;
William Lallemandeba6a542022-09-26 12:54:39 +0200150 memprintf(&str_fd, "%d", fd);
151 setenv("HAPROXY_STARTUPLOGS_FD", str_fd, 1);
152 ha_free(&str_fd);
153
154 } else {
155 /* in wait mode, copy the shm to an allocated buffer */
156 struct ring *prev = NULL;
157
158 if (fd == -1)
159 goto error;
160
161 prev = startup_logs_from_fd(fd, 0);
162 if (!prev)
163 goto error;
164
165 r = startup_logs_dup(prev);
166 if (!r)
167 goto error;
168 startup_logs_free(prev);
169 close(fd);
170 }
171
172 startup_logs = r;
173
174 return;
175error:
176 if (fd != -1)
177 close(fd);
178 /* couldn't get a mmap to work */
179 startup_logs = ring_new(STARTUP_LOG_SIZE);
180
181}
182
183#else /* ! USE_SHM_OPEN */
184
185void startup_logs_init()
186{
187 startup_logs = ring_new(STARTUP_LOG_SIZE);
188}
189
190#endif
191
192/* free the startup logs, unmap if it was an shm */
193void startup_logs_free(struct ring *r)
194{
195#ifdef USE_SHM_OPEN
196 if (r == shm_startup_logs)
197 munmap(r, STARTUP_LOG_SIZE);
198 else
199#endif /* ! USE_SHM_OPEN */
200 ring_free(r);
201}
202
203/* duplicate a startup logs which was previously allocated in a shm */
204struct ring *startup_logs_dup(struct ring *src)
205{
206 struct ring *dst = NULL;
207
208 /* must use the size of the previous buffer */
209 dst = ring_new(b_size(&src->buf));
210 if (!dst)
211 goto error;
212
213 b_reset(&dst->buf);
214 b_ncat(&dst->buf, &src->buf, b_data(&src->buf));
215error:
216 return dst;
217}
218
Amaury Denoyelle1833e432021-05-26 11:05:22 +0200219/* Put msg in usermsgs_buf.
220 *
221 * The message should not be terminated by a newline because this function
222 * manually insert it.
223 *
224 * If there is not enough room in the buffer, the message is silently discarded.
225 * Do not forget to frequently clear the buffer.
226 */
227static void usermsgs_put(const struct ist *msg)
228{
229 /* Allocate the buffer if not already done. */
230 if (unlikely(b_is_null(&usermsgs_buf))) {
231 usermsgs_buf.area = malloc(USER_MESSAGES_BUFSIZE * sizeof(char));
Aurelien DARRAGONd4dba382023-05-11 18:49:14 +0200232 if (usermsgs_buf.area)
233 usermsgs_buf.size = USER_MESSAGES_BUFSIZE;
Amaury Denoyelle1833e432021-05-26 11:05:22 +0200234 }
235
236 if (likely(!b_is_null(&usermsgs_buf))) {
237 if (b_room(&usermsgs_buf) >= msg->len + 2) {
238 /* Insert the message + newline. */
239 b_putblk(&usermsgs_buf, msg->ptr, msg->len);
240 b_putchr(&usermsgs_buf, '\n');
241 /* Insert NUL outside of the buffer. */
242 *b_tail(&usermsgs_buf) = '\0';
243 }
244 }
245}
246
Amaury Denoyelle6af81f82021-05-27 15:45:28 +0200247/* Clear the user messages log buffer.
248 *
249 * <prefix> will set the local-thread context appended to every output
250 * following this call. It can be NULL if not necessary.
251 */
252void usermsgs_clr(const char *prefix)
Amaury Denoyelle1833e432021-05-26 11:05:22 +0200253{
254 if (likely(!b_is_null(&usermsgs_buf))) {
255 b_reset(&usermsgs_buf);
256 usermsgs_buf.area[0] = '\0';
257 }
Amaury Denoyelle6af81f82021-05-27 15:45:28 +0200258
259 usermsgs_ctx.prefix = prefix;
Amaury Denoyelle1833e432021-05-26 11:05:22 +0200260}
261
262/* Check if the user messages buffer is empty. */
263int usermsgs_empty(void)
264{
265 return !!(b_is_null(&usermsgs_buf) || !b_data(&usermsgs_buf));
266}
267
268/* Return the messages log buffer content. */
269const char *usermsgs_str(void)
270{
271 if (unlikely(b_is_null(&usermsgs_buf)))
272 return "";
273
274 return b_head(&usermsgs_buf);
275}
276
Amaury Denoyelle6af81f82021-05-27 15:45:28 +0200277/* Set thread-local context infos to prefix forthcoming stderr output during
278 * configuration parsing.
279 *
280 * <file> and <line> specify the location of the parsed configuration.
281 *
282 * <obj> can be of various types. If not NULL, the string prefix generated will
283 * depend on its type.
284 */
285void set_usermsgs_ctx(const char *file, int line, enum obj_type *obj)
286{
287 usermsgs_ctx.file = file;
288 usermsgs_ctx.line = line;
289 usermsgs_ctx.obj = obj;
290}
291
292/* Set thread-local context infos to prefix forthcoming stderr output. It will
293 * be set as a complement to possibly already defined file/line.
294 *
295 * <obj> can be of various types. If not NULL, the string prefix generated will
296 * depend on its type.
297 */
298void register_parsing_obj(enum obj_type *obj)
299{
300 usermsgs_ctx.obj = obj;
301}
302
303/* Reset thread-local context infos for stderr output. */
304void reset_usermsgs_ctx(void)
305{
306 usermsgs_ctx.file = NULL;
307 usermsgs_ctx.line = 0;
308 usermsgs_ctx.obj = NULL;
309}
310
Amaury Denoyelle846830e2021-06-07 19:24:10 +0200311static void generate_usermsgs_ctx_str(void)
Amaury Denoyelle816281f2021-05-27 15:46:19 +0200312{
Amaury Denoyelle846830e2021-06-07 19:24:10 +0200313 struct usermsgs_ctx *ctx = &usermsgs_ctx;
314 void *area;
315 int ret;
Amaury Denoyelle816281f2021-05-27 15:46:19 +0200316
Amaury Denoyelle846830e2021-06-07 19:24:10 +0200317 if (unlikely(b_is_null(&ctx->str))) {
Tim Duesterhusec4a8752021-09-15 13:58:46 +0200318 area = calloc(USERMSGS_CTX_BUFSIZE, sizeof(*area));
Amaury Denoyelle846830e2021-06-07 19:24:10 +0200319 if (area)
320 ctx->str = b_make(area, USERMSGS_CTX_BUFSIZE, 0, 0);
321 }
322
323 if (likely(!b_is_null(&ctx->str))) {
324 b_reset(&ctx->str);
325
326 if (ctx->prefix) {
327 ret = snprintf(b_tail(&ctx->str), b_room(&ctx->str),
328 "%s : ", ctx->prefix);
329 b_add(&ctx->str, MIN(ret, b_room(&ctx->str)));
330 }
Amaury Denoyelle816281f2021-05-27 15:46:19 +0200331
Amaury Denoyelle846830e2021-06-07 19:24:10 +0200332 if (ctx->file) {
333 ret = snprintf(b_tail(&ctx->str), b_room(&ctx->str),
334 "[%s:%d] : ", ctx->file, ctx->line);
335 b_add(&ctx->str, MIN(ret, b_room(&ctx->str)));
336 }
337
338 switch (obj_type(ctx->obj)) {
339 case OBJ_TYPE_SERVER:
340 ret = snprintf(b_tail(&ctx->str), b_room(&ctx->str),
341 "'server %s/%s' : ",
342 __objt_server(ctx->obj)->proxy->id,
343 __objt_server(ctx->obj)->id);
344 b_add(&ctx->str, MIN(ret, b_room(&ctx->str)));
345 break;
346
347 case OBJ_TYPE_NONE:
348 default:
349 break;
350 }
Amaury Denoyelled0b237c2021-05-28 10:36:56 +0200351
Amaury Denoyelle846830e2021-06-07 19:24:10 +0200352 if (!b_data(&ctx->str))
353 snprintf(b_tail(&ctx->str), b_room(&ctx->str), "%s", "");
Amaury Denoyelle816281f2021-05-27 15:46:19 +0200354 }
355}
356
Amaury Denoyellece986e12021-06-04 11:20:32 +0200357/* Generic function to display messages prefixed by a label */
Amaury Denoyelle816281f2021-05-27 15:46:19 +0200358static void print_message(int use_usermsgs_ctx, const char *label, const char *fmt, va_list argp)
Amaury Denoyellece986e12021-06-04 11:20:32 +0200359{
Amaury Denoyelle1833e432021-05-26 11:05:22 +0200360 struct ist msg_ist = IST_NULL;
Amaury Denoyelle816281f2021-05-27 15:46:19 +0200361 char *head, *parsing_str, *msg;
Amaury Denoyellece986e12021-06-04 11:20:32 +0200362 char prefix[11]; // '[' + 8 chars + ']' + 0.
363
364 *prefix = '[';
365 strncpy(prefix + 1, label, sizeof(prefix) - 2);
366 msg = prefix + strlen(prefix);
367 *msg++ = ']';
368 while (msg < prefix + sizeof(prefix) - 1)
369 *msg++ = ' ';
370 *msg = 0;
371
Amaury Denoyelle816281f2021-05-27 15:46:19 +0200372 head = parsing_str = msg = NULL;
Amaury Denoyellece986e12021-06-04 11:20:32 +0200373 memprintf(&head, "%s (%u) : ", prefix, (uint)getpid());
374 memvprintf(&msg, fmt, argp);
375
Amaury Denoyelle1833e432021-05-26 11:05:22 +0200376 /* trim the trailing '\n' */
377 msg_ist = ist(msg);
378 if (msg_ist.len > 0 && msg_ist.ptr[msg_ist.len - 1] == '\n')
379 msg_ist.len--;
380
Amaury Denoyelle816281f2021-05-27 15:46:19 +0200381 if (use_usermsgs_ctx) {
Amaury Denoyelle846830e2021-06-07 19:24:10 +0200382 generate_usermsgs_ctx_str();
383 parsing_str = b_head(&usermsgs_ctx.str);
Amaury Denoyelle816281f2021-05-27 15:46:19 +0200384 reset_usermsgs_ctx();
385 }
386 else {
Amaury Denoyelle846830e2021-06-07 19:24:10 +0200387 parsing_str = "";
Amaury Denoyelle816281f2021-05-27 15:46:19 +0200388 }
389
Amaury Denoyellece986e12021-06-04 11:20:32 +0200390 if (global.mode & MODE_STARTING) {
391 if (unlikely(!startup_logs))
William Lallemandeba6a542022-09-26 12:54:39 +0200392 startup_logs_init();
Amaury Denoyellece986e12021-06-04 11:20:32 +0200393
394 if (likely(startup_logs)) {
Amaury Denoyelle816281f2021-05-27 15:46:19 +0200395 struct ist m[3];
Amaury Denoyellece986e12021-06-04 11:20:32 +0200396
397 m[0] = ist(head);
Amaury Denoyelle816281f2021-05-27 15:46:19 +0200398 m[1] = ist(parsing_str);
399 m[2] = msg_ist;
Amaury Denoyelle1833e432021-05-26 11:05:22 +0200400
Amaury Denoyelle816281f2021-05-27 15:46:19 +0200401 ring_write(startup_logs, ~0, 0, 0, m, 3);
Amaury Denoyellece986e12021-06-04 11:20:32 +0200402 }
403 }
Amaury Denoyelle1833e432021-05-26 11:05:22 +0200404 else {
405 usermsgs_put(&msg_ist);
406 }
Amaury Denoyellece986e12021-06-04 11:20:32 +0200407
Amaury Denoyelle816281f2021-05-27 15:46:19 +0200408 fprintf(stderr, "%s%s%s", head, parsing_str, msg);
Amaury Denoyellece986e12021-06-04 11:20:32 +0200409 fflush(stderr);
410
411 free(head);
412 free(msg);
413}
414
Amaury Denoyelle816281f2021-05-27 15:46:19 +0200415static void print_message_args(int use_usermsgs_ctx, const char *label, const char *fmt, ...)
416{
417 va_list argp;
418 va_start(argp, fmt);
419 print_message(use_usermsgs_ctx, label, fmt, argp);
420 va_end(argp);
421}
422
Amaury Denoyellece986e12021-06-04 11:20:32 +0200423/*
Aurelien DARRAGON88687f02023-04-04 22:04:35 +0200424 * Displays the message on stderr with the pid. Overrides the quiet
Amaury Denoyellece986e12021-06-04 11:20:32 +0200425 * mode during startup.
426 */
427void ha_alert(const char *fmt, ...)
428{
429 va_list argp;
430
Amaury Denoyelle0a1cdcc2021-05-26 11:05:45 +0200431 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE) ||
432 !(global.mode & MODE_STARTING)) {
433 if (!(warned & WARN_EXEC_PATH) && (global.mode & MODE_STARTING)) {
Amaury Denoyellece986e12021-06-04 11:20:32 +0200434 const char *path = get_exec_path();
435
436 warned |= WARN_EXEC_PATH;
Amaury Denoyelle816281f2021-05-27 15:46:19 +0200437 print_message_args(0, "NOTICE", "haproxy version is %s\n", haproxy_version);
Amaury Denoyellece986e12021-06-04 11:20:32 +0200438 if (path)
Amaury Denoyelle816281f2021-05-27 15:46:19 +0200439 print_message_args(0, "NOTICE", "path to executable is %s\n", path);
Amaury Denoyellece986e12021-06-04 11:20:32 +0200440 }
441 va_start(argp, fmt);
Amaury Denoyelle816281f2021-05-27 15:46:19 +0200442 print_message(1, "ALERT", fmt, argp);
Amaury Denoyellece986e12021-06-04 11:20:32 +0200443 va_end(argp);
444 }
445}
446
447/*
Aurelien DARRAGON88687f02023-04-04 22:04:35 +0200448 * Displays the message on stderr with the pid.
Amaury Denoyellece986e12021-06-04 11:20:32 +0200449 */
450void ha_warning(const char *fmt, ...)
451{
452 va_list argp;
453
454 warned |= WARN_ANY;
Willy Tarreau3c4a2972023-05-11 12:02:21 +0200455 HA_ATOMIC_INC(&tot_warnings);
Amaury Denoyellece986e12021-06-04 11:20:32 +0200456
Amaury Denoyelle0a1cdcc2021-05-26 11:05:45 +0200457 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE) ||
458 !(global.mode & MODE_STARTING)) {
Amaury Denoyelleda3d6812021-05-28 09:57:10 +0200459 if (!(warned & WARN_EXEC_PATH) && (global.mode & MODE_STARTING)) {
460 const char *path = get_exec_path();
461
462 warned |= WARN_EXEC_PATH;
463 print_message_args(0, "NOTICE", "haproxy version is %s\n", haproxy_version);
464 if (path)
465 print_message_args(0, "NOTICE", "path to executable is %s\n", path);
466 }
Amaury Denoyellece986e12021-06-04 11:20:32 +0200467 va_start(argp, fmt);
Amaury Denoyelle816281f2021-05-27 15:46:19 +0200468 print_message(1, "WARNING", fmt, argp);
Amaury Denoyellece986e12021-06-04 11:20:32 +0200469 va_end(argp);
470 }
471}
472
473/*
474 * Variant of _ha_diag_warning with va_list.
475 * Use it only if MODE_DIAG has been previously checked.
476 */
477void _ha_vdiag_warning(const char *fmt, va_list argp)
478{
Amaury Denoyelle816281f2021-05-27 15:46:19 +0200479 print_message(1, "DIAG", fmt, argp);
Amaury Denoyellece986e12021-06-04 11:20:32 +0200480}
481
482/*
483 * Output a diagnostic warning.
484 * Use it only if MODE_DIAG has been previously checked.
485 */
486void _ha_diag_warning(const char *fmt, ...)
487{
488 va_list argp;
489
490 va_start(argp, fmt);
491 _ha_vdiag_warning(fmt, argp);
492 va_end(argp);
493}
494
495/*
496 * Output a diagnostic warning. Do nothing of MODE_DIAG is not on.
497 */
498void ha_diag_warning(const char *fmt, ...)
499{
500 va_list argp;
501
502 if (global.mode & MODE_DIAG) {
503 va_start(argp, fmt);
504 _ha_vdiag_warning(fmt, argp);
505 va_end(argp);
506 }
507}
508
509/*
Aurelien DARRAGON88687f02023-04-04 22:04:35 +0200510 * Displays the message on stderr with the pid.
Amaury Denoyellece986e12021-06-04 11:20:32 +0200511 */
512void ha_notice(const char *fmt, ...)
513{
514 va_list argp;
515
Amaury Denoyelle0a1cdcc2021-05-26 11:05:45 +0200516 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE) ||
517 !(global.mode & MODE_STARTING)) {
Amaury Denoyellece986e12021-06-04 11:20:32 +0200518 va_start(argp, fmt);
Amaury Denoyelle816281f2021-05-27 15:46:19 +0200519 print_message(1, "NOTICE", fmt, argp);
Amaury Denoyellece986e12021-06-04 11:20:32 +0200520 va_end(argp);
521 }
522}
523
524/*
525 * Displays the message on <out> only if quiet mode is not set.
526 */
527void qfprintf(FILE *out, const char *fmt, ...)
528{
529 va_list argp;
530
531 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
532 va_start(argp, fmt);
533 vfprintf(out, fmt, argp);
534 fflush(out);
535 va_end(argp);
536 }
537}
538
539
540/* parse the "show startup-logs" command, returns 1 if a message is returned, otherwise zero */
541static int cli_parse_show_startup_logs(char **args, char *payload, struct appctx *appctx, void *private)
542{
543 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
544 return 1;
545
546 if (!startup_logs)
547 return cli_msg(appctx, LOG_INFO, "\n"); // nothing to print
548
Willy Tarreaucba88382022-05-05 15:18:57 +0200549 return ring_attach_cli(startup_logs, appctx, 0);
Amaury Denoyellece986e12021-06-04 11:20:32 +0200550}
551
552/* register cli keywords */
553static struct cli_kw_list cli_kws = {{ },{
William Lallemandeba6a542022-09-26 12:54:39 +0200554 { { "show", "startup-logs", NULL }, "show startup-logs : report logs emitted during HAProxy startup", cli_parse_show_startup_logs, NULL, NULL, NULL, ACCESS_MASTER },
Amaury Denoyellece986e12021-06-04 11:20:32 +0200555 {{},}
556}};
557
558INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
559
560
561static void deinit_errors_buffers()
562{
563 ring_free(_HA_ATOMIC_XCHG(&startup_logs, NULL));
Amaury Denoyelle1833e432021-05-26 11:05:22 +0200564 ha_free(&usermsgs_buf.area);
Amaury Denoyelle846830e2021-06-07 19:24:10 +0200565 ha_free(&usermsgs_ctx.str.area);
Amaury Denoyellece986e12021-06-04 11:20:32 +0200566}
567
Willy Tarreau032e7002022-04-27 17:50:53 +0200568/* errors might be used in threads and even before forking, thus 2 deinit */
Amaury Denoyellece986e12021-06-04 11:20:32 +0200569REGISTER_PER_THREAD_FREE(deinit_errors_buffers);
Willy Tarreau032e7002022-04-27 17:50:53 +0200570REGISTER_POST_DEINIT(deinit_errors_buffers);