BadVPN – Blame information for rev 1

Subversion Repositories:
Rev:
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 }