Coverage Report

Created: 2026-10-18 06:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/freeradius-server/src/lib/unlang/base.c
Line
Count
Source
1
/*
2
 *   This program is free software; you can redistribute it and/or modify
3
 *   it under the terms of the GNU General Public License as published by
4
 *   the Free Software Foundation; either version 2 of the License, or
5
 *   (at your option) any later version.
6
 *
7
 *   This program is distributed in the hope that it will be useful,
8
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 *   GNU General Public License for more details.
11
 *
12
 *   You should have received a copy of the GNU General Public License
13
 *   along with this program; if not, write to the Free Software
14
 *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15
 */
16
17
/**
18
 * $Id: f225b2c7cc251c9264fafd045dcfd24c574b97e1 $
19
 *
20
 * @file unlang/base.c
21
 * @brief Base, utility functions for the unlang library.
22
 *
23
 * @copyright 2019 The FreeRADIUS server project
24
 */
25
RCSID("$Id: f225b2c7cc251c9264fafd045dcfd24c574b97e1 $")
26
27
#include "unlang_priv.h"
28
29
/** Different operations the interpreter can execute
30
 */
31
unlang_op_t unlang_ops[UNLANG_TYPE_MAX];
32
33
/** Return whether a section has unlang data associated with it
34
 *
35
 * @param[in] cs  to check.
36
 * @return
37
 *  - true if it has data.
38
 *  - false if it doesn't have data.
39
 */
40
bool unlang_section(CONF_SECTION *cs)
41
0
{
42
0
  return (cf_data_find(cs, unlang_group_t, NULL) != NULL);
43
0
}
44
45
fr_hash_table_t *unlang_op_table = NULL;
46
47
/** Register an operation with the interpreter
48
 *
49
 * The main purpose of this registration API is to avoid intermixing the xlat,
50
 * condition, map APIs with the interpreter, i.e. the callbacks needed for that
51
 * functionality can be in their own source files, and we don't need to include
52
 * supporting types and function declarations in the interpreter.
53
 *
54
 * @param[in] op    #unlang_op_t to register.
55
 */
56
void unlang_register(unlang_op_t *op)
57
128
{
58
128
  fr_assert(op->type < UNLANG_TYPE_MAX); /* Unlang max isn't a valid type */
59
128
  fr_assert(unlang_op_table != NULL);
60
61
128
  memcpy(&unlang_ops[op->type], op, sizeof(unlang_ops[op->type]));
62
63
  /*
64
   *  Some instruction types are internal, and are not real keywords.
65
   */
66
128
  if ((op->flag & UNLANG_OP_FLAG_INTERNAL) != 0) return;
67
68
96
  MEM(fr_hash_table_insert(unlang_op_table, &unlang_ops[op->type]) == 0);
69
96
}
70
71
static TALLOC_CTX *unlang_ctx = NULL;
72
73
static uint32_t op_hash(void const *data)
74
96
{
75
96
  unlang_op_t const *a = data;
76
77
96
  return fr_hash_string(a->name);
78
96
}
79
80
static fr_cmp_ret_t op_cmp(void const *one, void const *two)
81
0
{
82
0
  unlang_op_t const *a = one;
83
0
  unlang_op_t const *b = two;
84
85
0
  return CMP(strcmp(a->name, b->name), 0);
86
0
}
87
88
static int _unlang_global_free(UNUSED void *uctx)
89
4
{
90
4
  TALLOC_FREE(unlang_ctx);
91
4
  unlang_op_table = NULL;
92
93
4
  return 0;
94
4
}
95
96
static int _unlang_global_init(UNUSED void *uctx)
97
4
{
98
4
  unlang_ctx = talloc_init("unlang");
99
4
  if (!unlang_ctx) return -1;
100
101
4
  unlang_op_table = fr_hash_table_alloc(unlang_ctx, op_hash, op_cmp, NULL);
102
4
  if (!unlang_op_table) goto fail;
103
104
  /*
105
   *  Explicitly initialise the xlat tree, and perform dictionary lookups.
106
   */
107
4
  if (xlat_global_init() < 0) {
108
0
  fail:
109
0
    TALLOC_FREE(unlang_ctx);
110
111
0
    memset(unlang_ops, 0, sizeof(unlang_ops));
112
0
    return -1;
113
0
  }
114
115
  /*
116
   *  Initialise global maps
117
   */
118
4
  if (map_global_init() < 0) goto fail;
119
120
4
  unlang_interpret_init_global(unlang_ctx);
121
122
  /*
123
   *  Operations which can fail, and which require cleanup.
124
   */
125
4
  if (unlang_subrequest_op_init() < 0) goto fail;
126
127
  /*
128
   *  Register operations for the default keywords.  The
129
   *  operations listed below cannot fail, and do not
130
   *  require cleanup.
131
   */
132
4
  unlang_compile_init(unlang_ctx);
133
4
  unlang_condition_init();
134
4
  unlang_finally_init();
135
4
  unlang_foreach_init();
136
4
  unlang_function_init();
137
4
  unlang_group_init();
138
4
  unlang_load_balance_init();
139
4
  unlang_map_init();
140
4
  unlang_module_init();
141
4
  unlang_parallel_init();
142
4
  unlang_return_init();
143
4
  unlang_detach_init();
144
4
  unlang_switch_init();
145
4
  unlang_call_init();
146
4
  unlang_caller_init();
147
4
  unlang_tmpl_init();
148
4
  unlang_edit_init();
149
4
  unlang_timeout_init();
150
4
  unlang_limit_init();
151
4
  unlang_transaction_init();
152
4
  unlang_try_init();
153
4
  unlang_catch_init();
154
155
4
  return 0;
156
4
}
157
158
int unlang_global_init(void)
159
4
{
160
4
  int ret;
161
  fr_atexit_global_once_ret(&ret, _unlang_global_init, _unlang_global_free, NULL);
162
4
  return ret;
163
4
}