]>
Commit | Line | Data |
---|---|---|
9b0a0ba9 OZ |
1 | /* |
2 | * BIRD Test -- Utils for testing parsing configuration file | |
3 | * | |
4 | * (c) 2015 CZ.NIC z.s.p.o. | |
5 | * | |
6 | * Can be freely distributed and used under the terms of the GNU GPL. | |
7 | */ | |
8 | ||
9 | #include <stdlib.h> | |
10 | #include <fcntl.h> | |
11 | #include <unistd.h> | |
12 | ||
13 | #include "test/birdtest.h" | |
14 | #include "test/bt-utils.h" | |
15 | ||
16 | #include "nest/bird.h" | |
17 | #include "nest/route.h" | |
18 | #include "nest/protocol.h" | |
19 | ||
20 | #include "sysdep/unix/unix.h" | |
21 | #include "sysdep/unix/krt.h" | |
22 | ||
23 | #include "nest/iface.h" | |
24 | #include "nest/locks.h" | |
25 | ||
26 | #include "filter/filter.h" | |
27 | ||
28 | #define BETWEEN(a, b, c) (((a) >= (b)) && ((a) <= (c))) | |
29 | ||
30 | static const byte *bt_config_parse_pos; | |
31 | static uint bt_config_parse_remain_len; | |
32 | ||
33 | /* This is cf_read_hook for hard-coded text configuration */ | |
34 | static int | |
35 | cf_static_read(byte *dest, uint max_len, int fd UNUSED) | |
36 | { | |
37 | if (max_len > bt_config_parse_remain_len) | |
38 | max_len = bt_config_parse_remain_len; | |
39 | memcpy(dest, bt_config_parse_pos, max_len); | |
40 | bt_config_parse_pos += max_len; | |
41 | bt_config_parse_remain_len -= max_len; | |
42 | return max_len; | |
43 | } | |
44 | ||
45 | /* This is cf_read_hook for reading configuration files, | |
46 | * function is copied from main.c, cf_read() */ | |
47 | static int | |
48 | cf_file_read(byte *dest, uint max_len, int fd) | |
49 | { | |
50 | int l = read(fd, dest, max_len); | |
51 | if (l < 0) | |
52 | cf_error("Read error"); | |
53 | return l; | |
54 | } | |
55 | ||
56 | void | |
57 | bt_bird_init(void) | |
58 | { | |
59 | if(bt_verbose) | |
60 | log_init_debug(""); | |
61 | log_switch(bt_verbose != 0, NULL, NULL); | |
62 | ||
63 | resource_init(); | |
64 | olock_init(); | |
65 | io_init(); | |
66 | rt_init(); | |
67 | if_init(); | |
68 | config_init(); | |
69 | ||
70 | protos_build(); | |
71 | proto_build(&proto_unix_kernel); | |
72 | proto_build(&proto_unix_iface); | |
73 | } | |
74 | ||
75 | void bt_bird_cleanup(void) | |
76 | { | |
77 | for (int i = 0; i < EAP_MAX; i++) | |
78 | attr_class_to_protocol[i] = NULL; | |
79 | ||
80 | config = new_config = NULL; | |
81 | } | |
82 | ||
83 | static char * | |
84 | bt_load_file(const char *filename, int quiet) | |
85 | { | |
86 | FILE *f = fopen(filename, "rb"); | |
87 | if (!quiet) | |
88 | bt_assert_msg(f != NULL, "Open %s", filename); | |
89 | ||
90 | if (f == NULL) | |
91 | return NULL; | |
92 | ||
93 | fseek(f, 0, SEEK_END); | |
94 | long file_size_ = ftell(f); | |
95 | fseek(f, 0, SEEK_SET); | |
96 | ||
97 | if (file_size_ < 0) | |
98 | return NULL; | |
99 | ||
100 | size_t file_size = file_size_; | |
101 | size_t read_size = 0; | |
102 | ||
103 | char *file_body = mb_allocz(&root_pool, file_size+1); | |
104 | ||
105 | /* XXX: copied from cf-lex.c */ | |
106 | errno=0; | |
107 | while ((read_size += fread(file_body+read_size, 1, file_size-read_size, f)) != file_size && ferror(f)) | |
108 | { | |
109 | bt_debug("iteration \n"); | |
110 | if(errno != EINTR) | |
111 | { | |
112 | bt_abort_msg("errno: %d", errno); | |
113 | break; | |
114 | } | |
115 | errno=0; | |
116 | clearerr(f); | |
117 | } | |
118 | fclose(f); | |
119 | ||
120 | if (!quiet) | |
121 | bt_assert_msg(read_size == file_size, "Read %s", filename); | |
122 | ||
123 | return file_body; | |
124 | } | |
125 | ||
126 | static void | |
127 | bt_show_cfg_error(const struct config *cfg) | |
128 | { | |
129 | int lino = 0; | |
130 | int lino_delta = 5; | |
131 | int lino_err = cfg->err_lino; | |
132 | ||
133 | const char *str = bt_load_file(cfg->err_file_name, 1); | |
134 | ||
135 | while (str && *str) | |
136 | { | |
137 | lino++; | |
138 | if (BETWEEN(lino, lino_err - lino_delta, lino_err + lino_delta)) | |
139 | bt_debug("%4u%s", lino, (lino_err == lino ? " >> " : " ")); | |
140 | do | |
141 | { | |
142 | if (BETWEEN(lino, lino_err - lino_delta, lino_err + lino_delta)) | |
143 | bt_debug("%c", *str); | |
144 | } while (*str && *(str++) != '\n'); | |
145 | } | |
146 | bt_debug("\n"); | |
147 | } | |
148 | ||
149 | static struct config * | |
150 | bt_config_parse__(struct config *cfg) | |
151 | { | |
152 | bt_assert_msg(config_parse(cfg) == 1, "Parse %s", cfg->file_name); | |
153 | ||
154 | if (cfg->err_msg) | |
155 | { | |
156 | bt_debug("Parse error %s, line %d: %s\n", cfg->err_file_name, cfg->err_lino, cfg->err_msg); | |
157 | bt_show_cfg_error(cfg); | |
158 | return NULL; | |
159 | } | |
160 | ||
161 | config_commit(cfg, RECONFIG_HARD, 0); | |
162 | new_config = cfg; | |
163 | ||
164 | return cfg; | |
165 | } | |
166 | ||
167 | struct config * | |
168 | bt_config_parse(const char *cfg_str) | |
169 | { | |
170 | struct config *cfg = config_alloc("configuration"); | |
171 | ||
172 | bt_config_parse_pos = cfg_str; | |
173 | bt_config_parse_remain_len = strlen(cfg_str); | |
174 | cf_read_hook = cf_static_read; | |
175 | ||
176 | return bt_config_parse__(cfg); | |
177 | } | |
178 | ||
179 | struct config * | |
180 | bt_config_file_parse(const char *filepath) | |
181 | { | |
182 | struct config *cfg = config_alloc(filepath); | |
183 | ||
184 | cfg->file_fd = open(filepath, O_RDONLY); | |
185 | bt_assert_msg(cfg->file_fd > 0, "Open %s", filepath); | |
186 | if (cfg->file_fd < 0) | |
187 | return NULL; | |
188 | ||
189 | cf_read_hook = cf_file_read; | |
190 | ||
191 | return bt_config_parse__(cfg); | |
192 | } | |
193 | ||
194 | /* | |
195 | * Returns @base raised to the power of @power. | |
196 | */ | |
197 | uint | |
198 | bt_naive_pow(uint base, uint power) | |
199 | { | |
200 | uint result = 1; | |
201 | uint i; | |
202 | for (i = 0; i < power; i++) | |
203 | result *= base; | |
204 | return result; | |
205 | } | |
206 | ||
207 | /** | |
208 | * bytes_to_hex - transform data into hexadecimal representation | |
209 | * @buf: preallocated string buffer | |
210 | * @in_data: data for transformation | |
211 | * @size: the length of @in_data | |
212 | * | |
213 | * This function transforms @in_data of length @size into hexadecimal | |
214 | * representation and writes it into @buf. | |
215 | */ | |
216 | void | |
217 | bt_bytes_to_hex(char *buf, const byte *in_data, size_t size) | |
218 | { | |
219 | size_t i; | |
220 | for(i = 0; i < size; i++) | |
221 | sprintf(buf + i*2, "%02x", in_data[i]); | |
222 | } | |
223 |