diff --git a/lib/modules/Stdio.pmod/module.pmod b/lib/modules/Stdio.pmod/module.pmod index bc11871eb185e6ea56d8100f133f10a58aee7dfc..ac53dab4a60d7c15aeb32011af351174ee82da27 100644 --- a/lib/modules/Stdio.pmod/module.pmod +++ b/lib/modules/Stdio.pmod/module.pmod @@ -744,6 +744,8 @@ class File //! @value PROP_SEND_FD //! The resulting pipe might support sending of file descriptors //! (see @[send_fd()] and @[receive_fd()] for details). + //! @value PROP_TTY + //! The resulting pipe is a pseudo-tty. //! @value PROP_REVERSE //! The resulting pipe supports communication "backwards" (but //! not necessarily "forwards", see @[PROP_BIDIRECTIONAL]). @@ -757,6 +759,9 @@ class File //! //! The two ends of a bi-directional pipe are indistinguishable. //! + //! For @[PROP_TTY] the returned object is the slave (unless + //! @[PROP_REVERSE] has been specified). + //! //! If the File object this function is called in was open to begin with, //! it will be closed before the pipe is created. //! @@ -768,7 +773,7 @@ class File //! @[Process.create_process()], @[send_fd()], @[receive_fd()], //! @[PROP_IPC], @[PROP_NONBLOCK], @[PROP_SEND_FD], //! @[PROP_SHUTDOWN], @[PROP_BUFFERED], @[PROP_REVERSE], - //! @[PROP_BIDIRECTIONAL] + //! @[PROP_BIDIRECTIONAL], @[PROP_TTY] //! File pipe(void|int required_properties) { diff --git a/src/configure.in b/src/configure.in index 854ca89a243e9d86cf2e8b90b5f2f78ca36446a1..dd0f0dfa9bb0e506c00888733fa10ed54355c1e1 100644 --- a/src/configure.in +++ b/src/configure.in @@ -3312,6 +3312,67 @@ AC_CHECK_HEADERS(winsock2.h sys/rusage.h time.h sys/time.h sys/types.h \ #endif ]) +AC_CHECK_TYPES([HPCON, LPPROC_THREAD_ATTRIBUTE_LIST, LPSTARTUPINFOEXW],,,[ +#if (defined(__WINNT__) || defined(__WIN32__)) && !defined(__NT__) +#define __NT__ +#endif +#ifndef _LARGEFILE_SOURCE +# define _FILE_OFFSET_BITS 64 +# define _LARGEFILE_SOURCE +#endif +#ifndef __STDC_EXT__ +# define __STDC_EXT__ +#endif /* !__STDC_EXT__ */ +#ifndef _PROTOTYPES +# define _PROTOTYPES +#endif /* !_PROTOTYPES */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif /* !_GNU_SOURCE */ +#ifdef __NT__ +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#ifndef WIN32 +#define WIN32 100 /* WinNT 1.0 */ +#endif +#if !defined(_WIN32_WINDOWS) || (_WIN32_WINDOWS < 0x500) +#undef _WIN32_WINDOWS +#define _WIN32_WINDOWS 0x0500 +#endif +#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x500) +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0500 +#endif +#if !defined(NTDDI_VERSION) || (NTDDI_VERSION < 0x05000000) +#undef NTDDI_VERSION +#define NTDDI_VERSION 0x05000000 +#endif +#endif /* __NT__ */ +#ifdef __amigaos__ +#define __USE_NETINET_IN_H +#endif +#ifndef __BUILTIN_VA_ARG_INCR +#define __BUILTIN_VA_ARG_INCR 1 +#endif /* !__BUILTIN_VA_ARG_INCR */ +#ifdef HAVE_WINDOWS_H +#include <windows.h> +#undef HAVE_WINDOWS_H +#endif +/* Necessary to find sys/socket.h on MacOS X 10.3 */ +#if HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif +/* Necessary to find ws2tcpip.h on WIN32. */ +#ifdef HAVE_WINSOCK2_H +# include <winsock2.h> +#endif +/* Necessary to find sys/user.h on OpenBSD */ +#ifdef HAVE_SYS_PARAM_H +# include <sys/param.h> +#endif +]) + # Setjmp. # # POSIX defines sigsetjmp(). diff --git a/src/fdlib.c b/src/fdlib.c index 5cd2c3f1a81a50e74193422624d7f79af2fd4435..d25465ca4ee5dcc502b7d359ad0de256f016722e 100644 --- a/src/fdlib.c +++ b/src/fdlib.c @@ -906,7 +906,7 @@ static int IsUncRoot(const p_wchar1 *path) return 0 ; } -PMOD_EXPORT p_wchar1 *pike_dwim_utf8_to_utf16(const p_wchar0 *str) +p_wchar1 *low_dwim_utf8_to_utf16(const p_wchar0 *str, size_t len) { /* NB: Maximum expansion factor is 2. * @@ -919,7 +919,6 @@ PMOD_EXPORT p_wchar1 *pike_dwim_utf8_to_utf16(const p_wchar0 *str) * NB: Some extra padding at the end for NUL and adding * of terminating slashes, etc. */ - size_t len = strlen(str); p_wchar1 *res = malloc((len + 4) * sizeof(p_wchar1)); size_t i = 0, j = 0; @@ -979,6 +978,11 @@ PMOD_EXPORT p_wchar1 *pike_dwim_utf8_to_utf16(const p_wchar0 *str) return res; } +PMOD_EXPORT p_wchar1 *pike_dwim_utf8_to_utf16(const p_wchar0 *str) +{ + return low_dwim_utf8_to_utf16(str, strlen(str)); +} + PMOD_EXPORT p_wchar0 *pike_utf16_to_utf8(const p_wchar1 *str) { /* NB: Maximum expansion factor is 1.5. diff --git a/src/fdlib.h b/src/fdlib.h index 1e1bd98333dd45fce1a1cd5f3d74968b8848ec4d..39a1a2901706b522dc7c4d51e42fd3d6cb6d4d26 100644 --- a/src/fdlib.h +++ b/src/fdlib.h @@ -45,6 +45,7 @@ #define fd_BIDIRECTIONAL 16 #define fd_REVERSE 32 #define fd_SEND_FD 64 +#define fd_TTY 128 #if defined(HAVE_WINSOCK_H) @@ -55,6 +56,7 @@ #define FILE_CAPABILITIES (fd_INTERPROCESSABLE) #define PIPE_CAPABILITIES (fd_INTERPROCESSABLE | fd_BUFFERED) #define SOCKET_CAPABILITIES (fd_BIDIRECTIONAL | fd_CAN_NONBLOCK | fd_CAN_SHUTDOWN) +#define TTY_CAPABILITIES (fd_TTY | fd_INTERPROCESSABLE | fd_BIDIRECTIONAL | fd_CAN_NONBLOCK) #include <winbase.h> @@ -70,6 +72,43 @@ typedef off_t PIKE_OFF_T; #define PRINTPIKEOFFT PRINTOFFT #endif +/* + * Some macros, structures and typedefs that are needed for ConPTY. + */ +#ifndef HAVE_HPCON +typedef VOID* HPCON; +#endif +#ifndef EXTENDED_STARTUPINFO_PRESENT +#define EXTENDED_STARTUPINFO_PRESENT 0x00080000 +#endif +#ifndef PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE +#define PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE 0x00020016 +#endif +#ifndef HAVE_LPPROC_THREAD_ATTRIBUTE_LIST +typedef struct _PROC_THREAD_ATTRIBUTE_ENTRY +{ + DWORD_PTR Attribute; + SIZE_T cbSize; + PVOID lpValue; +} PROC_THREAD_ATTRIBUTE_ENTRY, *LPPROC_THREAD_ATTRIBUTE_ENTRY; +typedef struct _PROC_THREAD_ATTRIBUTE_LIST +{ + DWORD dwFlags; + ULONG Size; + ULONG Count; + ULONG Reserved; + PULONG Unknown; + PROC_THREAD_ATTRIBUTE_ENTRY Entries[ANYSIZE_ARRAY]; +} PROC_THREAD_ATTRIBUTE_LIST, *LPPROC_THREAD_ATTRIBUTE_LIST; +#endif +#ifndef HAVE_LPSTARTUPINFOEXW +typedef struct _STARTUPINFOEXW +{ + STARTUPINFOW StartupInfo; + LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList; +} STARTUPINFOEXW, *LPSTARTUPINFOEXW; +#endif + #define SOCKFUN1(NAME,T1) PMOD_EXPORT int PIKE_CONCAT(debug_fd_,NAME) (FD,T1); #define SOCKFUN2(NAME,T1,T2) PMOD_EXPORT int PIKE_CONCAT(debug_fd_,NAME) (FD,T1,T2); #define SOCKFUN3(NAME,T1,T2,T3) PMOD_EXPORT int PIKE_CONCAT(debug_fd_,NAME) (FD,T1,T2,T3); @@ -130,6 +169,7 @@ PMOD_EXPORT char *debug_fd_info(int fd); PMOD_EXPORT int debug_fd_query_properties(int fd, int guess); void fd_init(void); void fd_exit(void); +p_wchar1 *low_dwim_utf8_to_utf16(const p_wchar0 *str, size_t len); PMOD_EXPORT p_wchar1 *pike_dwim_utf8_to_utf16(const p_wchar0 *str); PMOD_EXPORT p_wchar0 *pike_utf16_to_utf8(const p_wchar1 *str); PMOD_EXPORT int debug_fd_stat(const char *file, PIKE_STAT_T *buf); @@ -538,6 +578,7 @@ typedef struct my_fd_set_s my_fd_set; #endif #define UNIX_SOCKET_CAPABILITIES (fd_INTERPROCESSABLE | fd_BIDIRECTIONAL | fd_CAN_NONBLOCK | fd_SEND_FD) #define SOCKET_CAPABILITIES (fd_INTERPROCESSABLE | fd_BIDIRECTIONAL | fd_CAN_NONBLOCK | fd_CAN_SHUTDOWN) +#define TTY_CAPABILITIES (fd_TTY | fd_INTERPROCESSABLE | fd_BIDIRECTIONAL | fd_CAN_NONBLOCK) #endif /* Don't HAVE_WINSOCK */ diff --git a/src/modules/_Stdio/configure.in b/src/modules/_Stdio/configure.in index 14339740596987846ab6540029af7458a7520abd..e81c1f75be09afbe2282dba143017e02209a551f 100644 --- a/src/modules/_Stdio/configure.in +++ b/src/modules/_Stdio/configure.in @@ -5,14 +5,14 @@ AC_MODULE_INIT() AC_DEFINE(WITH_TERMIOS) -AC_HAVE_HEADERS(sys/types.h sys/socket.h arpa/inet.h sys/socketvar.h \ +AC_HAVE_HEADERS(sys/types.h sys/socket.h arpa/inet.h sys/socketvar.h pty.h \ netinet/in.h poll.h sys/poll.h sys/uio.h sys/mman.h linux/mman.h sys/time.h \ sys/param.h sys/mount.h ustat.h sys/statfs.h sys/statvfs.h sys/vfs.h \ sys/stream.h sys/protosw.h netdb.h sys/sysproto.h winsock2.h ws2tcpip.h \ direct.h sys/wait.h process.h sys/file.h net/netdb.h limits.h unistd.h \ termios.h poll.h sys/poll.h sys/select.h sys/un.h netinet/tcp.h \ sys/sendfile.h sys/ioctl.h linux/if.h sys/xattr.h libzfs.h io.h \ - AvailabilityMacros.h,,,[ + AvailabilityMacros.h sys/stropts.h,,,[ /* Needed for <sys/socket.h> on FreeBSD 4.9. */ #ifdef HAVE_SYS_TYPES_H #include <sys/types.h> @@ -68,6 +68,7 @@ AC_CHECK_LIB(gmp, main) AC_HAVE_FUNCS(readdir_r statvfs statfs ustat lseek64 lstat fsync \ grantpt unlockpt ptsname posix_openpt socketpair writev sendfile munmap \ + openpty \ madvise poll setsockopt getprotobyname inet_ntoa \ inet_ntop execve listxattr flistxattr getxattr fgetxattr setxattr fsetxattr \ fdopendir pathconf fpathconf dirfd fstatat openat unlinkat kqueue access) diff --git a/src/modules/_Stdio/file.c b/src/modules/_Stdio/file.c index 75de17c9d96ff13950f4bd3735303921133a2a11..551ff6bfb940452f99c5bc1ce988cb5d706b61c8 100644 --- a/src/modules/_Stdio/file.c +++ b/src/modules/_Stdio/file.c @@ -62,6 +62,21 @@ #include <sys/ioctl.h> #endif +#ifdef HAVE_SYS_STROPTS_H +#include <sys/stropts.h> +#endif + +#ifdef HAVE_PTY_H +#include <pty.h> +#endif + +#ifdef HAVE_TERMIOS_H +#include <termios.h> +#elif defined(HAVE_SYS_TERMIOS_H) +/* NB: Deprecated by <termios.h> above. */ +#include <sys/termios.h> +#endif + #ifdef HAVE_LINUX_IF_H #include <linux/if.h> #endif @@ -2507,23 +2522,19 @@ static int do_close(int flags) } } -/*! @decl string grantpt() - *! - *! If this file has been created by calling @[openpt()], return the - *! filename of the associated pts-file. This function should only be - *! called once. - *! - *! @returns - *! Returns the filename of the corresponding pts. - *! - *! @note - *! This function is only available on some platforms. - */ -#if defined(HAVE_GRANTPT) || defined(USE_PT_CHMOD) || defined(USE_CHGPT) -static void file_grantpt( INT32 args ) +#if !defined(HAVE_POSIX_OPENPT) && defined(PTY_MASTER_PATHNAME) +static int my_posix_openpt(int flags) { - pop_n_elems(args); + return open(PTY_MASTER_PATHNAME, flags); +} +#define HAVE_POSIX_OPENPT +#define posix_openpt(FLAGS) my_posix_openpt(FLAGS) +#endif + +#ifndef HAVE_GRANTPT #if defined(USE_PT_CHMOD) || defined(USE_CHGPT) +static int my_grantpt(int m) +{ push_text("Process.Process"); APPLY_MASTER("resolv", 1); @@ -2553,16 +2564,76 @@ static void file_grantpt( INT32 args ) apply_svalue(Pike_sp-3, 2); apply(Pike_sp[-1].u.object, "wait", 0); if(!UNSAFE_IS_ZERO(Pike_sp-1)) { - Pike_error( -#ifdef USE_PT_CHMOD - USE_PT_CHMOD -#else /* USE_CHGPT */ - USE_CHGPT -#endif /* USE_PT_CHMOD */ - " returned error %d.\n", Pike_sp[-1].u.integer); + errno = EINVAL; + return -1; } - pop_n_elems(3); -#else /* HAVE_GRANTPT */ + return 0; +} +#define HAVE_GRANTPT +#define grantpt(M) my_grantpt(M) +#endif +#endif + +#ifndef HAVE_UNLOCKPT +#define HAVE_UNLOCKPT +#define unlockpt(m) 0 +#endif + +#if !defined(HAVE_OPENPTY) && defined(HAVE_PTSNAME) && defined(HAVE_POSIX_OPENPT) +static int my_openpty(int *master, int *slave, void *ignored_name, + void *ignored_termp, void *ignored_winp) +{ + int m; + int s; + char *sname; + if (!master || !slave) { + errno = EINVAL; + return -1; + } + m = posix_openpt(O_RDWR | O_NOCTTY); + if (m < 0) return -1; + if (!grantpt(m) && !unlockpt(m) && (sname = ptsname(m))) { + int s = open(sname, O_RDWR | O_NOCTTY); + if (s >= 0) { + *master = m; + *slave = s; +#ifdef I_PUSH + /* Push required STREAMS modules. + * cf pts(4D)/pts(7D) on Solaris. + * + * Not required on Solaris 11.4 and later. + */ + ioctl(s, I_PUSH, "ptem"); /* Pseudo terminal emulation mode */ + ioctl(s, I_PUSH, "ldterm"); /* Terminal line discipline */ + ioctl(s, I_PUSH, "ttcompat"); /* BSD terminal compatibility */ +#endif + return 0; + } + } + close(m); + return -1; +} +#define HAVE_OPENPTY +#define openpty(M, S, N, T, W) my_openpty(M, S, N, T, W) +#endif + +/*! @decl string grantpt() + *! + *! If this file has been created by calling @[openpt()], return the + *! filename of the associated pts-file. This function should only be + *! called once. + *! + *! @returns + *! Returns the filename of the corresponding pts. + *! + *! @note + *! This function is only available on some platforms. + */ +#if defined(HAVE_GRANTPT) +static void file_grantpt( INT32 args ) +{ + pop_n_elems(args); + /* Make sure the fd doesn't get closed when it gets sent * to the subprocess (aka /usr/lib/pt_chmod). */ @@ -2570,14 +2641,13 @@ static void file_grantpt( INT32 args ) if( grantpt( FD ) ) Pike_error("grantpt failed: %s\n", strerror(errno)); set_close_on_exec(FD, 1); -#endif /* USE_PT_CHMOD || USE_CHGPT */ + push_text( ptsname( FD ) ); -#ifdef HAVE_UNLOCKPT + if( unlockpt( FD ) ) Pike_error("unlockpt failed: %s\n", strerror(errno)); -#endif } -#endif /* HAVE_GRANTPT || USE_PT_CHMOD || USE_CHGPT */ +#endif /* HAVE_GRANTPT */ /*! @decl int close() *! @decl int close(string direction) @@ -2978,7 +3048,7 @@ static void file_openat(INT32 args) } #endif /* HAVE_OPENAT */ -#if !defined(__NT__) && (defined(HAVE_POSIX_OPENPT) || defined(PTY_MASTER_PATHNAME)) +#if !defined(__NT__) && defined(HAVE_POSIX_OPENPT) /*! @decl int openpt(string mode) *! *! Open the master end of a pseudo-terminal pair. @@ -2992,9 +3062,8 @@ static void file_openat(INT32 args) static void file_openpt(INT32 args) { int flags,fd; -#ifdef HAVE_POSIX_OPENPT struct pike_string *flag_str; -#endif + close_fd(); if(args < 1) @@ -3003,7 +3072,6 @@ static void file_openpt(INT32 args) if(TYPEOF(Pike_sp[-args]) != PIKE_T_STRING) SIMPLE_BAD_ARG_ERROR("openpt", 1, "string"); -#ifdef HAVE_POSIX_OPENPT flags = parse((flag_str = Pike_sp[-args].u.string)->str); if(!( flags & (FILE_READ | FILE_WRITE))) @@ -3035,13 +3103,6 @@ static void file_openpt(INT32 args) } pop_n_elems(args); push_int(fd>=0); -#else - if(args > 1) - pop_n_elems(args - 1); - push_text(PTY_MASTER_PATHNAME); - stack_swap(); - file_open(2); -#endif } #endif @@ -4560,6 +4621,17 @@ static void file_pipe(INT32 args) } #endif +#ifdef HAVE_OPENPTY + if (!(type & ~(TTY_CAPABILITIES))) + { + i = openpty(inout, inout + 1, NULL, NULL, NULL); + if (i >= 0) { + type = TTY_CAPABILITIES; + break; + } + } +#endif + if (!i) { Pike_error("Cannot create a pipe matching those parameters.\n"); } @@ -5920,6 +5992,14 @@ static void f_get_all_active_fd(INT32 args) */ +/*! @decl constant PROP_TTY = 128 + *! + *! The @[Stdio.File] object supports tty operations. + *! + *! @seealso + *! @[Stdio.File()->pipe()] + */ + /*! @decl constant PROP_SEND_FD = 64 *! *! The @[Stdio.File] object might support the @[Stdio.File()->send_fd()] @@ -6221,10 +6301,6 @@ static void f_gethostip(INT32 args) { push_mapping(m); } -#ifdef HAVE_OPENPTY -#include <pty.h> -#endif - int fd_write_identifier_offset; PIKE_MODULE_INIT @@ -6343,6 +6419,9 @@ PIKE_MODULE_INIT add_integer_constant("PROP_BUFFERED",fd_BUFFERED,0); add_integer_constant("PROP_BIDIRECTIONAL",fd_BIDIRECTIONAL,0); add_integer_constant("PROP_REVERSE",fd_REVERSE,0); +#ifdef HAVE_OPENPTY + add_integer_constant("PROP_TTY",fd_TTY,0); +#endif add_integer_constant("PROP_IS_NONBLOCKING", FILE_NONBLOCKING, 0); diff --git a/src/ntlibfuncs.h b/src/ntlibfuncs.h index ce34a5353344e7cfeda437e39a93994851b356fe..101764dcead7ebceb786fc163b80d4ecbddd8129 100644 --- a/src/ntlibfuncs.h +++ b/src/ntlibfuncs.h @@ -21,4 +21,46 @@ NTLIBFUNC(kernel32, BOOL, MoveFileExW, ( DWORD dwFlags /* move options */ )); +/* The following are needed for pty handling, + * and taken from <consoleapi.h> and <processthreadsapi.h>. + */ + +NTLIBFUNC(kernel32, HRESULT, CreatePseudoConsole, ( + COORD size, + HANDLE hInput, + HANDLE hOutput, + DWORD dwFlags, + HPCON *phPC +)); + +NTLIBFUNC(kernel32, HRESULT, ResizePseudoConsole, ( + HPCON hPC, + COORD size +)); + +NTLIBFUNC(kernel32, VOID, ClosePseudoConsole, ( + HPCON hPC +)); + +NTLIBFUNC(kernel32, BOOL, InitializeProcThreadAttributeList, ( + LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList, + DWORD dwAttributeCount, + DWORD dwFlags, + PSIZE_T lpSize +)); + +NTLIBFUNC(kernel32, VOID, DeleteProcThreadAttributeList, ( + LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList +)); + +NTLIBFUNC(kernel32, BOOL, UpdateProcThreadAttribute, ( + LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList, + DWORD dwFlags, + DWORD_PTR Attribute, + PVOID lpValue, + SIZE_T cbSize, + PVOID lpPreviousValue, + PSIZE_T lpReturnSize +)); + #endif /* __NT__ */ diff --git a/src/signal_handler.c b/src/signal_handler.c index c8e3745ebab2d1e84d7c8310b92497051508c3e7..22db1e1356a57e5f0a1c8e39c94e71152d63e2c6 100644 --- a/src/signal_handler.c +++ b/src/signal_handler.c @@ -2847,11 +2847,11 @@ void f_create_process(INT32 args) HANDLE t1 = DO_NOT_WARN(INVALID_HANDLE_VALUE); HANDLE t2 = DO_NOT_WARN(INVALID_HANDLE_VALUE); HANDLE t3 = DO_NOT_WARN(INVALID_HANDLE_VALUE); - STARTUPINFO info; + STARTUPINFOW info; PROCESS_INFORMATION proc; int ret,err; - TCHAR *filename=NULL, *command_line=NULL, *dir=NULL; - void *env=NULL; + WCHAR *filename=NULL, *command_line=NULL, *dir=NULL; + WCHAR *env=NULL; /* Quote command to allow all characters (if possible) */ /* Damn! NT doesn't have quoting! The below code attempts to @@ -2943,7 +2943,8 @@ void f_create_process(INT32 args) * operations on it. */ - command_line=(TCHAR *)buf.s.str; + command_line = pike_dwim_utf8_to_utf16(buf.s.str); + toss_buffer(&buf); } /* FIXME: Ought to set filename properly. @@ -2951,8 +2952,8 @@ void f_create_process(INT32 args) memset(&info,0,sizeof(info)); info.cb=sizeof(info); - - GetStartupInfo(&info); + + GetStartupInfoW(&info); /* Protect inherit status for handles */ LOCK_IMUTEX(&handle_protection_mutex); @@ -2971,7 +2972,7 @@ void f_create_process(INT32 args) { if(TYPEOF(*tmp) == T_STRING) { - dir=(TCHAR *)STR0(tmp->u.string); + dir = pike_dwim_utf8_to_utf16(STR0(tmp->u.string)); /* fprintf(stderr,"DIR: %s\n",STR0(tmp->u.string)); */ } } @@ -3020,8 +3021,13 @@ void f_create_process(INT32 args) f_aggregate(ptr+1); push_string(make_shared_binary_string("\0",1)); o_multiply(); - /* FIXME: Wide strings? */ - env=(void *)Pike_sp[-1].u.string->str; + + /* NB: The environment string contains lots of NUL characters, + * so we must use the low-level variant here. + */ + env = low_dwim_utf8_to_utf16(Pike_sp[-1].u.string->str, + Pike_sp[-1].u.string->len); + pop_stack(); } } @@ -3031,26 +3037,31 @@ void f_create_process(INT32 args) THREADS_ALLOW_UID(); - SetHandleInformation(info.hStdInput, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT); - SetHandleInformation(info.hStdOutput, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT); - SetHandleInformation(info.hStdError, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT); - ret=CreateProcess(filename, - command_line, - NULL, /* process security attribute */ - NULL, /* thread security attribute */ - 1, /* inherithandles */ - 0, /* create flags */ - env, /* environment */ - dir, /* current dir */ - &info, - &proc); + SetHandleInformation(info.hStdInput, HANDLE_FLAG_INHERIT, + HANDLE_FLAG_INHERIT); + SetHandleInformation(info.hStdOutput, HANDLE_FLAG_INHERIT, + HANDLE_FLAG_INHERIT); + SetHandleInformation(info.hStdError, HANDLE_FLAG_INHERIT, + HANDLE_FLAG_INHERIT); + ret = CreateProcessW(filename, + command_line, + NULL, /* process security attribute */ + NULL, /* thread security attribute */ + 1, /* inherithandles */ + CREATE_UNICODE_ENVIRONMENT, /* create flags */ + env, /* environment */ + dir, /* current dir */ + &info, + &proc); err=GetLastError(); THREADS_DISALLOW_UID(); UNLOCK_IMUTEX(&handle_protection_mutex); - if(env) pop_stack(); + if(env) free(env); + if(dir) free(dir); + if(filename) free(filename); if(command_line) free(command_line); #if 1 if(t1 != DO_NOT_WARN(INVALID_HANDLE_VALUE)) CloseHandle(t1);