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: