BadVPN – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /** |
2 | * @file ncd.c |
||
3 | * @author Ambroz Bizjak <ambrop7@gmail.com> |
||
4 | * |
||
5 | * @section LICENSE |
||
6 | * |
||
7 | * Redistribution and use in source and binary forms, with or without |
||
8 | * modification, are permitted provided that the following conditions are met: |
||
9 | * 1. Redistributions of source code must retain the above copyright |
||
10 | * notice, this list of conditions and the following disclaimer. |
||
11 | * 2. Redistributions in binary form must reproduce the above copyright |
||
12 | * notice, this list of conditions and the following disclaimer in the |
||
13 | * documentation and/or other materials provided with the distribution. |
||
14 | * 3. Neither the name of the author nor the |
||
15 | * names of its contributors may be used to endorse or promote products |
||
16 | * derived from this software without specific prior written permission. |
||
17 | * |
||
18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
||
19 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
||
20 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
||
21 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
||
22 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||
23 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||
24 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
||
25 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||
26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||
27 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||
28 | */ |
||
29 | |||
30 | #include <stdint.h> |
||
31 | #include <stdio.h> |
||
32 | #include <string.h> |
||
33 | #include <stdlib.h> |
||
34 | |||
35 | #include <misc/version.h> |
||
36 | #include <misc/loglevel.h> |
||
37 | #include <misc/open_standard_streams.h> |
||
38 | #include <misc/string_begins_with.h> |
||
39 | #include <base/BLog.h> |
||
40 | #include <system/BReactor.h> |
||
41 | #include <system/BSignal.h> |
||
42 | #include <system/BProcess.h> |
||
43 | #include <udevmonitor/NCDUdevManager.h> |
||
44 | #include <random/BRandom2.h> |
||
45 | #include <ncd/NCDInterpreter.h> |
||
46 | #include <ncd/NCDBuildProgram.h> |
||
47 | |||
48 | #ifdef BADVPN_USE_SYSLOG |
||
49 | #include <base/BLog_syslog.h> |
||
50 | #endif |
||
51 | |||
52 | #include "ncd.h" |
||
53 | |||
54 | #include <generated/blog_channel_ncd.h> |
||
55 | |||
56 | #define LOGGER_STDOUT 1 |
||
57 | #define LOGGER_STDERR 2 |
||
58 | #define LOGGER_SYSLOG 3 |
||
59 | |||
60 | // command-line options |
||
61 | static struct { |
||
62 | int help; |
||
63 | int version; |
||
64 | int logger; |
||
65 | #ifdef BADVPN_USE_SYSLOG |
||
66 | char *logger_syslog_facility; |
||
67 | char *logger_syslog_ident; |
||
68 | #endif |
||
69 | int loglevel; |
||
70 | int loglevels[BLOG_NUM_CHANNELS]; |
||
71 | char *config_file; |
||
72 | int syntax_only; |
||
73 | int retry_time; |
||
74 | int signal_exit_code; |
||
75 | int no_udev; |
||
76 | char **extra_args; |
||
77 | int num_extra_args; |
||
78 | } options; |
||
79 | |||
80 | // reactor |
||
81 | static BReactor reactor; |
||
82 | |||
83 | // process manager |
||
84 | static BProcessManager manager; |
||
85 | |||
86 | // udev manager |
||
87 | static NCDUdevManager umanager; |
||
88 | |||
89 | // random number generator |
||
90 | static BRandom2 random2; |
||
91 | |||
92 | // interpreter |
||
93 | static NCDInterpreter interpreter; |
||
94 | |||
95 | // forward declarations of functions |
||
96 | static void print_help (const char *name); |
||
97 | static void print_version (void); |
||
98 | static int parse_arguments (int argc, char *argv[]); |
||
99 | static void signal_handler (void *unused); |
||
100 | static void interpreter_handler_finished (void *user, int exit_code); |
||
101 | |||
102 | int main (int argc, char **argv) |
||
103 | { |
||
104 | if (argc <= 0) { |
||
105 | return 1; |
||
106 | } |
||
107 | |||
108 | int main_exit_code = 1; |
||
109 | |||
110 | // open standard streams |
||
111 | open_standard_streams(); |
||
112 | |||
113 | // parse command-line arguments |
||
114 | if (!parse_arguments(argc, argv)) { |
||
115 | fprintf(stderr, "Failed to parse arguments\n"); |
||
116 | print_help(argv[0]); |
||
117 | goto fail0; |
||
118 | } |
||
119 | |||
120 | // handle --help and --version |
||
121 | if (options.help) { |
||
122 | print_version(); |
||
123 | print_help(argv[0]); |
||
124 | return 0; |
||
125 | } |
||
126 | if (options.version) { |
||
127 | print_version(); |
||
128 | return 0; |
||
129 | } |
||
130 | |||
131 | // initialize logger |
||
132 | switch (options.logger) { |
||
133 | case LOGGER_STDOUT: |
||
134 | BLog_InitStdout(); |
||
135 | break; |
||
136 | case LOGGER_STDERR: |
||
137 | BLog_InitStderr(); |
||
138 | break; |
||
139 | #ifdef BADVPN_USE_SYSLOG |
||
140 | case LOGGER_SYSLOG: |
||
141 | if (!BLog_InitSyslog(options.logger_syslog_ident, options.logger_syslog_facility)) { |
||
142 | fprintf(stderr, "Failed to initialize syslog logger\n"); |
||
143 | goto fail0; |
||
144 | } |
||
145 | break; |
||
146 | #endif |
||
147 | default: |
||
148 | ASSERT(0); |
||
149 | } |
||
150 | |||
151 | // configure logger channels |
||
152 | for (int i = 0; i < BLOG_NUM_CHANNELS; i++) { |
||
153 | if (options.loglevels[i] >= 0) { |
||
154 | BLog_SetChannelLoglevel(i, options.loglevels[i]); |
||
155 | } |
||
156 | else if (options.loglevel >= 0) { |
||
157 | BLog_SetChannelLoglevel(i, options.loglevel); |
||
158 | } else { |
||
159 | BLog_SetChannelLoglevel(i, DEFAULT_LOGLEVEL); |
||
160 | } |
||
161 | } |
||
162 | |||
163 | BLog(BLOG_NOTICE, "initializing "GLOBAL_PRODUCT_NAME" "PROGRAM_NAME" "GLOBAL_VERSION); |
||
164 | |||
165 | // initialize network |
||
166 | if (!BNetwork_GlobalInit()) { |
||
167 | BLog(BLOG_ERROR, "BNetwork_GlobalInit failed"); |
||
168 | goto fail1; |
||
169 | } |
||
170 | |||
171 | // init time |
||
172 | BTime_Init(); |
||
173 | |||
174 | // init reactor |
||
175 | if (!BReactor_Init(&reactor)) { |
||
176 | BLog(BLOG_ERROR, "BReactor_Init failed"); |
||
177 | goto fail1; |
||
178 | } |
||
179 | |||
180 | // init process manager |
||
181 | if (!BProcessManager_Init(&manager, &reactor)) { |
||
182 | BLog(BLOG_ERROR, "BProcessManager_Init failed"); |
||
183 | goto fail2; |
||
184 | } |
||
185 | |||
186 | // init udev manager |
||
187 | NCDUdevManager_Init(&umanager, options.no_udev, &reactor, &manager); |
||
188 | |||
189 | // init random number generator |
||
190 | if (!BRandom2_Init(&random2, BRANDOM2_INIT_LAZY)) { |
||
191 | BLog(BLOG_ERROR, "BRandom2_Init failed"); |
||
192 | goto fail3; |
||
193 | } |
||
194 | |||
195 | // setup signal handler |
||
196 | if (!BSignal_Init(&reactor, signal_handler, NULL)) { |
||
197 | BLog(BLOG_ERROR, "BSignal_Init failed"); |
||
198 | goto fail4; |
||
199 | } |
||
200 | |||
201 | // build program |
||
202 | NCDProgram program; |
||
203 | if (!NCDBuildProgram_Build(options.config_file, &program)) { |
||
204 | BLog(BLOG_ERROR, "failed to build program"); |
||
205 | goto fail5; |
||
206 | } |
||
207 | |||
208 | // setup interpreter parameters |
||
209 | struct NCDInterpreter_params params; |
||
210 | params.handler_finished = interpreter_handler_finished; |
||
211 | params.user = NULL; |
||
212 | params.retry_time = options.retry_time; |
||
213 | params.extra_args = options.extra_args; |
||
214 | params.num_extra_args = options.num_extra_args; |
||
215 | params.reactor = &reactor; |
||
216 | params.manager = &manager; |
||
217 | params.umanager = &umanager; |
||
218 | params.random2 = &random2; |
||
219 | |||
220 | // initialize interpreter |
||
221 | if (!NCDInterpreter_Init(&interpreter, program, params)) { |
||
222 | goto fail5; |
||
223 | } |
||
224 | |||
225 | // don't enter event loop if syntax check is requested |
||
226 | if (options.syntax_only) { |
||
227 | main_exit_code = 0; |
||
228 | goto fail6; |
||
229 | } |
||
230 | |||
231 | BLog(BLOG_NOTICE, "entering event loop"); |
||
232 | |||
233 | // enter event loop |
||
234 | main_exit_code = BReactor_Exec(&reactor); |
||
235 | |||
236 | fail6: |
||
237 | // free interpreter |
||
238 | NCDInterpreter_Free(&interpreter); |
||
239 | fail5: |
||
240 | // remove signal handler |
||
241 | BSignal_Finish(); |
||
242 | fail4: |
||
243 | // free random number generator |
||
244 | BRandom2_Free(&random2); |
||
245 | fail3: |
||
246 | // free udev manager |
||
247 | NCDUdevManager_Free(&umanager); |
||
248 | |||
249 | // free process manager |
||
250 | BProcessManager_Free(&manager); |
||
251 | fail2: |
||
252 | // free reactor |
||
253 | BReactor_Free(&reactor); |
||
254 | fail1: |
||
255 | // free logger |
||
256 | BLog(BLOG_NOTICE, "exiting"); |
||
257 | BLog_Free(); |
||
258 | fail0: |
||
259 | // finish objects |
||
260 | DebugObjectGlobal_Finish(); |
||
261 | |||
262 | return main_exit_code; |
||
263 | } |
||
264 | |||
265 | void print_help (const char *name) |
||
266 | { |
||
267 | printf( |
||
268 | "Usage:\n" |
||
269 | " %s\n" |
||
270 | " [--help]\n" |
||
271 | " [--version]\n" |
||
272 | " [--logger <stdout/stderr/syslog>]\n" |
||
273 | " (logger=syslog?\n" |
||
274 | " [--syslog-facility <string>]\n" |
||
275 | " [--syslog-ident <string>]\n" |
||
276 | " )\n" |
||
277 | " [--loglevel <0-5/none/error/warning/notice/info/debug>]\n" |
||
278 | " [--channel-loglevel <channel-name> <0-5/none/error/warning/notice/info/debug>] ...\n" |
||
279 | " [--retry-time <ms>]\n" |
||
280 | " [--no-udev]\n" |
||
281 | " [--config-file <ncd_program_file>]\n" |
||
282 | " [--syntax-only]\n" |
||
283 | " [--signal-exit-code <number>]\n" |
||
284 | " [-- program_args...]\n" |
||
285 | " [<ncd_program_file> program_args...]\n" , |
||
286 | name |
||
287 | ); |
||
288 | } |
||
289 | |||
290 | void print_version (void) |
||
291 | { |
||
292 | printf(GLOBAL_PRODUCT_NAME" "PROGRAM_NAME" "GLOBAL_VERSION"\n"GLOBAL_COPYRIGHT_NOTICE"\n"); |
||
293 | } |
||
294 | |||
295 | int parse_arguments (int argc, char *argv[]) |
||
296 | { |
||
297 | if (argc <= 0) { |
||
298 | return 0; |
||
299 | } |
||
300 | |||
301 | options.help = 0; |
||
302 | options.version = 0; |
||
303 | options.logger = LOGGER_STDERR; |
||
304 | #ifdef BADVPN_USE_SYSLOG |
||
305 | options.logger_syslog_facility = "daemon"; |
||
306 | options.logger_syslog_ident = argv[0]; |
||
307 | #endif |
||
308 | options.loglevel = -1; |
||
309 | for (int i = 0; i < BLOG_NUM_CHANNELS; i++) { |
||
310 | options.loglevels[i] = -1; |
||
311 | } |
||
312 | options.config_file = NULL; |
||
313 | options.syntax_only = 0; |
||
314 | options.retry_time = DEFAULT_RETRY_TIME; |
||
315 | options.signal_exit_code = DEFAULT_SIGNAL_EXIT_CODE; |
||
316 | options.no_udev = 0; |
||
317 | options.extra_args = NULL; |
||
318 | options.num_extra_args = 0; |
||
319 | |||
320 | for (int i = 1; i < argc; i++) { |
||
321 | char *arg = argv[i]; |
||
322 | if (!strcmp(arg, "--help")) { |
||
323 | options.help = 1; |
||
324 | } |
||
325 | else if (!strcmp(arg, "--version")) { |
||
326 | options.version = 1; |
||
327 | } |
||
328 | else if (!strcmp(arg, "--logger")) { |
||
329 | if (1 >= argc - i) { |
||
330 | fprintf(stderr, "%s: requires an argument\n", arg); |
||
331 | return 0; |
||
332 | } |
||
333 | char *arg2 = argv[i + 1]; |
||
334 | if (!strcmp(arg2, "stdout")) { |
||
335 | options.logger = LOGGER_STDOUT; |
||
336 | } |
||
337 | else if (!strcmp(arg2, "stderr")) { |
||
338 | options.logger = LOGGER_STDERR; |
||
339 | } |
||
340 | #ifdef BADVPN_USE_SYSLOG |
||
341 | else if (!strcmp(arg2, "syslog")) { |
||
342 | options.logger = LOGGER_SYSLOG; |
||
343 | } |
||
344 | #endif |
||
345 | else { |
||
346 | fprintf(stderr, "%s: wrong argument\n", arg); |
||
347 | return 0; |
||
348 | } |
||
349 | i++; |
||
350 | } |
||
351 | #ifdef BADVPN_USE_SYSLOG |
||
352 | else if (!strcmp(arg, "--syslog-facility")) { |
||
353 | if (1 >= argc - i) { |
||
354 | fprintf(stderr, "%s: requires an argument\n", arg); |
||
355 | return 0; |
||
356 | } |
||
357 | options.logger_syslog_facility = argv[i + 1]; |
||
358 | i++; |
||
359 | } |
||
360 | else if (!strcmp(arg, "--syslog-ident")) { |
||
361 | if (1 >= argc - i) { |
||
362 | fprintf(stderr, "%s: requires an argument\n", arg); |
||
363 | return 0; |
||
364 | } |
||
365 | options.logger_syslog_ident = argv[i + 1]; |
||
366 | i++; |
||
367 | } |
||
368 | #endif |
||
369 | else if (!strcmp(arg, "--loglevel")) { |
||
370 | if (1 >= argc - i) { |
||
371 | fprintf(stderr, "%s: requires an argument\n", arg); |
||
372 | return 0; |
||
373 | } |
||
374 | if ((options.loglevel = parse_loglevel(argv[i + 1])) < 0) { |
||
375 | fprintf(stderr, "%s: wrong argument\n", arg); |
||
376 | return 0; |
||
377 | } |
||
378 | i++; |
||
379 | } |
||
380 | else if (!strcmp(arg, "--channel-loglevel")) { |
||
381 | if (2 >= argc - i) { |
||
382 | fprintf(stderr, "%s: requires two arguments\n", arg); |
||
383 | return 0; |
||
384 | } |
||
385 | int channel = BLogGlobal_GetChannelByName(argv[i + 1]); |
||
386 | if (channel < 0) { |
||
387 | fprintf(stderr, "%s: wrong channel argument\n", arg); |
||
388 | return 0; |
||
389 | } |
||
390 | int loglevel = parse_loglevel(argv[i + 2]); |
||
391 | if (loglevel < 0) { |
||
392 | fprintf(stderr, "%s: wrong loglevel argument\n", arg); |
||
393 | return 0; |
||
394 | } |
||
395 | options.loglevels[channel] = loglevel; |
||
396 | i += 2; |
||
397 | } |
||
398 | else if (!strcmp(arg, "--config-file")) { |
||
399 | if (1 >= argc - i) { |
||
400 | fprintf(stderr, "%s: requires an argument\n", arg); |
||
401 | return 0; |
||
402 | } |
||
403 | options.config_file = argv[i + 1]; |
||
404 | i++; |
||
405 | } |
||
406 | else if (!strcmp(arg, "--syntax-only")) { |
||
407 | options.syntax_only = 1; |
||
408 | } |
||
409 | else if (!strcmp(arg, "--retry-time")) { |
||
410 | if (1 >= argc - i) { |
||
411 | fprintf(stderr, "%s: requires an argument\n", arg); |
||
412 | return 0; |
||
413 | } |
||
414 | if ((options.retry_time = atoi(argv[i + 1])) < 0) { |
||
415 | fprintf(stderr, "%s: wrong argument\n", arg); |
||
416 | return 0; |
||
417 | } |
||
418 | i++; |
||
419 | } |
||
420 | else if (!strcmp(arg, "--signal-exit-code")) { |
||
421 | if (1 >= argc - i) { |
||
422 | fprintf(stderr, "%s: requires an argument\n", arg); |
||
423 | return 0; |
||
424 | } |
||
425 | if ((options.signal_exit_code = atoi(argv[i + 1])) < 0) { |
||
426 | fprintf(stderr, "%s: wrong argument\n", arg); |
||
427 | return 0; |
||
428 | } |
||
429 | i++; |
||
430 | } |
||
431 | else if (!strcmp(arg, "--no-udev")) { |
||
432 | options.no_udev = 1; |
||
433 | } |
||
434 | else if (!strcmp(arg, "--")) { |
||
435 | options.extra_args = &argv[i + 1]; |
||
436 | options.num_extra_args = argc - i - 1; |
||
437 | i += options.num_extra_args; |
||
438 | } |
||
439 | else if (!string_begins_with(arg, "--")) { |
||
440 | if (options.config_file) { |
||
441 | fprintf(stderr, "%s: program is already specified (did you mean to use -- ?)\n", arg); |
||
442 | return 0; |
||
443 | } |
||
444 | options.config_file = argv[i]; |
||
445 | options.extra_args = &argv[i + 1]; |
||
446 | options.num_extra_args = argc - i - 1; |
||
447 | i += options.num_extra_args; |
||
448 | } |
||
449 | else { |
||
450 | fprintf(stderr, "unknown option: %s\n", arg); |
||
451 | return 0; |
||
452 | } |
||
453 | } |
||
454 | |||
455 | if (options.help || options.version) { |
||
456 | return 1; |
||
457 | } |
||
458 | |||
459 | if (!options.config_file) { |
||
460 | fprintf(stderr, "No program is specified.\n"); |
||
461 | return 0; |
||
462 | } |
||
463 | |||
464 | return 1; |
||
465 | } |
||
466 | |||
467 | void signal_handler (void *unused) |
||
468 | { |
||
469 | BLog(BLOG_NOTICE, "termination requested"); |
||
470 | |||
471 | NCDInterpreter_RequestShutdown(&interpreter, options.signal_exit_code); |
||
472 | } |
||
473 | |||
474 | void interpreter_handler_finished (void *user, int exit_code) |
||
475 | { |
||
476 | BReactor_Quit(&reactor, exit_code); |
||
477 | } |