[*] 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 namespace Aurora::IO
{ {
AuUInt64 AFileHandle::DupHandle(AuUInt64 uOSHandle, bool bWriteAccess) AuUInt64 DupHandle(AuUInt64 uOSHandle, bool bWriteAccess, bool bShareAccess)
{
return DupHandle(uOSHandle, bWriteAccess, false);
}
AuUInt64 AFileHandle::DupHandle(AuUInt64 uOSHandle, bool bWriteAccess, bool bShareAccess)
{ {
int fd = ::dup(uOSHandle); int fd = ::dup(uOSHandle);
@ -43,13 +38,34 @@ namespace Aurora::IO
return 0; return 0;
} }
int flags = ::fcntl(fd, F_GETFL, 0); if (!SetFDShareAccess(uOSHandle, bShareAccess))
if (flags == -1)
{ {
::close(fd); ::close(fd);
return 0; 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) if (bShareAccess)
{ {
flags &= ~FD_CLOEXEC; flags &= ~FD_CLOEXEC;
@ -59,14 +75,13 @@ namespace Aurora::IO
flags |= FD_CLOEXEC; flags |= FD_CLOEXEC;
} }
flags = ::fcntl(fd, F_SETFL, flags); flags = ::fcntl(uOSHandle, F_SETFL, flags);
if (flags == -1) if (flags == -1)
{ {
::close(fd);
return 0; return 0;
} }
return AuUInt64(fd); return 1;
} }
void AFileHandle::CloseHandle(AuUInt64 uOSHandle) void AFileHandle::CloseHandle(AuUInt64 uOSHandle)

View File

@ -9,5 +9,6 @@
namespace Aurora::IO 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 <sys/wait.h>
#include <Source/Threading/Primitives/AuSemaphore.Unix.hpp> #include <Source/Threading/Primitives/AuSemaphore.Unix.hpp>
#include <Source/IO/AuIOHandle.Unix.hpp>
#if defined(AURORA_COMPILER_CLANG) #if defined(AURORA_COMPILER_CLANG)
// warning: enumeration values 'kEnumCount' and 'kEnumInvalid' not handled in switch [-Wswitch // warning: enumeration values 'kEnumCount' and 'kEnumInvalid' not handled in switch [-Wswitch
@ -225,7 +226,8 @@ namespace Aurora::Processes
do do
{ {
tmp = ::read(handle, destination.ptr, destination.length); tmp = ::read(handle, destination.ptr, destination.length);
} while ((tmp == -1 && errno == EINTR)); }
while ((tmp == -1 && errno == EINTR));
if (tmp <= 0) if (tmp <= 0)
{ {
@ -267,16 +269,62 @@ namespace Aurora::Processes
::fcntl(handle, F_SETFL, control); ::fcntl(handle, F_SETFL, control);
} }
return ::write(handle, source.ptr, source.length) == source.length; 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) 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: 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; break;
case EStreamForward::eAsyncPipe: case EStreamForward::eAsyncPipe:
if (::pipe(fds)) if (::pipe(fds))
@ -286,22 +334,52 @@ namespace Aurora::Processes
} }
break; break;
case EStreamForward::eNull: case EStreamForward::eNull:
if (bIsRead)
{
fds[0] = ::open("/dev/null", O_RDWR); fds[0] = ::open("/dev/null", O_RDWR);
}
else
{
fds[1] = ::open("/dev/null", O_RDWR); fds[1] = ::open("/dev/null", O_RDWR);
}
break; break;
case EStreamForward::eNewConsoleWindow: 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)."); 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; return true;
} }
bool ProcessImpl::Init() bool ProcessImpl::Init()
{ {
InitProcessStdHandles(this->startup_.fwdOut, this->pipeStdOut_); InitProcessStdHandles(this->startup_.fwdOut, this->pipeStdOut_, AuIO::EStandardStream::eOutputStream, this->startup_.handleOutStream);
InitProcessStdHandles(this->startup_.fwdErr, this->pipeStdErr_); InitProcessStdHandles(this->startup_.fwdErr, this->pipeStdErr_, AuIO::EStandardStream::eErrorStream, this->startup_.handleErrorStream);
InitProcessStdHandles(this->startup_.fwdIn, this->pipeStdIn_); InitProcessStdHandles(this->startup_.fwdIn, this->pipeStdIn_, AuIO::EStandardStream::eInputStream, this->startup_.handleInputStream);
this->loopSource_ = AuMakeShared<ProcessAliveLoopSource>(); this->loopSource_ = AuMakeShared<ProcessAliveLoopSource>();
if (!this->loopSource_) if (!this->loopSource_)
@ -331,7 +409,8 @@ namespace Aurora::Processes
return false; 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_); this->fsStream_->Init(this->fsHandle_);
} }
@ -349,7 +428,7 @@ namespace Aurora::Processes
return false; 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_); this->fsErrorStream_->Init(this->fsErrorHandle_);
} }
@ -368,25 +447,19 @@ namespace Aurora::Processes
void ProcessImpl::ForkMain() void ProcessImpl::ForkMain()
{ {
if (this->startup_.fwdIn != EStreamForward::eCurrentProcess)
{ {
::dup2(pipeStdIn_[0], STDIN_FILENO); ::dup2(this->pipeStdIn_[0], STDIN_FILENO);
::close(pipeStdIn_[0]); ::close(this->pipeStdIn_[0]);
::close(pipeStdIn_[1]);
} }
if (this->startup_.fwdErr != EStreamForward::eCurrentProcess)
{ {
::dup2(pipeStdErr_[1], STDERR_FILENO); ::dup2(this->pipeStdErr_[1], STDERR_FILENO);
::close(pipeStdIn_[0]); ::close(this->pipeStdErr_[1]);
::close(pipeStdIn_[1]);
} }
if (this->startup_.fwdOut != EStreamForward::eCurrentProcess)
{ {
::dup2(pipeStdOut_[1], STDOUT_FILENO); ::dup2(this->pipeStdOut_[1], STDOUT_FILENO);
::close(pipeStdIn_[0]); ::close(this->pipeStdOut_[1]);
::close(pipeStdIn_[1]);
} }
#if defined(AURORA_IS_LINUX_DERIVED) #if defined(AURORA_IS_LINUX_DERIVED)
@ -421,8 +494,7 @@ namespace Aurora::Processes
if (this->type_ == ESpawnType::eSpawnOvermap) 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 this->ForkMain();
SysPushErrorGen("execv didn't overwrite the process map, given {} ({})", this->startup_.process, this->debug_);
return false; return false;
} }

View File

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