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