Map the guests to a ruby hash to avoid creating new ruby objects on each call of...
[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_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 rb_cvar_set(class, id, hash, 0);
145 return hash;
146 }
147 return rb_cvar_get(class, id);
148 }
149
150 static VALUE guest_find(VALUE class, VALUE key)
151 {
152 if (TYPE(key) != T_STRING)
153 {
154 key = rb_convert_type(key, T_STRING, "String", "to_s");
155 }
156 return rb_hash_aref(guest_hash(class), key);
157 }
158
159 static VALUE guest_get(VALUE class, VALUE key)
160 {
161 return guest_find(class, key);
162 }
163
164 static VALUE guest_each(int argc, VALUE *argv, VALUE class)
165 {
166 if (!rb_block_given_p())
167 {
168 rb_raise(rb_eArgError, "must be called with a block");
169 }
170 rb_block_call(guest_hash(class), rb_intern("each_value"), 0, 0,
171 rb_yield, 0);
172 return class;
173 }
174
175 static VALUE guest_new(VALUE class, VALUE name, VALUE kernel,
176 VALUE master, VALUE args)
177 {
178 VALUE self;
179 guest_t *guest;
180 guest = dumm->create_guest(dumm, StringValuePtr(name),
181 StringValuePtr(kernel), StringValuePtr(master),
182 StringValuePtr(args));
183 if (!guest)
184 {
185 rb_raise(rb_eRuntimeError, "creating guest failed");
186 }
187 self = Data_Wrap_Struct(class, NULL, NULL, guest);
188 rb_hash_aset(guest_hash(class), name, self);
189 return self;
190 }
191
192 static VALUE guest_to_s(VALUE self)
193 {
194 guest_t *guest;
195
196 Data_Get_Struct(self, guest_t, guest);
197 return rb_str_new2(guest->get_name(guest));
198 }
199
200 static VALUE guest_start(VALUE self)
201 {
202 guest_t *guest;
203
204 Data_Get_Struct(self, guest_t, guest);
205
206 if (!guest->start(guest, invoke, NULL, NULL))
207 {
208 rb_raise(rb_eRuntimeError, "starting guest failed");
209 }
210 return self;
211 }
212
213 static VALUE guest_stop(VALUE self)
214 {
215 guest_t *guest;
216
217 Data_Get_Struct(self, guest_t, guest);
218 guest->stop(guest, NULL);
219 return self;
220 }
221
222 static VALUE guest_running(VALUE self)
223 {
224 guest_t *guest;
225
226 Data_Get_Struct(self, guest_t, guest);
227 return guest->get_pid(guest) ? Qtrue : Qfalse;
228 }
229
230 static void exec_cb(void *data, char *buf)
231 {
232 rb_yield(rb_str_new2(buf));
233 }
234
235 static VALUE guest_exec(VALUE self, VALUE cmd)
236 {
237 guest_t *guest;
238 bool block;
239 int ret;
240
241 block = rb_block_given_p();
242 Data_Get_Struct(self, guest_t, guest);
243 if ((ret = guest->exec_str(guest, block ? (void*)exec_cb : NULL, TRUE, NULL,
244 "exec %s", StringValuePtr(cmd))) != 0)
245 {
246 rb_raise(rb_eRuntimeError, "executing command failed (%d)", ret);
247 }
248 return self;
249 }
250
251 static VALUE guest_mconsole(VALUE self, VALUE cmd)
252 {
253 guest_t *guest;
254 bool block;
255 int ret;
256
257 block = rb_block_given_p();
258 Data_Get_Struct(self, guest_t, guest);
259 if ((ret = guest->exec_str(guest, block ? (void*)exec_cb : NULL, TRUE, NULL,
260 "%s", StringValuePtr(cmd))) != 0)
261 {
262 rb_raise(rb_eRuntimeError, "executing command failed (%d)", ret);
263 }
264 return self;
265 }
266
267 static VALUE guest_add_iface(VALUE self, VALUE name)
268 {
269 guest_t *guest;
270 iface_t *iface;
271
272 Data_Get_Struct(self, guest_t, guest);
273 iface = guest->create_iface(guest, StringValuePtr(name));
274 if (!iface)
275 {
276 rb_raise(rb_eRuntimeError, "adding interface failed");
277 }
278 return Data_Wrap_Struct(rbc_iface, NULL, NULL, iface);
279 }
280
281 static VALUE guest_find_iface(VALUE self, VALUE key)
282 {
283 enumerator_t *enumerator;
284 iface_t *iface, *found = NULL;
285 guest_t *guest;
286
287 if (TYPE(key) == T_SYMBOL)
288 {
289 key = rb_convert_type(key, T_STRING, "String", "to_s");
290 }
291 Data_Get_Struct(self, guest_t, guest);
292 enumerator = guest->create_iface_enumerator(guest);
293 while (enumerator->enumerate(enumerator, &iface))
294 {
295 if (streq(iface->get_guestif(iface), StringValuePtr(key)))
296 {
297 found = iface;
298 break;
299 }
300 }
301 enumerator->destroy(enumerator);
302 if (!found)
303 {
304 return Qnil;
305 }
306 return Data_Wrap_Struct(rbc_iface, NULL, NULL, iface);
307 }
308
309 static VALUE guest_get_iface(VALUE self, VALUE key)
310 {
311 VALUE iface = guest_find_iface(self, key);
312 if (NIL_P(iface))
313 {
314 rb_raise(rb_eRuntimeError, "interface not found");
315 }
316 return iface;
317 }
318
319 static VALUE guest_each_iface(int argc, VALUE *argv, VALUE self)
320 {
321 enumerator_t *enumerator;
322 linked_list_t *list;
323 guest_t *guest;
324 iface_t *iface;
325
326 if (!rb_block_given_p())
327 {
328 rb_raise(rb_eArgError, "must be called with a block");
329 }
330 Data_Get_Struct(self, guest_t, guest);
331 list = linked_list_create();
332 enumerator = guest->create_iface_enumerator(guest);
333 while (enumerator->enumerate(enumerator, &iface))
334 {
335 list->insert_last(list, iface);
336 }
337 enumerator->destroy(enumerator);
338 while (list->remove_first(list, (void**)&iface) == SUCCESS)
339 {
340 rb_yield(Data_Wrap_Struct(rbc_iface, NULL, NULL, iface));
341 }
342 list->destroy(list);
343 return self;
344 }
345
346 static VALUE guest_delete(VALUE self)
347 {
348 guest_t *guest;
349
350 Data_Get_Struct(self, guest_t, guest);
351 if (guest->get_pid(guest))
352 {
353 rb_raise(rb_eRuntimeError, "guest is running");
354 }
355 dumm->delete_guest(dumm, guest);
356 return Qnil;
357 }
358
359 static VALUE guest_add_overlay(VALUE self, VALUE dir)
360 {
361 guest_t *guest;
362
363 Data_Get_Struct(self, guest_t, guest);
364 if (!guest->add_overlay(guest, StringValuePtr(dir)))
365 {
366 rb_raise(rb_eRuntimeError, "loading overlay failed");
367 }
368 return self;
369 }
370
371 static VALUE guest_del_overlay(VALUE self, VALUE dir)
372 {
373 guest_t *guest;
374
375 Data_Get_Struct(self, guest_t, guest);
376 return guest->del_overlay(guest, StringValuePtr(dir)) ? Qtrue : Qfalse;
377 }
378
379 static VALUE guest_pop_overlay(VALUE self)
380 {
381 guest_t *guest;
382
383 Data_Get_Struct(self, guest_t, guest);
384 return guest->pop_overlay(guest) ? Qtrue : Qfalse;
385 }
386
387 static void guest_init()
388 {
389 rbc_guest = rb_define_class_under(rbm_dumm , "Guest", rb_cObject);
390 rb_include_module(rb_class_of(rbc_guest), rb_mEnumerable);
391 rb_include_module(rbc_guest, rb_mEnumerable);
392
393 rb_define_singleton_method(rbc_guest, "[]", guest_get, 1);
394 rb_define_singleton_method(rbc_guest, "each", guest_each, -1);
395 rb_define_singleton_method(rbc_guest, "new", guest_new, 4);
396 rb_define_singleton_method(rbc_guest, "include?", guest_find, 1);
397 rb_define_singleton_method(rbc_guest, "guest?", guest_find, 1);
398
399 rb_define_method(rbc_guest, "to_s", guest_to_s, 0);
400 rb_define_method(rbc_guest, "start", guest_start, 0);
401 rb_define_method(rbc_guest, "stop", guest_stop, 0);
402 rb_define_method(rbc_guest, "running?", guest_running, 0);
403 rb_define_method(rbc_guest, "exec", guest_exec, 1);
404 rb_define_method(rbc_guest, "mconsole", guest_mconsole, 1);
405 rb_define_method(rbc_guest, "add", guest_add_iface, 1);
406 rb_define_method(rbc_guest, "[]", guest_get_iface, 1);
407 rb_define_method(rbc_guest, "each", guest_each_iface, -1);
408 rb_define_method(rbc_guest, "include?", guest_find_iface, 1);
409 rb_define_method(rbc_guest, "iface?", guest_find_iface, 1);
410 rb_define_method(rbc_guest, "delete", guest_delete, 0);
411 rb_define_method(rbc_guest, "add_overlay", guest_add_overlay, 1);
412 rb_define_method(rbc_guest, "del_overlay", guest_del_overlay, 1);
413 rb_define_method(rbc_guest, "pop_overlay", guest_pop_overlay, 0);
414 }
415
416 /**
417 * Bridge binding
418 */
419 static VALUE bridge_find(VALUE class, VALUE key)
420 {
421 enumerator_t *enumerator;
422 bridge_t *bridge, *found = NULL;
423
424 if (TYPE(key) == T_SYMBOL)
425 {
426 key = rb_convert_type(key, T_STRING, "String", "to_s");
427 }
428 enumerator = dumm->create_bridge_enumerator(dumm);
429 while (enumerator->enumerate(enumerator, &bridge))
430 {
431 if (streq(bridge->get_name(bridge), StringValuePtr(key)))
432 {
433 found = bridge;
434 break;
435 }
436 }
437 enumerator->destroy(enumerator);
438 if (!found)
439 {
440 return Qnil;
441 }
442 return Data_Wrap_Struct(class, NULL, NULL, found);
443 }
444
445 static VALUE bridge_get(VALUE class, VALUE key)
446 {
447 VALUE bridge = bridge_find(class, key);
448 if (NIL_P(bridge))
449 {
450 rb_raise(rb_eRuntimeError, "bridge not found");
451 }
452 return bridge;
453 }
454
455 static VALUE bridge_each(int argc, VALUE *argv, VALUE class)
456 {
457 enumerator_t *enumerator;
458 linked_list_t *list;
459 bridge_t *bridge;
460
461 if (!rb_block_given_p())
462 {
463 rb_raise(rb_eArgError, "must be called with a block");
464 }
465 list = linked_list_create();
466 enumerator = dumm->create_bridge_enumerator(dumm);
467 while (enumerator->enumerate(enumerator, &bridge))
468 {
469 list->insert_last(list, bridge);
470 }
471 enumerator->destroy(enumerator);
472 while (list->remove_first(list, (void**)&bridge) == SUCCESS)
473 {
474 rb_yield(Data_Wrap_Struct(class, NULL, NULL, bridge));
475 }
476 list->destroy(list);
477 return class;
478 }
479
480 static VALUE bridge_new(VALUE class, VALUE name)
481
482 {
483 bridge_t *bridge;
484
485 bridge = dumm->create_bridge(dumm, StringValuePtr(name));
486 if (!bridge)
487 {
488 rb_raise(rb_eRuntimeError, "creating bridge failed");
489 }
490 return Data_Wrap_Struct(class, NULL, NULL, bridge);
491 }
492
493 static VALUE bridge_to_s(VALUE self)
494 {
495 bridge_t *bridge;
496
497 Data_Get_Struct(self, bridge_t, bridge);
498 return rb_str_new2(bridge->get_name(bridge));
499 }
500
501 static VALUE bridge_each_iface(int argc, VALUE *argv, VALUE self)
502 {
503 enumerator_t *enumerator;
504 linked_list_t *list;
505 bridge_t *bridge;
506 iface_t *iface;
507
508 if (!rb_block_given_p())
509 {
510 rb_raise(rb_eArgError, "must be called with a block");
511 }
512 Data_Get_Struct(self, bridge_t, bridge);
513 list = linked_list_create();
514 enumerator = bridge->create_iface_enumerator(bridge);
515 while (enumerator->enumerate(enumerator, &iface))
516 {
517 list->insert_last(list, iface);
518 }
519 enumerator->destroy(enumerator);
520 while (list->remove_first(list, (void**)&iface) == SUCCESS)
521 {
522 rb_yield(Data_Wrap_Struct(rbc_iface, NULL, NULL, iface));
523 }
524 list->destroy(list);
525 return self;
526 }
527
528 static VALUE bridge_delete(VALUE self)
529 {
530 bridge_t *bridge;
531
532 Data_Get_Struct(self, bridge_t, bridge);
533 dumm->delete_bridge(dumm, bridge);
534 return Qnil;
535 }
536
537 static void bridge_init()
538 {
539 rbc_bridge = rb_define_class_under(rbm_dumm , "Bridge", rb_cObject);
540 rb_include_module(rb_class_of(rbc_bridge), rb_mEnumerable);
541 rb_include_module(rbc_bridge, rb_mEnumerable);
542
543 rb_define_singleton_method(rbc_bridge, "[]", bridge_get, 1);
544 rb_define_singleton_method(rbc_bridge, "each", bridge_each, -1);
545 rb_define_singleton_method(rbc_bridge, "new", bridge_new, 1);
546 rb_define_singleton_method(rbc_bridge, "include?", bridge_find, 1);
547 rb_define_singleton_method(rbc_bridge, "bridge?", bridge_find, 1);
548
549 rb_define_method(rbc_bridge, "to_s", bridge_to_s, 0);
550 rb_define_method(rbc_bridge, "each", bridge_each_iface, -1);
551 rb_define_method(rbc_bridge, "delete", bridge_delete, 0);
552 }
553
554 /**
555 * Iface wrapper
556 */
557 static VALUE iface_to_s(VALUE self)
558 {
559 iface_t *iface;
560
561 Data_Get_Struct(self, iface_t, iface);
562 return rb_str_new2(iface->get_hostif(iface));
563 }
564
565 static VALUE iface_connect(VALUE self, VALUE vbridge)
566 {
567 iface_t *iface;
568 bridge_t *bridge;
569
570 Data_Get_Struct(self, iface_t, iface);
571 Data_Get_Struct(vbridge, bridge_t, bridge);
572 if (!bridge->connect_iface(bridge, iface))
573 {
574 rb_raise(rb_eRuntimeError, "connecting iface failed");
575 }
576 return self;
577 }
578
579 static VALUE iface_disconnect(VALUE self)
580 {
581 iface_t *iface;
582 bridge_t *bridge;
583
584 Data_Get_Struct(self, iface_t, iface);
585 bridge = iface->get_bridge(iface);
586 if (!bridge || !bridge->disconnect_iface(bridge, iface))
587 {
588 rb_raise(rb_eRuntimeError, "disconnecting iface failed");
589 }
590 return self;
591 }
592
593 static VALUE iface_add_addr(VALUE self, VALUE name)
594 {
595 iface_t *iface;
596 host_t *addr;
597
598 addr = host_create_from_string(StringValuePtr(name), 0);
599 if (!addr)
600 {
601 rb_raise(rb_eArgError, "invalid IP address");
602 }
603 Data_Get_Struct(self, iface_t, iface);
604 if (!iface->add_address(iface, addr))
605 {
606 addr->destroy(addr);
607 rb_raise(rb_eRuntimeError, "adding address failed");
608 }
609 if (rb_block_given_p()) {
610 rb_yield(self);
611 iface->delete_address(iface, addr);
612 }
613 addr->destroy(addr);
614 return self;
615 }
616
617 static VALUE iface_each_addr(int argc, VALUE *argv, VALUE self)
618 {
619 enumerator_t *enumerator;
620 linked_list_t *list;
621 iface_t *iface;
622 host_t *addr;
623 char buf[64];
624
625 if (!rb_block_given_p())
626 {
627 rb_raise(rb_eArgError, "must be called with a block");
628 }
629 Data_Get_Struct(self, iface_t, iface);
630 enumerator = iface->create_address_enumerator(iface);
631 while (enumerator->enumerate(enumerator, &addr))
632 {
633 list->insert_last(list, addr->clone(addr));
634 }
635 enumerator->destroy(enumerator);
636 while (list->remove_first(list, (void**)&addr) == SUCCESS)
637 {
638 snprintf(buf, sizeof(buf), "%H", addr);
639 addr->destroy(addr);
640 rb_yield(rb_str_new2(buf));
641 }
642 list->destroy(list);
643 return self;
644 }
645
646 static VALUE iface_del_addr(VALUE self, VALUE vaddr)
647 {
648 iface_t *iface;
649 host_t *addr;
650
651 addr = host_create_from_string(StringValuePtr(vaddr), 0);
652 if (!addr)
653 {
654 rb_raise(rb_eArgError, "invalid IP address");
655 }
656 Data_Get_Struct(self, iface_t, iface);
657 if (!iface->delete_address(iface, addr))
658 {
659 addr->destroy(addr);
660 rb_raise(rb_eRuntimeError, "address not found");
661 }
662 if (rb_block_given_p()) {
663 rb_yield(self);
664 iface->add_address(iface, addr);
665 }
666 addr->destroy(addr);
667 return self;
668 }
669
670 static VALUE iface_delete(VALUE self)
671 {
672 guest_t *guest;
673 iface_t *iface;
674
675 Data_Get_Struct(self, iface_t, iface);
676 guest = iface->get_guest(iface);
677 guest->destroy_iface(guest, iface);
678 return Qnil;
679 }
680
681 static void iface_init()
682 {
683 rbc_iface = rb_define_class_under(rbm_dumm , "Iface", rb_cObject);
684 rb_include_module(rbc_iface, rb_mEnumerable);
685
686 rb_define_method(rbc_iface, "to_s", iface_to_s, 0);
687 rb_define_method(rbc_iface, "connect", iface_connect, 1);
688 rb_define_method(rbc_iface, "disconnect", iface_disconnect, 0);
689 rb_define_method(rbc_iface, "add", iface_add_addr, 1);
690 rb_define_method(rbc_iface, "del", iface_del_addr, 1);
691 rb_define_method(rbc_iface, "each", iface_each_addr, -1);
692 rb_define_method(rbc_iface, "delete", iface_delete, 0);
693 }
694
695 static VALUE template_load(VALUE class, VALUE dir)
696 {
697 if (!dumm->load_template(dumm, StringValuePtr(dir)))
698 {
699 rb_raise(rb_eRuntimeError, "loading template failed");
700 }
701 return class;
702 }
703
704 static VALUE template_unload(VALUE class)
705 {
706 if (!dumm->load_template(dumm, NULL))
707 {
708 rb_raise(rb_eRuntimeError, "unloading template failed");
709 }
710 return class;
711 }
712
713 static VALUE template_each(int argc, VALUE *argv, VALUE class)
714 {
715 enumerator_t *enumerator;
716 char *template;
717
718 if (!rb_block_given_p())
719 {
720 rb_raise(rb_eArgError, "must be called with a block");
721 }
722 enumerator = dumm->create_template_enumerator(dumm);
723 while (enumerator->enumerate(enumerator, &template))
724 {
725 rb_yield(rb_str_new2(template));
726 }
727 enumerator->destroy(enumerator);
728 return class;
729 }
730
731 static void template_init()
732 {
733 rbc_template = rb_define_class_under(rbm_dumm , "Template", rb_cObject);
734
735 rb_define_singleton_method(rbc_template, "load", template_load, 1);
736 rb_define_singleton_method(rbc_template, "unload", template_unload, 0);
737 rb_define_singleton_method(rbc_template, "each", template_each, -1);
738 }
739
740 /**
741 * extension finalization
742 */
743 void Final_dumm()
744 {
745 struct sigaction action;
746
747 dumm->destroy(dumm);
748
749 sigemptyset(&action.sa_mask);
750 action.sa_handler = SIG_DFL;
751 action.sa_flags = 0;
752 sigaction(SIGCHLD, &action, NULL);
753
754 library_deinit();
755 }
756
757 /**
758 * extension initialization
759 */
760 void Init_dumm()
761 {
762 struct sigaction action;
763
764 /* there are too many to report, rubyruby... */
765 setenv("LEAK_DETECTIVE_DISABLE", "1", 1);
766
767 library_init(NULL);
768
769 dumm = dumm_create(NULL);
770
771 dumm_init();
772 guest_init();
773 bridge_init();
774 iface_init();
775 template_init();
776
777 sigemptyset(&action.sa_mask);
778 action.sa_sigaction = sigchld_handler;
779 action.sa_flags = SA_SIGINFO;
780 sigaction(SIGCHLD, &action, NULL);
781
782 rb_set_end_proc(Final_dumm, 0);
783 }