a970046fe0c97b3756ef0fc8de8bc836d6fe47a6
[strongswan.git] / src / dumm / ext / dumm.c
1 /*
2 * Copyright (C) 2008-2009 Tobias Brunner
3 * Copyright (C) 2008 Martin Willi
4 * Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #include <stdio.h>
18 #include <signal.h>
19 #include <unistd.h>
20 #include <fcntl.h>
21
22 #include <library.h>
23 #include <dumm.h>
24 #include <debug.h>
25 #include <utils/linked_list.h>
26
27 #undef PACKAGE_NAME
28 #undef PACKAGE_TARNAME
29 #undef PACKAGE_VERSION
30 #undef PACKAGE_STRING
31 #undef PACKAGE_BUGREPORT
32 #undef PACKAGE_URL
33 #include <ruby.h>
34
35 static dumm_t *dumm;
36
37 static VALUE rbm_dumm;
38 static VALUE rbc_guest;
39 static VALUE rbc_bridge;
40 static VALUE rbc_iface;
41 static VALUE rbc_template;
42
43 /**
44 * Guest invocation callback
45 */
46 static pid_t invoke(void *null, guest_t *guest, char *args[], int argc)
47 {
48 pid_t pid;
49
50 pid = fork();
51 switch (pid)
52 {
53 case 0: /* child */
54 /* create a new process group in order to prevent signals (e.g.
55 * SIGINT) sent to the parent from terminating the child */
56 setpgid(0, 0);
57 dup2(open("/dev/null", 0), 1);
58 dup2(open("/dev/null", 0), 2);
59 execvp(args[0], args);
60 /* FALL */
61 case -1:
62 return 0;
63 default:
64 return pid;
65 }
66 }
67
68 /**
69 * SIGCHLD signal handler
70 */
71 static void sigchld_handler(int signal, siginfo_t *info, void* ptr)
72 {
73 enumerator_t *enumerator;
74 guest_t *guest;
75
76 enumerator = dumm->create_guest_enumerator(dumm);
77 while (enumerator->enumerate(enumerator, &guest))
78 {
79 if (guest->get_pid(guest) == info->si_pid)
80 {
81 guest->sigchild(guest);
82 break;
83 }
84 }
85 enumerator->destroy(enumerator);
86 }
87
88
89 /**
90 * Global Dumm bindings
91 */
92 static VALUE dumm_add_overlay(VALUE class, VALUE dir)
93 {
94 if (!dumm->add_overlay(dumm, StringValuePtr(dir)))
95 {
96 rb_raise(rb_eRuntimeError, "loading overlay failed");
97 }
98 return class;
99 }
100
101 static VALUE dumm_del_overlay(VALUE class, VALUE dir)
102 {
103 return dumm->del_overlay(dumm, StringValuePtr(dir)) ? Qtrue : Qfalse;
104 }
105
106 static VALUE dumm_pop_overlay(VALUE class)
107 {
108 return dumm->pop_overlay(dumm) ? Qtrue : Qfalse;
109 }
110
111 static void dumm_init()
112 {
113 rbm_dumm = rb_define_module("Dumm");
114
115 rb_define_module_function(rbm_dumm, "add_overlay", dumm_add_overlay, 1);
116 rb_define_module_function(rbm_dumm, "del_overlay", dumm_del_overlay, 1);
117 rb_define_module_function(rbm_dumm, "pop_overlay", dumm_pop_overlay, 0);
118 }
119
120 /**
121 * Guest bindings
122 */
123 static VALUE guest_find(VALUE class, VALUE key)
124 {
125 enumerator_t *enumerator;
126 guest_t *guest, *found = NULL;
127
128 if (TYPE(key) == T_SYMBOL)
129 {
130 key = rb_convert_type(key, T_STRING, "String", "to_s");
131 }
132 enumerator = dumm->create_guest_enumerator(dumm);
133 while (enumerator->enumerate(enumerator, &guest))
134 {
135 if (streq(guest->get_name(guest), StringValuePtr(key)))
136 {
137 found = guest;
138 break;
139 }
140 }
141 enumerator->destroy(enumerator);
142 if (!found)
143 {
144 return Qnil;
145 }
146 return Data_Wrap_Struct(class, NULL, NULL, found);
147 }
148
149 static VALUE guest_get(VALUE class, VALUE key)
150 {
151 VALUE guest = guest_find(class, key);
152 if (NIL_P(guest))
153 {
154 rb_raise(rb_eRuntimeError, "guest not found");
155 }
156 return guest;
157 }
158
159 static VALUE guest_each(int argc, VALUE *argv, VALUE class)
160 {
161 linked_list_t *list;
162 enumerator_t *enumerator;
163 guest_t *guest;
164
165 if (!rb_block_given_p())
166 {
167 rb_raise(rb_eArgError, "must be called with a block");
168 }
169 list = linked_list_create();
170 enumerator = dumm->create_guest_enumerator(dumm);
171 while (enumerator->enumerate(enumerator, &guest))
172 {
173 list->insert_last(list, guest);
174 }
175 enumerator->destroy(enumerator);
176 while (list->remove_first(list, (void**)&guest) == SUCCESS)
177 {
178 rb_yield(Data_Wrap_Struct(class, NULL, NULL, guest));
179 }
180 list->destroy(list);
181 return class;
182 }
183
184 static VALUE guest_new(VALUE class, VALUE name, VALUE kernel,
185 VALUE master, VALUE args)
186 {
187 guest_t *guest;
188
189 guest = dumm->create_guest(dumm, StringValuePtr(name), StringValuePtr(kernel),
190 StringValuePtr(master), StringValuePtr(args));
191 if (!guest)
192 {
193 rb_raise(rb_eRuntimeError, "creating guest failed");
194 }
195 return Data_Wrap_Struct(class, NULL, NULL, guest);
196 }
197
198 static VALUE guest_to_s(VALUE self)
199 {
200 guest_t *guest;
201
202 Data_Get_Struct(self, guest_t, guest);
203 return rb_str_new2(guest->get_name(guest));
204 }
205
206 static VALUE guest_start(VALUE self)
207 {
208 guest_t *guest;
209
210 Data_Get_Struct(self, guest_t, guest);
211
212 if (!guest->start(guest, invoke, NULL, NULL))
213 {
214 rb_raise(rb_eRuntimeError, "starting guest failed");
215 }
216 return self;
217 }
218
219 static VALUE guest_stop(VALUE self)
220 {
221 guest_t *guest;
222
223 Data_Get_Struct(self, guest_t, guest);
224 guest->stop(guest, NULL);
225 return self;
226 }
227
228 static VALUE guest_running(VALUE self)
229 {
230 guest_t *guest;
231
232 Data_Get_Struct(self, guest_t, guest);
233 return guest->get_pid(guest) ? Qtrue : Qfalse;
234 }
235
236 static void exec_cb(void *data, char *buf)
237 {
238 rb_yield(rb_str_new2(buf));
239 }
240
241 static VALUE guest_exec(VALUE self, VALUE cmd)
242 {
243 guest_t *guest;
244 bool block;
245 int ret;
246
247 block = rb_block_given_p();
248 Data_Get_Struct(self, guest_t, guest);
249 if ((ret = guest->exec_str(guest, block ? (void*)exec_cb : NULL, TRUE, NULL,
250 "exec %s", StringValuePtr(cmd))) != 0)
251 {
252 rb_raise(rb_eRuntimeError, "executing command failed (%d)", ret);
253 }
254 return self;
255 }
256
257 static VALUE guest_mconsole(VALUE self, VALUE cmd)
258 {
259 guest_t *guest;
260 bool block;
261 int ret;
262
263 block = rb_block_given_p();
264 Data_Get_Struct(self, guest_t, guest);
265 if ((ret = guest->exec_str(guest, block ? (void*)exec_cb : NULL, TRUE, NULL,
266 "%s", StringValuePtr(cmd))) != 0)
267 {
268 rb_raise(rb_eRuntimeError, "executing command failed (%d)", ret);
269 }
270 return self;
271 }
272
273 static VALUE guest_add_iface(VALUE self, VALUE name)
274 {
275 guest_t *guest;
276 iface_t *iface;
277
278 Data_Get_Struct(self, guest_t, guest);
279 iface = guest->create_iface(guest, StringValuePtr(name));
280 if (!iface)
281 {
282 rb_raise(rb_eRuntimeError, "adding interface failed");
283 }
284 return Data_Wrap_Struct(rbc_iface, NULL, NULL, iface);
285 }
286
287 static VALUE guest_find_iface(VALUE self, VALUE key)
288 {
289 enumerator_t *enumerator;
290 iface_t *iface, *found = NULL;
291 guest_t *guest;
292
293 if (TYPE(key) == T_SYMBOL)
294 {
295 key = rb_convert_type(key, T_STRING, "String", "to_s");
296 }
297 Data_Get_Struct(self, guest_t, guest);
298 enumerator = guest->create_iface_enumerator(guest);
299 while (enumerator->enumerate(enumerator, &iface))
300 {
301 if (streq(iface->get_guestif(iface), StringValuePtr(key)))
302 {
303 found = iface;
304 break;
305 }
306 }
307 enumerator->destroy(enumerator);
308 if (!found)
309 {
310 return Qnil;
311 }
312 return Data_Wrap_Struct(rbc_iface, NULL, NULL, iface);
313 }
314
315 static VALUE guest_get_iface(VALUE self, VALUE key)
316 {
317 VALUE iface = guest_find_iface(self, key);
318 if (NIL_P(iface))
319 {
320 rb_raise(rb_eRuntimeError, "interface not found");
321 }
322 return iface;
323 }
324
325 static VALUE guest_each_iface(int argc, VALUE *argv, VALUE self)
326 {
327 enumerator_t *enumerator;
328 linked_list_t *list;
329 guest_t *guest;
330 iface_t *iface;
331
332 if (!rb_block_given_p())
333 {
334 rb_raise(rb_eArgError, "must be called with a block");
335 }
336 Data_Get_Struct(self, guest_t, guest);
337 list = linked_list_create();
338 enumerator = guest->create_iface_enumerator(guest);
339 while (enumerator->enumerate(enumerator, &iface))
340 {
341 list->insert_last(list, iface);
342 }
343 enumerator->destroy(enumerator);
344 while (list->remove_first(list, (void**)&iface) == SUCCESS)
345 {
346 rb_yield(Data_Wrap_Struct(rbc_iface, NULL, NULL, iface));
347 }
348 list->destroy(list);
349 return self;
350 }
351
352 static VALUE guest_delete(VALUE self)
353 {
354 guest_t *guest;
355
356 Data_Get_Struct(self, guest_t, guest);
357 if (guest->get_pid(guest))
358 {
359 rb_raise(rb_eRuntimeError, "guest is running");
360 }
361 dumm->delete_guest(dumm, guest);
362 return Qnil;
363 }
364
365 static VALUE guest_add_overlay(VALUE self, VALUE dir)
366 {
367 guest_t *guest;
368
369 Data_Get_Struct(self, guest_t, guest);
370 if (!guest->add_overlay(guest, StringValuePtr(dir)))
371 {
372 rb_raise(rb_eRuntimeError, "loading overlay failed");
373 }
374 return self;
375 }
376
377 static VALUE guest_del_overlay(VALUE self, VALUE dir)
378 {
379 guest_t *guest;
380
381 Data_Get_Struct(self, guest_t, guest);
382 return guest->del_overlay(guest, StringValuePtr(dir)) ? Qtrue : Qfalse;
383 }
384
385 static VALUE guest_pop_overlay(VALUE self)
386 {
387 guest_t *guest;
388
389 Data_Get_Struct(self, guest_t, guest);
390 return guest->pop_overlay(guest) ? Qtrue : Qfalse;
391 }
392
393 static void guest_init()
394 {
395 rbc_guest = rb_define_class_under(rbm_dumm , "Guest", rb_cObject);
396 rb_include_module(rb_class_of(rbc_guest), rb_mEnumerable);
397 rb_include_module(rbc_guest, rb_mEnumerable);
398
399 rb_define_singleton_method(rbc_guest, "[]", guest_get, 1);
400 rb_define_singleton_method(rbc_guest, "each", guest_each, -1);
401 rb_define_singleton_method(rbc_guest, "new", guest_new, 4);
402 rb_define_singleton_method(rbc_guest, "include?", guest_find, 1);
403 rb_define_singleton_method(rbc_guest, "guest?", guest_find, 1);
404
405 rb_define_method(rbc_guest, "to_s", guest_to_s, 0);
406 rb_define_method(rbc_guest, "start", guest_start, 0);
407 rb_define_method(rbc_guest, "stop", guest_stop, 0);
408 rb_define_method(rbc_guest, "running?", guest_running, 0);
409 rb_define_method(rbc_guest, "exec", guest_exec, 1);
410 rb_define_method(rbc_guest, "mconsole", guest_mconsole, 1);
411 rb_define_method(rbc_guest, "add", guest_add_iface, 1);
412 rb_define_method(rbc_guest, "[]", guest_get_iface, 1);
413 rb_define_method(rbc_guest, "each", guest_each_iface, -1);
414 rb_define_method(rbc_guest, "include?", guest_find_iface, 1);
415 rb_define_method(rbc_guest, "iface?", guest_find_iface, 1);
416 rb_define_method(rbc_guest, "delete", guest_delete, 0);
417 rb_define_method(rbc_guest, "add_overlay", guest_add_overlay, 1);
418 rb_define_method(rbc_guest, "del_overlay", guest_del_overlay, 1);
419 rb_define_method(rbc_guest, "pop_overlay", guest_pop_overlay, 0);
420 }
421
422 /**
423 * Bridge binding
424 */
425 static VALUE bridge_find(VALUE class, VALUE key)
426 {
427 enumerator_t *enumerator;
428 bridge_t *bridge, *found = NULL;
429
430 if (TYPE(key) == T_SYMBOL)
431 {
432 key = rb_convert_type(key, T_STRING, "String", "to_s");
433 }
434 enumerator = dumm->create_bridge_enumerator(dumm);
435 while (enumerator->enumerate(enumerator, &bridge))
436 {
437 if (streq(bridge->get_name(bridge), StringValuePtr(key)))
438 {
439 found = bridge;
440 break;
441 }
442 }
443 enumerator->destroy(enumerator);
444 if (!found)
445 {
446 return Qnil;
447 }
448 return Data_Wrap_Struct(class, NULL, NULL, found);
449 }
450
451 static VALUE bridge_get(VALUE class, VALUE key)
452 {
453 VALUE bridge = bridge_find(class, key);
454 if (NIL_P(bridge))
455 {
456 rb_raise(rb_eRuntimeError, "bridge not found");
457 }
458 return bridge;
459 }
460
461 static VALUE bridge_each(int argc, VALUE *argv, VALUE class)
462 {
463 enumerator_t *enumerator;
464 linked_list_t *list;
465 bridge_t *bridge;
466
467 if (!rb_block_given_p())
468 {
469 rb_raise(rb_eArgError, "must be called with a block");
470 }
471 list = linked_list_create();
472 enumerator = dumm->create_bridge_enumerator(dumm);
473 while (enumerator->enumerate(enumerator, &bridge))
474 {
475 list->insert_last(list, bridge);
476 }
477 enumerator->destroy(enumerator);
478 while (list->remove_first(list, (void**)&bridge) == SUCCESS)
479 {
480 rb_yield(Data_Wrap_Struct(class, NULL, NULL, bridge));
481 }
482 list->destroy(list);
483 return class;
484 }
485
486 static VALUE bridge_new(VALUE class, VALUE name)
487
488 {
489 bridge_t *bridge;
490
491 bridge = dumm->create_bridge(dumm, StringValuePtr(name));
492 if (!bridge)
493 {
494 rb_raise(rb_eRuntimeError, "creating bridge failed");
495 }
496 return Data_Wrap_Struct(class, NULL, NULL, bridge);
497 }
498
499 static VALUE bridge_to_s(VALUE self)
500 {
501 bridge_t *bridge;
502
503 Data_Get_Struct(self, bridge_t, bridge);
504 return rb_str_new2(bridge->get_name(bridge));
505 }
506
507 static VALUE bridge_each_iface(int argc, VALUE *argv, VALUE self)
508 {
509 enumerator_t *enumerator;
510 linked_list_t *list;
511 bridge_t *bridge;
512 iface_t *iface;
513
514 if (!rb_block_given_p())
515 {
516 rb_raise(rb_eArgError, "must be called with a block");
517 }
518 Data_Get_Struct(self, bridge_t, bridge);
519 list = linked_list_create();
520 enumerator = bridge->create_iface_enumerator(bridge);
521 while (enumerator->enumerate(enumerator, &iface))
522 {
523 list->insert_last(list, iface);
524 }
525 enumerator->destroy(enumerator);
526 while (list->remove_first(list, (void**)&iface) == SUCCESS)
527 {
528 rb_yield(Data_Wrap_Struct(rbc_iface, NULL, NULL, iface));
529 }
530 list->destroy(list);
531 return self;
532 }
533
534 static VALUE bridge_delete(VALUE self)
535 {
536 bridge_t *bridge;
537
538 Data_Get_Struct(self, bridge_t, bridge);
539 dumm->delete_bridge(dumm, bridge);
540 return Qnil;
541 }
542
543 static void bridge_init()
544 {
545 rbc_bridge = rb_define_class_under(rbm_dumm , "Bridge", rb_cObject);
546 rb_include_module(rb_class_of(rbc_bridge), rb_mEnumerable);
547 rb_include_module(rbc_bridge, rb_mEnumerable);
548
549 rb_define_singleton_method(rbc_bridge, "[]", bridge_get, 1);
550 rb_define_singleton_method(rbc_bridge, "each", bridge_each, -1);
551 rb_define_singleton_method(rbc_bridge, "new", bridge_new, 1);
552 rb_define_singleton_method(rbc_bridge, "include?", bridge_find, 1);
553 rb_define_singleton_method(rbc_bridge, "bridge?", bridge_find, 1);
554
555 rb_define_method(rbc_bridge, "to_s", bridge_to_s, 0);
556 rb_define_method(rbc_bridge, "each", bridge_each_iface, -1);
557 rb_define_method(rbc_bridge, "delete", bridge_delete, 0);
558 }
559
560 /**
561 * Iface wrapper
562 */
563 static VALUE iface_to_s(VALUE self)
564 {
565 iface_t *iface;
566
567 Data_Get_Struct(self, iface_t, iface);
568 return rb_str_new2(iface->get_hostif(iface));
569 }
570
571 static VALUE iface_connect(VALUE self, VALUE vbridge)
572 {
573 iface_t *iface;
574 bridge_t *bridge;
575
576 Data_Get_Struct(self, iface_t, iface);
577 Data_Get_Struct(vbridge, bridge_t, bridge);
578 if (!bridge->connect_iface(bridge, iface))
579 {
580 rb_raise(rb_eRuntimeError, "connecting iface failed");
581 }
582 return self;
583 }
584
585 static VALUE iface_disconnect(VALUE self)
586 {
587 iface_t *iface;
588 bridge_t *bridge;
589
590 Data_Get_Struct(self, iface_t, iface);
591 bridge = iface->get_bridge(iface);
592 if (!bridge || !bridge->disconnect_iface(bridge, iface))
593 {
594 rb_raise(rb_eRuntimeError, "disconnecting iface failed");
595 }
596 return self;
597 }
598
599 static VALUE iface_add_addr(VALUE self, VALUE name)
600 {
601 iface_t *iface;
602 host_t *addr;
603
604 addr = host_create_from_string(StringValuePtr(name), 0);
605 if (!addr)
606 {
607 rb_raise(rb_eArgError, "invalid IP address");
608 }
609 Data_Get_Struct(self, iface_t, iface);
610 if (!iface->add_address(iface, addr))
611 {
612 addr->destroy(addr);
613 rb_raise(rb_eRuntimeError, "adding address failed");
614 }
615 if (rb_block_given_p()) {
616 rb_yield(self);
617 iface->delete_address(iface, addr);
618 }
619 addr->destroy(addr);
620 return self;
621 }
622
623 static VALUE iface_each_addr(int argc, VALUE *argv, VALUE self)
624 {
625 enumerator_t *enumerator;
626 linked_list_t *list;
627 iface_t *iface;
628 host_t *addr;
629 char buf[64];
630
631 if (!rb_block_given_p())
632 {
633 rb_raise(rb_eArgError, "must be called with a block");
634 }
635 Data_Get_Struct(self, iface_t, iface);
636 enumerator = iface->create_address_enumerator(iface);
637 while (enumerator->enumerate(enumerator, &addr))
638 {
639 list->insert_last(list, addr->clone(addr));
640 }
641 enumerator->destroy(enumerator);
642 while (list->remove_first(list, (void**)&addr) == SUCCESS)
643 {
644 snprintf(buf, sizeof(buf), "%H", addr);
645 addr->destroy(addr);
646 rb_yield(rb_str_new2(buf));
647 }
648 list->destroy(list);
649 return self;
650 }
651
652 static VALUE iface_del_addr(VALUE self, VALUE vaddr)
653 {
654 iface_t *iface;
655 host_t *addr;
656
657 addr = host_create_from_string(StringValuePtr(vaddr), 0);
658 if (!addr)
659 {
660 rb_raise(rb_eArgError, "invalid IP address");
661 }
662 Data_Get_Struct(self, iface_t, iface);
663 if (!iface->delete_address(iface, addr))
664 {
665 addr->destroy(addr);
666 rb_raise(rb_eRuntimeError, "address not found");
667 }
668 if (rb_block_given_p()) {
669 rb_yield(self);
670 iface->add_address(iface, addr);
671 }
672 addr->destroy(addr);
673 return self;
674 }
675
676 static VALUE iface_delete(VALUE self)
677 {
678 guest_t *guest;
679 iface_t *iface;
680
681 Data_Get_Struct(self, iface_t, iface);
682 guest = iface->get_guest(iface);
683 guest->destroy_iface(guest, iface);
684 return Qnil;
685 }
686
687 static void iface_init()
688 {
689 rbc_iface = rb_define_class_under(rbm_dumm , "Iface", rb_cObject);
690 rb_include_module(rbc_iface, rb_mEnumerable);
691
692 rb_define_method(rbc_iface, "to_s", iface_to_s, 0);
693 rb_define_method(rbc_iface, "connect", iface_connect, 1);
694 rb_define_method(rbc_iface, "disconnect", iface_disconnect, 0);
695 rb_define_method(rbc_iface, "add", iface_add_addr, 1);
696 rb_define_method(rbc_iface, "del", iface_del_addr, 1);
697 rb_define_method(rbc_iface, "each", iface_each_addr, -1);
698 rb_define_method(rbc_iface, "delete", iface_delete, 0);
699 }
700
701 static VALUE template_load(VALUE class, VALUE dir)
702 {
703 if (!dumm->load_template(dumm, StringValuePtr(dir)))
704 {
705 rb_raise(rb_eRuntimeError, "loading template failed");
706 }
707 return class;
708 }
709
710 static VALUE template_unload(VALUE class)
711 {
712 if (!dumm->load_template(dumm, NULL))
713 {
714 rb_raise(rb_eRuntimeError, "unloading template failed");
715 }
716 return class;
717 }
718
719 static VALUE template_each(int argc, VALUE *argv, VALUE class)
720 {
721 enumerator_t *enumerator;
722 char *template;
723
724 if (!rb_block_given_p())
725 {
726 rb_raise(rb_eArgError, "must be called with a block");
727 }
728 enumerator = dumm->create_template_enumerator(dumm);
729 while (enumerator->enumerate(enumerator, &template))
730 {
731 rb_yield(rb_str_new2(template));
732 }
733 enumerator->destroy(enumerator);
734 return class;
735 }
736
737 static void template_init()
738 {
739 rbc_template = rb_define_class_under(rbm_dumm , "Template", rb_cObject);
740
741 rb_define_singleton_method(rbc_template, "load", template_load, 1);
742 rb_define_singleton_method(rbc_template, "unload", template_unload, 0);
743 rb_define_singleton_method(rbc_template, "each", template_each, -1);
744 }
745
746 /**
747 * extension finalization
748 */
749 void Final_dumm()
750 {
751 struct sigaction action;
752
753 dumm->destroy(dumm);
754
755 sigemptyset(&action.sa_mask);
756 action.sa_handler = SIG_DFL;
757 action.sa_flags = 0;
758 sigaction(SIGCHLD, &action, NULL);
759
760 library_deinit();
761 }
762
763 /**
764 * extension initialization
765 */
766 void Init_dumm()
767 {
768 struct sigaction action;
769
770 /* there are too many to report, rubyruby... */
771 setenv("LEAK_DETECTIVE_DISABLE", "1", 1);
772
773 library_init(NULL);
774
775 dumm = dumm_create(NULL);
776
777 dumm_init();
778 guest_init();
779 bridge_init();
780 iface_init();
781 template_init();
782
783 sigemptyset(&action.sa_mask);
784 action.sa_sigaction = sigchld_handler;
785 action.sa_flags = SA_SIGINFO;
786 sigaction(SIGCHLD, &action, NULL);
787
788 rb_set_end_proc(Final_dumm, 0);
789 }