passing a block to guest.exec() processes output lines
authorMartin Willi <martin@strongswan.org>
Wed, 9 Jul 2008 10:51:10 +0000 (10:51 -0000)
committerMartin Willi <martin@strongswan.org>
Wed, 9 Jul 2008 10:51:10 +0000 (10:51 -0000)
src/dumm/irdumm.c

index 53443bf..9b5e021 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <library.h>
 #include <dumm.h>
+#include <debug.h>
 
 #undef PACKAGE_NAME
 #undef PACKAGE_TARNAME
@@ -79,6 +80,23 @@ static void sigchld_handler(int signal, siginfo_t *info, void* ptr)
 }
 
 /**
+ * SIGINT/SEGV/TERM signal handler
+ */
+static void sigint_handler(int signal, siginfo_t *info, void* ptr)
+{
+       struct sigaction action;
+       
+       dumm->destroy(dumm);
+       
+       action.sa_handler = SIG_DFL;
+       action.sa_flags = 0;
+       sigaction(SIGCHLD, &action, NULL);
+       
+       library_deinit();
+       exit(0);
+}
+
+/**
  * Guest bindings
  */
 static VALUE guest_get(VALUE class, VALUE key)
@@ -169,20 +187,66 @@ static VALUE guest_stop(VALUE self)
        return self;
 }
 
-static void cb(void *data, char *buf, size_t len)
+typedef struct {
+       char buf[1024];
+       char *top;
+} exec_t;
+
+static void exec_cb(exec_t *exec, char *buf, size_t len)
 {
-       printf("%.*s", len, buf);
+       size_t to_copy;
+       char *nl;
+       
+       while (len)
+       {
+               to_copy = min(len, sizeof(exec->buf) - (exec->top - exec->buf));
+               memcpy(exec->top, buf, to_copy);
+               exec->top += to_copy;
+               len -= to_copy;
+               buf += to_copy;
+               
+               while (TRUE)
+               {
+                       nl = memchr(exec->buf, '\n', exec->top - exec->buf);
+                       if (!nl)
+                       {
+                               break;
+                       }
+                       if (nl > exec->buf)
+                       {
+                               rb_yield(rb_str_new(exec->buf, nl - exec->buf));
+                       }
+                       nl++;
+                       to_copy = exec->top - nl;
+                       memmove(exec->buf, nl, to_copy);
+                       exec->top = exec->buf + to_copy;
+               }
+               if (exec->top >= exec->buf + sizeof(exec->buf))
+               {
+                       rb_yield(rb_str_new(exec->buf, sizeof(exec->buf)));
+                       exec->top = exec->buf;
+               }
+       }
 }
 
 static VALUE guest_exec(VALUE self, VALUE cmd)
 {
        guest_t *guest;
+       exec_t exec;
+       bool block;
        
+       block = rb_block_given_p();
+       exec.top = exec.buf;
        Data_Get_Struct(self, guest_t, guest);
-       if (guest->exec(guest, cb, NULL, "%s", StringValuePtr(cmd)) != 0)
+       if (guest->exec(guest, block ? (void*)exec_cb : NULL, &exec,
+                                       "%s", StringValuePtr(cmd)) != 0)
        {
                rb_raise(rb_eRuntimeError, "executing command failed");
        }
+       if (exec.top != exec.buf && block)
+       {
+               rb_yield(rb_str_new(exec.buf, exec.top - exec.buf));
+       }
        return self;
 }
 
@@ -521,9 +585,14 @@ int main(int argc, char *argv[])
        iface_init();
        
        sigemptyset(&action.sa_mask);
-       action.sa_sigaction = sigchld_handler;
        action.sa_flags = SA_SIGINFO;
+       action.sa_sigaction = sigchld_handler;
        sigaction(SIGCHLD, &action, NULL);
+       action.sa_sigaction = sigint_handler;
+       sigaction(SIGINT, &action, NULL);
+       sigaction(SIGTERM, &action, NULL);
+       sigaction(SIGSEGV, &action, NULL);
+       sigaction(SIGHUP, &action, NULL);
 
        rb_require("irb");
        rb_eval_string_protect("include Dumm", &state);