2#include "mount-view-syscalls.h"
3#include "pedigree/kernel/process/Thread.h"
4#include "pedigree/kernel/processor/Processor.h"
5#include "pedigree/kernel/processor/ProcessorInformation.h"
6#include "pedigree/kernel/syscallError.h"
11#include "PosixSubsystem.h"
13#include "ResolvedPath.h"
14#include "file-syscalls.h"
16#include "modules/system/vfs/MountView.h"
17#include "user-namespace.h"
22uint32_t permissionsForMode(uint32_t mode) {
23 uint32_t permissions = mode & FILE_AMASK;
25 permissions |= FILE_UR;
28 permissions |= FILE_UW;
31 permissions |= FILE_UX;
34 permissions |= FILE_GR;
37 permissions |= FILE_GW;
40 permissions |= FILE_GX;
43 permissions |= FILE_OR;
46 permissions |= FILE_OW;
49 permissions |= FILE_OX;
54 MountResult(
int result)
56 error(result < 0 ?
Processor::information().getCurrentThread()->getErrno() : 0) {}
63 SYSCALL_ERROR(NoSuchDevice);
67 while (owner && owner->identity() != view->ownerNamespace()) {
68 owner = owner->parent();
70 if ((owner ? owner->identity() : 0) == view->ownerNamespace() &&
71 posix_namespace_capable(owner, PosixCapabilities::SysAdmin)) {
74 SYSCALL_ERROR(NotEnoughPermissions);
88 m_Root->setPermissions(permissionsForMode(0755));
90 new PtmxFile(
String(
"ptmx"), 2,
this, m_Root, m_Root, permissionsForMode(0620),
true);
94 if (!m_Root->addEntry(
String(
"ptmx"), multiplexer)) {
104 static String name(
"devpts");
107 SyncStatus
sync()
override {
108 return SyncStatus::Success;
127bool copyPath(
const char* user,
String& result) {
129 if (status == PosixSubsystem::UserStringSuccess)
131 syscallError(status == PosixSubsystem::UserStringBadAddress ? Error::BadAddress
132 : Error::NameTooLong);
135bool initialiseSelinux(
RamFs& filesystem) {
141 const Entry entries[] = {
142 {
"enforce", 0444,
"0\n"}, {
"policyvers", 0444,
"0\n"}, {
"disable", 0666,
""}};
143 for (
const auto& entry : entries) {
144 if (!filesystem.Filesystem::createFile(
String(entry.name), entry.mode, filesystem.
getRoot()))
150 const size_t bytes = StringLength(entry.value);
151 if (bytes && file.get()->
write(0, bytes,
reinterpret_cast<uintptr_t
>(entry.value)) != bytes)
156MountResult mount(
const char* source,
const char* target,
const char* type,
size_t flags,
161 constexpr size_t Bind = 4096, Recursive = 16384, Remount = 32;
162 constexpr size_t Silent = 32768, Private = 1UL << 18, Slave = 1UL << 19;
163 constexpr size_t Policy = VfsMountView::SupportedMountFlags;
164 if ((flags & 0xffff0000UL) == 0xc0ed0000UL) {
168 if (flags & ~(Policy | Bind | Recursive | Remount | Private | Slave)) {
169 SYSCALL_ERROR(OperationNotSupported);
173 if ((source && !copyPath(source, sourceCopy)) || !copyPath(target, targetCopy) ||
174 (type && !copyPath(type, typeCopy)) ||
175 (data && !copyPath(
static_cast<const char*
>(data),
options))) {
181 if (!view || !context || !findFilePath(targetCopy, selected,
FilesystemPathRef(),
true)) {
184 if (flags & (Private | Slave)) {
185 if ((flags & ~(Private | Slave | Recursive)) ||
186 (flags & (Private | Slave)) == (Private | Slave)) {
187 SYSCALL_ERROR(InvalidArgument);
193 if (flags & Remount) {
194 if (!(flags & Bind)) {
195 SYSCALL_ERROR(OperationNotSupported);
198 return view->remount(context, selected.path(), flags & Policy, flags & Recursive) ? 0 : -1;
205 return view->bind(context, original.path(), selected.path(), flags & Recursive) ? 0 : -1;
207 if ((flags & Recursive) || !selected.get()->
isDirectory()) {
208 syscallError((flags & Recursive) ? Error::InvalidArgument : Error::NotADirectory);
211 uint32_t rootMode = 0755;
212 if (
options.length() && typeCopy !=
"devpts") {
214 SYSCALL_ERROR(OperationNotSupported);
218 for (
size_t i = 5; i <
options.length(); ++i) {
220 SYSCALL_ERROR(InvalidArgument);
223 rootMode = rootMode * 8 +
options[i] -
'0';
228 if (typeCopy ==
"proc") {
231 if (!filesystem || !filesystem->
initialise(
nullptr)) {
233 SYSCALL_ERROR(OutOfMemory);
236 backing = filesystem;
238 }
else if (typeCopy ==
"devpts") {
239 if (
options !=
"newinstance,ptmxmode=0666,mode=620") {
240 SYSCALL_ERROR(OperationNotSupported);
243 auto* filesystem =
new DevPts;
244 if (!filesystem || !filesystem->
initialise(
nullptr)) {
246 SYSCALL_ERROR(OutOfMemory);
249 backing = filesystem;
251 }
else if (typeCopy ==
"tmpfs" || typeCopy ==
"ramfs" || typeCopy ==
"selinuxfs") {
252 auto* filesystem =
new RamFs;
254 SYSCALL_ERROR(OutOfMemory);
258 (typeCopy ==
"selinuxfs" && !initialiseSelinux(*filesystem))) {
260 SYSCALL_ERROR(IoError);
263 filesystem->
getRoot()->setPermissions(permissionsForMode(rootMode));
264 backing = filesystem;
267 SYSCALL_ERROR(DeviceDoesNotExist);
271 SYSCALL_ERROR(DeviceDoesNotExist);
274 if (owned && !
VFS::instance().registerFilesystem(backing, typeCopy).length()) {
276 SYSCALL_ERROR(OutOfMemory);
279 const auto ownership =
280 owned ? VfsMountView::BackingOwnership::Attachment : VfsMountView::BackingOwnership::External;
281 if (view->attach(context, selected.path(), backing, ownership, flags & Policy))
284 if (owned && !
VFS::instance().retireOwnedFilesystem(backing))
285 FATAL(
"Unpublished mount backing retained unexpectedly");
289MountResult unmount(
const char* target,
int flags) {
293 constexpr int lazy = 2;
295 SYSCALL_ERROR(OperationNotSupported);
299 if (!copyPath(target, copied))
304 if (!view || !context) {
305 SYSCALL_ERROR(DoesNotExist);
308 return view->detach(context, copied, flags & lazy) ? 0 : -1;
310MountResult pivot(
const char* newRoot,
const char* putOld) {
315 if (!copyPath(newRoot, next) || !copyPath(putOld, previous))
320 if (!view || !context) {
321 SYSCALL_ERROR(DoesNotExist);
324 return view->pivot(context, next, previous) ? 0 : -1;
327int posix_mount(
const char* source,
const char* target,
const char* type,
size_t flags,
329 const MountResult result = mount(source, target, type, flags, data);
330 syscallError(result.error);
333int posix_umount2(
const char* target,
int flags) {
334 const MountResult result = unmount(target, flags);
335 syscallError(result.error);
338int posix_pivot_root(
const char* newRoot,
const char* putOld) {
339 const MountResult result = pivot(newRoot, putOld);
340 syscallError(result.error);
static Directory * fromFile(File *pF)
MUST_USE_RESULT LookupStatus lookupChild(const HashedStringView &s, ChildLease &child) const
virtual uint64_t write(uint64_t location, uint64_t size, uintptr_t buffer, bool bCanBlock=true) final
virtual bool isDirectory()
virtual bool removeNode(File *parent, const String &filename, File *file)=0
virtual bool initialise(Disk *pDisk)=0
virtual const String & getVolumeLabel() const =0
bool createSymlink(const StringView &path, const String &value, File *pStartNode=0)
bool createDirectory(const StringView &path, uint32_t mask, File *pStartNode=0)
virtual SyncStatus sync()
virtual File * getRoot() const =0
bool createFile(const StringView &path, uint32_t mask, File *pStartNode=0)
static UserStringResult copyUserString(const char *userString, String ©, size_t maxLength)
static ProcessorInformation & information()
virtual bool initialise(Disk *pDisk) override
virtual File * getRoot() const override