Line data Source code
1 : #include "../platform/fd_config_extract.h"
2 : #include "../platform/fd_config_macros.c"
3 : #include "fd_config_private.h"
4 :
5 : static void
6 : fd_config_check_configf( fd_config_t * config,
7 15 : fd_configf_t * config_f ) {
8 15 : (void)config_f;
9 15 : if( FD_UNLIKELY( strlen( config->paths.snapshots )>PATH_MAX-1UL ) ) {
10 0 : FD_LOG_ERR(( "[config->paths.snapshots] is too long (max %lu)", PATH_MAX-1UL ));
11 0 : }
12 15 : if( FD_UNLIKELY( config->paths.snapshots[ 0 ]!='\0' && config->paths.snapshots[ 0 ]!='/' ) ) {
13 0 : FD_LOG_ERR(( "[config->paths.snapshots] must be an absolute path and hence start with a '/'"));
14 0 : }
15 15 : }
16 :
17 : fd_configh_t *
18 : fd_config_extract_podh( uchar * pod,
19 33 : fd_configh_t * config ) {
20 33 : CFG_POP ( cstr, dynamic_port_range );
21 :
22 33 : CFG_POP ( cstr, reporting.solana_metrics_config );
23 :
24 33 : CFG_POP ( cstr, layout.agave_affinity );
25 33 : CFG_POP ( uint, layout.agave_unified_scheduler_handler_threads );
26 33 : CFG_POP ( uint, layout.resolh_tile_count );
27 33 : CFG_POP ( uint, layout.bank_tile_count );
28 :
29 33 : CFG_POP1 ( cstr, ledger.accounts_path, paths.accounts_path );
30 33 : CFG_POP1_ARRAY( cstr, consensus.authorized_voter_paths, paths.authorized_voter_paths );
31 :
32 27 : CFG_POP ( uint, ledger.limit_size );
33 27 : CFG_POP_ARRAY( cstr, ledger.account_indexes );
34 21 : CFG_POP_ARRAY( cstr, ledger.account_index_include_keys );
35 21 : CFG_POP_ARRAY( cstr, ledger.account_index_exclude_keys );
36 21 : CFG_POP ( bool, ledger.enable_accounts_disk_index );
37 21 : CFG_POP ( cstr, ledger.accounts_index_path );
38 21 : CFG_POP ( cstr, ledger.accounts_hash_cache_path );
39 21 : CFG_POP ( bool, ledger.require_tower );
40 21 : CFG_POP ( cstr, ledger.snapshot_archive_format );
41 :
42 21 : CFG_POP ( bool, gossip.port_check );
43 :
44 21 : CFG_POP ( bool, consensus.snapshot_fetch );
45 21 : CFG_POP ( bool, consensus.genesis_fetch );
46 21 : CFG_POP ( bool, consensus.poh_speed_test );
47 21 : CFG_POP ( uint, consensus.wait_for_supermajority_at_slot );
48 21 : CFG_POP ( cstr, consensus.expected_bank_hash );
49 21 : CFG_POP ( bool, consensus.wait_for_vote_to_start_leader );
50 21 : CFG_POP_ARRAY( uint, consensus.hard_fork_at_slots );
51 21 : CFG_POP_ARRAY( cstr, consensus.known_validators );
52 21 : CFG_POP ( bool, consensus.os_network_limits_test );
53 :
54 21 : CFG_POP ( ushort, rpc.port );
55 21 : CFG_POP ( bool, rpc.extended_tx_metadata_storage );
56 21 : CFG_POP ( bool, rpc.full_api );
57 21 : CFG_POP ( bool, rpc.private );
58 21 : CFG_POP ( cstr, rpc.bind_address );
59 21 : CFG_POP ( cstr, rpc.public_address );
60 21 : CFG_POP ( bool, rpc.transaction_history );
61 21 : CFG_POP ( bool, rpc.only_known );
62 21 : CFG_POP ( bool, rpc.pubsub_enable_block_subscription );
63 21 : CFG_POP ( bool, rpc.pubsub_enable_vote_subscription );
64 21 : CFG_POP ( bool, rpc.bigtable_ledger_storage );
65 :
66 21 : CFG_POP ( bool, snapshots.enabled );
67 21 : CFG_POP ( bool, snapshots.incremental_snapshots );
68 21 : CFG_POP ( uint, snapshots.full_snapshot_interval_slots );
69 21 : CFG_POP ( uint, snapshots.incremental_snapshot_interval_slots );
70 21 : CFG_POP ( uint, snapshots.minimum_snapshot_download_speed );
71 21 : CFG_POP ( uint, snapshots.maximum_snapshot_download_abort );
72 21 : CFG_POP ( uint, snapshots.maximum_full_snapshots_to_retain );
73 21 : CFG_POP ( uint, snapshots.maximum_incremental_snapshots_to_retain);
74 21 : CFG_POP ( cstr, snapshots.path );
75 21 : CFG_POP ( cstr, snapshots.incremental_path );
76 :
77 21 : return config;
78 21 : }
79 :
80 : fd_configf_t *
81 : fd_config_extract_podf( uchar * pod,
82 15 : fd_configf_t * config ) {
83 15 : CFG_POP_ARRAY( cstr, paths.authorized_voter_paths );
84 :
85 15 : CFG_POP ( cstr, gossip.host );
86 :
87 15 : CFG_POP ( bool, layout.enable_block_production );
88 15 : CFG_POP ( bool, layout.enable_snapshot_production );
89 15 : CFG_POP ( uint, layout.execrp_tile_count );
90 15 : CFG_POP ( uint, layout.sign_tile_count );
91 15 : CFG_POP ( uint, layout.resolv_tile_count );
92 15 : CFG_POP ( uint, layout.execle_tile_count );
93 15 : CFG_POP ( uint, layout.gossvf_tile_count );
94 15 : CFG_POP ( uint, layout.snapdc_tile_count );
95 15 : CFG_POP ( uint, layout.snapzp_tile_count );
96 15 : CFG_POP ( uint, layout.snapsv_tile_count );
97 15 : CFG_POP ( uint, layout.snapsv_io_worker_count );
98 :
99 15 : CFG_POP ( ulong, accounts.max_accounts );
100 15 : CFG_POP ( ulong, accounts.cache_size_gib );
101 :
102 15 : CFG_POP ( ulong, runtime.max_live_slots );
103 15 : CFG_POP ( ulong, runtime.max_fork_width );
104 :
105 15 : CFG_POP ( ulong, runtime.program_cache.heap_size_mib );
106 15 : CFG_POP ( ulong, runtime.program_cache.mean_cache_entry_size );
107 :
108 15 : CFG_POP ( cstr, consensus.wait_for_supermajority_with_bank_hash );
109 :
110 15 : CFG_POP ( uint, snapshots.sources.max_local_full_effective_age );
111 15 : CFG_POP ( uint, snapshots.sources.max_local_incremental_age );
112 15 : CFG_POP ( bool, snapshots.sources.gossip.allow_any );
113 15 : CFG_POP_ARRAY( cstr, snapshots.sources.gossip.allow_list );
114 15 : CFG_POP_ARRAY( cstr, snapshots.sources.gossip.block_list );
115 15 : CFG_POP_ARRAY( cstr, snapshots.sources.servers );
116 15 : CFG_POP ( bool, snapshots.incremental_snapshots );
117 15 : CFG_POP ( bool, snapshots.genesis_download );
118 15 : CFG_POP ( uint, snapshots.max_full_snapshots_to_keep );
119 15 : CFG_POP ( uint, snapshots.max_incremental_snapshots_to_keep );
120 15 : CFG_POP ( uint, snapshots.max_retry_abort );
121 15 : CFG_POP ( uint, snapshots.min_download_speed_mibs );
122 15 : CFG_POP ( ulong, snapshots.wait_for_peers_timeout_seconds );
123 15 : CFG_POP ( ulong, snapshots.full_snapshot_interval_blocks );
124 15 : CFG_POP ( ulong, snapshots.incremental_snapshot_interval_blocks );
125 15 : CFG_POP ( ulong, snapshots.max_incremental_snapshot_accounts );
126 :
127 15 : CFG_POP ( bool, snapshots.server.enabled );
128 15 : CFG_POP ( cstr, snapshots.server.http_listen_address );
129 15 : CFG_POP ( uint, snapshots.server.http_listen_port );
130 15 : CFG_POP ( ulong, snapshots.server.max_http_connections );
131 15 : CFG_POP ( ulong, snapshots.server.idle_timeout_millis );
132 15 : CFG_POP ( ulong, snapshots.server.send_timeout_millis );
133 15 : CFG_POP ( ulong, snapshots.server.send_buffer_size_kib );
134 :
135 15 : CFG_POP ( bool, development.hard_fork_fatal );
136 15 : CFG_POP ( bool, development.fixed_fec_sets );
137 15 : CFG_POP ( bool, development.alpenglow );
138 :
139 15 : CFG_POP ( ushort, development.votor.quic_client_listen_port );
140 15 : CFG_POP ( ushort, development.votor.quic_server_listen_port );
141 :
142 15 : CFG_POP ( bool, development.genesis.validate_genesis_hash );
143 15 : CFG_POP ( ulong, development.genesis.max_file_size_mib );
144 :
145 15 : CFG_POP ( cstr, development.ledger_input.format );
146 15 : CFG_POP ( cstr, development.ledger_input.path );
147 15 : CFG_POP ( ulong, development.ledger_input.end_slot );
148 :
149 15 : CFG_POP ( cstr, development.backtest.affinity );
150 15 : CFG_POP ( ulong, development.backtest.root_distance );
151 :
152 15 : CFG_POP ( cstr, development.forktest.affinity );
153 :
154 15 : return config;
155 15 : }
156 :
157 : fd_config_t *
158 : fd_config_extract_pod( uchar * pod,
159 51 : fd_config_t * config ) {
160 51 : CFG_POP ( cstr, name );
161 51 : CFG_POP ( cstr, user );
162 :
163 51 : CFG_POP ( bool, telemetry );
164 :
165 51 : CFG_POP ( cstr, log.path );
166 51 : CFG_POP ( cstr, log.colorize );
167 51 : CFG_POP ( cstr, log.level_logfile );
168 51 : CFG_POP ( cstr, log.level_stderr );
169 51 : CFG_POP ( cstr, log.level_flush );
170 :
171 51 : if( FD_UNLIKELY( config->is_firedancer ) ) {
172 15 : CFG_POP ( cstr, paths.base );
173 15 : CFG_POP ( cstr, paths.identity_key );
174 15 : CFG_POP ( cstr, paths.vote_account );
175 15 : CFG_POP ( cstr, paths.snapshots );
176 15 : CFG_POP ( cstr, paths.genesis );
177 15 : CFG_POP ( cstr, paths.accounts );
178 15 : CFG_POP ( cstr, paths.shredb );
179 15 : CFG_POP ( cstr, paths.guidb );
180 36 : } else {
181 36 : CFG_POP1 ( cstr, scratch_directory, paths.base );
182 36 : CFG_POP1 ( cstr, ledger.path, frankendancer.paths.ledger );
183 36 : CFG_POP1 ( cstr, consensus.identity_path, paths.identity_key );
184 36 : CFG_POP1 ( cstr, consensus.vote_account_path, paths.vote_account );
185 36 : }
186 :
187 51 : CFG_POP_ARRAY( cstr, gossip.entrypoints );
188 51 : CFG_POP ( ushort, gossip.port );
189 :
190 51 : CFG_POP ( ushort, consensus.expected_shred_version );
191 51 : CFG_POP ( cstr, consensus.expected_genesis_hash );
192 51 : CFG_POP ( bool, consensus.wait_for_vote_to_start_leader );
193 :
194 51 : CFG_POP ( cstr, layout.affinity );
195 51 : CFG_POP ( cstr, layout.blocklist_cores );
196 51 : CFG_POP ( uint, layout.net_tile_count );
197 51 : CFG_POP ( uint, layout.quic_tile_count );
198 51 : CFG_POP ( uint, layout.verify_tile_count );
199 51 : CFG_POP ( uint, layout.shred_tile_count );
200 :
201 51 : CFG_POP ( cstr, hugetlbfs.mount_path );
202 51 : CFG_POP ( cstr, hugetlbfs.max_page_size );
203 51 : CFG_POP ( ulong, hugetlbfs.gigantic_page_threshold_mib );
204 :
205 51 : CFG_POP ( cstr, net.interface );
206 51 : CFG_POP ( cstr, net.bind_address );
207 51 : CFG_POP ( cstr, net.provider );
208 51 : CFG_POP ( uint, net.ingress_buffer_size );
209 51 : CFG_POP ( cstr, net.xdp.xdp_mode );
210 51 : CFG_POP ( boolau, net.xdp.xdp_zero_copy );
211 48 : CFG_POP ( cstr, net.xdp.poll_mode );
212 48 : CFG_POP ( uint, net.xdp.xdp_rx_queue_size );
213 48 : CFG_POP ( uint, net.xdp.xdp_tx_queue_size );
214 48 : CFG_POP ( uint, net.xdp.flush_timeout_micros );
215 48 : CFG_POP ( cstr, net.xdp.rss_queue_mode );
216 48 : CFG_POP ( boolau, net.xdp.listen_gre );
217 48 : CFG_POP ( boolau, net.xdp.native_bond );
218 48 : CFG_POP ( uint, net.mlx5.rx_queue_size );
219 48 : CFG_POP ( uint, net.mlx5.tx_queue_size );
220 48 : CFG_POP ( uint, net.socket.receive_buffer_size );
221 48 : CFG_POP ( uint, net.socket.send_buffer_size );
222 :
223 48 : CFG_POP ( ulong, tiles.netlink.max_routes );
224 48 : CFG_POP ( ulong, tiles.netlink.max_peer_routes );
225 48 : CFG_POP ( ulong, tiles.netlink.max_neighbors );
226 :
227 48 : CFG_POP ( ulong, tiles.gossip.max_entries );
228 :
229 48 : CFG_POP ( ushort, tiles.quic.regular_transaction_listen_port );
230 48 : CFG_POP ( ushort, tiles.quic.quic_transaction_listen_port );
231 48 : CFG_POP ( uint, tiles.quic.txn_reassembly_count );
232 48 : CFG_POP ( uint, tiles.quic.max_concurrent_connections );
233 48 : CFG_POP ( uint, tiles.quic.max_concurrent_handshakes );
234 48 : CFG_POP ( uint, tiles.quic.idle_timeout_millis );
235 48 : CFG_POP ( uint, tiles.quic.ack_delay_millis );
236 48 : CFG_POP ( bool, tiles.quic.retry );
237 48 : CFG_POP ( cstr, tiles.quic.ssl_key_log_file );
238 :
239 48 : CFG_POP ( uint, tiles.verify.signature_cache_size );
240 48 : CFG_POP ( uint, tiles.verify.receive_buffer_size );
241 48 : CFG_POP ( uint, tiles.verify.mtu );
242 :
243 48 : CFG_POP ( uint, tiles.dedup.signature_cache_size );
244 :
245 48 : CFG_POP ( bool, tiles.bundle.enabled );
246 48 : CFG_POP ( cstr, tiles.bundle.url );
247 48 : CFG_POP ( cstr, tiles.bundle.tls_domain_name );
248 48 : CFG_POP ( cstr, tiles.bundle.tip_distribution_program_addr );
249 48 : CFG_POP ( cstr, tiles.bundle.tip_payment_program_addr );
250 48 : CFG_POP ( cstr, tiles.bundle.tip_distribution_authority );
251 48 : CFG_POP ( uint, tiles.bundle.commission_bps );
252 48 : CFG_POP ( ulong, tiles.bundle.keepalive_interval_millis );
253 48 : CFG_POP ( bool, tiles.bundle.tls_cert_verify );
254 :
255 48 : CFG_POP ( uint, tiles.pack.max_pending_transactions );
256 48 : CFG_POP ( bool, tiles.pack.use_consumed_cus );
257 48 : CFG_POP ( cstr, tiles.pack.schedule_strategy );
258 48 : CFG_POP_ARRAY( cstr, tiles.pack.account_blocklist );
259 :
260 48 : CFG_POP ( ulong, tiles.replay.max_transaction_lookahead_buffer_size );
261 48 : CFG_POP_ARRAY( cstr, tiles.replay.enable_features );
262 :
263 48 : CFG_POP ( bool, tiles.pohh.lagged_consecutive_leader_start );
264 :
265 48 : CFG_POP ( uint, tiles.shred.max_pending_shred_sets );
266 48 : CFG_POP ( ushort, tiles.shred.shred_listen_port );
267 48 : CFG_POP_ARRAY( cstr, tiles.shred.additional_shred_destinations_retransmit );
268 48 : CFG_POP_ARRAY( cstr, tiles.shred.additional_shred_destinations_leader );
269 :
270 48 : CFG_POP ( cstr, tiles.metric.prometheus_listen_address );
271 48 : CFG_POP ( ushort, tiles.metric.prometheus_listen_port );
272 :
273 48 : CFG_POP ( cstr, tiles.event.url );
274 :
275 48 : CFG_POP ( bool, tiles.gui.enabled );
276 48 : CFG_POP ( cstr, tiles.gui.gui_listen_address );
277 48 : CFG_POP ( ushort, tiles.gui.gui_listen_port );
278 48 : CFG_POP ( ulong, tiles.gui.max_http_connections );
279 48 : CFG_POP ( ulong, tiles.gui.max_websocket_connections );
280 48 : CFG_POP ( ulong, tiles.gui.max_http_request_length );
281 48 : CFG_POP ( ulong, tiles.gui.send_buffer_size_mb );
282 48 : CFG_POP ( ulong, tiles.gui.db_size_gib );
283 :
284 48 : CFG_POP ( bool, tiles.rpc.enabled );
285 48 : CFG_POP ( cstr, tiles.rpc.rpc_listen_address );
286 48 : CFG_POP ( ushort, tiles.rpc.rpc_listen_port );
287 48 : CFG_POP ( ulong, tiles.rpc.max_http_connections );
288 48 : CFG_POP ( ulong, tiles.rpc.max_websocket_connections );
289 48 : CFG_POP ( ulong, tiles.rpc.max_http_request_length );
290 48 : CFG_POP ( ulong, tiles.rpc.send_buffer_size_mb );
291 48 : CFG_POP ( bool, tiles.rpc.delay_startup );
292 :
293 48 : CFG_POP ( ushort, tiles.repair.repair_client_listen_port );
294 48 : CFG_POP ( ulong, tiles.repair.slot_max );
295 :
296 48 : CFG_POP ( ulong, tiles.rotor.slot_max );
297 :
298 48 : CFG_POP ( bool, tiles.rserve.enabled );
299 48 : CFG_POP ( ushort, tiles.rserve.repair_serve_listen_port );
300 48 : CFG_POP ( ulong, tiles.rserve.shred_storage_limit_gib );
301 :
302 48 : CFG_POP ( ulong, capture.capture_start_slot );
303 48 : CFG_POP ( cstr, capture.solcap_capture );
304 48 : CFG_POP ( bool, capture.recent_only );
305 48 : CFG_POP ( ulong, capture.recent_slots_per_file );
306 48 : CFG_POP ( cstr, capture.dump_proto_dir );
307 48 : CFG_POP ( cstr, capture.dump_syscall_name_filter );
308 48 : CFG_POP ( cstr, capture.dump_instr_program_id_filter );
309 48 : CFG_POP ( bool, capture.dump_syscall_to_pb );
310 48 : CFG_POP ( bool, capture.dump_instr_to_pb );
311 48 : CFG_POP ( bool, capture.dump_txn_to_pb );
312 48 : CFG_POP ( bool, capture.dump_txn_as_fixture );
313 48 : CFG_POP ( bool, capture.dump_block_to_pb );
314 :
315 48 : CFG_POP ( ushort, tiles.txsend.txsend_src_port );
316 :
317 48 : CFG_POP ( bool, development.sandbox );
318 48 : CFG_POP ( bool, development.no_clone );
319 48 : CFG_POP ( cstr, development.core_dump );
320 48 : CFG_POP ( bool, development.no_agave );
321 48 : CFG_POP ( bool, development.bootstrap );
322 :
323 48 : CFG_POP ( bool, development.gossip.allow_private_address );
324 :
325 48 : CFG_POP ( ulong, development.genesis.hashes_per_tick );
326 48 : CFG_POP ( ulong, development.genesis.target_tick_duration_micros );
327 48 : CFG_POP ( ulong, development.genesis.ticks_per_slot );
328 48 : CFG_POP ( ulong, development.genesis.fund_initial_accounts );
329 48 : CFG_POP ( ulong, development.genesis.fund_initial_amount_lamports );
330 48 : CFG_POP ( ulong, development.genesis.vote_account_stake_lamports );
331 48 : CFG_POP ( bool, development.genesis.warmup_epochs );
332 :
333 48 : CFG_POP ( uint, development.bench.benchg_tile_count );
334 48 : CFG_POP ( uint, development.bench.benchs_tile_count );
335 48 : CFG_POP ( cstr, development.bench.affinity );
336 48 : CFG_POP ( bool, development.bench.larger_max_cost_per_block );
337 48 : CFG_POP ( bool, development.bench.larger_shred_limits_per_block );
338 48 : CFG_POP ( ulong, development.bench.disable_blockstore_from_slot );
339 48 : CFG_POP ( bool, development.bench.disable_status_cache );
340 :
341 48 : CFG_POP ( cstr, development.bundle.ssl_key_log_file );
342 48 : CFG_POP ( uint, development.bundle.buffer_size_kib );
343 48 : CFG_POP ( uint, development.bundle.ssl_heap_size_mib );
344 :
345 48 : CFG_POP ( bool, development.event.report_shreds );
346 48 : CFG_POP ( bool, development.event.report_transactions );
347 48 : CFG_POP ( bool, development.event.report_transaction_diffs );
348 :
349 48 : CFG_POP ( cstr, development.pktgen.affinity );
350 48 : CFG_POP ( cstr, development.pktgen.fake_dst_ip );
351 :
352 48 : CFG_POP ( cstr, development.udpecho.affinity );
353 :
354 48 : if( FD_UNLIKELY( !config->is_firedancer ) ) {
355 33 : CFG_POP ( bool, development.gui.websocket_compression );
356 33 : }
357 :
358 48 : CFG_POP ( ulong, development.accdb.partition_size_gib );
359 :
360 48 : CFG_POP ( bool, development.hugetlbfs.min_size );
361 :
362 48 : if( FD_UNLIKELY( config->is_firedancer ) ) {
363 15 : if( FD_UNLIKELY( !fd_config_extract_podf( pod, &config->firedancer ) ) ) return NULL;
364 15 : fd_config_check_configf( config, &config->firedancer );
365 33 : } else {
366 33 : if( FD_UNLIKELY( !fd_config_extract_podh( pod, &config->frankendancer ) ) ) return NULL;
367 33 : }
368 :
369 : /* Renamed config options */
370 :
371 36 : # define CFG_RENAMED( old_path, new_path ) \
372 468 : do { \
373 468 : char const * key = #old_path; \
374 468 : fd_pod_info_t info[1]; \
375 468 : if( FD_UNLIKELY( !fd_pod_query( pod, key, info ) ) ) { \
376 0 : FD_LOG_WARNING(( "Config option `%s` was renamed to `%s`. " \
377 0 : "Please update your config file.", \
378 0 : #old_path, #new_path )); \
379 0 : return NULL; \
380 0 : } \
381 468 : (void)config->new_path; /* assert new path exists */ \
382 468 : } while(0)
383 :
384 36 : CFG_RENAMED( tiles.net.interface, net.interface );
385 36 : CFG_RENAMED( tiles.net.bind_address, net.bind_address );
386 36 : CFG_RENAMED( tiles.net.provider, net.provider );
387 36 : CFG_RENAMED( tiles.net.xdp_mode, net.xdp.xdp_mode );
388 36 : CFG_RENAMED( tiles.net.xdp_zero_copy, net.xdp.xdp_zero_copy );
389 36 : CFG_RENAMED( tiles.net.xdp_rx_queue_size, net.xdp.xdp_rx_queue_size );
390 36 : CFG_RENAMED( tiles.net.xdp_tx_queue_size, net.xdp.xdp_tx_queue_size );
391 36 : CFG_RENAMED( tiles.net.flush_timeout_micros, net.xdp.flush_timeout_micros );
392 36 : CFG_RENAMED( tiles.net.send_buffer_size, net.ingress_buffer_size );
393 :
394 36 : CFG_RENAMED( development.net.provider, net.provider );
395 36 : CFG_RENAMED( development.net.sock_receive_buffer_size, net.socket.receive_buffer_size );
396 36 : CFG_RENAMED( development.net.sock_send_buffer_size, net.socket.send_buffer_size );
397 :
398 36 : CFG_RENAMED( tiles.repair.repair_intake_listen_port, tiles.repair.repair_client_listen_port );
399 :
400 36 : # undef CFG_RENAMED
401 :
402 36 : if( FD_UNLIKELY( !fdctl_pod_find_leftover( pod ) ) ) return NULL;
403 30 : return config;
404 36 : }
405 :
406 : #undef CFG_POP
407 : #undef CFG_ARRAY
|