/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 | } |