#ifdef _GNU_SOURCE #undef _GNU_SOURCE #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include HelHandle __mlibc_getPassthrough(int fd) { auto handle = getHandleForFd(fd); __ensure(handle); return handle; } namespace mlibc { int sys_chdir(const char *path) { SignalGuard sguard; managarm::posix::ChdirRequest req(getSysdepsAllocator()); req.set_path(frg::string(getSysdepsAllocator(), path)); auto [offer, send_req, send_tail, recv_resp] = exchangeMsgsSync( getPosixLane(), helix_ng::offer( helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_req.error()); HEL_CHECK(send_tail.error()); HEL_CHECK(recv_resp.error()); managarm::posix::ChdirResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; return 0; } int sys_fchdir(int fd) { SignalGuard sguard; managarm::posix::CntRequest req(getSysdepsAllocator()); req.set_request_type(managarm::posix::CntReqType::FCHDIR); req.set_fd(fd); auto [offer, send_req, recv_resp] = exchangeMsgsSync( getPosixLane(), helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_req.error()); HEL_CHECK(recv_resp.error()); managarm::posix::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; return 0; } int sys_chroot(const char *path) { SignalGuard sguard; managarm::posix::ChrootRequest req(getSysdepsAllocator()); req.set_path(frg::string(getSysdepsAllocator(), path)); auto [offer, send_req, send_tail, recv_resp] = exchangeMsgsSync( getPosixLane(), helix_ng::offer( helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_req.error()); HEL_CHECK(send_tail.error()); HEL_CHECK(recv_resp.error()); managarm::posix::ChrootResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; return 0; } int sys_mkdir(const char *path, mode_t mode) { return sys_mkdirat(AT_FDCWD, path, mode); } int sys_mkdirat(int dirfd, const char *path, mode_t mode) { SignalGuard sguard; managarm::posix::MkdirAtRequest req(getSysdepsAllocator()); req.set_fd(dirfd); req.set_path(frg::string(getSysdepsAllocator(), path)); req.set_mode(mode); 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()); managarm::posix::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; return 0; } int sys_symlink(const char *target_path, const char *link_path) { return sys_symlinkat(target_path, AT_FDCWD, link_path); } int sys_symlinkat(const char *target_path, int dirfd, const char *link_path) { SignalGuard sguard; managarm::posix::SymlinkAtRequest req(getSysdepsAllocator()); req.set_fd(dirfd); req.set_path(frg::string(getSysdepsAllocator(), link_path)); req.set_target_path(frg::string(getSysdepsAllocator(), target_path)); 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()); managarm::posix::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; return 0; } int sys_link(const char *old_path, const char *new_path) { return sys_linkat(AT_FDCWD, old_path, AT_FDCWD, new_path, 0); } int sys_linkat(int olddirfd, const char *old_path, int newdirfd, const char *new_path, int flags) { SignalGuard sguard; managarm::posix::LinkAtRequest req(getSysdepsAllocator()); req.set_path(frg::string(getSysdepsAllocator(), old_path)); req.set_target_path(frg::string(getSysdepsAllocator(), new_path)); req.set_fd(olddirfd); req.set_newfd(newdirfd); 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()); managarm::posix::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; return 0; } int sys_rename(const char *path, const char *new_path) { return sys_renameat(AT_FDCWD, path, AT_FDCWD, new_path); } int sys_renameat(int olddirfd, const char *old_path, int newdirfd, const char *new_path) { SignalGuard sguard; managarm::posix::RenameAtRequest req(getSysdepsAllocator()); req.set_path(frg::string(getSysdepsAllocator(), old_path)); req.set_target_path(frg::string(getSysdepsAllocator(), new_path)); req.set_fd(olddirfd); req.set_newfd(newdirfd); 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()); managarm::posix::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; return 0; } } // namespace mlibc namespace mlibc { int do_dup2(int fd, int flags, int newfd, bool fcntl_mode, int *outfd) { SignalGuard sguard; managarm::posix::Dup2Request req(getSysdepsAllocator()); req.set_fd(fd); req.set_newfd(newfd); req.set_flags(flags); req.set_fcntl_mode(fcntl_mode); auto [offer, send_req, recv_resp] = exchangeMsgsSync( getPosixLane(), helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_req.error()); HEL_CHECK(recv_resp.error()); managarm::posix::Dup2Response resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; if (outfd) *outfd = resp.fd(); return 0; } int sys_fcntl(int fd, int request, va_list args, int *result) { SignalGuard sguard; if (request == F_DUPFD) { int newfd; int wantedFd = va_arg(args, int); if (int e = do_dup2(fd, 0, wantedFd, true, &newfd); e) return e; *result = newfd; return 0; } else if (request == F_DUPFD_CLOEXEC) { int newfd; int wantedFd = va_arg(args, int); if (int e = do_dup2(fd, O_CLOEXEC, wantedFd, true, &newfd); e) return e; *result = newfd; return 0; } else if (request == F_GETFD) { managarm::posix::CntRequest req(getSysdepsAllocator()); req.set_request_type(managarm::posix::CntReqType::FD_GET_FLAGS); req.set_fd(fd); auto [offer, send_req, recv_resp] = exchangeMsgsSync( getPosixLane(), helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_req.error()); HEL_CHECK(recv_resp.error()); managarm::posix::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; *result = resp.flags(); return 0; } else if (request == F_SETFD) { managarm::posix::CntRequest req(getSysdepsAllocator()); req.set_request_type(managarm::posix::CntReqType::FD_SET_FLAGS); req.set_fd(fd); req.set_flags(va_arg(args, int)); auto [offer, send_req, recv_resp] = exchangeMsgsSync( getPosixLane(), helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_req.error()); HEL_CHECK(recv_resp.error()); managarm::posix::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; *result = static_cast(resp.error()); return 0; } else if (request == F_GETFL) { SignalGuard sguard; auto handle = getHandleForFd(fd); if (!handle) return EBADF; managarm::fs::CntRequest req(getSysdepsAllocator()); req.set_req_type(managarm::fs::CntReqType::PT_GET_FILE_FLAGS); req.set_fd(fd); auto [offer, send_req, recv_resp] = exchangeMsgsSync( handle, helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_req.error()); HEL_CHECK(recv_resp.error()); managarm::fs::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() == managarm::fs::Errors::ILLEGAL_OPERATION_TARGET) { mlibc::infoLogger() << "\e[31mmlibc: fcntl(F_GETFL) unimplemented for this file\e[39m" << frg::endlog; return EINVAL; } else if (resp.error() != managarm::fs::Errors::SUCCESS) { return resp.error() | toErrno; } *result = resp.flags(); return 0; } else if (request == F_SETFL) { SignalGuard sguard; auto handle = getHandleForFd(fd); if (!handle) return EBADF; managarm::fs::CntRequest req(getSysdepsAllocator()); req.set_req_type(managarm::fs::CntReqType::PT_SET_FILE_FLAGS); req.set_fd(fd); req.set_flags(va_arg(args, int)); auto [offer, send_req, recv_resp] = exchangeMsgsSync( handle, helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_req.error()); HEL_CHECK(recv_resp.error()); managarm::fs::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() == managarm::fs::Errors::ILLEGAL_OPERATION_TARGET) { mlibc::infoLogger() << "\e[31mmlibc: fcntl(F_SETFL) unimplemented for this file\e[39m" << frg::endlog; return EINVAL; } else if (resp.error() != managarm::fs::Errors::SUCCESS) { return resp.error() | toErrno; } *result = 0; return 0; } else if (request == F_SETLK) { mlibc::infoLogger() << "\e[31mmlibc: F_SETLK\e[39m" << frg::endlog; return 0; } else if (request == F_SETLKW) { mlibc::infoLogger() << "\e[31mmlibc: F_SETLKW\e[39m" << frg::endlog; return 0; } else if (request == F_GETLK) { struct flock *lock = va_arg(args, struct flock *); lock->l_type = F_UNLCK; mlibc::infoLogger() << "\e[31mmlibc: F_GETLK is stubbed!\e[39m" << frg::endlog; return 0; } else if (request == F_OFD_SETLK) { mlibc::infoLogger() << "\e[31mmlibc: F_OFD_SETLK\e[39m" << frg::endlog; return 0; } else if (request == F_OFD_SETLKW) { mlibc::infoLogger() << "\e[31mmlibc: F_OFD_SETLKW\e[39m" << frg::endlog; return 0; } else if (request == F_OFD_GETLK) { struct flock *lock = va_arg(args, struct flock *); lock->l_type = F_UNLCK; mlibc::infoLogger() << "\e[31mmlibc: F_OFD_GETLK is stubbed!\e[39m" << frg::endlog; return 0; } else if (request == F_ADD_SEALS) { auto seals = va_arg(args, int); auto handle = getHandleForFd(fd); if (!handle) return EBADF; managarm::fs::CntRequest req(getSysdepsAllocator()); req.set_req_type(managarm::fs::CntReqType::PT_ADD_SEALS); req.set_fd(fd); req.set_seals(seals); auto [offer, send_req, recv_resp] = exchangeMsgsSync( handle, helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::RecvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_req.error()); HEL_CHECK(recv_resp.error()); managarm::fs::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() == managarm::fs::Errors::ILLEGAL_OPERATION_TARGET) { mlibc::infoLogger( ) << "\e[31mmlibc: fcntl(F_ADD_SEALS) unimplemented for this file\e[39m" << frg::endlog; return EINVAL; } else if (resp.error() != managarm::fs::Errors::SUCCESS) { return resp.error() | toErrno; } *result = resp.seals(); return 0; } else if (request == F_GET_SEALS) { auto handle = getHandleForFd(fd); if (!handle) return EBADF; managarm::fs::CntRequest req(getSysdepsAllocator()); req.set_req_type(managarm::fs::CntReqType::PT_GET_SEALS); req.set_fd(fd); auto [offer, send_req, recv_resp] = exchangeMsgsSync( handle, helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::RecvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_req.error()); HEL_CHECK(recv_resp.error()); managarm::fs::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() == managarm::fs::Errors::ILLEGAL_OPERATION_TARGET) { mlibc::infoLogger( ) << "\e[31mmlibc: fcntl(F_GET_SEALS) unimplemented for this file\e[39m" << frg::endlog; return EINVAL; } else if (resp.error() != managarm::fs::Errors::SUCCESS) { return resp.error() | toErrno; } *result = resp.seals(); return 0; } else { mlibc::infoLogger() << "\e[31mmlibc: Unexpected fcntl() request: " << request << "\e[39m" << frg::endlog; return EINVAL; } } int sys_open_dir(const char *path, int *handle) { return sys_open(path, 0, 0, handle); } int sys_read_entries(int fd, void *buffer, size_t max_size, size_t *bytes_read) { SignalGuard sguard; auto handle = getHandleForFd(fd); if (!handle) return EBADF; managarm::fs::ReadEntriesRequest req(getSysdepsAllocator()); auto [offer, send_req, recv_resp] = exchangeMsgsSync( handle, helix_ng::offer( helix_ng::want_lane, helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); auto conversation = offer.descriptor(); HEL_CHECK(send_req.error()); HEL_CHECK(recv_resp.error()); auto preamble = bragi::read_preamble(recv_resp); __ensure(!preamble.error()); frg::vector tailBuffer{getSysdepsAllocator()}; tailBuffer.resize(preamble.tail_size()); auto [recv_tail] = exchangeMsgsSync( conversation.getHandle(), helix_ng::recvBuffer(tailBuffer.data(), tailBuffer.size()) ); HEL_CHECK(recv_tail.error()); auto resp = *bragi::parse_head_tail( recv_resp, tailBuffer, getSysdepsAllocator() ); recv_resp.reset(); if (resp.error() == managarm::fs::Errors::END_OF_FILE) { *bytes_read = 0; return 0; } else if (resp.error() != managarm::fs::Errors::SUCCESS) { return resp.error() | toErrno; } __ensure(max_size > sizeof(struct dirent)); auto ent = new (buffer) struct dirent; memset(ent, 0, sizeof(struct dirent)); memcpy(ent->d_name, resp.path().data(), resp.path().size()); ent->d_reclen = sizeof(struct dirent); *bytes_read = sizeof(struct dirent); return 0; } int sys_ttyname(int fd, char *buf, size_t size) { SignalGuard sguard; managarm::posix::CntRequest req(getSysdepsAllocator()); req.set_request_type(managarm::posix::CntReqType::TTY_NAME); req.set_fd(fd); auto [offer, send_req, recv_resp] = exchangeMsgsSync( getPosixLane(), helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_req.error()); HEL_CHECK(recv_resp.error()); managarm::posix::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; __ensure(size >= resp.path().size() + 1); memcpy(buf, resp.path().data(), size); buf[resp.path().size()] = '\0'; return 0; } int sys_fdatasync(int) { mlibc::infoLogger() << "\e[35mmlibc: fdatasync() is a no-op\e[39m" << frg::endlog; return 0; } int sys_getcwd(char *buffer, size_t size) { SignalGuard sguard; managarm::posix::CntRequest req(getSysdepsAllocator()); req.set_request_type(managarm::posix::CntReqType::GETCWD); req.set_size(size); auto [offer, send_req, recv_resp, recv_path] = exchangeMsgsSync( getPosixLane(), helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline(), helix_ng::recvBuffer(buffer, size) ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_req.error()); HEL_CHECK(recv_resp.error()); HEL_CHECK(recv_path.error()); managarm::posix::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; if (static_cast(resp.size()) >= size) return ERANGE; return 0; } int sys_vm_map(void *hint, size_t size, int prot, int flags, int fd, off_t offset, void **window) { SignalGuard sguard; managarm::posix::VmMapRequest req(getSysdepsAllocator()); req.set_address_hint(reinterpret_cast(hint)); req.set_size(size); req.set_mode(prot); req.set_flags(flags); req.set_fd(fd); req.set_rel_offset(offset); auto [offer, sendReq, recvResp] = exchangeMsgsSync( getPosixLane(), helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(sendReq.error()); HEL_CHECK(recvResp.error()); managarm::posix::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recvResp.data(), recvResp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; *window = reinterpret_cast(resp.offset()); return 0; } int sys_vm_remap(void *pointer, size_t size, size_t new_size, void **window) { SignalGuard sguard; managarm::posix::CntRequest req(getSysdepsAllocator()); req.set_request_type(managarm::posix::CntReqType::VM_REMAP); req.set_address(reinterpret_cast(pointer)); req.set_size(size); req.set_new_size(new_size); auto [offer, send_req, recv_resp] = exchangeMsgsSync( getPosixLane(), helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_req.error()); HEL_CHECK(recv_resp.error()); managarm::posix::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; *window = reinterpret_cast(resp.offset()); return 0; } int sys_vm_protect(void *pointer, size_t size, int prot) { SignalGuard sguard; managarm::posix::CntRequest req(getSysdepsAllocator()); req.set_request_type(managarm::posix::CntReqType::VM_PROTECT); req.set_address(reinterpret_cast(pointer)); req.set_size(size); req.set_mode(prot); auto [offer, send_req, recv_resp] = exchangeMsgsSync( getPosixLane(), helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_req.error()); HEL_CHECK(recv_resp.error()); managarm::posix::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; return 0; } int sys_vm_unmap(void *pointer, size_t size) { SignalGuard sguard; managarm::posix::CntRequest req(getSysdepsAllocator()); req.set_request_type(managarm::posix::CntReqType::VM_UNMAP); req.set_address(reinterpret_cast(pointer)); req.set_size(size); auto [offer, send_req, recv_resp] = exchangeMsgsSync( getPosixLane(), helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_req.error()); HEL_CHECK(recv_resp.error()); managarm::posix::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; return 0; } int sys_setsid(pid_t *sid) { SignalGuard sguard; managarm::posix::CntRequest req(getSysdepsAllocator()); req.set_request_type(managarm::posix::CntReqType::SETSID); auto [offer, send_req, recv_resp] = exchangeMsgsSync( getPosixLane(), helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_req.error()); HEL_CHECK(recv_resp.error()); managarm::posix::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) { *sid = -1; return resp.error() | toErrno; } *sid = resp.sid(); return 0; } int sys_tcgetattr(int fd, struct termios *attr) { int result; if (int e = sys_ioctl(fd, TCGETS, attr, &result); e) return e; return 0; } int sys_tcsetattr(int fd, int when, const struct termios *attr) { if (when < TCSANOW || when > TCSAFLUSH) return EINVAL; if (int e = sys_ioctl(fd, TCSETS, const_cast(attr), nullptr); e) return e; return 0; } int sys_tcdrain(int) { mlibc::infoLogger() << "\e[35mmlibc: tcdrain() is a stub\e[39m" << frg::endlog; return 0; } int sys_socket(int domain, int type_and_flags, int proto, int *fd) { constexpr int type_mask = int(0xF); constexpr int flags_mask = ~int(0xF); SignalGuard sguard; managarm::posix::SocketRequest req(getSysdepsAllocator()); req.set_domain(domain); req.set_socktype(type_and_flags & type_mask); req.set_protocol(proto); req.set_flags(type_and_flags & flags_mask); auto [offer, sendReq, recvResp] = exchangeMsgsSync( getPosixLane(), helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(sendReq.error()); HEL_CHECK(recvResp.error()); managarm::posix::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recvResp.data(), recvResp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; *fd = resp.fd(); return 0; } int sys_pipe(int *fds, int flags) { SignalGuard sguard; managarm::posix::CntRequest req(getSysdepsAllocator()); req.set_request_type(managarm::posix::CntReqType::PIPE_CREATE); req.set_flags(flags); auto [offer, send_req, recv_resp] = exchangeMsgsSync( getPosixLane(), helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_req.error()); HEL_CHECK(recv_resp.error()); managarm::posix::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; __ensure(resp.fds_size() == 2); fds[0] = resp.fds(0); fds[1] = resp.fds(1); return 0; } int sys_socketpair(int domain, int type_and_flags, int proto, int *fds) { constexpr int type_mask = int(0xF); constexpr int flags_mask = ~int(0xF); __ensure(!((type_and_flags & flags_mask) & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))); SignalGuard sguard; managarm::posix::SockpairRequest req(getSysdepsAllocator()); req.set_domain(domain); req.set_socktype(type_and_flags & type_mask); req.set_protocol(proto); req.set_flags(type_and_flags & flags_mask); auto [offer, sendReq, recvResp] = exchangeMsgsSync( getPosixLane(), helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(sendReq.error()); HEL_CHECK(recvResp.error()); managarm::posix::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recvResp.data(), recvResp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; __ensure(resp.fds_size() == 2); fds[0] = resp.fds(0); fds[1] = resp.fds(1); return 0; } int sys_msg_send(int sockfd, const struct msghdr *hdr, int flags, ssize_t *length) { frg::small_vector sglist{getSysdepsAllocator()}; auto handle = getHandleForFd(sockfd); if (!handle) return EBADF; size_t overall_size = 0; for (size_t i = 0; i < hdr->msg_iovlen; i++) { HelSgItem item{ .buffer = hdr->msg_iov[i].iov_base, .length = hdr->msg_iov[i].iov_len, }; sglist.push_back(item); overall_size += hdr->msg_iov[i].iov_len; } SignalGuard sguard; managarm::fs::SendMsgRequest req(getSysdepsAllocator()); req.set_flags(flags); req.set_size(overall_size); req.set_has_cmsg_creds(false); req.set_has_cmsg_rights(false); for (auto cmsg = CMSG_FIRSTHDR(hdr); cmsg; cmsg = CMSG_NXTHDR(hdr, cmsg)) { __ensure(cmsg->cmsg_level == SOL_SOCKET); __ensure(cmsg->cmsg_len >= sizeof(struct cmsghdr)); if (cmsg->cmsg_type == SCM_CREDENTIALS) { req.set_has_cmsg_creds(true); size_t size = cmsg->cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr)); __ensure(size == sizeof(struct ucred)); struct ucred creds; memcpy(&creds, CMSG_DATA(cmsg), sizeof(struct ucred)); req.set_creds_pid(creds.pid); req.set_creds_uid(creds.uid); req.set_creds_gid(creds.gid); } else if (cmsg->cmsg_type == SCM_RIGHTS) { req.set_has_cmsg_rights(true); size_t size = cmsg->cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr)); __ensure(!(size % sizeof(int))); for (size_t off = 0; off < size; off += sizeof(int)) { int fd; memcpy(&fd, CMSG_DATA(cmsg) + off, sizeof(int)); req.add_fds(fd); } } else { mlibc::infoLogger( ) << "mlibc: sys_msg_send only supports SCM_RIGHTS or SCM_CREDENTIALS, got: " << cmsg->cmsg_type << "!" << frg::endlog; return EINVAL; } } auto [offer, send_head, send_tail, send_data, imbue_creds, send_addr, recv_resp] = exchangeMsgsSync( handle, helix_ng::offer( helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), helix_ng::sendBufferSg(sglist.data(), hdr->msg_iovlen), helix_ng::imbueCredentials(), helix_ng::sendBuffer(hdr->msg_name, hdr->msg_namelen), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_head.error()); HEL_CHECK(send_tail.error()); HEL_CHECK(send_data.error()); HEL_CHECK(imbue_creds.error()); HEL_CHECK(send_addr.error()); HEL_CHECK(recv_resp.error()); managarm::fs::SendMsgReply resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::fs::Errors::SUCCESS) return resp.error() | toErrno; *length = resp.size(); return 0; } int sys_msg_recv(int sockfd, struct msghdr *hdr, int flags, ssize_t *length) { if (!hdr->msg_iovlen) { return EMSGSIZE; } auto handle = getHandleForFd(sockfd); if (!handle) return EBADF; SignalGuard sguard; managarm::fs::RecvMsgRequest req(getSysdepsAllocator()); req.set_flags(flags); req.set_size(hdr->msg_iov[0].iov_len); req.set_addr_size(hdr->msg_namelen); req.set_ctrl_size(hdr->msg_controllen); auto [offer, send_req, imbue_creds, recv_resp, recv_addr, recv_data, recv_ctrl] = exchangeMsgsSync( handle, helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::imbueCredentials(), helix_ng::recvInline(), helix_ng::recvBuffer(hdr->msg_name, hdr->msg_namelen), helix_ng::recvBuffer(hdr->msg_iov[0].iov_base, hdr->msg_iov[0].iov_len), helix_ng::recvBuffer(hdr->msg_control, hdr->msg_controllen) ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_req.error()); HEL_CHECK(imbue_creds.error()); HEL_CHECK(recv_resp.error()); managarm::fs::RecvMsgReply resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::fs::Errors::SUCCESS) { return resp.error() | toErrno; } else { __ensure(resp.error() == managarm::fs::Errors::SUCCESS); HEL_CHECK(recv_addr.error()); HEL_CHECK(recv_data.error()); HEL_CHECK(recv_ctrl.error()); hdr->msg_namelen = resp.addr_size(); hdr->msg_controllen = recv_ctrl.actualLength(); hdr->msg_flags = resp.flags(); *length = resp.ret_val(); return 0; } } int sys_pselect( int, fd_set *read_set, fd_set *write_set, fd_set *except_set, const struct timespec *timeout, const sigset_t *sigmask, int *num_events ) { // TODO: Do not keep errors from epoll (?). int fd = epoll_create1(0); if (fd == -1) return -1; for (int k = 0; k < FD_SETSIZE; k++) { struct epoll_event ev; memset(&ev, 0, sizeof(struct epoll_event)); if (read_set && FD_ISSET(k, read_set)) ev.events |= EPOLLIN; // TODO: Additional events. if (write_set && FD_ISSET(k, write_set)) ev.events |= EPOLLOUT; // TODO: Additional events. if (except_set && FD_ISSET(k, except_set)) ev.events |= EPOLLPRI; if (!ev.events) continue; ev.data.u32 = k; if (epoll_ctl(fd, EPOLL_CTL_ADD, k, &ev)) return -1; } struct epoll_event evnts[16]; int n = epoll_pwait( fd, evnts, 16, timeout ? (timeout->tv_sec * 1000 + timeout->tv_nsec / 100) : -1, sigmask ); if (n == -1) return -1; fd_set res_read_set; fd_set res_write_set; fd_set res_except_set; FD_ZERO(&res_read_set); FD_ZERO(&res_write_set); FD_ZERO(&res_except_set); int m = 0; for (int i = 0; i < n; i++) { int k = evnts[i].data.u32; if (read_set && FD_ISSET(k, read_set) && evnts[i].events & (EPOLLIN | EPOLLERR | EPOLLHUP)) { FD_SET(k, &res_read_set); m++; } if (write_set && FD_ISSET(k, write_set) && evnts[i].events & (EPOLLOUT | EPOLLERR | EPOLLHUP)) { FD_SET(k, &res_write_set); m++; } if (except_set && FD_ISSET(k, except_set) && evnts[i].events & EPOLLPRI) { FD_SET(k, &res_except_set); m++; } } if (close(fd)) __ensure("close() failed on epoll file"); if (read_set) memcpy(read_set, &res_read_set, sizeof(fd_set)); if (write_set) memcpy(write_set, &res_write_set, sizeof(fd_set)); if (except_set) memcpy(except_set, &res_except_set, sizeof(fd_set)); *num_events = m; return 0; } int sys_poll(struct pollfd *fds, nfds_t count, int timeout, int *num_events) { __ensure(timeout >= 0 || timeout == -1); // TODO: Report errors correctly. SignalGuard sguard; managarm::posix::CntRequest req(getSysdepsAllocator()); req.set_request_type(managarm::posix::CntReqType::EPOLL_CALL); req.set_timeout(timeout > 0 ? int64_t{timeout} * 1000000 : timeout); req.set_cancellation_id(allocateCancellationId()); for (nfds_t i = 0; i < count; i++) { req.add_fds(fds[i].fd); req.add_events(fds[i].events); } auto [offer, send_req, recv_resp] = exchangeMsgsSyncCancellable( getPosixLane(), req.cancellation_id(), -1, helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_req.error()); HEL_CHECK(recv_resp.error()); managarm::posix::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) { return resp.error() | toErrno; } else { __ensure(resp.events_size() == count); int m = 0; for (nfds_t i = 0; i < count; i++) { if (resp.events(i)) m++; fds[i].revents = resp.events(i); } *num_events = m; return 0; } } int sys_epoll_create(int flags, int *fd) { // Some applications assume EPOLL_CLOEXEC and O_CLOEXEC to be the same. // They are on linux, but not yet on managarm. __ensure(!(flags & ~(EPOLL_CLOEXEC | O_CLOEXEC))); SignalGuard sguard; uint32_t proto_flags = 0; if (flags & EPOLL_CLOEXEC || flags & O_CLOEXEC) proto_flags |= managarm::posix::OpenFlags::OF_CLOEXEC; managarm::posix::CntRequest req(getSysdepsAllocator()); req.set_request_type(managarm::posix::CntReqType::EPOLL_CREATE); req.set_flags(proto_flags); auto [offer, send_req, recv_resp] = exchangeMsgsSync( getPosixLane(), helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_req.error()); HEL_CHECK(recv_resp.error()); managarm::posix::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; *fd = resp.fd(); return 0; } int sys_epoll_ctl(int epfd, int mode, int fd, struct epoll_event *ev) { SignalGuard sguard; managarm::posix::CntRequest req(getSysdepsAllocator()); if (mode == EPOLL_CTL_ADD) { __ensure(ev); req.set_request_type(managarm::posix::CntReqType::EPOLL_ADD); req.set_flags(ev->events); req.set_cookie(ev->data.u64); } else if (mode == EPOLL_CTL_MOD) { __ensure(ev); req.set_request_type(managarm::posix::CntReqType::EPOLL_MODIFY); req.set_flags(ev->events); req.set_cookie(ev->data.u64); } else if (mode == EPOLL_CTL_DEL) { req.set_request_type(managarm::posix::CntReqType::EPOLL_DELETE); } else { mlibc::panicLogger() << "\e[31mmlibc: Illegal epoll_ctl() mode\e[39m" << frg::endlog; } req.set_fd(epfd); req.set_newfd(fd); auto [offer, send_req, recv_resp] = exchangeMsgsSync( getPosixLane(), helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_req.error()); HEL_CHECK(recv_resp.error()); managarm::posix::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; return 0; } int sys_epoll_pwait( int epfd, struct epoll_event *ev, int n, int timeout, const sigset_t *sigmask, int *raised ) { if (!(timeout >= 0 || timeout == -1)) return EINVAL; SignalGuard sguard; managarm::posix::CntRequest req(getSysdepsAllocator()); req.set_request_type(managarm::posix::CntReqType::EPOLL_WAIT); req.set_fd(epfd); req.set_size(n); req.set_timeout(timeout > 0 ? int64_t{timeout} * 1000000 : timeout); if (sigmask != nullptr) { req.set_sigmask(*reinterpret_cast(sigmask)); req.set_sigmask_needed(true); } else { req.set_sigmask_needed(false); } auto [offer, send_req, recv_resp, recv_data] = exchangeMsgsSync( getPosixLane(), helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline(), helix_ng::recvBuffer(ev, n * sizeof(struct epoll_event)) ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_req.error()); HEL_CHECK(recv_resp.error()); HEL_CHECK(recv_data.error()); managarm::posix::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; __ensure(!(recv_data.actualLength() % sizeof(struct epoll_event))); *raised = recv_data.actualLength() / sizeof(struct epoll_event); return 0; } int sys_timerfd_create(int clockid, int flags, int *fd) { SignalGuard sguard; managarm::posix::TimerFdCreateRequest req(getSysdepsAllocator()); req.set_clock(clockid); req.set_flags(flags); auto [offer, sendReq, recvResp] = exchangeMsgsSync( getPosixLane(), helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(sendReq.error()); HEL_CHECK(recvResp.error()); managarm::posix::TimerFdCreateResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recvResp.data(), recvResp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; *fd = resp.fd(); return 0; } int sys_timerfd_settime( int fd, int flags, const struct itimerspec *value, struct itimerspec *oldvalue ) { SignalGuard sguard; managarm::posix::TimerFdSetRequest req(getSysdepsAllocator()); req.set_fd(fd); req.set_flags(flags); req.set_value_sec(value->it_value.tv_sec); req.set_value_nsec(value->it_value.tv_nsec); req.set_interval_sec(value->it_interval.tv_sec); req.set_interval_nsec(value->it_interval.tv_nsec); auto [offer, sendReq, recvResp] = exchangeMsgsSync( getPosixLane(), helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(sendReq.error()); HEL_CHECK(recvResp.error()); managarm::posix::TimerFdSetResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recvResp.data(), recvResp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; if (oldvalue) { oldvalue->it_value.tv_sec = resp.value_sec(); oldvalue->it_value.tv_nsec = resp.value_nsec(); oldvalue->it_interval.tv_sec = resp.interval_sec(); oldvalue->it_interval.tv_nsec = resp.interval_nsec(); } return 0; } int sys_timerfd_gettime(int fd, struct itimerspec *its) { SignalGuard sguard; managarm::posix::TimerFdGetRequest req(getSysdepsAllocator()); req.set_fd(fd); auto [offer, sendReq, recvResp] = exchangeMsgsSync( getPosixLane(), helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(sendReq.error()); HEL_CHECK(recvResp.error()); managarm::posix::TimerFdGetResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recvResp.data(), recvResp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; if (its) { its->it_value.tv_sec = resp.value_sec(); its->it_value.tv_nsec = resp.value_nsec(); its->it_interval.tv_sec = resp.interval_sec(); its->it_interval.tv_nsec = resp.interval_nsec(); } else { return EFAULT; } return 0; } int sys_signalfd_create(const sigset_t *masks, int flags, int *fd) { __ensure(!(flags & ~(SFD_CLOEXEC | SFD_NONBLOCK))); uint32_t proto_flags = 0; if (flags & SFD_CLOEXEC) proto_flags |= managarm::posix::OpenFlags::OF_CLOEXEC; if (flags & SFD_NONBLOCK) proto_flags |= managarm::posix::OpenFlags::OF_NONBLOCK; SignalGuard sguard; managarm::posix::CntRequest req(getSysdepsAllocator()); req.set_request_type(managarm::posix::CntReqType::SIGNALFD_CREATE); req.set_flags(proto_flags); req.set_sigset(*reinterpret_cast(masks)); req.set_fd(*fd); auto [offer, send_req, recv_resp] = exchangeMsgsSync( getPosixLane(), helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_req.error()); HEL_CHECK(recv_resp.error()); managarm::posix::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; *fd = resp.fd(); return 0; } int sys_pidfd_open(pid_t pid, unsigned int flags, int *outfd) { SignalGuard sguard; managarm::posix::PidfdOpenRequest req(getSysdepsAllocator()); req.set_pid(pid); req.set_flags(flags); auto [offer, send_req, recv_resp] = exchangeMsgsSync( getPosixLane(), helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_req.error()); HEL_CHECK(recv_resp.error()); managarm::posix::PidfdOpenResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; *outfd = resp.fd(); return 0; } int sys_pidfd_getpid(int pidfd, pid_t *outpid) { SignalGuard sguard; managarm::posix::PidfdGetPidRequest req(getSysdepsAllocator()); req.set_pidfd(pidfd); auto [offer, send_req, recv_resp] = exchangeMsgsSync( getPosixLane(), helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_req.error()); HEL_CHECK(recv_resp.error()); managarm::posix::PidfdGetPidResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; *outpid = resp.pid(); return 0; } int sys_pidfd_send_signal(int pidfd, int sig, siginfo_t *info, unsigned int flags) { SignalGuard sguard; if (info) { mlibc::infoLogger() << "mlibc: pidfd_send_signal does not support passing siginfo_t info" << frg::endlog; return EINVAL; } managarm::posix::PidfdSendSignalRequest req(getSysdepsAllocator()); req.set_pidfd(pidfd); req.set_signal(sig); req.set_flags(flags); auto [offer, send_req, recv_resp] = exchangeMsgsSync( getPosixLane(), helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_req.error()); HEL_CHECK(recv_resp.error()); managarm::posix::PidfdSendSignalResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; return 0; } int sys_reboot(int command) { if (command != RB_POWER_OFF && command != RB_AUTOBOOT) { mlibc::infoLogger( ) << "mlibc: Anything other than power off or reboot is not supported yet!" << frg::endlog; return EINVAL; } SignalGuard sguard; managarm::posix::RebootRequest req(getSysdepsAllocator()); req.set_cmd(command); auto [offer, sendReq, recvResp] = exchangeMsgsSync( getPosixLane(), helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(sendReq.error()); HEL_CHECK(recvResp.error()); managarm::posix::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recvResp.data(), recvResp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; return 0; } int sys_inotify_create(int flags, int *fd) { __ensure(!(flags & ~(IN_CLOEXEC | IN_NONBLOCK))); SignalGuard sguard; uint32_t proto_flags = 0; if (flags & IN_CLOEXEC) proto_flags |= managarm::posix::OpenFlags::OF_CLOEXEC; if (flags & IN_NONBLOCK) proto_flags |= managarm::posix::OpenFlags::OF_NONBLOCK; managarm::posix::InotifyCreateRequest req(getSysdepsAllocator()); req.set_flags(proto_flags); auto [offer, sendReq, recvResp] = exchangeMsgsSync( getPosixLane(), helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(sendReq.error()); HEL_CHECK(recvResp.error()); managarm::posix::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recvResp.data(), recvResp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; *fd = resp.fd(); return 0; } int sys_inotify_add_watch(int ifd, const char *path, uint32_t mask, int *wd) { SignalGuard sguard; managarm::posix::InotifyAddRequest req(getSysdepsAllocator()); req.set_fd(ifd); req.set_path(frg::string(getSysdepsAllocator(), path)); req.set_flags(mask); 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()); managarm::posix::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; *wd = resp.wd(); return 0; } int sys_inotify_rm_watch(int ifd, int wd) { SignalGuard sguard; managarm::posix::InotifyRmRequest req(getSysdepsAllocator()); req.set_ifd(ifd); req.set_wd(wd); auto [offer, send_head, recv_resp] = exchangeMsgsSync( getPosixLane(), helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_head.error()); HEL_CHECK(recv_resp.error()); managarm::posix::InotifyRmReply resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; return 0; } int sys_eventfd_create(unsigned int initval, int flags, int *fd) { if (flags & ~(EFD_NONBLOCK | EFD_CLOEXEC | EFD_SEMAPHORE)) return EINVAL; SignalGuard sguard; uint32_t proto_flags = 0; if (flags & EFD_NONBLOCK) proto_flags |= managarm::posix::EventFdFlags::NONBLOCK; if (flags & EFD_CLOEXEC) proto_flags |= managarm::posix::EventFdFlags::CLOEXEC; if (flags & EFD_SEMAPHORE) proto_flags |= managarm::posix::EventFdFlags::SEMAPHORE; managarm::posix::EventfdCreateRequest req(getSysdepsAllocator()); req.set_flags(proto_flags); req.set_initval(initval); auto [offer, sendReq, recvResp] = exchangeMsgsSync( getPosixLane(), helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(sendReq.error()); HEL_CHECK(recvResp.error()); managarm::posix::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recvResp.data(), recvResp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; *fd = resp.fd(); return 0; } int sys_open(const char *path, int flags, mode_t mode, int *fd) { return sys_openat(AT_FDCWD, path, flags, mode, fd); } int sys_openat(int dirfd, const char *path, int flags, mode_t mode, int *fd) { SignalGuard sguard; // We do not support O_TMPFILE. if (flags & O_TMPFILE) return EOPNOTSUPP; uint32_t proto_flags = 0; if (flags & O_APPEND) proto_flags |= managarm::posix::OpenFlags::OF_APPEND; if (flags & O_CREAT) proto_flags |= managarm::posix::OpenFlags::OF_CREATE; if (flags & O_EXCL) proto_flags |= managarm::posix::OpenFlags::OF_EXCLUSIVE; if (flags & O_NONBLOCK) proto_flags |= managarm::posix::OpenFlags::OF_NONBLOCK; if (flags & O_TRUNC) proto_flags |= managarm::posix::OpenFlags::OF_TRUNC; if (flags & O_CLOEXEC) proto_flags |= managarm::posix::OpenFlags::OF_CLOEXEC; if (flags & O_NOCTTY) proto_flags |= managarm::posix::OpenFlags::OF_NOCTTY; if (flags & O_NOFOLLOW) proto_flags |= managarm::posix::OpenFlags::OF_NOFOLLOW; if (flags & O_DIRECTORY) proto_flags |= managarm::posix::OpenFlags::OF_DIRECTORY; if (flags & O_PATH) proto_flags |= managarm::posix::OpenFlags::OF_PATH; else if ((flags & O_ACCMODE) == O_RDONLY) proto_flags |= managarm::posix::OpenFlags::OF_RDONLY; else if ((flags & O_ACCMODE) == O_WRONLY) proto_flags |= managarm::posix::OpenFlags::OF_WRONLY; else if ((flags & O_ACCMODE) == O_RDWR) proto_flags |= managarm::posix::OpenFlags::OF_RDWR; managarm::posix::OpenAtRequest req(getSysdepsAllocator()); req.set_fd(dirfd); req.set_path(frg::string(getSysdepsAllocator(), path)); req.set_flags(proto_flags); req.set_mode(mode); auto [offer, sendHead, sendTail, recvResp] = exchangeMsgsSync( getPosixLane(), helix_ng::offer( helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(sendHead.error()); HEL_CHECK(sendTail.error()); HEL_CHECK(recvResp.error()); managarm::posix::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recvResp.data(), recvResp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; *fd = resp.fd(); return 0; } int sys_mkfifoat(int dirfd, const char *path, mode_t mode) { SignalGuard sguard; managarm::posix::MkfifoAtRequest req(getSysdepsAllocator()); req.set_fd(dirfd); req.set_path(frg::string(getSysdepsAllocator(), path)); req.set_mode(mode); 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()); managarm::posix::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; return 0; } int sys_mknodat(int dirfd, const char *path, int mode, int dev) { SignalGuard sguard; managarm::posix::MknodAtRequest req(getSysdepsAllocator()); req.set_dirfd(dirfd); req.set_path(frg::string(getSysdepsAllocator(), path)); req.set_mode(mode); req.set_device(dev); 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()); managarm::posix::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; return 0; } int sys_read(int fd, void *data, size_t max_size, ssize_t *bytes_read) { SignalGuard sguard; auto handle = getHandleForFd(fd); if (!handle) return EBADF; managarm::fs::CntRequest req(getSysdepsAllocator()); req.set_req_type(managarm::fs::CntReqType::READ); req.set_fd(fd); req.set_size(max_size); req.set_cancellation_id(allocateCancellationId()); frg::string ser(getSysdepsAllocator()); req.SerializeToString(&ser); auto [offer, send_req, imbue_creds, recv_resp, recv_data] = exchangeMsgsSyncCancellable( handle, req.cancellation_id(), fd, helix_ng::offer( helix_ng::sendBuffer(ser.data(), ser.size()), helix_ng::imbueCredentials(), helix_ng::recvInline(), helix_ng::recvBuffer(data, max_size) ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_req.error()); HEL_CHECK(imbue_creds.error()); HEL_CHECK(recv_resp.error()); managarm::fs::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); HEL_CHECK(recv_data.error()); *bytes_read = recv_data.actualLength(); return resp.error() | toErrno; } int sys_readv(int fd, const struct iovec *iovs, int iovc, ssize_t *bytes_read) { for (int i = 0; i < iovc; i++) { ssize_t intermed = 0; if (int e = sys_read(fd, iovs[i].iov_base, iovs[i].iov_len, &intermed); e) return e; else if (intermed == 0) break; *bytes_read += intermed; } return 0; } int sys_write(int fd, const void *data, size_t size, ssize_t *bytes_written) { SignalGuard sguard; auto handle = getHandleForFd(fd); if (!handle) return EBADF; managarm::fs::CntRequest req(getSysdepsAllocator()); req.set_req_type(managarm::fs::CntReqType::WRITE); req.set_fd(fd); req.set_size(size); auto [offer, send_req, imbue_creds, send_data, recv_resp] = exchangeMsgsSync( handle, helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::imbueCredentials(), helix_ng::sendBuffer(data, size), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_req.error()); HEL_CHECK(imbue_creds.error()); HEL_CHECK(send_data.error()); HEL_CHECK(recv_resp.error()); managarm::fs::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::fs::Errors::SUCCESS) return resp.error() | toErrno; if (bytes_written) *bytes_written = resp.size(); return 0; } int sys_writev(int fd, const struct iovec *iovs, int iovc, ssize_t *bytes_written) { frg::small_vector sglist{getSysdepsAllocator()}; size_t overall_size = 0; for (int i = 0; i < iovc; i++) { HelSgItem item{ .buffer = iovs[i].iov_base, .length = iovs[i].iov_len, }; sglist.push_back(item); overall_size += iovs[i].iov_len; } SignalGuard sguard; auto handle = getHandleForFd(fd); if (!handle) return EBADF; managarm::fs::CntRequest req(getSysdepsAllocator()); req.set_req_type(managarm::fs::CntReqType::WRITE); req.set_fd(fd); req.set_size(overall_size); auto [offer, send_req, imbue_creds, send_data, recv_resp] = exchangeMsgsSync( handle, helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::imbueCredentials(), helix_ng::sendBufferSg(sglist.data(), iovc), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_req.error()); HEL_CHECK(imbue_creds.error()); HEL_CHECK(send_data.error()); HEL_CHECK(recv_resp.error()); managarm::fs::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::fs::Errors::SUCCESS) return resp.error() | toErrno; if (bytes_written) *bytes_written = resp.size(); return 0; } int sys_pread(int fd, void *buf, size_t n, off_t off, ssize_t *bytes_read) { SignalGuard sguard; auto handle = getHandleForFd(fd); if (!handle) return EBADF; managarm::fs::CntRequest req(getSysdepsAllocator()); req.set_req_type(managarm::fs::CntReqType::PT_PREAD); req.set_fd(fd); req.set_size(n); req.set_offset(off); auto [offer, send_req, imbue_creds, recv_resp, recv_data] = exchangeMsgsSync( handle, helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::imbueCredentials(), helix_ng::recvInline(), helix_ng::recvBuffer(buf, n) ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_req.error()); HEL_CHECK(imbue_creds.error()); HEL_CHECK(recv_resp.error()); managarm::fs::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() == managarm::fs::Errors::END_OF_FILE) { *bytes_read = 0; return 0; } else if (resp.error() == managarm::fs::Errors::SUCCESS) { HEL_CHECK(recv_data.error()); *bytes_read = recv_data.actualLength(); return 0; } return resp.error() | toErrno; } int sys_pwrite(int fd, const void *buf, size_t n, off_t off, ssize_t *bytes_written) { SignalGuard sguard; auto handle = getHandleForFd(fd); if (!handle) return EBADF; managarm::fs::CntRequest req(getSysdepsAllocator()); req.set_req_type(managarm::fs::CntReqType::PT_PWRITE); req.set_fd(fd); req.set_size(n); req.set_offset(off); frg::string ser(getSysdepsAllocator()); req.SerializeToString(&ser); auto [offer, send_head, imbue_creds, to_write, recv_resp] = exchangeMsgsSync( handle, helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::imbueCredentials(), helix_ng::sendBuffer(buf, n), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_head.error()); HEL_CHECK(imbue_creds.error()); HEL_CHECK(to_write.error()); HEL_CHECK(recv_resp.error()); managarm::fs::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::fs::Errors::SUCCESS) return resp.error() | toErrno; *bytes_written = n; return 0; } int sys_seek(int fd, off_t offset, int whence, off_t *new_offset) { SignalGuard sguard; auto handle = getHandleForFd(fd); if (!handle) return EBADF; managarm::fs::CntRequest req(getSysdepsAllocator()); req.set_fd(fd); req.set_rel_offset(offset); if (whence == SEEK_SET) { req.set_req_type(managarm::fs::CntReqType::SEEK_ABS); } else if (whence == SEEK_CUR) { req.set_req_type(managarm::fs::CntReqType::SEEK_REL); } else if (whence == SEEK_END) { req.set_req_type(managarm::fs::CntReqType::SEEK_EOF); } else { return EINVAL; } frg::string ser(getSysdepsAllocator()); req.SerializeToString(&ser); auto [offer, send_req, recv_resp] = exchangeMsgsSync( handle, helix_ng::offer(helix_ng::sendBuffer(ser.data(), ser.size()), helix_ng::recvInline()) ); HEL_CHECK(offer.error()); HEL_CHECK(send_req.error()); HEL_CHECK(recv_resp.error()); managarm::fs::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::fs::Errors::SUCCESS) return resp.error() | toErrno; *new_offset = resp.offset(); return 0; } int sys_close(int fd) { SignalGuard sguard; managarm::posix::CloseRequest req(getSysdepsAllocator()); req.set_fd(fd); auto [offer, sendReq, recvResp] = exchangeMsgsSync( getPosixLane(), helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(sendReq.error()); HEL_CHECK(recvResp.error()); managarm::posix::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recvResp.data(), recvResp.length()); return resp.error() | toErrno; } int sys_dup(int fd, int flags, int *newfd) { SignalGuard sguard; __ensure(!(flags & ~(O_CLOEXEC))); uint32_t proto_flags = 0; if (flags & O_CLOEXEC) proto_flags |= managarm::posix::OpenFlags::OF_CLOEXEC; managarm::posix::CntRequest req(getSysdepsAllocator()); req.set_request_type(managarm::posix::CntReqType::DUP); req.set_fd(fd); req.set_flags(proto_flags); auto [offer, send_req, recv_resp] = exchangeMsgsSync( getPosixLane(), helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_req.error()); HEL_CHECK(recv_resp.error()); managarm::posix::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; *newfd = resp.fd(); return 0; } int sys_dup2(int fd, int flags, int newfd) { return do_dup2(fd, flags, newfd, false, nullptr); } int sys_stat(fsfd_target fsfdt, int fd, const char *path, int flags, struct stat *result) { SignalGuard sguard; managarm::posix::FstatAtRequest req(getSysdepsAllocator()); if (fsfdt == fsfd_target::path) { req.set_fd(AT_FDCWD); req.set_path(frg::string(getSysdepsAllocator(), path)); } else if (fsfdt == fsfd_target::fd) { flags |= AT_EMPTY_PATH; req.set_fd(fd); } else { __ensure(fsfdt == fsfd_target::fd_path); req.set_fd(fd); req.set_path(frg::string(getSysdepsAllocator(), path)); } if (!(flags & AT_EMPTY_PATH) && (!path || !strlen(path))) { return ENOENT; } 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()); managarm::posix::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; memset(result, 0, sizeof(struct stat)); switch (resp.file_type()) { case managarm::posix::FileType::FT_REGULAR: result->st_mode = S_IFREG; break; case managarm::posix::FileType::FT_DIRECTORY: result->st_mode = S_IFDIR; break; case managarm::posix::FileType::FT_SYMLINK: result->st_mode = S_IFLNK; break; case managarm::posix::FileType::FT_CHAR_DEVICE: result->st_mode = S_IFCHR; break; case managarm::posix::FileType::FT_BLOCK_DEVICE: result->st_mode = S_IFBLK; break; case managarm::posix::FileType::FT_SOCKET: result->st_mode = S_IFSOCK; break; case managarm::posix::FileType::FT_FIFO: result->st_mode = S_IFIFO; break; default: __ensure(!resp.file_type()); } result->st_dev = 1; result->st_ino = resp.fs_inode(); result->st_mode |= resp.mode(); result->st_nlink = resp.num_links(); result->st_uid = resp.uid(); result->st_gid = resp.gid(); result->st_rdev = resp.ref_devnum(); result->st_size = resp.file_size(); result->st_atim.tv_sec = resp.atime_secs(); result->st_atim.tv_nsec = resp.atime_nanos(); result->st_mtim.tv_sec = resp.mtime_secs(); result->st_mtim.tv_nsec = resp.mtime_nanos(); result->st_ctim.tv_sec = resp.ctime_secs(); result->st_ctim.tv_nsec = resp.ctime_nanos(); result->st_blksize = 4096; result->st_blocks = resp.file_size() / 512 + 1; return 0; } int sys_statx(int dirfd, const char *pathname, int flags, unsigned int mask, struct statx *statxbuf) { SignalGuard sguard; managarm::posix::FstatAtRequest req(getSysdepsAllocator()); if (pathname) req.set_path(frg::string(getSysdepsAllocator(), pathname)); req.set_fd(dirfd); if (flags & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH | AT_NO_AUTOMOUNT | AT_STATX_SYNC_AS_STAT | AT_STATX_FORCE_SYNC | AT_STATX_DONT_SYNC)) { return EINVAL; } if (!(flags & AT_EMPTY_PATH) && (!pathname || !strlen(pathname))) { return ENOENT; } 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()); managarm::posix::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; else { __ensure(resp.error() == managarm::posix::Errors::SUCCESS); memset(statxbuf, 0, sizeof(struct statx)); switch (resp.file_type()) { case managarm::posix::FileType::FT_REGULAR: statxbuf->stx_mode = S_IFREG; break; case managarm::posix::FileType::FT_DIRECTORY: statxbuf->stx_mode = S_IFDIR; break; case managarm::posix::FileType::FT_SYMLINK: statxbuf->stx_mode = S_IFLNK; break; case managarm::posix::FileType::FT_CHAR_DEVICE: statxbuf->stx_mode = S_IFCHR; break; case managarm::posix::FileType::FT_BLOCK_DEVICE: statxbuf->stx_mode = S_IFBLK; break; case managarm::posix::FileType::FT_SOCKET: statxbuf->stx_mode = S_IFSOCK; break; case managarm::posix::FileType::FT_FIFO: statxbuf->stx_mode = S_IFIFO; break; default: __ensure(!resp.file_type()); } statxbuf->stx_mask = mask; // TODO: Properly? // statxbuf->st_dev = 1; statxbuf->stx_ino = resp.fs_inode(); statxbuf->stx_mode |= resp.mode(); statxbuf->stx_nlink = resp.num_links(); statxbuf->stx_uid = resp.uid(); statxbuf->stx_gid = resp.gid(); statxbuf->stx_rdev_major = major(resp.ref_devnum()); statxbuf->stx_rdev_minor = minor(resp.ref_devnum()); statxbuf->stx_size = resp.file_size(); statxbuf->stx_atime.tv_sec = resp.atime_secs(); statxbuf->stx_atime.tv_nsec = resp.atime_nanos(); statxbuf->stx_mtime.tv_sec = resp.mtime_secs(); statxbuf->stx_mtime.tv_nsec = resp.mtime_nanos(); statxbuf->stx_ctime.tv_sec = resp.ctime_secs(); statxbuf->stx_ctime.tv_nsec = resp.ctime_nanos(); statxbuf->stx_blksize = 4096; statxbuf->stx_blocks = resp.file_size() / 512 + 1; return 0; } } int sys_readlink(const char *path, void *data, size_t max_size, ssize_t *length) { return sys_readlinkat(AT_FDCWD, path, data, max_size, length); } int sys_readlinkat(int dirfd, const char *path, void *data, size_t max_size, ssize_t *length) { SignalGuard sguard; managarm::posix::ReadlinkAtRequest req(getSysdepsAllocator()); req.set_fd(dirfd); req.set_path(frg::string(getSysdepsAllocator(), path)); auto [offer, send_head, send_tail, recv_resp, recv_data] = exchangeMsgsSync( getPosixLane(), helix_ng::offer( helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), helix_ng::recvInline(), helix_ng::recvBuffer(data, max_size) ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_head.error()); HEL_CHECK(send_tail.error()); HEL_CHECK(recv_resp.error()); managarm::posix::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; *length = recv_data.actualLength(); return 0; } int sys_rmdir(const char *path) { SignalGuard sguard; managarm::posix::RmdirRequest req(getSysdepsAllocator()); req.set_path(frg::string(getSysdepsAllocator(), path)); 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()); managarm::posix::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; return 0; } int sys_ftruncate(int fd, size_t size) { SignalGuard sguard; auto handle = getHandleForFd(fd); if (!handle) return EBADF; managarm::fs::CntRequest req(getSysdepsAllocator()); req.set_req_type(managarm::fs::CntReqType::PT_TRUNCATE); req.set_size(size); auto [offer, send_req, recv_resp] = exchangeMsgsSync( handle, helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_req.error()); HEL_CHECK(recv_resp.error()); managarm::fs::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::fs::Errors::SUCCESS) return resp.error() | toErrno; return 0; } int sys_fallocate(int fd, off_t offset, size_t size) { SignalGuard sguard; auto handle = getHandleForFd(fd); if (!handle) return EBADF; managarm::fs::CntRequest req(getSysdepsAllocator()); req.set_req_type(managarm::fs::CntReqType::PT_FALLOCATE); req.set_rel_offset(offset); req.set_size(size); auto [offer, send_req, recv_resp] = exchangeMsgsSync( handle, helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_req.error()); HEL_CHECK(recv_resp.error()); managarm::fs::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::fs::Errors::SUCCESS) return resp.error() | toErrno; return 0; } int sys_unlinkat(int fd, const char *path, int flags) { SignalGuard sguard; managarm::posix::UnlinkAtRequest req(getSysdepsAllocator()); req.set_fd(fd); req.set_path(frg::string(getSysdepsAllocator(), path)); 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()); managarm::posix::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; return 0; } int sys_access(const char *path, int mode) { return sys_faccessat(AT_FDCWD, path, mode, 0); } int sys_faccessat(int dirfd, const char *pathname, int, int flags) { SignalGuard sguard; managarm::posix::AccessAtRequest req(getSysdepsAllocator()); req.set_path(frg::string(getSysdepsAllocator(), pathname)); req.set_fd(dirfd); 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()); managarm::posix::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; return 0; } int sys_flock(int fd, int opts) { SignalGuard sguard; managarm::fs::CntRequest req(getSysdepsAllocator()); req.set_req_type(managarm::fs::CntReqType::FLOCK); req.set_fd(fd); req.set_flock_flags(opts); auto handle = getHandleForFd(fd); if (!handle) { return EBADF; } auto [offer, send_req, recv_resp] = exchangeMsgsSync( handle, helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_req.error()); HEL_CHECK(recv_resp.error()); managarm::posix::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; return 0; } int sys_isatty(int fd) { SignalGuard sguard; managarm::posix::IsTtyRequest req(getSysdepsAllocator()); req.set_fd(fd); auto [offer, sendReq, recvResp] = exchangeMsgsSync( getPosixLane(), helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(sendReq.error()); HEL_CHECK(recvResp.error()); managarm::posix::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recvResp.data(), recvResp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; if (resp.mode()) return 0; return ENOTTY; } int sys_chmod(const char *pathname, mode_t mode) { return sys_fchmodat(AT_FDCWD, pathname, mode, 0); } int sys_fchmod(int fd, mode_t mode) { return sys_fchmodat(fd, "", mode, AT_EMPTY_PATH); } int sys_fchmodat(int fd, const char *pathname, mode_t mode, int flags) { SignalGuard sguard; managarm::posix::FchmodAtRequest req(getSysdepsAllocator()); req.set_fd(fd); req.set_path(frg::string(getSysdepsAllocator(), pathname)); req.set_mode(mode); 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()); managarm::posix::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; return 0; } int sys_fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group, int flags) { (void)dirfd; (void)pathname; (void)owner; (void)group; (void)flags; mlibc::infoLogger() << "mlibc: sys_fchownat is a stub!" << frg::endlog; return 0; } int sys_umask(mode_t mode, mode_t *old) { SignalGuard sguard; managarm::posix::UmaskRequest req(getSysdepsAllocator()); req.set_newmask(mode); auto [offer, send_head, recv_resp] = exchangeMsgsSync( getPosixLane(), helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_head.error()); HEL_CHECK(recv_resp.error()); managarm::posix::UmaskResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); *old = resp.oldmask(); return 0; } int sys_utimensat(int dirfd, const char *pathname, const struct timespec times[2], int flags) { SignalGuard sguard; managarm::posix::UtimensAtRequest req(getSysdepsAllocator()); req.set_fd(dirfd); if (pathname != nullptr) req.set_path(frg::string(getSysdepsAllocator(), pathname)); if (times) { req.set_atimeSec(times[0].tv_sec); req.set_atimeNsec(times[0].tv_nsec); req.set_mtimeSec(times[1].tv_sec); req.set_mtimeNsec(times[1].tv_nsec); } else { req.set_atimeSec(UTIME_NOW); req.set_atimeNsec(UTIME_NOW); req.set_mtimeSec(UTIME_NOW); req.set_mtimeNsec(UTIME_NOW); } 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()); managarm::posix::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; return 0; } int sys_getentropy(void *buffer, size_t length) { SignalGuard sguard; auto p = reinterpret_cast(buffer); size_t n = 0; while (n < length) { size_t chunk; HEL_CHECK(helGetRandomBytes(p + n, length - n, &chunk)); n += chunk; } return 0; } int sys_gethostname(char *buffer, size_t bufsize) { SignalGuard sguard; mlibc::infoLogger() << "mlibc: gethostname always returns managarm" << frg::endlog; char name[10] = "managarm\0"; if (bufsize < 10) return ENAMETOOLONG; strncpy(buffer, name, 10); return 0; } int sys_fsync(int fd) { auto handle = getHandleForFd(fd); if (!handle) return EBADF; mlibc::infoLogger() << "mlibc: fsync is a stub" << frg::endlog; return 0; } int sys_memfd_create(const char *name, int flags, int *fd) { SignalGuard sguard; managarm::posix::MemFdCreateRequest req(getSysdepsAllocator()); req.set_name(frg::string(getSysdepsAllocator(), name)); 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()); managarm::posix::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; *fd = resp.fd(); return 0; } int sys_uname(struct utsname *buf) { __ensure(buf); mlibc::infoLogger() << "\e[31mmlibc: uname() returns static information\e[39m" << frg::endlog; strcpy(buf->sysname, "Managarm"); strcpy(buf->nodename, "managarm"); strcpy(buf->release, "0.0.1-rolling"); strcpy(buf->version, "Managarm is not Managram"); #if defined(__x86_64__) strcpy(buf->machine, "x86_64"); #elif defined(__aarch64__) strcpy(buf->machine, "aarch64"); #elif defined(__riscv) strcpy(buf->machine, "riscv64"); #else #error Unknown architecture #endif return 0; } int sys_madvise(void *, size_t, int) { mlibc::infoLogger() << "mlibc: sys_madvise is a stub!" << frg::endlog; return 0; } int sys_ptsname(int fd, char *buffer, size_t length) { int index; if (int e = sys_ioctl(fd, TIOCGPTN, &index, nullptr); e) return e; if ((size_t)snprintf(buffer, length, "/dev/pts/%d", index) >= length) { return ERANGE; } return 0; } int sys_unlockpt(int fd) { int unlock = 0; if (int e = sys_ioctl(fd, TIOCSPTLCK, &unlock, nullptr); e) return e; return 0; } int sys_setrlimit(int resource, const struct rlimit *limit) { switch (resource) { case RLIMIT_NOFILE: { SignalGuard sguard; managarm::posix::SetResourceLimitRequest req(getSysdepsAllocator()); req.set_resource(resource); req.set_cur(limit->rlim_cur); req.set_max(limit->rlim_max); auto [offer, send_req, recv_resp] = exchangeMsgsSync( getPosixLane(), helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_req.error()); HEL_CHECK(recv_resp.error()); managarm::posix::SetResourceLimitResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); return resp.error() | toErrno; } default: mlibc::infoLogger() << "mlibc: unhandled rlimit resource " << resource << frg::endlog; return EINVAL; } } int sys_getrlimit(int resource, struct rlimit *limit) { switch (resource) { case RLIMIT_NOFILE: /* TODO: change this once we support more than 512 */ limit->rlim_cur = 512; limit->rlim_max = 512; return 0; default: return EINVAL; } } int sys_sysconf(int num, long *ret) { switch (num) { case _SC_OPEN_MAX: { struct rlimit ru; if (int e = sys_getrlimit(RLIMIT_NOFILE, &ru); e) { return e; } *ret = (ru.rlim_cur == RLIM_INFINITY) ? -1 : ru.rlim_cur; break; } case _SC_PHYS_PAGES: case _SC_AVPHYS_PAGES: { // defer these to the generic implementation. return EINVAL; } default: { SignalGuard sguard; managarm::posix::SysconfRequest req(getSysdepsAllocator()); req.set_num(num); auto [offer, send_req, recv_resp] = exchangeMsgsSync( getPosixLane(), helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_req.error()); HEL_CHECK(recv_resp.error()); managarm::posix::SysconfResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; *ret = resp.value(); return 0; } } return 0; } int sys_sysinfo(struct sysinfo *info) { SignalGuard sguard; managarm::posix::GetMemoryInformationRequest req(getSysdepsAllocator()); auto [offer, send_req, recv_resp] = exchangeMsgsSync( getPosixLane(), helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_req.error()); HEL_CHECK(recv_resp.error()); managarm::posix::GetMemoryInformationResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); FILE *uptime = fopen("/proc/uptime", "r"); __ensure(uptime); int uptime_sec; int uptime_msec; int idle_sec; int idle_msec; fscanf(uptime, "%d.%d %d.%d", &uptime_sec, &uptime_msec, &idle_sec, &idle_msec); fclose(uptime); // TODO: fill in missing fields. *info = {}; info->uptime = uptime_sec; info->totalram = resp.total_usable_memory(); info->freeram = resp.available_memory(); info->mem_unit = resp.memory_unit(); return 0; } int sys_fstatfs(int fd, struct statfs *buf) { SignalGuard sguard; managarm::posix::FstatfsRequest req(getSysdepsAllocator()); req.set_fd(fd); 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()); managarm::posix::FstatfsResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; memset(buf, NULL, sizeof(struct statfs)); buf->f_type = resp.fstype(); return 0; } int sys_prctl(int option, va_list va, int *out) { switch (option) { case PR_CAPBSET_READ: // TODO: Implement PR_CAPBSET read if we ever support capabilities *out = 1; return 0; case PR_SET_NAME: { const auto name = va_arg(va, char *); *out = 0; return pthread_setname_np(pthread_self(), name); } case PR_GET_NAME: { const auto name = va_arg(va, char *); *out = 0; return pthread_getname_np(pthread_self(), name, 16); } case PR_SET_PDEATHSIG: { managarm::posix::ParentDeathSignalRequest req{getSysdepsAllocator()}; const auto value = va_arg(va, int); req.set_signal(value); auto [offer, send_req, recv_resp] = exchangeMsgsSync( getPosixLane(), helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_req.error()); HEL_CHECK(recv_resp.error()); managarm::posix::ParentDeathSignalResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; *out = 0; return 0; } case PR_GET_DUMPABLE: { managarm::posix::ProcessDumpableRequest req{getSysdepsAllocator()}; auto [offer, send_req, recv_resp] = exchangeMsgsSync( getPosixLane(), helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_req.error()); HEL_CHECK(recv_resp.error()); managarm::posix::ProcessDumpableResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; *out = resp.value(); return 0; } case PR_SET_DUMPABLE: { const auto dumpable = va_arg(va, long); managarm::posix::ProcessDumpableRequest req{getSysdepsAllocator()}; req.set_set(1); req.set_new_value(dumpable); auto [offer, send_req, recv_resp] = exchangeMsgsSync( getPosixLane(), helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_req.error()); HEL_CHECK(recv_resp.error()); managarm::posix::ProcessDumpableResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; return 0; } default: mlibc::infoLogger() << "mlibc: prctl: operation: " << option << " unimplemented!" << frg::endlog; return EINVAL; } } int sys_statfs(const char *path, struct statfs *buf) { SignalGuard sguard; managarm::posix::FstatfsRequest req(getSysdepsAllocator()); req.set_fd(-1); req.set_path(frg::string(getSysdepsAllocator(), path)); 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()); managarm::posix::FstatfsResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if (resp.error() != managarm::posix::Errors::SUCCESS) return resp.error() | toErrno; memset(buf, NULL, sizeof(struct statfs)); buf->f_type = resp.fstype(); return 0; } int sys_getpriority(int, id_t, int *value) { mlibc::infoLogger() << "\e[35mmlibc: getpriority() always returns 0\e[39m" << frg::endlog; *value = 0; return 0; } int sys_setpriority(int, id_t, int) { mlibc::infoLogger() << "\e[35mmlibc: setpriority() is a stub\e[39m" << frg::endlog; return 0; } // We don't support extended attributes yet int sys_removexattr(const char *, const char *) { return ENOSYS; } int sys_lgetxattr(const char *, const char *, void *, size_t, ssize_t *) { return ENOSYS; } int sys_setxattr(const char *, const char *, const void *, size_t, int) { return ENOSYS; } // We don't implement name_to_handle_at int sys_name_to_handle_at(int, const char *, struct file_handle *, int *, int) { return ENOSYS; } } // namespace mlibc