20#include "pedigree/kernel/Subsystem.h"
21#include "pedigree/kernel/compiler.h"
22#include "pedigree/kernel/machine/Disk.h"
23#include "pedigree/kernel/machine/Keyboard.h"
24#include "pedigree/kernel/machine/KeymapManager.h"
25#include "pedigree/kernel/machine/Machine.h"
26#include "pedigree/kernel/process/Process.h"
27#include "pedigree/kernel/process/TerminationDeferral.h"
28#include "pedigree/kernel/processor/PhysicalMemoryManager.h"
29#include "pedigree/kernel/processor/Processor.h"
30#include "pedigree/kernel/processor/VirtualAddressSpace.h"
31#include "pedigree/kernel/processor/types.h"
32#include "pedigree/kernel/syscallError.h"
33#include "pedigree/kernel/utilities/Pointers.h"
34#include "pedigree/kernel/utilities/assert.h"
35#include "pedigree/kernel/utilities/utility.h"
37#include <FileDescriptor.h>
38#include <PosixProcess.h>
39#include <PosixSubsystem.h>
48#include "DevFs-block.h"
49#include "TerminalControl.h"
50#include "advisory-lock-syscalls.h"
51#include "console-syscalls.h"
52#include "eventfd-syscalls.h"
53#include "fanotify-syscalls.h"
54#include "file-metadata.h"
55#include "file-syscalls.h"
56#include "inotify-syscalls.h"
58#include "memfd-syscalls.h"
59#include "metadata-syscalls.h"
60#include "modules/subsys/posix/IoEvent.h"
61#include "modules/system/console/Console.h"
62#include "modules/system/users/User.h"
63#include "modules/system/vfs/Directory.h"
64#include "modules/system/vfs/File.h"
66#include "modules/system/vfs/MountView.h"
67#include "modules/system/vfs/Pipe.h"
68#include "modules/system/vfs/Symlink.h"
69#include "modules/system/vfs/VFS.h"
70#include "namespace-file.h"
71#include "net-syscalls.h"
72#include "network-namespace.h"
73#include "pipe-syscalls.h"
74#include "signalfd-syscalls.h"
75#include "timerfd-syscalls.h"
76#include "user-namespace.h"
81#include <sys/statfs.h>
82#include <sys/statvfs.h>
85static constexpr bool VerboseNormalisation =
false;
87extern int posix_getpid();
93 unsigned short d_reclen;
97extern DevFs* g_pDevFs;
103#define CHECK_FLAG(a, b) (((a) & (b)) == (b))
107 if (pStockProcess->getType() != Process::Posix) {
115static bool copyUserString(
const char* userString,
String& copy) {
116 PosixSubsystem::UserStringResult result =
118 if (result == PosixSubsystem::UserStringBadAddress) {
119 SYSCALL_ERROR(BadAddress);
122 if (result == PosixSubsystem::UserStringTooLong) {
123 SYSCALL_ERROR(NameTooLong);
132 auto* subsystem =
static_cast<PosixSubsystem*
>(process->getSubsystem());
133 return subsystem ? subsystem->findFileRetained(name, result, start, followFinal) :
nullptr;
138 auto* subsystem =
static_cast<PosixSubsystem*
>(process->getSubsystem());
139 return subsystem ? subsystem->followFile(selected) :
nullptr;
145 SYSCALL_ERROR(DoesNotExist);
150 if (selected.get() != file) {
151 SYSCALL_ERROR(DoesNotExist);
154 return followFilePath(selected);
158 File* target = traverseSymlink(dir, selected);
161 if (!target->
isDirectory() || selected.get() != target) {
162 SYSCALL_ERROR(NotADirectory);
166 auto context = process->acquireFilesystemContext();
168 return view && context && view->changeCwd(context, selected.path());
171static bool doStat(
const char* name,
File* file,
struct stat* output) {
172 return posix_stat_file(name, file, output);
176static struct Remapping {
185 {
"/dev",
"/dev",
"dev",
true,
true},
186 {
"/proc",
"/proc",
"proc",
true,
false},
187 {
"/tmp",
"/tmp",
"tmpfs",
true,
false},
188 {
"/run",
"/run",
"tmpfs",
true,
false},
189 {
"/var/run",
"/run",
"tmpfs",
true,
false},
193 {
"/.profile",
"/root/.profile",
nullptr,
true,
false},
194 {
"/.bashrc",
"/root/.bashrc",
nullptr,
true,
false},
195 {
"/support/pup/db",
"/var/cache/pup",
nullptr,
true,
false},
196 {
"/support/pup",
"/etc/pup",
nullptr,
true,
false},
197 {
"/system/initscripts",
"/etc/init.d",
nullptr,
true,
false},
198 {
"/system/modules",
"/usr/lib/modules",
nullptr,
true,
false},
199 {
"/system/include",
"/usr/include",
nullptr,
true,
false},
200 {
"/system/locale",
"/usr/share/locale",
nullptr,
true,
false},
201 {
"/system/keymaps",
"/usr/share/keymaps",
nullptr,
true,
false},
202 {
"/system/fonts",
"/usr/share/fonts",
nullptr,
true,
false},
203 {
"/applications",
"/usr/bin",
nullptr,
true,
false},
204 {
"/libraries",
"/usr/lib",
nullptr,
true,
false},
205 {
"/initscripts",
"/etc/init.d",
nullptr,
true,
false},
206 {
"/config",
"/etc",
nullptr,
true,
false},
207 {
"/support",
"/usr/lib/pedigree",
nullptr,
true,
false},
208 {
"/include",
"/usr/include",
nullptr,
true,
false},
209 {
"/users",
"/home",
nullptr,
true,
false},
210 {
"/fonts",
"/usr/share/fonts",
nullptr,
true,
false},
211 {
"/docs",
"/usr/share/doc",
nullptr,
true,
false},
212 {
"/doc",
"/usr/share/doc",
nullptr,
true,
false},
213 {
nullptr,
nullptr,
nullptr,
false,
false},
216bool normalisePath(
String& nameToOpen,
const char* name,
bool* onDevFs) {
217 if (!name || !name[0]) {
228 bool fixFilesystemPaths =
true;
233 if (!StringCompare(name,
"/dev/tty")) {
235 auto cttyContext = pProcess->acquireCttyContext();
236 if (!cttyContext || !cttyContext->file()) {
241 nameToOpen.assign(name);
245 struct Remapping* remap = g_Remappings;
246 EMIT_IF(VerboseNormalisation) {
247 F_NOTICE(
"performing remap for '" << name <<
"'...");
250 while (remap->from !=
nullptr) {
251 if (!(fixFilesystemPaths || remap->all_abis)) {
252 EMIT_IF(VerboseNormalisation) {
253 F_NOTICE(
" -> ignoring " << remap->from <<
" as it is not for the current ABI");
259 EMIT_IF(VerboseNormalisation) {
260 F_NOTICE(
" -> check against " << remap->from);
262 if (!StringCompare(name, remap->from)) {
263 EMIT_IF(VerboseNormalisation) {
264 F_NOTICE(
" -> direct remap to " << remap->to);
266 nameToOpen.assign(remap->to);
272 if (!StringCompareN(name, remap->from, StringLength(remap->from))) {
273 EMIT_IF(VerboseNormalisation) {
274 F_NOTICE(
" -> possibly partial remap");
279 if (*(name + StringLength(remap->from)) ==
'/') {
281 nameToOpen.assign(remap->to);
282 nameToOpen += (name + StringLength(remap->from));
283 EMIT_IF(VerboseNormalisation) {
284 F_NOTICE(
" -> indirect remap to create path '" << nameToOpen <<
"'...");
291 EMIT_IF(VerboseNormalisation) {
293 " -> cannot use this remap as it is not actually "
294 "matching a path segment");
301 if (onDevFs && remap) {
302 *onDevFs = remap->on_devfs;
306 nameToOpen.assign(name);
314int posix_close(
int fd) {
316 F_NOTICE(
"close(" << fd <<
")");
321 ERROR(
"No subsystem for this process!");
328 SYSCALL_ERROR(BadFileDescriptor);
333 F_NOTICE(
"close(" << fd <<
")");
344 if (ConsoleManager::instance().isConsole(pFd->getFile())) {
345 if (ConsoleManager::instance().isMasterConsole(pFd->getFile())) {
353int posix_open(
const char* name,
int flags,
int mode) {
354 return posix_openat(AT_FDCWD, name, flags, mode);
358constexpr size_t ScalarIoBounceCapacity = PIPE_BUF_MAX + 1;
359constexpr size_t RegularReadBounceCapacity = 128 * 1024;
360constexpr size_t RegularWriteBounceCapacity = 64 * 1024;
362#if PEDIGREE_BENCHMARK_VM_DIAGNOSTICS
363Process::BenchmarkVmCounter vmLengthCounter(
bool unmap,
size_t pages) {
364 const size_t bucket = pages <= 1 ? 0
370 const auto first = unmap ? Process::VmMunmapLength1 : Process::VmMmapLength1;
371 return static_cast<Process::BenchmarkVmCounter
>(
static_cast<size_t>(first) + bucket);
377 file->getFilesystem() && file->getFilesystem()->
getDisk();
378 const size_t limit = diskBackedRegular ? RegularReadBounceCapacity : ScalarIoBounceCapacity;
379 capacity = length < limit ? length : limit;
381 if (!bounce && capacity > ScalarIoBounceCapacity) {
382 capacity = ScalarIoBounceCapacity;
389 const size_t limit = regularFile ? RegularWriteBounceCapacity : ScalarIoBounceCapacity;
390 capacity = length < limit ? length : limit;
392 if (!bounce && capacity > ScalarIoBounceCapacity) {
393 capacity = ScalarIoBounceCapacity;
399bool copyWriteSource(
void* destination,
const void* source,
size_t& requested) {
403 if (requested <= ScalarIoBounceCapacity) {
408 requested = ScalarIoBounceCapacity;
412bool checkReadDestination(
void* destination,
size_t& requested) {
414 PosixSubsystem::SafeWrite)) {
417 if (requested <= ScalarIoBounceCapacity) {
422 requested = ScalarIoBounceCapacity;
424 PosixSubsystem::SafeWrite);
427bool scalarIoRangeDoesNotWrap(
const void* buffer,
size_t length) {
432 const uintptr_t address =
reinterpret_cast<uintptr_t
>(buffer);
433 return address && length - 1 <= (~static_cast<uintptr_t>(0) - address);
436bool positionalIoRangeIsValid(off_t offset,
size_t length) {
437 if (offset < 0 || length >
static_cast<size_t>(SSIZE_MAX)) {
441 const uint64_t location =
static_cast<uint64_t
>(offset);
442 return static_cast<uint64_t
>(length) <=
static_cast<uint64_t
>(INT64_MAX) - location;
446int posix_read(
int fd,
char* ptr,
int len) {
447 F_NOTICE(
"read(" <<
Dec << fd <<
Hex <<
", " <<
reinterpret_cast<uintptr_t
>(ptr) <<
", " << len
450 SYSCALL_ERROR(InvalidArgument);
459 ERROR(
"No subsystem for this process!");
466 SYSCALL_ERROR(BadFileDescriptor);
469 if (pFd->getFile() &&
470 ((pFd->getAccessFlags() & O_PATH) || (pFd->getAccessFlags() & O_ACCMODE) == O_WRONLY)) {
471 SYSCALL_ERROR(BadFileDescriptor);
475 if (!pFd->getFile()) {
476 auto timerFd = pFd->getTimerFdImpl();
477 auto signalFd = pFd->getSignalFdImpl();
478 if (timerFd || signalFd) {
481 return timerFd ? timerFd->readToUser(ptr, len, canBlock)
482 : signalFd->readToUser(ptr, len, canBlock);
487 if (len <
static_cast<int>(
sizeof(uint64_t))) {
488 SYSCALL_ERROR(InvalidArgument);
492 PosixSubsystem::SafeWrite)) {
493 SYSCALL_ERROR(BadAddress);
500 const int result = eventFd->readValue(value, canBlock);
505 SYSCALL_ERROR(BadAddress);
513 const size_t length =
static_cast<size_t>(len);
516 return inotify->readEventsToUser(
reinterpret_cast<uint8_t*
>(ptr), length, canBlock);
518 auto fanotify = pFd->getFanotifyImpl();
522 return fanotify->readToUser(ptr,
static_cast<size_t>(len), canBlock);
528 PosixSubsystem::SafeWrite)) {
529 F_NOTICE(
" -> invalid address");
530 SYSCALL_ERROR(BadAddress);
533 return posix_recv_descriptor(pFd, ptr, len, 0);
536 SYSCALL_ERROR(InvalidArgument);
541 SYSCALL_ERROR(IsADirectory);
549 const size_t length =
static_cast<size_t>(len);
550 if (!scalarIoRangeDoesNotWrap(ptr, length)) {
551 SYSCALL_ERROR(BadAddress);
554 size_t bounceCapacity = 0;
558 const bool canBlock = !(statusFlags & O_NONBLOCK);
559 size_t totalRead = 0;
561 while (totalRead < length) {
562 if (pThread->getInterruptionReason() == Thread::InterruptedBySignal) {
566 pThread->clearInterruption();
567 SYSCALL_ERROR(Interrupted);
571 const size_t remaining = length - totalRead;
573 remaining < RegularReadBounceCapacity ? remaining : RegularReadBounceCapacity;
574 char* userDestination =
reinterpret_cast<char*
>(
reinterpret_cast<uintptr_t
>(ptr) + totalRead);
578 userDestination, requested);
580 position->advanceOffset(cached);
586 bounce = allocateReadBounce(pFd->getFile(), remaining, bounceCapacity);
588 pThread->clearInterruption();
590 return static_cast<int>(totalRead);
592 SYSCALL_ERROR(OutOfMemory);
596 if (requested > bounceCapacity) {
597 requested = bounceCapacity;
602 if (!checkReadDestination(userDestination, requested)) {
604 pThread->clearInterruption();
605 return static_cast<int>(totalRead);
607 pThread->clearInterruption();
608 SYSCALL_ERROR(BadAddress);
614 const bool operationCanBlock = canBlock && (position || !totalRead);
615 if (!operationCanBlock) {
617 if (!(ready & (ReadyRead | ReadyError | ReadyHangup))) {
621 pThread->clearInterruption();
622 SYSCALL_ERROR(NoMoreProcesses);
623 F_NOTICE(
" -> async and nothing available to read");
628 if (pThread->getInterruptionReason() == Thread::InterruptedBySignal) {
632 pThread->clearInterruption();
633 SYSCALL_ERROR(Interrupted);
640 amount = pFd->getFile()->
read(position->offset(), requested,
641 reinterpret_cast<uintptr_t
>(bounce.get()), operationCanBlock);
643 amount = pFd->readFile(0, requested,
reinterpret_cast<uintptr_t
>(bounce.get()),
646 const bool signalInterrupted =
647 pThread->getInterruptionReason() == Thread::InterruptedBySignal;
648 const size_t backendError = pThread->
getErrno();
650 if (!amount && pFd->terminalHungUp())
653 if (!totalRead && signalInterrupted) {
654 pThread->clearInterruption();
655 SYSCALL_ERROR(Interrupted);
656 F_NOTICE(
" -> interrupted");
660 pThread->clearInterruption();
671 pThread->clearInterruption();
672 return static_cast<int>(totalRead);
674 pThread->clearInterruption();
675 SYSCALL_ERROR(BadAddress);
680 position->advanceOffset(amount);
683 if (amount < requested || signalInterrupted ||
684 pThread->getInterruptionReason() == Thread::InterruptedBySignal) {
689 pThread->clearInterruption();
690 F_NOTICE(
" -> " <<
Dec << totalRead <<
Hex);
691 return static_cast<int>(totalRead);
694 pThread->clearInterruption();
697 return readFile(&position, position.statusFlags());
705int posix_write(
int fd,
char* ptr,
int len,
bool nocheck) {
706 F_NOTICE(
"write(" << fd <<
", " <<
reinterpret_cast<uintptr_t
>(ptr) <<
", " << len <<
")");
708 SYSCALL_ERROR(InvalidArgument);
711 F_NOTICE(
" s = " <<
String(ptr, len));
718 ERROR(
"No subsystem for this process!");
725 SYSCALL_ERROR(BadFileDescriptor);
728 if (pFd->getFile() &&
729 ((pFd->getAccessFlags() & O_PATH) || (pFd->getAccessFlags() & O_ACCMODE) == O_RDONLY)) {
730 SYSCALL_ERROR(BadFileDescriptor);
736 !pFd->getFile()->isBlockDevice() && !mountWrite.acquire(pFd->openingPath())) {
739 if (!pFd->getFile()) {
740 if (pFd->getTimerFdImpl() || pFd->getSignalFdImpl() || pFd->getFanotifyImpl()) {
741 SYSCALL_ERROR(InvalidArgument);
747 if (len !=
static_cast<int>(
sizeof(uint64_t))) {
748 SYSCALL_ERROR(InvalidArgument);
754 ForwardMemoryCopy(&value, ptr,
sizeof(value));
756 SYSCALL_ERROR(BadAddress);
762 return eventFd->writeValue(value, canBlock);
766 SYSCALL_ERROR(BadFileDescriptor);
774 PosixSubsystem::SafeRead)) {
775 F_NOTICE(
" -> invalid address");
776 SYSCALL_ERROR(BadAddress);
779 return posix_send_descriptor(pFd, ptr, len, 0, nocheck);
782 SYSCALL_ERROR(InvalidArgument);
787 if (pFd->terminalHungUp()) {
788 SYSCALL_ERROR(IoError);
794 const bool pipeLike = pFd->getFile()->
isPipe() || pFd->getFile()->
isFifo();
795 const size_t length =
static_cast<size_t>(len);
796 if (!scalarIoRangeDoesNotWrap(ptr, length)) {
797 SYSCALL_ERROR(BadAddress);
800 const bool regularFile =
802 size_t bounceCapacity = 0;
805 SYSCALL_ERROR(OutOfMemory);
808 bool deliverPipeSignal =
false;
811 const bool canBlock = !(statusFlags & O_NONBLOCK);
813 size_t totalWritten = 0;
815 while (totalWritten < length) {
816 if (totalWritten && pThread->getInterruptionReason() == Thread::InterruptedBySignal) {
820 const size_t remaining = length - totalWritten;
821 size_t requested = remaining < bounceCapacity ? remaining : bounceCapacity;
822 const char* userSource =
823 reinterpret_cast<const char*
>(
reinterpret_cast<uintptr_t
>(ptr) + totalWritten);
826 ForwardMemoryCopy(bounce.get(), userSource, requested);
827 }
else if (!copyWriteSource(bounce.get(), userSource, requested)) {
829 pThread->clearInterruption();
830 return static_cast<int>(totalWritten);
832 pThread->clearInterruption();
833 SYSCALL_ERROR(BadAddress);
837 if (pThread->getInterruptionReason() == Thread::InterruptedBySignal) {
841 pThread->clearInterruption();
842 SYSCALL_ERROR(Interrupted);
849 uint64_t location = position->offset();
851 (statusFlags & O_APPEND)
852 ? writeGuard.append(requested,
reinterpret_cast<uintptr_t
>(bounce.get()), location,
853 canBlock, !regularFile)
854 : writeGuard.write(location, requested, reinterpret_cast<uintptr_t>(bounce.get()),
855 canBlock, !regularFile);
857 position->setOffset(location + amount);
859 }
else if (ConsoleManager::instance().isConsole(pFd->getFile())) {
860 amount = pFd->writeFile(0, requested,
reinterpret_cast<uintptr_t
>(bounce.get()), canBlock);
863 writeGuard.write(0, requested,
reinterpret_cast<uintptr_t
>(bounce.get()), canBlock);
865 const bool signalInterrupted =
866 pThread->getInterruptionReason() == Thread::InterruptedBySignal;
867 const size_t backendError = pThread->
getErrno();
874 if (signalInterrupted && !pFd->terminalHungUp()) {
875 pThread->clearInterruption();
876 SYSCALL_ERROR(Interrupted);
877 F_NOTICE(
" -> interrupted");
881 pThread->clearInterruption();
882 deliverPipeSignal = pipeLike && backendError == Error::BrokenPipe;
886 pThread->clearInterruption();
887 F_NOTICE(
" -> write to a broken pipe");
888 SYSCALL_ERROR(BrokenPipe);
889 deliverPipeSignal =
true;
893 pThread->clearInterruption();
894 SYSCALL_ERROR(NoMoreProcesses);
898 pThread->clearInterruption();
899 F_NOTICE(
" -> write to a broken pipe");
900 SYSCALL_ERROR(BrokenPipe);
901 deliverPipeSignal =
true;
908 totalWritten += amount;
909 if (amount < requested || signalInterrupted ||
910 pThread->getInterruptionReason() == Thread::InterruptedBySignal) {
915 pThread->clearInterruption();
916 F_NOTICE(
" -> write returns " << totalWritten);
917 return static_cast<int>(totalWritten);
920 pThread->clearInterruption();
925 result = writeFile(&position, position.statusFlags());
933 if (deliverPipeSignal) {
939ssize_t posix_pread64(
int fd,
char* ptr,
size_t len, off_t offset) {
940 F_NOTICE(
"pread64(" <<
Dec << fd <<
Hex <<
", " <<
reinterpret_cast<uintptr_t
>(ptr) <<
", " << len
941 <<
", " << offset <<
")");
942 if (!positionalIoRangeIsValid(offset, len)) {
943 SYSCALL_ERROR(InvalidArgument);
951 ERROR(
"No subsystem for this process!");
957 SYSCALL_ERROR(BadFileDescriptor);
961 if (!descriptor->getFile() || !descriptor->getFile()->
isSeekable()) {
962 SYSCALL_ERROR(IllegalSeek);
966 if ((statusFlags & O_PATH) || (statusFlags & O_ACCMODE) == O_WRONLY) {
967 SYSCALL_ERROR(BadFileDescriptor);
971 SYSCALL_ERROR(IsADirectory);
977 if (!scalarIoRangeDoesNotWrap(ptr, len)) {
978 SYSCALL_ERROR(BadAddress);
982 size_t bounceCapacity = 0;
984 const bool canBlock = !(statusFlags & O_NONBLOCK);
985 const uint64_t startingOffset =
static_cast<uint64_t
>(offset);
986 size_t totalRead = 0;
988 thread->clearInterruption();
989 while (totalRead < len) {
990 if (thread->getInterruptionReason() == Thread::InterruptedBySignal) {
994 thread->clearInterruption();
995 SYSCALL_ERROR(Interrupted);
999 const size_t remaining = len - totalRead;
1001 remaining < RegularReadBounceCapacity ? remaining : RegularReadBounceCapacity;
1002 char* userDestination =
reinterpret_cast<char*
>(
reinterpret_cast<uintptr_t
>(ptr) + totalRead);
1004 *descriptor->getFile(), startingOffset + totalRead, userDestination, requested);
1006 totalRead += cached;
1010 bounce = allocateReadBounce(descriptor->getFile(), remaining, bounceCapacity);
1012 thread->clearInterruption();
1014 return static_cast<ssize_t
>(totalRead);
1016 SYSCALL_ERROR(OutOfMemory);
1020 if (requested > bounceCapacity) {
1021 requested = bounceCapacity;
1023 if (!checkReadDestination(userDestination, requested)) {
1025 thread->clearInterruption();
1026 return static_cast<ssize_t
>(totalRead);
1028 thread->clearInterruption();
1029 SYSCALL_ERROR(BadAddress);
1033 if (thread->getInterruptionReason() == Thread::InterruptedBySignal) {
1037 thread->clearInterruption();
1038 SYSCALL_ERROR(Interrupted);
1043 const uint64_t amount = descriptor->getFile()->
read(
1044 startingOffset + totalRead, requested,
reinterpret_cast<uintptr_t
>(bounce.get()), canBlock);
1045 const bool signalInterrupted = thread->getInterruptionReason() == Thread::InterruptedBySignal;
1046 const size_t backendError = thread->
getErrno();
1048 if (!totalRead && signalInterrupted) {
1049 thread->clearInterruption();
1050 SYSCALL_ERROR(Interrupted);
1054 thread->clearInterruption();
1065 thread->clearInterruption();
1066 return static_cast<ssize_t
>(totalRead);
1068 thread->clearInterruption();
1069 SYSCALL_ERROR(BadAddress);
1073 totalRead += amount;
1074 if (amount < requested || signalInterrupted ||
1075 thread->getInterruptionReason() == Thread::InterruptedBySignal) {
1080 thread->clearInterruption();
1081 return static_cast<ssize_t
>(totalRead);
1084ssize_t posix_pwrite64(
int fd,
const char* ptr,
size_t len, off_t offset) {
1085 F_NOTICE(
"pwrite64(" <<
Dec << fd <<
Hex <<
", " <<
reinterpret_cast<uintptr_t
>(ptr) <<
", "
1086 << len <<
", " << offset <<
")");
1087 if (!positionalIoRangeIsValid(offset, len)) {
1088 SYSCALL_ERROR(InvalidArgument);
1096 ERROR(
"No subsystem for this process!");
1102 SYSCALL_ERROR(BadFileDescriptor);
1106 if (!descriptor->getFile() || !descriptor->getFile()->
isSeekable()) {
1107 SYSCALL_ERROR(IllegalSeek);
1111 if (descriptor->openingPath() && descriptor->getFile() &&
1113 !descriptor->getFile()->isBlockDevice() && !mountWrite.acquire(descriptor->openingPath())) {
1117 if ((statusFlags & O_PATH) || (statusFlags & O_ACCMODE) == O_RDONLY) {
1118 SYSCALL_ERROR(BadFileDescriptor);
1122 SYSCALL_ERROR(IsADirectory);
1128 if (!scalarIoRangeDoesNotWrap(ptr, len)) {
1129 SYSCALL_ERROR(BadAddress);
1134 !descriptor->getFile()->isBlockDevice();
1135 size_t bounceCapacity = 0;
1138 SYSCALL_ERROR(OutOfMemory);
1141 const bool canBlock = !(statusFlags & O_NONBLOCK);
1142 const uint64_t startingOffset =
static_cast<uint64_t
>(offset);
1144 size_t totalWritten = 0;
1146 thread->clearInterruption();
1147 while (totalWritten < len) {
1148 if (totalWritten && thread->getInterruptionReason() == Thread::InterruptedBySignal) {
1152 const size_t remaining = len - totalWritten;
1153 size_t requested = remaining < bounceCapacity ? remaining : bounceCapacity;
1154 const char* userSource =
1155 reinterpret_cast<const char*
>(
reinterpret_cast<uintptr_t
>(ptr) + totalWritten);
1156 if (!copyWriteSource(bounce.get(), userSource, requested)) {
1158 thread->clearInterruption();
1159 return static_cast<ssize_t
>(totalWritten);
1161 thread->clearInterruption();
1162 SYSCALL_ERROR(BadAddress);
1166 if (thread->getInterruptionReason() == Thread::InterruptedBySignal) {
1170 thread->clearInterruption();
1171 SYSCALL_ERROR(Interrupted);
1176 const uint64_t amount =
1177 writeGuard.write(startingOffset + totalWritten, requested,
1178 reinterpret_cast<uintptr_t
>(bounce.get()), canBlock, !regularFile);
1179 const bool signalInterrupted = thread->getInterruptionReason() == Thread::InterruptedBySignal;
1180 const size_t backendError = thread->
getErrno();
1182 if (!totalWritten && signalInterrupted) {
1183 thread->clearInterruption();
1184 SYSCALL_ERROR(Interrupted);
1192 thread->clearInterruption();
1196 thread->clearInterruption();
1197 SYSCALL_ERROR(NoMoreProcesses);
1204 totalWritten += amount;
1205 if (amount < requested || signalInterrupted ||
1206 thread->getInterruptionReason() == Thread::InterruptedBySignal) {
1211 thread->clearInterruption();
1212 return static_cast<ssize_t
>(totalWritten);
1215enum class VectorPayloadValidation {
1223 static constexpr size_t InlineCount = 8;
1224 struct iovec inlineVectors[InlineCount];
1226 struct iovec* vectors =
nullptr;
1230constexpr size_t SmallVectorIoBounceCapacity = 4096;
1232static_assert(SmallVectorIoBounceCapacity <= ScalarIoBounceCapacity &&
1233 SmallVectorIoBounceCapacity <= RegularReadBounceCapacity);
1235static bool snapshotIoVectors(
1236 const struct iovec* userVectors,
int vectorCount,
bool writeOperation,
1238 VectorPayloadValidation payloadValidation = VectorPayloadValidation::Full) {
1239 constexpr int MaximumIoVectors = 1024;
1240 if (vectorCount < 0 || vectorCount > MaximumIoVectors) {
1241 SYSCALL_ERROR(InvalidArgument);
1250 if (
static_cast<size_t>(vectorCount) <= IoVectorSnapshot::InlineCount) {
1251 vectorOwner.vectors = vectorOwner.inlineVectors;
1254 vectorOwner.vectors = vectorOwner.heap.get();
1256 struct iovec* vectors = vectorOwner.vectors;
1258 SYSCALL_ERROR(OutOfMemory);
1262 sizeof(
struct iovec))) {
1263 SYSCALL_ERROR(BadAddress);
1267 const bool validatePayload = payloadValidation != VectorPayloadValidation::CopyTime &&
1268 payloadValidation != VectorPayloadValidation::CommitTime;
1269 const bool rangeOnly = payloadValidation == VectorPayloadValidation::AddressRange;
1270 const size_t access = writeOperation ? PosixSubsystem::SafeRead : PosixSubsystem::SafeWrite;
1271 for (
int i = 0; i < vectorCount; ++i) {
1272 if (vectors[i].iov_len >
static_cast<size_t>(INT_MAX) - totalLength) {
1273 SYSCALL_ERROR(InvalidArgument);
1276 if (vectors[i].iov_len && validatePayload) {
1277 const uintptr_t base =
reinterpret_cast<uintptr_t
>(vectors[i].iov_base);
1278 const bool valid = rangeOnly
1280 :
PosixSubsystem::checkUserBuffer(base, vectors[i].iov_len, 1, access);
1282 SYSCALL_ERROR(BadAddress);
1286 totalLength += vectors[i].iov_len;
1294 bool publishMetadata,
bool reportError,
bool& signalInterrupted,
1295 bool& deliverPipeSignal) {
1296 File* file = descriptor->getFile();
1297 const bool canBlock = !(statusFlags & O_NONBLOCK);
1300 uint64_t written = 0;
1303 uint64_t location = position->offset();
1304 written = (statusFlags & O_APPEND)
1305 ? writeGuard.append(length,
reinterpret_cast<uintptr_t
>(buffer), location,
1306 canBlock, publishMetadata)
1307 : writeGuard.write(location, length, reinterpret_cast<uintptr_t>(buffer),
1308 canBlock, publishMetadata);
1310 position->setOffset(location + written);
1312 }
else if (ConsoleManager::instance().isConsole(file)) {
1313 written = descriptor->writeFile(0, length,
reinterpret_cast<uintptr_t
>(buffer), canBlock);
1316 writeGuard.write(0, length,
reinterpret_cast<uintptr_t
>(buffer), canBlock, publishMetadata);
1319 signalInterrupted = thread->getInterruptionReason() == Thread::InterruptedBySignal;
1320 const size_t backendError = thread->
getErrno();
1321 thread->clearInterruption();
1322 if (!written && signalInterrupted && !descriptor->terminalHungUp()) {
1324 SYSCALL_ERROR(Interrupted);
1330 if (!written && backendError) {
1331 deliverPipeSignal = (file->
isPipe() || file->
isFifo()) && backendError == Error::BrokenPipe;
1339 const bool pipeLike = file->
isPipe() || file->
isFifo();
1340 if (!canBlock && !written && length && (!pipeLike ||
Pipe::fromFile(file)->getReaderCount())) {
1342 SYSCALL_ERROR(NoMoreProcesses);
1346 if (pipeLike && !written && length) {
1348 SYSCALL_ERROR(BrokenPipe);
1350 deliverPipeSignal =
true;
1353 return static_cast<int>(written);
1358 void* buffer,
size_t length,
bool reportError,
1359 bool& signalInterrupted) {
1360 File* file = descriptor->getFile();
1361 const bool canBlock = !(statusFlags & O_NONBLOCK);
1364 uint64_t amount = 0;
1367 amount = file->
read(position->offset(), length,
reinterpret_cast<uintptr_t
>(buffer), canBlock);
1369 amount = descriptor->readFile(0, length,
reinterpret_cast<uintptr_t
>(buffer), canBlock);
1372 signalInterrupted = thread->getInterruptionReason() == Thread::InterruptedBySignal;
1373 const size_t backendError = thread->
getErrno();
1374 thread->clearInterruption();
1375 if (!amount && signalInterrupted && !descriptor->terminalHungUp()) {
1377 SYSCALL_ERROR(Interrupted);
1381 if (!amount && backendError) {
1387 return static_cast<int>(amount);
1390static bool scatterEventFdValue(
const struct iovec* vectors,
int vectorCount, uint64_t value) {
1392 const uint8_t* source =
reinterpret_cast<const uint8_t*
>(&value);
1393 for (
int i = 0; i < vectorCount && copied <
sizeof(value); ++i) {
1394 size_t fragment = vectors[i].iov_len;
1395 if (fragment >
sizeof(value) - copied) {
1396 fragment =
sizeof(value) - copied;
1399 SYSCALL_ERROR(BadAddress);
1404 return copied ==
sizeof(value);
1407static int posixWritev(
int fd,
const struct iovec* iov,
int iovcnt,
bool suppressAppend) {
1408 F_NOTICE(
"writev(" << fd <<
", <iov>, " << iovcnt <<
")");
1418 SYSCALL_ERROR(BadFileDescriptor);
1421 if (descriptor->getFile()) {
1422 const int accessFlags = descriptor->getAccessFlags();
1423 if ((accessFlags & O_PATH) || (accessFlags & O_ACCMODE) == O_RDONLY) {
1424 SYSCALL_ERROR(BadFileDescriptor);
1430 if (descriptor->openingPath() && descriptor->getFile() &&
1432 !descriptor->getFile()->isBlockDevice() && !mountWrite.acquire(descriptor->openingPath())) {
1435 const bool regularFile = descriptor->getFile() &&
1437 !descriptor->getFile()->isBlockDevice();
1438 const VectorPayloadValidation payloadValidation =
1439 regularFile ? VectorPayloadValidation::CopyTime : VectorPayloadValidation::Full;
1441 size_t totalLength = 0;
1442 if (!snapshotIoVectors(iov, iovcnt,
true, vectorOwner, totalLength, payloadValidation)) {
1445 struct iovec* vectors = vectorOwner.vectors;
1454 if (!regularFile && (descriptor->getTimerFdImpl() || descriptor->getSignalFdImpl() ||
1455 descriptor->getFanotifyImpl())) {
1456 SYSCALL_ERROR(InvalidArgument);
1463 const bool canBlock = !(descriptor->
getStatusFlags() & O_NONBLOCK);
1466 int totalWritten = 0;
1467 for (
int i = 0; i < iovcnt; ++i) {
1468 if (!vectors[i].iov_len) {
1471 if (vectors[i].iov_len !=
sizeof(uint64_t)) {
1472 SYSCALL_ERROR(InvalidArgument);
1473 return totalWritten ? totalWritten : -1;
1478 SYSCALL_ERROR(BadAddress);
1479 return totalWritten ? totalWritten : -1;
1482 const int written = eventFd->writeValue(value, canBlock);
1484 return totalWritten ? totalWritten : written;
1486 totalWritten += written;
1488 return totalWritten;
1494 message.msg_iovlen =
static_cast<size_t>(iovcnt);
1495 return static_cast<int>(posix_sendmsg_descriptor(descriptor, &
message));
1497 if (!descriptor->getFile()) {
1498 SYSCALL_ERROR(InvalidArgument);
1501 bool deliverPipeSignal =
false;
1503 const bool pipeLike = descriptor->getFile()->
isPipe() || descriptor->getFile()->
isFifo();
1504 if (pipeLike && totalLength <= PIPE_BUF_MAX) {
1507 for (
int i = 0; i < iovcnt; ++i) {
1508 if (vectors[i].iov_len &&
1510 vectors[i].iov_len)) {
1511 SYSCALL_ERROR(BadAddress);
1514 offset += vectors[i].iov_len;
1517 if (thread->getInterruptionReason() == Thread::InterruptedBySignal) {
1518 thread->clearInterruption();
1519 SYSCALL_ERROR(Interrupted);
1522 bool signalInterrupted =
false;
1523 return totalLength ? writeFileVectorElement(thread, descriptor, position, statusFlags,
1524 writeGuard, aggregate.get(), totalLength,
true,
1525 true, signalInterrupted, deliverPipeSignal)
1529 const size_t bounceLimit = regularFile ? RegularWriteBounceCapacity : ScalarIoBounceCapacity;
1530 const size_t bounceCapacity = totalLength < bounceLimit ? totalLength : bounceLimit;
1531 uint8_t smallBounce[SmallVectorIoBounceCapacity];
1533 uint8_t* bounce = smallBounce;
1534 if (!regularFile || bounceCapacity >
sizeof(smallBounce)) {
1536 bounce = bounceOwner.get();
1539 SYSCALL_ERROR(OutOfMemory);
1543 for (
int i = 0; i < iovcnt; ++i) {
1544 F_NOTICE(
"writev: iov[" << i <<
"] is @ " << vectors[i].iov_base <<
", " << vectors[i].iov_len
1548 int totalWritten = 0;
1549 int vectorIndex = 0;
1550 size_t vectorOffset = 0;
1551 while (
static_cast<size_t>(totalWritten) < totalLength) {
1552 if (totalWritten && thread->getInterruptionReason() == Thread::InterruptedBySignal) {
1553 thread->clearInterruption();
1554 return totalWritten;
1557 const size_t remaining = totalLength -
static_cast<size_t>(totalWritten);
1558 const size_t requested = remaining < bounceCapacity ? remaining : bounceCapacity;
1559 size_t gathered = 0;
1560 while (gathered < requested) {
1561 while (vectorIndex < iovcnt && vectorOffset == vectors[vectorIndex].iov_len) {
1565 assert(vectorIndex < iovcnt);
1567 const size_t vectorRemaining = vectors[vectorIndex].iov_len - vectorOffset;
1568 const size_t fragment =
1569 vectorRemaining < requested - gathered ? vectorRemaining : requested - gathered;
1570 const char* userSource =
reinterpret_cast<const char*
>(
1571 reinterpret_cast<uintptr_t
>(vectors[vectorIndex].iov_base) + vectorOffset);
1573 thread->clearInterruption();
1575 return totalWritten;
1577 SYSCALL_ERROR(BadAddress);
1580 gathered += fragment;
1581 vectorOffset += fragment;
1584 if (thread->getInterruptionReason() == Thread::InterruptedBySignal) {
1585 thread->clearInterruption();
1587 return totalWritten;
1589 SYSCALL_ERROR(Interrupted);
1593 bool signalInterrupted =
false;
1594 const int r = writeFileVectorElement(thread, descriptor, position, statusFlags, writeGuard,
1595 bounce, requested, !regularFile, totalWritten == 0,
1596 signalInterrupted, deliverPipeSignal);
1598 return totalWritten ? totalWritten : r;
1602 if (
static_cast<size_t>(r) < requested || signalInterrupted) {
1603 return totalWritten;
1607 return totalWritten;
1610 thread->clearInterruption();
1615 int statusFlags = position.statusFlags();
1616 if (suppressAppend) {
1617 statusFlags &= ~O_APPEND;
1619 result = writeVector(&position, statusFlags);
1627 if (deliverPipeSignal) {
1633int posix_writev(
int fd,
const struct iovec* iov,
int iovcnt) {
1634 return posixWritev(fd, iov, iovcnt,
false);
1637int posix_readv(
int fd,
const struct iovec* iov,
int iovcnt) {
1638 F_NOTICE(
"readv(" << fd <<
", <iov>, " << iovcnt <<
")");
1648 SYSCALL_ERROR(BadFileDescriptor);
1651 if (descriptor->getFile()) {
1652 const int accessFlags = descriptor->getAccessFlags();
1653 if ((accessFlags & O_PATH) || (accessFlags & O_ACCMODE) == O_WRONLY) {
1654 SYSCALL_ERROR(BadFileDescriptor);
1658 const bool regularFile = descriptor->getFile() &&
1660 !descriptor->getFile()->isBlockDevice();
1664 VectorPayloadValidation payloadValidation =
1665 regularFile ? VectorPayloadValidation::CopyTime : VectorPayloadValidation::Full;
1666 if (timerFd || signalFd || fanotify) {
1667 payloadValidation = VectorPayloadValidation::CommitTime;
1670 size_t totalLength = 0;
1673 if (!snapshotIoVectors(iov, iovcnt,
false, vectorOwner, totalLength, payloadValidation)) {
1676 struct iovec* vectors = vectorOwner.vectors;
1684 if (timerFd || signalFd || fanotify) {
1685 const bool canBlock = !(descriptor->
getStatusFlags() & O_NONBLOCK);
1688 struct iovec* vectors;
1692 } scatter{vectors, iovcnt};
1693 auto copy = [](
void* context,
const void* data,
size_t size) ->
bool {
1694 auto& cursor = *
static_cast<Scatter*
>(context);
1695 auto* bytes =
static_cast<const uint8_t*
>(data);
1697 while (cursor.index < cursor.count &&
1698 cursor.offset == cursor.vectors[cursor.index].iov_len) {
1702 if (cursor.index == cursor.count) {
1703 SYSCALL_ERROR(BadAddress);
1706 const struct iovec& vector = cursor.vectors[cursor.index];
1707 const size_t available = vector.iov_len - cursor.offset;
1708 const size_t amount = size < available ? size : available;
1709 const uintptr_t base =
reinterpret_cast<uintptr_t
>(vector.iov_base);
1710 if (cursor.offset > ~uintptr_t(0) - base) {
1711 SYSCALL_ERROR(BadAddress);
1714 void* destination =
reinterpret_cast<void*
>(base + cursor.offset);
1716 SYSCALL_ERROR(BadAddress);
1719 cursor.offset += amount;
1725 return timerFd ? timerFd->readWithCopy(totalLength, canBlock, copy, &scatter)
1726 : signalFd ? signalFd->readWithCopy(totalLength, canBlock, copy, &scatter)
1727 : fanotify->readWithCopy(totalLength, canBlock, copy, &scatter);
1733 if (totalLength <
sizeof(uint64_t)) {
1734 SYSCALL_ERROR(InvalidArgument);
1738 const bool canBlock = !(descriptor->
getStatusFlags() & O_NONBLOCK);
1741 const int result = eventFd->readValue(value, canBlock);
1745 return scatterEventFdValue(vectors, iovcnt, value) ? result : -1;
1751 message.msg_iovlen =
static_cast<size_t>(iovcnt);
1752 return static_cast<int>(posix_recvmsg_descriptor(descriptor, &
message));
1754 if (!descriptor->getFile()) {
1755 SYSCALL_ERROR(InvalidArgument);
1759 SYSCALL_ERROR(IsADirectory);
1764 const bool pipeLike = descriptor->getFile()->
isPipe() || descriptor->getFile()->
isFifo();
1765 if (pipeLike && totalLength) {
1766 const size_t readCapacity = totalLength < PIPE_BUF_MAX ? totalLength : PIPE_BUF_MAX;
1768 if (statusFlags & O_NONBLOCK) {
1769 const ReadyMask ready =
1771 if (!(ready & (ReadyRead | ReadyError | ReadyHangup))) {
1772 SYSCALL_ERROR(NoMoreProcesses);
1776 if (thread->getInterruptionReason() == Thread::InterruptedBySignal) {
1777 thread->clearInterruption();
1778 SYSCALL_ERROR(Interrupted);
1781 bool signalInterrupted =
false;
1783 readFileVectorElement(thread, descriptor, position, statusFlags, aggregate.get(),
1784 readCapacity,
true, signalInterrupted);
1790 for (
int i = 0; i < iovcnt && copied < static_cast<size_t>(amount); ++i) {
1791 size_t fragment = vectors[i].iov_len;
1792 if (fragment >
static_cast<size_t>(amount) - copied) {
1793 fragment =
static_cast<size_t>(amount) - copied;
1798 return static_cast<int>(copied);
1800 SYSCALL_ERROR(BadAddress);
1805 return static_cast<int>(copied);
1808 if (regularFile && position) {
1809 uint8_t smallBounce[SmallVectorIoBounceCapacity];
1810 size_t bounceCapacity = totalLength;
1812 uint8_t* bounce = smallBounce;
1813 if (totalLength >
sizeof(smallBounce)) {
1814 bounceOwner = allocateReadBounce(descriptor->getFile(), totalLength, bounceCapacity);
1815 bounce = bounceOwner.get();
1818 SYSCALL_ERROR(OutOfMemory);
1822 size_t totalRead = 0;
1823 int vectorIndex = 0;
1824 size_t vectorOffset = 0;
1825 while (totalRead < totalLength) {
1826 if (totalRead && thread->getInterruptionReason() == Thread::InterruptedBySignal) {
1827 thread->clearInterruption();
1828 return static_cast<int>(totalRead);
1831 const size_t remaining = totalLength - totalRead;
1832 const size_t requested = remaining < bounceCapacity ? remaining : bounceCapacity;
1833 bool signalInterrupted =
false;
1834 const int amount = readFileVectorElement(thread, descriptor, position, statusFlags, bounce,
1835 requested, totalRead == 0, signalInterrupted);
1837 return totalRead ?
static_cast<int>(totalRead) : amount;
1840 return static_cast<int>(totalRead);
1844 while (copied <
static_cast<size_t>(amount)) {
1845 while (vectorIndex < iovcnt && vectorOffset == vectors[vectorIndex].iov_len) {
1849 assert(vectorIndex < iovcnt);
1851 const size_t vectorRemaining = vectors[vectorIndex].iov_len - vectorOffset;
1852 const size_t fragment = vectorRemaining < static_cast<size_t>(amount) - copied
1854 :
static_cast<size_t>(amount) - copied;
1855 void* userDestination =
reinterpret_cast<void*
>(
1856 reinterpret_cast<uintptr_t
>(vectors[vectorIndex].iov_base) + vectorOffset);
1858 thread->clearInterruption();
1860 return static_cast<int>(totalRead);
1862 SYSCALL_ERROR(BadAddress);
1867 vectorOffset += fragment;
1868 position->advanceOffset(fragment);
1869 totalRead += fragment;
1872 if (
static_cast<size_t>(amount) < requested || signalInterrupted) {
1873 return static_cast<int>(totalRead);
1877 return static_cast<int>(totalRead);
1880 size_t bounceCapacity = 0;
1882 allocateReadBounce(descriptor->getFile(), totalLength, bounceCapacity);
1884 SYSCALL_ERROR(OutOfMemory);
1888 for (
int i = 0; i < iovcnt; ++i) {
1889 F_NOTICE(
"readv: iov[" << i <<
"] is @ " << vectors[i].iov_base <<
", " << vectors[i].iov_len
1892 if (!vectors[i].iov_len) {
1896 size_t vectorOffset = 0;
1897 while (vectorOffset < vectors[i].iov_len) {
1898 if (totalRead && thread->getInterruptionReason() == Thread::InterruptedBySignal) {
1899 thread->clearInterruption();
1903 const size_t remaining = vectors[i].iov_len - vectorOffset;
1904 size_t requested = remaining < bounceCapacity ? remaining : bounceCapacity;
1905 void* userDestination =
reinterpret_cast<void*
>(
1906 reinterpret_cast<uintptr_t
>(vectors[i].iov_base) + vectorOffset);
1910 if (!regularFile && !checkReadDestination(userDestination, requested)) {
1911 thread->clearInterruption();
1915 SYSCALL_ERROR(BadAddress);
1921 const bool operationCanBlock = !(statusFlags & O_NONBLOCK) && (position || !totalRead);
1922 if (!operationCanBlock) {
1923 const ReadyMask ready =
1925 if (!(ready & (ReadyRead | ReadyError | ReadyHangup))) {
1929 thread->clearInterruption();
1930 SYSCALL_ERROR(NoMoreProcesses);
1935 if (thread->getInterruptionReason() == Thread::InterruptedBySignal) {
1936 thread->clearInterruption();
1940 SYSCALL_ERROR(Interrupted);
1944 const int elementFlags = operationCanBlock ? statusFlags : statusFlags | O_NONBLOCK;
1945 bool signalInterrupted =
false;
1947 readFileVectorElement(thread, descriptor, position, elementFlags, bounce.get(),
1948 requested, totalRead == 0, signalInterrupted);
1950 return totalRead ? totalRead : r;
1957 thread->clearInterruption();
1961 SYSCALL_ERROR(BadAddress);
1966 position->advanceOffset(
static_cast<size_t>(r));
1969 vectorOffset +=
static_cast<size_t>(r);
1970 if (
static_cast<size_t>(r) < requested || signalInterrupted) {
1979 thread->clearInterruption();
1982 return readVector(&position, position.statusFlags());
1991constexpr int LinuxRwfNoAppend = 0x20;
1993ssize_t positionalReadVector(
int fd,
const struct iovec* iov,
int iovcnt, off_t offset) {
1995 size_t totalLength = 0;
1996 if (!snapshotIoVectors(iov, iovcnt,
false, vectorOwner, totalLength,
1997 VectorPayloadValidation::AddressRange)) {
2000 if (!positionalIoRangeIsValid(offset, totalLength)) {
2001 SYSCALL_ERROR(InvalidArgument);
2013 SYSCALL_ERROR(BadFileDescriptor);
2016 if (!descriptor->getFile() || !descriptor->getFile()->
isSeekable()) {
2017 SYSCALL_ERROR(IllegalSeek);
2022 if ((statusFlags & O_PATH) || (statusFlags & O_ACCMODE) == O_WRONLY) {
2023 SYSCALL_ERROR(BadFileDescriptor);
2027 SYSCALL_ERROR(IsADirectory);
2030 if (!iovcnt || !totalLength) {
2034 struct iovec* vectors = vectorOwner.vectors;
2035 size_t bounceCapacity = 0;
2037 allocateReadBounce(descriptor->getFile(), totalLength, bounceCapacity);
2039 SYSCALL_ERROR(OutOfMemory);
2042 const bool canBlock = !(statusFlags & O_NONBLOCK);
2043 const uint64_t startingOffset =
static_cast<uint64_t
>(offset);
2044 size_t totalRead = 0;
2046 thread->clearInterruption();
2047 for (
int i = 0; i < iovcnt; ++i) {
2048 size_t vectorOffset = 0;
2049 while (vectorOffset < vectors[i].iov_len) {
2050 if (totalRead && thread->getInterruptionReason() == Thread::InterruptedBySignal) {
2051 thread->clearInterruption();
2052 return static_cast<ssize_t
>(totalRead);
2055 const size_t remaining = vectors[i].iov_len - vectorOffset;
2056 size_t requested = remaining < bounceCapacity ? remaining : bounceCapacity;
2057 void* userDestination =
2058 reinterpret_cast<void*
>(
reinterpret_cast<uintptr_t
>(vectors[i].iov_base) + vectorOffset);
2059 if (!checkReadDestination(userDestination, requested)) {
2060 thread->clearInterruption();
2062 return static_cast<ssize_t
>(totalRead);
2064 SYSCALL_ERROR(BadAddress);
2068 if (thread->getInterruptionReason() == Thread::InterruptedBySignal) {
2069 thread->clearInterruption();
2071 return static_cast<ssize_t
>(totalRead);
2073 SYSCALL_ERROR(Interrupted);
2078 const uint64_t amount =
2079 descriptor->getFile()->
read(startingOffset + totalRead, requested,
2080 reinterpret_cast<uintptr_t
>(bounce.get()), canBlock);
2081 const bool signalInterrupted = thread->getInterruptionReason() == Thread::InterruptedBySignal;
2082 const size_t backendError = thread->
getErrno();
2084 thread->clearInterruption();
2085 if (!totalRead && signalInterrupted) {
2086 SYSCALL_ERROR(Interrupted);
2095 return static_cast<ssize_t
>(totalRead);
2099 thread->clearInterruption();
2101 return static_cast<ssize_t
>(totalRead);
2103 SYSCALL_ERROR(BadAddress);
2107 totalRead +=
static_cast<size_t>(amount);
2108 vectorOffset +=
static_cast<size_t>(amount);
2109 if (amount < requested || signalInterrupted ||
2110 thread->getInterruptionReason() == Thread::InterruptedBySignal) {
2111 thread->clearInterruption();
2112 return static_cast<ssize_t
>(totalRead);
2117 thread->clearInterruption();
2118 return static_cast<ssize_t
>(totalRead);
2121ssize_t positionalWriteVector(
int fd,
const struct iovec* iov,
int iovcnt, off_t offset,
2124 size_t totalLength = 0;
2125 if (!snapshotIoVectors(iov, iovcnt,
true, vectorOwner, totalLength,
2126 VectorPayloadValidation::AddressRange)) {
2129 if (!positionalIoRangeIsValid(offset, totalLength)) {
2130 SYSCALL_ERROR(InvalidArgument);
2142 SYSCALL_ERROR(BadFileDescriptor);
2145 if (!descriptor->getFile() || !descriptor->getFile()->
isSeekable()) {
2146 SYSCALL_ERROR(IllegalSeek);
2151 if (descriptor->openingPath() && descriptor->getFile() &&
2153 !descriptor->getFile()->isBlockDevice() && !mountWrite.acquire(descriptor->openingPath())) {
2157 if ((statusFlags & O_PATH) || (statusFlags & O_ACCMODE) == O_RDONLY) {
2158 SYSCALL_ERROR(BadFileDescriptor);
2162 SYSCALL_ERROR(IsADirectory);
2165 if (!iovcnt || !totalLength) {
2169 struct iovec* vectors = vectorOwner.vectors;
2170 const size_t bounceCapacity =
2171 totalLength < ScalarIoBounceCapacity ? totalLength : ScalarIoBounceCapacity;
2173 const bool canBlock = !(statusFlags & O_NONBLOCK);
2174 const uint64_t startingOffset =
static_cast<uint64_t
>(offset);
2175 const bool append = honorAppend && (statusFlags & O_APPEND);
2177 size_t totalWritten = 0;
2178 int vectorIndex = 0;
2179 size_t vectorOffset = 0;
2181 thread->clearInterruption();
2182 while (totalWritten < totalLength) {
2183 if (totalWritten && thread->getInterruptionReason() == Thread::InterruptedBySignal) {
2184 thread->clearInterruption();
2185 return static_cast<ssize_t
>(totalWritten);
2188 const size_t remaining = totalLength - totalWritten;
2189 const size_t requested = remaining < bounceCapacity ? remaining : bounceCapacity;
2190 size_t gathered = 0;
2191 while (gathered < requested) {
2192 while (vectorIndex < iovcnt && vectorOffset == vectors[vectorIndex].iov_len) {
2196 assert(vectorIndex < iovcnt);
2198 const size_t vectorRemaining = vectors[vectorIndex].iov_len - vectorOffset;
2199 const size_t fragment =
2200 vectorRemaining < requested - gathered ? vectorRemaining : requested - gathered;
2201 const void* userSource =
reinterpret_cast<const void*
>(
2202 reinterpret_cast<uintptr_t
>(vectors[vectorIndex].iov_base) + vectorOffset);
2204 thread->clearInterruption();
2206 return static_cast<ssize_t
>(totalWritten);
2208 SYSCALL_ERROR(BadAddress);
2211 gathered += fragment;
2212 vectorOffset += fragment;
2215 if (thread->getInterruptionReason() == Thread::InterruptedBySignal) {
2216 thread->clearInterruption();
2218 return static_cast<ssize_t
>(totalWritten);
2220 SYSCALL_ERROR(Interrupted);
2225 uint64_t location = startingOffset + totalWritten;
2226 const uint64_t amount =
2227 append ? writeGuard.append(requested,
reinterpret_cast<uintptr_t
>(bounce.get()), location,
2229 : writeGuard.write(location, requested,
reinterpret_cast<uintptr_t
>(bounce.get()),
2231 const bool signalInterrupted = thread->getInterruptionReason() == Thread::InterruptedBySignal;
2232 const size_t backendError = thread->
getErrno();
2234 thread->clearInterruption();
2235 if (!totalWritten && signalInterrupted) {
2236 SYSCALL_ERROR(Interrupted);
2241 return static_cast<ssize_t
>(totalWritten);
2247 SYSCALL_ERROR(NoMoreProcesses);
2250 return static_cast<ssize_t
>(totalWritten);
2254 totalWritten +=
static_cast<size_t>(amount);
2255 if (amount < requested || signalInterrupted ||
2256 thread->getInterruptionReason() == Thread::InterruptedBySignal) {
2257 thread->clearInterruption();
2258 return static_cast<ssize_t
>(totalWritten);
2262 thread->clearInterruption();
2263 return static_cast<ssize_t
>(totalWritten);
2267ssize_t posix_preadv(
int fd,
const struct iovec* iov,
int iovcnt, off_t offset) {
2268 F_NOTICE(
"preadv(" << fd <<
", <iov>, " << iovcnt <<
", " << offset <<
")");
2269 return positionalReadVector(fd, iov, iovcnt, offset);
2272ssize_t posix_pwritev(
int fd,
const struct iovec* iov,
int iovcnt, off_t offset) {
2273 F_NOTICE(
"pwritev(" << fd <<
", <iov>, " << iovcnt <<
", " << offset <<
")");
2274 return positionalWriteVector(fd, iov, iovcnt, offset,
false);
2277ssize_t posix_preadv2(
int fd,
const struct iovec* iov,
int iovcnt, off_t offset,
int flags) {
2278 F_NOTICE(
"preadv2(" << fd <<
", <iov>, " << iovcnt <<
", " << offset <<
", " << flags <<
")");
2280 SYSCALL_ERROR(OperationNotSupported);
2284 return posix_readv(fd, iov, iovcnt);
2286 return positionalReadVector(fd, iov, iovcnt, offset);
2289ssize_t posix_pwritev2(
int fd,
const struct iovec* iov,
int iovcnt, off_t offset,
int flags) {
2290 F_NOTICE(
"pwritev2(" << fd <<
", <iov>, " << iovcnt <<
", " << offset <<
", " << flags <<
")");
2291 if (flags & ~LinuxRwfNoAppend) {
2292 SYSCALL_ERROR(OperationNotSupported);
2296 return posixWritev(fd, iov, iovcnt, flags & LinuxRwfNoAppend);
2298 return positionalWriteVector(fd, iov, iovcnt, offset, !(flags & LinuxRwfNoAppend));
2301off_t posix_lseek(
int file, off_t ptr,
int dir) {
2302 F_NOTICE(
"lseek(" << file <<
", " << ptr <<
", " << dir <<
")");
2308 ERROR(
"No subsystem for this process!");
2315 SYSCALL_ERROR(BadFileDescriptor);
2320 if (position.statusFlags() & O_PATH) {
2321 SYSCALL_ERROR(BadFileDescriptor);
2325 if (position.isNoopSeekEndpoint()) {
2326 if (dir < SEEK_SET || dir > 4) {
2327 SYSCALL_ERROR(InvalidArgument);
2334 File* fileObject = position.file();
2335 if (fileObject && fileObject->
isSeekable()) {
2338 position.setOffset(ptr);
2341 position.advanceOffset(ptr);
2344 position.setOffset(fileObject->getSize() + ptr);
2348 return static_cast<off_t
>(position.offset());
2352 SYSCALL_ERROR(IllegalSeek);
2357 SYSCALL_ERROR(IllegalSeek);
2364int posix_link(
char* target,
char* link) {
2365 return posix_linkat(AT_FDCWD, target, AT_FDCWD, link, AT_SYMLINK_FOLLOW);
2368int posix_readlink(
const char* path,
char* buf,
unsigned int bufsize) {
2369 return posix_readlinkat(AT_FDCWD, path, buf, bufsize);
2372int posix_realpath(
const char* path,
char* buf,
size_t bufsize) {
2373 F_NOTICE(
"realpath");
2376 if (!copyUserString(path, pathCopy)) {
2377 F_NOTICE(
"realpath -> invalid address");
2381 PosixSubsystem::SafeWrite)) {
2382 F_NOTICE(
"realpath -> invalid address");
2383 SYSCALL_ERROR(BadAddress);
2388 normalisePath(realPath, pathCopy.cstr());
2389 F_NOTICE(
" -> traversing " << realPath);
2392 File* f = findFilePath(realPath, fileLease);
2394 SYSCALL_ERROR(DoesNotExist);
2398 f = traverseSymlink(f, fileLease);
2400 SYSCALL_ERROR(DoesNotExist);
2405 SYSCALL_ERROR(NotADirectory);
2410 auto context = process->acquireFilesystemContext();
2413 if (!context || !context->snapshot(snapshot) || !view ||
2414 !view->formatPath(snapshot, fileLease.path(), actualPath))
2416 if (actualPath.length() >= bufsize) {
2417 SYSCALL_ERROR(NameTooLong);
2422 F_NOTICE(
" -> returning " << actualPath);
2424 SYSCALL_ERROR(BadAddress);
2431int posix_unlink(
char* name) {
2432 return posix_unlinkat(AT_FDCWD, name, 0);
2435int posix_symlink(
char* target,
char* link) {
2436 return posix_symlinkat(target, AT_FDCWD, link);
2439int posix_rename(
const char* source,
const char* dst) {
2440 return posix_renameat(AT_FDCWD, source, AT_FDCWD, dst);
2443int posix_getcwd(
char* buf,
size_t maxlen) {
2444 F_NOTICE(
"getcwd(" << maxlen <<
")");
2448 auto context = process->acquireFilesystemContext();
2450 if (!context || !context->snapshot(snapshot) || !snapshot.cwd) {
2451 SYSCALL_ERROR(DoesNotExist);
2454 File* cwd = snapshot.cwd->node();
2456 SYSCALL_ERROR(DoesNotExist);
2461 if (!view || !view->formatPath(snapshot, snapshot.cwd, str))
2464 size_t maxLength = str.length();
2465 if (maxLength >= maxlen) {
2467 SYSCALL_ERROR(BadRange);
2471 SYSCALL_ERROR(BadAddress);
2475 F_NOTICE(
" -> " << str);
2477 return maxLength + 1;
2480int posix_stat(
const char* name,
struct stat* st) {
2481 F_NOTICE(
"stat(" << name <<
") => fstatat");
2482 return posix_fstatat(AT_FDCWD, name, st, 0);
2485int posix_fstat(
int fd,
struct stat* st) {
2486 F_NOTICE(
"fstat(" << fd <<
") => fstatat");
2487 return posix_fstatat(fd, 0, st, AT_EMPTY_PATH);
2490int posix_lstat(
char* name,
struct stat* st) {
2491 F_NOTICE(
"lstat(" << name <<
") => fstatat");
2492 return posix_fstatat(AT_FDCWD, name, st, AT_SYMLINK_NOFOLLOW);
2495static int getdents_common(
int fd,
2497 void* buffer,
int count) {
2502 ERROR(
"No subsystem for this process!");
2509 F_NOTICE(
" -> bad file");
2510 SYSCALL_ERROR(BadFileDescriptor);
2515 SYSCALL_ERROR(BadFileDescriptor);
2520 F_NOTICE(
" -> not a directory");
2521 SYSCALL_ERROR(NotADirectory);
2526 F_NOTICE(
" -> count is zero");
2530 const size_t capacity =
static_cast<size_t>(count) < 65536 ? count : 65536;
2533 SYSCALL_ERROR(OutOfMemory);
2545 } context = {set_dent, entries.get(), capacity, 0,
false};
2548 Context* context =
reinterpret_cast<Context*
>(opaque);
2549 F_NOTICE(
" -> " << entry.name.toString());
2550 size_t reclen = context->setDent(entry, context->buffer, context->available - context->written);
2552 context->rejected =
true;
2555 context->buffer = adjust_pointer(context->buffer, reclen);
2556 context->written += reclen;
2561 uint64_t cookie = position.offset();
2562 Directory::ReadStatus status = pDirectory->
enumerate(cookie, emitter, &context);
2564 if (status == Directory::ReadStatus::IoError && !context.written) {
2565 SYSCALL_ERROR(IoError);
2568 if (status == Directory::ReadStatus::Stopped && context.rejected && !context.written) {
2569 SYSCALL_ERROR(InvalidArgument);
2573 SYSCALL_ERROR(BadAddress);
2576 position.setOffset(cookie);
2578 F_NOTICE(
" -> " << context.written);
2579 return context.written;
2582static char getdentsType(Directory::EntryType type) {
2584 case Directory::EntryType::Directory:
2586 case Directory::EntryType::Symlink:
2588 case Directory::EntryType::Fifo:
2590 case Directory::EntryType::Socket:
2592 case Directory::EntryType::CharacterDevice:
2594 case Directory::EntryType::BlockDevice:
2596 case Directory::EntryType::Regular:
2598 case Directory::EntryType::Unknown:
2607 char* char_buffer =
reinterpret_cast<char*
>(buffer);
2609 size_t filenameLength = file.name.length();
2611 size_t reclen = (offsetof(
struct linux_dirent, d_name) + filenameLength + 2 +
sizeof(long) - 1) &
2612 ~(
sizeof(long) - 1);
2614 if (avail < reclen) {
2619 ByteSet(entry, 0, reclen);
2620 entry->d_reclen = reclen;
2621 entry->d_off = file.nextCookie;
2623 entry->d_ino = file.inode;
2624 if (!entry->d_ino) {
2628 MemoryCopy(entry->d_name, file.name.str(), filenameLength);
2629 entry->d_name[filenameLength] = 0;
2630 char_buffer[reclen - 2] = 0;
2631 char_buffer[reclen - 1] = getdentsType(file.type);
2638 struct dirent* entry =
reinterpret_cast<struct dirent*
>(buffer);
2640 size_t filenameLength = file.name.length();
2641 size_t reclen = (offsetof(
struct dirent, d_name) + filenameLength + 1 +
sizeof(uint64_t) - 1) &
2642 ~(
sizeof(uint64_t) - 1);
2644 if (avail < reclen) {
2649 ByteSet(entry, 0, reclen);
2650 entry->d_reclen = reclen;
2651 entry->d_off = file.nextCookie;
2653 entry->d_ino = file.inode;
2654 if (!entry->d_ino) {
2658 MemoryCopy(entry->d_name, file.name.str(), filenameLength);
2659 entry->d_name[filenameLength] = 0;
2660 entry->d_type = getdentsType(file.type);
2665int posix_getdents(
int fd,
struct linux_dirent* ents,
int count) {
2666 F_NOTICE(
"getdents(" << fd <<
")");
2668 SYSCALL_ERROR(InvalidArgument);
2672 PosixSubsystem::SafeWrite)) {
2673 F_NOTICE(
"getdents -> invalid address");
2674 SYSCALL_ERROR(BadAddress);
2678 return getdents_common(fd, getdents_helper, ents, count);
2681int posix_getdents64(
int fd,
struct dirent* ents,
int count) {
2682 F_NOTICE(
"getdents64(" << fd <<
")");
2684 SYSCALL_ERROR(InvalidArgument);
2688 PosixSubsystem::SafeWrite)) {
2689 F_NOTICE(
"getdents64 -> invalid address");
2690 SYSCALL_ERROR(BadAddress);
2694 return getdents_common(fd, getdents64_helper, ents, count);
2697template <
typename T>
2698static bool copyIoctlInput(
const void* buffer, T& value) {
2700 SYSCALL_ERROR(BadAddress);
2706template <
typename T>
2707static int copyIoctlResult(
void* buffer,
const T& value) {
2709 SYSCALL_ERROR(BadAddress);
2715int posix_ioctl(
int fd,
size_t command,
void* buf) {
2716 F_NOTICE(
"ioctl(" <<
Dec << fd <<
", " <<
Hex << command <<
", "
2717 <<
reinterpret_cast<uintptr_t
>(buf) <<
")");
2722 ERROR(
"No subsystem for this process!");
2729 F_NOTICE(
" -> ioctl for a file that doesn't exist");
2730 SYSCALL_ERROR(BadFileDescriptor);
2735 SYSCALL_ERROR(BadFileDescriptor);
2739 if (command == FIOCLEX || command == FIONCLEX) {
2745 const bool terminalPolicyCommand =
2746 command == TIOCSCTTY || command == TIOCGPGRP || command == TIOCSPGRP || command == TIOCGSID;
2747 if (!terminalPolicyCommand && !f->acquireTerminalOperation(terminalOperation)) {
2748 SYSCALL_ERROR(IoError);
2752 if (command == FIONBIO) {
2754 if (!copyIoctlInput(buf, enabled)) {
2764 auto fanotify = f->getFanotifyImpl();
2765 if (fanotify && command == FIONREAD)
2766 return copyIoctlResult(buf, fanotify->queuedMetadataBytes());
2767 if (f->getTimerFdImpl() || f->getSignalFdImpl() || fanotify) {
2768 SYSCALL_ERROR(NotAConsole);
2773 return posix_network_ioctl(*f->
networkImpl, command,
reinterpret_cast<uintptr_t
>(buf));
2775 if (!f->getFile()) {
2776 F_NOTICE(
" -> fd " << fd <<
" is not supposed to be ioctl'd");
2777 SYSCALL_ERROR(InvalidArgument);
2781 size_t terminalNumber = ~size_t(0);
2782 if ((command & 0xff00) == 0x5600 || command == 0x4b3a || command == 0x4b3b) {
2783 if (ConsoleManager::instance().isConsole(f->getFile())) {
2784 terminalNumber =
static_cast<ConsoleFile*
>(f->getFile())->getPhysicalConsoleNumber();
2786 if (!g_pDevFs->getTerminalManager().isTerminal(terminalNumber)) {
2787 SYSCALL_ERROR(NotAConsole);
2792 if (f->getFile()->
supports(command)) {
2793 return f->getFile()->
command(command, buf);
2799 if (f->getFile()->
isPipe() || f->getFile()->
isFifo()) {
2801 }
else if (ConsoleManager::instance().isConsole(f->getFile())) {
2802 auto* console =
static_cast<ConsoleFile*
>(f->getFile());
2803 available =
static_cast<int>(console->readableBytes(*f->terminalEpoch()));
2805 SYSCALL_ERROR(NotAConsole);
2808 F_NOTICE(
" -> FIONREAD: " <<
Dec << available <<
" bytes");
2809 return copyIoctlResult(buf, available);
2814 F_NOTICE(
" -> KDGETLED, arg=" << buf);
2816 return copyIoctlResult(buf, state);
2822 F_NOTICE(
" -> KDSETLED, arg=" << buf);
2823 uintptr_t leds =
reinterpret_cast<uintptr_t
>(buf);
2830 F_NOTICE(
" -> KDGKBTYPE");
2831 if (ConsoleManager::instance().isConsole(f->getFile())) {
2833 return copyIoctlResult(buf,
static_cast<unsigned char>(0x02));
2835 SYSCALL_ERROR(NotAConsole);
2842 const uintptr_t mode =
reinterpret_cast<uintptr_t
>(buf);
2844 SYSCALL_ERROR(InvalidArgument);
2847 g_pDevFs->getTerminalManager().setSystemMode(
2854 const int mode = g_pDevFs->getTerminalManager().getSystemMode(terminalNumber) ==
2855 VirtualTerminalManager::Graphics
2858 return copyIoctlResult(buf, mode);
2863 F_NOTICE(
" -> KDGKBMODE (stubbed), arg=" << buf);
2868 F_NOTICE(
" -> KDSKBMODE, arg=" << buf);
2870 size_t consoleNumber = 0;
2871 if (ConsoleManager::instance().isConsole(f->getFile())) {
2873 consoleNumber = pConsole->getPhysicalConsoleNumber();
2874 if (consoleNumber == ~0U) {
2875 ERROR(
"KDSKBMODE used on something that is not a VT");
2879 SYSCALL_ERROR(NotAConsole);
2883 long mode =
reinterpret_cast<long>(buf);
2885 g_pDevFs->getTerminalManager().setInputMode(consoleNumber, TextIO::Raw);
2887 g_pDevFs->getTerminalManager().setInputMode(consoleNumber, TextIO::Standard);
2894 F_NOTICE(
" -> KDGKBENT, arg=" << buf);
2895 POSIX_VERBOSE_LOG(
"io",
" -> KDGKBENT, arg=" << buf);
2897 struct kbentry entryCopy = {};
2898 if (!copyIoctlInput(buf, entryCopy)) {
2901 struct kbentry* kbent = &entryCopy;
2902 bool shift = kbent->kb_table & 0x1;
2903 bool altgr = kbent->kb_table & 0x2;
2904 bool ctrl = kbent->kb_table & 0x4;
2905 bool alt = kbent->kb_table & 0x8;
2908 KeymapManager::EscapeState escape = KeymapManager::EscapeNone;
2914 F_NOTICE(
" -> no keymap entry for table #" <<
Dec << kbent->kb_table <<
" index #" <<
Hex
2915 << kbent->kb_index);
2916 kbent->kb_value = 0xF000 |
static_cast<uint16_t
>(entry->value & 0xFFFF);
2918 kbent->kb_value = 0;
2921 POSIX_VERBOSE_LOG(
"io",
" -> val for table #" <<
Dec << kbent->kb_table <<
" #" <<
Hex
2922 << kbent->kb_index <<
" is now "
2923 << kbent->kb_value <<
"!");
2924 return copyIoctlResult(buf, entryCopy);
2930 F_NOTICE(
" -> KDSKBENT (stubbed), arg=" << buf);
2931 POSIX_VERBOSE_LOG(
"io",
" -> KDSKBENT (stubbed), arg=" << buf);
2936 F_NOTICE(
" -> KDKBDREP (stubbed), arg=" << buf);
2940 if (ConsoleManager::instance().isConsole(f->getFile())) {
2941 return console_tcgetattr(f,
reinterpret_cast<struct termios*
>(buf));
2943 SYSCALL_ERROR(NotAConsole);
2949 if (ConsoleManager::instance().isConsole(f->getFile())) {
2950 return console_tcsetattr(f, TCSANOW,
reinterpret_cast<struct termios*
>(buf));
2952 SYSCALL_ERROR(NotAConsole);
2958 if (ConsoleManager::instance().isConsole(f->getFile())) {
2959 return console_tcsetattr(f, TCSADRAIN,
reinterpret_cast<struct termios*
>(buf));
2961 SYSCALL_ERROR(NotAConsole);
2967 if (ConsoleManager::instance().isConsole(f->getFile())) {
2968 return console_tcsetattr(f, TCSAFLUSH,
reinterpret_cast<struct termios*
>(buf));
2970 SYSCALL_ERROR(NotAConsole);
2976 if (ConsoleManager::instance().isConsole(f->getFile())) {
2977 pid_t pgrp = TerminalControl::foreground(*
static_cast<ConsoleFile*
>(f->getFile()),
2978 f->terminalEpoch());
2979 return pgrp < 0 ? -1 : copyIoctlResult(buf, pgrp);
2981 SYSCALL_ERROR(NotAConsole);
2987 if (ConsoleManager::instance().isConsole(f->getFile())) {
2989 return copyIoctlInput(buf, pgrp)
2990 ? TerminalControl::setForeground(*
static_cast<ConsoleFile*
>(f->getFile()), pgrp,
2994 SYSCALL_ERROR(NotAConsole);
3000 if (ConsoleManager::instance().isConsole(f->getFile())) {
3001 const pid_t session =
3002 TerminalControl::session(*
static_cast<ConsoleFile*
>(f->getFile()), f->terminalEpoch());
3003 return session < 0 ? -1 : copyIoctlResult(buf, session);
3005 SYSCALL_ERROR(NotAConsole);
3011 if (ConsoleManager::instance().isConsole(f->getFile())) {
3012 return console_flush(f->getFile(),
static_cast<int>(
reinterpret_cast<uintptr_t
>(buf)));
3014 SYSCALL_ERROR(NotAConsole);
3020 if (ConsoleManager::instance().isConsole(f->getFile())) {
3021 F_NOTICE(
" -> TIOCGWINSZ");
3022 struct winsize value = {};
3023 const int result = console_getwinsize(f->getFile(), &value);
3024 return result < 0 ? result : copyIoctlResult(buf, value);
3026 SYSCALL_ERROR(NotAConsole);
3032 if (ConsoleManager::instance().isConsole(f->getFile())) {
3033 struct winsize value = {};
3034 if (!copyIoctlInput(buf, value)) {
3037 const struct winsize* ws = &value;
3038 F_NOTICE(
" -> TIOCSWINSZ " <<
Dec << ws->ws_col <<
"x" << ws->ws_row <<
Hex);
3039 return console_setwinsize(f->getFile(), ws);
3041 SYSCALL_ERROR(NotAConsole);
3047 if (ConsoleManager::instance().isConsole(f->getFile())) {
3048 F_NOTICE(
" -> TIOCSCTTY");
3049 return TerminalControl::attach(*
static_cast<ConsoleFile*
>(f->getFile()),
3050 reinterpret_cast<uintptr_t
>(buf) == 1,
false,
3051 f->terminalEpoch());
3053 SYSCALL_ERROR(NotAConsole);
3059 F_NOTICE(
" -> TIOCGPTN");
3060 unsigned int result = console_getptn(fd);
3062 F_NOTICE(
" -> ok, returning " << result);
3064 SYSCALL_ERROR(BadAddress);
3070 F_NOTICE(
" -> failed!");
3076 if (ConsoleManager::instance().isConsole(f->getFile()) &&
3077 ConsoleManager::instance().isMasterConsole(f->getFile())) {
3079 if (!copyIoctlInput(buf, locked)) {
3082 if (locked != 0 && locked != 1) {
3083 SYSCALL_ERROR(InvalidArgument);
3086 F_NOTICE(
" -> TIOCSPTLCK " << locked);
3087 return ConsoleManager::instance().
setPtyLock(f->getFile(), locked != 0) ? 0 : -1;
3089 SYSCALL_ERROR(NotAConsole);
3095 F_NOTICE(
" -> VT_OPENQRY (stubbed)");
3097 size_t newTty = g_pDevFs->getTerminalManager().
openInactive();
3098 const int result = newTty != ~size_t(0) ?
static_cast<int>(newTty + 1) : -1;
3099 return copyIoctlResult(buf, result);
3104 return copyIoctlResult(buf, g_pDevFs->getTerminalManager().getTerminalMode(terminalNumber));
3109 if (!copyIoctlInput(buf, mode)) {
3112 if (!g_pDevFs->getTerminalManager().setTerminalMode(terminalNumber, mode)) {
3113 SYSCALL_ERROR(InvalidArgument);
3121 F_NOTICE(
" -> VT_GETSTATE (stubbed)");
3123 return copyIoctlResult(buf, g_pDevFs->getTerminalManager().getState());
3129 const uintptr_t permission =
reinterpret_cast<uintptr_t
>(buf);
3130 auto& terminals = g_pDevFs->getTerminalManager();
3131 const bool accepted =
3132 permission == VT_ACKACQ
3133 ? terminals.acknowledgeAcquire(terminalNumber)
3134 : permission <= 1 &&
3135 terminals.reportPermission(terminalNumber,
3136 permission ? VirtualTerminalManager::Allowed
3139 SYSCALL_ERROR(InvalidArgument);
3147 const uintptr_t ttyNum =
reinterpret_cast<uintptr_t
>(buf);
3148 if (!ttyNum || !g_pDevFs->getTerminalManager().
activate(ttyNum - 1)) {
3149 SYSCALL_ERROR(InvalidArgument);
3161 F_NOTICE(
" -> invalid combination of fd " << fd <<
" and ioctl " <<
Hex << command);
3162 SYSCALL_ERROR(InvalidArgument);
3166int posix_chdir(
const char* path) {
3170 if (!copyUserString(path, pathCopy)) {
3171 F_NOTICE(
"chdir -> invalid address");
3175 F_NOTICE(
"chdir(" << pathCopy <<
")");
3178 normalisePath(realPath, pathCopy.cstr());
3181 File* dir = findFilePath(realPath, dirLease);
3183 F_NOTICE(
"Path lookup failed.");
3185 SYSCALL_ERROR(DoesNotExist);
3189 return doChdir(dir, dirLease) ? 0 : -1;
3192int posix_dup(
int fd) {
3193 F_NOTICE(
"dup(" << fd <<
")");
3199 ERROR(
"No subsystem for this process!");
3205 SYSCALL_ERROR(BadFileDescriptor);
3209 size_t newFd = pSubsystem->
getFd();
3215 (f->getTimerFdImpl() && !f2->timerFdPublished()) ||
3216 (f->getSignalFdImpl() && !f2->signalFdPublished())) {
3218 pSubsystem->
freeFd(newFd);
3219 SYSCALL_ERROR(BadFileDescriptor);
3227 return static_cast<int>(newFd);
3230int posix_dup2(
int fd1,
int fd2) {
3231 F_NOTICE(
"dup2(" << fd1 <<
", " << fd2 <<
")");
3233 constexpr int MaximumFileDescriptors = 16384;
3234 if (fd2 < 0 || fd2 >= MaximumFileDescriptors) {
3235 SYSCALL_ERROR(BadFileDescriptor);
3243 ERROR(
"No subsystem for this process!");
3249 SYSCALL_ERROR(BadFileDescriptor);
3265 (f->getTimerFdImpl() && !f2->timerFdPublished()) ||
3266 (f->getSignalFdImpl() && !f2->signalFdPublished())) {
3268 SYSCALL_ERROR(BadFileDescriptor);
3279int posix_dup3(
int oldfd,
int newfd,
int flags) {
3280 F_NOTICE(
"dup3(" << oldfd <<
", " << newfd <<
", " << flags <<
")");
3282 if (flags & ~O_CLOEXEC || oldfd == newfd) {
3283 SYSCALL_ERROR(InvalidArgument);
3287 constexpr int MaximumFileDescriptors = 16384;
3288 if (newfd < 0 || newfd >= MaximumFileDescriptors) {
3289 SYSCALL_ERROR(BadFileDescriptor);
3296 ERROR(
"No subsystem for this process!");
3301 static_cast<size_t>(oldfd),
static_cast<size_t>(newfd), flags & O_CLOEXEC);
3302 if (result == PosixSubsystem::DescriptorDuplicationResult::TargetBusy) {
3303 SYSCALL_ERROR(DeviceBusy);
3306 if (result != PosixSubsystem::DescriptorDuplicationResult::Success) {
3307 SYSCALL_ERROR(BadFileDescriptor);
3314int posix_mkdir(
const char* name,
int mode) {
3315 return posix_mkdirat(AT_FDCWD, name, mode);
3318int posix_rmdir(
const char* path) {
3319 return posix_unlinkat(AT_FDCWD, path, AT_REMOVEDIR);
3322int posix_isatty(
int fd) {
3327 ERROR(
"No subsystem for this process!");
3334 ERROR(
"isatty: no such file descriptor (" <<
Dec << fd <<
Hex <<
")");
3339 ConsoleManager::instance().isConsole(pFd->getFile()) && !pFd->terminalHungUp() ? 1 : 0;
3340 NOTICE(
"isatty(" << fd <<
") -> " << result);
3344int posix_fcntl(
int fd,
int cmd,
void* arg) {
3346 F_NOTICE(
"fcntl(" << fd <<
", " <<
cmd <<
", " << arg <<
")");
3353 ERROR(
"No subsystem for this process!");
3359 SYSCALL_ERROR(BadFileDescriptor);
3364 cmd != F_DUPFD &&
cmd != F_DUPFD_CLOEXEC) {
3365 SYSCALL_ERROR(BadFileDescriptor);
3370#ifdef F_DUPFD_CLOEXEC
3371 case F_DUPFD_CLOEXEC:
3374 constexpr intptr_t MaximumFileDescriptors = 16384;
3375 const intptr_t minimum =
reinterpret_cast<intptr_t
>(arg);
3376 if (minimum < 0 || minimum >= MaximumFileDescriptors) {
3377 SYSCALL_ERROR(InvalidArgument);
3381 const size_t fd2 = pSubsystem->
getFd(
static_cast<size_t>(minimum));
3385 (f->getTimerFdImpl() && !f2->timerFdPublished()) ||
3386 (f->getSignalFdImpl() && !f2->signalFdPublished())) {
3389 SYSCALL_ERROR(BadFileDescriptor);
3392#ifdef F_DUPFD_CLOEXEC
3393 if (
cmd == F_DUPFD_CLOEXEC) {
3403 return static_cast<int>(fd2);
3407 F_NOTICE(
" -> get fd flags");
3410 F_NOTICE(
" -> set fd flags: " << arg);
3411 f->
fdflags =
reinterpret_cast<size_t>(arg);
3417 F_NOTICE(
" -> set flags " << arg);
3423 return posix_memfd_fcntl(f,
cmd,
reinterpret_cast<uintptr_t
>(arg));
3430 return posix_advisory_fcntl(*pSubsystem, fd, f,
cmd, arg);
3432 F_NOTICE(
" -> F_GETOWN (stubbed)");
3436 F_NOTICE(
" -> F_SETOWN");
3440 NOTICE(
"Adding ioevent to thread");
3445 ERROR(
"F_SETOWN on something that can't raise events [fd="
3446 << fd <<
" file=" << f->getFile() <<
" impl=" << f->
networkImpl.
get() <<
"!");
3453 WARNING(
"fcntl: unknown control " <<
cmd <<
" on fd " << fd);
3456 SYSCALL_ERROR(Unimplemented);
3460void* posix_mmap(
void* addr,
size_t len,
int prot,
int flags,
int fd, off_t off) {
3463 F_NOTICE(
" -> addr=" << addr <<
", len=" << len <<
", prot=" << prot <<
", flags=" << flags
3464 <<
", fildes=" << fd <<
", off=" << off <<
".");
3470 ERROR(
"No subsystem for this process!");
3476 const uintptr_t pageMask = pageSz - 1;
3477 const bool fixedNoReplace = flags & MAP_FIXED_NOREPLACE;
3478 const bool fixed = fixedNoReplace || (flags & MAP_FIXED);
3479 const MemoryMapManager::Placement placement =
3481 ? MemoryMapManager::Placement::FixedNoReplace
3482 : (fixed ? MemoryMapManager::Placement::FixedReplace : MemoryMapManager::Placement::Hint);
3485 const int mappingType = flags & (MAP_PRIVATE | MAP_SHARED);
3486 if ((prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC)) ||
3487 (mappingType != MAP_PRIVATE && mappingType != MAP_SHARED) || !len ||
3488 len > ~static_cast<size_t>(0) - pageMask ||
3489 (!(flags & MAP_ANON) && (off < 0 || (
static_cast<uint64_t
>(off) & pageMask)))) {
3490 SYSCALL_ERROR(InvalidArgument);
3493 const size_t roundedLength = (len + pageMask) & ~pageMask;
3494 if (!(flags & MAP_ANON) &&
static_cast<uint64_t
>(off) > ~
static_cast<size_t>(0) - roundedLength) {
3495 SYSCALL_ERROR(InvalidArgument);
3498#if PEDIGREE_BENCHMARK_VM_DIAGNOSTICS
3499 pProcess->recordBenchmarkVmCounter(Process::VmMmapCalls);
3500 pProcess->recordBenchmarkVmCounter(flags & MAP_ANON ? Process::VmMmapAnonymousCalls
3502 const size_t mappingPages = roundedLength / pageSz;
3503 pProcess->recordBenchmarkVmCounter(Process::VmMmapPages, mappingPages);
3504 pProcess->recordBenchmarkVmCounter(vmLengthCounter(
false, mappingPages));
3508 uintptr_t sanityAddress =
reinterpret_cast<uintptr_t
>(addr);
3510 if ((sanityAddress & pageMask) || sanityAddress < va.
getUserStart() ||
3513 SYSCALL_ERROR(InvalidArgument);
3514 F_NOTICE(
" -> mmap given invalid fixed address");
3517 }
else if (sanityAddress) {
3518 sanityAddress &= ~pageMask;
3526 MemoryMapManager::MapStatus mapStatus = MemoryMapManager::MapStatus::NoMemory;
3527 const MemoryLockMode requestedLock =
3528 flags & MAP_LOCKED ? MemoryLockMode::Eager : MemoryLockMode::None;
3529 if (requestedLock != MemoryLockMode::None) {
3531 if (!posix_global_capable(14) && !pSubsystem->memoryLockAccount().limit().current) {
3532 SYSCALL_ERROR(NotEnoughPermissions);
3539 if (prot == PROT_NONE) {
3540 perms = MemoryMappedObject::None;
3543 perms = MemoryMappedObject::Read;
3544 if (prot & PROT_WRITE)
3545 perms |= MemoryMappedObject::Write;
3546 if (prot & PROT_EXEC)
3547 perms |= MemoryMappedObject::Exec;
3550 if (flags & MAP_ANON) {
3551 if (flags & MAP_SHARED) {
3552 F_NOTICE(
" -> failed (MAP_SHARED cannot be used with MAP_ANONYMOUS)");
3553 SYSCALL_ERROR(InvalidArgument);
3558 sanityAddress, len, perms, placement, &mapStatus, requestedLock);
3560 if (mapStatus == MemoryMapManager::MapStatus::AddressInUse) {
3561 SYSCALL_ERROR(FileExists);
3562 }
else if (mapStatus == MemoryMapManager::MapStatus::LockLimit) {
3563 SYSCALL_ERROR(NoMoreProcesses);
3565 SYSCALL_ERROR(OutOfMemory);
3567 F_NOTICE(
" -> failed (mapAnon)!");
3571 F_NOTICE(
" -> " << sanityAddress);
3573 if ((flags & MAP_POPULATE) && !(flags & MAP_NONBLOCK)) {
3577 return reinterpret_cast<void*
>(sanityAddress);
3582 SYSCALL_ERROR(BadFileDescriptor);
3587 File* fileToMap = f->getFile();
3590 posix_uts_file_namespace(fileToMap, namespaceBacking)) {
3591 SYSCALL_ERROR(NoSuchDevice);
3596 const int accessMode = descriptorFlags & O_ACCMODE;
3597 if (descriptorFlags & O_PATH) {
3598 SYSCALL_ERROR(BadFileDescriptor);
3601 if (accessMode == O_WRONLY) {
3602 SYSCALL_ERROR(PermissionDenied);
3606 MemoryMappedObject::Read | MemoryMappedObject::Write | MemoryMappedObject::Exec;
3607 if ((flags & MAP_SHARED) && accessMode != O_RDWR) {
3609 if (prot & PROT_WRITE) {
3610 SYSCALL_ERROR(PermissionDenied);
3615 auto* view = VfsMountView::fromPath(f->openingPath());
3616 const auto mountFlags = view ? view->mountFlags(f->openingPath()) : 0;
3617 if (mountFlags & VfsMountView::NoExec) {
3619 if (prot & PROT_EXEC) {
3620 SYSCALL_ERROR(NotEnoughPermissions);
3624 if ((flags & MAP_SHARED) && (mountFlags & VfsMountView::ReadOnly) &&
3627 if (prot & PROT_WRITE) {
3628 SYSCALL_ERROR(PermissionDenied);
3633 F_NOTICE(
"mmap: file name is " << fileToMap->
getFullPath());
3635 bool bCopyOnWrite = (flags & MAP_SHARED) == 0;
3637 accessMode == O_RDWR, f->openingPath()};
3639 fileToMap, sanityAddress, roundedLength, perms, off, bCopyOnWrite, placement, &mapStatus,
3642 if (mapStatus == MemoryMapManager::MapStatus::AddressInUse) {
3643 SYSCALL_ERROR(FileExists);
3644 }
else if (mapStatus == MemoryMapManager::MapStatus::PolicyDenied) {
3645 SYSCALL_ERROR(NotEnoughPermissions);
3646 }
else if (mapStatus == MemoryMapManager::MapStatus::TextBusy) {
3647 SYSCALL_ERROR(TextFileBusy);
3648 }
else if (mapStatus == MemoryMapManager::MapStatus::LockLimit) {
3649 SYSCALL_ERROR(NoMoreProcesses);
3651 SYSCALL_ERROR(OutOfMemory);
3653 F_NOTICE(
" -> failed (mapFile)!");
3657 F_NOTICE(
" -> " << sanityAddress);
3659 if ((flags & MAP_POPULATE) && !(flags & MAP_NONBLOCK)) {
3663 return reinterpret_cast<void*
>(sanityAddress);
3667int posix_msync(
void* p,
size_t len,
int flags) {
3668 const uintptr_t address =
reinterpret_cast<uintptr_t
>(p);
3670 if ((address & pageMask) || (flags & ~(MS_ASYNC | MS_INVALIDATE | MS_SYNC)) ||
3671 ((flags & MS_ASYNC) && (flags & MS_SYNC))) {
3672 SYSCALL_ERROR(InvalidArgument);
3678 if (len > ~
static_cast<size_t>(0) - pageMask ||
3679 ((len + pageMask) & ~pageMask) > ~
static_cast<uintptr_t
>(0) - address) {
3680 SYSCALL_ERROR(OutOfMemory);
3687 (len + pageMask) & ~pageMask)) {
3688 SYSCALL_ERROR(DeviceBusy);
3692 syscallError(error);
3698int posix_mprotect(
void* p,
size_t len,
int prot) {
3699 const uintptr_t address =
reinterpret_cast<uintptr_t
>(p);
3701 if ((address & pageMask) || (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC))) {
3702 SYSCALL_ERROR(InvalidArgument);
3709 if (prot != PROT_NONE) {
3710 permissions = MemoryMappedObject::Read;
3711 if (prot & PROT_WRITE) {
3712 permissions |= MemoryMappedObject::Write;
3714 if (prot & PROT_EXEC) {
3715 permissions |= MemoryMappedObject::Exec;
3720 if (status == MemoryMapManager::ProtectStatus::AccessDenied) {
3721 SYSCALL_ERROR(PermissionDenied);
3722 }
else if (status == MemoryMapManager::ProtectStatus::Unsupported) {
3723 SYSCALL_ERROR(OperationNotSupported);
3724 }
else if (status == MemoryMapManager::ProtectStatus::TextBusy) {
3725 SYSCALL_ERROR(TextFileBusy);
3727 SYSCALL_ERROR(OutOfMemory);
3734int posix_munmap(
void* addr,
size_t len) {
3735 F_NOTICE(
"munmap(" <<
reinterpret_cast<uintptr_t
>(addr) <<
", " << len <<
")");
3737 const uintptr_t address =
reinterpret_cast<uintptr_t
>(addr);
3739 const size_t pageMask = pageSz - 1;
3740 if (!len || (address & pageMask) || len > ~
static_cast<size_t>(0) - pageMask) {
3741 SYSCALL_ERROR(InvalidArgument);
3744 const size_t roundedLength = (len + pageMask) & ~pageMask;
3745 if (address > ~
static_cast<uintptr_t
>(0) - roundedLength) {
3746 SYSCALL_ERROR(InvalidArgument);
3750#if PEDIGREE_BENCHMARK_VM_DIAGNOSTICS
3752 const size_t mappingPages = roundedLength / pageSz;
3753 process->recordBenchmarkVmCounter(Process::VmMunmapCalls);
3754 process->recordBenchmarkVmCounter(Process::VmMunmapPages, mappingPages);
3755 process->recordBenchmarkVmCounter(vmLengthCounter(
true, mappingPages));
3758 MemoryMapManager::VmStatus status;
3760 if (status != MemoryMapManager::VmStatus::Success) {
3761 if (status == MemoryMapManager::VmStatus::Unsupported)
3762 SYSCALL_ERROR(OperationNotSupported);
3764 SYSCALL_ERROR(OutOfMemory);
3771int posix_access(
const char* name,
int amode) {
3772 return posix_faccessat(AT_FDCWD, name, amode, 0);
3775int posix_ftruncate(
int a, off_t b) {
3776 F_NOTICE(
"ftruncate(" << a <<
", " << b <<
")");
3779 SYSCALL_ERROR(InvalidArgument);
3787 ERROR(
"No subsystem for this process!");
3794 SYSCALL_ERROR(BadFileDescriptor);
3798 SYSCALL_ERROR(BadFileDescriptor);
3803 !pFd->getFile()->isBlockDevice() && !mountWrite.acquire(pFd->openingPath())) {
3806 File* pFile = pFd->getFile();
3808 SYSCALL_ERROR(InvalidArgument);
3812 SYSCALL_ERROR(InvalidArgument);
3815 if (!pFd->truncateAllowed()) {
3816 SYSCALL_ERROR(PermissionDenied);
3819 return pFile->
resize(
static_cast<size_t>(b)) ? 0 : -1;
3822int posix_fsync(
int fd) {
3823 F_NOTICE(
"fsync(" << fd <<
")");
3829 ERROR(
"No subsystem for this process!");
3836 SYSCALL_ERROR(BadFileDescriptor);
3840 SYSCALL_ERROR(BadFileDescriptor);
3844 File* pFile = pFd->getFile();
3846 SYSCALL_ERROR(InvalidArgument);
3849 if (!pFile->
sync()) {
3850 SYSCALL_ERROR(IoError);
3857EXPORTED_PUBLIC
int pedigree_get_mount(
char* mount_buf,
char* info_buf,
size_t n) {
3859 PosixSubsystem::SafeWrite) &&
3861 PosixSubsystem::SafeWrite))) {
3862 F_NOTICE(
"pedigree_get_mount -> invalid address");
3863 SYSCALL_ERROR(BadAddress);
3867 NOTICE(
"pedigree_get_mount(" <<
Dec << n <<
Hex <<
")");
3873 for (
const auto& mount : mounts) {
3876 if (mount.hasDisk) {
3877 info = mount.diskParentName;
3878 if (info.length() && mount.diskName.length()) {
3881 info += mount.diskName;
3883 info.assign(
"no disk", 8);
3888 SYSCALL_ERROR(BadAddress);
3900int posix_chmod(
const char* path, mode_t mode) {
3901 return posix_fchmodat(AT_FDCWD, path, mode, 0);
3904int posix_chown(
const char* path, uid_t owner, gid_t group) {
3905 return posix_fchownat(AT_FDCWD, path, owner, group, 0);
3908int posix_fchmod(
int fd, mode_t mode) {
3910 if (!acquireDescriptor(fd, descriptor) || !descriptor->getFile() ||
3912 SYSCALL_ERROR(BadFileDescriptor);
3915 if (mode ==
static_cast<mode_t
>(-1)) {
3916 SYSCALL_ERROR(InvalidArgument);
3920 if (descriptor->openingPath() && !mountWrite.acquire(descriptor->openingPath())) {
3923 File* file = descriptor->getFile();
3924 if (file->getFilesystem() && file->getFilesystem()->
isReadOnly()) {
3925 SYSCALL_ERROR(ReadOnlyFilesystem);
3928 return posix_chmod_file(file, mode) ? 0 : -1;
3931int posix_fchown(
int fd, uid_t owner, gid_t group) {
3933 if (!acquireDescriptor(fd, descriptor) || !descriptor->getFile() ||
3935 SYSCALL_ERROR(BadFileDescriptor);
3939 if (descriptor->openingPath() && !mountWrite.acquire(descriptor->openingPath())) {
3942 File* file = descriptor->getFile();
3943 if (file->getFilesystem() && file->getFilesystem()->
isReadOnly()) {
3944 SYSCALL_ERROR(ReadOnlyFilesystem);
3947 return posix_chown_file(file, owner, group) ? 0 : -1;
3950int posix_fchdir(
int fd) {
3951 F_NOTICE(
"fchdir(" << fd <<
")");
3957 ERROR(
"No subsystem for this process!");
3965 SYSCALL_ERROR(BadFileDescriptor);
3969 File* file = pFd->getFile();
3970 targetLease.retain(pFd->openingPath());
3971 return doChdir(file, targetLease) ? 0 : -1;
3974static int statvfs_doer(
Filesystem* pFs,
struct statvfs* userBuffer,
3977 SYSCALL_ERROR(DoesNotExist);
3981 struct statvfs value = {};
3982 struct statvfs* buf = &value;
3984 buf->f_bsize = 4096;
3985 buf->f_frsize = 512;
3986 buf->f_blocks =
static_cast<fsblkcnt_t
>(-1);
3987 buf->f_bfree =
static_cast<fsblkcnt_t
>(-1);
3988 buf->f_bavail =
static_cast<fsblkcnt_t
>(-1);
3990 buf->f_ffree =
static_cast<fsfilcnt_t
>(-1);
3991 buf->f_favail =
static_cast<fsfilcnt_t
>(-1);
3993 buf->f_flag = (pFs->
isReadOnly() ? ST_RDONLY : 0) | ST_NOSUID;
3994 if (
auto* view = VfsMountView::fromPath(path)) {
3995 if (view->mountFlags(path) & VfsMountView::ReadOnly) {
3996 buf->f_flag |= ST_RDONLY;
4002 SYSCALL_ERROR(BadAddress);
4008int posix_fstatvfs(
int fd,
struct statvfs* buf) {
4010 PosixSubsystem::SafeWrite)) {
4011 F_NOTICE(
"fstatvfs -> invalid address");
4012 SYSCALL_ERROR(BadAddress);
4016 F_NOTICE(
"fstatvfs(" << fd <<
")");
4022 ERROR(
"No subsystem for this process!");
4029 SYSCALL_ERROR(BadFileDescriptor);
4033 File* file = pFd->getFile();
4036 SYSCALL_ERROR(InvalidArgument);
4040 return statvfs_doer(file->getFilesystem(), buf, pFd->openingPath());
4043int posix_statvfs(
const char* path,
struct statvfs* buf) {
4045 if (!copyUserString(path, pathCopy)) {
4046 F_NOTICE(
"statvfs -> invalid address");
4050 PosixSubsystem::SafeWrite)) {
4051 F_NOTICE(
"statvfs -> invalid address");
4052 SYSCALL_ERROR(BadAddress);
4056 F_NOTICE(
"statvfs(" << pathCopy <<
")");
4059 normalisePath(realPath, pathCopy.cstr());
4062 File* file = findFilePath(realPath, fileLease);
4064 SYSCALL_ERROR(DoesNotExist);
4069 file = traverseSymlink(file, fileLease);
4073 return statvfs_doer(file->getFilesystem(), buf, fileLease.path());
4076int posix_utime(
const char* path,
const struct utimbuf* times) {
4078 if (!copyUserString(path, pathCopy)) {
4079 F_NOTICE(
"utimes -> invalid address");
4082 struct utimbuf snapshot = {};
4084 F_NOTICE(
"utimes -> invalid address");
4085 SYSCALL_ERROR(BadAddress);
4088 if (times && (snapshot.actime < 0 || snapshot.modtime < 0 ||
4089 static_cast<uint64_t
>(snapshot.actime) > UINT32_MAX ||
4090 static_cast<uint64_t
>(snapshot.modtime) > UINT32_MAX)) {
4091 SYSCALL_ERROR(InvalidArgument);
4095 F_NOTICE(
"utime(" << pathCopy <<
")");
4098 normalisePath(realPath, pathCopy.cstr());
4101 File* file = findFilePath(realPath, fileLease);
4103 SYSCALL_ERROR(DoesNotExist);
4108 file = traverseSymlink(file, fileLease);
4118 if (fileLease.path() && !mountWrite.acquire(fileLease.path())) {
4122 Time::Timestamp accessTime;
4123 Time::Timestamp modifyTime;
4125 accessTime = snapshot.actime;
4126 modifyTime = snapshot.modtime;
4128 accessTime = modifyTime = Time::getTime();
4137int posix_utimes(
const char* path,
const struct timeval* times) {
4138 return posix_futimesat(AT_FDCWD, path, times);
4141int posix_chroot(
const char* path) {
4143 if (!posix_capable(PosixCapabilities::SysChroot)) {
4144 SYSCALL_ERROR(NotEnoughPermissions);
4148 if (!copyUserString(path, copied))
4151 normalisePath(normalised, copied.cstr());
4155 auto context = process->acquireFilesystemContext();
4157 return view && context && view->changeRoot(context, target.path()) ? 0 : -1;
4160int posix_flock(
int fd,
int operation) {
4161 F_NOTICE(
"flock(" << fd <<
", " << operation <<
")");
4163 const int lockType = operation & ~LOCK_NB;
4164 if (lockType != LOCK_SH && lockType != LOCK_EX && lockType != LOCK_UN) {
4165 SYSCALL_ERROR(InvalidArgument);
4172 ERROR(
"No subsystem for this process!");
4178 SYSCALL_ERROR(BadFileDescriptor);
4182 return posix_advisory_flock(descriptor, operation);
4188 auto* subsystem =
static_cast<PosixSubsystem*
>(process->getSubsystem());
4190 if (!subsystem || !view) {
4191 SYSCALL_ERROR(DoesNotExist);
4194 if (dirfd == AT_FDCWD) {
4195 auto context = process->acquireFilesystemContext();
4197 if (!context || !context->snapshot(snapshot) || !snapshot.cwd) {
4198 SYSCALL_ERROR(DoesNotExist);
4201 directory.retain(snapshot.cwd);
4202 return directory.get();
4205 SYSCALL_ERROR(BadFileDescriptor);
4208 File* file = descriptor->getFile();
4209 auto path = descriptor->openingPath();
4210 auto* openingView = VfsMountView::fromPath(path);
4211 if (!(flags & AT_EMPTY_PATH) &&
4212 (!file->
isDirectory() || !openingView || !openingView->attachmentId(path))) {
4213 SYSCALL_ERROR(NotADirectory);
4216 if (!path && !view->anonymousPath(file, path))
4218 directory.retain(path);
4228 if (!context || !view) {
4229 SYSCALL_ERROR(DoesNotExist);
4232 if (!view->resolveParent(context, start, pathname, parent, basename))
4234 result.retain(parent);
4241 File* anchor = check_dirfd(pathname.length() && pathname[0] ==
'/' ? AT_FDCWD : dirfd, descriptor,
4242 start, pathname.length() ? 0 : flags);
4245 if (!pathname.length()) {
4246 if (!(flags & AT_EMPTY_PATH)) {
4247 SYSCALL_ERROR(DoesNotExist);
4250 result.retain(start.path());
4254 normalisePath(normalised, pathname.cstr());
4255 return findFilePath(normalised, result, start.path(), !(flags & AT_SYMLINK_NOFOLLOW));
4258int posix_openat(
int dirfd,
const char* pathname,
int flags, mode_t mode) {
4262 if (!copyUserString(pathname, pathnameCopy)) {
4263 F_NOTICE(
"open -> invalid address");
4269 File* cwd = check_dirfd(pathnameCopy.length() && pathnameCopy[0] ==
'/' ? AT_FDCWD : dirfd,
4270 dirDescriptor, cwdLease);
4274 const bool pathOnly = flags & O_PATH;
4276 flags &= O_PATH | O_NOFOLLOW | O_DIRECTORY | O_CLOEXEC;
4278 F_NOTICE(
"openat(" << dirfd <<
", " << pathnameCopy <<
", " << flags <<
", " <<
Oct << mode
4285 F_NOTICE(
" -> No subsystem for this process!");
4290 if (!(CHECK_FLAG(flags, O_RDONLY) || CHECK_FLAG(flags, O_RDWR) || CHECK_FLAG(flags, O_WRONLY))) {
4291 F_NOTICE(
"One of O_RDONLY, O_WRONLY, or O_RDWR must be passed.");
4292 SYSCALL_ERROR(InvalidArgument);
4297 if (!pathnameCopy.length()) {
4298 F_NOTICE(
" -> File does not exist (empty path).");
4299 SYSCALL_ERROR(DoesNotExist);
4304 if (pPosixProcess) {
4305 mode &= ~pPosixProcess->getMask();
4308 size_t fd = pSubsystem->
getFd();
4313 bool openingCtty =
false;
4316 normalisePath(nameToOpen, pathnameCopy.cstr());
4317 file = findFilePath(nameToOpen, fileLease, cwdLease.path());
4319 bool bCreated =
false;
4322 if (lookupError && lookupError != Error::DoesNotExist) {
4326 if (flags & O_CREAT) {
4327 F_NOTICE(
" {O_CREAT}");
4330 bool worked = findParentPath(nameToOpen, cwdLease.path(), parent, basename) &&
4331 VFS::instance().mountView()->createFile(parent.path(), basename, mode);
4334 F_NOTICE(
" -> File does not exist (createFile failed)");
4339 file = findFilePath(basename, fileLease, parent.path());
4341 F_NOTICE(
" -> File does not exist (O_CREAT failed)");
4343 SYSCALL_ERROR(DoesNotExist);
4350 F_NOTICE(
" -> Does not exist.");
4352 SYSCALL_ERROR(DoesNotExist);
4359 F_NOTICE(
" -> File does not exist.");
4360 SYSCALL_ERROR(DoesNotExist);
4365 if (file->
isSymlink() && (flags & O_NOFOLLOW)) {
4367 SYSCALL_ERROR(LoopExists);
4372 file = traverseSymlink(file, fileLease);
4377 SYSCALL_ERROR(DoesNotExist);
4382 if ((flags & O_DIRECTORY) && !file->
isDirectory()) {
4383 SYSCALL_ERROR(NotADirectory);
4388 auto* descriptor =
new FileDescriptor(fileLease.path(), 0, fd, 0, flags);
4391 SYSCALL_ERROR(OutOfMemory);
4395 return static_cast<int>(fd);
4398 if (file->
isDirectory() && (flags & (O_WRONLY | O_RDWR))) {
4400 F_NOTICE(
" -> Is a directory, and O_WRONLY or O_RDWR was specified.");
4401 SYSCALL_ERROR(IsADirectory);
4406 if ((flags & O_CREAT) && (flags & O_EXCL) && !bCreated) {
4408 F_NOTICE(
" -> File exists");
4409 SYSCALL_ERROR(FileExists);
4414 auto* openingView = VfsMountView::fromPath(fileLease.path());
4415 const auto mountFlags = openingView ? openingView->mountFlags(fileLease.path()) : 0;
4416 if ((mountFlags & VfsMountView::NoDev) &&
4417 (file->isBlockDevice() || file->isCharacterDevice() ||
4419 file->isDirectPhysicalMapping())) {
4420 SYSCALL_ERROR(PermissionDenied);
4426 !file->isBlockDevice() && fileLease.path() &&
4427 !VfsMountView::retainWrite(fileLease.path(), mountWrite)) {
4432 bool allowTruncate =
false;
4433 if (!posix_landlock_open(fileLease.path(), flags, allowTruncate)) {
4438 if (g_pDevFs && g_pDevFs->isControllingTerminalSelector(file)) {
4440 file = pProcess->acquireCtty(cttyLease);
4443 SYSCALL_ERROR(NoSuchDevice);
4446 if (ConsoleManager::instance().isMasterConsole(file))
4447 file = ConsoleManager::instance().getOther(file);
4450 const bool checkRead = (flags & O_ACCMODE) != O_WRONLY;
4453 if (posix_uts_file_namespace(file, namespaceBacking) &&
4454 ((flags & O_ACCMODE) != O_RDONLY || (flags & O_TRUNC))) {
4455 SYSCALL_ERROR(PermissionDenied);
4461 if (ConsoleManager::instance().isPtySlaveLocked(file)) {
4462 F_NOTICE(
" -> PTY slave is locked");
4463 SYSCALL_ERROR(IoError);
4480 if (!
VFS::checkAccess(file, checkRead, flags & (O_WRONLY | O_RDWR | O_TRUNC),
false)) {
4482 F_NOTICE(
" -> file access denied.");
4487 if ((newFile != file) &&
4488 (!
VFS::checkAccess(newFile, checkRead, flags & (O_WRONLY | O_RDWR | O_TRUNC),
false))) {
4490 F_NOTICE(
" -> file access denied.");
4500 if (ConsoleManager::instance().isConsole(file)) {
4502 if (ConsoleManager::instance().isMasterConsole(file)) {
4505 if (!ConsoleManager::instance().lockConsole(file)) {
4506 F_NOTICE(
"Couldn't lock pseudoterminal master");
4507 SYSCALL_ERROR(DeviceBusy);
4513 if ((flags & O_NOCTTY) == 0 && !openingCtty) {
4514 F_NOTICE(
" -> setting opened terminal '" << file->
getName() <<
"' to be controlling");
4515 if (TerminalControl::attach(*
static_cast<ConsoleFile*
>(file),
false,
true) < 0) {
4524 if ((flags & O_TRUNC) && !file->
isDirectory() && !file->isBlockDevice() && !file->
isPipe() &&
4525 !file->
isFifo() && file->getFilesystem() != g_pDevFs &&
4526 !ConsoleManager::instance().isConsole(file)) {
4527 F_NOTICE(
" -> {O_TRUNC}");
4536 F_NOTICE(
"FIFO => checking if we have any readers");
4541 if (flags & O_WRONLY) {
4542 const bool bCanBlock = !(flags & O_NONBLOCK);
4546 F_NOTICE(
" -> ENXIO");
4547 SYSCALL_ERROR(NoSuchDevice);
4549 F_NOTICE(
" -> EINTR (fifo)");
4550 SYSCALL_ERROR(Interrupted);
4556 F_NOTICE(
"FIFO => successfully observed a reader");
4561 if (!openedPath && openingView && file->isCharacterDevice() &&
4562 file->getFilesystem() == fileLease.get()->getFilesystem() &&
4563 !openingView->pathForNode(fileLease.path(), file, openedPath)) {
4569 if (!f || !f->terminalAvailable()) {
4572 SYSCALL_ERROR(OutOfMemory);
4576 if ((flags & O_ACCMODE) != O_RDONLY) {
4582 f->setTruncateAllowed(allowTruncate);
4587 F_NOTICE(
" -> " << fd);
4589 return static_cast<int>(fd);
4592int posix_mkdirat(
int dirfd,
const char* pathname, mode_t mode) {
4594 if (!copyUserString(pathname, copied))
4598 if (!check_dirfd(copied.length() && copied[0] ==
'/' ? AT_FDCWD : dirfd, descriptor, start))
4600 String normalised, basename;
4601 normalisePath(normalised, copied.cstr());
4602 if (!findParentPath(normalised, start.path(), parent, basename))
4604 if (!basename.length() || basename ==
"." || basename ==
"..") {
4605 SYSCALL_ERROR(FileExists);
4608 if (
auto* process = getPosixProcess())
4609 mode &= ~process->getMask();
4610 return VFS::instance().mountView()->createDirectory(parent.path(), basename, mode) ? 0 : -1;
4613int posix_fchownat(
int dirfd,
const char* pathname, uid_t owner, gid_t group,
int flags) {
4614 if (flags & ~(AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW)) {
4615 SYSCALL_ERROR(InvalidArgument);
4619 if ((!pathname && !(flags & AT_EMPTY_PATH)) || (pathname && !copyUserString(pathname, copied))) {
4621 SYSCALL_ERROR(BadAddress);
4626 File* file = findAtPath(dirfd, copied, flags, selected, descriptor);
4628 const auto path = selected.path() ? selected.path()
4629 : descriptor ? descriptor->openingPath()
4631 if (file && path && !mountWrite.acquire(path)) {
4634 return file && posix_chown_file(file, owner, group) ? 0 : -1;
4637int posix_futimesat(
int dirfd,
const char* pathname,
const struct timeval* times) {
4638 F_NOTICE(
"futimesat");
4641 if (!copyUserString(pathname, pathnameCopy)) {
4642 F_NOTICE(
"utimes -> invalid address");
4645 struct timeval snapshot[2] = {};
4647 F_NOTICE(
"utimes -> invalid address");
4648 SYSCALL_ERROR(BadAddress);
4651 for (
const struct timeval& value : snapshot) {
4652 if (times && (value.tv_sec < 0 ||
static_cast<uint64_t
>(value.tv_sec) > UINT32_MAX ||
4653 value.tv_usec < 0 || value.tv_usec >= 1000000)) {
4654 SYSCALL_ERROR(InvalidArgument);
4659 F_NOTICE(
"futimesat(" << dirfd <<
", " << pathnameCopy <<
", " << times <<
")");
4662 normalisePath(realPath, pathnameCopy.cstr());
4666 File* file = findAtPath(dirfd, realPath, 0, fileLease, descriptor);
4668 SYSCALL_ERROR(DoesNotExist);
4673 file = traverseSymlink(file, fileLease);
4683 if (fileLease.path() && !mountWrite.acquire(fileLease.path())) {
4687 Time::Timestamp accessTime;
4688 Time::Timestamp modifyTime;
4690 accessTime = snapshot[0].tv_sec;
4691 modifyTime = snapshot[1].tv_sec;
4693 accessTime = modifyTime = Time::getTime();
4702int posix_unlinkat(
int dirfd,
const char* pathname,
int flags) {
4703 if (flags & ~AT_REMOVEDIR) {
4704 SYSCALL_ERROR(InvalidArgument);
4708 if (!copyUserString(pathname, copied))
4712 if (!check_dirfd(copied.length() && copied[0] ==
'/' ? AT_FDCWD : dirfd, descriptor, start))
4714 String normalised, basename;
4715 normalisePath(normalised, copied.cstr());
4717 if (!findParentPath(normalised, start.path(), parent, basename))
4719 if (!basename.length()) {
4720 syscallError(flags & AT_REMOVEDIR ? Error::DeviceBusy : Error::IsADirectory);
4727 options.crossFinalMount =
false;
4731 selected.retain(entry);
4732 File* file = selected.get();
4733 if (copied.length() && copied[copied.length() - 1] ==
'/' && !file->
isDirectory()) {
4734 SYSCALL_ERROR(NotADirectory);
4737 if (file->
isDirectory() != !!(flags & AT_REMOVEDIR)) {
4738 syscallError(file->
isDirectory() ? Error::IsADirectory : Error::NotADirectory);
4741 return VFS::instance().mountView()->remove(parent.path(), basename, file) ? 0 : -1;
4744int posix_renameat(
int olddirfd,
const char* oldpath,
int newdirfd,
const char* newpath) {
4745 String source, destination;
4746 if (!copyUserString(oldpath, source) || !copyUserString(newpath, destination))
4750 if (!check_dirfd(source.length() && source[0] ==
'/' ? AT_FDCWD : olddirfd, oldDescriptor,
4752 !check_dirfd(destination.length() && destination[0] ==
'/' ? AT_FDCWD : newdirfd,
4753 newDescriptor, newStart))
4755 String realSource, realDestination, oldName, newName;
4756 normalisePath(realSource, source.cstr());
4757 normalisePath(realDestination, destination.cstr());
4758 if (!findParentPath(realSource, oldStart.path(), oldParent, oldName) ||
4759 !findParentPath(realDestination, newStart.path(), newParent, newName))
4762 const bool directory = (source.length() && source[source.length() - 1] ==
'/') ||
4763 (destination.length() && destination[destination.length() - 1] ==
'/');
4764 return VFS::instance().mountView()->rename(oldParent.path(), oldName, newParent.path(), newName,
4770int posix_linkat(
int olddirfd,
const char* oldpath,
int newdirfd,
const char* newpath,
int flags) {
4771 if (flags & ~(AT_EMPTY_PATH | AT_SYMLINK_FOLLOW)) {
4772 SYSCALL_ERROR(InvalidArgument);
4775 String source, destination;
4776 if (!copyUserString(oldpath, source) || !copyUserString(newpath, destination))
4780 const int lookupFlags =
4781 (flags & AT_EMPTY_PATH) | ((flags & AT_SYMLINK_FOLLOW) ? 0 : AT_SYMLINK_NOFOLLOW);
4782 if (!findAtPath(olddirfd, source, lookupFlags, target, sourceDescriptor))
4784 if (!check_dirfd(destination.length() && destination[0] ==
'/' ? AT_FDCWD : newdirfd,
4785 destinationDescriptor, start))
4787 String normalised, basename;
4788 normalisePath(normalised, destination.cstr());
4789 if (!findParentPath(normalised, start.path(), parent, basename))
4791 return VFS::instance().mountView()->createLink(parent.path(), basename, target.path()) ? 0 : -1;
4794int posix_symlinkat(
const char* oldpath,
int newdirfd,
const char* newpath) {
4795 String value, destination;
4796 if (!copyUserString(oldpath, value) || !copyUserString(newpath, destination))
4800 if (!check_dirfd(destination.length() && destination[0] ==
'/' ? AT_FDCWD : newdirfd, descriptor,
4803 String normalised, basename;
4804 normalisePath(normalised, destination.cstr());
4805 if (!findParentPath(normalised, start.path(), parent, basename))
4807 return VFS::instance().mountView()->createSymlink(parent.path(), basename, value) ? 0 : -1;
4810int posix_readlinkat(
int dirfd,
const char* pathname,
char* buf,
size_t bufsiz) {
4811 F_NOTICE(
"readlinkat");
4814 if (!copyUserString(pathname, pathnameCopy)) {
4815 F_NOTICE(
"readlink -> invalid address");
4820 File* cwd = check_dirfd(pathnameCopy.length() && pathnameCopy[0] ==
'/' ? AT_FDCWD : dirfd,
4821 dirDescriptor, cwdLease, pathnameCopy.length() ? 0 : AT_EMPTY_PATH);
4826 PosixSubsystem::SafeWrite)) {
4827 F_NOTICE(
"readlink -> invalid address");
4828 SYSCALL_ERROR(BadAddress);
4832 F_NOTICE(
"readlinkat(" << dirfd <<
", " << pathnameCopy <<
", "
4833 <<
reinterpret_cast<uintptr_t
>(buf) <<
", " << bufsiz <<
")");
4836 normalisePath(realPath, pathnameCopy.cstr());
4839 File* f = pathnameCopy.length() ? findFilePath(realPath, fileLease, cwdLease.path()) : cwd;
4842 SYSCALL_ERROR(DoesNotExist);
4847 SYSCALL_ERROR(InvalidArgument);
4855 SYSCALL_ERROR(InvalidArgument);
4859 const size_t capacity = bufsiz < PATH_MAX ? bufsiz : PATH_MAX;
4862 SYSCALL_ERROR(OutOfMemory);
4870 SYSCALL_ERROR(BadAddress);
4876int posix_fchmodat(
int dirfd,
const char* pathname, mode_t mode,
int flags) {
4877 if (flags & ~(AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW)) {
4878 SYSCALL_ERROR(InvalidArgument);
4882 if ((!pathname && !(flags & AT_EMPTY_PATH)) || (pathname && !copyUserString(pathname, copied))) {
4884 SYSCALL_ERROR(BadAddress);
4889 File* file = findAtPath(dirfd, copied, flags, selected, descriptor);
4891 const auto path = selected.path() ? selected.path()
4892 : descriptor ? descriptor->openingPath()
4894 if (file && path && !mountWrite.acquire(path)) {
4897 return file && posix_chmod_file(file, mode) ? 0 : -1;
4900int posix_faccessat(
int dirfd,
const char* pathname,
int mode,
int flags) {
4901 F_NOTICE(
"faccessat");
4903 constexpr int validModes = R_OK | W_OK | X_OK;
4904 constexpr int validFlags = AT_EACCESS | AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH;
4905 if ((mode & ~validModes) || (flags & ~validFlags)) {
4906 SYSCALL_ERROR(InvalidArgument);
4911 if (!copyUserString(pathname, pathnameCopy)) {
4912 F_NOTICE(
"access -> invalid address");
4916 F_NOTICE(
"faccessat(" << dirfd <<
", " << pathnameCopy <<
", " << mode <<
", " << flags <<
")");
4918 if (!pathnameCopy.length() && !(flags & AT_EMPTY_PATH)) {
4919 SYSCALL_ERROR(DoesNotExist);
4926 ERROR(
"No subsystem for this process!");
4931 if (flags & AT_EACCESS) {
4932 if (!Process::currentFilesystemCredentials(accessCredentials)) {
4933 SYSCALL_ERROR(PermissionDenied);
4936 }
else if (process->getType() == Process::Posix) {
4937 accessCredentials =
static_cast<PosixProcess*
>(process)->realFilesystemCredentials();
4939 if (!Process::currentFilesystemCredentials(accessCredentials)) {
4940 SYSCALL_ERROR(PermissionDenied);
4943 const int64_t uid = process->
getUserId(), gid = process->getGroupId();
4944 if (uid < 0 || gid < 0) {
4945 SYSCALL_ERROR(PermissionDenied);
4948 accessCredentials.uid = uid;
4949 accessCredentials.gid = gid;
4955 File* file = findAtPath(dirfd, pathnameCopy, flags, fileLease, descriptor);
4958 F_NOTICE(
" -> '" << pathnameCopy <<
"' does not exist");
4960 SYSCALL_ERROR(DoesNotExist);
4969 const auto retainedPath = fileLease.path() ? fileLease.path()
4970 : descriptor ? descriptor->openingPath()
4972 auto* view = VfsMountView::fromPath(retainedPath);
4973 if (view && (mode & W_OK) && !file->isCharacterDevice() && !file->isBlockDevice() &&
4977 if (view && (mode & X_OK) && !file->
isDirectory() &&
4978 (view->mountFlags(retainedPath) & VfsMountView::NoExec)) {
4979 SYSCALL_ERROR(PermissionDenied);
4983 if (!
VFS::checkAccess(file, mode & R_OK, mode & W_OK, mode & X_OK, accessCredentials)) {
4985 F_NOTICE(
" -> not ok");
4993int posix_fstatat(
int dirfd,
const char* pathname,
struct stat* buf,
int flags) {
4994 F_NOTICE(
"fstatat");
4995 constexpr int noAutomount = 0x800;
4996 if (flags & ~(AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW | noAutomount)) {
4997 SYSCALL_ERROR(InvalidArgument);
5000 if (!pathname && !(flags & AT_EMPTY_PATH)) {
5001 SYSCALL_ERROR(BadAddress);
5006 PosixSubsystem::SafeWrite)) {
5007 F_NOTICE(
"fstat -> invalid address");
5008 SYSCALL_ERROR(BadAddress);
5014 if (!copyUserString(pathname, pathnameCopy)) {
5015 F_NOTICE(
"fstat -> invalid address");
5020 if ((flags & AT_EMPTY_PATH) && !pathnameCopy.length() && dirfd != AT_FDCWD) {
5022 if (!acquireDescriptor(dirfd, descriptor)) {
5023 SYSCALL_ERROR(BadFileDescriptor);
5026 if (descriptor->getTimerFdImpl() || descriptor->getSignalFdImpl() ||
5027 descriptor->getFanotifyImpl()) {
5031 struct stat snapshot = {};
5032 snapshot.st_dev = 0x10000;
5033 snapshot.st_ino = 1;
5034 snapshot.st_mode = 0600;
5035 snapshot.st_nlink = 1;
5038 SYSCALL_ERROR(BadAddress);
5043 if (!descriptor->getFile()) {
5044 SYSCALL_ERROR(BadFileDescriptor);
5047 struct stat snapshot = {};
5048 if (!doStat(0, descriptor->getFile(), &snapshot))
5051 SYSCALL_ERROR(BadAddress);
5059 File* file = findAtPath(dirfd, pathnameCopy, flags, fileLease, descriptor);
5063 struct stat snapshot = {};
5064 if (!doStat(0, file, &snapshot)) {
5068 SYSCALL_ERROR(BadAddress);
5072 F_NOTICE(
" -> Success");
5076int posix_mknod(
const char* pathname, mode_t mode, dev_t dev) {
5077 return posix_mknodat(AT_FDCWD, pathname, mode, dev);
5080static int do_statfs(
File* file,
struct statfs* userBuffer) {
5082 PosixSubsystem::SafeWrite)) {
5083 F_NOTICE(
" -> invalid address for buf [" << userBuffer <<
"]");
5084 SYSCALL_ERROR(BadAddress);
5089 F_NOTICE(
" -> file does not exist");
5090 SYSCALL_ERROR(DoesNotExist);
5096 struct statfs value = {};
5097 struct statfs* buf = &value;
5099 bool bFilled =
false;
5100 if (pFs == g_pDevFs) {
5101 F_NOTICE(
" -> file '" << file->
getName() <<
"' is on devfs");
5105 F_NOTICE(
" -> filling statfs struct with /dev/pts data");
5106 ByteSet(buf, 0,
sizeof(*buf));
5107 buf->f_type = 0x1CD1;
5108 buf->f_bsize = 4096;
5109 buf->f_namelen = PATH_MAX;
5110 buf->f_frsize = 4096;
5117 F_NOTICE(
" -> filling statfs struct with ext2 data");
5118 ByteSet(buf, 0,
sizeof(*buf));
5119 buf->f_type = 0xEF53;
5124 buf->f_bsize = 4096;
5125 buf->f_blocks = 0x100000;
5127 buf->f_bfree = buf->f_blocks;
5128 buf->f_bavail = buf->f_blocks;
5129 buf->f_files = 1234;
5130 buf->f_ffree = 5678;
5131 buf->f_namelen = PATH_MAX;
5136 if (kind ==
"proc") {
5137 buf->f_type = 0x9fa0;
5138 }
else if (kind ==
"devpts") {
5139 buf->f_type = 0x1cd1;
5140 }
else if (kind ==
"ramfs") {
5141 buf->f_type = 0x858458f6;
5146 SYSCALL_ERROR(BadAddress);
5153int posix_statfs(
const char* path,
struct statfs* buf) {
5157 if (!copyUserString(path, pathCopy)) {
5158 F_NOTICE(
" -> invalid address for path");
5162 F_NOTICE(
"statfs(" << pathCopy <<
")");
5164 normalisePath(normalisedPath, pathCopy.cstr());
5165 F_NOTICE(
" -> actually performing statfs on " << normalisedPath);
5167 File* file = findFilePath(normalisedPath, fileLease);
5169 return do_statfs(file, buf);
5172int posix_fstatfs(
int fd,
struct statfs* buf) {
5173 F_NOTICE(
"fstatfs(" << fd <<
")");
5178 ERROR(
"No subsystem for this process!");
5185 SYSCALL_ERROR(BadFileDescriptor);
5189 return do_statfs(pFd->getFile(), buf);
5192void generate_mtab(
String& result) {
5199 if (!view || !context || !view->snapshotMounts(context, mounts))
5201 auto escape = [](
const String& value) {
5203 for (
size_t i = 0; i < value.length(); ++i) {
5218 const char byte[] = {value[i], 0};
5226 for (
const auto& mount : mounts) {
5228 if (!mount.backing.pin(pin))
5231 String path = escape(mount.path);
5234 "%s %s unknown %s 0 0\n", source.length() ? source.cstr() :
"none", path.cstr(),
5235 (pin.filesystem()->isReadOnly() || (mount.flags &
VfsMountView::ReadOnly)) ?
"ro" :
"rw");
Memory-mapped file interface.
bool setPtyLock(File *file, bool locked)
Set the UNIX 98 PTY slave lock associated with a master.
void unlockConsole(File *file)
Release a console master locked as above.
ReadStatus enumerate(uint64_t &cookie, DirectoryEntryEmitter emitter, void *context)
static Directory * fromFile(File *pF)
virtual size_t getSize() const
Gets the size of the disk.
virtual size_t getBlockSize() const
Gets the preferred I/O extent of the disk.
OpenFileDescriptionLease acquireOpenFileDescription() const
int fdflags
File descriptor flags (fcntl)
bool eventFdPublished() const
void removeStatusFlag(int flag)
Helper to remove a single flag from the status flags.
IoEvent * ioevent
IO event for reporting changes to files.
SharedPointer< InotifyInstance > getInotifyImpl() const
PositionGuard lockPosition() const
SharedPointer< EventFd > getEventFdImpl() const
int getStatusFlags() const
Get current status flags.
void addStatusFlag(int newFlag)
Helper to add a single flag to the status flags.
void setStatusFlags(int newFlags)
Set status flags, distributing any associated changes as needed.
SharedPointer< NetworkSyscalls > networkImpl
Network syscall implementation for this descriptor (if it's a socket).
size_t fd
Descriptor number.
bool networkPublished() const
virtual void getFullPath(String &result, bool bWithMount=true)
void monitor(Thread *pThread, Event *pEvent)
virtual bool isSeekable() const
virtual uint64_t read(uint64_t location, uint64_t size, uintptr_t buffer, bool bCanBlock=true) final
virtual int command(const size_t command, void *buffer)
bool supportsRegularFileOperations()
virtual bool isSocket() const
virtual bool isDirectory()
void setModifiedTime(Time::Timestamp t)
void publishEvent(FileEventMask mask, const StringView &name=StringView(), bool targetIsDirectory=false)
virtual bool isFifo() const
virtual bool isPipe() const
void setAccessedTime(Time::Timestamp t)
virtual bool supports(const size_t command) const
virtual File * openForDescriptor(RetainedFile &owner)
virtual const String & getVolumeLabel() const =0
virtual void setLedState(char state)
virtual char getLedState()
static KeymapManager & instance()
Singleton design.
KeymapEntry * getKeymapEntry(bool bCtrl, bool bShift, bool bAlt, bool bAltGr, uint8_t nCombinator, uint8_t keyCode)
Returns the keymap entry corresponding to given keycode and modifiers.
uint8_t convertPc102ScancodeToHidKeycode(uint8_t scancode, EscapeState &escape)
Converts a pc102 scancode into a HID keycode.
virtual Keyboard * getKeyboard()=0
MemoryMappedObject * mapAnon(uintptr_t &address, size_t length, MemoryMappedObject::Permissions perms)
static MemoryMapManager & instance()
MemoryMappedObject * mapFile(File *pFile, uintptr_t &address, size_t length, MemoryMappedObject::Permissions perms, size_t offset=0, bool bCopyOnWrite=true)
size_t removeAndRelease(uintptr_t base, size_t length, VmStatus *status=nullptr)
static constexpr size_t getPageSize() PURE
bool waitForReader(bool bCanBlock)
static Pipe * fromFile(File *pF)
virtual void threadException(Thread *pThread, ExceptionType eType, InterruptState *pState=nullptr, uintptr_t faultAddress=0, uintptr_t errorCode=0)
bool acquireFileDescriptor(size_t fd, DescriptorLease &descriptor)
bool closeFileDescriptor(size_t fd, const DescriptorLease &descriptor)
static bool copyFromUser(void *destination, const void *source, size_t count, size_t elementSize=1)
static size_t readCachedFile(File &file, uint64_t offset, void *destination, size_t count)
size_t getFd(size_t minimum=0)
static UserStringResult copyUserString(const char *userString, String ©, size_t maxLength)
void freeFd(size_t fdNum)
static bool checkUserAddressRange(uintptr_t addr, size_t count, size_t elementSize, size_t *extent=nullptr)
static bool checkUserBuffer(uintptr_t addr, size_t count, size_t elementSize, size_t flags, size_t *extent=nullptr)
static bool copyToUser(void *destination, const void *source, size_t count, size_t elementSize=1)
void addFileDescriptor(size_t fd, FileDescriptor *pFd)
DescriptorDuplicationResult duplicateFileDescriptor(size_t source, size_t target, bool closeOnExec)
static bool checkAddress(uintptr_t addr, size_t extent, size_t flags)
virtual int64_t getUserId() const
static ProcessorInformation & information()
bool compare(const char *s, size_t len) const
static Symlink * fromFile(File *pF)
virtual int followLink(char *pBuffer, size_t bufLen)
void setErrno(size_t err)
Process * getParent() const
void getMounts(Vector< MountSnapshot > &mounts) const
static bool checkAccess(File *pFile, bool bRead, bool bWrite, bool bExecute)
A vector / dynamic array.
virtual uintptr_t getUserStart() const =0
virtual uintptr_t getKernelStart() const =0
bool activate(size_t n)
Starts the process of activating the given tty.
Structure representing an entry in the keymap table.