prototype of irdumm - interactive ruby shell for dumm
[strongswan.git] / src / dumm / irdumm.c
1 /*
2 * Copyright (C) 2008 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include <stdio.h>
17 #include <signal.h>
18 #include <unistd.h>
19 #include <fcntl.h>
20
21 #include <library.h>
22 #include <dumm.h>
23
24 #undef PACKAGE_NAME
25 #undef PACKAGE_TARNAME
26 #undef PACKAGE_VERSION
27 #undef PACKAGE_STRING
28 #include <ruby.h>
29
30 dumm_t *dumm;
31
32 VALUE rbm_dumm;
33 VALUE rbc_guest;
34 VALUE rbc_bridge;
35 VALUE rbc_iface;
36
37 /**
38 * Guest invocation callback
39 */
40 static pid_t invoke(void *null, guest_t *guest, char *args[], int argc)
41 {
42 pid_t pid;
43
44 args[argc] = "con0=xterm";
45
46 pid = fork();
47 switch (pid)
48 {
49 case 0: /* child */
50 dup2(open("/dev/null", 0), 1);
51 dup2(open("/dev/null", 0), 2);
52 execvp(args[0], args);
53 /* FALL */
54 case -1:
55 rb_raise(rb_eException, "starting guest failed");
56 return 0;
57 default:
58 return pid;
59 }
60 }
61
62 /**
63 * SIGCHLD signal handler
64 */
65 static void sigchld_handler(int signal, siginfo_t *info, void* ptr)
66 {
67 enumerator_t *enumerator;
68 guest_t *guest;
69
70 enumerator = dumm->create_guest_enumerator(dumm);
71 while (enumerator->enumerate(enumerator, &guest))
72 {
73 if (guest->get_pid(guest) == info->si_pid)
74 {
75 guest->sigchild(guest);
76 break;
77 }
78 }
79 enumerator->destroy(enumerator);
80 }
81
82 /**
83 * Guest bindings
84 */
85 static VALUE guest_get(VALUE class, VALUE key)
86 {
87 enumerator_t *enumerator;
88 guest_t *guest, *found = NULL;
89
90 enumerator = dumm->create_guest_enumerator(dumm);
91 while (enumerator->enumerate(enumerator, &guest))
92 {
93 if (streq(guest->get_name(guest), StringValuePtr(key)))
94 {
95 found = guest;
96 break;
97 }
98 }
99 enumerator->destroy(enumerator);
100 if (!found)
101 {
102 return Qnil;
103 }
104 return Data_Wrap_Struct(class, NULL, NULL, found);
105 }
106
107 static VALUE guest_each(int argc, VALUE *argv, VALUE class)
108 {
109 enumerator_t *enumerator;
110 guest_t *guest;
111
112 if (!rb_block_given_p())
113 {
114 rb_raise(rb_eArgError, "must be called with a block");
115 }
116 enumerator = dumm->create_guest_enumerator(dumm);
117 while (enumerator->enumerate(enumerator, &guest))
118 {
119 rb_yield(Data_Wrap_Struct(class, NULL, NULL, guest));
120 }
121 enumerator->destroy(enumerator);
122 return Qnil;
123 }
124
125 static VALUE guest_new(VALUE class, VALUE name, VALUE kernel,
126 VALUE master, VALUE mem)
127
128 {
129 guest_t *guest;
130
131 guest = dumm->create_guest(dumm, StringValuePtr(name), StringValuePtr(kernel),
132 StringValuePtr(master), FIX2INT(mem));
133 if (!guest)
134 {
135 return Qnil;
136 }
137 return Data_Wrap_Struct(class, NULL, NULL, guest);
138 }
139
140 static VALUE guest_to_s(VALUE self)
141 {
142 guest_t *guest;
143
144 Data_Get_Struct(self, guest_t, guest);
145 return rb_str_new2(guest->get_name(guest));
146 }
147
148 static VALUE guest_start(VALUE self)
149 {
150 guest_t *guest;
151
152 Data_Get_Struct(self, guest_t, guest);
153
154 if (guest->start(guest, invoke, NULL, NULL))
155 {
156 return Qtrue;
157 }
158 return Qfalse;
159 }
160
161 static VALUE guest_stop(VALUE self)
162 {
163 guest_t *guest;
164
165 Data_Get_Struct(self, guest_t, guest);
166
167 if (guest->stop(guest, NULL))
168 {
169 return Qtrue;
170 }
171 return Qfalse;
172 }
173
174 static VALUE guest_add_iface(VALUE self, VALUE name)
175 {
176 guest_t *guest;
177 iface_t *iface;
178
179 Data_Get_Struct(self, guest_t, guest);
180 iface = guest->create_iface(guest, StringValuePtr(name));
181 if (iface)
182 {
183 return Data_Wrap_Struct(rbc_iface, NULL, NULL, iface);
184 }
185 return Qnil;
186 }
187
188 static VALUE guest_get_iface(VALUE self, VALUE key)
189 {
190 enumerator_t *enumerator;
191 iface_t *iface, *found = NULL;
192 guest_t *guest;
193
194 Data_Get_Struct(self, guest_t, guest);
195 enumerator = guest->create_iface_enumerator(guest);
196 while (enumerator->enumerate(enumerator, &iface))
197 {
198 if (streq(iface->get_guestif(iface), StringValuePtr(key)))
199 {
200 found = iface;
201 break;
202 }
203 }
204 enumerator->destroy(enumerator);
205 if (!found)
206 {
207 return Qnil;
208 }
209 return Data_Wrap_Struct(rbc_iface, NULL, NULL, iface);
210 }
211
212 static VALUE guest_each_iface(int argc, VALUE *argv, VALUE self)
213 {
214 enumerator_t *enumerator;
215 guest_t *guest;
216 iface_t *iface;
217
218 if (!rb_block_given_p())
219 {
220 rb_raise(rb_eArgError, "must be called with a block");
221 }
222 Data_Get_Struct(self, guest_t, guest);
223 enumerator = guest->create_iface_enumerator(guest);
224 while (enumerator->enumerate(enumerator, &iface))
225 {
226 rb_yield(Data_Wrap_Struct(rbc_iface, NULL, NULL, iface));
227 }
228 enumerator->destroy(enumerator);
229 return Qnil;
230 }
231
232 static VALUE guest_delete(VALUE self)
233 {
234 guest_t *guest;
235
236 Data_Get_Struct(self, guest_t, guest);
237 dumm->delete_guest(dumm, guest);
238 return Qnil;
239 }
240
241 static void guest_init()
242 {
243 rbc_guest = rb_define_class_under(rbm_dumm , "Guest", rb_cObject);
244 rb_define_singleton_method(rbc_guest, "[]", guest_get, 1);
245 rb_define_singleton_method(rbc_guest, "each", guest_each, -1);
246 rb_define_singleton_method(rbc_guest, "new", guest_new, 4);
247 rb_define_method(rbc_guest, "to_s", guest_to_s, 0);
248 rb_define_method(rbc_guest, "start", guest_start, 0);
249 rb_define_method(rbc_guest, "stop", guest_stop, 0);
250 rb_define_method(rbc_guest, "add", guest_add_iface, 1);
251 rb_define_method(rbc_guest, "[]", guest_get_iface, 1);
252 rb_define_method(rbc_guest, "each", guest_each_iface, -1);
253 rb_define_method(rbc_guest, "delete", guest_delete, 0);
254 }
255
256 /**
257 * Bridge binding
258 */
259 static VALUE bridge_get(VALUE class, VALUE key)
260 {
261 enumerator_t *enumerator;
262 bridge_t *bridge, *found = NULL;
263
264 enumerator = dumm->create_bridge_enumerator(dumm);
265 while (enumerator->enumerate(enumerator, &bridge))
266 {
267 if (streq(bridge->get_name(bridge), StringValuePtr(key)))
268 {
269 found = bridge;
270 break;
271 }
272 }
273 enumerator->destroy(enumerator);
274 if (!found)
275 {
276 return Qnil;
277 }
278 return Data_Wrap_Struct(class, NULL, NULL, found);
279 }
280
281 static VALUE bridge_each(int argc, VALUE *argv, VALUE class)
282 {
283 enumerator_t *enumerator;
284 bridge_t *bridge;
285
286 if (!rb_block_given_p())
287 {
288 rb_raise(rb_eArgError, "must be called with a block");
289 }
290 enumerator = dumm->create_bridge_enumerator(dumm);
291 while (enumerator->enumerate(enumerator, &bridge))
292 {
293 rb_yield(Data_Wrap_Struct(class, NULL, NULL, bridge));
294 }
295 enumerator->destroy(enumerator);
296 return Qnil;
297 }
298
299 static VALUE bridge_new(VALUE class, VALUE name)
300
301 {
302 bridge_t *bridge;
303
304 bridge = dumm->create_bridge(dumm, StringValuePtr(name));
305 if (!bridge)
306 {
307 return Qnil;
308 }
309 return Data_Wrap_Struct(class, NULL, NULL, bridge);
310 }
311
312 static VALUE bridge_to_s(VALUE self)
313 {
314 bridge_t *bridge;
315
316 Data_Get_Struct(self, bridge_t, bridge);
317 return rb_str_new2(bridge->get_name(bridge));
318 }
319
320 static VALUE bridge_each_iface(int argc, VALUE *argv, VALUE self)
321 {
322 enumerator_t *enumerator;
323 bridge_t *bridge;
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, bridge_t, bridge);
331 enumerator = bridge->create_iface_enumerator(bridge);
332 while (enumerator->enumerate(enumerator, &iface))
333 {
334 rb_yield(Data_Wrap_Struct(rbc_iface, NULL, NULL, iface));
335 }
336 enumerator->destroy(enumerator);
337 return Qnil;
338 }
339
340 static VALUE bridge_delete(VALUE self)
341 {
342 bridge_t *bridge;
343
344 Data_Get_Struct(self, bridge_t, bridge);
345 dumm->delete_bridge(dumm, bridge);
346 return Qnil;
347 }
348
349 static void bridge_init()
350 {
351 rbc_bridge = rb_define_class_under(rbm_dumm , "Bridge", rb_cObject);
352 rb_define_singleton_method(rbc_bridge, "[]", bridge_get, 1);
353 rb_define_singleton_method(rbc_bridge, "each", bridge_each, -1);
354 rb_define_singleton_method(rbc_bridge, "new", bridge_new, 1);
355 rb_define_method(rbc_bridge, "to_s", bridge_to_s, 0);
356 rb_define_method(rbc_bridge, "each", bridge_each_iface, -1);
357 rb_define_method(rbc_bridge, "delete", bridge_delete, 0);
358 }
359
360 /**
361 * Iface wrapper
362 */
363 static VALUE iface_to_s(VALUE self)
364 {
365 iface_t *iface;
366
367 Data_Get_Struct(self, iface_t, iface);
368 return rb_str_new2(iface->get_hostif(iface));
369 }
370
371 static VALUE iface_connect(VALUE self, VALUE vbridge)
372 {
373 iface_t *iface;
374 bridge_t *bridge;
375
376 Data_Get_Struct(self, iface_t, iface);
377 Data_Get_Struct(vbridge, bridge_t, bridge);
378 if (bridge->connect_iface(bridge, iface))
379 {
380 return self;
381 }
382 return Qnil;
383 }
384
385 static VALUE iface_disconnect(VALUE self)
386 {
387 iface_t *iface;
388 bridge_t *bridge;
389
390 Data_Get_Struct(self, iface_t, iface);
391 bridge = iface->get_bridge(iface);
392 if (bridge && bridge->disconnect_iface(bridge, iface))
393 {
394 return self;
395 }
396 return Qnil;
397 }
398
399 static VALUE iface_delete(VALUE self)
400 {
401 guest_t *guest;
402 iface_t *iface;
403
404 Data_Get_Struct(self, iface_t, iface);
405 guest = iface->get_guest(iface);
406 guest->destroy_iface(guest, iface);
407 return Qnil;
408 }
409
410 static void iface_init()
411 {
412 rbc_iface = rb_define_class_under(rbm_dumm , "Iface", rb_cObject);
413 rb_define_method(rbc_iface, "to_s", iface_to_s, 0);
414 rb_define_method(rbc_iface, "connect", iface_connect, 1);
415 rb_define_method(rbc_iface, "disconnect", iface_disconnect, 0);
416 rb_define_method(rbc_iface, "delete", iface_delete, 0);
417 }
418
419 /**
420 * main routine, parses args and reads from console
421 */
422 int main(int argc, char *argv[])
423 {
424 int state;
425 struct sigaction action;
426
427 ruby_init();
428 ruby_init_loadpath();
429
430 /* there are to many to report, rubyruby... */
431 setenv("LEAK_DETECTIVE_DISABLE", "1", 1);
432
433 library_init(NULL);
434
435 dumm = dumm_create(NULL);
436
437 rbm_dumm = rb_define_module("Dumm");
438
439 guest_init();
440 bridge_init();
441 iface_init();
442
443 sigemptyset(&action.sa_mask);
444 action.sa_sigaction = sigchld_handler;
445 action.sa_flags = SA_SIGINFO;
446 sigaction(SIGCHLD, &action, NULL);
447
448 rb_require("irb");
449 rb_eval_string_protect("include Dumm", &state);
450 rb_eval_string_protect("IRB.start", &state);
451 if (state)
452 {
453 rb_p(ruby_errinfo);
454 }
455
456 dumm->destroy(dumm);
457
458 action.sa_handler = SIG_DFL;
459 action.sa_flags = 0;
460 sigaction(SIGCHLD, &action, NULL);
461
462 library_deinit();
463 return 0;
464 }
465