]>
Commit | Line | Data |
---|---|---|
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 | timer_init(); | |
66 | io_init(); | |
67 | rt_init(); | |
68 | if_init(); | |
69 | config_init(); | |
70 | ||
71 | protos_build(); | |
72 | proto_build(&proto_unix_kernel); | |
73 | proto_build(&proto_unix_iface); | |
74 | } | |
75 | ||
76 | void bt_bird_cleanup(void) | |
77 | { | |
78 | for (int i = 0; i < PROTOCOL__MAX; i++) | |
79 | class_to_protocol[i] = NULL; | |
80 | ||
81 | config = new_config = NULL; | |
82 | } | |
83 | ||
84 | static char * | |
85 | bt_load_file(const char *filename, int quiet) | |
86 | { | |
87 | FILE *f = fopen(filename, "rb"); | |
88 | if (!quiet) | |
89 | bt_assert_msg(f != NULL, "Open %s", filename); | |
90 | ||
91 | if (f == NULL) | |
92 | return NULL; | |
93 | ||
94 | fseek(f, 0, SEEK_END); | |
95 | long file_size_ = ftell(f); | |
96 | fseek(f, 0, SEEK_SET); | |
97 | ||
98 | if (file_size_ < 0) | |
99 | return NULL; | |
100 | ||
101 | size_t file_size = file_size_; | |
102 | size_t read_size = 0; | |
103 | ||
104 | char *file_body = mb_allocz(&root_pool, file_size+1); | |
105 | ||
106 | /* XXX: copied from cf-lex.c */ | |
107 | errno=0; | |
108 | while ((read_size += fread(file_body+read_size, 1, file_size-read_size, f)) != file_size && ferror(f)) | |
109 | { | |
110 | bt_debug("iteration \n"); | |
111 | if(errno != EINTR) | |
112 | { | |
113 | bt_abort_msg("errno: %d", errno); | |
114 | break; | |
115 | } | |
116 | errno=0; | |
117 | clearerr(f); | |
118 | } | |
119 | fclose(f); | |
120 | ||
121 | if (!quiet) | |
122 | bt_assert_msg(read_size == file_size, "Read %s", filename); | |
123 | ||
124 | return file_body; | |
125 | } | |
126 | ||
127 | static void | |
128 | bt_show_cfg_error(const struct config *cfg) | |
129 | { | |
130 | int lino = 0; | |
131 | int lino_delta = 5; | |
132 | int lino_err = cfg->err_lino; | |
133 | ||
134 | const char *str = bt_load_file(cfg->err_file_name, 1); | |
135 | ||
136 | while (str && *str) | |
137 | { | |
138 | lino++; | |
139 | if (BETWEEN(lino, lino_err - lino_delta, lino_err + lino_delta)) | |
140 | bt_debug("%4u%s", lino, (lino_err == lino ? " >> " : " ")); | |
141 | do | |
142 | { | |
143 | if (BETWEEN(lino, lino_err - lino_delta, lino_err + lino_delta)) | |
144 | bt_debug("%c", *str); | |
145 | } while (*str && *(str++) != '\n'); | |
146 | } | |
147 | bt_debug("\n"); | |
148 | } | |
149 | ||
150 | static struct config * | |
151 | bt_config_parse__(struct config *cfg) | |
152 | { | |
153 | bt_assert_msg(config_parse(cfg) == 1, "Parse %s", cfg->file_name); | |
154 | ||
155 | if (cfg->err_msg) | |
156 | { | |
157 | bt_debug("Parse error %s, line %d: %s\n", cfg->err_file_name, cfg->err_lino, cfg->err_msg); | |
158 | bt_show_cfg_error(cfg); | |
159 | return NULL; | |
160 | } | |
161 | ||
162 | config_commit(cfg, RECONFIG_HARD, 0); | |
163 | new_config = cfg; | |
164 | ||
165 | return cfg; | |
166 | } | |
167 | ||
168 | struct config * | |
169 | bt_config_parse(const char *cfg_str) | |
170 | { | |
171 | struct config *cfg = config_alloc("configuration"); | |
172 | ||
173 | bt_config_parse_pos = cfg_str; | |
174 | bt_config_parse_remain_len = strlen(cfg_str); | |
175 | cf_read_hook = cf_static_read; | |
176 | ||
177 | return bt_config_parse__(cfg); | |
178 | } | |
179 | ||
180 | struct config * | |
181 | bt_config_file_parse(const char *filepath) | |
182 | { | |
183 | struct config *cfg = config_alloc(filepath); | |
184 | ||
185 | cfg->file_fd = open(filepath, O_RDONLY); | |
186 | bt_assert_msg(cfg->file_fd > 0, "Open %s", filepath); | |
187 | if (cfg->file_fd < 0) | |
188 | return NULL; | |
189 | ||
190 | cf_read_hook = cf_file_read; | |
191 | ||
192 | return bt_config_parse__(cfg); | |
193 | } | |
194 | ||
195 | /* | |
196 | * Returns @base raised to the power of @power. | |
197 | */ | |
198 | uint | |
199 | bt_naive_pow(uint base, uint power) | |
200 | { | |
201 | uint result = 1; | |
202 | uint i; | |
203 | for (i = 0; i < power; i++) | |
204 | result *= base; | |
205 | return result; | |
206 | } | |
207 | ||
208 | /** | |
209 | * bytes_to_hex - transform data into hexadecimal representation | |
210 | * @buf: preallocated string buffer | |
211 | * @in_data: data for transformation | |
212 | * @size: the length of @in_data | |
213 | * | |
214 | * This function transforms @in_data of length @size into hexadecimal | |
215 | * representation and writes it into @buf. | |
216 | */ | |
217 | void | |
218 | bt_bytes_to_hex(char *buf, const byte *in_data, size_t size) | |
219 | { | |
220 | size_t i; | |
221 | for(i = 0; i < size; i++) | |
222 | sprintf(buf + i*2, "%02x", in_data[i]); | |
223 | } | |
224 |