Handle missing stdio handles on Windows

This commit is contained in:
Justine Tunney 2022-08-22 17:03:11 -07:00
parent 2227cefa5d
commit 58d22c7c3d
3 changed files with 16 additions and 235 deletions

View file

@ -16,10 +16,10 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/intrin/pushpop.h"
#include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/intrin/pthread.h"
#include "libc/intrin/pushpop.h"
#include "libc/intrin/spinlock.h"
#include "libc/nt/runtime.h"
#include "libc/sysv/consts/o.h"
@ -39,6 +39,15 @@ void(__fds_unlock)(void) {
pthread_mutex_unlock(&__fds_lock_obj);
}
static textwindows dontinline void SetupWinStd(struct Fds *fds, int i, int x) {
int64_t h;
h = GetStdHandle(x);
if (!h || h == -1) return;
fds->__init_p[i].kind = pushpop(kFdFile);
fds->__init_p[i].handle = h;
fds->f = i + 1;
}
textstartup void InitializeFileDescriptors(void) {
struct Fds *fds;
fds = VEIL("r", &g_fds);
@ -54,15 +63,10 @@ textstartup void InitializeFileDescriptors(void) {
fds->__init_p[1].handle = VEIL("r", 0x3F8ull);
fds->__init_p[2].handle = VEIL("r", 0x3F8ull);
} else if (IsWindows()) {
pushmov(&fds->f, 3ull);
fds->__init_p[0].kind = pushpop(kFdFile);
fds->__init_p[1].kind = pushpop(kFdFile);
fds->__init_p[2].kind = pushpop(kFdFile);
fds->__init_p[0].handle = GetStdHandle(pushpop(kNtStdInputHandle));
fds->__init_p[1].handle = GetStdHandle(pushpop(kNtStdOutputHandle));
fds->__init_p[2].handle = GetStdHandle(pushpop(kNtStdErrorHandle));
SetupWinStd(fds, 0, kNtStdInputHandle);
SetupWinStd(fds, 1, kNtStdOutputHandle);
SetupWinStd(fds, 2, kNtStdErrorHandle);
}
fds->__init_p[0].flags = O_RDONLY;
fds->__init_p[1].flags = O_WRONLY | O_APPEND;
fds->__init_p[2].flags = O_WRONLY | O_APPEND;
}

View file

@ -173,6 +173,6 @@ BENCH(clone, bench) {
char *volatile tp;
errno_t *volatile ep;
EZBENCH2("__errno_location", donothing, (ep = __errno_location()));
EZBENCH2("__get_tls_privileged", donothing, (tp = __get_tls_privileged()));
EZBENCH2("__get_tls_priv", donothing, (tp = __get_tls_privileged()));
EZBENCH2("__get_tls", donothing, (tp = __get_tls()));
}

View file

@ -539,14 +539,6 @@ func_notdir_suffix (char *o, char **argv, const char *funcname)
continue;
o = variable_buffer_output (o, p, len - (p - p2));
}
#ifdef HAVE_DOS_PATHS
/* Handle the case of "d:foo/bar". */
else if (is_notdir && p2[0] && p2[1] == ':')
{
p = p2 + 2;
o = variable_buffer_output (o, p, len - (p - p2));
}
#endif
else if (is_notdir)
o = variable_buffer_output (o, p2, len);
@ -587,11 +579,6 @@ func_basename_dir (char *o, char **argv, const char *funcname)
o = variable_buffer_output (o, p2, ++p - p2);
else if (p >= p2 && (*p == '.'))
o = variable_buffer_output (o, p2, p - p2);
#ifdef HAVE_DOS_PATHS
/* Handle the "d:foobar" case */
else if (p2[0] && p2[1] == ':' && is_dir)
o = variable_buffer_output (o, p2, 2);
#endif
else if (is_dir)
o = variable_buffer_output (o, "./", 2);
else
@ -1458,140 +1445,6 @@ shell_completed (int exit_code, int exit_sig)
define_variable_cname (".SHELLSTATUS", buf, o_override, 0);
}
#ifdef WINDOWS32
/*untested*/
// #include "sub_proc.h"
int
windows32_openpipe (int *pipedes, int errfd, pid_t *pid_p, char **command_argv, char **envp)
{
SECURITY_ATTRIBUTES saAttr;
HANDLE hIn = INVALID_HANDLE_VALUE;
HANDLE hErr = INVALID_HANDLE_VALUE;
HANDLE hChildOutRd;
HANDLE hChildOutWr;
HANDLE hProcess, tmpIn, tmpErr;
DWORD e;
/* Set status for return. */
pipedes[0] = pipedes[1] = -1;
*pid_p = (pid_t)-1;
saAttr.nLength = sizeof (SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
/* Standard handles returned by GetStdHandle can be NULL or
INVALID_HANDLE_VALUE if the parent process closed them. If that
happens, we open the null device and pass its handle to
process_begin below as the corresponding handle to inherit. */
tmpIn = GetStdHandle (STD_INPUT_HANDLE);
if (DuplicateHandle (GetCurrentProcess (), tmpIn,
GetCurrentProcess (), &hIn,
0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE)
{
e = GetLastError ();
if (e == ERROR_INVALID_HANDLE)
{
tmpIn = CreateFile ("NUL", GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (tmpIn != INVALID_HANDLE_VALUE
&& DuplicateHandle (GetCurrentProcess (), tmpIn,
GetCurrentProcess (), &hIn,
0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE)
CloseHandle (tmpIn);
}
if (hIn == INVALID_HANDLE_VALUE)
{
ON (error, NILF,
_("windows32_openpipe: DuplicateHandle(In) failed (e=%ld)\n"), e);
return -1;
}
}
tmpErr = (HANDLE)_get_osfhandle (errfd);
if (DuplicateHandle (GetCurrentProcess (), tmpErr,
GetCurrentProcess (), &hErr,
0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE)
{
e = GetLastError ();
if (e == ERROR_INVALID_HANDLE)
{
tmpErr = CreateFile ("NUL", GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (tmpErr != INVALID_HANDLE_VALUE
&& DuplicateHandle (GetCurrentProcess (), tmpErr,
GetCurrentProcess (), &hErr,
0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE)
CloseHandle (tmpErr);
}
if (hErr == INVALID_HANDLE_VALUE)
{
ON (error, NILF,
_("windows32_openpipe: DuplicateHandle(Err) failed (e=%ld)\n"), e);
return -1;
}
}
if (! CreatePipe (&hChildOutRd, &hChildOutWr, &saAttr, 0))
{
ON (error, NILF, _("CreatePipe() failed (e=%ld)\n"), GetLastError());
return -1;
}
hProcess = process_init_fd (hIn, hChildOutWr, hErr);
if (!hProcess)
{
O (error, NILF, _("windows32_openpipe(): process_init_fd() failed\n"));
return -1;
}
/* make sure that CreateProcess() has Path it needs */
sync_Path_environment ();
/* 'sync_Path_environment' may realloc 'environ', so take note of
the new value. */
envp = environ;
if (! process_begin (hProcess, command_argv, envp, command_argv[0], NULL))
{
/* register process for wait */
process_register (hProcess);
/* set the pid for returning to caller */
*pid_p = (pid_t) hProcess;
/* set up to read data from child */
pipedes[0] = _open_osfhandle ((intptr_t) hChildOutRd, O_RDONLY);
/* this will be closed almost right away */
pipedes[1] = _open_osfhandle ((intptr_t) hChildOutWr, O_APPEND);
return 0;
}
else
{
/* reap/cleanup the failed process */
process_cleanup (hProcess);
/* close handles which were duplicated, they weren't used */
if (hIn != INVALID_HANDLE_VALUE)
CloseHandle (hIn);
if (hErr != INVALID_HANDLE_VALUE)
CloseHandle (hErr);
/* close pipe handles, they won't be used */
CloseHandle (hChildOutRd);
CloseHandle (hChildOutWr);
return -1;
}
}
#endif
/*
Do shell spawning, with the naughty bits for different OSes.
@ -1607,26 +1460,13 @@ func_shell_base (char *o, char **argv, int trim_newlines)
int pipedes[2];
pid_t pid;
#ifndef __MSDOS__
#ifdef WINDOWS32
/* Reset just_print_flag. This is needed on Windows when batch files
are used to run the commands, because we normally refrain from
creating batch files under -n. */
int j_p_f = just_print_flag;
just_print_flag = 0;
#endif
/* Construct the argument list. */
command_argv = construct_command_argv (argv[0], NULL, NULL, 0,
&batch_filename);
if (command_argv == 0)
{
#ifdef WINDOWS32
just_print_flag = j_p_f;
#endif
return o;
}
#endif /* !__MSDOS__ */
/* Using a target environment for 'shell' loses in cases like:
export var = $(shell echo foobie)
@ -1648,21 +1488,6 @@ func_shell_base (char *o, char **argv, int trim_newlines)
errfd = (output_context && output_context->err >= 0
? output_context->err : FD_STDERR);
#if defined(WINDOWS32)
windows32_openpipe (pipedes, errfd, &pid, command_argv, envp);
/* Restore the value of just_print_flag. */
just_print_flag = j_p_f;
if (pipedes[0] < 0)
{
/* Open of the pipe failed, mark as failed execution. */
shell_completed (127, 0);
OS (error, reading_file, "pipe: %s", strerror (errno));
pid = -1;
goto done;
}
#else
if (pipe (pipedes) < 0)
{
OS (error, reading_file, "pipe: %s", strerror (errno));
@ -1692,7 +1517,6 @@ func_shell_base (char *o, char **argv, int trim_newlines)
shell_completed (127, 0);
goto done;
}
#endif
{
char *buffer;
@ -1798,7 +1622,6 @@ func_eq (char *o, char **argv, char *funcname UNUSED)
return o;
}
/*
string-boolean not operator.
*/
@ -1815,17 +1638,8 @@ func_not (char *o, char **argv, char *funcname UNUSED)
#endif
#ifdef HAVE_DOS_PATHS
# ifdef __CYGWIN__
# define IS_ABSOLUTE(n) ((n[0] && n[1] == ':') || STOP_SET (n[0], MAP_DIRSEP))
# else
# define IS_ABSOLUTE(n) (n[0] && n[1] == ':')
# endif
# define ROOT_LEN 3
#else
# define IS_ABSOLUTE(n) (n[0] == '/')
# define ROOT_LEN 1
#endif
#define IS_ABSOLUTE(n) (n[0] == '/')
#define ROOT_LEN 1
/* Return the absolute name of file NAME which does not contain any '.',
'..' components nor any repeated path separators ('/'). */
@ -1849,52 +1663,15 @@ abspath (const char *name, char *apath)
return NULL;
strcpy (apath, starting_directory);
#ifdef HAVE_DOS_PATHS
if (STOP_SET (name[0], MAP_DIRSEP))
{
if (STOP_SET (name[1], MAP_DIRSEP))
{
/* A UNC. Don't prepend a drive letter. */
apath[0] = name[0];
apath[1] = name[1];
root_len = 2;
}
/* We have /foo, an absolute file name except for the drive
letter. Assume the missing drive letter is the current
drive, which we can get if we remove from starting_directory
everything past the root directory. */
apath[root_len] = '\0';
}
#endif
dest = strchr (apath, '\0');
}
else
{
#if defined(__CYGWIN__) && defined(HAVE_DOS_PATHS)
if (STOP_SET (name[0], MAP_DIRSEP))
root_len = 1;
#endif
memcpy (apath, name, root_len);
apath[root_len] = '\0';
dest = apath + root_len;
/* Get past the root, since we already copied it. */
name += root_len;
#ifdef HAVE_DOS_PATHS
if (! STOP_SET (apath[root_len - 1], MAP_DIRSEP))
{
/* Convert d:foo into d:./foo and increase root_len. */
apath[2] = '.';
apath[3] = '/';
dest++;
root_len++;
/* strncpy above copied one character too many. */
name--;
}
else
apath[root_len - 1] = '/'; /* make sure it's a forward slash */
#endif
}
for (start = end = name; *start != '\0'; start = end)