Skip to content
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

FUSE (WIP) #891

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
147 changes: 145 additions & 2 deletions options/ansi/generic/string-stubs.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif

#include <string.h>
#include <errno.h>
#include <wchar.h>
Expand Down Expand Up @@ -341,7 +345,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 @@ -456,10 +462,21 @@ char *strerror(int e) {
case ERESTART: s = "Interrupted system call should be restarted (ERESTART)"; break;
case EUSERS: s = "Too many users (EUSERS)"; break;
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.

// POSIX extensions.
Expand All @@ -478,6 +495,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)
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't this be indented one more?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The case statements I replaced were on the same indentation level - but I can indent it a level more of desired

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
4 changes: 4 additions & 0 deletions options/ansi/include/string.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ int strerror_r(int, char *, size_t);
void *mempcpy(void *, const void *, size_t);

// GNU extensions.
#ifdef _GNU_SOURCE
const char *strerrorname_np(int e);
const char *strerrordesc_np(int e);
#endif
int strverscmp(const char *l0, const char *r0);
int ffsl(long i);
int ffsll(long long i);
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 @@ -40,6 +40,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
8 changes: 8 additions & 0 deletions options/posix/include/fcntl.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,20 +39,28 @@ int posix_fallocate(int, off_t, off_t);

// This is a linux extension

#ifdef _GNU_SOURCE

struct file_handle {
unsigned int handle_bytes;
int handle_type;
unsigned char f_handle[0];
};

#endif /* _GNU_SOURCE */

#ifndef __MLIBC_ABI_ONLY

#ifdef _GNU_SOURCE

int name_to_handle_at(int, const char *, struct file_handle *, int *, int);
int open_by_handle_at(int, struct file_handle *, int);

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
39 changes: 38 additions & 1 deletion sysdeps/managarm/generic/mount.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@
namespace mlibc {

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

managarm::posix::MountRequest<MemoryAllocator> req(getSysdepsAllocator());
req.set_path(frg::string<MemoryAllocator>(getSysdepsAllocator(), source));
req.set_target_path(frg::string<MemoryAllocator>(getSysdepsAllocator(), target));
req.set_fs_type(frg::string<MemoryAllocator>(getSysdepsAllocator(), 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(
Expand All @@ -37,6 +40,40 @@ int sys_mount(const char *source, const char *target,
auto resp = *bragi::parse_head_only<managarm::posix::SvrResponse>(recv_resp, getSysdepsAllocator());
if(resp.error() == managarm::posix::Errors::FILE_NOT_FOUND)
return ENOENT;
else if(resp.error() == managarm::posix::Errors::UNKNOWN_FILESYSTEM)
return ENODEV;
__ensure(resp.error() == managarm::posix::Errors::SUCCESS);
return 0;
}

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;
}
Expand Down
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 @@ -96,6 +96,8 @@ all_test_cases = [
'glibc/error_expect_fail',
'glibc/error',
'glibc/error_at_line',
'glibc/strerrorname',
'glibc/strerrordesc',
'linux/xattr',
'linux/pthread_setname_np',
'linux/pthread_attr',
Expand Down