Skip to content

FUSE (WIP) #891

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 141 additions & 2 deletions options/ansi/generic/string.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,9 @@ wchar_t *wmemset(wchar_t *d, wchar_t c, size_t n) {
return ret;
}

char *strerror(int e) {
namespace {

const char *strerror_base(int e) {
const char *s;
switch(e) {
case EAGAIN: s = "Operation would block (EAGAIN)"; break;
Expand Down Expand Up @@ -463,10 +465,21 @@ char *strerror(int e) {
#endif

default:
s = "Unknown error code (?)";
s = nullptr;
}
return s;
}

} // anonymous namespace

char *strerror(int e) {
const char *s = strerror_base(e);
if(s == nullptr)
s = "Unknown error code (?)";

return const_cast<char *>(s);
}

// strlen() is defined in options/internals.

extern "C" char *__gnu_strerror_r(int e, char *buffer, size_t bufsz) {
Expand All @@ -491,6 +504,132 @@ void *mempcpy(void *dest, const void *src, size_t len) {
}

// GNU extensions.
const char *strerrorname_np(int e) {
const char *s;
#define X(x) case x: s = #x; break;
switch(e) {
X(EAGAIN)
X(EACCES)
X(EBADF)
X(EEXIST)
X(EFAULT)
X(EINTR)
X(EINVAL)
X(EIO)
X(EISDIR)
X(ENOENT)
X(ENOMEM)
X(ENOTDIR)
X(ENOSYS)
X(EPERM)
X(EPIPE)
X(ESPIPE)
X(ENXIO)
X(ENOEXEC)
X(ENOSPC)
X(ENOTSOCK)
X(ENOTCONN)
X(EDOM)
X(EILSEQ)
X(ERANGE)
X(E2BIG)
X(EADDRINUSE)
X(EADDRNOTAVAIL)
X(EAFNOSUPPORT)
X(EALREADY)
X(EBADMSG)
X(EBUSY)
X(ECANCELED)
X(ECHILD)
X(ECONNABORTED)
X(ECONNREFUSED)
X(ECONNRESET)
X(EDEADLK)
X(EDESTADDRREQ)
X(EDQUOT)
X(EFBIG)
X(EHOSTUNREACH)
X(EIDRM)
X(EINPROGRESS)
X(EISCONN)
X(ELOOP)
X(EMFILE)
X(EMLINK)
X(EMSGSIZE)
X(EMULTIHOP)
X(ENAMETOOLONG)
X(ENETDOWN)
X(ENETRESET)
X(ENETUNREACH)
X(ENFILE)
X(ENOBUFS)
X(ENODEV)
X(ENOLCK)
X(ENOLINK)
X(ENOMSG)
X(ENOPROTOOPT)
X(ENOTEMPTY)
X(ENOTRECOVERABLE)
X(ENOTSUP)
X(ENOTTY)
X(EOVERFLOW)
#if EOPNOTSUPP != ENOTSUP
/* these are aliases on the mlibc abi */
X(EOPNOTSUPP)
#endif
X(EOWNERDEAD)
X(EPROTO)
X(EPROTONOSUPPORT)
X(EPROTOTYPE)
X(EROFS)
X(ESRCH)
X(ESTALE)
X(ETIMEDOUT)
X(ETXTBSY)
X(EXDEV)
X(ENODATA)
X(ETIME)
X(ENOKEY)
X(ESHUTDOWN)
X(EHOSTDOWN)
X(EBADFD)
X(ENOMEDIUM)
X(ENOTBLK)
X(ENONET)
X(EPFNOSUPPORT)
X(ESOCKTNOSUPPORT)
X(ESTRPIPE)
X(EREMOTEIO)
X(ERFKILL)
X(EBADR)
X(EUNATCH)
X(EMEDIUMTYPE)
X(EREMOTE)
X(EKEYREJECTED)
X(EUCLEAN)
X(EBADSLT)
X(ENOANO)
X(ENOCSI)
X(ENOSTR)
X(ETOOMANYREFS)
X(ENOPKG)
X(EKEYREVOKED)
X(EXFULL)
X(ELNRNG)
X(ENOTUNIQ)
X(ERESTART)
X(EUSERS)
default:
s = nullptr;
}
#undef X
return s;
}

const char *strerrordesc_np(int e) {
return strerror_base(e);
}

// Taken from musl.
int strverscmp(const char *l0, const char *r0) {
const unsigned char *l = (const unsigned char *)l0;
Expand Down
2 changes: 2 additions & 0 deletions options/ansi/include/string.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ size_t strlen(const char *__s);

/* POSIX extensions. */
#if defined(_GNU_SOURCE)
const char *strerrorname_np(int e);
const char *strerrordesc_np(int e);
char *strerror_r(int __errnum, char *__buffer, size_t __size) __asm__("__gnu_strerror_r");
#else
int strerror_r(int __errnum, char *__buffer, size_t __size);
Expand Down
5 changes: 5 additions & 0 deletions options/linux/include/sys/mount.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ extern "C" {

#ifndef __MLIBC_ABI_ONLY

#define MNT_FORCE 1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Double define

#define MNT_DETACH (1<<1)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Styling is wrong (see the constants defined earlier in the file.

#define MNT_EXPIRE (1<<2)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should move these defines outside the MLIBC_ABI_ONLY define. Also please make sure these new defines match Linux. Better yet, we should really move these to an abi-bit header, as I'm pretty sure that at least some of the constants in this file don't match Linux.

#define UMOUNT_NOFOLLOW (1<<3)

int mount(const char *__source, const char *__target,
const char *__fstype, unsigned long __flags, const void *__data);
int umount(const char *__target);
Expand Down
5 changes: 3 additions & 2 deletions options/posix/include/fcntl.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,18 +55,19 @@ struct file_handle {
int handle_type;
__extension__ unsigned char f_handle[0];
};
#endif
#endif /* _GNU_SOURCE */

#ifndef __MLIBC_ABI_ONLY

#ifdef _GNU_SOURCE
int name_to_handle_at(int __dirfd, const char *__path, struct file_handle *__handle, int *__mount_id, int __flags);
int open_by_handle_at(int __dirfd, struct file_handle *__handle, int __flags);
#endif

ssize_t splice(int __fd_in, off_t *__off_in, int __fd_out, off_t *__off_out, size_t __len, unsigned int __flags);
ssize_t vmsplice(int __fd, const struct iovec *__iov, size_t __nr_segs, unsigned int __flags);

#endif /* _GNU_SOURCE */

#endif /* !__MLIBC_ABI_ONLY */

#define SPLICE_F_MOVE 1
Expand Down
42 changes: 39 additions & 3 deletions sysdeps/managarm/generic/mount.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,17 @@

namespace mlibc {

int
sys_mount(const char *source, const char *target, const char *fstype, unsigned long, const void *) {
int sys_mount(const char *source, const char *target, const char *fstype, unsigned long,
const void * data) {
SignalGuard sguard;

managarm::posix::MountRequest<MemoryAllocator> req(getSysdepsAllocator());
req.set_path(frg::string<MemoryAllocator>(getSysdepsAllocator(), source ? source : ""));
req.set_target_path(frg::string<MemoryAllocator>(getSysdepsAllocator(), target ? target : ""));
req.set_fs_type(frg::string<MemoryAllocator>(getSysdepsAllocator(), fstype ? fstype : ""));
if(data){
req.set_arguments(frg::string<MemoryAllocator>(getSysdepsAllocator(), (char*)data));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the extra data always a string? (Is it just the mount options as specified by -o to mount(8)?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not aware of any cases in which this data isn't a string, but I don't think it's is required to be a string. This is mainly a temporary measure until I can think of a better way to approach this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mount(2) on my system says:

The data argument is interpreted by the different filesystems. Typically it is a string of comma-separated options understood by this filesystem. See mount(8) for details of the options available for each filesystem type.

I think that, practically speaking, we would be fine by just interpreting this as a string in almost any occasion. However, I don't think it's technically correct.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That seems fine to me then. Since the man page directs you to mount(8) then it'd be difficult to specify binary data (maybe check mount source code?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might check the source later, but it's not very high-priority for me. I was thinking about implementing some sort of fs-specific argument decoding dispatch mechanism, but I'm not sure how I'd go about doing this and it'd probably require the sysdep to be aware of every possible filesystem - which would be impractical at best

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm just throwing around ideas here, but isn't it also possible to have a pushMemory action similarly to how we have a pushDescriptor action that pushes an arbitrary piece of memory across process boundaries? Or maybe a mechanism which turns a piece of memory into a descriptor? IIRC that would also help at other points in the managarm sysdeps.

}

auto [offer, send_head, send_tail, recv_resp] = exchangeMsgsSync(
getPosixLane(),
Expand All @@ -41,4 +44,37 @@ sys_mount(const char *source, const char *target, const char *fstype, unsigned l
return 0;
}

} // namespace mlibc
int sys_umount2(const char *target, int flags) {
SignalGuard sguard;

managarm::posix::Umount2Request<MemoryAllocator> req(getSysdepsAllocator());
req.set_target(frg::string<MemoryAllocator>(getSysdepsAllocator(), target));
req.set_flags(flags);

auto [offer, send_head, send_tail, recv_resp] =
exchangeMsgsSync(
getPosixLane(),
helix_ng::offer(
helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()),
helix_ng::recvInline()
)
);

HEL_CHECK(offer.error());
HEL_CHECK(send_head.error());
HEL_CHECK(send_tail.error());
HEL_CHECK(recv_resp.error());

auto resp = *bragi::parse_head_only<managarm::posix::SvrResponse>(recv_resp, getSysdepsAllocator());
if(resp.error() == managarm::posix::Errors::ILLEGAL_ARGUMENTS)
return EINVAL;
else if(resp.error() == managarm::posix::Errors::FILE_NOT_FOUND)
return ENOENT;
else if(resp.error() == managarm::posix::Errors::NOT_A_MOUNTPOINT)
return EINVAL;
__ensure(resp.error() == managarm::posix::Errors::SUCCESS);
return 0;
}

} //namespace mlibc

14 changes: 14 additions & 0 deletions tests/glibc/strerrordesc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <string.h>
#include <errno.h>
#include <assert.h>

int main(void) {
#if !defined(__GLIBC__) || (__GLIBC__ >= 2 && __GLIBC_MINOR__ >= 32)
const char *s = strerrordesc_np(EINVAL);
assert(!strcmp(s, "Invalid argument (EINVAL)"));
assert(strerrordesc_np(0) == NULL);
#endif
}
14 changes: 14 additions & 0 deletions tests/glibc/strerrorname.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <string.h>
#include <errno.h>
#include <assert.h>

int main(void) {
#if !defined(__GLIBC__) || (__GLIBC__ >= 2 && __GLIBC_MINOR__ >= 32)
const char *s = strerrorname_np(EINVAL);
assert(!strcmp(s, "EINVAL"));
assert(strerrorname_np(0) == NULL);
#endif
}
2 changes: 2 additions & 0 deletions tests/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ all_test_cases = [
'glibc/error_at_line',
'glibc/getgrouplist',
'glibc/rpmatch',
'glibc/strerrorname',
'glibc/strerrordesc',
'linux/xattr',
'linux/pthread_setname_np',
'linux/pthread_attr',
Expand Down
Loading