exec on a guest now returns the return value of the executed process
[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 #include <debug.h>
24
25 #undef PACKAGE_NAME
26 #undef PACKAGE_TARNAME
27 #undef PACKAGE_VERSION
28 #undef PACKAGE_STRING
29 #include <ruby.h>
30
31 dumm_t *dumm;
32
33 VALUE rbm_dumm;
34 VALUE rbc_guest;
35 VALUE rbc_bridge;
36 VALUE rbc_iface;
37 VALUE rbc_template;
38
39 /**
40 * Guest invocation callback
41 */
42 static pid_t invoke(void *null, guest_t *guest, char *args[], int argc)
43 {
44 pid_t pid;
45
46 args[argc++] = "con0=xterm";
47 args[argc++] = "xterm=gnome-terminal,-t,-x";
48
49 pid = fork();
50 switch (pid)
51 {
52 case 0: /* child */
53 dup2(open("/dev/null", 0), 1);
54 dup2(open("/dev/null", 0), 2);
55 execvp(args[0], args);
56 /* FALL */
57 case -1:
58 return 0;
59 default:
60 return pid;
61 }
62 }
63
64 /**
65 * SIGCHLD signal handler
66 */
67 static void sigchld_handler(int signal, siginfo_t *info, void* ptr)
68 {
69 enumerator_t *enumerator;
70 guest_t *guest;
71
72 enumerator = dumm->create_guest_enumerator(dumm);
73 while (enumerator->enumerate(enumerator, &guest))
74 {
75 if (guest->get_pid(guest) == info->si_pid)
76 {
77 guest->sigchild(guest);
78 break;
79 }
80 }
81 enumerator->destroy(enumerator);
82 }
83
84 /**
85 * SIGINT/SEGV/TERM signal handler
86 */
87 static void sigint_handler(int signal, siginfo_t *info, void* ptr)
88 {
89 struct sigaction action;
90
91 dumm->destroy(dumm);
92
93 action.sa_handler = SIG_DFL;
94 action.sa_flags = 0;
95 sigaction(SIGCHLD, &action, NULL);
96
97 library_deinit();
98 exit(0);
99 }
100
101 /**
102 * Guest bindings
103 */
104 static VALUE guest_get(VALUE class, VALUE key)
105 {
106 enumerator_t *enumerator;
107 guest_t *guest, *found = NULL;
108
109 enumerator = dumm->create_guest_enumerator(dumm);
110 while (enumerator->enumerate(enumerator, &guest))
111 {
112 if (streq(guest->get_name(guest), StringValuePtr(key)))
113 {
114 found = guest;
115 break;
116 }
117 }
118 enumerator->destroy(enumerator);
119 if (!found)
120 {
121 rb_raise(rb_eRuntimeError, "guest not found");
122 }
123 return Data_Wrap_Struct(class, NULL, NULL, found);
124 }
125
126 static VALUE guest_each(int argc, VALUE *argv, VALUE class)
127 {
128 enumerator_t *enumerator;
129 guest_t *guest;
130
131 if (!rb_block_given_p())
132 {
133 rb_raise(rb_eArgError, "must be called with a block");
134 }
135 enumerator = dumm->create_guest_enumerator(dumm);
136 while (enumerator->enumerate(enumerator, &guest))
137 {
138 rb_yield(Data_Wrap_Struct(class, NULL, NULL, guest));
139 }
140 enumerator->destroy(enumerator);
141 return class;
142 }
143
144 static VALUE guest_new(VALUE class, VALUE name, VALUE kernel,
145 VALUE master, VALUE mem)
146 {
147 guest_t *guest;
148
149 guest = dumm->create_guest(dumm, StringValuePtr(name), StringValuePtr(kernel),
150 StringValuePtr(master), FIX2INT(mem));
151 if (!guest)
152 {
153 rb_raise(rb_eRuntimeError, "creating guest failed");
154 }
155 return Data_Wrap_Struct(class, NULL, NULL, guest);
156 }
157
158 static VALUE guest_to_s(VALUE self)
159 {
160 guest_t *guest;
161
162 Data_Get_Struct(self, guest_t, guest);
163 return rb_str_new2(guest->get_name(guest));
164 }
165
166 static VALUE guest_start(VALUE self)
167 {
168 guest_t *guest;
169
170 Data_Get_Struct(self, guest_t, guest);
171
172 if (!guest->start(guest, invoke, NULL, NULL))
173 {
174 rb_raise(rb_eRuntimeError, "starting guest failed");
175 }
176 return self;
177 }
178
179 static VALUE guest_stop(VALUE self)
180 {
181 guest_t *guest;
182
183 Data_Get_Struct(self, guest_t, guest);
184 guest->stop(guest, NULL);
185 return self;
186 }
187
188 static void exec_cb(void *data, char *buf)
189 {
190 rb_yield(rb_str_new2(buf));
191 }
192
193 static VALUE guest_exec(VALUE self, VALUE cmd)
194 {
195 guest_t *guest;
196 bool block;
197 int ret;
198
199 block = rb_block_given_p();
200 Data_Get_Struct(self, guest_t, guest);
201 if ((ret = guest->exec_str(guest, block ? (void*)exec_cb : NULL, TRUE, NULL,
202 "%s", StringValuePtr(cmd))) != 0)
203 {
204 rb_raise(rb_eRuntimeError, "executing command failed (%d)", ret);
205 }
206 return self;
207 }
208
209 static VALUE guest_add_iface(VALUE self, VALUE name)
210 {
211 guest_t *guest;
212 iface_t *iface;
213
214 Data_Get_Struct(self, guest_t, guest);
215 iface = guest->create_iface(guest, StringValuePtr(name));
216 if (!iface)
217 {
218 rb_raise(rb_eRuntimeError, "adding interface failed");
219 }
220 return Data_Wrap_Struct(rbc_iface, NULL, NULL, iface);
221 }
222
223 static VALUE guest_get_iface(VALUE self, VALUE key)
224 {
225 enumerator_t *enumerator;
226 iface_t *iface, *found = NULL;
227 guest_t *guest;
228
229 Data_Get_Struct(self, guest_t, guest);
230 enumerator = guest->create_iface_enumerator(guest);
231 while (enumerator->enumerate(enumerator, &iface))
232 {
233 if (streq(iface->get_guestif(iface), StringValuePtr(key)))
234 {
235 found = iface;
236 break;
237 }
238 }
239 enumerator->destroy(enumerator);
240 if (!found)
241 {
242 rb_raise(rb_eRuntimeError, "interface not found");
243 }
244 return Data_Wrap_Struct(rbc_iface, NULL, NULL, iface);
245 }
246
247 static VALUE guest_each_iface(int argc, VALUE *argv, VALUE self)
248 {
249 enumerator_t *enumerator;
250 guest_t *guest;
251 iface_t *iface;
252
253 if (!rb_block_given_p())
254 {
255 rb_raise(rb_eArgError, "must be called with a block");
256 }
257 Data_Get_Struct(self, guest_t, guest);
258 enumerator = guest->create_iface_enumerator(guest);
259 while (enumerator->enumerate(enumerator, &iface))
260 {
261 rb_yield(Data_Wrap_Struct(rbc_iface, NULL, NULL, iface));
262 }
263 enumerator->destroy(enumerator);
264 return self;
265 }
266
267 static VALUE guest_delete(VALUE self)
268 {
269 guest_t *guest;
270
271 Data_Get_Struct(self, guest_t, guest);
272 dumm->delete_guest(dumm, guest);
273 return Qnil;
274 }
275
276 static void guest_init()
277 {
278 rbc_guest = rb_define_class_under(rbm_dumm , "Guest", rb_cObject);
279 rb_define_singleton_method(rbc_guest, "[]", guest_get, 1);
280 rb_define_singleton_method(rbc_guest, "each", guest_each, -1);
281 rb_define_singleton_method(rbc_guest, "new", guest_new, 4);
282 rb_define_method(rbc_guest, "to_s", guest_to_s, 0);
283 rb_define_method(rbc_guest, "start", guest_start, 0);
284 rb_define_method(rbc_guest, "stop", guest_stop, 0);
285 rb_define_method(rbc_guest, "exec", guest_exec, 1);
286 rb_define_method(rbc_guest, "add", guest_add_iface, 1);
287 rb_define_method(rbc_guest, "[]", guest_get_iface, 1);
288 rb_define_method(rbc_guest, "each", guest_each_iface, -1);
289 rb_define_method(rbc_guest, "delete", guest_delete, 0);
290 rb_include_module(rb_class_of(rbc_guest), rb_mEnumerable);
291 rb_include_module(rbc_guest, rb_mEnumerable);
292 }
293
294 /**
295 * Bridge binding
296 */
297 static VALUE bridge_get(VALUE class, VALUE key)
298 {
299 enumerator_t *enumerator;
300 bridge_t *bridge, *found = NULL;
301
302 enumerator = dumm->create_bridge_enumerator(dumm);
303 while (enumerator->enumerate(enumerator, &bridge))
304 {
305 if (streq(bridge->get_name(bridge), StringValuePtr(key)))
306 {
307 found = bridge;
308 break;
309 }
310 }
311 enumerator->destroy(enumerator);
312 if (!found)
313 {
314 rb_raise(rb_eRuntimeError, "bridge not found");
315 }
316 return Data_Wrap_Struct(class, NULL, NULL, found);
317 }
318
319 static VALUE bridge_each(int argc, VALUE *argv, VALUE class)
320 {
321 enumerator_t *enumerator;
322 bridge_t *bridge;
323
324 if (!rb_block_given_p())
325 {
326 rb_raise(rb_eArgError, "must be called with a block");
327 }
328 enumerator = dumm->create_bridge_enumerator(dumm);
329 while (enumerator->enumerate(enumerator, &bridge))
330 {
331 rb_yield(Data_Wrap_Struct(class, NULL, NULL, bridge));
332 }
333 enumerator->destroy(enumerator);
334 return class;
335 }
336
337 static VALUE bridge_new(VALUE class, VALUE name)
338
339 {
340 bridge_t *bridge;
341
342 bridge = dumm->create_bridge(dumm, StringValuePtr(name));
343 if (!bridge)
344 {
345 rb_raise(rb_eRuntimeError, "creating bridge failed");
346 }
347 return Data_Wrap_Struct(class, NULL, NULL, bridge);
348 }
349
350 static VALUE bridge_to_s(VALUE self)
351 {
352 bridge_t *bridge;
353
354 Data_Get_Struct(self, bridge_t, bridge);
355 return rb_str_new2(bridge->get_name(bridge));
356 }
357
358 static VALUE bridge_each_iface(int argc, VALUE *argv, VALUE self)
359 {
360 enumerator_t *enumerator;
361 bridge_t *bridge;
362 iface_t *iface;
363
364 if (!rb_block_given_p())
365 {
366 rb_raise(rb_eArgError, "must be called with a block");
367 }
368 Data_Get_Struct(self, bridge_t, bridge);
369 enumerator = bridge->create_iface_enumerator(bridge);
370 while (enumerator->enumerate(enumerator, &iface))
371 {
372 rb_yield(Data_Wrap_Struct(rbc_iface, NULL, NULL, iface));
373 }
374 enumerator->destroy(enumerator);
375 return self;
376 }
377
378 static VALUE bridge_delete(VALUE self)
379 {
380 bridge_t *bridge;
381
382 Data_Get_Struct(self, bridge_t, bridge);
383 dumm->delete_bridge(dumm, bridge);
384 return Qnil;
385 }
386
387 static void bridge_init()
388 {
389 rbc_bridge = rb_define_class_under(rbm_dumm , "Bridge", rb_cObject);
390 rb_define_singleton_method(rbc_bridge, "[]", bridge_get, 1);
391 rb_define_singleton_method(rbc_bridge, "each", bridge_each, -1);
392 rb_define_singleton_method(rbc_bridge, "new", bridge_new, 1);
393 rb_define_method(rbc_bridge, "to_s", bridge_to_s, 0);
394 rb_define_method(rbc_bridge, "each", bridge_each_iface, -1);
395 rb_define_method(rbc_bridge, "delete", bridge_delete, 0);
396 rb_include_module(rb_class_of(rbc_bridge), rb_mEnumerable);
397 rb_include_module(rbc_bridge, rb_mEnumerable);
398 }
399
400 /**
401 * Iface wrapper
402 */
403 static VALUE iface_to_s(VALUE self)
404 {
405 iface_t *iface;
406
407 Data_Get_Struct(self, iface_t, iface);
408 return rb_str_new2(iface->get_hostif(iface));
409 }
410
411 static VALUE iface_connect(VALUE self, VALUE vbridge)
412 {
413 iface_t *iface;
414 bridge_t *bridge;
415
416 Data_Get_Struct(self, iface_t, iface);
417 Data_Get_Struct(vbridge, bridge_t, bridge);
418 if (!bridge->connect_iface(bridge, iface))
419 {
420 rb_raise(rb_eRuntimeError, "connecting iface failed");
421 }
422 return self;
423 }
424
425 static VALUE iface_disconnect(VALUE self)
426 {
427 iface_t *iface;
428 bridge_t *bridge;
429
430 Data_Get_Struct(self, iface_t, iface);
431 bridge = iface->get_bridge(iface);
432 if (!bridge || !bridge->disconnect_iface(bridge, iface))
433 {
434 rb_raise(rb_eRuntimeError, "disconnecting iface failed");
435 }
436 return self;
437 }
438
439 static VALUE iface_add_addr(VALUE self, VALUE name)
440 {
441 iface_t *iface;
442 host_t *addr;
443
444 addr = host_create_from_string(StringValuePtr(name), 0);
445 if (!addr)
446 {
447 rb_raise(rb_eArgError, "invalid IP address");
448 }
449 Data_Get_Struct(self, iface_t, iface);
450 if (!iface->add_address(iface, addr))
451 {
452 rb_raise(rb_eRuntimeError, "adding address failed");
453 }
454 addr->destroy(addr);
455 return self;
456 }
457
458 static VALUE iface_each_addr(int argc, VALUE *argv, VALUE self)
459 {
460 enumerator_t *enumerator;
461 iface_t *iface;
462 host_t *addr;
463 char buf[64];
464
465 if (!rb_block_given_p())
466 {
467 rb_raise(rb_eArgError, "must be called with a block");
468 }
469 Data_Get_Struct(self, iface_t, iface);
470 enumerator = iface->create_address_enumerator(iface);
471 while (enumerator->enumerate(enumerator, &addr))
472 {
473 snprintf(buf, sizeof(buf), "%H", addr);
474 rb_yield(rb_str_new2(buf));
475 }
476 enumerator->destroy(enumerator);
477 return self;
478 }
479
480 static VALUE iface_del_addr(VALUE self, VALUE vaddr)
481 {
482 iface_t *iface;
483 host_t *addr;
484
485 addr = host_create_from_string(StringValuePtr(vaddr), 0);
486 if (!addr)
487 {
488 rb_raise(rb_eArgError, "invalid IP address");
489 }
490 Data_Get_Struct(self, iface_t, iface);
491 if (!iface->delete_address(iface, addr))
492 {
493 addr->destroy(addr);
494 rb_raise(rb_eRuntimeError, "address not found");
495 }
496 addr->destroy(addr);
497 return self;
498 }
499
500 static VALUE iface_delete(VALUE self)
501 {
502 guest_t *guest;
503 iface_t *iface;
504
505 Data_Get_Struct(self, iface_t, iface);
506 guest = iface->get_guest(iface);
507 guest->destroy_iface(guest, iface);
508 return Qnil;
509 }
510
511 static void iface_init()
512 {
513 rbc_iface = rb_define_class_under(rbm_dumm , "Iface", rb_cObject);
514 rb_define_method(rbc_iface, "to_s", iface_to_s, 0);
515 rb_define_method(rbc_iface, "connect", iface_connect, 1);
516 rb_define_method(rbc_iface, "disconnect", iface_disconnect, 0);
517 rb_define_method(rbc_iface, "add", iface_add_addr, 1);
518 rb_define_method(rbc_iface, "del", iface_del_addr, 1);
519 rb_define_method(rbc_iface, "each", iface_each_addr, -1);
520 rb_define_method(rbc_iface, "delete", iface_delete, 0);
521 rb_include_module(rbc_iface, rb_mEnumerable);
522 }
523
524 static VALUE template_load(VALUE class, VALUE name)
525 {
526 if (!dumm->load_template(dumm, StringValuePtr(name)))
527 {
528 rb_raise(rb_eRuntimeError, "loading template failed");
529 }
530 return class;
531 }
532
533 static VALUE template_unload(VALUE class)
534 {
535 if (!dumm->load_template(dumm, NULL))
536 {
537 rb_raise(rb_eRuntimeError, "unloading template failed");
538 }
539 return class;
540 }
541
542 static void template_init()
543 {
544 rbc_template = rb_define_class_under(rbm_dumm , "Template", rb_cObject);
545 rb_define_singleton_method(rbc_template, "load", template_load, 1);
546 rb_define_singleton_method(rbc_template, "unload", template_unload, 0);
547 }
548
549 /**
550 * main routine, parses args and reads from console
551 */
552 int main(int argc, char *argv[])
553 {
554 int state, i;
555 struct sigaction action;
556 char buf[512];
557
558 ruby_init();
559 ruby_init_loadpath();
560
561 /* there are too many to report, rubyruby... */
562 setenv("LEAK_DETECTIVE_DISABLE", "1", 1);
563
564 library_init(NULL);
565
566 dumm = dumm_create(NULL);
567
568 rbm_dumm = rb_define_module("Dumm");
569
570 guest_init();
571 bridge_init();
572 iface_init();
573 template_init();
574
575 sigemptyset(&action.sa_mask);
576 action.sa_flags = SA_SIGINFO;
577 action.sa_sigaction = sigchld_handler;
578 sigaction(SIGCHLD, &action, NULL);
579 action.sa_sigaction = sigint_handler;
580 sigaction(SIGINT, &action, NULL);
581 sigaction(SIGTERM, &action, NULL);
582 sigaction(SIGSEGV, &action, NULL);
583 sigaction(SIGHUP, &action, NULL);
584
585 rb_eval_string_protect("include Dumm", &state);
586 if (state)
587 {
588 rb_p(ruby_errinfo);
589 }
590 for (i = 1; i < argc; i++)
591 {
592 snprintf(buf, sizeof(buf), "load \"%s\"", argv[i]);
593 printf("%s\n", buf);
594 rb_eval_string_protect(buf, &state);
595 if (state)
596 {
597 rb_p(ruby_errinfo);
598 }
599 }
600 rb_require("irb");
601 rb_require("irb/completion");
602 rb_eval_string_protect("IRB.start", &state);
603 if (state)
604 {
605 rb_p(ruby_errinfo);
606 }
607
608 dumm->destroy(dumm);
609
610 action.sa_handler = SIG_DFL;
611 action.sa_flags = 0;
612 sigaction(SIGCHLD, &action, NULL);
613
614 library_deinit();
615 ruby_finalize();
616 return 0;
617 }
618