added an extended exec function to guests that allows to get the output of the comman...
authorTobias Brunner <tobias@strongswan.org>
Wed, 30 Jul 2008 12:58:45 +0000 (12:58 -0000)
committerTobias Brunner <tobias@strongswan.org>
Wed, 30 Jul 2008 12:58:45 +0000 (12:58 -0000)
src/dumm/guest.c
src/dumm/guest.h

index 94ee83d..79dc45f 100644 (file)
@@ -326,21 +326,18 @@ static bool load_template(private_guest_t *this, char *path)
 }
 
 /**
- * Implementation of gues_t.exec
+ * Variadic version of the exec function
  */
-static int exec(private_guest_t *this, void(*cb)(void*,char*,size_t), void *data,
-                               char *cmd, ...)
+static int vexec(private_guest_t *this, void(*cb)(void*,char*,size_t), void *data,
+                                char *cmd, va_list args)
 {
        char buf[1024];
        size_t len;
-       va_list args;
-
+       
        if (this->mconsole)
        {
-               va_start(args, cmd);
                len = vsnprintf(buf, sizeof(buf), cmd, args);
-               va_end(args);
-       
+               
                if (len > 0 && len < sizeof(buf))
                {
                        return this->mconsole->exec(this->mconsole, cb, data, buf);
@@ -350,6 +347,98 @@ static int exec(private_guest_t *this, void(*cb)(void*,char*,size_t), void *data
 }
 
 /**
+ * Implementation of guest_t.exec
+ */
+static int exec(private_guest_t *this, void(*cb)(void*,char*,size_t), void *data,
+                               char *cmd, ...)
+{
+       int res;
+       va_list args;
+       va_start(args, cmd);
+       res = vexec(this, cb, data, cmd, args);
+       va_end(args);
+       return res;
+}
+
+typedef struct {
+       chunk_t buf;
+       void (*cb)(void*,char*);
+       void *data;
+} exec_str_t;
+
+/**
+ * callback that combines chunks to a string. if a callback is given, the string
+ * is split at newlines and the callback is called for each line.
+ */
+static void exec_str_cb(exec_str_t *data, char *buf, size_t len)
+{
+       if (!data->buf.ptr)
+       {
+               data->buf = chunk_alloc(len + 1);
+               memcpy(data->buf.ptr, buf, len);
+               data->buf.ptr[len] = '\0';
+       }
+       else
+       {
+               size_t newlen = strlen(data->buf.ptr) + len + 1;
+               if (newlen > data->buf.len)
+               {
+                       data->buf.ptr = realloc(data->buf.ptr, newlen);
+                       data->buf.len = newlen;
+               }
+               strncat(data->buf.ptr, buf, len);
+       }
+       
+       if (data->cb)
+       {
+               char *nl;
+               while ((nl = strchr(data->buf.ptr, '\n')) != NULL)
+               {
+                       *nl++ = '\0';
+                       data->cb(data->data, data->buf.ptr);
+                       memmove(data->buf.ptr, nl, strlen(nl) + 1);
+               }
+       }
+}
+
+/**
+ * Implementation of guest_t.exec_str
+ */
+static int exec_str(private_guest_t *this, void(*cb)(void*,char*), bool lines,
+                                       void *data, char *cmd, ...)
+{
+       int res;
+       va_list args;
+       va_start(args, cmd);
+       if (cb)
+       {
+               exec_str_t exec = { chunk_empty, NULL, NULL };
+               if (lines)
+               {
+                       exec.cb = cb;
+                       exec.data = data;
+               }
+               res = vexec(this, (void(*)(void*,char*,size_t))exec_str_cb, &exec, cmd, args);
+               if (exec.buf.ptr)
+               {
+                       if (!lines || strlen(exec.buf.ptr) > 0)
+                       {
+                               /* return the complete string or the remaining stuff in the
+                                * buffer (i.e. when there was no newline at the end) */
+                               cb(data, exec.buf.ptr);
+                       }
+                       chunk_free(&exec.buf);
+               }
+       }
+       else
+       {
+               res = vexec(this, NULL, NULL, cmd, args);
+       }
+       va_end(args);
+       return res;
+}
+
+/**
  * Implementation of guest_t.sigchild.
  */
 static void sigchild(private_guest_t *this)
@@ -473,7 +562,8 @@ static private_guest_t *guest_create_generic(char *parent, char *name,
        this->public.start = (void*)start;
        this->public.stop = (void*)stop;
        this->public.load_template = (bool(*)(guest_t*, char *path))load_template;
-       this->public.exec = (int(*)(guest_t*, void(*cb)(void*,char*,size_t), void *data, char *cmd, ...))exec;
+       this->public.exec = (int(*)(guest_t*, void(*cb)(void*,char*,size_t),void*,char*,...))exec;
+       this->public.exec_str = (int(*)(guest_t*, void(*cb)(void*,char*),bool,void*,char*,...))exec_str;
        this->public.sigchild = (void(*)(guest_t*))sigchild;
        this->public.destroy = (void*)destroy;
                
index 98e5ebb..3b1b064 100644 (file)
@@ -153,6 +153,22 @@ struct guest_t {
                                char *cmd, ...);
        
        /**
+        * Execute a command in the guest and return the output by lines or as combined
+        * string.
+        * 
+        * @note This function does not work with binary output (i.e. containing 0 bytes).
+        * 
+        * @param cb            callback to call for each line or for the complete output
+        * @param lines         TRUE if the callback should be called for each line (instead of for the combined output)
+        * @param data          data to pass to callback
+        * @param cmd           command to execute
+        * @param ...           printf style argument list for cmd
+        * @return                      return value
+        */
+       int (*exec_str)(guest_t *this, void(*cb)(void*,char*), bool lines,
+                               void *data, char *cmd, ...);
+       
+       /**
         * @brief Called whenever a SIGCHILD for the guests PID is received.
         */
        void (*sigchild)(guest_t *this);