diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index 9837b09fd51..c822db14572 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -1622,6 +1622,7 @@ # Unix interface @ stdcall -syscall __wine_unix_call(int64 long ptr) +@ stdcall -syscall __wine_unix_spawnvp(long ptr) @ cdecl __wine_set_unix_funcs(long ptr) @ cdecl __wine_init_unix_lib(long long ptr ptr) @ stdcall __wine_ctrl_routine(ptr) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 5e39209eddc..dfc0d4c9a09 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -344,6 +344,7 @@ static void * const syscalls[] = NtYieldExecution, __wine_dbg_write, __wine_unix_call, + __wine_unix_spawnvp, wine_nt_to_unix_file_name, wine_server_call, wine_server_fd_to_handle, diff --git a/dlls/ntdll/unix/process.c b/dlls/ntdll/unix/process.c index f5b8b5315cd..1a53741de57 100644 --- a/dlls/ntdll/unix/process.c +++ b/dlls/ntdll/unix/process.c @@ -481,6 +481,59 @@ static NTSTATUS spawn_process( const RTL_USER_PROCESS_PARAMETERS *params, int so } +/*********************************************************************** + * __wine_unix_spawnvp + */ +NTSTATUS WINAPI __wine_unix_spawnvp( char * const argv[], int wait ) +{ + pid_t pid, wret; + int fd[2], status, err; + +#ifdef HAVE_PIPE2 + if (pipe2( fd, O_CLOEXEC ) == -1) +#endif + { + if (pipe(fd) == -1) return STATUS_TOO_MANY_OPENED_FILES; + fcntl( fd[0], F_SETFD, FD_CLOEXEC ); + fcntl( fd[1], F_SETFD, FD_CLOEXEC ); + } + + if (!(pid = fork())) + { + /* in child */ + close( fd[0] ); + signal( SIGPIPE, SIG_DFL ); + if (!wait) + { + if (!(pid = fork())) execvp( argv[0], argv ); /* in grandchild */ + if (pid > 0) _exit(0); /* exit child if fork succeeded */ + } + else execvp( argv[0], argv ); + + err = errno_to_status( errno ); + write( fd[1], &err, sizeof(err) ); + _exit(1); + } + close( fd[1] ); + + if (pid != -1) + { + while (pid != (wret = waitpid( pid, &status, 0 ))) + if (wret == -1 && errno != EINTR) break; + + if (read( fd[0], &err, sizeof(err) ) <= 0) /* if we read something, exec or second fork failed */ + { + if (pid == wret && WIFEXITED(status)) err = WEXITSTATUS(status); + else err = 255; /* abnormal exit with an abort or an interrupt */ + } + } + else err = errno_to_status( errno ); + + close( fd[0] ); + return err; +} + + /*********************************************************************** * fork_and_exec * diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 4e856a41865..0057a341525 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -2854,7 +2854,7 @@ static LRESULT start_screensaver(void) if (!is_virtual_desktop()) { const char *argv[3] = { "xdg-screensaver", "activate", NULL }; - int pid = _spawnvp( _P_DETACH, argv[0], argv ); + int pid = __wine_unix_spawnvp( (char **)argv, FALSE ); if (pid > 0) { TRACE( "started process %d\n", pid ); diff --git a/dlls/wow64/syscall.c b/dlls/wow64/syscall.c index cc2ab1c48b3..952b862a37d 100644 --- a/dlls/wow64/syscall.c +++ b/dlls/wow64/syscall.c @@ -284,6 +284,25 @@ NTSTATUS WINAPI wow64___wine_unix_call( UINT *args ) } +/********************************************************************** + * wow64___wine_unix_spawnvp + */ +NTSTATUS WINAPI wow64___wine_unix_spawnvp( UINT *args ) +{ + ULONG *argv32 = get_ptr( &args ); + int wait = get_ulong( &args ); + + unsigned int i, count = 0; + char **argv; + + while (argv32[count]) count++; + argv = Wow64AllocateTemp( (count + 1) * sizeof(*argv) ); + for (i = 0; i < count; i++) argv[i] = ULongToPtr( argv32[i] ); + argv[count] = NULL; + return __wine_unix_spawnvp( argv, wait ); +} + + /********************************************************************** * wow64_wine_server_call */ diff --git a/dlls/wow64/syscall.h b/dlls/wow64/syscall.h index be0ca780b9b..bc403dd6d31 100644 --- a/dlls/wow64/syscall.h +++ b/dlls/wow64/syscall.h @@ -245,6 +245,7 @@ SYSCALL_ENTRY( NtYieldExecution ) \ SYSCALL_ENTRY( __wine_dbg_write ) \ SYSCALL_ENTRY( __wine_unix_call ) \ + SYSCALL_ENTRY( __wine_unix_spawnvp ) \ SYSCALL_ENTRY( wine_nt_to_unix_file_name ) \ SYSCALL_ENTRY( wine_server_call ) \ SYSCALL_ENTRY( wine_server_fd_to_handle ) \ diff --git a/include/winternl.h b/include/winternl.h index 9e96591ad8e..f119ce6f4f6 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -4603,6 +4603,7 @@ static inline PLIST_ENTRY RemoveTailList(PLIST_ENTRY le) /* Wine internal functions */ extern NTSTATUS CDECL __wine_init_unix_lib( HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out ); +extern NTSTATUS WINAPI __wine_unix_spawnvp( char * const argv[], int wait ); /* The thread information for 16-bit threads */ /* NtCurrentTeb()->SubSystemTib points to this */