Index: subversion/include/svn_utf.h =================================================================== --- subversion/include/svn_utf.h (revision 18908) +++ subversion/include/svn_utf.h (working copy) @@ -42,6 +42,10 @@ * OS400. */ #define SVN_APR_LOCALE_CHARSET (const char*)APR_LOCALE_CHARSET #define SVN_APR_DEFAULT_CHARSET (const char*)APR_DEFAULT_CHARSET + +/* xlate handle keys for UTF-8 <--> EBCDIC string conversions. */ +#define SVN_UTF_UTOE_XLATE_HANDLE "svn-utf-utoe-xlate-handle" +#define SVN_UTF_ETOU_XLATE_HANDLE "svn-utf-etou-xlate-handle" #endif /** Index: subversion/libsvn_repos/hooks.c =================================================================== --- subversion/libsvn_repos/hooks.c (revision 18908) +++ subversion/libsvn_repos/hooks.c (working copy) @@ -22,6 +22,11 @@ #include #include +#ifdef AS400 +#include /* For spawn() and struct inheritance. */ +#include /* for open() and oflag parms. */ +#endif + #include "svn_error.h" #include "svn_path.h" #include "svn_repos.h" @@ -52,6 +57,7 @@ svn_boolean_t read_errstream, apr_file_t *stdin_handle, apr_pool_t *pool) +#ifndef AS400 { apr_file_t *read_errhandle, *write_errhandle, *null_handle; apr_status_t apr_err; @@ -164,8 +170,215 @@ return err; } +#else /* Run hooks with spawn() on OS400. */ +{ + const char* script_stderr_utf8; + const char **native_args = NULL; + char buffer[20]; +#pragma convert(0) + /* Even with the UTF support in V5R4 a few functions don't support utf-8 + * args, including spawn(), which takes this char array. */ + char *xmp_envp[2] = {"QIBM_USE_DESCRIPTOR_STDIO=Y", NULL}; +#pragma convert(1208) + int rc, fd_map[3], ignoreFds[2], useFds[2], stdinFds[2], exitcode; + svn_stringbuf_t *script_output = svn_stringbuf_create("", pool); + pid_t child_pid, wait_rv; + apr_size_t args_arr_size = 0, i = 0; + struct inheritance xmp_inherit = {0}; + /* Find number of elements in args array. */ + while (args[args_arr_size] != NULL) + args_arr_size++; + /* Allocate memory for the native_args string array plus one for + * the ending null element. */ + native_args = apr_palloc(pool, sizeof(char *) * args_arr_size + 1); + + /* Convert utf-8 args to ebcdic for use by spawn(). */ + while(args[i] != NULL) + { + SVN_ERR(svn_utf_cstring_from_utf8_ex((const char**)(&(native_args[i])), + args[i++], (const char *)0, + SVN_UTF_UTOE_XLATE_HANDLE, + pool)); + } + + /* Make the last element in the array a NULL pointer as required + * by spawn. */ + native_args[args_arr_size] = NULL; + + /* Get two data pipes, allowing stdout and stderr to be separate. */ + if (pipe(ignoreFds) != 0 || pipe(useFds) != 0 ) + { + return svn_error_createf(SVN_ERR_EXTERNAL_PROGRAM, NULL, + "Error piping hook script %s.", cmd); + } + + + /* Get a pipe for stdin if needed and map it. */ + if (stdin_handle) + { + /* This is a bit cumbersome, but spawn can't work with apr_file_t, so + * if there is stdin for the script we open another pipe to the + * script's stdin which we can later write what we read from + * stdin_handle. Ugh! */ + if (pipe(stdinFds) != 0 ) + { + return svn_error_createf(SVN_ERR_EXTERNAL_PROGRAM, NULL, + "Error piping hook script %s.", cmd); + } + fd_map[0] = stdinFds[0]; + } + else + { +#pragma convert(0) + if (fd_map[0] = open("/dev/zero", O_RDONLY) == -1) +#pragma convert(1208) + return svn_error_createf( + SVN_ERR_EXTERNAL_PROGRAM, NULL, + "Error opening /dev/zero for hook script %s", cmd); + } + + + /* Map stdout. */ +#pragma convert(0) + if (fd_map[1] = open("/dev/null", O_WRONLY) == -1) +#pragma convert(1208) + return svn_error_createf(SVN_ERR_EXTERNAL_PROGRAM, NULL, + "Error opening /dev/null for hook script %s", + cmd); + + /* Map stderr. */ + fd_map[2] = read_errstream ? useFds[1] : ignoreFds[1]; + + /* Spawn the hook command. */ + if ((child_pid = spawn(native_args[0], 3, fd_map, &xmp_inherit, + native_args, xmp_envp)) == -1) + { + return svn_error_createf(SVN_ERR_EXTERNAL_PROGRAM, NULL, + "Error spawning process for hook script %s.", + cmd); + } + + /* If there is "APR stdin", read it and then write it to the hook's stdin + * pipe. */ + if (stdin_handle) + { + apr_size_t bytes_read = sizeof(buffer); + svn_error_t *err; + while (!svn_io_file_read(stdin_handle, buffer, &bytes_read, pool)) + { + if (write(stdinFds[1], buffer, bytes_read) == -1) + return svn_error_createf( + SVN_ERR_EXTERNAL_PROGRAM, NULL, + "Error piping stdin to hook script %s.", cmd); + bytes_read = sizeof(buffer); + } + if (close(stdinFds[1]) == -1) + return svn_error_createf(SVN_ERR_EXTERNAL_PROGRAM, NULL, + "Error closing write end of stdin pipe"); + + if (close(stdinFds[0]) == -1) + return svn_error_createf(SVN_ERR_EXTERNAL_PROGRAM, NULL, + "Error closing read end of stdin pipe"); + } + + /* Close the write ends of the stdout and stderr pipes so we don't hang + * on the read ends later. */ + if (close(ignoreFds[1]) == -1) + return svn_error_createf(SVN_ERR_EXTERNAL_PROGRAM, NULL, + "Error closing write end of stdout pipe"); + + if (close(useFds[1]) == -1) + return svn_error_createf(SVN_ERR_EXTERNAL_PROGRAM, NULL, + "Error closing write end of stderr pipe"); + + /* Close the unused read end of our ignored pipe. */ + if (close(ignoreFds[0]) == -1) + return svn_error_createf(SVN_ERR_EXTERNAL_PROGRAM, NULL, + "Error closing read end of stdout pipe"); + + /* Read the hook's stderr. */ + while ((rc = read(useFds[0], buffer, sizeof(buffer))) > 0) + { + buffer[rc] = '\0'; + svn_stringbuf_appendcstr(script_output, buffer); + } + + /* Close the read end of the stderr pipe. */ + if (close(useFds[0]) == -1) + return svn_error_createf(SVN_ERR_EXTERNAL_PROGRAM, NULL, + "Error closing read end of stderr pipe"); + + /* Wait for the child process to complete. */ + if ((wait_rv = waitpid(child_pid, &exitcode, 0)) == -1) + { + return svn_error_createf(SVN_ERR_EXTERNAL_PROGRAM, NULL, + "Error waiting for process completion of " \ + "hook script %s.", cmd); + } + + if (script_output->len > 1) + { + SVN_ERR(svn_utf_cstring_to_utf8_ex(&script_stderr_utf8, + script_output->data, + (const char*)0, + SVN_UTF_ETOU_XLATE_HANDLE, + pool)); + } + + if (WIFEXITED(exitcode)) + { + if (WEXITSTATUS(exitcode)) + { + if (read_errstream) + { + return svn_error_createf + (SVN_ERR_EXTERNAL_PROGRAM, NULL, + _("'%s' hook failed with error output:\n%s"), name, + script_stderr_utf8); + } + else + { + return svn_error_createf + (SVN_ERR_EXTERNAL_PROGRAM, NULL, + _("'%s' hook failed; no error output available"), name); + } + } + else + return SVN_NO_ERROR; + } + else if (WIFSIGNALED(exitcode)) + { + return svn_error_createf + (SVN_ERR_EXTERNAL_PROGRAM, NULL, + _("Process '%s' failed because of an uncaught terminating signal"), + cmd); + } + else if (WIFEXCEPTION(exitcode)) + { + return svn_error_createf + (SVN_ERR_EXTERNAL_PROGRAM, NULL, + _("Process '%s' failed unexpectedly with OS400 exception %d"), + cmd, WEXCEPTNUMBER(exitcode)); + } + else if (WIFSTOPPED(exitcode)) + { + return svn_error_createf + (SVN_ERR_EXTERNAL_PROGRAM, NULL, + _("Process '%s' stopped unexpectedly by signal %d"), + cmd, WSTOPSIG(exitcode)); + } + else + { + return svn_error_createf + (SVN_ERR_EXTERNAL_PROGRAM, NULL, + _("Process '%s' failed unexpectedly"), cmd); + } +} +#endif /* AS400 */ + + /* Create a temporary file F that will automatically be deleted when it is closed. Fill it with VALUE, and leave it open and rewound, ready to be read from. */ Index: subversion/libsvn_subr/cmdline.c =================================================================== --- subversion/libsvn_subr/cmdline.c (revision 18908) +++ subversion/libsvn_subr/cmdline.c (working copy) @@ -46,10 +46,6 @@ #define SVN_UTF_CONTOU_XLATE_HANDLE "svn-utf-contou-xlate-handle" #define SVN_UTF_UTOCON_XLATE_HANDLE "svn-utf-utocon-xlate-handle" -#ifdef AS400_UTF8 -#define SVN_UTF_ETOU_XLATE_HANDLE "svn-utf-etou-xlate-handle" -#endif - /* The stdin encoding. If null, it's the same as the native encoding. */ static const char *input_encoding = NULL; Index: subversion/libsvn_subr/io.c =================================================================== --- subversion/libsvn_subr/io.c (revision 18908) +++ subversion/libsvn_subr/io.c (working copy) @@ -52,9 +52,6 @@ #include "svn_config.h" #include "svn_private_config.h" -#ifdef AS400 -#define SVN_UTF_UTOE_XLATE_HANDLE "svn-utf-utoe-xlate-handle" -#endif /* Windows is 'aided' by a number of types of applications that