[*] Linux: begin catching up AuProcesses to NT

This commit is contained in:
Reece Wilson 2023-09-15 00:11:14 +01:00
parent 81775a76bf
commit d166a00d81
4 changed files with 130 additions and 42 deletions

View File

@ -29,12 +29,7 @@
namespace Aurora::IO
{
AuUInt64 AFileHandle::DupHandle(AuUInt64 uOSHandle, bool bWriteAccess)
{
return DupHandle(uOSHandle, bWriteAccess, false);
}
AuUInt64 AFileHandle::DupHandle(AuUInt64 uOSHandle, bool bWriteAccess, bool bShareAccess)
AuUInt64 DupHandle(AuUInt64 uOSHandle, bool bWriteAccess, bool bShareAccess)
{
int fd = ::dup(uOSHandle);
@ -42,13 +37,34 @@ namespace Aurora::IO
{
return 0;
}
int flags = ::fcntl(fd, F_GETFL, 0);
if (flags == -1)
if (!SetFDShareAccess(uOSHandle, bShareAccess))
{
::close(fd);
return 0;
}
return AuUInt64(fd);
}
AuUInt64 AFileHandle::DupHandle(AuUInt64 uOSHandle, bool bWriteAccess)
{
return Aurora::IO::DupHandle(uOSHandle, bWriteAccess, false);
}
AuUInt64 AFileHandle::DupHandle(AuUInt64 uOSHandle, bool bWriteAccess, bool bShareAccess)
{
return Aurora::IO::DupHandle(uOSHandle, bWriteAccess, bShareAccess);
}
int SetFDShareAccess(AuUInt64 uOSHandle, bool bShareAccess)
{
int flags = ::fcntl(uOSHandle, F_GETFL, 0);
if (flags == -1)
{
return 0;
}
if (bShareAccess)
{
@ -59,14 +75,13 @@ namespace Aurora::IO
flags |= FD_CLOEXEC;
}
flags = ::fcntl(fd, F_SETFL, flags);
flags = ::fcntl(uOSHandle, F_SETFL, flags);
if (flags == -1)
{
::close(fd);
return 0;
}
return AuUInt64(fd);
return 1;
}
void AFileHandle::CloseHandle(AuUInt64 uOSHandle)

View File

@ -9,5 +9,6 @@
namespace Aurora::IO
{
int SetFDShareAccess(AuUInt64 uOSHandle, bool bShareAccess);
AuUInt64 DupHandle(AuUInt64 uOSHandle, bool bWriteAccess, bool bShareAccess);
}

View File

@ -17,6 +17,7 @@
#include <sys/wait.h>
#include <Source/Threading/Primitives/AuSemaphore.Unix.hpp>
#include <Source/IO/AuIOHandle.Unix.hpp>
#if defined(AURORA_COMPILER_CLANG)
// warning: enumeration values 'kEnumCount' and 'kEnumInvalid' not handled in switch [-Wswitch
@ -225,7 +226,8 @@ namespace Aurora::Processes
do
{
tmp = ::read(handle, destination.ptr, destination.length);
} while ((tmp == -1 && errno == EINTR));
}
while ((tmp == -1 && errno == EINTR));
if (tmp <= 0)
{
@ -267,16 +269,62 @@ namespace Aurora::Processes
::fcntl(handle, F_SETFL, control);
}
return ::write(handle, source.ptr, source.length) == source.length;
}
static bool InitProcessStdHandles(EStreamForward fwd, int *fds)
static bool InitProcessStdHandles(EStreamForward fwd, int *fds, AuIO::EStandardStream stream, IO::IIOHandle *pHandle)
{
AuOptionalEx<AuUInt64> optHandle;
bool bIsRead = stream == AuIO::EStandardStream::eInputStream;
switch (fwd)
{
case EStreamForward::eIOHandle:
optHandle = pHandle->GetOSHandleSafe();
if (!optHandle)
{
return false;
}
if (bIsRead)
{
fds[0] = dup((int)optHandle.value());
}
else
{
fds[1] = dup((int)optHandle.value());
}
break;
case EStreamForward::eCurrentProcess:
// Intentionally NO-OP
if (stream == AuIO::EStandardStream::eInputStream)
{
fds[0] = dup(STDIN_FILENO);
if (fds[0] < 0)
{
return false;
}
}
else if (stream == AuIO::EStandardStream::eErrorStream)
{
fds[1] = dup(STDERR_FILENO);
if (fds[1] < 0)
{
return false;
}
}
else if (stream == AuIO::EStandardStream::eOutputStream)
{
fds[1] = dup(STDOUT_FILENO);
if (fds[1] < 0)
{
return false;
}
}
else
{
return false;
}
break;
case EStreamForward::eAsyncPipe:
if (::pipe(fds))
@ -286,22 +334,52 @@ namespace Aurora::Processes
}
break;
case EStreamForward::eNull:
fds[0] = ::open("/dev/null", O_RDWR);
fds[1] = ::open("/dev/null", O_RDWR);
if (bIsRead)
{
fds[0] = ::open("/dev/null", O_RDWR);
}
else
{
fds[1] = ::open("/dev/null", O_RDWR);
}
break;
case EStreamForward::eNewConsoleWindow:
SysPushErrorGeneric("AuProcesses is not the right place for PTY support. At least not in this form (this level of abstraction only cares for pipes).");
break;
return false;
}
if (fds[0] > 0)
{
if (!AuIO::SetFDShareAccess(fds[0], bIsRead))
{
return false;
}
}
if (fds[1] > 0)
{
if (!AuIO::SetFDShareAccess(fds[1], !bIsRead))
{
return false;
}
}
// Yea, I guess we can't really guard against threads racing to leak close on exec-less fds
// Let's just not care on UNIX.
// Worst case, we leak a daemons input/output FD to a different daemon of a differing permission level
// ...and somehow you can find that fd
// ...and probably dup it before ::start()
// ...and issue the right commands over the stream to do something bad
// Shouldn't need to worry about his for a while.
return true;
}
bool ProcessImpl::Init()
{
InitProcessStdHandles(this->startup_.fwdOut, this->pipeStdOut_);
InitProcessStdHandles(this->startup_.fwdErr, this->pipeStdErr_);
InitProcessStdHandles(this->startup_.fwdIn, this->pipeStdIn_);
InitProcessStdHandles(this->startup_.fwdOut, this->pipeStdOut_, AuIO::EStandardStream::eOutputStream, this->startup_.handleOutStream);
InitProcessStdHandles(this->startup_.fwdErr, this->pipeStdErr_, AuIO::EStandardStream::eErrorStream, this->startup_.handleErrorStream);
InitProcessStdHandles(this->startup_.fwdIn, this->pipeStdIn_, AuIO::EStandardStream::eInputStream, this->startup_.handleInputStream);
this->loopSource_ = AuMakeShared<ProcessAliveLoopSource>();
if (!this->loopSource_)
@ -331,7 +409,8 @@ namespace Aurora::Processes
return false;
}
this->fsHandle_->InitFromPairMove(this->pipeStdOut_[0], this->pipeStdIn_[1]);
this->fsHandle_->InitFromPairMove(this->pipeStdOut_[0] == -1 ? AuOptionalEx<AuUInt64> {} : AuOptionalEx<AuUInt64> { (AuUInt64)this->pipeStdOut_[0] } ,
this->pipeStdIn_[1] == -1 ? AuOptionalEx<AuUInt64> {} : AuOptionalEx<AuUInt64> { (AuUInt64)this->pipeStdIn_[1] });
this->fsStream_->Init(this->fsHandle_);
}
@ -349,7 +428,7 @@ namespace Aurora::Processes
return false;
}
this->fsErrorHandle_->InitFromPairMove(this->pipeStdErr_[0], -1);
this->fsErrorHandle_->InitFromPairMove(this->pipeStdErr_[0] == -1 ? AuOptionalEx<AuUInt64> {} : AuOptionalEx<AuUInt64> { (AuUInt64)this->pipeStdErr_[0] }, {});
this->fsErrorStream_->Init(this->fsErrorHandle_);
}
@ -368,25 +447,19 @@ namespace Aurora::Processes
void ProcessImpl::ForkMain()
{
if (this->startup_.fwdIn != EStreamForward::eCurrentProcess)
{
::dup2(pipeStdIn_[0], STDIN_FILENO);
::close(pipeStdIn_[0]);
::close(pipeStdIn_[1]);
::dup2(this->pipeStdIn_[0], STDIN_FILENO);
::close(this->pipeStdIn_[0]);
}
if (this->startup_.fwdErr != EStreamForward::eCurrentProcess)
{
::dup2(pipeStdErr_[1], STDERR_FILENO);
::close(pipeStdIn_[0]);
::close(pipeStdIn_[1]);
::dup2(this->pipeStdErr_[1], STDERR_FILENO);
::close(this->pipeStdErr_[1]);
}
if (this->startup_.fwdOut != EStreamForward::eCurrentProcess)
{
::dup2(pipeStdOut_[1], STDOUT_FILENO);
::close(pipeStdIn_[0]);
::close(pipeStdIn_[1]);
::dup2(this->pipeStdOut_[1], STDOUT_FILENO);
::close(this->pipeStdOut_[1]);
}
#if defined(AURORA_IS_LINUX_DERIVED)
@ -421,8 +494,7 @@ namespace Aurora::Processes
if (this->type_ == ESpawnType::eSpawnOvermap)
{
::execv(this->startup_.process.c_str(), (char *const *)this->cargs_.data()); // https://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html
SysPushErrorGen("execv didn't overwrite the process map, given {} ({})", this->startup_.process, this->debug_);
this->ForkMain();
return false;
}

View File

@ -56,9 +56,9 @@ namespace Aurora::Processes
private:
int pipeStdOut_[2]{};
int pipeStdErr_[2]{};
int pipeStdIn_ [2]{};
int pipeStdOut_[2] { -1, -1 };
int pipeStdErr_[2] { -1, -1 };
int pipeStdIn_ [2] { -1, -1 };
bool bDontRelOut_ {};
bool bDontRelIn_ {};