Path: blob/master/Utilities/cmlibuv/src/win/process-stdio.c
3153 views
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.1*2* Permission is hereby granted, free of charge, to any person obtaining a copy3* of this software and associated documentation files (the "Software"), to4* deal in the Software without restriction, including without limitation the5* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or6* sell copies of the Software, and to permit persons to whom the Software is7* furnished to do so, subject to the following conditions:8*9* The above copyright notice and this permission notice shall be included in10* all copies or substantial portions of the Software.11*12* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR13* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,14* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE15* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER16* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING17* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS18* IN THE SOFTWARE.19*/2021#include <assert.h>22#include <io.h>23#include <stdio.h>24#include <stdlib.h>2526#include "uv.h"27#include "internal.h"28#include "handle-inl.h"293031/*32* The `child_stdio_buffer` buffer has the following layout:33* int number_of_fds34* unsigned char crt_flags[number_of_fds]35* HANDLE os_handle[number_of_fds]36*/37#define CHILD_STDIO_SIZE(count) \38(sizeof(int) + \39sizeof(unsigned char) * (count) + \40sizeof(uintptr_t) * (count))4142#define CHILD_STDIO_COUNT(buffer) \43*((unsigned int*) (buffer))4445#define CHILD_STDIO_CRT_FLAGS(buffer, fd) \46*((unsigned char*) (buffer) + sizeof(int) + fd)4748#define CHILD_STDIO_HANDLE(buffer, fd) \49*((HANDLE*) ((unsigned char*) (buffer) + \50sizeof(int) + \51sizeof(unsigned char) * \52CHILD_STDIO_COUNT((buffer)) + \53sizeof(HANDLE) * (fd)))545556/* CRT file descriptor mode flags */57#define FOPEN 0x0158#define FEOFLAG 0x0259#define FCRLF 0x0460#define FPIPE 0x0861#define FNOINHERIT 0x1062#define FAPPEND 0x2063#define FDEV 0x4064#define FTEXT 0x80656667/*68* Clear the HANDLE_FLAG_INHERIT flag from all HANDLEs that were inherited69* the parent process. Don't check for errors - the stdio handles may not be70* valid, or may be closed already. There is no guarantee that this function71* does a perfect job.72*/73void uv_disable_stdio_inheritance(void) {74HANDLE handle;75STARTUPINFOW si;7677/* Make the windows stdio handles non-inheritable. */78handle = GetStdHandle(STD_INPUT_HANDLE);79if (handle != NULL && handle != INVALID_HANDLE_VALUE)80SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);8182handle = GetStdHandle(STD_OUTPUT_HANDLE);83if (handle != NULL && handle != INVALID_HANDLE_VALUE)84SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);8586handle = GetStdHandle(STD_ERROR_HANDLE);87if (handle != NULL && handle != INVALID_HANDLE_VALUE)88SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);8990/* Make inherited CRT FDs non-inheritable. */91GetStartupInfoW(&si);92if (uv__stdio_verify(si.lpReserved2, si.cbReserved2))93uv__stdio_noinherit(si.lpReserved2);94}959697static int uv__duplicate_handle(uv_loop_t* loop, HANDLE handle, HANDLE* dup) {98HANDLE current_process;99100101/* _get_osfhandle will sometimes return -2 in case of an error. This seems to102* happen when fd <= 2 and the process' corresponding stdio handle is set to103* NULL. Unfortunately DuplicateHandle will happily duplicate (HANDLE) -2, so104* this situation goes unnoticed until someone tries to use the duplicate.105* Therefore we filter out known-invalid handles here. */106if (handle == INVALID_HANDLE_VALUE ||107handle == NULL ||108handle == (HANDLE) -2) {109*dup = INVALID_HANDLE_VALUE;110return ERROR_INVALID_HANDLE;111}112113current_process = GetCurrentProcess();114115if (!DuplicateHandle(current_process,116handle,117current_process,118dup,1190,120TRUE,121DUPLICATE_SAME_ACCESS)) {122*dup = INVALID_HANDLE_VALUE;123return GetLastError();124}125126return 0;127}128129130static int uv__duplicate_fd(uv_loop_t* loop, int fd, HANDLE* dup) {131HANDLE handle;132133if (fd == -1) {134*dup = INVALID_HANDLE_VALUE;135return ERROR_INVALID_HANDLE;136}137138handle = uv__get_osfhandle(fd);139return uv__duplicate_handle(loop, handle, dup);140}141142143int uv__create_nul_handle(HANDLE* handle_ptr,144DWORD access) {145HANDLE handle;146SECURITY_ATTRIBUTES sa;147148sa.nLength = sizeof sa;149sa.lpSecurityDescriptor = NULL;150sa.bInheritHandle = TRUE;151152handle = CreateFileW(L"NUL",153access,154FILE_SHARE_READ | FILE_SHARE_WRITE,155&sa,156OPEN_EXISTING,1570,158NULL);159if (handle == INVALID_HANDLE_VALUE) {160return GetLastError();161}162163*handle_ptr = handle;164return 0;165}166167168int uv__stdio_create(uv_loop_t* loop,169const uv_process_options_t* options,170BYTE** buffer_ptr) {171BYTE* buffer;172int count, i;173int err;174175count = options->stdio_count;176177if (count < 0 || count > 255) {178/* Only support FDs 0-255 */179return ERROR_NOT_SUPPORTED;180} else if (count < 3) {181/* There should always be at least 3 stdio handles. */182count = 3;183}184185/* Allocate the child stdio buffer */186buffer = (BYTE*) uv__malloc(CHILD_STDIO_SIZE(count));187if (buffer == NULL) {188return ERROR_OUTOFMEMORY;189}190191/* Prepopulate the buffer with INVALID_HANDLE_VALUE handles so we can clean192* up on failure. */193CHILD_STDIO_COUNT(buffer) = count;194for (i = 0; i < count; i++) {195CHILD_STDIO_CRT_FLAGS(buffer, i) = 0;196CHILD_STDIO_HANDLE(buffer, i) = INVALID_HANDLE_VALUE;197}198199for (i = 0; i < count; i++) {200uv_stdio_container_t fdopt;201if (i < options->stdio_count) {202fdopt = options->stdio[i];203} else {204fdopt.flags = UV_IGNORE;205}206207switch (fdopt.flags & (UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD |208UV_INHERIT_STREAM)) {209case UV_IGNORE:210/* Starting a process with no stdin/stout/stderr can confuse it. So no211* matter what the user specified, we make sure the first three FDs are212* always open in their typical modes, e. g. stdin be readable and213* stdout/err should be writable. For FDs > 2, don't do anything - all214* handles in the stdio buffer are initialized with.215* INVALID_HANDLE_VALUE, which should be okay. */216if (i <= 2) {217DWORD access = (i == 0) ? FILE_GENERIC_READ :218FILE_GENERIC_WRITE | FILE_READ_ATTRIBUTES;219220err = uv__create_nul_handle(&CHILD_STDIO_HANDLE(buffer, i),221access);222if (err)223goto error;224225CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV;226}227break;228229case UV_CREATE_PIPE: {230/* Create a pair of two connected pipe ends; one end is turned into an231* uv_pipe_t for use by the parent. The other one is given to the232* child. */233uv_pipe_t* parent_pipe = (uv_pipe_t*) fdopt.data.stream;234HANDLE child_pipe = INVALID_HANDLE_VALUE;235236/* Create a new, connected pipe pair. stdio[i]. stream should point to237* an uninitialized, but not connected pipe handle. */238assert(fdopt.data.stream->type == UV_NAMED_PIPE);239assert(!(fdopt.data.stream->flags & UV_HANDLE_CONNECTION));240assert(!(fdopt.data.stream->flags & UV_HANDLE_PIPESERVER));241242err = uv__create_stdio_pipe_pair(loop,243parent_pipe,244&child_pipe,245fdopt.flags);246if (err)247goto error;248249CHILD_STDIO_HANDLE(buffer, i) = child_pipe;250CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE;251break;252}253254case UV_INHERIT_FD: {255/* Inherit a raw FD. */256HANDLE child_handle;257258/* Make an inheritable duplicate of the handle. */259err = uv__duplicate_fd(loop, fdopt.data.fd, &child_handle);260if (err) {261/* If fdopt. data. fd is not valid and fd <= 2, then ignore the262* error. */263if (fdopt.data.fd <= 2 && err == ERROR_INVALID_HANDLE) {264CHILD_STDIO_CRT_FLAGS(buffer, i) = 0;265CHILD_STDIO_HANDLE(buffer, i) = INVALID_HANDLE_VALUE;266break;267}268goto error;269}270271/* Figure out what the type is. */272switch (GetFileType(child_handle)) {273case FILE_TYPE_DISK:274CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN;275break;276277case FILE_TYPE_PIPE:278CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE;279break;280281case FILE_TYPE_CHAR:282case FILE_TYPE_REMOTE:283CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV;284break;285286case FILE_TYPE_UNKNOWN:287if (GetLastError() != 0) {288err = GetLastError();289CloseHandle(child_handle);290goto error;291}292CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV;293break;294295default:296assert(0);297return -1;298}299300CHILD_STDIO_HANDLE(buffer, i) = child_handle;301break;302}303304case UV_INHERIT_STREAM: {305/* Use an existing stream as the stdio handle for the child. */306HANDLE stream_handle, child_handle;307unsigned char crt_flags;308uv_stream_t* stream = fdopt.data.stream;309310/* Leech the handle out of the stream. */311if (stream->type == UV_TTY) {312stream_handle = ((uv_tty_t*) stream)->handle;313crt_flags = FOPEN | FDEV;314} else if (stream->type == UV_NAMED_PIPE &&315stream->flags & UV_HANDLE_CONNECTION) {316stream_handle = ((uv_pipe_t*) stream)->handle;317crt_flags = FOPEN | FPIPE;318} else {319stream_handle = INVALID_HANDLE_VALUE;320crt_flags = 0;321}322323if (stream_handle == NULL ||324stream_handle == INVALID_HANDLE_VALUE) {325/* The handle is already closed, or not yet created, or the stream326* type is not supported. */327err = ERROR_NOT_SUPPORTED;328goto error;329}330331/* Make an inheritable copy of the handle. */332err = uv__duplicate_handle(loop, stream_handle, &child_handle);333if (err)334goto error;335336CHILD_STDIO_HANDLE(buffer, i) = child_handle;337CHILD_STDIO_CRT_FLAGS(buffer, i) = crt_flags;338break;339}340341default:342assert(0);343return -1;344}345}346347*buffer_ptr = buffer;348return 0;349350error:351uv__stdio_destroy(buffer);352return err;353}354355356void uv__stdio_destroy(BYTE* buffer) {357int i, count;358359count = CHILD_STDIO_COUNT(buffer);360for (i = 0; i < count; i++) {361HANDLE handle = CHILD_STDIO_HANDLE(buffer, i);362if (handle != INVALID_HANDLE_VALUE) {363CloseHandle(handle);364}365}366367uv__free(buffer);368}369370371void uv__stdio_noinherit(BYTE* buffer) {372int i, count;373374count = CHILD_STDIO_COUNT(buffer);375for (i = 0; i < count; i++) {376HANDLE handle = CHILD_STDIO_HANDLE(buffer, i);377if (handle != INVALID_HANDLE_VALUE) {378SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);379}380}381}382383384int uv__stdio_verify(BYTE* buffer, WORD size) {385unsigned int count;386387/* Check the buffer pointer. */388if (buffer == NULL)389return 0;390391/* Verify that the buffer is at least big enough to hold the count. */392if (size < CHILD_STDIO_SIZE(0))393return 0;394395/* Verify if the count is within range. */396count = CHILD_STDIO_COUNT(buffer);397if (count > 256)398return 0;399400/* Verify that the buffer size is big enough to hold info for N FDs. */401if (size < CHILD_STDIO_SIZE(count))402return 0;403404return 1;405}406407408WORD uv__stdio_size(BYTE* buffer) {409return (WORD) CHILD_STDIO_SIZE(CHILD_STDIO_COUNT((buffer)));410}411412413HANDLE uv__stdio_handle(BYTE* buffer, int fd) {414return CHILD_STDIO_HANDLE(buffer, fd);415}416417418