2 * Copyright (C) 2008 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
29 #undef PACKAGE_TARNAME
30 #undef PACKAGE_VERSION
36 static VALUE rbm_dumm
;
37 static VALUE rbc_guest
;
38 static VALUE rbc_bridge
;
39 static VALUE rbc_iface
;
40 static VALUE rbc_template
;
43 * Guest invocation callback
45 static pid_t
invoke(void *null
, guest_t
*guest
, char *args
[], int argc
)
49 args
[argc
++] = "con0=xterm";
50 args
[argc
++] = "xterm=gnome-terminal,-t,-x";
56 /* create a new process group in order to prevent signals (e.g.
57 * SIGINT) sent to the parent from terminating the child */
59 dup2(open("/dev/null", 0), 1);
60 dup2(open("/dev/null", 0), 2);
61 execvp(args
[0], args
);
71 * SIGCHLD signal handler
73 static void sigchld_handler(int signal
, siginfo_t
*info
, void* ptr
)
75 enumerator_t
*enumerator
;
78 enumerator
= dumm
->create_guest_enumerator(dumm
);
79 while (enumerator
->enumerate(enumerator
, &guest
))
81 if (guest
->get_pid(guest
) == info
->si_pid
)
83 guest
->sigchild(guest
);
87 enumerator
->destroy(enumerator
);
95 static VALUE
guest_find(VALUE
class, VALUE key
)
97 enumerator_t
*enumerator
;
98 guest_t
*guest
, *found
= NULL
;
99 if (TYPE(key
) == T_SYMBOL
) {
100 key
= rb_convert_type(key
, T_STRING
, "String", "to_s");
102 enumerator
= dumm
->create_guest_enumerator(dumm
);
103 while (enumerator
->enumerate(enumerator
, &guest
))
105 if (streq(guest
->get_name(guest
), StringValuePtr(key
)))
111 enumerator
->destroy(enumerator
);
116 return Data_Wrap_Struct(class, NULL
, NULL
, found
);
119 static VALUE
guest_get(VALUE
class, VALUE key
)
121 VALUE guest
= guest_find(class, key
);
124 rb_raise(rb_eRuntimeError
, "guest not found");
129 static VALUE
guest_exist(VALUE
class, VALUE key
)
131 return NIL_P(guest_find(class, key
)) ? Qfalse
: Qtrue
;
134 static VALUE
guest_each(int argc
, VALUE
*argv
, VALUE
class)
136 enumerator_t
*enumerator
;
139 if (!rb_block_given_p())
141 rb_raise(rb_eArgError
, "must be called with a block");
143 enumerator
= dumm
->create_guest_enumerator(dumm
);
144 while (enumerator
->enumerate(enumerator
, &guest
))
146 rb_yield(Data_Wrap_Struct(class, NULL
, NULL
, guest
));
148 enumerator
->destroy(enumerator
);
152 static VALUE
guest_new(VALUE
class, VALUE name
, VALUE kernel
,
153 VALUE master
, VALUE mem
)
157 guest
= dumm
->create_guest(dumm
, StringValuePtr(name
), StringValuePtr(kernel
),
158 StringValuePtr(master
), FIX2INT(mem
));
161 rb_raise(rb_eRuntimeError
, "creating guest failed");
163 return Data_Wrap_Struct(class, NULL
, NULL
, guest
);
166 static VALUE
guest_to_s(VALUE self
)
170 Data_Get_Struct(self
, guest_t
, guest
);
171 return rb_str_new2(guest
->get_name(guest
));
174 static VALUE
guest_start(VALUE self
)
178 Data_Get_Struct(self
, guest_t
, guest
);
180 if (!guest
->start(guest
, invoke
, NULL
, NULL
))
182 rb_raise(rb_eRuntimeError
, "starting guest failed");
187 static VALUE
guest_stop(VALUE self
)
191 Data_Get_Struct(self
, guest_t
, guest
);
192 guest
->stop(guest
, NULL
);
196 static VALUE
guest_running(VALUE self
)
200 Data_Get_Struct(self
, guest_t
, guest
);
201 return guest
->get_pid(guest
) ? Qtrue
: Qfalse
;
204 static void exec_cb(void *data
, char *buf
)
206 rb_yield(rb_str_new2(buf
));
209 static VALUE
guest_exec(VALUE self
, VALUE cmd
)
215 block
= rb_block_given_p();
216 Data_Get_Struct(self
, guest_t
, guest
);
217 if ((ret
= guest
->exec_str(guest
, block ?
(void*)exec_cb
: NULL
, TRUE
, NULL
,
218 "%s", StringValuePtr(cmd
))) != 0)
220 rb_raise(rb_eRuntimeError
, "executing command failed (%d)", ret
);
225 static VALUE
guest_add_iface(VALUE self
, VALUE name
)
230 Data_Get_Struct(self
, guest_t
, guest
);
231 iface
= guest
->create_iface(guest
, StringValuePtr(name
));
234 rb_raise(rb_eRuntimeError
, "adding interface failed");
236 return Data_Wrap_Struct(rbc_iface
, NULL
, NULL
, iface
);
239 static VALUE
guest_find_iface(VALUE self
, VALUE key
)
241 enumerator_t
*enumerator
;
242 iface_t
*iface
, *found
= NULL
;
244 if (TYPE(key
) == T_SYMBOL
) {
245 key
= rb_convert_type(key
, T_STRING
, "String", "to_s");
247 Data_Get_Struct(self
, guest_t
, guest
);
248 enumerator
= guest
->create_iface_enumerator(guest
);
249 while (enumerator
->enumerate(enumerator
, &iface
))
251 if (streq(iface
->get_guestif(iface
), StringValuePtr(key
)))
257 enumerator
->destroy(enumerator
);
262 return Data_Wrap_Struct(rbc_iface
, NULL
, NULL
, iface
);
265 static VALUE
guest_get_iface(VALUE self
, VALUE key
)
267 VALUE iface
= guest_find_iface(self
, key
);
270 rb_raise(rb_eRuntimeError
, "interface not found");
275 static VALUE
guest_exist_iface(VALUE self
, VALUE key
)
277 return NIL_P(guest_find_iface(self
, key
)) ? Qfalse
: Qtrue
;
280 static VALUE
guest_each_iface(int argc
, VALUE
*argv
, VALUE self
)
282 enumerator_t
*enumerator
;
286 if (!rb_block_given_p())
288 rb_raise(rb_eArgError
, "must be called with a block");
290 Data_Get_Struct(self
, guest_t
, guest
);
291 enumerator
= guest
->create_iface_enumerator(guest
);
292 while (enumerator
->enumerate(enumerator
, &iface
))
294 rb_yield(Data_Wrap_Struct(rbc_iface
, NULL
, NULL
, iface
));
296 enumerator
->destroy(enumerator
);
300 static VALUE
guest_delete(VALUE self
)
304 Data_Get_Struct(self
, guest_t
, guest
);
305 dumm
->delete_guest(dumm
, guest
);
309 static void guest_init()
311 rbc_guest
= rb_define_class_under(rbm_dumm
, "Guest", rb_cObject
);
312 rb_include_module(rb_class_of(rbc_guest
), rb_mEnumerable
);
313 rb_include_module(rbc_guest
, rb_mEnumerable
);
315 rb_define_singleton_method(rbc_guest
, "[]", guest_get
, 1);
316 rb_define_singleton_method(rbc_guest
, "each", guest_each
, -1);
317 rb_define_singleton_method(rbc_guest
, "new", guest_new
, 4);
318 rb_define_singleton_method(rbc_guest
, "include?", guest_exist
, 1);
319 rb_define_singleton_method(rbc_guest
, "guest?", guest_exist
, 1);
321 rb_define_method(rbc_guest
, "to_s", guest_to_s
, 0);
322 rb_define_method(rbc_guest
, "start", guest_start
, 0);
323 rb_define_method(rbc_guest
, "stop", guest_stop
, 0);
324 rb_define_method(rbc_guest
, "running?", guest_running
, 0);
325 rb_define_method(rbc_guest
, "exec", guest_exec
, 1);
326 rb_define_method(rbc_guest
, "add", guest_add_iface
, 1);
327 rb_define_method(rbc_guest
, "[]", guest_get_iface
, 1);
328 rb_define_method(rbc_guest
, "each", guest_each_iface
, -1);
329 rb_define_method(rbc_guest
, "include?", guest_exist_iface
, 1);
330 rb_define_method(rbc_guest
, "iface?", guest_exist_iface
, 1);
331 rb_define_method(rbc_guest
, "delete", guest_delete
, 0);
337 static VALUE
bridge_get(VALUE
class, VALUE key
)
339 enumerator_t
*enumerator
;
340 bridge_t
*bridge
, *found
= NULL
;
342 enumerator
= dumm
->create_bridge_enumerator(dumm
);
343 while (enumerator
->enumerate(enumerator
, &bridge
))
345 if (streq(bridge
->get_name(bridge
), StringValuePtr(key
)))
351 enumerator
->destroy(enumerator
);
354 rb_raise(rb_eRuntimeError
, "bridge not found");
356 return Data_Wrap_Struct(class, NULL
, NULL
, found
);
359 static VALUE
bridge_each(int argc
, VALUE
*argv
, VALUE
class)
361 enumerator_t
*enumerator
;
364 if (!rb_block_given_p())
366 rb_raise(rb_eArgError
, "must be called with a block");
368 enumerator
= dumm
->create_bridge_enumerator(dumm
);
369 while (enumerator
->enumerate(enumerator
, &bridge
))
371 rb_yield(Data_Wrap_Struct(class, NULL
, NULL
, bridge
));
373 enumerator
->destroy(enumerator
);
377 static VALUE
bridge_new(VALUE
class, VALUE name
)
382 bridge
= dumm
->create_bridge(dumm
, StringValuePtr(name
));
385 rb_raise(rb_eRuntimeError
, "creating bridge failed");
387 return Data_Wrap_Struct(class, NULL
, NULL
, bridge
);
390 static VALUE
bridge_to_s(VALUE self
)
394 Data_Get_Struct(self
, bridge_t
, bridge
);
395 return rb_str_new2(bridge
->get_name(bridge
));
398 static VALUE
bridge_each_iface(int argc
, VALUE
*argv
, VALUE self
)
400 enumerator_t
*enumerator
;
404 if (!rb_block_given_p())
406 rb_raise(rb_eArgError
, "must be called with a block");
408 Data_Get_Struct(self
, bridge_t
, bridge
);
409 enumerator
= bridge
->create_iface_enumerator(bridge
);
410 while (enumerator
->enumerate(enumerator
, &iface
))
412 rb_yield(Data_Wrap_Struct(rbc_iface
, NULL
, NULL
, iface
));
414 enumerator
->destroy(enumerator
);
418 static VALUE
bridge_delete(VALUE self
)
422 Data_Get_Struct(self
, bridge_t
, bridge
);
423 dumm
->delete_bridge(dumm
, bridge
);
427 static void bridge_init()
429 rbc_bridge
= rb_define_class_under(rbm_dumm
, "Bridge", rb_cObject
);
430 rb_include_module(rb_class_of(rbc_bridge
), rb_mEnumerable
);
431 rb_include_module(rbc_bridge
, rb_mEnumerable
);
433 rb_define_singleton_method(rbc_bridge
, "[]", bridge_get
, 1);
434 rb_define_singleton_method(rbc_bridge
, "each", bridge_each
, -1);
435 rb_define_singleton_method(rbc_bridge
, "new", bridge_new
, 1);
437 rb_define_method(rbc_bridge
, "to_s", bridge_to_s
, 0);
438 rb_define_method(rbc_bridge
, "each", bridge_each_iface
, -1);
439 rb_define_method(rbc_bridge
, "delete", bridge_delete
, 0);
445 static VALUE
iface_to_s(VALUE self
)
449 Data_Get_Struct(self
, iface_t
, iface
);
450 return rb_str_new2(iface
->get_hostif(iface
));
453 static VALUE
iface_connect(VALUE self
, VALUE vbridge
)
458 Data_Get_Struct(self
, iface_t
, iface
);
459 Data_Get_Struct(vbridge
, bridge_t
, bridge
);
460 if (!bridge
->connect_iface(bridge
, iface
))
462 rb_raise(rb_eRuntimeError
, "connecting iface failed");
467 static VALUE
iface_disconnect(VALUE self
)
472 Data_Get_Struct(self
, iface_t
, iface
);
473 bridge
= iface
->get_bridge(iface
);
474 if (!bridge
|| !bridge
->disconnect_iface(bridge
, iface
))
476 rb_raise(rb_eRuntimeError
, "disconnecting iface failed");
481 static VALUE
iface_add_addr(VALUE self
, VALUE name
)
486 addr
= host_create_from_string(StringValuePtr(name
), 0);
489 rb_raise(rb_eArgError
, "invalid IP address");
491 Data_Get_Struct(self
, iface_t
, iface
);
492 if (!iface
->add_address(iface
, addr
))
495 rb_raise(rb_eRuntimeError
, "adding address failed");
497 if (rb_block_given_p()) {
499 iface
->delete_address(iface
, addr
);
505 static VALUE
iface_each_addr(int argc
, VALUE
*argv
, VALUE self
)
507 enumerator_t
*enumerator
;
512 if (!rb_block_given_p())
514 rb_raise(rb_eArgError
, "must be called with a block");
516 Data_Get_Struct(self
, iface_t
, iface
);
517 enumerator
= iface
->create_address_enumerator(iface
);
518 while (enumerator
->enumerate(enumerator
, &addr
))
520 snprintf(buf
, sizeof(buf
), "%H", addr
);
521 rb_yield(rb_str_new2(buf
));
523 enumerator
->destroy(enumerator
);
527 static VALUE
iface_del_addr(VALUE self
, VALUE vaddr
)
532 addr
= host_create_from_string(StringValuePtr(vaddr
), 0);
535 rb_raise(rb_eArgError
, "invalid IP address");
537 Data_Get_Struct(self
, iface_t
, iface
);
538 if (!iface
->delete_address(iface
, addr
))
541 rb_raise(rb_eRuntimeError
, "address not found");
543 if (rb_block_given_p()) {
545 iface
->add_address(iface
, addr
);
551 static VALUE
iface_delete(VALUE self
)
556 Data_Get_Struct(self
, iface_t
, iface
);
557 guest
= iface
->get_guest(iface
);
558 guest
->destroy_iface(guest
, iface
);
562 static void iface_init()
564 rbc_iface
= rb_define_class_under(rbm_dumm
, "Iface", rb_cObject
);
565 rb_include_module(rbc_iface
, rb_mEnumerable
);
567 rb_define_method(rbc_iface
, "to_s", iface_to_s
, 0);
568 rb_define_method(rbc_iface
, "connect", iface_connect
, 1);
569 rb_define_method(rbc_iface
, "disconnect", iface_disconnect
, 0);
570 rb_define_method(rbc_iface
, "add", iface_add_addr
, 1);
571 rb_define_method(rbc_iface
, "del", iface_del_addr
, 1);
572 rb_define_method(rbc_iface
, "each", iface_each_addr
, -1);
573 rb_define_method(rbc_iface
, "delete", iface_delete
, 0);
576 static VALUE
template_load(VALUE
class, VALUE name
)
578 if (!dumm
->load_template(dumm
, StringValuePtr(name
)))
580 rb_raise(rb_eRuntimeError
, "loading template failed");
585 static VALUE
template_unload(VALUE
class)
587 if (!dumm
->load_template(dumm
, NULL
))
589 rb_raise(rb_eRuntimeError
, "unloading template failed");
594 static void template_init()
596 rbc_template
= rb_define_class_under(rbm_dumm
, "Template", rb_cObject
);
598 rb_define_singleton_method(rbc_template
, "load", template_load
, 1);
599 rb_define_singleton_method(rbc_template
, "unload", template_unload
, 0);
603 * extension finalization
607 struct sigaction action
;
611 sigemptyset(&action
.sa_mask
);
612 action
.sa_handler
= SIG_DFL
;
614 sigaction(SIGCHLD
, &action
, NULL
);
620 * extension initialization
624 struct sigaction action
;
626 /* there are too many to report, rubyruby... */
627 setenv("LEAK_DETECTIVE_DISABLE", "1", 1);
631 dumm
= dumm_create(NULL
);
633 rbm_dumm
= rb_define_module("Dumm");
640 sigemptyset(&action
.sa_mask
);
641 action
.sa_sigaction
= sigchld_handler
;
642 action
.sa_flags
= SA_SIGINFO
;
643 sigaction(SIGCHLD
, &action
, NULL
);
645 rb_set_end_proc(Final_dumm
, 0);