loading ruby scripts specified at command line
[strongswan.git] / src / dumm / irdumm.c
1 /*
2 * Copyright (C) 2008 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include <stdio.h>
17 #include <signal.h>
18 #include <unistd.h>
19 #include <fcntl.h>
20
21 #include <library.h>
22 #include <dumm.h>
23 #include <debug.h>
24
25 #undef PACKAGE_NAME
26 #undef PACKAGE_TARNAME
27 #undef PACKAGE_VERSION
28 #undef PACKAGE_STRING
29 #include <ruby.h>
30
31 dumm_t *dumm;
32
33 VALUE rbm_dumm;
34 VALUE rbc_guest;
35 VALUE rbc_bridge;
36 VALUE rbc_iface;
37 VALUE rbc_template;
38
39 /**
40 * Guest invocation callback
41 */
42 static pid_t invoke(void *null, guest_t *guest, char *args[], int argc)
43 {
44 pid_t pid;
45
46 args[argc] = "con0=xterm";
47
48 pid = fork();
49 switch (pid)
50 {
51 case 0: /* child */
52 dup2(open("/dev/null", 0), 1);
53 dup2(open("/dev/null", 0), 2);
54 execvp(args[0], args);
55 /* FALL */
56 case -1:
57 return 0;
58 default:
59 return pid;
60 }
61 }
62
63 /**
64 * SIGCHLD signal handler
65 */
66 static void sigchld_handler(int signal, siginfo_t *info, void* ptr)
67 {
68 enumerator_t *enumerator;
69 guest_t *guest;
70
71 enumerator = dumm->create_guest_enumerator(dumm);
72 while (enumerator->enumerate(enumerator, &guest))
73 {
74 if (guest->get_pid(guest) == info->si_pid)
75 {
76 guest->sigchild(guest);
77 break;
78 }
79 }
80 enumerator->destroy(enumerator);
81 }
82
83 /**
84 * SIGINT/SEGV/TERM signal handler
85 */
86 static void sigint_handler(int signal, siginfo_t *info, void* ptr)
87 {
88 struct sigaction action;
89
90 dumm->destroy(dumm);
91
92 action.sa_handler = SIG_DFL;
93 action.sa_flags = 0;
94 sigaction(SIGCHLD, &action, NULL);
95
96 library_deinit();
97 exit(0);
98 }
99
100 /**
101 * Guest bindings
102 */
103 static VALUE guest_get(VALUE class, VALUE key)
104 {
105 enumerator_t *enumerator;
106 guest_t *guest, *found = NULL;
107
108 enumerator = dumm->create_guest_enumerator(dumm);
109 while (enumerator->enumerate(enumerator, &guest))
110 {
111 if (streq(guest->get_name(guest), StringValuePtr(key)))
112 {
113 found = guest;
114 break;
115 }
116 }
117 enumerator->destroy(enumerator);
118 if (!found)
119 {
120 rb_raise(rb_eRuntimeError, "guest not found");
121 }
122 return Data_Wrap_Struct(class, NULL, NULL, found);
123 }
124
125 static VALUE guest_each(int argc, VALUE *argv, VALUE class)
126 {
127 enumerator_t *enumerator;
128 guest_t *guest;
129
130 if (!rb_block_given_p())
131 {
132 rb_raise(rb_eArgError, "must be called with a block");
133 }
134 enumerator = dumm->create_guest_enumerator(dumm);
135 while (enumerator->enumerate(enumerator, &guest))
136 {
137 rb_yield(Data_Wrap_Struct(class, NULL, NULL, guest));
138 }
139 enumerator->destroy(enumerator);
140 return class;
141 }
142
143 static VALUE guest_new(VALUE class, VALUE name, VALUE kernel,
144 VALUE master, VALUE mem)
145 {
146 guest_t *guest;
147
148 guest = dumm->create_guest(dumm, StringValuePtr(name), StringValuePtr(kernel),
149 StringValuePtr(master), FIX2INT(mem));
150 if (!guest)
151 {
152 rb_raise(rb_eRuntimeError, "creating guest failed");
153 }
154 return Data_Wrap_Struct(class, NULL, NULL, guest);
155 }
156
157 static VALUE guest_to_s(VALUE self)
158 {
159 guest_t *guest;
160
161 Data_Get_Struct(self, guest_t, guest);
162 return rb_str_new2(guest->get_name(guest));
163 }
164
165 static VALUE guest_start(VALUE self)
166 {
167 guest_t *guest;
168
169 Data_Get_Struct(self, guest_t, guest);
170
171 if (!guest->start(guest, invoke, NULL, NULL))
172 {
173 rb_raise(rb_eRuntimeError, "starting guest failed");
174 }
175 return self;
176 }
177
178 static VALUE guest_stop(VALUE self)
179 {
180 guest_t *guest;
181
182 Data_Get_Struct(self, guest_t, guest);
183 guest->stop(guest, NULL);
184 return self;
185 }
186
187 typedef struct {
188 char buf[1024];
189 char *top;
190 } exec_t;
191
192 static void exec_cb(exec_t *exec, char *buf, size_t len)
193 {
194 size_t to_copy;
195 char *nl;
196
197 while (len)
198 {
199 to_copy = min(len, sizeof(exec->buf) - (exec->top - exec->buf));
200 memcpy(exec->top, buf, to_copy);
201 exec->top += to_copy;
202 len -= to_copy;
203 buf += to_copy;
204
205 while (TRUE)
206 {
207 nl = memchr(exec->buf, '\n', exec->top - exec->buf);
208 if (!nl)
209 {
210 break;
211 }
212 if (nl > exec->buf)
213 {
214 rb_yield(rb_str_new(exec->buf, nl - exec->buf));
215 }
216 nl++;
217 to_copy = exec->top - nl;
218 memmove(exec->buf, nl, to_copy);
219 exec->top = exec->buf + to_copy;
220 }
221 if (exec->top >= exec->buf + sizeof(exec->buf))
222 {
223 rb_yield(rb_str_new(exec->buf, sizeof(exec->buf)));
224 exec->top = exec->buf;
225 }
226 }
227 }
228
229 static VALUE guest_exec(VALUE self, VALUE cmd)
230 {
231 guest_t *guest;
232 exec_t exec;
233 bool block;
234
235 block = rb_block_given_p();
236 exec.top = exec.buf;
237 Data_Get_Struct(self, guest_t, guest);
238 if (guest->exec(guest, block ? (void*)exec_cb : NULL, &exec,
239 "%s", StringValuePtr(cmd)) != 0)
240 {
241 rb_raise(rb_eRuntimeError, "executing command failed");
242 }
243 if (exec.top != exec.buf && block)
244 {
245 rb_yield(rb_str_new(exec.buf, exec.top - exec.buf));
246 }
247 return self;
248 }
249
250 static VALUE guest_add_iface(VALUE self, VALUE name)
251 {
252 guest_t *guest;
253 iface_t *iface;
254
255 Data_Get_Struct(self, guest_t, guest);
256 iface = guest->create_iface(guest, StringValuePtr(name));
257 if (!iface)
258 {
259 rb_raise(rb_eRuntimeError, "adding interface failed");
260 }
261 return Data_Wrap_Struct(rbc_iface, NULL, NULL, iface);
262 }
263
264 static VALUE guest_get_iface(VALUE self, VALUE key)
265 {
266 enumerator_t *enumerator;
267 iface_t *iface, *found = NULL;
268 guest_t *guest;
269
270 Data_Get_Struct(self, guest_t, guest);
271 enumerator = guest->create_iface_enumerator(guest);
272 while (enumerator->enumerate(enumerator, &iface))
273 {
274 if (streq(iface->get_guestif(iface), StringValuePtr(key)))
275 {
276 found = iface;
277 break;
278 }
279 }
280 enumerator->destroy(enumerator);
281 if (!found)
282 {
283 rb_raise(rb_eRuntimeError, "interface not found");
284 }
285 return Data_Wrap_Struct(rbc_iface, NULL, NULL, iface);
286 }
287
288 static VALUE guest_each_iface(int argc, VALUE *argv, VALUE self)
289 {
290 enumerator_t *enumerator;
291 guest_t *guest;
292 iface_t *iface;
293
294 if (!rb_block_given_p())
295 {
296 rb_raise(rb_eArgError, "must be called with a block");
297 }
298 Data_Get_Struct(self, guest_t, guest);
299 enumerator = guest->create_iface_enumerator(guest);
300 while (enumerator->enumerate(enumerator, &iface))
301 {
302 rb_yield(Data_Wrap_Struct(rbc_iface, NULL, NULL, iface));
303 }
304 enumerator->destroy(enumerator);
305 return self;
306 }
307
308 static VALUE guest_delete(VALUE self)
309 {
310 guest_t *guest;
311
312 Data_Get_Struct(self, guest_t, guest);
313 dumm->delete_guest(dumm, guest);
314 return Qnil;
315 }
316
317 static void guest_init()
318 {
319 rbc_guest = rb_define_class_under(rbm_dumm , "Guest", rb_cObject);
320 rb_define_singleton_method(rbc_guest, "[]", guest_get, 1);
321 rb_define_singleton_method(rbc_guest, "each", guest_each, -1);
322 rb_define_singleton_method(rbc_guest, "new", guest_new, 4);
323 rb_define_method(rbc_guest, "to_s", guest_to_s, 0);
324 rb_define_method(rbc_guest, "start", guest_start, 0);
325 rb_define_method(rbc_guest, "stop", guest_stop, 0);
326 rb_define_method(rbc_guest, "exec", guest_exec, 1);
327 rb_define_method(rbc_guest, "add", guest_add_iface, 1);
328 rb_define_method(rbc_guest, "[]", guest_get_iface, 1);
329 rb_define_method(rbc_guest, "each", guest_each_iface, -1);
330 rb_define_method(rbc_guest, "delete", guest_delete, 0);
331 rb_include_module(rb_class_of(rbc_guest), rb_mEnumerable);
332 rb_include_module(rbc_guest, rb_mEnumerable);
333 }
334
335 /**
336 * Bridge binding
337 */
338 static VALUE bridge_get(VALUE class, VALUE key)
339 {
340 enumerator_t *enumerator;
341 bridge_t *bridge, *found = NULL;
342
343 enumerator = dumm->create_bridge_enumerator(dumm);
344 while (enumerator->enumerate(enumerator, &bridge))
345 {
346 if (streq(bridge->get_name(bridge), StringValuePtr(key)))
347 {
348 found = bridge;
349 break;
350 }
351 }
352 enumerator->destroy(enumerator);
353 if (!found)
354 {
355 rb_raise(rb_eRuntimeError, "bridge not found");
356 }
357 return Data_Wrap_Struct(class, NULL, NULL, found);
358 }
359
360 static VALUE bridge_each(int argc, VALUE *argv, VALUE class)
361 {
362 enumerator_t *enumerator;
363 bridge_t *bridge;
364
365 if (!rb_block_given_p())
366 {
367 rb_raise(rb_eArgError, "must be called with a block");
368 }
369 enumerator = dumm->create_bridge_enumerator(dumm);
370 while (enumerator->enumerate(enumerator, &bridge))
371 {
372 rb_yield(Data_Wrap_Struct(class, NULL, NULL, bridge));
373 }
374 enumerator->destroy(enumerator);
375 return class;
376 }
377
378 static VALUE bridge_new(VALUE class, VALUE name)
379
380 {
381 bridge_t *bridge;
382
383 bridge = dumm->create_bridge(dumm, StringValuePtr(name));
384 if (!bridge)
385 {
386 rb_raise(rb_eRuntimeError, "creating bridge failed");
387 }
388 return Data_Wrap_Struct(class, NULL, NULL, bridge);
389 }
390
391 static VALUE bridge_to_s(VALUE self)
392 {
393 bridge_t *bridge;
394
395 Data_Get_Struct(self, bridge_t, bridge);
396 return rb_str_new2(bridge->get_name(bridge));
397 }
398
399 static VALUE bridge_each_iface(int argc, VALUE *argv, VALUE self)
400 {
401 enumerator_t *enumerator;
402 bridge_t *bridge;
403 iface_t *iface;
404
405 if (!rb_block_given_p())
406 {
407 rb_raise(rb_eArgError, "must be called with a block");
408 }
409 Data_Get_Struct(self, bridge_t, bridge);
410 enumerator = bridge->create_iface_enumerator(bridge);
411 while (enumerator->enumerate(enumerator, &iface))
412 {
413 rb_yield(Data_Wrap_Struct(rbc_iface, NULL, NULL, iface));
414 }
415 enumerator->destroy(enumerator);
416 return self;
417 }
418
419 static VALUE bridge_delete(VALUE self)
420 {
421 bridge_t *bridge;
422
423 Data_Get_Struct(self, bridge_t, bridge);
424 dumm->delete_bridge(dumm, bridge);
425 return Qnil;
426 }
427
428 static void bridge_init()
429 {
430 rbc_bridge = rb_define_class_under(rbm_dumm , "Bridge", rb_cObject);
431 rb_define_singleton_method(rbc_bridge, "[]", bridge_get, 1);
432 rb_define_singleton_method(rbc_bridge, "each", bridge_each, -1);
433 rb_define_singleton_method(rbc_bridge, "new", bridge_new, 1);
434 rb_define_method(rbc_bridge, "to_s", bridge_to_s, 0);
435 rb_define_method(rbc_bridge, "each", bridge_each_iface, -1);
436 rb_define_method(rbc_bridge, "delete", bridge_delete, 0);
437 rb_include_module(rb_class_of(rbc_bridge), rb_mEnumerable);
438 rb_include_module(rbc_bridge, rb_mEnumerable);
439 }
440
441 /**
442 * Iface wrapper
443 */
444 static VALUE iface_to_s(VALUE self)
445 {
446 iface_t *iface;
447
448 Data_Get_Struct(self, iface_t, iface);
449 return rb_str_new2(iface->get_hostif(iface));
450 }
451
452 static VALUE iface_connect(VALUE self, VALUE vbridge)
453 {
454 iface_t *iface;
455 bridge_t *bridge;
456
457 Data_Get_Struct(self, iface_t, iface);
458 Data_Get_Struct(vbridge, bridge_t, bridge);
459 if (!bridge->connect_iface(bridge, iface))
460 {
461 rb_raise(rb_eRuntimeError, "connecting iface failed");
462 }
463 return self;
464 }
465
466 static VALUE iface_disconnect(VALUE self)
467 {
468 iface_t *iface;
469 bridge_t *bridge;
470
471 Data_Get_Struct(self, iface_t, iface);
472 bridge = iface->get_bridge(iface);
473 if (!bridge || !bridge->disconnect_iface(bridge, iface))
474 {
475 rb_raise(rb_eRuntimeError, "disconnecting iface failed");
476 }
477 return self;
478 }
479
480 static VALUE iface_add_addr(VALUE self, VALUE name)
481 {
482 iface_t *iface;
483 host_t *addr;
484
485 addr = host_create_from_string(StringValuePtr(name), 0);
486 if (!addr)
487 {
488 rb_raise(rb_eRuntimeError, "invalid IP address");
489 }
490 Data_Get_Struct(self, iface_t, iface);
491 if (!iface->add_address(iface, addr))
492 {
493 rb_raise(rb_eRuntimeError, "adding address failed");
494 }
495 return self;
496 }
497
498 static VALUE iface_each_addr(int argc, VALUE *argv, VALUE self)
499 {
500 enumerator_t *enumerator;
501 iface_t *iface;
502 host_t *addr;
503 char buf[64];
504
505 if (!rb_block_given_p())
506 {
507 rb_raise(rb_eArgError, "must be called with a block");
508 }
509 Data_Get_Struct(self, iface_t, iface);
510 enumerator = iface->create_address_enumerator(iface);
511 while (enumerator->enumerate(enumerator, &addr))
512 {
513 snprintf(buf, sizeof(buf), "%H", addr);
514 rb_yield(rb_str_new2(buf));
515 }
516 enumerator->destroy(enumerator);
517 return self;
518 }
519
520 static VALUE iface_del_addr(VALUE self, VALUE vaddr)
521 {
522 iface_t *iface;
523 host_t *addr;
524
525 addr = host_create_from_string(StringValuePtr(vaddr), 0);
526 Data_Get_Struct(self, iface_t, iface);
527 if (!iface->delete_address(iface, addr))
528 {
529 addr->destroy(addr);
530 rb_raise(rb_eRuntimeError, "address not found");
531 }
532 addr->destroy(addr);
533 return self;
534 }
535
536 static VALUE iface_delete(VALUE self)
537 {
538 guest_t *guest;
539 iface_t *iface;
540
541 Data_Get_Struct(self, iface_t, iface);
542 guest = iface->get_guest(iface);
543 guest->destroy_iface(guest, iface);
544 return Qnil;
545 }
546
547 static void iface_init()
548 {
549 rbc_iface = rb_define_class_under(rbm_dumm , "Iface", rb_cObject);
550 rb_define_method(rbc_iface, "to_s", iface_to_s, 0);
551 rb_define_method(rbc_iface, "connect", iface_connect, 1);
552 rb_define_method(rbc_iface, "disconnect", iface_disconnect, 0);
553 rb_define_method(rbc_iface, "add", iface_add_addr, 1);
554 rb_define_method(rbc_iface, "del", iface_del_addr, 1);
555 rb_define_method(rbc_iface, "each", iface_each_addr, -1);
556 rb_define_method(rbc_iface, "delete", iface_delete, 0);
557 rb_include_module(rbc_iface, rb_mEnumerable);
558 }
559
560 static VALUE template_load(VALUE class, VALUE name)
561 {
562 if (!dumm->load_template(dumm, StringValuePtr(name)))
563 {
564 rb_raise(rb_eRuntimeError, "loading template failed");
565 }
566 return class;
567 }
568
569 static VALUE template_unload(VALUE class)
570 {
571 if (!dumm->load_template(dumm, NULL))
572 {
573 rb_raise(rb_eRuntimeError, "unloading template failed");
574 }
575 return class;
576 }
577
578 static void template_init()
579 {
580 rbc_template = rb_define_class_under(rbm_dumm , "Template", rb_cObject);
581 rb_define_singleton_method(rbc_template, "load", template_load, 1);
582 rb_define_singleton_method(rbc_template, "unload", template_unload, 0);
583 }
584
585 /**
586 * main routine, parses args and reads from console
587 */
588 int main(int argc, char *argv[])
589 {
590 int state, i;
591 struct sigaction action;
592 char buf[512];
593
594 ruby_init();
595 ruby_init_loadpath();
596
597 /* there are to many to report, rubyruby... */
598 setenv("LEAK_DETECTIVE_DISABLE", "1", 1);
599
600 library_init(NULL);
601
602 dumm = dumm_create(NULL);
603
604 rbm_dumm = rb_define_module("Dumm");
605
606 guest_init();
607 bridge_init();
608 iface_init();
609 template_init();
610
611 sigemptyset(&action.sa_mask);
612 action.sa_flags = SA_SIGINFO;
613 action.sa_sigaction = sigchld_handler;
614 sigaction(SIGCHLD, &action, NULL);
615 action.sa_sigaction = sigint_handler;
616 sigaction(SIGINT, &action, NULL);
617 sigaction(SIGTERM, &action, NULL);
618 sigaction(SIGSEGV, &action, NULL);
619 sigaction(SIGHUP, &action, NULL);
620
621 rb_eval_string_protect("include Dumm", &state);
622 if (state)
623 {
624 rb_p(ruby_errinfo);
625 }
626 for (i = 1; i < argc; i++)
627 {
628 snprintf(buf, sizeof(buf), "load \"%s\"", argv[i]);
629 printf("%s\n", buf);
630 rb_eval_string_protect(buf, &state);
631 if (state)
632 {
633 rb_p(ruby_errinfo);
634 }
635 }
636 rb_require("irb");
637 rb_eval_string_protect("IRB.start", &state);
638 if (state)
639 {
640 rb_p(ruby_errinfo);
641 }
642
643 dumm->destroy(dumm);
644
645 action.sa_handler = SIG_DFL;
646 action.sa_flags = 0;
647 sigaction(SIGCHLD, &action, NULL);
648
649 library_deinit();
650 return 0;
651 }
652