Coverage Report

Created: 2026-08-09 07:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/fluent-bit/src/flb_lib.c
Line
Count
Source
1
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3
/*  Fluent Bit Demo
4
 *  ===============
5
 *  Copyright (C) 2015-2026 The Fluent Bit Authors
6
 *
7
 *  Licensed under the Apache License, Version 2.0 (the "License");
8
 *  you may not use this file except in compliance with the License.
9
 *  You may obtain a copy of the License at
10
 *
11
 *      http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 *  Unless required by applicable law or agreed to in writing, software
14
 *  distributed under the License is distributed on an "AS IS" BASIS,
15
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 *  See the License for the specific language governing permissions and
17
 *  limitations under the License.
18
 */
19
20
21
#include <fluent-bit/flb_lib.h>
22
#include <fluent-bit/flb_mem.h>
23
#include <fluent-bit/flb_compat.h>
24
#include <fluent-bit/flb_pipe.h>
25
#include <fluent-bit/flb_engine.h>
26
#include <fluent-bit/flb_fips.h>
27
#include <fluent-bit/flb_input.h>
28
#include <fluent-bit/flb_output.h>
29
#include <fluent-bit/flb_filter.h>
30
#include <fluent-bit/flb_utils.h>
31
#include <fluent-bit/flb_time.h>
32
#include <fluent-bit/flb_coro.h>
33
#include <fluent-bit/flb_callback.h>
34
#include <fluent-bit/flb_plugin.h>
35
#include <fluent-bit/flb_kv.h>
36
#include <fluent-bit/flb_metrics.h>
37
#include <fluent-bit/flb_upstream.h>
38
#include <fluent-bit/flb_downstream.h>
39
#include <fluent-bit/tls/flb_tls.h>
40
#include <fluent-bit/config_format/flb_cf.h>
41
42
#include <signal.h>
43
#include <stdarg.h>
44
#include <sys/stat.h>
45
#include <errno.h>
46
#include <stdlib.h>
47
48
#ifdef FLB_HAVE_MTRACE
49
#include <mcheck.h>
50
#endif
51
52
#ifdef FLB_HAVE_AWS_ERROR_REPORTER
53
#include <fluent-bit/aws/flb_aws_error_reporter.h>
54
55
struct flb_aws_error_reporter *error_reporter;
56
#endif
57
58
/* thread initializator */
59
static pthread_once_t flb_lib_once = PTHREAD_ONCE_INIT;
60
61
/* reference to the last 'flb_lib_ctx' context started through flb_start() */
62
FLB_TLS_DEFINE(flb_ctx_t, flb_lib_active_context);
63
64
/* reference to the last 'flb_cf' context started through flb_start() */
65
FLB_TLS_DEFINE(struct flb_cf, flb_lib_active_cf_context);
66
67
#ifdef FLB_SYSTEM_WINDOWS
68
static inline int flb_socket_init_win32(void)
69
{
70
    WSADATA wsaData;
71
    int err;
72
73
    err = WSAStartup(MAKEWORD(2, 2), &wsaData);
74
    if (err != 0) {
75
        fprintf(stderr, "WSAStartup failed with error: %d\n", err);
76
        return err;
77
    }
78
    return 0;
79
}
80
#endif
81
82
static inline struct flb_input_instance *in_instance_get(flb_ctx_t *ctx,
83
                                                         int ffd)
84
7.15k
{
85
7.15k
    struct mk_list *head;
86
7.15k
    struct flb_input_instance *i_ins;
87
88
7.15k
    mk_list_foreach(head, &ctx->config->inputs) {
89
7.15k
        i_ins = mk_list_entry(head, struct flb_input_instance, _head);
90
7.15k
        if (i_ins->id == ffd) {
91
7.15k
            return i_ins;
92
7.15k
        }
93
7.15k
    }
94
95
0
    return NULL;
96
7.15k
}
97
98
static inline struct flb_output_instance *out_instance_get(flb_ctx_t *ctx,
99
                                                           int ffd)
100
2.09k
{
101
2.09k
    struct mk_list *head;
102
2.09k
    struct flb_output_instance *o_ins;
103
104
2.09k
    mk_list_foreach(head, &ctx->config->outputs) {
105
2.09k
        o_ins = mk_list_entry(head, struct flb_output_instance, _head);
106
2.09k
        if (o_ins->id == ffd) {
107
2.09k
            return o_ins;
108
2.09k
        }
109
2.09k
    }
110
111
0
    return NULL;
112
2.09k
}
113
114
static inline struct flb_filter_instance *filter_instance_get(flb_ctx_t *ctx,
115
                                                              int ffd)
116
2
{
117
2
    struct mk_list *head;
118
2
    struct flb_filter_instance *f_ins;
119
120
2
    mk_list_foreach(head, &ctx->config->filters) {
121
2
        f_ins = mk_list_entry(head, struct flb_filter_instance, _head);
122
2
        if (f_ins->id == ffd) {
123
2
            return f_ins;
124
2
        }
125
2
    }
126
127
0
    return NULL;
128
2
}
129
130
void flb_init_env()
131
4
{
132
4
    flb_tls_init();
133
4
    flb_coro_init();
134
4
    flb_upstream_init();
135
4
    flb_downstream_init();
136
4
    flb_output_prepare();
137
138
4
    FLB_TLS_INIT(flb_lib_active_context);
139
4
    FLB_TLS_INIT(flb_lib_active_cf_context);
140
141
    /* libraries */
142
4
    cmt_initialize();
143
4
}
144
145
flb_ctx_t *flb_create()
146
2.08k
{
147
2.08k
    int ret;
148
2.08k
    flb_ctx_t *ctx;
149
2.08k
    struct flb_config *config;
150
151
#ifdef FLB_HAVE_MTRACE
152
    /* Start tracing malloc and free */
153
    mtrace();
154
#endif
155
156
#ifdef FLB_SYSTEM_WINDOWS
157
    /* Ensure we initialized Windows Sockets */
158
    if (flb_socket_init_win32()) {
159
        return NULL;
160
    }
161
#endif
162
163
2.08k
    ctx = flb_calloc(1, sizeof(flb_ctx_t));
164
2.08k
    if (!ctx) {
165
0
        perror("malloc");
166
0
        return NULL;
167
0
    }
168
169
2.08k
    config = flb_config_init();
170
2.08k
    if (!config) {
171
0
        flb_free(ctx);
172
0
        return NULL;
173
0
    }
174
2.08k
    ctx->config = config;
175
2.08k
    ctx->status = FLB_LIB_NONE;
176
177
    /*
178
     * Initialize our pipe to send data to our worker, used
179
     * by 'lib' input plugin.
180
     */
181
2.08k
    ret = flb_pipe_create(config->ch_data);
182
2.08k
    if (ret == -1) {
183
0
        perror("pipe");
184
0
        flb_config_exit(ctx->config);
185
0
        flb_free(ctx);
186
0
        return NULL;
187
0
    }
188
189
    /* Create the event loop to receive notifications */
190
2.08k
    ctx->event_loop = mk_event_loop_create(256);
191
2.08k
    if (!ctx->event_loop) {
192
0
        flb_config_exit(ctx->config);
193
0
        flb_free(ctx);
194
0
        return NULL;
195
0
    }
196
2.08k
    config->ch_evl = ctx->event_loop;
197
198
    /* Prepare the notification channels */
199
2.08k
    ctx->event_channel = flb_calloc(1, sizeof(struct mk_event));
200
2.08k
    if (!ctx->event_channel) {
201
0
        perror("calloc");
202
0
        flb_config_exit(ctx->config);
203
0
        flb_free(ctx);
204
0
        return NULL;
205
0
    }
206
207
2.08k
    MK_EVENT_ZERO(ctx->event_channel);
208
209
2.08k
    ret = mk_event_channel_create(config->ch_evl,
210
2.08k
                                  &config->ch_notif[0],
211
2.08k
                                  &config->ch_notif[1],
212
2.08k
                                  ctx->event_channel);
213
2.08k
    if (ret != 0) {
214
0
        flb_error("[lib] could not create notification channels");
215
0
        flb_stop(ctx);
216
0
        flb_destroy(ctx);
217
0
        return NULL;
218
0
    }
219
220
    #ifdef FLB_HAVE_AWS_ERROR_REPORTER
221
    if (is_error_reporting_enabled()) {
222
        error_reporter = flb_aws_error_reporter_create();
223
    }
224
    #endif
225
226
2.08k
    return ctx;
227
2.08k
}
228
229
/* Release resources associated to the library context */
230
void flb_destroy(flb_ctx_t *ctx)
231
2.08k
{
232
2.08k
    if (!ctx) {
233
0
        return;
234
0
    }
235
236
2.08k
    if (ctx->event_channel) {
237
2.08k
        mk_event_del(ctx->event_loop, ctx->event_channel);
238
2.08k
        flb_free(ctx->event_channel);
239
2.08k
    }
240
241
    /* Remove resources from the event loop */
242
2.08k
    mk_event_loop_destroy(ctx->event_loop);
243
244
    /* cfg->is_running is set to false when flb_engine_shutdown has been invoked (event loop) */
245
2.08k
    if (ctx->config) {
246
2.08k
        if (ctx->config->is_running == FLB_TRUE) {
247
0
            flb_engine_shutdown(ctx->config);
248
0
        }
249
2.08k
        flb_config_exit(ctx->config);
250
2.08k
    }
251
252
    #ifdef FLB_HAVE_AWS_ERROR_REPORTER
253
    if (is_error_reporting_enabled()) {
254
        flb_aws_error_reporter_destroy(error_reporter);
255
    }
256
    #endif
257
258
2.08k
    flb_free(ctx);
259
2.08k
    ctx = NULL;
260
261
#ifdef FLB_HAVE_MTRACE
262
    /* Stop tracing malloc and free */
263
    muntrace();
264
#endif
265
2.08k
}
266
267
/* Defines a new input instance */
268
int flb_input(flb_ctx_t *ctx, const char *input, void *data)
269
2.23k
{
270
2.23k
    struct flb_input_instance *i_ins;
271
272
2.23k
    i_ins = flb_input_new(ctx->config, input, data, FLB_TRUE);
273
2.23k
    if (!i_ins) {
274
127
        return -1;
275
127
    }
276
277
2.11k
    return i_ins->id;
278
2.23k
}
279
280
/* Defines a new output instance */
281
int flb_output(flb_ctx_t *ctx, const char *output, struct flb_lib_out_cb *cb)
282
2.36k
{
283
2.36k
    struct flb_output_instance *o_ins;
284
285
2.36k
    o_ins = flb_output_new(ctx->config, output, cb, FLB_TRUE);
286
2.36k
    if (!o_ins) {
287
236
        return -1;
288
236
    }
289
290
2.12k
    return o_ins->id;
291
2.36k
}
292
293
/* Defines a new filter instance */
294
int flb_filter(flb_ctx_t *ctx, const char *filter, void *data)
295
137
{
296
137
    struct flb_filter_instance *f_ins;
297
298
137
    f_ins = flb_filter_new(ctx->config, filter, data);
299
137
    if (!f_ins) {
300
125
        return -1;
301
125
    }
302
303
12
    return f_ins->id;
304
137
}
305
306
/* Set an input interface property */
307
int flb_input_set(flb_ctx_t *ctx, int ffd, ...)
308
2.09k
{
309
2.09k
    int ret;
310
2.09k
    char *key;
311
2.09k
    char *value;
312
2.09k
    va_list va;
313
2.09k
    struct flb_input_instance *i_ins;
314
315
2.09k
    i_ins = in_instance_get(ctx, ffd);
316
2.09k
    if (!i_ins) {
317
0
        return -1;
318
0
    }
319
320
2.09k
    va_start(va, ffd);
321
4.65k
    while ((key = va_arg(va, char *))) {
322
2.57k
        value = va_arg(va, char *);
323
2.57k
        if (!value) {
324
            /* Wrong parameter */
325
12
            va_end(va);
326
12
            return -1;
327
12
        }
328
2.56k
        ret = flb_input_set_property(i_ins, key, value);
329
2.56k
        if (ret != 0) {
330
0
            va_end(va);
331
0
            return -1;
332
0
        }
333
2.56k
    }
334
335
2.09k
    va_end(va);
336
2.08k
    return 0;
337
2.09k
}
338
339
int flb_input_set_processor(flb_ctx_t *ctx, int ffd, struct flb_processor *proc)
340
0
{
341
0
    struct flb_input_instance *i_ins;
342
343
0
    i_ins = in_instance_get(ctx, ffd);
344
0
    if (!i_ins || proc == NULL) {
345
0
        return -1;
346
0
    }
347
348
0
    if (i_ins->processor) {
349
0
        flb_processor_destroy(i_ins->processor);
350
0
    }
351
352
0
    proc->data = i_ins;
353
0
    proc->source_plugin_type = FLB_PLUGIN_INPUT;
354
0
    i_ins->processor = proc;
355
356
0
    return 0;
357
0
}
358
359
int flb_input_set_test(flb_ctx_t *ctx, int ffd, char *test_name,
360
                       void (*in_callback) (void *, int, int, void *, size_t, void *),
361
                       void *in_callback_data)
362
0
{
363
0
    struct flb_input_instance *i_ins;
364
365
0
    i_ins = in_instance_get(ctx, ffd);
366
0
    if (!i_ins) {
367
0
        return -1;
368
0
    }
369
370
    /*
371
     * Enabling a test, set the output instance in 'test' mode, so no real
372
     * flush callback is invoked, only the desired implemented test.
373
     */
374
375
    /* Formatter test */
376
0
    if (strcmp(test_name, "formatter") == 0) {
377
0
        i_ins->test_mode = FLB_TRUE;
378
0
        i_ins->test_formatter.rt_ctx = ctx;
379
0
        i_ins->test_formatter.rt_ffd = ffd;
380
0
        i_ins->test_formatter.rt_in_callback = in_callback;
381
0
        i_ins->test_formatter.rt_data = in_callback_data;
382
0
    }
383
0
    else {
384
0
        return -1;
385
0
    }
386
387
0
    return 0;
388
0
}
389
390
int flb_output_set_http_test(flb_ctx_t *ctx, int ffd, char *test_name,
391
                             void (*out_response) (void *, int, int, void *, size_t, void *),
392
                             void *out_callback_data)
393
0
{
394
0
    struct flb_output_instance *o_ins;
395
396
0
    o_ins = out_instance_get(ctx, ffd);
397
0
    if (!o_ins) {
398
0
        return -1;
399
0
    }
400
401
    /*
402
     * Enabling a test, set the output instance in 'test' mode, so no real
403
     * flush callback is invoked, only the desired implemented test.
404
     */
405
406
    /* Response test */
407
0
    if (strcmp(test_name, "response") == 0) {
408
0
        o_ins->test_mode = FLB_TRUE;
409
0
        o_ins->test_response.rt_ctx = ctx;
410
0
        o_ins->test_response.rt_ffd = ffd;
411
0
        o_ins->test_response.rt_out_response = out_response;
412
0
        o_ins->test_response.rt_data = out_callback_data;
413
0
    }
414
0
    else {
415
0
        return -1;
416
0
    }
417
418
0
    return 0;
419
0
}
420
421
static inline int flb_config_map_property_check(char *plugin_name, struct mk_list *config_map, char *key, char *val)
422
0
{
423
0
    struct flb_kv *kv;
424
0
    struct mk_list properties;
425
0
    int r;
426
427
0
    mk_list_init(&properties);
428
429
0
    kv = flb_kv_item_create(&properties, (char *) key, (char *) val);
430
0
    if (!kv) {
431
0
        return FLB_LIB_ERROR;
432
0
    }
433
434
0
    r = flb_config_map_properties_check(plugin_name, &properties, config_map);
435
0
    flb_kv_item_destroy(kv);
436
0
    return r;
437
0
}
438
439
/* Check if a given k, v is a valid config directive for the given output plugin */
440
int flb_output_property_check(flb_ctx_t *ctx, int ffd, char *key, char *val)
441
0
{
442
0
    struct flb_output_instance *o_ins;
443
0
    struct mk_list *config_map;
444
0
    struct flb_output_plugin *p;
445
0
    int r;
446
447
0
    o_ins = out_instance_get(ctx, ffd);
448
0
    if (!o_ins) {
449
0
      return FLB_LIB_ERROR;
450
0
    }
451
452
0
    p = o_ins->p;
453
0
    if (!p->config_map) {
454
0
        return FLB_LIB_NO_CONFIG_MAP;
455
0
    }
456
457
0
    config_map = flb_config_map_create(ctx->config, p->config_map);
458
0
    if (!config_map) {
459
0
        return FLB_LIB_ERROR;
460
0
    }
461
462
0
    r = flb_config_map_property_check(p->name, config_map, key, val);
463
0
    flb_config_map_destroy(config_map);
464
0
    return r;
465
0
}
466
467
/* Check if a given k, v is a valid config directive for the given input plugin */
468
int flb_input_property_check(flb_ctx_t *ctx, int ffd, char *key, char *val)
469
0
{
470
0
    struct flb_input_instance *i_ins;
471
0
    struct flb_input_plugin *p;
472
0
    struct mk_list *config_map;
473
0
    int r;
474
475
0
    i_ins = in_instance_get(ctx, ffd);
476
0
    if (!i_ins) {
477
0
      return FLB_LIB_ERROR;
478
0
    }
479
480
0
    p = i_ins->p;
481
0
    if (!p->config_map) {
482
0
        return FLB_LIB_NO_CONFIG_MAP;
483
0
    }
484
485
0
    config_map = flb_config_map_create(ctx->config, p->config_map);
486
0
    if (!config_map) {
487
0
        return FLB_LIB_ERROR;
488
0
    }
489
490
0
    r = flb_config_map_property_check(p->name, config_map, key, val);
491
0
    flb_config_map_destroy(config_map);
492
0
    return r;
493
0
}
494
495
/* Check if a given k, v is a valid config directive for the given filter plugin */
496
int flb_filter_property_check(flb_ctx_t *ctx, int ffd, char *key, char *val)
497
0
{
498
0
    struct flb_filter_instance *f_ins;
499
0
    struct flb_filter_plugin *p;
500
0
    struct mk_list *config_map;
501
0
    int r;
502
503
0
    f_ins = filter_instance_get(ctx, ffd);
504
0
    if (!f_ins) {
505
0
      return FLB_LIB_ERROR;
506
0
    }
507
508
0
    p = f_ins->p;
509
0
    if (!p->config_map) {
510
0
        return FLB_LIB_NO_CONFIG_MAP;
511
0
    }
512
513
0
    config_map = flb_config_map_create(ctx->config, p->config_map);
514
0
    if (!config_map) {
515
0
        return FLB_LIB_ERROR;
516
0
    }
517
518
0
    r = flb_config_map_property_check(p->name, config_map, key, val);
519
0
    flb_config_map_destroy(config_map);
520
0
    return r;
521
0
}
522
523
/* Set an output interface property */
524
int flb_output_set(flb_ctx_t *ctx, int ffd, ...)
525
2.09k
{
526
2.09k
    int ret;
527
2.09k
    char *key;
528
2.09k
    char *value;
529
2.09k
    va_list va;
530
2.09k
    struct flb_output_instance *o_ins;
531
532
2.09k
    o_ins = out_instance_get(ctx, ffd);
533
2.09k
    if (!o_ins) {
534
0
        return -1;
535
0
    }
536
537
2.09k
    va_start(va, ffd);
538
5.64k
    while ((key = va_arg(va, char *))) {
539
3.54k
        value = va_arg(va, char *);
540
3.54k
        if (!value) {
541
            /* Wrong parameter */
542
0
            va_end(va);
543
0
            return -1;
544
0
        }
545
546
3.54k
        ret = flb_output_set_property(o_ins, key, value);
547
3.54k
        if (ret != 0) {
548
0
            va_end(va);
549
0
            return -1;
550
0
        }
551
3.54k
    }
552
553
2.09k
    va_end(va);
554
2.09k
    return 0;
555
2.09k
}
556
557
int flb_output_set_processor(flb_ctx_t *ctx, int ffd, struct flb_processor *proc)
558
0
{
559
0
    struct flb_output_instance *o_ins;
560
561
0
    o_ins = out_instance_get(ctx, ffd);
562
0
    if (!o_ins || proc == NULL) {
563
0
        return -1;
564
0
    }
565
566
0
    if (o_ins->processor) {
567
0
        flb_processor_destroy(o_ins->processor);
568
0
    }
569
570
0
    proc->data = o_ins;
571
0
    proc->source_plugin_type = FLB_PLUGIN_OUTPUT;
572
0
    o_ins->processor = proc;
573
574
0
    return 0;
575
0
}
576
577
int flb_output_set_callback(flb_ctx_t *ctx, int ffd, char *name,
578
                            void (*cb)(char *, void *, void *))
579
0
{
580
0
    struct flb_output_instance *o_ins;
581
582
0
    o_ins = out_instance_get(ctx, ffd);
583
0
    if (!o_ins) {
584
0
        return -1;
585
0
    }
586
587
0
    return flb_callback_set(o_ins->callback, name, cb);
588
0
}
589
590
int flb_output_set_test(flb_ctx_t *ctx, int ffd, char *test_name,
591
                        void (*out_callback) (void *, int, int, void *, size_t, void *),
592
                        void *out_callback_data,
593
                        void *test_ctx)
594
0
{
595
0
    return flb_output_set_test_with_ctx_callback(ctx, ffd, test_name,
596
0
                                                 out_callback,
597
0
                                                 out_callback_data,
598
0
                                                 test_ctx, NULL);
599
0
}
600
601
int flb_output_set_test_with_ctx_callback(flb_ctx_t *ctx, int ffd,
602
                                          char *test_name,
603
                                          void (*out_callback) (void *, int, int, void *, size_t, void *),
604
                                          void *out_callback_data,
605
                                          void *test_ctx,
606
                                          void *(*test_ctx_callback) (struct flb_config *,
607
                                                                      struct flb_input_instance *,
608
                                                                      void *, void *))
609
0
{
610
0
    struct flb_output_instance *o_ins;
611
612
0
    o_ins = out_instance_get(ctx, ffd);
613
0
    if (!o_ins) {
614
0
        return -1;
615
0
    }
616
617
    /*
618
     * Enabling a test, set the output instance in 'test' mode, so no real
619
     * flush callback is invoked, only the desired implemented test.
620
     */
621
622
    /* Formatter test */
623
0
    if (strcmp(test_name, "formatter") == 0) {
624
0
        o_ins->test_mode = FLB_TRUE;
625
0
        o_ins->test_formatter.rt_ctx = ctx;
626
0
        o_ins->test_formatter.rt_ffd = ffd;
627
0
        o_ins->test_formatter.rt_out_callback = out_callback;
628
0
        o_ins->test_formatter.rt_data = out_callback_data;
629
0
        o_ins->test_formatter.flush_ctx = test_ctx;
630
0
        o_ins->test_formatter.flush_ctx_callback = test_ctx_callback;
631
0
    }
632
0
    else {
633
0
        return -1;
634
0
    }
635
636
0
    return 0;
637
0
}
638
639
/* Set an filter interface property */
640
int flb_filter_set(flb_ctx_t *ctx, int ffd, ...)
641
2
{
642
2
    int ret;
643
2
    char *key;
644
2
    char *value;
645
2
    va_list va;
646
2
    struct flb_filter_instance *f_ins;
647
648
2
    f_ins = filter_instance_get(ctx, ffd);
649
2
    if (!f_ins) {
650
0
        return -1;
651
0
    }
652
653
2
    va_start(va, ffd);
654
10
    while ((key = va_arg(va, char *))) {
655
8
        value = va_arg(va, char *);
656
8
        if (!value) {
657
            /* Wrong parameter */
658
0
            va_end(va);
659
0
            return -1;
660
0
        }
661
662
8
        ret = flb_filter_set_property(f_ins, key, value);
663
8
        if (ret != 0) {
664
0
            va_end(va);
665
0
            return -1;
666
0
        }
667
8
    }
668
669
2
    va_end(va);
670
2
    return 0;
671
2
}
672
673
/* Set a service property */
674
int flb_service_set(flb_ctx_t *ctx, ...)
675
2.08k
{
676
2.08k
    int ret;
677
2.08k
    char *key;
678
2.08k
    char *value;
679
2.08k
    va_list va;
680
681
2.08k
    va_start(va, ctx);
682
683
8.82k
    while ((key = va_arg(va, char *))) {
684
6.73k
        value = va_arg(va, char *);
685
6.73k
        if (!value) {
686
            /* Wrong parameter */
687
0
            va_end(va);
688
0
            return -1;
689
0
        }
690
691
6.73k
        ret = flb_config_set_property(ctx->config, key, value);
692
6.73k
        if (ret != 0) {
693
0
            va_end(va);
694
0
            return -1;
695
0
        }
696
6.73k
    }
697
698
2.08k
    va_end(va);
699
2.08k
    return 0;
700
2.08k
}
701
702
/* Load a configuration file that may be used by the input or output plugin */
703
int flb_lib_config_file(struct flb_lib_ctx *ctx, const char *path)
704
0
{
705
0
    struct flb_cf *cf;
706
0
    int ret;
707
0
    char tmp[PATH_MAX + 1];
708
0
    char *cfg = NULL;
709
0
    char *end;
710
0
    char *real_path;
711
0
    struct stat st;
712
713
    /* Check if file exists and resolve path */
714
0
    ret = stat(path, &st);
715
0
    if (ret == -1 && errno == ENOENT) {
716
        /* Try to resolve the real path (if exists) */
717
0
        if (path[0] == '/') {
718
0
            fprintf(stderr, "Error: configuration file not found: %s\n", path);
719
0
            return -1;
720
0
        }
721
722
0
        if (ctx->config->conf_path) {
723
0
            snprintf(tmp, PATH_MAX, "%s%s", ctx->config->conf_path, path);
724
0
            cfg = tmp;
725
0
        }
726
0
        else {
727
0
            cfg = (char *) path;
728
0
        }
729
0
    }
730
0
    else {
731
0
        cfg = (char *) path;
732
0
    }
733
734
0
    if (access(cfg, R_OK) != 0) {
735
0
        perror("access");
736
0
        fprintf(stderr, "Error: cannot read configuration file: %s\n", cfg);
737
0
        return -1;
738
0
    }
739
740
    /* Use modern config format API that supports both .conf and .yaml/.yml */
741
0
    cf = flb_cf_create_from_file(NULL, cfg);
742
0
    if (!cf) {
743
0
        fprintf(stderr, "Error reading configuration file: %s\n", cfg);
744
0
        return -1;
745
0
    }
746
747
    /* Set configuration root path */
748
0
    if (cfg) {
749
0
        real_path = realpath(cfg, NULL);
750
0
        if (real_path) {
751
0
            end = strrchr(real_path, FLB_DIRCHAR);
752
0
            if (end) {
753
0
                end++;
754
0
                *end = '\0';
755
0
                if (ctx->config->conf_path) {
756
0
                    flb_free(ctx->config->conf_path);
757
0
                }
758
0
                ctx->config->conf_path = flb_strdup(real_path);
759
0
            }
760
0
            free(real_path);
761
0
        }
762
0
    }
763
764
    /* Load the configuration format into the config */
765
0
    ret = flb_config_load_config_format(ctx->config, cf);
766
0
    if (ret != 0) {
767
0
        flb_cf_destroy(cf);
768
0
        fprintf(stderr, "Error loading configuration from file: %s\n", cfg);
769
0
        return -1;
770
0
    }
771
772
    /* Destroy old cf_main if it exists (created by flb_config_init) */
773
0
    if (ctx->config->cf_main) {
774
0
        flb_cf_destroy(ctx->config->cf_main);
775
0
    }
776
777
    /* Store the config format object */
778
0
    ctx->config->cf_main = cf;
779
780
0
    return 0;
781
0
}
782
783
/* This is a wrapper to release a buffer which comes from out_lib_flush() */
784
int flb_lib_free(void* data)
785
0
{
786
0
    if (data == NULL) {
787
0
        return -1;
788
0
    }
789
0
    flb_free(data);
790
0
    return 0;
791
0
}
792
793
static int flb_input_run_formatter(flb_ctx_t *ctx, struct flb_input_instance *i_ins,
794
                                   const void *data, size_t len)
795
0
{
796
0
    int ret;
797
0
    void *out_buf = NULL;
798
0
    size_t out_size = 0;
799
0
    struct flb_test_in_formatter *itf;
800
801
0
    if (!i_ins) {
802
0
        return -1;
803
0
    }
804
805
0
    itf = &i_ins->test_formatter;
806
807
    /* Invoke the input plugin formatter test callback */
808
0
    ret = itf->callback(ctx->config,
809
0
                        i_ins,
810
0
                        i_ins->context,
811
0
                        data, len,
812
0
                        &out_buf, &out_size);
813
814
    /* Call the runtime test callback checker */
815
0
    if (itf->rt_in_callback) {
816
0
        itf->rt_in_callback(itf->rt_ctx,
817
0
                            itf->rt_ffd,
818
0
                            ret,
819
0
                            out_buf, out_size,
820
0
                            itf->rt_data);
821
0
    }
822
0
    else {
823
0
        flb_free(out_buf);
824
0
    }
825
826
0
    return 0;
827
0
}
828
829
static int flb_output_run_response(flb_ctx_t *ctx, struct flb_output_instance *o_ins,
830
                                   int status, const void *data, size_t len)
831
0
{
832
0
    int ret;
833
0
    void *out_buf = NULL;
834
0
    size_t out_size = 0;
835
0
    struct flb_test_out_response *resp;
836
837
0
    if (!o_ins) {
838
0
        return -1;
839
0
    }
840
841
0
    resp = &o_ins->test_response;
842
843
    /* Invoke the input plugin formatter test callback */
844
0
    ret = resp->callback(ctx->config,
845
0
                         o_ins->context,
846
0
                         status, data, len,
847
0
                         &out_buf, &out_size);
848
849
    /* Call the runtime test callback checker */
850
0
    if (resp->rt_out_response) {
851
0
        resp->rt_out_response(resp->rt_ctx,
852
0
                              resp->rt_ffd,
853
0
                              ret,
854
0
                              out_buf, out_size,
855
0
                              resp->rt_data);
856
0
    }
857
0
    else {
858
0
        flb_free(out_buf);
859
0
    }
860
861
0
    return 0;
862
0
}
863
864
/* Push some data into the Engine */
865
int flb_lib_push(flb_ctx_t *ctx, int ffd, const void *data, size_t len)
866
5.05k
{
867
5.05k
    int ret;
868
5.05k
    struct flb_input_instance *i_ins;
869
870
5.05k
    if (ctx->status == FLB_LIB_NONE || ctx->status == FLB_LIB_ERROR) {
871
3
        flb_error("[lib] cannot push data, engine is not running");
872
3
        return -1;
873
3
    }
874
875
5.05k
    i_ins = in_instance_get(ctx, ffd);
876
5.05k
    if (!i_ins) {
877
0
        return -1;
878
0
    }
879
880
    /* If input's test_formatter is registered, priorize to run it. */
881
5.05k
    if (i_ins->test_formatter.callback != NULL) {
882
0
        ret = flb_input_run_formatter(ctx, i_ins, data, len);
883
0
    }
884
5.05k
    else {
885
5.05k
        ret = flb_pipe_w(i_ins->channel[1], data, len);
886
5.05k
        if (ret == -1) {
887
0
            flb_pipe_error();
888
0
            return -1;
889
0
        }
890
5.05k
    }
891
5.05k
    return ret;
892
5.05k
}
893
894
/* Emulate some data from the response */
895
int flb_lib_response(flb_ctx_t *ctx, int ffd, int status, const void *data, size_t len)
896
0
{
897
0
    int ret = -1;
898
0
    struct flb_output_instance *o_ins;
899
900
0
    if (ctx->status == FLB_LIB_NONE || ctx->status == FLB_LIB_ERROR) {
901
0
        flb_error("[lib] cannot push data, engine is not running");
902
0
        return -1;
903
0
    }
904
905
0
    o_ins = out_instance_get(ctx, ffd);
906
0
    if (!o_ins) {
907
0
        return -1;
908
0
    }
909
910
    /* If output's test_response callback is registered, prioritize to run it. */
911
0
    if (o_ins->test_response.callback != NULL) {
912
0
        ret = flb_output_run_response(ctx, o_ins, status, data, len);
913
0
    }
914
0
    return ret;
915
0
}
916
917
static void flb_lib_worker(void *data)
918
2.08k
{
919
2.08k
    int ret;
920
2.08k
    flb_ctx_t *ctx = data;
921
2.08k
    struct flb_config *config;
922
923
2.08k
    config = ctx->config;
924
2.08k
    flb_context_set(ctx);
925
2.08k
    mk_utils_worker_rename("flb-pipeline");
926
2.08k
    ret = flb_engine_start(config);
927
2.08k
    if (ret == -1) {
928
1.11k
        flb_engine_failed(config);
929
1.11k
        flb_engine_shutdown(config);
930
1.11k
    }
931
2.08k
    config->exit_status_code = ret;
932
2.08k
    ctx->status = FLB_LIB_NONE;
933
2.08k
}
934
935
/* Return the current time to be used by lib callers */
936
double flb_time_now()
937
82
{
938
82
    struct flb_time t;
939
940
82
    flb_time_get(&t);
941
82
    return flb_time_to_double(&t);
942
82
}
943
944
int static do_start(flb_ctx_t *ctx)
945
2.08k
{
946
2.08k
    int fd;
947
2.08k
    int bytes;
948
2.08k
    int ret;
949
2.08k
    uint64_t val;
950
2.08k
    pthread_t tid;
951
2.08k
    struct mk_event *event;
952
2.08k
    struct flb_config *config;
953
954
2.08k
    pthread_once(&flb_lib_once, flb_init_env);
955
956
2.08k
    flb_debug("[lib] context set: %p", ctx);
957
958
    /* set context as the last active one */
959
960
2.08k
    config = ctx->config;
961
962
    /* OpenSSL default properties must be configured before worker threads start. */
963
2.08k
    ret = flb_fips_init(config);
964
2.08k
    if (ret != 0) {
965
0
        return -1;
966
0
    }
967
968
    /* spawn worker thread */
969
2.08k
    ret = mk_utils_worker_spawn(flb_lib_worker, ctx, &tid);
970
2.08k
    if (ret == -1) {
971
0
        return -1;
972
0
    }
973
2.08k
    config->worker = tid;
974
975
    /* Wait for the started signal so we can return to the caller */
976
2.08k
    mk_event_wait(config->ch_evl);
977
2.08k
    mk_event_foreach(event, config->ch_evl) {
978
2.08k
        fd = event->fd;
979
2.08k
        bytes = flb_pipe_r(fd, &val, sizeof(uint64_t));
980
2.08k
        if (bytes <= 0) {
981
#if defined(FLB_SYSTEM_MACOS)
982
            pthread_cancel(tid);
983
#endif
984
0
            pthread_join(tid, NULL);
985
0
            ctx->status = FLB_LIB_ERROR;
986
0
            return -1;
987
0
        }
988
989
2.08k
        if (val == FLB_ENGINE_STARTED) {
990
973
            flb_debug("[lib] backend started");
991
973
            ctx->status = FLB_LIB_OK;
992
973
            break;
993
973
        }
994
1.11k
        else if (val == FLB_ENGINE_FAILED) {
995
1.11k
            flb_debug("[lib] backend failed");
996
#if defined(FLB_SYSTEM_MACOS)
997
            pthread_cancel(tid);
998
#endif
999
1.11k
            pthread_join(tid, NULL);
1000
1.11k
            ctx->status = FLB_LIB_ERROR;
1001
1.11k
            return -1;
1002
1.11k
        }
1003
0
        else {
1004
0
            flb_error("[lib] other error");
1005
0
        }
1006
2.08k
    }
1007
1008
973
    return 0;
1009
2.08k
}
1010
1011
/* Start the engine */
1012
int flb_start(flb_ctx_t *ctx)
1013
2.08k
{
1014
2.08k
    int ret;
1015
1016
2.08k
    ret = do_start(ctx);
1017
2.08k
    if (ret == 0) {
1018
        /* set context as the last active one */
1019
973
        flb_context_set(ctx);
1020
973
    }
1021
1022
2.08k
    return ret;
1023
2.08k
}
1024
1025
/* Start the engine without setting the global context */
1026
int flb_start_trace(flb_ctx_t *ctx)
1027
0
{
1028
0
    return do_start(ctx);
1029
0
}
1030
1031
int flb_loop(flb_ctx_t *ctx)
1032
0
{
1033
0
    while (ctx->status == FLB_LIB_OK) {
1034
0
        sleep(1);
1035
0
    }
1036
0
    return 0;
1037
0
}
1038
1039
/* Stop the engine */
1040
int flb_stop(flb_ctx_t *ctx)
1041
2.08k
{
1042
2.08k
    int ret;
1043
2.08k
    pthread_t tid;
1044
1045
2.08k
    flb_debug("[lib] ctx stop address: %p, config context=%p\n", ctx, ctx->config);
1046
1047
2.08k
    tid = ctx->config->worker;
1048
1049
2.08k
    if (ctx->status == FLB_LIB_NONE || ctx->status == FLB_LIB_ERROR) {
1050
        /*
1051
         * There is a chance the worker thread is still active while
1052
         * the service exited for some reason (plugin action). Always
1053
         * wait and double check that the child thread is not running.
1054
         */
1055
#if defined(FLB_SYSTEM_MACOS)
1056
        pthread_cancel(tid);
1057
#endif
1058
1.11k
        pthread_join(tid, NULL);
1059
1.11k
        return 0;
1060
1.11k
    }
1061
1062
973
    if (!ctx->config) {
1063
0
        return 0;
1064
0
    }
1065
1066
973
    if (ctx->config->cf_main) {
1067
973
        flb_cf_destroy(ctx->config->cf_main);
1068
973
        ctx->config->cf_main = NULL;
1069
973
    }
1070
1071
973
    flb_debug("[lib] sending STOP signal to the engine");
1072
1073
973
    flb_engine_exit(ctx->config);
1074
#if defined(FLB_SYSTEM_MACOS)
1075
    pthread_cancel(tid);
1076
#endif
1077
973
    ret = pthread_join(tid, NULL);
1078
973
    if (ret != 0) {
1079
0
        flb_errno();
1080
0
    }
1081
973
    flb_debug("[lib] Fluent Bit engine stopped");
1082
1083
973
    return ret;
1084
973
}
1085
1086
1087
void flb_context_set(flb_ctx_t *ctx)
1088
3.05k
{
1089
3.05k
    FLB_TLS_SET(flb_lib_active_context, ctx);
1090
3.05k
}
1091
1092
flb_ctx_t *flb_context_get()
1093
0
{
1094
0
    flb_ctx_t *ctx;
1095
1096
0
    ctx = FLB_TLS_GET(flb_lib_active_context);
1097
0
    return ctx;
1098
0
}
1099
1100
void flb_cf_context_set(struct flb_cf *cf)
1101
0
{
1102
0
    FLB_TLS_SET(flb_lib_active_cf_context, cf);
1103
0
}
1104
1105
struct flb_cf *flb_cf_context_get()
1106
0
{
1107
0
    struct flb_cf *cf;
1108
1109
0
    cf = FLB_TLS_GET(flb_lib_active_cf_context);
1110
0
    return cf;
1111
0
}