rb_cvar_set() takes three arguments in Ruby 1.9
[strongswan.git] / src / dumm / ext / dumm.c
1 /*
2 * Copyright (C) 2008-2010 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 <utils/debug.h>
25 #include <collections/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_hash_create(VALUE class)
124 {
125 enumerator_t *enumerator;
126 guest_t *guest;
127 VALUE hash = rb_hash_new();
128 enumerator = dumm->create_guest_enumerator(dumm);
129 while (enumerator->enumerate(enumerator, &guest))
130 {
131 rb_hash_aset(hash, rb_str_new2(guest->get_name(guest)),
132 Data_Wrap_Struct(class, NULL, NULL, guest));
133 }
134 enumerator->destroy(enumerator);
135 return hash;
136 }
137
138 static VALUE guest_hash(VALUE class)
139 {
140 ID id = rb_intern("@@guests");
141 if (!rb_cvar_defined(class, id))
142 {
143 VALUE hash = guest_hash_create(class);
144 #ifdef RB_CVAR_SET_4_ARGS
145 rb_cvar_set(class, id, hash, 0);
146 #else
147 rb_cvar_set(class, id, hash);
148 #endif
149 return hash;
150 }
151 return rb_cvar_get(class, id);
152 }
153
154 static VALUE guest_find(VALUE class, VALUE key)
155 {
156 if (TYPE(key) != T_STRING)
157 {
158 key = rb_convert_type(key, T_STRING, "String", "to_s");
159 }
160 return rb_hash_aref(guest_hash(class), key);
161 }
162
163 static VALUE guest_get(VALUE class, VALUE key)
164 {
165 return guest_find(class, key);
166 }
167
168 static VALUE guest_each(int argc, VALUE *argv, VALUE class)
169 {
170 if (!rb_block_given_p())
171 {
172 rb_raise(rb_eArgError, "must be called with a block");
173 }
174 rb_block_call(guest_hash(class), rb_intern("each_value"), 0, 0,
175 rb_yield, 0);
176 return class;
177 }
178
179 static VALUE guest_new(VALUE class, VALUE name, VALUE kernel,
180 VALUE master, VALUE args)
181 {
182 VALUE self;
183 guest_t *guest;
184 guest = dumm->create_guest(dumm, StringValuePtr(name),
185 StringValuePtr(kernel), StringValuePtr(master),
186 StringValuePtr(args));
187 if (!guest)
188 {
189 rb_raise(rb_eRuntimeError, "creating guest failed");
190 }
191 self = Data_Wrap_Struct(class, NULL, NULL, guest);
192 rb_hash_aset(guest_hash(class), name, self);
193 return self;
194 }
195
196 static VALUE guest_to_s(VALUE self)
197 {
198 guest_t *guest;
199
200 Data_Get_Struct(self, guest_t, guest);
201 return rb_str_new2(guest->get_name(guest));
202 }
203
204 static VALUE guest_start(VALUE self)
205 {
206 guest_t *guest;
207
208 Data_Get_Struct(self, guest_t, guest);
209
210 if (!guest->start(guest, invoke, NULL, NULL))
211 {
212 rb_raise(rb_eRuntimeError, "starting guest failed");
213 }
214 return self;
215 }
216
217 static VALUE guest_stop(VALUE self)
218 {
219 guest_t *guest;
220
221 Data_Get_Struct(self, guest_t, guest);
222 guest->stop(guest, NULL);
223 return self;
224 }
225
226 static VALUE guest_running(VALUE self)
227 {
228 guest_t *guest;
229
230 Data_Get_Struct(self, guest_t, guest);
231 return guest->get_pid(guest) ? Qtrue : Qfalse;
232 }
233
234 static void exec_cb(void *data, char *buf)
235 {
236 rb_yield(rb_str_new2(buf));
237 }
238
239 static VALUE guest_exec(VALUE self, VALUE cmd)
240 {
241 guest_t *guest;
242 bool block;
243 int ret;
244
245 block = rb_block_given_p();
246 Data_Get_Struct(self, guest_t, guest);
247 ret = guest->exec_str(guest, block ? (void*)exec_cb : NULL, TRUE, NULL,
248 "exec %s", StringValuePtr(cmd));
249 rb_iv_set(self, "@execstatus", INT2NUM(ret));
250 return self;
251 }
252
253 static VALUE guest_mconsole(VALUE self, VALUE cmd)
254 {
255 guest_t *guest;
256 bool block;
257 int ret;
258
259 block = rb_block_given_p();
260 Data_Get_Struct(self, guest_t, guest);
261 if ((ret = guest->exec_str(guest, block ? (void*)exec_cb : NULL, TRUE, NULL,
262 "%s", StringValuePtr(cmd))) != 0)
263 {
264 rb_raise(rb_eRuntimeError, "executing command failed (%d)", ret);
265 }
266 return self;
267 }
268
269 static VALUE guest_add_iface(VALUE self, VALUE name)
270 {
271 guest_t *guest;
272 iface_t *iface;
273
274 Data_Get_Struct(self, guest_t, guest);
275 iface = guest->create_iface(guest, StringValuePtr(name));
276 if (!iface)
277 {
278 rb_raise(rb_eRuntimeError, "adding interface failed");
279 }
280 return Data_Wrap_Struct(rbc_iface, NULL, NULL, iface);
281 }
282
283 static VALUE guest_find_iface(VALUE self, VALUE key)
284 {
285 enumerator_t *enumerator;
286 iface_t *iface, *found = NULL;
287 guest_t *guest;
288
289 if (TYPE(key) == T_SYMBOL)
290 {
291 key = rb_convert_type(key, T_STRING, "String", "to_s");
292 }
293 Data_Get_Struct(self, guest_t, guest);
294 enumerator = guest->create_iface_enumerator(guest);
295 while (enumerator->enumerate(enumerator, &iface))
296 {
297 if (streq(iface->get_guestif(iface), StringValuePtr(key)))
298 {
299 found = iface;
300 break;
301 }
302 }
303 enumerator->destroy(enumerator);
304 if (!found)
305 {
306 return Qnil;
307 }
308 return Data_Wrap_Struct(rbc_iface, NULL, NULL, iface);
309 }
310
311 static VALUE guest_get_iface(VALUE self, VALUE key)
312 {
313 VALUE iface = guest_find_iface(self, key);
314 if (NIL_P(iface))
315 {
316 rb_raise(rb_eRuntimeError, "interface not found");
317 }
318 return iface;
319 }
320
321 static VALUE guest_each_iface(int argc, VALUE *argv, VALUE self)
322 {
323 enumerator_t *enumerator;
324 linked_list_t *list;
325 guest_t *guest;
326 iface_t *iface;
327
328 if (!rb_block_given_p())
329 {
330 rb_raise(rb_eArgError, "must be called with a block");
331 }
332 Data_Get_Struct(self, guest_t, guest);
333 list = linked_list_create();
334 enumerator = guest->create_iface_enumerator(guest);
335 while (enumerator->enumerate(enumerator, &iface))
336 {
337 list->insert_last(list, iface);
338 }
339 enumerator->destroy(enumerator);
340 while (list->remove_first(list, (void**)&iface) == SUCCESS)
341 {
342 rb_yield(Data_Wrap_Struct(rbc_iface, NULL, NULL, iface));
343 }
344 list->destroy(list);
345 return self;
346 }
347
348 static VALUE guest_delete(VALUE self)
349 {
350 guest_t *guest;
351
352 Data_Get_Struct(self, guest_t, guest);
353 if (guest->get_pid(guest))
354 {
355 rb_raise(rb_eRuntimeError, "guest is running");
356 }
357 dumm->delete_guest(dumm, guest);
358 return Qnil;
359 }
360
361 static VALUE guest_add_overlay(VALUE self, VALUE dir)
362 {
363 guest_t *guest;
364
365 Data_Get_Struct(self, guest_t, guest);
366 if (!guest->add_overlay(guest, StringValuePtr(dir)))
367 {
368 rb_raise(rb_eRuntimeError, "loading overlay failed");
369 }
370 return self;
371 }
372
373 static VALUE guest_del_overlay(VALUE self, VALUE dir)
374 {
375 guest_t *guest;
376
377 Data_Get_Struct(self, guest_t, guest);
378 return guest->del_overlay(guest, StringValuePtr(dir)) ? Qtrue : Qfalse;
379 }
380
381 static VALUE guest_pop_overlay(VALUE self)
382 {
383 guest_t *guest;
384
385 Data_Get_Struct(self, guest_t, guest);
386 return guest->pop_overlay(guest) ? Qtrue : Qfalse;
387 }
388
389 static void guest_init()
390 {
391 rbc_guest = rb_define_class_under(rbm_dumm , "Guest", rb_cObject);
392 rb_include_module(rb_class_of(rbc_guest), rb_mEnumerable);
393 rb_include_module(rbc_guest, rb_mEnumerable);
394
395 rb_define_singleton_method(rbc_guest, "[]", guest_get, 1);
396 rb_define_singleton_method(rbc_guest, "each", guest_each, -1);
397 rb_define_singleton_method(rbc_guest, "new", guest_new, 4);
398 rb_define_singleton_method(rbc_guest, "include?", guest_find, 1);
399 rb_define_singleton_method(rbc_guest, "guest?", guest_find, 1);
400
401 rb_define_method(rbc_guest, "to_s", guest_to_s, 0);
402 rb_define_method(rbc_guest, "start", guest_start, 0);
403 rb_define_method(rbc_guest, "stop", guest_stop, 0);
404 rb_define_method(rbc_guest, "running?", guest_running, 0);
405 rb_define_method(rbc_guest, "exec", guest_exec, 1);
406 rb_define_method(rbc_guest, "mconsole", guest_mconsole, 1);
407 rb_define_method(rbc_guest, "add", guest_add_iface, 1);
408 rb_define_method(rbc_guest, "[]", guest_get_iface, 1);
409 rb_define_method(rbc_guest, "each", guest_each_iface, -1);
410 rb_define_method(rbc_guest, "include?", guest_find_iface, 1);
411 rb_define_method(rbc_guest, "iface?", guest_find_iface, 1);
412 rb_define_method(rbc_guest, "delete", guest_delete, 0);
413 rb_define_method(rbc_guest, "add_overlay", guest_add_overlay, 1);
414 rb_define_method(rbc_guest, "del_overlay", guest_del_overlay, 1);
415 rb_define_method(rbc_guest, "pop_overlay", guest_pop_overlay, 0);
416
417 rb_define_attr(rbc_guest, "execstatus", 1, 0);
418 }
419
420 /**
421 * Bridge binding
422 */
423 static VALUE bridge_find(VALUE class, VALUE key)
424 {
425 enumerator_t *enumerator;
426 bridge_t *bridge, *found = NULL;
427
428 if (TYPE(key) == T_SYMBOL)
429 {
430 key = rb_convert_type(key, T_STRING, "String", "to_s");
431 }
432 enumerator = dumm->create_bridge_enumerator(dumm);
433 while (enumerator->enumerate(enumerator, &bridge))
434 {
435 if (streq(bridge->get_name(bridge), StringValuePtr(key)))
436 {
437 found = bridge;
438 break;
439 }
440 }
441 enumerator->destroy(enumerator);
442 if (!found)
443 {
444 return Qnil;
445 }
446 return Data_Wrap_Struct(class, NULL, NULL, found);
447 }
448
449 static VALUE bridge_get(VALUE class, VALUE key)
450 {
451 VALUE bridge = bridge_find(class, key);
452 if (NIL_P(bridge))
453 {
454 rb_raise(rb_eRuntimeError, "bridge not found");
455 }
456 return bridge;
457 }
458
459 static VALUE bridge_each(int argc, VALUE *argv, VALUE class)
460 {
461 enumerator_t *enumerator;
462 linked_list_t *list;
463 bridge_t *bridge;
464
465 if (!rb_block_given_p())
466 {
467 rb_raise(rb_eArgError, "must be called with a block");
468 }
469 list = linked_list_create();
470 enumerator = dumm->create_bridge_enumerator(dumm);
471 while (enumerator->enumerate(enumerator, &bridge))
472 {
473 list->insert_last(list, bridge);
474 }
475 enumerator->destroy(enumerator);
476 while (list->remove_first(list, (void**)&bridge) == SUCCESS)
477 {
478 rb_yield(Data_Wrap_Struct(class, NULL, NULL, bridge));
479 }
480 list->destroy(list);
481 return class;
482 }
483
484 static VALUE bridge_new(VALUE class, VALUE name)
485
486 {
487 bridge_t *bridge;
488
489 bridge = dumm->create_bridge(dumm, StringValuePtr(name));
490 if (!bridge)
491 {
492 rb_raise(rb_eRuntimeError, "creating bridge failed");
493 }
494 return Data_Wrap_Struct(class, NULL, NULL, bridge);
495 }
496
497 static VALUE bridge_to_s(VALUE self)
498 {
499 bridge_t *bridge;
500
501 Data_Get_Struct(self, bridge_t, bridge);
502 return rb_str_new2(bridge->get_name(bridge));
503 }
504
505 static VALUE bridge_each_iface(int argc, VALUE *argv, VALUE self)
506 {
507 enumerator_t *enumerator;
508 linked_list_t *list;
509 bridge_t *bridge;
510 iface_t *iface;
511
512 if (!rb_block_given_p())
513 {
514 rb_raise(rb_eArgError, "must be called with a block");
515 }
516 Data_Get_Struct(self, bridge_t, bridge);
517 list = linked_list_create();
518 enumerator = bridge->create_iface_enumerator(bridge);
519 while (enumerator->enumerate(enumerator, &iface))
520 {
521 list->insert_last(list, iface);
522 }
523 enumerator->destroy(enumerator);
524 while (list->remove_first(list, (void**)&iface) == SUCCESS)
525 {
526 rb_yield(Data_Wrap_Struct(rbc_iface, NULL, NULL, iface));
527 }
528 list->destroy(list);
529 return self;
530 }
531
532 static VALUE bridge_delete(VALUE self)
533 {
534 bridge_t *bridge;
535
536 Data_Get_Struct(self, bridge_t, bridge);
537 dumm->delete_bridge(dumm, bridge);
538 return Qnil;
539 }
540
541 static void bridge_init()
542 {
543 rbc_bridge = rb_define_class_under(rbm_dumm , "Bridge", rb_cObject);
544 rb_include_module(rb_class_of(rbc_bridge), rb_mEnumerable);
545 rb_include_module(rbc_bridge, rb_mEnumerable);
546
547 rb_define_singleton_method(rbc_bridge, "[]", bridge_get, 1);
548 rb_define_singleton_method(rbc_bridge, "each", bridge_each, -1);
549 rb_define_singleton_method(rbc_bridge, "new", bridge_new, 1);
550 rb_define_singleton_method(rbc_bridge, "include?", bridge_find, 1);
551 rb_define_singleton_method(rbc_bridge, "bridge?", bridge_find, 1);
552
553 rb_define_method(rbc_bridge, "to_s", bridge_to_s, 0);
554 rb_define_method(rbc_bridge, "each", bridge_each_iface, -1);
555 rb_define_method(rbc_bridge, "delete", bridge_delete, 0);
556 }
557
558 /**
559 * Iface wrapper
560 */
561 static VALUE iface_to_s(VALUE self)
562 {
563 iface_t *iface;
564
565 Data_Get_Struct(self, iface_t, iface);
566 return rb_str_new2(iface->get_hostif(iface));
567 }
568
569 static VALUE iface_connect(VALUE self, VALUE vbridge)
570 {
571 iface_t *iface;
572 bridge_t *bridge;
573
574 Data_Get_Struct(self, iface_t, iface);
575 Data_Get_Struct(vbridge, bridge_t, bridge);
576 if (!bridge->connect_iface(bridge, iface))
577 {
578 rb_raise(rb_eRuntimeError, "connecting iface failed");
579 }
580 return self;
581 }
582
583 static VALUE iface_disconnect(VALUE self)
584 {
585 iface_t *iface;
586 bridge_t *bridge;
587
588 Data_Get_Struct(self, iface_t, iface);
589 bridge = iface->get_bridge(iface);
590 if (!bridge || !bridge->disconnect_iface(bridge, iface))
591 {
592 rb_raise(rb_eRuntimeError, "disconnecting iface failed");
593 }
594 return self;
595 }
596
597 static VALUE iface_add_addr(VALUE self, VALUE name)
598 {
599 iface_t *iface;
600 host_t *addr;
601 int bits;
602
603 addr = host_create_from_subnet(StringValuePtr(name), &bits);
604 if (!addr)
605 {
606 rb_raise(rb_eArgError, "invalid IP address");
607 }
608 Data_Get_Struct(self, iface_t, iface);
609 if (!iface->add_address(iface, addr, bits))
610 {
611 addr->destroy(addr);
612 rb_raise(rb_eRuntimeError, "adding address failed");
613 }
614 if (rb_block_given_p()) {
615 rb_yield(self);
616 iface->delete_address(iface, addr, bits);
617 }
618 addr->destroy(addr);
619 return self;
620 }
621
622 static VALUE iface_each_addr(int argc, VALUE *argv, VALUE self)
623 {
624 enumerator_t *enumerator;
625 linked_list_t *list;
626 iface_t *iface;
627 host_t *addr;
628 char buf[64];
629
630 if (!rb_block_given_p())
631 {
632 rb_raise(rb_eArgError, "must be called with a block");
633 }
634 Data_Get_Struct(self, iface_t, iface);
635 enumerator = iface->create_address_enumerator(iface);
636 while (enumerator->enumerate(enumerator, &addr))
637 {
638 list->insert_last(list, addr->clone(addr));
639 }
640 enumerator->destroy(enumerator);
641 while (list->remove_first(list, (void**)&addr) == SUCCESS)
642 {
643 snprintf(buf, sizeof(buf), "%H", addr);
644 addr->destroy(addr);
645 rb_yield(rb_str_new2(buf));
646 }
647 list->destroy(list);
648 return self;
649 }
650
651 static VALUE iface_del_addr(VALUE self, VALUE vaddr)
652 {
653 iface_t *iface;
654 host_t *addr;
655 int bits;
656
657 addr = host_create_from_subnet(StringValuePtr(vaddr), &bits);
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, bits))
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, bits);
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 }