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 TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/intrin/pushpop.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h" #include "libc/calls/strace.internal.h"
#include "libc/intrin/pthread.h" #include "libc/intrin/pthread.h"
#include "libc/intrin/pushpop.h"
#include "libc/intrin/spinlock.h" #include "libc/intrin/spinlock.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/sysv/consts/o.h" #include "libc/sysv/consts/o.h"
@ -39,6 +39,15 @@ void(__fds_unlock)(void) {
pthread_mutex_unlock(&__fds_lock_obj); 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) { textstartup void InitializeFileDescriptors(void) {
struct Fds *fds; struct Fds *fds;
fds = VEIL("r", &g_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[1].handle = VEIL("r", 0x3F8ull);
fds->__init_p[2].handle = VEIL("r", 0x3F8ull); fds->__init_p[2].handle = VEIL("r", 0x3F8ull);
} else if (IsWindows()) { } else if (IsWindows()) {
pushmov(&fds->f, 3ull); SetupWinStd(fds, 0, kNtStdInputHandle);
fds->__init_p[0].kind = pushpop(kFdFile); SetupWinStd(fds, 1, kNtStdOutputHandle);
fds->__init_p[1].kind = pushpop(kFdFile); SetupWinStd(fds, 2, kNtStdErrorHandle);
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));
} }
fds->__init_p[0].flags = O_RDONLY;
fds->__init_p[1].flags = O_WRONLY | O_APPEND; fds->__init_p[1].flags = O_WRONLY | O_APPEND;
fds->__init_p[2].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; char *volatile tp;
errno_t *volatile ep; errno_t *volatile ep;
EZBENCH2("__errno_location", donothing, (ep = __errno_location())); 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())); EZBENCH2("__get_tls", donothing, (tp = __get_tls()));
} }

View file

@ -539,14 +539,6 @@ func_notdir_suffix (char *o, char **argv, const char *funcname)
continue; continue;
o = variable_buffer_output (o, p, len - (p - p2)); 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) else if (is_notdir)
o = variable_buffer_output (o, p2, len); 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); o = variable_buffer_output (o, p2, ++p - p2);
else if (p >= p2 && (*p == '.')) else if (p >= p2 && (*p == '.'))
o = variable_buffer_output (o, p2, p - p2); 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) else if (is_dir)
o = variable_buffer_output (o, "./", 2); o = variable_buffer_output (o, "./", 2);
else else
@ -1458,140 +1445,6 @@ shell_completed (int exit_code, int exit_sig)
define_variable_cname (".SHELLSTATUS", buf, o_override, 0); 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. 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]; int pipedes[2];
pid_t pid; 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. */ /* Construct the argument list. */
command_argv = construct_command_argv (argv[0], NULL, NULL, 0, command_argv = construct_command_argv (argv[0], NULL, NULL, 0,
&batch_filename); &batch_filename);
if (command_argv == 0) if (command_argv == 0)
{ {
#ifdef WINDOWS32
just_print_flag = j_p_f;
#endif
return o; return o;
} }
#endif /* !__MSDOS__ */
/* Using a target environment for 'shell' loses in cases like: /* Using a target environment for 'shell' loses in cases like:
export var = $(shell echo foobie) 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 errfd = (output_context && output_context->err >= 0
? output_context->err : FD_STDERR); ? 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) if (pipe (pipedes) < 0)
{ {
OS (error, reading_file, "pipe: %s", strerror (errno)); 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); shell_completed (127, 0);
goto done; goto done;
} }
#endif
{ {
char *buffer; char *buffer;
@ -1798,7 +1622,6 @@ func_eq (char *o, char **argv, char *funcname UNUSED)
return o; return o;
} }
/* /*
string-boolean not operator. string-boolean not operator.
*/ */
@ -1815,17 +1638,8 @@ func_not (char *o, char **argv, char *funcname UNUSED)
#endif #endif
#ifdef HAVE_DOS_PATHS #define IS_ABSOLUTE(n) (n[0] == '/')
# ifdef __CYGWIN__ #define ROOT_LEN 1
# 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
/* Return the absolute name of file NAME which does not contain any '.', /* Return the absolute name of file NAME which does not contain any '.',
'..' components nor any repeated path separators ('/'). */ '..' components nor any repeated path separators ('/'). */
@ -1849,52 +1663,15 @@ abspath (const char *name, char *apath)
return NULL; return NULL;
strcpy (apath, starting_directory); 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'); dest = strchr (apath, '\0');
} }
else else
{ {
#if defined(__CYGWIN__) && defined(HAVE_DOS_PATHS)
if (STOP_SET (name[0], MAP_DIRSEP))
root_len = 1;
#endif
memcpy (apath, name, root_len); memcpy (apath, name, root_len);
apath[root_len] = '\0'; apath[root_len] = '\0';
dest = apath + root_len; dest = apath + root_len;
/* Get past the root, since we already copied it. */ /* Get past the root, since we already copied it. */
name += root_len; 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) for (start = end = name; *start != '\0'; start = end)