Coverage Report

Created: 2025-07-11 06:44

/src/open5gs/lib/app/ogs-init.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
3
 *
4
 * This file is part of Open5GS.
5
 *
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU Affero General Public License as published by
8
 * the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
18
 */
19
20
#include "ogs-app.h"
21
22
int __ogs_app_domain;
23
24
static int read_config(void);
25
static int parse_config(void);
26
27
int ogs_app_initialize(
28
        const char *version, const char *default_config,
29
        const char *const argv[])
30
0
{
31
0
    int rv, opt;
32
0
    ogs_getopt_t options;
33
0
    struct {
34
0
        char *config_file;
35
0
        char *log_file;
36
0
        char *log_level;
37
0
        char *domain_mask;
38
0
        char *config_section_id;
39
0
    } optarg;
40
41
0
    ogs_core_initialize();
42
0
    ogs_app_setup_log();
43
44
0
    ogs_app_context_init();
45
0
    ogs_app_config_init();
46
0
    ogs_app()->version = version;
47
48
    /**************************************************************************
49
     * Stage 1 : Command Line Options
50
     */
51
0
    memset(&optarg, 0, sizeof(optarg));
52
53
0
    ogs_getopt_init(&options, (char**)argv);
54
0
    while ((opt = ogs_getopt(&options, "c:l:e:m:k:")) != -1) {
55
0
        switch (opt) {
56
0
        case 'c':
57
0
            optarg.config_file = options.optarg;
58
0
            break;
59
0
        case 'l':
60
0
            optarg.log_file = options.optarg;
61
0
            break;
62
0
        case 'e':
63
0
            optarg.log_level = options.optarg;
64
0
            break;
65
0
        case 'm':
66
0
            optarg.domain_mask = options.optarg;
67
0
            break;
68
0
        case 'k':
69
0
            optarg.config_section_id = options.optarg;
70
0
            break;
71
0
        case '?':
72
0
        default:
73
0
            ogs_assert_if_reached();
74
0
            return OGS_ERROR;
75
0
        }
76
0
    }
77
78
    /**************************************************************************
79
     * Stage 2 : Load Configuration File
80
     */
81
0
    if (optarg.config_file)
82
0
        ogs_app()->file = optarg.config_file;
83
0
    else
84
0
        ogs_app()->file = default_config;
85
86
0
    rv = read_config();
87
0
    if (rv != OGS_OK) return rv;
88
89
0
    rv = parse_config();
90
0
    if (rv != OGS_OK) return rv;
91
92
    /**************************************************************************
93
     * Stage 3 : Initialize Default Memory Pool
94
     */
95
0
    ogs_pkbuf_default_create(&ogs_global_conf()->pkbuf_config);
96
97
    /**************************************************************************
98
     * Stage 4 : Setup LOG Module
99
     */
100
0
    if (optarg.log_file)
101
0
        ogs_app()->logger.file = optarg.log_file;
102
103
0
    if (ogs_app()->logger.file) {
104
0
        if (ogs_log_add_file(ogs_app()->logger.file) == NULL) {
105
0
            ogs_fatal("cannot open log file : %s", 
106
0
                    ogs_app()->logger.file);
107
0
            return OGS_ERROR;
108
0
        }
109
0
    }
110
111
0
    if (optarg.domain_mask)
112
0
        ogs_app()->logger.domain = optarg.domain_mask;
113
114
0
    if (optarg.log_level) 
115
0
        ogs_app()->logger.level = optarg.log_level;
116
117
0
    rv = ogs_log_config_domain(
118
0
            ogs_app()->logger.domain, ogs_app()->logger.level);
119
0
    if (rv != OGS_OK) return rv;
120
121
0
    ogs_log_set_timestamp(ogs_app()->logger_default.timestamp,
122
0
                          ogs_app()->logger.timestamp);
123
124
    /**************************************************************************
125
     * Stage 5 : Setup Database Module
126
     */
127
0
    if (ogs_env_get("DB_URI"))
128
0
        ogs_app()->db_uri = ogs_env_get("DB_URI");
129
130
    /**************************************************************************
131
     * Stage 6 : Setup configuration section ID for running multiple NF from
132
     * same config file
133
     */
134
0
    if (optarg.config_section_id)
135
0
        ogs_app()->config_section_id = atoi(optarg.config_section_id);
136
137
    /**************************************************************************
138
     * Stage 7 : Print Banner
139
     */
140
0
    if (ogs_app()->version) {
141
0
        ogs_log_print(OGS_LOG_INFO,
142
0
                "Open5GS daemon %s\n\n", ogs_app()->version);
143
144
0
        ogs_info("Configuration: '%s'", ogs_app()->file);
145
146
0
        if (ogs_app()->logger.file) {
147
0
            ogs_info("File Logging: '%s'", ogs_app()->logger.file);
148
149
0
            if (ogs_app()->logger.level)
150
0
                ogs_info("LOG-LEVEL: '%s'", ogs_app()->logger.level);
151
152
0
            if (ogs_app()->logger.domain)
153
0
                ogs_info("LOG-DOMAIN: '%s'", ogs_app()->logger.domain);
154
0
        }
155
0
    }
156
157
    /**************************************************************************
158
     * Stage 8 : Queue, Timer and Poll
159
     */
160
0
    ogs_app()->queue = ogs_queue_create(ogs_app()->pool.event);
161
0
    ogs_assert(ogs_app()->queue);
162
0
    ogs_app()->timer_mgr = ogs_timer_mgr_create(ogs_app()->pool.timer);
163
0
    ogs_assert(ogs_app()->timer_mgr);
164
0
    ogs_app()->pollset = ogs_pollset_create(ogs_app()->pool.socket);
165
0
    ogs_assert(ogs_app()->pollset);
166
167
0
    return rv;
168
0
}
169
170
void ogs_app_terminate(void)
171
0
{
172
0
    ogs_app_config_final();
173
0
    ogs_app_context_final();
174
175
0
    ogs_pkbuf_default_destroy();
176
177
0
    ogs_core_terminate();
178
0
}
179
180
static int read_config(void)
181
0
{
182
0
    FILE *file;
183
0
    yaml_parser_t parser;
184
0
    yaml_document_t *document = NULL;
185
186
0
    ogs_assert(ogs_app()->file);
187
188
0
    file = fopen(ogs_app()->file, "rb");
189
0
    if (!file) {
190
0
        ogs_fatal("cannot open file `%s`", ogs_app()->file);
191
0
        return OGS_ERROR;
192
0
    }
193
194
0
    ogs_assert(yaml_parser_initialize(&parser));
195
0
    yaml_parser_set_input_file(&parser, file);
196
197
0
    document = calloc(1, sizeof(yaml_document_t));
198
0
    if (!yaml_parser_load(&parser, document)) {
199
0
        ogs_fatal("Failed to parse configuration file '%s'", ogs_app()->file);
200
0
        switch (parser.error) {
201
0
        case YAML_MEMORY_ERROR:
202
0
            ogs_error("Memory error: Not enough memory for parsing");
203
0
            break;
204
0
        case YAML_READER_ERROR:
205
0
            if (parser.problem_value != -1)
206
0
                ogs_error("Reader error - %s: #%X at %zd", parser.problem,
207
0
                    parser.problem_value, parser.problem_offset);
208
0
            else
209
0
                ogs_error("Reader error - %s at %zd", parser.problem,
210
0
                    parser.problem_offset);
211
0
            break;
212
0
        case YAML_SCANNER_ERROR:
213
0
            if (parser.context)
214
0
                ogs_error("Scanner error - %s at line %zu, column %zu "
215
0
                        "%s at line %zu, column %zu", parser.context,
216
0
                        parser.context_mark.line+1,
217
0
                        parser.context_mark.column+1,
218
0
                        parser.problem, parser.problem_mark.line+1,
219
0
                        parser.problem_mark.column+1);
220
0
            else
221
0
                ogs_error("Scanner error - %s at line %zu, column %zu",
222
0
                        parser.problem, parser.problem_mark.line+1,
223
0
                        parser.problem_mark.column+1);
224
0
            break;
225
0
        case YAML_PARSER_ERROR:
226
0
            if (parser.context)
227
0
                ogs_error("Parser error - %s at line %zu, column %zu "
228
0
                        "%s at line %zu, column %zu", parser.context,
229
0
                        parser.context_mark.line+1,
230
0
                        parser.context_mark.column+1,
231
0
                        parser.problem, parser.problem_mark.line+1,
232
0
                        parser.problem_mark.column+1);
233
0
            else
234
0
                ogs_error("Parser error - %s at line %zu, column %zu",
235
0
                        parser.problem, parser.problem_mark.line+1,
236
0
                        parser.problem_mark.column+1);
237
0
            break;
238
0
        default:
239
            /* Couldn't happen. */
240
0
            ogs_assert_if_reached();
241
0
            break;
242
0
        }
243
244
0
        free(document);
245
0
        yaml_parser_delete(&parser);
246
0
        ogs_assert(!fclose(file));
247
0
        return OGS_ERROR;
248
0
    }
249
250
0
    ogs_app()->document = document;
251
252
0
    yaml_parser_delete(&parser);
253
0
    ogs_assert(!fclose(file));
254
255
0
    return OGS_OK;
256
0
}
257
258
static int context_prepare(void)
259
0
{
260
0
    int rv;
261
262
0
#define USRSCTP_LOCAL_UDP_PORT      9899
263
0
    ogs_app()->usrsctp.udp_port = USRSCTP_LOCAL_UDP_PORT;
264
265
0
    rv = ogs_app_global_conf_prepare();
266
0
    if (rv != OGS_OK) return rv;
267
268
0
    return OGS_OK;
269
0
}
270
271
static int context_validation(void)
272
0
{
273
0
    return OGS_OK;
274
0
}
275
276
static void parse_config_logger_file(ogs_yaml_iter_t *logger_iter,
277
                                     const char *logger_key)
278
0
{
279
0
    ogs_yaml_iter_t iter;
280
281
    /* Legacy format:
282
     *   logger:
283
     *     file: /var/log/open5gs/mme.log */
284
0
    if (!strcmp(logger_key, "file") && ogs_yaml_iter_has_value(logger_iter)) {
285
0
        ogs_app()->logger.file = ogs_yaml_iter_value(logger_iter);
286
287
0
        ogs_warn("Please change the configuration file as below.");
288
0
        ogs_log_print(OGS_LOG_WARN, "\n<OLD Format>\n");
289
0
        ogs_log_print(OGS_LOG_WARN, "logger:\n");
290
0
        ogs_log_print(OGS_LOG_WARN, "  file: %s\n", ogs_app()->logger.file);
291
0
        ogs_log_print(OGS_LOG_WARN, "\n<NEW Format>\n");
292
0
        ogs_log_print(OGS_LOG_WARN, "logger:\n");
293
0
        ogs_log_print(OGS_LOG_WARN, "  file:\n");
294
0
        ogs_log_print(OGS_LOG_WARN, "    path: %s\n", ogs_app()->logger.file);
295
0
        ogs_log_print(OGS_LOG_WARN, "\n\n\n");
296
0
        return;
297
0
    }
298
299
    /* Current format:
300
     *   logger:
301
     *     default:
302
     *       timestamp: false
303
     *     file:
304
     *       path: /var/log/open5gs/mme.log
305
     *       timestamp: true */
306
0
    ogs_yaml_iter_recurse(logger_iter, &iter);
307
0
    while (ogs_yaml_iter_next(&iter)) {
308
0
        const char *key = ogs_yaml_iter_key(&iter);
309
0
        ogs_assert(key);
310
0
        if (!strcmp(key, "timestamp")) {
311
0
            ogs_log_ts_e ts = ogs_yaml_iter_bool(&iter)
312
0
                              ? OGS_LOG_TS_ENABLED
313
0
                              : OGS_LOG_TS_DISABLED;
314
0
            if (!strcmp(logger_key, "default")) {
315
0
                ogs_app()->logger_default.timestamp = ts;
316
0
            } else if (!strcmp(logger_key, "file")) {
317
0
                ogs_app()->logger.timestamp = ts;
318
0
            }
319
0
        } else if (!strcmp(key, "path")) {
320
0
            if (!strcmp(logger_key, "file")) {
321
0
                ogs_app()->logger.file = ogs_yaml_iter_value(&iter);
322
0
            }
323
0
        }
324
0
    }
325
0
}
326
327
static int parse_config(void)
328
0
{
329
0
    int rv;
330
0
    yaml_document_t *document = NULL;
331
0
    ogs_yaml_iter_t root_iter;
332
333
0
    document = ogs_app()->document;
334
0
    ogs_assert(document);
335
336
0
    rv = context_prepare();
337
0
    if (rv != OGS_OK) return rv;
338
339
0
    ogs_yaml_iter_init(&root_iter, document);
340
0
    while (ogs_yaml_iter_next(&root_iter)) {
341
0
        const char *root_key = ogs_yaml_iter_key(&root_iter);
342
0
        ogs_assert(root_key);
343
0
        if (!strcmp(root_key, "db_uri")) {
344
0
            ogs_app()->db_uri = ogs_yaml_iter_value(&root_iter);
345
0
        } else if (!strcmp(root_key, "logger")) {
346
0
            ogs_yaml_iter_t logger_iter;
347
0
            ogs_yaml_iter_recurse(&root_iter, &logger_iter);
348
0
            while (ogs_yaml_iter_next(&logger_iter)) {
349
0
                const char *logger_key = ogs_yaml_iter_key(&logger_iter);
350
0
                ogs_assert(logger_key);
351
0
                parse_config_logger_file(&logger_iter, logger_key);
352
0
                if (!strcmp(logger_key, "level")) {
353
0
                    ogs_app()->logger.level =
354
0
                        ogs_yaml_iter_value(&logger_iter);
355
0
                } else if (!strcmp(logger_key, "domain")) {
356
0
                    ogs_app()->logger.domain =
357
0
                        ogs_yaml_iter_value(&logger_iter);
358
0
                }
359
0
            }
360
0
        } else if (!strcmp(root_key, "global")) {
361
0
            rv = ogs_app_parse_global_conf(&root_iter);
362
0
            if (rv != OGS_OK) {
363
0
                ogs_error("ogs_global_conf_parse_config() failed");
364
0
                return rv;
365
0
            }
366
0
        } else {
367
0
            rv = ogs_app_count_nf_conf_sections(root_key);
368
0
            if (rv != OGS_OK) {
369
0
                ogs_error("ogs_app_count_nf_conf_sections() failed");
370
0
                return rv;
371
0
            }
372
0
        }
373
0
    }
374
375
0
    rv = context_validation();
376
0
    if (rv != OGS_OK) return rv;
377
378
0
    return OGS_OK;
379
0
}
380
381
void ogs_app_setup_log(void)
382
0
{
383
0
    ogs_log_install_domain(&__ogs_app_domain, "app", ogs_core()->log.level);
384
0
}