a970046fe0c97b3756ef0fc8de8bc836d6fe47a6
2 * Copyright (C) 2008-2009 Tobias Brunner
3 * Copyright (C) 2008 Martin Willi
4 * Hochschule fuer Technik Rapperswil
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>.
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
25 #include <utils/linked_list.h>
28 #undef PACKAGE_TARNAME
29 #undef PACKAGE_VERSION
31 #undef PACKAGE_BUGREPORT
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
;
44 * Guest invocation callback
46 static pid_t
invoke(void *null
, guest_t
*guest
, char *args
[], int argc
)
54 /* create a new process group in order to prevent signals (e.g.
55 * SIGINT) sent to the parent from terminating the child */
57 dup2(open("/dev/null", 0), 1);
58 dup2(open("/dev/null", 0), 2);
59 execvp(args
[0], args
);
69 * SIGCHLD signal handler
71 static void sigchld_handler(int signal
, siginfo_t
*info
, void* ptr
)
73 enumerator_t
*enumerator
;
76 enumerator
= dumm
->create_guest_enumerator(dumm
);
77 while (enumerator
->enumerate(enumerator
, &guest
))
79 if (guest
->get_pid(guest
) == info
->si_pid
)
81 guest
->sigchild(guest
);
85 enumerator
->destroy(enumerator
);
90 * Global Dumm bindings
92 static VALUE
dumm_add_overlay(VALUE
class, VALUE dir
)
94 if (!dumm
->add_overlay(dumm
, StringValuePtr(dir
)))
96 rb_raise(rb_eRuntimeError
, "loading overlay failed");
101 static VALUE
dumm_del_overlay(VALUE
class, VALUE dir
)
103 return dumm
->del_overlay(dumm
, StringValuePtr(dir
)) ? Qtrue
: Qfalse
;
106 static VALUE
dumm_pop_overlay(VALUE
class)
108 return dumm
->pop_overlay(dumm
) ? Qtrue
: Qfalse
;
111 static void dumm_init()
113 rbm_dumm
= rb_define_module("Dumm");
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);
123 static VALUE
guest_find(VALUE
class, VALUE key
)
125 enumerator_t
*enumerator
;
126 guest_t
*guest
, *found
= NULL
;
128 if (TYPE(key
) == T_SYMBOL
)
130 key
= rb_convert_type(key
, T_STRING
, "String", "to_s");
132 enumerator
= dumm
->create_guest_enumerator(dumm
);
133 while (enumerator
->enumerate(enumerator
, &guest
))
135 if (streq(guest
->get_name(guest
), StringValuePtr(key
)))
141 enumerator
->destroy(enumerator
);
146 return Data_Wrap_Struct(class, NULL
, NULL
, found
);
149 static VALUE
guest_get(VALUE
class, VALUE key
)
151 VALUE guest
= guest_find(class, key
);
154 rb_raise(rb_eRuntimeError
, "guest not found");
159 static VALUE
guest_each(int argc
, VALUE
*argv
, VALUE
class)
162 enumerator_t
*enumerator
;
165 if (!rb_block_given_p())
167 rb_raise(rb_eArgError
, "must be called with a block");
169 list
= linked_list_create();
170 enumerator
= dumm
->create_guest_enumerator(dumm
);
171 while (enumerator
->enumerate(enumerator
, &guest
))
173 list
->insert_last(list
, guest
);
175 enumerator
->destroy(enumerator
);
176 while (list
->remove_first(list
, (void**)&guest
) == SUCCESS
)
178 rb_yield(Data_Wrap_Struct(class, NULL
, NULL
, guest
));
184 static VALUE
guest_new(VALUE
class, VALUE name
, VALUE kernel
,
185 VALUE master
, VALUE args
)
189 guest
= dumm
->create_guest(dumm
, StringValuePtr(name
), StringValuePtr(kernel
),
190 StringValuePtr(master
), StringValuePtr(args
));
193 rb_raise(rb_eRuntimeError
, "creating guest failed");
195 return Data_Wrap_Struct(class, NULL
, NULL
, guest
);
198 static VALUE
guest_to_s(VALUE self
)
202 Data_Get_Struct(self
, guest_t
, guest
);
203 return rb_str_new2(guest
->get_name(guest
));
206 static VALUE
guest_start(VALUE self
)
210 Data_Get_Struct(self
, guest_t
, guest
);
212 if (!guest
->start(guest
, invoke
, NULL
, NULL
))
214 rb_raise(rb_eRuntimeError
, "starting guest failed");
219 static VALUE
guest_stop(VALUE self
)
223 Data_Get_Struct(self
, guest_t
, guest
);
224 guest
->stop(guest
, NULL
);
228 static VALUE
guest_running(VALUE self
)
232 Data_Get_Struct(self
, guest_t
, guest
);
233 return guest
->get_pid(guest
) ? Qtrue
: Qfalse
;
236 static void exec_cb(void *data
, char *buf
)
238 rb_yield(rb_str_new2(buf
));
241 static VALUE
guest_exec(VALUE self
, VALUE cmd
)
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)
252 rb_raise(rb_eRuntimeError
, "executing command failed (%d)", ret
);
257 static VALUE
guest_mconsole(VALUE self
, VALUE cmd
)
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)
268 rb_raise(rb_eRuntimeError
, "executing command failed (%d)", ret
);
273 static VALUE
guest_add_iface(VALUE self
, VALUE name
)
278 Data_Get_Struct(self
, guest_t
, guest
);
279 iface
= guest
->create_iface(guest
, StringValuePtr(name
));
282 rb_raise(rb_eRuntimeError
, "adding interface failed");
284 return Data_Wrap_Struct(rbc_iface
, NULL
, NULL
, iface
);
287 static VALUE
guest_find_iface(VALUE self
, VALUE key
)
289 enumerator_t
*enumerator
;
290 iface_t
*iface
, *found
= NULL
;
293 if (TYPE(key
) == T_SYMBOL
)
295 key
= rb_convert_type(key
, T_STRING
, "String", "to_s");
297 Data_Get_Struct(self
, guest_t
, guest
);
298 enumerator
= guest
->create_iface_enumerator(guest
);
299 while (enumerator
->enumerate(enumerator
, &iface
))
301 if (streq(iface
->get_guestif(iface
), StringValuePtr(key
)))
307 enumerator
->destroy(enumerator
);
312 return Data_Wrap_Struct(rbc_iface
, NULL
, NULL
, iface
);
315 static VALUE
guest_get_iface(VALUE self
, VALUE key
)
317 VALUE iface
= guest_find_iface(self
, key
);
320 rb_raise(rb_eRuntimeError
, "interface not found");
325 static VALUE
guest_each_iface(int argc
, VALUE
*argv
, VALUE self
)
327 enumerator_t
*enumerator
;
332 if (!rb_block_given_p())
334 rb_raise(rb_eArgError
, "must be called with a block");
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
))
341 list
->insert_last(list
, iface
);
343 enumerator
->destroy(enumerator
);
344 while (list
->remove_first(list
, (void**)&iface
) == SUCCESS
)
346 rb_yield(Data_Wrap_Struct(rbc_iface
, NULL
, NULL
, iface
));
352 static VALUE
guest_delete(VALUE self
)
356 Data_Get_Struct(self
, guest_t
, guest
);
357 if (guest
->get_pid(guest
))
359 rb_raise(rb_eRuntimeError
, "guest is running");
361 dumm
->delete_guest(dumm
, guest
);
365 static VALUE
guest_add_overlay(VALUE self
, VALUE dir
)
369 Data_Get_Struct(self
, guest_t
, guest
);
370 if (!guest
->add_overlay(guest
, StringValuePtr(dir
)))
372 rb_raise(rb_eRuntimeError
, "loading overlay failed");
377 static VALUE
guest_del_overlay(VALUE self
, VALUE dir
)
381 Data_Get_Struct(self
, guest_t
, guest
);
382 return guest
->del_overlay(guest
, StringValuePtr(dir
)) ? Qtrue
: Qfalse
;
385 static VALUE
guest_pop_overlay(VALUE self
)
389 Data_Get_Struct(self
, guest_t
, guest
);
390 return guest
->pop_overlay(guest
) ? Qtrue
: Qfalse
;
393 static void guest_init()
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
);
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);
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);
425 static VALUE
bridge_find(VALUE
class, VALUE key
)
427 enumerator_t
*enumerator
;
428 bridge_t
*bridge
, *found
= NULL
;
430 if (TYPE(key
) == T_SYMBOL
)
432 key
= rb_convert_type(key
, T_STRING
, "String", "to_s");
434 enumerator
= dumm
->create_bridge_enumerator(dumm
);
435 while (enumerator
->enumerate(enumerator
, &bridge
))
437 if (streq(bridge
->get_name(bridge
), StringValuePtr(key
)))
443 enumerator
->destroy(enumerator
);
448 return Data_Wrap_Struct(class, NULL
, NULL
, found
);
451 static VALUE
bridge_get(VALUE
class, VALUE key
)
453 VALUE bridge
= bridge_find(class, key
);
456 rb_raise(rb_eRuntimeError
, "bridge not found");
461 static VALUE
bridge_each(int argc
, VALUE
*argv
, VALUE
class)
463 enumerator_t
*enumerator
;
467 if (!rb_block_given_p())
469 rb_raise(rb_eArgError
, "must be called with a block");
471 list
= linked_list_create();
472 enumerator
= dumm
->create_bridge_enumerator(dumm
);
473 while (enumerator
->enumerate(enumerator
, &bridge
))
475 list
->insert_last(list
, bridge
);
477 enumerator
->destroy(enumerator
);
478 while (list
->remove_first(list
, (void**)&bridge
) == SUCCESS
)
480 rb_yield(Data_Wrap_Struct(class, NULL
, NULL
, bridge
));
486 static VALUE
bridge_new(VALUE
class, VALUE name
)
491 bridge
= dumm
->create_bridge(dumm
, StringValuePtr(name
));
494 rb_raise(rb_eRuntimeError
, "creating bridge failed");
496 return Data_Wrap_Struct(class, NULL
, NULL
, bridge
);
499 static VALUE
bridge_to_s(VALUE self
)
503 Data_Get_Struct(self
, bridge_t
, bridge
);
504 return rb_str_new2(bridge
->get_name(bridge
));
507 static VALUE
bridge_each_iface(int argc
, VALUE
*argv
, VALUE self
)
509 enumerator_t
*enumerator
;
514 if (!rb_block_given_p())
516 rb_raise(rb_eArgError
, "must be called with a block");
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
))
523 list
->insert_last(list
, iface
);
525 enumerator
->destroy(enumerator
);
526 while (list
->remove_first(list
, (void**)&iface
) == SUCCESS
)
528 rb_yield(Data_Wrap_Struct(rbc_iface
, NULL
, NULL
, iface
));
534 static VALUE
bridge_delete(VALUE self
)
538 Data_Get_Struct(self
, bridge_t
, bridge
);
539 dumm
->delete_bridge(dumm
, bridge
);
543 static void bridge_init()
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
);
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);
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);
563 static VALUE
iface_to_s(VALUE self
)
567 Data_Get_Struct(self
, iface_t
, iface
);
568 return rb_str_new2(iface
->get_hostif(iface
));
571 static VALUE
iface_connect(VALUE self
, VALUE vbridge
)
576 Data_Get_Struct(self
, iface_t
, iface
);
577 Data_Get_Struct(vbridge
, bridge_t
, bridge
);
578 if (!bridge
->connect_iface(bridge
, iface
))
580 rb_raise(rb_eRuntimeError
, "connecting iface failed");
585 static VALUE
iface_disconnect(VALUE self
)
590 Data_Get_Struct(self
, iface_t
, iface
);
591 bridge
= iface
->get_bridge(iface
);
592 if (!bridge
|| !bridge
->disconnect_iface(bridge
, iface
))
594 rb_raise(rb_eRuntimeError
, "disconnecting iface failed");
599 static VALUE
iface_add_addr(VALUE self
, VALUE name
)
604 addr
= host_create_from_string(StringValuePtr(name
), 0);
607 rb_raise(rb_eArgError
, "invalid IP address");
609 Data_Get_Struct(self
, iface_t
, iface
);
610 if (!iface
->add_address(iface
, addr
))
613 rb_raise(rb_eRuntimeError
, "adding address failed");
615 if (rb_block_given_p()) {
617 iface
->delete_address(iface
, addr
);
623 static VALUE
iface_each_addr(int argc
, VALUE
*argv
, VALUE self
)
625 enumerator_t
*enumerator
;
631 if (!rb_block_given_p())
633 rb_raise(rb_eArgError
, "must be called with a block");
635 Data_Get_Struct(self
, iface_t
, iface
);
636 enumerator
= iface
->create_address_enumerator(iface
);
637 while (enumerator
->enumerate(enumerator
, &addr
))
639 list
->insert_last(list
, addr
->clone(addr
));
641 enumerator
->destroy(enumerator
);
642 while (list
->remove_first(list
, (void**)&addr
) == SUCCESS
)
644 snprintf(buf
, sizeof(buf
), "%H", addr
);
646 rb_yield(rb_str_new2(buf
));
652 static VALUE
iface_del_addr(VALUE self
, VALUE vaddr
)
657 addr
= host_create_from_string(StringValuePtr(vaddr
), 0);
660 rb_raise(rb_eArgError
, "invalid IP address");
662 Data_Get_Struct(self
, iface_t
, iface
);
663 if (!iface
->delete_address(iface
, addr
))
666 rb_raise(rb_eRuntimeError
, "address not found");
668 if (rb_block_given_p()) {
670 iface
->add_address(iface
, addr
);
676 static VALUE
iface_delete(VALUE self
)
681 Data_Get_Struct(self
, iface_t
, iface
);
682 guest
= iface
->get_guest(iface
);
683 guest
->destroy_iface(guest
, iface
);
687 static void iface_init()
689 rbc_iface
= rb_define_class_under(rbm_dumm
, "Iface", rb_cObject
);
690 rb_include_module(rbc_iface
, rb_mEnumerable
);
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);
701 static VALUE
template_load(VALUE
class, VALUE dir
)
703 if (!dumm
->load_template(dumm
, StringValuePtr(dir
)))
705 rb_raise(rb_eRuntimeError
, "loading template failed");
710 static VALUE
template_unload(VALUE
class)
712 if (!dumm
->load_template(dumm
, NULL
))
714 rb_raise(rb_eRuntimeError
, "unloading template failed");
719 static VALUE
template_each(int argc
, VALUE
*argv
, VALUE
class)
721 enumerator_t
*enumerator
;
724 if (!rb_block_given_p())
726 rb_raise(rb_eArgError
, "must be called with a block");
728 enumerator
= dumm
->create_template_enumerator(dumm
);
729 while (enumerator
->enumerate(enumerator
, &template))
731 rb_yield(rb_str_new2(template));
733 enumerator
->destroy(enumerator
);
737 static void template_init()
739 rbc_template
= rb_define_class_under(rbm_dumm
, "Template", rb_cObject
);
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);
747 * extension finalization
751 struct sigaction action
;
755 sigemptyset(&action
.sa_mask
);
756 action
.sa_handler
= SIG_DFL
;
758 sigaction(SIGCHLD
, &action
, NULL
);
764 * extension initialization
768 struct sigaction action
;
770 /* there are too many to report, rubyruby... */
771 setenv("LEAK_DETECTIVE_DISABLE", "1", 1);
775 dumm
= dumm_create(NULL
);
783 sigemptyset(&action
.sa_mask
);
784 action
.sa_sigaction
= sigchld_handler
;
785 action
.sa_flags
= SA_SIGINFO
;
786 sigaction(SIGCHLD
, &action
, NULL
);
788 rb_set_end_proc(Final_dumm
, 0);