You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by mt...@apache.org on 2010/01/04 13:45:22 UTC

svn commit: r895617 - in /commons/sandbox/runtime/trunk/src/main/native: include/acr_args.h include/acr_exec.h os/unix/exec.c shared/args.c test/testsuite.c

Author: mturk
Date: Mon Jan  4 12:45:21 2010
New Revision: 895617

URL: http://svn.apache.org/viewvc?rev=895617&view=rev
Log:
Implement shell execute

Modified:
    commons/sandbox/runtime/trunk/src/main/native/include/acr_args.h
    commons/sandbox/runtime/trunk/src/main/native/include/acr_exec.h
    commons/sandbox/runtime/trunk/src/main/native/os/unix/exec.c
    commons/sandbox/runtime/trunk/src/main/native/shared/args.c
    commons/sandbox/runtime/trunk/src/main/native/test/testsuite.c

Modified: commons/sandbox/runtime/trunk/src/main/native/include/acr_args.h
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/include/acr_args.h?rev=895617&r1=895616&r2=895617&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/include/acr_args.h (original)
+++ commons/sandbox/runtime/trunk/src/main/native/include/acr_args.h Mon Jan  4 12:45:21 2010
@@ -48,7 +48,7 @@
  * @return number of argumennts in argv array or -1 in case of error.
  */
 ACR_DECLARE(int) ACR_StringToArgvA(const char *cmdline,
-                                   char ***argv)
+                                   char ***argv);
 
 #if defined(WIN32)
 /**
@@ -59,6 +59,40 @@
 
 #endif
 
+/**
+ * Duplicate argument array.
+ * @param argv Argument array to duplicate. It has to be NULL terminated.
+ * @return duplicated array.
+ * @note Single free is needed to free the entire array data storage.
+ *       Like with ACR_StringToArgv function the argv[0] can be directly
+ *       used by functions that require zero separated double zero terminated
+ *       string.
+ */
+ACR_DECLARE(char **) ACR_DuplicateArgsA(const char *const *argv);
+
+/**
+ * Unicode version of ACR_DuplicateArgsA.
+ * @note In addition to ACR_DuplicateArgsA, the unicode version double quotes
+ *       the first argument (argv[0]) if it contains space or tab characters.
+ */
+ACR_DECLARE(wchar_t **) ACR_DuplicateArgsW(const wchar_t *const *argv);
+
+/**
+ * Merge two argument arrays into one.
+ * @param argv1 Source argument array.
+ * @param argv2 Arrgument array to concat to the first one.
+ * @note Any of the source argument array can be NULL in which
+ *       case function behaves like ACR_DuplicateArgs function.
+ */
+ACR_DECLARE(char **) ACR_MergeArgsA(const char *const *argv1,
+                                    const char *const *argv2);
+
+/**
+ * Unicode version of ACR_MergeArgsA.
+ */
+ACR_DECLARE(wchar_t **) ACR_MergeArgsW(const wchar_t *const *argv1,
+                                       const wchar_t *const *argv2);
+
 #ifdef __cplusplus
 }
 #endif

Modified: commons/sandbox/runtime/trunk/src/main/native/include/acr_exec.h
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/include/acr_exec.h?rev=895617&r1=895616&r2=895617&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/include/acr_exec.h (original)
+++ commons/sandbox/runtime/trunk/src/main/native/include/acr_exec.h Mon Jan  4 12:45:21 2010
@@ -55,9 +55,72 @@
 #define ACR_PROC_HAS_STDOUT     0x0002
 #define ACR_PROC_HAS_STDERR     0x0004
 
+/**
+ * Create new executable object structure
+ * @param flags Execution flags to use.
+*         See ACR_PROC_* for details.
+ */
 ACR_DECLARE(acr_exec_t *) ACR_ExecNew(int flags);
-ACR_DECLARE(int) ACR_ShellExec(acr_exec_t *exe, const acr_pchar_t *cmdline);
+
+/**
+ * Execute shell command
+ * Uppon exit the returned value can be one of:
+ * <PRE>
+ * ACR_CHILD_DONE    if the child exited cleanly.
+ * ACR_CHILD_NOTDONE if the waiting for a child exit failed.
+ * ACR_CHILD_SIGNAL  if the child was ended by a signal
+ * ACR_CHILD_ERROR   if there was an error in child execution
+ * ACR_PARENT_ERROR  if there was an error when starting the process.
+ *                   In all cases the exitval member of the exec object has
+ *                   the actual error value.
+ * </PRE>
+ * @param exe The executable object
+ * @param cmdline Command line to pass to the shell
+ * @param envp Optional environment passed to the shell. If null the current
+ *             environment of the calling process is used.
+ * @return Exit reason.
+ */
+ACR_DECLARE(int) ACR_ExecShellCmd(acr_exec_t *exe, const acr_pchar_t *cmdline,
+                                  const acr_pchar_t *const *envp);
+
+/**
+ * Execute shell script file.
+ * @param exe The executable object
+ * @param file shell script to execute
+ * @param argv Parameters for the script file.
+ * @param envp Optional environment passed to the shell. If null the current
+ *             environment of the calling process is used.
+ * @return Exit reason.
+ */
+ACR_DECLARE(int) ACR_ExecShellScript(acr_exec_t *ep, const acr_pchar_t *file,
+                                     const acr_pchar_t *const *argv,
+                                     const acr_pchar_t *const *envp);
+
+/**
+ * Get executed program output stream.
+ * @param exe The executable object
+ * @param which Stream to get:
+ *              STDOUT_FILENO returns the stdout stream
+ *              STDERR_FILENO returns the stdout stream
+ */
 ACR_DECLARE(const char *) ACR_ExecStream(acr_exec_t *exe, int which);
+
+/**
+ * Set data for the child process stdin.
+ * @param exe The executable object
+ * @param data input data.
+ * @param len input data length.
+ *
+ * @return EINVAL if the executable object was created without
+ *         ACR_PROC_HAS_STDIN flag.
+ */
+ACR_DECLARE(int) ACR_ExecStdinSet(acr_exec_t *e,
+                                   const void *data, size_t len);
+
+/**
+ * Free allocated executable object resources.
+ * @param exe The executable object
+ */
 ACR_DECLARE(void) ACR_ExecFree(acr_exec_t *exe);
 
 #ifdef __cplusplus

Modified: commons/sandbox/runtime/trunk/src/main/native/os/unix/exec.c
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/os/unix/exec.c?rev=895617&r1=895616&r2=895617&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/os/unix/exec.c (original)
+++ commons/sandbox/runtime/trunk/src/main/native/os/unix/exec.c Mon Jan  4 12:45:21 2010
@@ -27,6 +27,7 @@
 #include "acr_file.h"
 #include "acr_pipe.h"
 #include "acr_time.h"
+#include "acr_args.h"
 #include "acr_exec.h"
 
 /**
@@ -37,6 +38,7 @@
 extern int pipepair(int pd[2], int flags);
 extern int nullpipe(int flags, int fd);
 
+#define PIPE_STDINP         0
 #define PIPE_STDINP_RDS     0
 #define PIPE_STDINP_WRS     1
 #define PIPE_STDOUT         2
@@ -93,7 +95,9 @@
     return NULL;
 }
 
-ACR_DECLARE(int) ACR_ShellExec(acr_exec_t *ep, const acr_pchar_t *cmdline)
+static int do_exec(acr_exec_t *ep, const char *cmdline,
+                   char **argv,
+                   const char *const *envp)
 {
     pid_t  pid;
     ssize_t rd;
@@ -104,7 +108,11 @@
     _info_c info = { -1,  0,  0,  0 };
 
     /* Create pipes */
-    if (ep->flags & ACR_PROC_HAS_STDERR) {
+    if (ep->flags & ACR_PROC_HAS_STDIN && ep->data.iov_len) {
+        if ((rc = pipepair(&pipes[PIPE_STDINP], ACR_PIPE_READ_BLOCK)))
+            goto cleanup;
+    }
+    if (ep->flags & ACR_PROC_HAS_STDOUT) {
         if ((rc = pipepair(&pipes[PIPE_STDOUT], ACR_PIPE_WRITE_BLOCK)))
             goto cleanup;
     }
@@ -143,7 +151,7 @@
          */
         acr_cloexec(pipes[PIPE_SIGNAL_WRS]);
 
-        close(STDOUT_FILENO);
+        close(STDIN_FILENO);
         if (pipes[PIPE_STDINP_RDS] == -1) {
             /* Redirect stdin to /dev/null
              */
@@ -152,7 +160,7 @@
                 rc = ACR_GET_OS_ERROR();
                 goto child_cleanup;
             }
-        }        
+        }
         if (dup2(pipes[PIPE_STDINP_RDS], STDIN_FILENO) == -1) {
             rc = ACR_GET_OS_ERROR();
             goto child_cleanup;
@@ -183,8 +191,12 @@
         }
         i_close(&pipes[PIPE_STDOUT_WRS]);
         i_close(&pipes[PIPE_STDERR_WRS]);
-
-        execv(SHELL_PATH, (char * const *)args);
+        if (argv == NULL)
+            argv = (char **)args;
+        if (envp)
+            execve(argv[0], (char * const *)argv, envp);
+        else
+            execv(argv[0],  (char * const *)argv);
         rc = ACR_GET_OS_ERROR();
 
 child_cleanup:
@@ -201,9 +213,10 @@
     else {
         /* Parent process */
         struct pollfd ps[4];
-        int    npipes  = 0;
-        int    running = ep->flags & (ACR_PROC_HAS_STDOUT | ACR_PROC_HAS_STDERR);
-        pid_t  child   = pid;
+        int    npipes    = 0;
+        int    running   = ep->flags & (ACR_PROC_HAS_STDOUT | ACR_PROC_HAS_STDERR);
+        pid_t  child     = pid;
+        const char *inpp = (const char *)ep->data.iov_base;
 
         /* Close parent side of pipes
          */
@@ -224,9 +237,14 @@
              */
             running = 0;
         }
-
         while (running) {
             npipes = 0;
+            if (pipes[PIPE_STDINP_WRS] != -1) {
+                ps[npipes].fd = pipes[PIPE_STDOUT_WRS];
+                ps[npipes].events  = POLLOUT;
+                ps[npipes].revents = 0;
+                npipes++;
+            }
             if (pipes[PIPE_STDOUT_RDS] != -1) {
                 ps[npipes].fd = pipes[PIPE_STDOUT_RDS];
                 ps[npipes].events  = POLLIN;
@@ -246,10 +264,28 @@
                 } while (rc == -1 && errno == EINTR);
                 if (rc < 1)
                     break;
+
+                if (pipes[PIPE_STDINP_WRS] != -1 && ps[i].revents) {
+                    if (ps[i].revents & POLLOUT) {
+                        ssize_t wr;
+                        wr = r_write(pipes[PIPE_STDINP_WRS], inpp,
+                                     ep->data.iov_len);
+                        if (wr > 0) {
+                            ep->data.iov_len -= wr;
+                            inpp += wr;
+                        }
+                        else
+                            i_close(&pipes[PIPE_STDINP_WRS]);
+                    }
+                    else {
+                        i_close(&pipes[PIPE_STDINP_WRS]);
+                    }
+                    i++;
+                }
                 if (pipes[PIPE_STDOUT_RDS] != -1 && ps[i].revents) {
                     if (ps[i].revents & POLLIN) {
                         char   buf[512];
-    
+
                         rd = r_read(pipes[PIPE_STDOUT_RDS], buf, sizeof(buf));
                         if (rd > 0)
                             acr_sbuf_bcat(&ep->sout, buf, rd);
@@ -264,7 +300,7 @@
                 if (pipes[PIPE_STDERR_RDS] != -1 && ps[i].revents) {
                     if (ps[i].revents & POLLIN) {
                         char   buf[512];
-    
+
                         rd = r_read(pipes[PIPE_STDERR_RDS], buf, sizeof(buf));
                         if (rd > 0)
                             acr_sbuf_bcat(&ep->serr, buf, rd);
@@ -346,6 +382,31 @@
     return ep->exitwhy;
 }
 
+ACR_DECLARE(int) ACR_ExecShellCmd(acr_exec_t *ep, const char *cmdline,
+                                  const char *const *envp)
+{
+    return do_exec(ep, cmdline, NULL, envp);
+}
+
+ACR_DECLARE(int) ACR_ExecShellScript(acr_exec_t *ep, const char *fname,
+                                     const char *const *argv,
+                                     const char *const *envp)
+{
+    int    rc;
+    char **args = NULL;
+    const char *sa[3] = { SHELL_PATH, fname, NULL };
+
+    if (!(args = ACR_MergeArgsA((const char *const *)sa, argv))) {
+        ep->exitval = ACR_GET_OS_ERROR();
+        ep->exitwhy = ACR_PARENT_ERROR;
+        return ep->exitwhy;
+    }
+    rc = do_exec(ep, fname, args, envp);
+    x_free(args);
+
+    return rc;
+}
+
 ACR_DECLARE(const char *) ACR_ExecStream(acr_exec_t *e, int which)
 {
     if (e) {
@@ -361,6 +422,17 @@
     return NULL;
 }
 
+ACR_DECLARE(int) ACR_ExecStdinSet(acr_exec_t *e,
+                                   const void *data, size_t len)
+{
+    if (e && (e->flags & ACR_PROC_HAS_STDIN)) {
+        e->data.iov_base = (void *)data;
+        e->data.iov_len  = len;
+        return 0;
+    }
+    return ACR_EINVAL;
+}
+
 ACR_DECLARE(void) ACR_ExecFree(acr_exec_t *e)
 {
     if (e) {
@@ -372,4 +444,3 @@
     }
 }
 
-

Modified: commons/sandbox/runtime/trunk/src/main/native/shared/args.c
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/shared/args.c?rev=895617&r1=895616&r2=895617&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/shared/args.c (original)
+++ commons/sandbox/runtime/trunk/src/main/native/shared/args.c Mon Jan  4 12:45:21 2010
@@ -606,3 +606,145 @@
     return dupargv;
 }
 
+ACR_DECLARE(char **) ACR_MergeArgsA(const char *const *argv1,
+                                    const char *const *argv2)
+{
+    size_t arglen;
+    size_t argnum = 1;
+    size_t length = 0;
+    char  *buffer;
+    char  **dupargv  = NULL;
+    const char *const *ap1 = argv1;
+    const char *const *ap2 = argv2;
+
+    if (ap1) {
+        while (*ap1) {
+            ++argnum;
+            length += (strlen(*ap1) + 1);
+            ap1++;
+        }
+    }
+    if (ap2) {
+        while (*ap2) {
+            ++argnum;
+            length += (strlen(*ap2) + 1);
+            ap2++;
+        }
+    }
+    if (!length) {
+        /* Nothing to duplicate
+         */
+        return NULL;
+    }
+    arglen = ACR_ALIGN_DEFAULT(argnum * sizeof(char *));
+    buffer = x_malloc(arglen + length + 1);
+    if (!buffer)
+        return NULL;
+    argnum = 0;
+    ap1 = argv1;
+    ap2 = argv2;
+    dupargv = (char **)buffer;
+    buffer += arglen;
+    if (ap1) {
+        while (*ap1) {
+            size_t len = strlen(*ap1) + 1;
+            memcpy(buffer, *ap1, len);
+            dupargv[argnum++] = buffer;
+            buffer += len;
+            ap1++;
+        }
+    }
+    if (ap2) {
+        while (*ap2) {
+            size_t len = strlen(*ap2) + 1;
+            memcpy(buffer, *ap2, len);
+            dupargv[argnum++] = buffer;
+            buffer += len;
+            ap2++;
+        }
+    }
+    *buffer = '\0';
+    dupargv[argnum] = NULL;
+
+    return dupargv;
+}
+
+ACR_DECLARE(wchar_t **) ACR_MergeArgsW(const wchar_t *const *argv1,
+                                       const wchar_t *const *argv2)
+{
+    size_t    arglen;
+    size_t    argnum = 1;
+    size_t    length = 0;
+    wchar_t  *buffer;
+    wchar_t **dupargv  = NULL;
+    const wchar_t *const *ap1 = argv1;
+    const wchar_t *const *ap2 = argv2;
+
+    if (ap1) {
+        while (*ap1) {
+            ++argnum;
+            length += (wcslen(*ap1) + 1);
+            ap1++;
+        }
+    }
+    if (ap2) {
+        while (*ap2) {
+            ++argnum;
+            length += (wcslen(*ap2) + 1);
+            ap2++;
+        }
+    }
+    if (!length) {
+        /* Nothing to duplicate
+         */
+        return NULL;
+    }
+    arglen = ACR_ALIGN_DEFAULT(argnum * sizeof(wchar_t *));
+    buffer = x_malloc(arglen + ((length + 3) * sizeof(wchar_t)));
+    if (!buffer)
+        return NULL;
+    argnum = 0;
+    ap1 = argv1;
+    ap2 = argv2;
+    dupargv = (wchar_t **)buffer;
+    buffer += (arglen / sizeof(wchar_t));
+    if (ap1) {
+        while (*ap1) {
+            size_t len = wcslen(*ap1) + 1;
+            if (argnum == 0 && wcspbrk(*ap1, L" \t")) {
+                buffer[0] = L'"';
+                memcpy(buffer + 1, *ap1, len * sizeof(wchar_t));
+                buffer[len + 1] = L'"';
+            }
+            else
+                memcpy(buffer, *ap1, len * sizeof(wchar_t));
+            dupargv[argnum++] = buffer;
+            buffer += len;
+            ap1++;
+        }
+    }
+    if (ap2) {
+        while (*ap2) {
+            size_t len = wcslen(*ap2) + 1;
+            if (argnum == 0 && wcspbrk(*ap2, L" \t")) {
+                buffer[0] = L'"';
+                memcpy(buffer + 1, *ap2, len * sizeof(wchar_t));
+                buffer[len + 1] = L'"';
+            }
+            else
+                memcpy(buffer, *ap2, len * sizeof(wchar_t));
+            dupargv[argnum++] = buffer;
+            buffer += len;
+            ap2++;
+        }
+    }
+    /* Add double zero termination.
+     * dupargv[0] can be used as zero separated
+     * double zero terminated string
+     */
+    *buffer = L'\0';
+    dupargv[argnum] = NULL;
+
+    return dupargv;
+}
+

Modified: commons/sandbox/runtime/trunk/src/main/native/test/testsuite.c
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/test/testsuite.c?rev=895617&r1=895616&r2=895617&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/test/testsuite.c (original)
+++ commons/sandbox/runtime/trunk/src/main/native/test/testsuite.c Mon Jan  4 12:45:21 2010
@@ -574,8 +574,26 @@
     if (argc < 1) {
         return ACR_EINVAL;
     }
-    exe = ACR_ExecNew(0);
-    rc = ACR_ShellExec(exe, argv[0]);
+    exe = ACR_ExecNew(ACR_PROC_HAS_STDOUT);
+    rc = ACR_ExecShellCmd(exe, argv[0], NULL);
+
+    fprintf(stdout, "[STDOUT]:\n%s", ACR_ExecStream(exe, 1));
+    fprintf(stdout, "[STDERR]:\n%s", ACR_ExecStream(exe, 2));
+    fprintf(stdout, "\n[EXITWHY]: %d\n[EXITVAL]: %d\n",
+            exe->exitwhy, exe->exitval);
+    ACR_ExecFree(exe);
+    return 0;
+}
+
+static int test_exec2(int argc, const char *const argv[])
+{
+    int rc;
+    acr_exec_t *exe;
+    if (argc < 1) {
+        return ACR_EINVAL;
+    }
+    exe = ACR_ExecNew(ACR_PROC_HAS_STDOUT | ACR_PROC_HAS_STDERR);
+    rc = ACR_ExecShellScript(exe, argv[0], &argv[1], NULL);
 
     fprintf(stdout, "[STDOUT]:\n%s", ACR_ExecStream(exe, 1));
     fprintf(stdout, "[STDERR]:\n%s", ACR_ExecStream(exe, 2));
@@ -673,6 +691,9 @@
         else if (!strcasecmp(run_test, "shexe")) {
             rv = test_exec1(argc, argv);
         }
+        else if (!strcasecmp(run_test, "shrun")) {
+            rv = test_exec2(argc, argv);
+        }
     }
 
 cleanup: