Fix warnings and make it enough to build binutils

This commit is contained in:
Mark Poliakov 2024-01-15 18:25:31 +02:00
parent 85eb9a7c74
commit af1b621042
80 changed files with 1754 additions and 396 deletions

View File

@ -11,6 +11,7 @@ yggdrasil-rt = { git = "https://git.alnyan.me/yggdrasil/yggdrasil-rt.git" }
libyalloc = { git = "https://git.alnyan.me/yggdrasil/libyalloc.git" }
bitflags = { version = "2.4.1" }
chrono = { version = "0.4.31", default-features = false }
linked_list_allocator = { version = "0.10.5", default-features = false }
[build-dependencies]
cbindgen = { git = "https://git.alnyan.me/yggdrasil/cbindgen.git", branch = "master" }

View File

@ -1,5 +1,4 @@
use std::{
env,
fs::{self, DirEntry},
path::Path,
};

View File

@ -1,12 +1,10 @@
#ifndef _ASSERT_H
#define _ASSERT_H 1
#define assert(x) \
do { \
if (!(x)) { \
__assert_fail(__FILE__, __LINE__, #x); \
} \
} while(0)
#define __ASSERT_VOID_CAST (void)
#define assert(expr) \
((expr) ? __ASSERT_VOID_CAST(0) : __assert_fail(__FILE__, __LINE__, #expr))
[[noreturn]] void __assert_fail(const char *file, int line, const char *message);

15
include/bits/signal.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef _YGGDRASIL_SIGNAL_H
#define _YGGDRASIL_SIGNAL_H 1
#include <stdatomic.h>
typedef _Atomic int sig_atomic_t;
#define SIG_IGN __sig_ignore
// TODO
#define SIG_ERR __sig_terminate
// TODO
#define SIG_HOLD __sig_terminate
#define SIG_DFL ((sig_handler_t) 0)
#endif

View File

@ -3,8 +3,8 @@
int printf(const char *format, ...);
int fprintf(FILE *stream, const char *format, ...);
int sprintf(FILE *stream, const char *format, ...);
int snprintf(FILE *stream, size_t len, const char *format, ...);
int sprintf(char *dst, const char *format, ...);
int snprintf(char *dst, size_t len, const char *format, ...);
int dprintf(int fd, const char *format, ...);
int scanf(const char *format, ...);

7
include/bits/sys/param.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef _YGGDRASIL_SYS_PARAM_H
#define _YGGDRASIL_SYS_PARAM_H 1
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#endif

12
include/bits/sys/select.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef _YGGDRASIL_SYS_SELECT_H
#define _YGGDRASIL_SYS_SELECT_H 1
#define __FD_INDEX(fd) ((fd) / sizeof(uint64_t))
#define __FD_BIT(fd) ((fd) % sizeof(uint64_t))
#define FD_CLR(fd, set) ((set)->bits[__FD_INDEX(fd)] &= ~(1 << __FD_BIT(fd)))
#define FD_ISSET(fd, set) (((set)->bits[__FD_INDEX(fd)] & (1 << __FD_BIT(fd))) != 0)
#define FD_SET(fd, set) ((set)->bits[__FD_INDEX(fd)] |= (1 << __FD_BIT(fd)))
#define FD_ZERO(set) ((void) memset((set)->bits, 0, sizeof((set)->bits)))
#endif

View File

@ -8,7 +8,7 @@
#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFFIFO)
#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)

46
include/inttypes.h Normal file
View File

@ -0,0 +1,46 @@
#ifndef _INTTYPES_H
#define _INTTYPES_H 1
#include <stddef.h>
#include <stdint.h>
#define PRIo64 "lo"
#define PRId64 "ld"
#define PRIu64 "lu"
#define PRIx64 "lx"
#define PRIo32 "o"
#define PRId32 "d"
#define PRIu32 "u"
#define PRIx32 "x"
#define PRIo16 "ho"
#define PRId16 "hd"
#define PRIu16 "hu"
#define PRIx16 "hx"
#define PRIo8 "hho"
#define PRId8 "hhd"
#define PRIu8 "hhu"
#define PRIx8 "hhx"
#define SCNo64 PRIo64
#define SCNd64 PRId64
#define SCNu64 PRIu64
#define SCNx64 PRIx64
#define SCNo32 PRIo32
#define SCNd32 PRId32
#define SCNu32 PRIu32
#define SCNx32 PRIx32
#define SCNo16 PRIo16
#define SCNd16 PRId16
#define SCNu16 PRIu16
#define SCNx16 PRIx16
#define SCNo8 PRIo8
#define SCNd8 PRId8
#define SCNu8 PRIu8
#define SCNx8 PRIx8
#endif

4
include/memory.h Normal file
View File

@ -0,0 +1,4 @@
#ifndef _MEMORY_H
#define _MEMORY_H 1
#include <string.h>
#endif

View File

@ -1,4 +1,4 @@
use libyalloc::GlobalAllocator;
use libyalloc::global::GlobalAllocator;
#[global_allocator]
pub static GLOBAL_ALLOCATOR: GlobalAllocator = GlobalAllocator;

View File

@ -96,7 +96,7 @@ impl<T> FromResidual<yggdrasil_rt::Error> for EResult<T> {
}
impl<T> FromResidual<Result<Infallible, Errno>> for EResult<T> {
fn from_residual(residual: Result<Infallible, Errno>) -> Self {
fn from_residual(_residual: Result<Infallible, Errno>) -> Self {
todo!()
}
}
@ -109,11 +109,11 @@ impl<T> Try for EResult<T> {
match self.into_set_errno() {
Self::Ok(value) => ControlFlow::Continue(value),
Self::Errno(e) => ControlFlow::Break(Err(e)),
Self::Err(error) => unreachable!(),
Self::Err(_error) => unreachable!(),
}
}
fn from_output(output: Self::Output) -> Self {
fn from_output(_output: Self::Output) -> Self {
todo!()
}
}

View File

@ -1,3 +1,8 @@
use core::{
ffi::c_int,
ops::{Deref, DerefMut},
};
use yggdrasil_rt::{
io::{FileMode, OpenOptions, RawFd, SeekFrom},
path::Path,
@ -5,35 +10,27 @@ use yggdrasil_rt::{
};
use crate::{
error::EResult,
header::errno::Errno,
io::{Read, Seek, Write},
error::{self, EResult},
header::errno::{Errno, EBADF},
io::{AsRawFd, AsRawFdOpt, FromRawFd, IntoRawFd, Read, Seek, Write},
};
pub enum FileBacking {
File(File),
File(ManagedFile),
}
pub struct File {
pub struct RawFile {
fd: RawFd,
}
pub struct ManagedFile {
inner: RawFile,
reference: bool,
}
impl File {
pub unsafe fn new(fd: RawFd) -> Self {
Self {
fd,
reference: false,
}
}
pub fn from_raw(fd: RawFd) -> Self {
Self {
fd,
reference: false,
}
}
// RawFile
impl RawFile {
pub fn open_at<P: AsRef<Path>>(
at: Option<RawFd>,
pathname: P,
@ -42,26 +39,17 @@ impl File {
) -> Result<Self, Errno> {
let fd =
EResult::from(unsafe { syscall::open(at, pathname.as_ref().as_str(), opts, mode) })?;
Ok(Self {
fd,
reference: false,
})
Ok(Self { fd })
}
pub unsafe fn close(&self) -> Result<(), Errno> {
yggdrasil_rt::debug_trace!("Close fd {:?}", self.fd);
pub unsafe fn close(self: &mut Self) -> Result<(), Errno> {
EResult::from(unsafe { syscall::close(self.fd) })?;
self.fd = RawFd::NONE;
Ok(())
}
pub fn into_raw_fd(self) -> RawFd {
let fd = self.fd;
core::mem::forget(self);
fd
}
}
impl Write for File {
impl Write for RawFile {
fn write(&mut self, data: &[u8]) -> Result<usize, Errno> {
let count = EResult::from(unsafe { syscall::write(self.fd, data) })?;
Ok(count)
@ -73,21 +61,107 @@ impl Write for File {
}
}
impl Read for File {
impl Read for RawFile {
fn read(&mut self, data: &mut [u8]) -> Result<usize, Errno> {
let count = EResult::from(unsafe { syscall::read(self.fd, data) })?;
Ok(count)
}
}
impl Seek for File {
impl Seek for RawFile {
fn seek(&mut self, off: SeekFrom) -> Result<u64, Errno> {
let pos = EResult::from(unsafe { syscall::seek(self.fd, off) })?;
Ok(pos)
}
}
impl Drop for File {
impl FromRawFd for RawFile {
unsafe fn from_raw_fd(fd: RawFd) -> Self {
Self { fd }
}
}
impl AsRawFd for RawFile {
fn as_raw_fd(&self) -> RawFd {
self.fd
}
}
impl IntoRawFd for RawFile {
fn into_raw_fd(self) -> RawFd {
self.fd
}
}
impl TryFrom<c_int> for RawFile {
type Error = Errno;
fn try_from(value: c_int) -> Result<Self, Self::Error> {
if value >= 0 {
Ok(Self {
fd: RawFd(value as _),
})
} else {
error::set_errno_result(EBADF)
}
}
}
// ManagedFile
impl ManagedFile {
pub fn open_at<P: AsRef<Path>>(
at: Option<RawFd>,
pathname: P,
opts: OpenOptions,
mode: FileMode,
) -> Result<Self, Errno> {
let inner = RawFile::open_at(at, pathname, opts, mode)?;
Ok(Self {
inner,
reference: false,
})
}
pub unsafe fn close(self: &mut Self) -> Result<(), Errno> {
if self.reference {
unreachable!("Cannot close a reference ManagedFile");
}
self.reference = true;
RawFile::close(&mut self.inner)
}
}
impl FromRawFd for ManagedFile {
unsafe fn from_raw_fd(fd: RawFd) -> Self {
Self::from(RawFile::from_raw_fd(fd))
}
}
impl Deref for ManagedFile {
type Target = RawFile;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl DerefMut for ManagedFile {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
impl From<RawFile> for ManagedFile {
fn from(value: RawFile) -> Self {
Self {
inner: value,
reference: false,
}
}
}
impl Drop for ManagedFile {
fn drop(&mut self) {
if !self.reference {
unsafe {
@ -97,19 +171,29 @@ impl Drop for File {
}
}
// FileBacking
impl FileBacking {
pub unsafe fn make_ref(&self) -> Self {
match self {
Self::File(file) => Self::File(File {
fd: file.fd,
Self::File(file) => Self::File(ManagedFile {
inner: RawFile::from_raw_fd(file.inner.fd),
reference: true,
}),
}
}
pub fn as_raw_fd(&self) -> EResult<RawFd> {
pub unsafe fn close(self: &mut Self) -> Result<(), Errno> {
match self {
Self::File(file) => EResult::Ok(file.fd),
Self::File(file) => ManagedFile::close(file),
}
}
}
impl AsRawFdOpt for FileBacking {
fn as_raw_fd_opt(&self) -> Option<RawFd> {
match self {
Self::File(file) => Some(file.as_raw_fd()),
}
}
}

View File

@ -9,7 +9,7 @@ use yggdrasil_rt::io::{DirectoryEntry, RawFd};
use crate::{error, io::dir::DirReader, util::Nullable};
use super::{errno::EBADF, limits::NAME_MAX, sys_types::ino_t};
use super::{errno::EBADF, sys_types::ino_t};
#[derive(Debug)]
#[repr(C)]
@ -22,7 +22,7 @@ pub struct DIR {
#[repr(C)]
pub struct dirent {
pub d_ino: ino_t,
pub d_name: [c_char; NAME_MAX],
pub d_name: [c_char; 256],
}
pub type __scandir_filter_fn_t = extern "C" fn(*const dirent) -> c_int;
@ -30,10 +30,10 @@ pub type __scandir_compar_fn_t = extern "C" fn(*mut *const dirent, *mut *const d
impl From<DirectoryEntry> for dirent {
fn from(value: DirectoryEntry) -> Self {
let mut d_name = [0; NAME_MAX];
let mut d_name = [0; 256];
let len = value.name.len();
if len + 1 >= NAME_MAX {
if len >= 255 {
todo!("Name too long");
}

View File

@ -47,6 +47,17 @@ pub const EMLINK: Errno = Errno(31);
pub const EPIPE: Errno = Errno(32);
pub const EDOM: Errno = Errno(33);
pub const ERANGE: Errno = Errno(34);
pub const EDEADLK: Errno = Errno(35);
pub const ENAMETOOLONG: Errno = Errno(36);
pub const ENOLCK: Errno = Errno(37);
pub const ENOSYS: Errno = Errno(38);
pub const ENOTEMPTY: Errno = Errno(39);
pub const ELOOP: Errno = Errno(40);
pub const EWOULDBLOCK: Errno = EAGAIN;
pub const ENOMSG: Errno = Errno(42);
pub const MAX_ERROR: Errno = ERANGE;
static SUCCESS: &CStr = static_cstr!("Success");

View File

@ -1,11 +1,8 @@
use core::ffi::{c_char, c_int, c_short, CStr, VaList};
use yggdrasil_rt::{
io::{FileMode, OpenOptions, RawFd},
path::Path,
};
use yggdrasil_rt::io::{FileMode, OpenOptions};
use crate::{error, file::File, header::errno::EINVAL, util::Nullable};
use crate::{error, file::RawFile, header::errno::EINVAL, io::IntoRawFd, util::Nullable};
use super::{
errno::Errno,
@ -137,7 +134,15 @@ unsafe extern "C" fn creat(pathname: *const c_char, mode: mode_t) -> c_int {
#[no_mangle]
unsafe extern "C" fn fcntl(fd: c_int, cmd: c_int, args: ...) -> c_int {
todo!()
let Ok(file) = RawFile::try_from(fd) else {
return -1;
};
match cmd {
F_GETFD => 0,
F_SETFD => 0,
_ => todo!("fcntl({}, {}, ...)", fd, cmd),
}
}
#[no_mangle]
@ -148,7 +153,7 @@ unsafe extern "C" fn open(pathname: *const c_char, opts: c_int, mut args: ...) -
let result = match open_opts(opts, &mut args) {
Ok(OpenMode::File(opts, mode)) => {
File::open_at(None, pathname, opts, mode).map(File::into_raw_fd)
RawFile::open_at(None, pathname, opts, mode).map(RawFile::into_raw_fd)
}
Ok(OpenMode::Directory) => {
todo!();

View File

@ -1,19 +0,0 @@
// TODO take from yggdrasil-abi
pub const FILESIZEBITS: usize = 64;
pub const MAX_CANON: usize = 64;
pub const LINK_MAX: usize = 4096;
pub const NAME_MAX: usize = 255;
pub const PATH_MAX: usize = 4096;
pub const SYMLINK_MAX: usize = 4096;
pub const PIPE_BUF: usize = 4096;
pub const OPEN_MAX: u32 = u32::MAX - 1;
pub const STREAM_MAX: u32 = OPEN_MAX;
pub const PAGESIZE: usize = 4096;
pub const PAGE_SIZE: usize = PAGESIZE;
pub const ATEXIT_MAX: usize = 32;

View File

@ -1,4 +1,7 @@
use core::ffi::{c_char, c_int};
use core::{
ffi::{c_char, c_int},
ptr::null_mut,
};
#[derive(Clone, Copy)]
#[repr(C)]
@ -75,7 +78,8 @@ unsafe extern "C" fn newlocale(
#[no_mangle]
unsafe extern "C" fn setlocale(category: c_int, locale: *const c_char) -> *mut c_char {
todo!()
// TODO
null_mut()
}
#[no_mangle]

View File

@ -1,11 +1,10 @@
language = "C"
style = "Type"
sys_includes = []
sys_includes = ["bits/math.h"]
no_includes = true
include_guard = "_MATH_H"
trailer = "#include <bits/math.h>"
usize_type = "size_t"
isize_type = "ssize_t"

View File

@ -1 +1,13 @@
use core::ffi::{c_double, c_float};
pub const NAN: f64 = f64::NAN;
#[no_mangle]
unsafe extern "C" fn fabs(x: c_double) -> c_double {
todo!()
}
#[no_mangle]
unsafe extern "C" fn fabsf(x: c_float) -> c_float {
todo!()
}

View File

@ -2,6 +2,11 @@
// TODO limits.h is compiler-provided
pub mod sys_param;
pub mod sys_resource;
pub mod sys_select;
pub mod sys_socket;
pub mod sys_time;
pub mod sys_types;
pub mod sys_wait;
@ -9,16 +14,20 @@ pub mod ctype;
pub mod dirent;
pub mod errno;
pub mod fcntl;
pub mod limits;
pub mod locale;
pub mod math;
pub mod pwd;
pub mod setjmp;
pub mod signal;
pub mod stdio;
pub mod stdlib;
pub mod string;
pub mod strings;
pub mod sys_stat;
pub mod termios;
pub mod time;
pub mod unistd;
pub mod wchar;
/*
Impl Check Name
@ -95,7 +104,7 @@ PARTIAL sys/wait.h - declarations for waiting
----- tar.h - extended tar definitions
----- termios.h - define values for termios
----- tgmath.h - type-generic macros
----- time.h - time types
MOSTLY time.h - time types
OSSUP trace.h - tracing
OSSUP ulimit.h - ulimit commands
PARTIAL unistd.h - standard symbolic constants and types

View File

@ -0,0 +1,14 @@
language = "C"
style = "Tag"
sys_includes = ["stddef.h", "sys/types.h"]
no_includes = true
include_guard = "_PWD_H"
usize_type = "size_t"
isize_type = "ssize_t"
[export]
include = ["passwd"]
exclude = []

13
src/header/pwd/mod.rs Normal file
View File

@ -0,0 +1,13 @@
use core::ffi::c_char;
use super::sys_types::{gid_t, uid_t};
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[repr(C)]
pub struct passwd {
pub pw_name: *mut c_char,
pub pw_uid: uid_t,
pub pw_gid: gid_t,
pub pw_dir: *mut c_char,
pub pw_shell: *mut c_char,
}

View File

@ -1,5 +1,3 @@
use core::ffi::c_int;
#[cfg(target_arch = "x86_64")]
mod x86_64;

View File

@ -1,4 +1,4 @@
use core::{arch::global_asm, ffi::c_int};
use core::arch::global_asm;
#[repr(C)]
pub struct __jmp_buf {

View File

@ -0,0 +1,19 @@
language = "C"
style = "Type"
sys_includes = [
"stddef.h",
"stdint.h",
"sys/types.h",
"bits/signal.h"
]
no_includes = true
include_guard = "_SIGNAL_H"
usize_type = "size_t"
isize_type = "ssize_t"
[export]
include = ["sig_handler_t", "SIGABRT"]
exclude = []

106
src/header/signal/mod.rs Normal file
View File

@ -0,0 +1,106 @@
use core::ffi::c_int;
use yggdrasil_rt::process::Signal;
use crate::signal;
use super::sys_types::pid_t;
pub type sig_handler_t = unsafe extern "C" fn(SigNumber);
extern "C" {
fn __sig_terminate(_: SigNumber);
fn __sig_ignore(_: SigNumber);
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
#[repr(transparent)]
pub struct SigNumber(pub c_int);
// TODO generate these based on the ABI
pub const SIGSEGV: SigNumber = SigNumber(1);
pub const SIGABRT: SigNumber = SigNumber(2);
pub const SIGKILL: SigNumber = SigNumber(3);
pub const SIGINT: SigNumber = SigNumber(4);
// TODO not yet defined signals
pub const SIGALRM: SigNumber = SigNumber::INVALID;
pub const SIGBUS: SigNumber = SigNumber::INVALID;
pub const SIGCHLD: SigNumber = SigNumber::INVALID;
pub const SIGCONT: SigNumber = SigNumber::INVALID;
pub const SIGFPE: SigNumber = SigNumber::INVALID;
pub const SIGHUP: SigNumber = SigNumber::INVALID;
pub const SIGPIPE: SigNumber = SigNumber::INVALID;
pub const SIGQUIT: SigNumber = SigNumber::INVALID;
pub const SIGSTOP: SigNumber = SigNumber::INVALID;
pub const SIGTERM: SigNumber = SigNumber::INVALID;
pub const SIGTSTP: SigNumber = SigNumber::INVALID;
pub const SIGTTIN: SigNumber = SigNumber::INVALID;
pub const SIGTTOU: SigNumber = SigNumber::INVALID;
pub const SIGUSR1: SigNumber = SigNumber::INVALID;
pub const SIGUSR2: SigNumber = SigNumber::INVALID;
pub const SIGPOLL: SigNumber = SigNumber::INVALID;
pub const SIGPROF: SigNumber = SigNumber::INVALID;
pub const SIGSYS: SigNumber = SigNumber::INVALID;
pub const SIGTRAP: SigNumber = SigNumber::INVALID;
pub const SIGURG: SigNumber = SigNumber::INVALID;
pub const SIGVTALRM: SigNumber = SigNumber::INVALID;
pub const SIGXCPU: SigNumber = SigNumber::INVALID;
pub const SIGXFSZ: SigNumber = SigNumber::INVALID;
impl SigNumber {
pub const INVALID: Self = Self(-65536);
}
impl TryFrom<SigNumber> for Signal {
type Error = ();
fn try_from(value: SigNumber) -> Result<Self, Self::Error> {
match value {
SIGSEGV => Ok(Signal::MemoryAccessViolation),
SIGABRT => Ok(Signal::Aborted),
SIGKILL => Ok(Signal::Killed),
SIGINT => Ok(Signal::Interrupted),
_ => Err(()),
}
}
}
impl From<Signal> for SigNumber {
fn from(value: Signal) -> Self {
match value {
Signal::Aborted => SIGABRT,
Signal::Interrupted => SIGINT,
Signal::Killed => SIGKILL,
Signal::MemoryAccessViolation => SIGSEGV,
}
}
}
#[no_mangle]
unsafe extern "C" fn kill(pid: pid_t, signum: SigNumber) -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn killpg(pid: pid_t, signum: SigNumber) -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn raise(signum: SigNumber) -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn signal(signum: SigNumber, handler: sig_handler_t) -> sig_handler_t {
// NOTE handler might be NULL, so check that
let Ok(signal) = Signal::try_from(signum) else {
// Ignore
return __sig_terminate;
};
let handler_ptr = handler as usize;
let handler = (handler_ptr != 0).then_some(handler);
signal::set_handler(signal, handler)
}

View File

@ -10,9 +10,12 @@ use yggdrasil_rt::{
};
use crate::{
error::{CSizeResult, CZeroResult},
header::{errno::Errno, sys_types::off_t},
io::{Read, Seek, Write},
error::{self, CSizeResult, CZeroResult},
header::{
errno::{Errno, EBADF},
sys_types::off_t,
},
io::{AsRawFdOpt, Read, Seek, Write},
};
use super::{
@ -23,10 +26,16 @@ fn open_inner<O: FileOpenSource>(source: O, mode_str: &[u8]) -> Result<*mut FILE
let opts = match mode_str {
b"r" | b"rb" => OpenOptions::READ,
b"r+" | b"rb+" => OpenOptions::READ | OpenOptions::WRITE,
b"w" | b"wb" => OpenOptions::TRUNCATE | OpenOptions::WRITE,
b"w+" | b"wb+" => OpenOptions::TRUNCATE | OpenOptions::READ | OpenOptions::WRITE,
b"a" | b"ab" => OpenOptions::APPEND | OpenOptions::READ | OpenOptions::WRITE,
b"a+" | b"ab+" => OpenOptions::APPEND | OpenOptions::READ | OpenOptions::WRITE,
b"w" | b"wb" => OpenOptions::TRUNCATE | OpenOptions::WRITE | OpenOptions::CREATE,
b"w+" | b"wb+" => {
OpenOptions::TRUNCATE | OpenOptions::READ | OpenOptions::WRITE | OpenOptions::CREATE
}
b"a" | b"ab" => {
OpenOptions::APPEND | OpenOptions::READ | OpenOptions::WRITE | OpenOptions::CREATE
}
b"a+" | b"ab+" => {
OpenOptions::APPEND | OpenOptions::READ | OpenOptions::WRITE | OpenOptions::CREATE
}
// TODO: errno and fail
_ => todo!(),
};
@ -57,7 +66,9 @@ pub unsafe extern "C" fn fopen(pathname: *const c_char, mode: *const c_char) ->
let pathname = pathname.to_str().unwrap();
let mode = CStr::from_ptr(mode);
open_inner(Path::from_str(pathname), mode.to_bytes()).unwrap_or(null_mut())
let res = open_inner(Path::from_str(pathname), mode.to_bytes()).unwrap_or(null_mut());
yggdrasil_rt::debug_trace!("fopen({:?}, {:?}) -> {:p}", pathname, mode, res);
res
}
#[no_mangle]
@ -113,9 +124,12 @@ pub unsafe extern "C" fn fclose(stream: *mut FILE) -> c_int {
#[no_mangle]
pub unsafe extern "C" fn fileno(stream: *mut FILE) -> c_int {
let stream = stream.as_mut().unwrap();
match stream.as_raw_fd() {
Ok(RawFd(fd)) => fd as _,
Err(_) => -1,
match stream.as_raw_fd_opt() {
Some(RawFd(fd)) => fd as _,
None => {
error::set_errno(EBADF);
-1
}
}
}

View File

@ -5,13 +5,13 @@ use core::{
use crate::{
error,
header::{stdlib::realloc, string::strlen},
header::stdlib::realloc,
io::{Read, Write},
};
use super::{
stderr, stdin, stdout,
unlocked::{flockfile, fputc_unlocked, fputs_unlocked, funlockfile, fwrite_unlocked},
unlocked::{flockfile, fputc_unlocked, fputs_unlocked, funlockfile},
EOF, FILE,
};

View File

@ -12,15 +12,15 @@ use yggdrasil_rt::{
use crate::{
error::{EResult, TryFromExt},
file::{File, FileBacking},
file::{FileBacking, ManagedFile, RawFile},
io::{
buffered::{BufWriter, FileWriter, LineWriter, ReadBuffer, UnbufferedWriter},
BufRead, Read, Seek, Write,
AsRawFdOpt, BufRead, FromRawFd, Read, Seek, Write,
},
sync::{Mutex, RawMutex},
};
use super::{errno::Errno, limits};
use super::errno::Errno;
// TODO:
// L_ctermid
@ -86,16 +86,22 @@ pub struct FILE {
}
impl FILE {
pub unsafe fn from_c_file(file: File, flags: FileFlags) -> Self {
assert!(!flags.contains(FileFlags::BUILTIN));
let inner = FileBacking::File(file);
// TODO run is_terminal on file and check for desired buffering mode
unsafe fn from_backing(
backing: FileBacking,
flags: FileFlags,
buffering: BufferingMode,
) -> Self {
let output = backing.make_ref();
let output: Box<dyn FileWriter> = match buffering {
BufferingMode::None => Box::new(UnbufferedWriter::new(output)),
BufferingMode::Full => Box::new(BufWriter::with_capacity(output, BUFSIZ)),
BufferingMode::Line => Box::new(LineWriter::with_capacity(output, BUFSIZ)),
};
Self {
lock: RawMutex::new(),
output: Box::new(BufWriter::with_capacity(inner.make_ref(), BUFSIZ)),
inner,
read_buffer: Some(ReadBuffer::owned(BUFSIZ)),
output,
inner: backing,
read_buffer: None, // Some(ReadBuffer::owned(BUFSIZ)),
flags,
@ -105,48 +111,39 @@ impl FILE {
}
}
pub unsafe fn new_builtin(fd: RawFd, flags: FileFlags, buffered: bool) -> Self {
let inner = FileBacking::File(File::new(fd));
Self {
lock: RawMutex::new(),
pub unsafe fn from_raw_file(file: RawFile, flags: FileFlags) -> Self {
Self::from_managed_file(file.into(), flags)
}
output: if buffered {
Box::new(LineWriter::with_capacity(inner.make_ref(), BUFSIZ))
} else {
Box::new(UnbufferedWriter::new(inner.make_ref()))
},
inner,
read_buffer: Some(ReadBuffer::owned(BUFSIZ)),
pub unsafe fn from_managed_file(file: ManagedFile, flags: FileFlags) -> Self {
assert!(!flags.contains(FileFlags::BUILTIN));
let inner = FileBacking::File(file);
Self::from_backing(inner, flags, BufferingMode::Full)
}
flags: FileFlags::BUILTIN | flags,
ungetc: Vec::new(),
last_operation: None,
}
pub unsafe fn new_builtin(fd: RawFd, flags: FileFlags, buffering: BufferingMode) -> Self {
let inner = FileBacking::File(ManagedFile::from_raw_fd(fd));
Self::from_backing(inner, flags, buffering)
}
pub unsafe fn close(self: *mut Self) -> Result<(), Errno> {
// TODO lock needed?
let r = self.as_mut().unwrap();
r.flush()?;
if r.flags.contains(FileFlags::BUILTIN) {
// NOTE The OS will close the file for us
Ok(())
todo!()
} else {
// Drop the file
drop(Box::from_raw(self));
Ok(())
let mut this = Box::from_raw(self);
let result = FileBacking::close(&mut this.inner);
drop(this);
result
}
}
pub unsafe fn as_raw_fd_unlocked(&mut self) -> Result<RawFd, Errno> {
let fd = self.inner.as_raw_fd()?;
Ok(fd)
}
pub fn as_raw_fd(&mut self) -> Result<RawFd, Errno> {
locked_op!(self, self.as_raw_fd_unlocked())
pub unsafe fn as_raw_fd_opt_unlocked(&self) -> Option<RawFd> {
self.inner.as_raw_fd_opt()
}
pub unsafe fn clear_error_unlocked(&mut self) {
@ -247,7 +244,7 @@ impl FILE {
self.lock.release();
}
fn reset(&mut self) {
pub fn reset(&mut self) {
if let Some(read_buffer) = self.read_buffer.as_mut() {
read_buffer.reset();
}
@ -403,9 +400,15 @@ impl Seek for FILE {
}
}
impl AsRawFdOpt for FILE {
fn as_raw_fd_opt(&self) -> Option<RawFd> {
locked_op!(self, self.as_raw_fd_opt_unlocked())
}
}
impl FileOpenSource for &Path {
fn open_with(self, opts: OpenOptions) -> Result<FILE, Errno> {
let f = File::open_at(None, self, opts, FileMode::default_file())?;
let f = ManagedFile::open_at(None, self, opts, FileMode::default_file())?;
let mut flags = FileFlags::empty();
if opts.contains(OpenOptions::READ) {
flags |= FileFlags::READ;
@ -413,13 +416,13 @@ impl FileOpenSource for &Path {
if opts.contains(OpenOptions::WRITE) {
flags |= FileFlags::WRITE;
}
Ok(unsafe { FILE::from_c_file(f, flags) })
Ok(unsafe { FILE::from_managed_file(f, flags) })
}
}
impl FileOpenSource for RawFd {
fn open_with(self, opts: OpenOptions) -> Result<FILE, Errno> {
let f = File::from_raw(self);
let f = unsafe { RawFile::from_raw_fd(self) };
let mut flags = FileFlags::empty();
if opts.contains(OpenOptions::READ) {
flags |= FileFlags::READ;
@ -427,7 +430,7 @@ impl FileOpenSource for RawFd {
if opts.contains(OpenOptions::WRITE) {
flags |= FileFlags::WRITE;
}
Ok(unsafe { FILE::from_c_file(f, flags) })
Ok(unsafe { FILE::from_raw_file(f, flags) })
}
}
@ -481,17 +484,17 @@ pub unsafe fn setup_default_files() {
let stdin_ = Box::into_raw(Box::new(FILE::new_builtin(
RawFd::STDIN,
FileFlags::READ,
true,
BufferingMode::Line,
)));
let stdout_ = Box::into_raw(Box::new(FILE::new_builtin(
RawFd::STDOUT,
FileFlags::WRITE,
true,
BufferingMode::Line,
)));
let stderr_ = Box::into_raw(Box::new(FILE::new_builtin(
RawFd::STDERR,
FileFlags::WRITE,
false,
BufferingMode::None,
)));
stdin = stdin_;

View File

@ -57,7 +57,7 @@ fn fmt_float_exp<W: Write + fmt::Write>(
}
fn fmt_float_string(val: c_double, precision: usize) -> String {
let mut string = format!("{:.p$}", val, p = precision);
let string = format!("{:.p$}", val, p = precision);
// TODO trim
string
}

View File

@ -20,6 +20,7 @@ pub enum FmtSize {
Long,
LongLong,
Size,
#[allow(unused)]
LongFloat,
}

View File

@ -194,6 +194,11 @@ unsafe extern "C" fn fprintf(stream: *mut FILE, format: *const c_char, mut args:
vfprintf(stream, format, args.as_va_list())
}
#[no_mangle]
unsafe extern "C" fn vprintf(format: *const c_char, ap: VaList) -> c_int {
vfprintf(stdout, format, ap)
}
#[no_mangle]
unsafe extern "C" fn vfprintf(stream: *mut FILE, format: *const c_char, ap: VaList) -> c_int {
if format.is_null() {

View File

@ -1,4 +1,4 @@
use core::ffi::{c_char, c_int, c_void, CStr, VaList};
use core::ffi::{c_char, c_int, CStr, VaList};
use crate::header::errno::Errno;

View File

@ -2,9 +2,12 @@ use core::ffi::{c_char, c_int, c_void, CStr};
use yggdrasil_rt::io::RawFd;
use crate::error::{CSizeResult, CZeroResult};
use crate::{
error::{self, CSizeResult, CZeroResult},
header::errno::EBADF,
};
use super::{FileFlags, EOF, FILE};
use super::{stdin, stdout, FileFlags, EOF, FILE};
#[no_mangle]
pub unsafe extern "C" fn flockfile(stream: *mut FILE) {
@ -48,9 +51,12 @@ pub unsafe extern "C" fn clearerr_unlocked(stream: *mut FILE) {
#[no_mangle]
pub unsafe extern "C" fn fileno_unlocked(stream: *mut FILE) -> c_int {
let stream = stream.as_mut().unwrap();
match stream.as_raw_fd_unlocked() {
Ok(RawFd(fd)) => fd as _,
Err(_) => -1,
match stream.as_raw_fd_opt_unlocked() {
Some(RawFd(fd)) => fd as _,
None => {
error::set_errno(EBADF);
-1
}
}
}
@ -97,22 +103,28 @@ pub unsafe extern "C" fn fflush_unlocked(stream: *mut FILE) -> c_int {
#[no_mangle]
pub unsafe extern "C" fn fgetc_unlocked(stream: *mut FILE) -> c_int {
todo!()
let stream = stream.as_mut().unwrap();
let mut buf = [0];
match stream.read_unlocked(&mut buf) {
Ok(1) => buf[0] as c_int,
Ok(_) => EOF,
Err(_) => EOF,
}
}
#[no_mangle]
pub unsafe extern "C" fn getc_unlocked(stream: *mut FILE) -> c_int {
todo!()
fgetc_unlocked(stream)
}
#[no_mangle]
pub unsafe extern "C" fn getchar_unlocked() -> c_int {
todo!()
fgetc_unlocked(stdin)
}
#[no_mangle]
pub unsafe extern "C" fn putchar_unlocked(c: c_char) -> c_int {
todo!()
pub unsafe extern "C" fn putchar_unlocked(c: c_int) -> c_int {
fputc_unlocked(c, stdout)
}
#[no_mangle]

View File

@ -7,8 +7,9 @@ use core::{
use crate::{allocator::GLOBAL_ALLOCATOR, error, header::errno::ENOMEM};
unsafe fn alloc_inner(size: usize, offset: usize, align: usize) -> *mut c_void {
let layout = Layout::from_size_align(size + offset, align).unwrap();
unsafe fn alloc_inner(size: usize) -> *mut c_void {
let size = (size + 15) & !15;
let layout = Layout::from_size_align(size + 16, 16).unwrap();
let ptr = GLOBAL_ALLOCATOR.alloc(layout);
if ptr.is_null() {
@ -16,20 +17,19 @@ unsafe fn alloc_inner(size: usize, offset: usize, align: usize) -> *mut c_void {
return ptr as *mut c_void;
}
*(ptr as *mut u64) = (size + offset) as u64;
*(ptr as *mut u64).add(1) = align as u64;
*(ptr as *mut u64) = (size + 16) as u64;
*(ptr as *mut u64).add(1) = 16 as u64;
ptr.add(offset) as *mut c_void
ptr.add(16) as *mut c_void
}
unsafe fn get_allocation(ptr: *mut c_void) -> (*mut u8, Layout) {
let ptr = (ptr as *mut u64).offset(-2);
let size = *ptr as usize;
let align = *ptr.add(1) as usize;
(
ptr as *mut u8,
Layout::from_size_align(size, align).unwrap(),
)
assert!(ptr as usize > 0x10);
let base = (ptr as *mut u8).sub(16);
let size = *(base as *mut u64);
let align = *(base as *mut u64).add(1);
let layout = Layout::from_size_align(size as _, align as _).unwrap();
(base, layout)
}
#[no_mangle]
@ -51,7 +51,7 @@ pub unsafe extern "C" fn calloc(nmemb: usize, size: usize) -> *mut c_void {
#[no_mangle]
pub unsafe extern "C" fn malloc(size: usize) -> *mut c_void {
alloc_inner(size, 16, 8)
alloc_inner(size)
}
#[no_mangle]
@ -84,3 +84,15 @@ pub unsafe extern "C" fn free(ptr: *mut c_void) {
let (allocation, layout) = get_allocation(ptr);
GLOBAL_ALLOCATOR.dealloc(allocation, layout);
}
#[no_mangle]
unsafe extern "C" fn ymalloc(size: usize) -> *mut c_void {
let ptr = GLOBAL_ALLOCATOR.alloc(Layout::from_size_align(size, 8).unwrap());
ptr as _
}
#[no_mangle]
unsafe extern "C" fn yfree(ptr: *mut c_void, size: usize) {
assert!(!ptr.is_null());
GLOBAL_ALLOCATOR.dealloc(ptr as _, Layout::from_size_align(size, 8).unwrap());
}

View File

@ -1,8 +1,4 @@
use core::ffi::c_int;
use crate::{allocator::GLOBAL_ALLOCATOR, error};
use super::errno::ENOMEM;
use core::ffi::{c_char, c_int};
mod malloc;
mod number;
@ -35,6 +31,34 @@ pub use malloc::{calloc, free, malloc, realloc};
pub const EXIT_SUCCESS: c_int = 0;
pub const EXIT_FAILURE: c_int = 1;
pub const MB_CUR_MAX: c_int = 4;
// TODO RAND_MAX
// TODO MB_CUR_MAX
#[no_mangle]
unsafe extern "C" fn mktemp(tstr: *mut c_char) -> *mut c_char {
todo!()
}
#[no_mangle]
unsafe extern "C" fn mkdtemp(tstr: *mut c_char) -> *mut c_char {
todo!()
}
#[no_mangle]
unsafe extern "C" fn mkstemp(temp: *mut c_char) -> c_int {
todo!()
}
// #[no_mangle]
// unsafe extern "C" fn faccessat(fd: c_int, path: *const c_char, amode: c_int, flag: c_int) -> c_int {
// todo!()
// }
#[no_mangle]
unsafe extern "C" fn getprogname() -> *const c_char {
todo!()
}

View File

@ -1,5 +1,5 @@
use core::{
ffi::{c_char, c_double, c_float, c_int, c_long, c_longlong, c_ulong, c_ulonglong, CStr},
ffi::{c_char, c_double, c_float, c_int, c_long, c_longlong, c_ulong, c_ulonglong},
ops::{AddAssign, MulAssign, Neg},
ptr::null_mut,
};
@ -128,8 +128,6 @@ unsafe fn str_to_int_inner<F: Copy + Neg<Output = F> + MulAssign + AddAssign + F
) -> F {
string.ensure();
let mut matched = false;
// Skip whitespace
while (*string as u8).is_ascii_whitespace() {
string = string.add(1);
@ -201,7 +199,6 @@ unsafe fn str_to_int_inner<F: Copy + Neg<Output = F> + MulAssign + AddAssign + F
value *= mul;
value += digit;
matched = true;
string = string.add(1);
}

View File

@ -1,7 +1,6 @@
use core::{
ffi::{c_char, c_int, CStr},
ptr::null_mut,
slice::memchr,
};
use crate::process;

View File

@ -1,3 +1,8 @@
use core::{
cmp::Ordering,
ffi::{c_int, c_void},
};
/*
void *bsearch(const void *, const void *, size_t, size_t,
int (*)(const void *, const void *));
@ -6,3 +11,131 @@ int posix_memalign(void **, size_t, size_t);
void qsort(void *, size_t, size_t, int (*)(const void *,
const void *));
*/
pub type qsort_compar_fn_t = extern "C" fn(*const c_void, *const c_void) -> c_int;
pub type qsort_compar_r_fn_t = extern "C" fn(*const c_void, *const c_void, *mut c_void) -> c_int;
pub type bsearch_compar_fn_t = extern "C" fn(*const c_void, *const c_void) -> c_int;
struct Array {
base: *mut c_void,
size: usize,
nmemb: usize,
}
impl Array {
unsafe fn new(base: *mut c_void, nmemb: usize, size: usize) -> Option<Self> {
if nmemb == 0 || size == 0 || base.is_null() {
return None;
}
Some(Self { base, nmemb, size })
}
fn element(&mut self, i: usize) -> *mut c_void {
if i >= self.nmemb {
panic!("i = {}, nmemb = {}", i, self.nmemb);
}
unsafe { self.base.add(i * self.size) }
}
fn partition<F: Fn(*mut c_void, *mut c_void) -> Ordering>(
&mut self,
lower: usize,
upper: usize,
cmp: &F,
) -> usize {
if lower >= upper {
panic!()
}
let pivot_ptr = self.element(lower);
let mut i = lower;
let mut j = upper;
while i < j {
while i <= upper - 1 && cmp(self.element(i), pivot_ptr).is_le() {
i += 1;
}
while j >= lower + 1 && cmp(self.element(j), pivot_ptr).is_gt() {
j -= 1;
}
if i < j {
self.swap(i, j);
}
}
self.swap(lower, j);
j
}
fn swap(&mut self, i: usize, j: usize) {
let el_i = self.element(i) as *mut u8;
let el_j = self.element(j) as *mut u8;
unsafe {
for i in 0..self.size {
core::ptr::swap(el_i.add(i), el_j.add(i));
}
}
}
fn sort_inner<F: Fn(*mut c_void, *mut c_void) -> Ordering>(
&mut self,
lower: usize,
upper: usize,
cmp: &F,
) {
if lower < upper {
let partition = self.partition(lower, upper, cmp);
if partition != 0 {
self.sort_inner(lower, partition - 1, cmp);
}
self.sort_inner(partition + 1, upper, cmp);
}
}
fn sort<F: Fn(*mut c_void, *mut c_void) -> Ordering>(&mut self, cmp: &F) {
if self.nmemb != 0 {
self.sort_inner(0, self.nmemb - 1, cmp);
}
}
}
#[no_mangle]
unsafe extern "C" fn bsearch(
key: *const c_void,
base: *const c_void,
nmemb: usize,
size: usize,
compar: bsearch_compar_fn_t,
) -> *mut c_void {
todo!()
}
#[no_mangle]
unsafe extern "C" fn qsort(
base: *mut c_void,
nmemb: usize,
size: usize,
compar: qsort_compar_fn_t,
) {
let Some(mut array) = Array::new(base, nmemb, size) else {
return;
};
array.sort(&|a, b| compar(a, b).cmp(&0));
}
#[no_mangle]
unsafe extern "C" fn qsort_r(
base: *mut c_void,
nmemb: usize,
size: usize,
compar: qsort_compar_r_fn_t,
arg: *mut c_void,
) {
let Some(mut array) = Array::new(base, nmemb, size) else {
return;
};
array.sort(&|a, b| compar(a, b, arg).cmp(&0))
}

View File

@ -1,7 +1,7 @@
language = "C"
style = "Type"
sys_includes = ["stddef.h", "locale.h"]
sys_includes = ["stddef.h", "locale.h", "bits/string.h", "strings.h"]
no_includes = true
include_guard = "_STRING_H"

View File

@ -4,17 +4,28 @@ use core::{
ptr::null_mut,
};
use crate::header::{
errno::{self, Errno},
locale::locale_t,
string::strlen,
use yggdrasil_rt::memcpy;
use crate::{
header::{
errno::{self, Errno},
locale::locale_t,
stdlib::malloc,
string::strlen,
},
util::Nullable,
};
use super::{mem::mempcpy, memset};
#[no_mangle]
unsafe extern "C" fn stpcpy(dst: *mut c_char, src: *const c_char) -> *mut c_char {
stpncpy(dst, src, usize::MAX)
if dst.is_null() || src.is_null() {
panic!();
}
let ptr = mempcpy(dst as _, src as _, strlen(src)) as *mut c_char;
*ptr = 0;
ptr
}
#[no_mangle]
@ -28,7 +39,11 @@ unsafe extern "C" fn stpncpy(dst: *mut c_char, src: *const c_char, n: usize) ->
#[no_mangle]
unsafe extern "C" fn strcat(dst: *mut c_char, src: *const c_char) -> *mut c_char {
strncat(dst, src, usize::MAX)
if dst.is_null() {
panic!();
}
stpcpy(dst.add(strlen(dst)), src);
dst
}
#[no_mangle]
@ -59,7 +74,8 @@ unsafe extern "C" fn strcmp(a: *const c_char, b: *const c_char) -> c_int {
#[no_mangle]
unsafe extern "C" fn strcpy(dst: *mut c_char, src: *const c_char) -> *mut c_char {
strncpy(dst, src, usize::MAX)
stpcpy(dst, src);
dst
}
#[no_mangle]
@ -80,7 +96,11 @@ unsafe extern "C" fn strcspn(mut s: *const c_char, reject: *const c_char) -> usi
#[no_mangle]
unsafe extern "C" fn strdup(s: *const c_char) -> *mut c_char {
strndup(s, usize::MAX)
s.ensure();
let len = strlen(s);
let data = malloc(len + 1);
memcpy(data as _, s as _, len + 1);
data as _
}
unsafe fn strerror_inner(e: c_int) -> *const c_char {
@ -105,25 +125,29 @@ unsafe extern "C" fn strerror_r(e: c_int, buf: *mut c_char, n: usize) -> *mut c_
#[no_mangle]
unsafe extern "C" fn strncat(dst: *mut c_char, src: *const c_char, n: usize) -> *mut c_char {
if dst.is_null() {
if dst.is_null() || src.is_null() {
panic!();
}
let len = strnlen(src, n);
let p = dst.add(strlen(dst));
let p = mempcpy(p as _, src as _, len) as *mut c_char;
*p = 0;
let ptr = dst.add(strlen(dst));
let ptr = mempcpy(ptr as _, src as _, len) as *mut c_char;
*ptr = 0;
dst
}
#[no_mangle]
unsafe extern "C" fn strncmp(mut a: *const c_char, mut b: *const c_char, mut n: usize) -> c_int {
if a.is_null() || b.is_null() {
if a.is_null() {
panic!();
}
if b.is_null() {
panic!();
}
if a == b {
return 0;
}
while n != 0 {
match Ord::cmp(&*a, &*b) {
Ordering::Less => return -1,

View File

@ -1,13 +1,13 @@
language = "C"
style = "Type"
sys_includes = ["stddef.h", "stdint.h"]
sys_includes = ["stddef.h"]
no_includes = true
include_guard = "_LIMITS_H"
include_guard = "_STRINGS_H"
usize_type = "size_t"
isize_type = "ssize_t"
[export]
include = []
exclude = []

29
src/header/strings/mod.rs Normal file
View File

@ -0,0 +1,29 @@
use core::{
cmp::Ordering,
ffi::{c_char, c_int},
};
#[no_mangle]
unsafe extern "C" fn strcasecmp(s1: *const c_char, s2: *const c_char) -> c_int {
strncasecmp(s1, s2, usize::MAX)
}
#[no_mangle]
unsafe extern "C" fn strncasecmp(s1: *const c_char, s2: *const c_char, n: usize) -> c_int {
for i in 0..n {
let c0 = (*s1.add(i) as u8).to_ascii_lowercase();
let c1 = (*s2.add(i) as u8).to_ascii_lowercase();
match c0.cmp(&c1) {
Ordering::Less => return -1,
Ordering::Equal => (),
Ordering::Greater => return 1,
}
if c0 == 0 {
break;
}
}
0
}

View File

@ -0,0 +1,20 @@
language = "C"
style = "Type"
sys_includes = [
"stddef.h",
"stdint.h",
"sys/types.h",
"limits.h",
"signal.h",
"bits/sys/param.h"
]
no_includes = true
include_guard = "_SYS_PARAM_H"
usize_type = "size_t"
isize_type = "ssize_t"
[export]
exclude = []

View File

View File

@ -0,0 +1,14 @@
language = "C"
style = "Tag"
sys_includes = ["stddef.h", "stdint.h", "sys/types.h"]
no_includes = true
include_guard = "_SYS_RESOURCE_H"
usize_type = "size_t"
isize_type = "ssize_t"
[export]
include = ["rlimit"]
exclude = []

View File

@ -0,0 +1,22 @@
use core::ffi::c_int;
pub type rlim_t = u64;
pub const RLIM_INFINITY: rlim_t = u64::MAX;
pub const RLIM_SAVED_MAX: rlim_t = u64::MAX - 1;
pub const RLIM_SAVED_CUR: rlim_t = u64::MAX - 2;
pub const RLIMIT_CORE: c_int = 1;
pub const RLIMIT_CPU: c_int = 2;
pub const RLIMIT_DATA: c_int = 3;
pub const RLIMIT_FSIZE: c_int = 4;
pub const RLIMIT_NOFILE: c_int = 5;
pub const RLIMIT_STACK: c_int = 6;
pub const RLIMIT_AS: c_int = 7;
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[repr(C)]
pub struct rlimit {
rlim_cur: rlim_t,
rlim_max: rlim_t,
}

View File

@ -0,0 +1,20 @@
language = "C"
style = "Tag"
sys_includes = [
"stddef.h",
"sys/types.h",
"sys/time.h",
"string.h",
"bits/sys/select.h"
]
no_includes = true
include_guard = "_SYS_SOCKET_H"
usize_type = "size_t"
isize_type = "ssize_t"
[export]
include = ["sockaddr", "socklen_t"]
exclude = []

View File

@ -0,0 +1,24 @@
use core::ffi::c_int;
use super::sys_time::__ygg_timeval_t;
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
#[repr(C)]
pub struct __fd_set {
bits: [u64; 4],
}
pub const FD_SETSIZE: usize = 64 * 4;
pub type fd_set = __fd_set;
#[no_mangle]
unsafe extern "C" fn select(
nfds: c_int,
readfds: *mut fd_set,
writefds: *mut fd_set,
exceptfds: *mut fd_set,
timeout: *mut __ygg_timeval_t,
) -> c_int {
todo!()
}

View File

@ -0,0 +1,14 @@
language = "C"
style = "Tag"
sys_includes = ["stddef.h", "stdint.h", "sys/types.h"]
no_includes = true
include_guard = "_SYS_SOCKET_H"
usize_type = "size_t"
isize_type = "ssize_t"
[export]
include = ["sockaddr", "socklen_t"]
exclude = []

View File

@ -0,0 +1,10 @@
pub type sa_family_t = u16;
pub type socklen_t = usize;
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[repr(C)]
pub struct sockaddr {
pub sa_family: sa_family_t,
pub sa_data: [u8; 30],
}

View File

@ -1,25 +1,18 @@
use core::{
ffi::{c_char, c_int, CStr},
mem::MaybeUninit,
};
use core::ffi::{c_char, c_int, CStr};
use yggdrasil_rt::{
io::{FileAttr, FileMode, FileType, RawFd},
path::Path,
sys as syscall,
};
use yggdrasil_rt::io::{FileAttr, FileMode, FileType, RawFd};
use crate::{
error::{self, CZeroResult, EResult},
error::{self, CZeroResult},
io,
util::Nullable,
};
use super::{
errno::{Errno, EBADF},
errno::EBADF,
fcntl::{AT_FDCWD, AT_SYMLINK_NOFOLLOW},
sys_time::__ygg_timespec_t,
sys_types::{blkcnt_t, blksize_t, dev_t, gid_t, ino_t, mode_t, nlink_t, off_t, uid_t},
time::{__ygg_timespec_t, timespec},
};
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]

View File

@ -0,0 +1,14 @@
language = "C"
style = "Tag"
sys_includes = ["stdarg.h", "stddef.h", "stdint.h", "sys/types.h"]
no_includes = true
include_guard = "_SYS_TIME_H"
usize_type = "size_t"
isize_type = "ssize_t"
[export]
include = ["timeval", "timespec", "__ygg_timeval_t", "__ygg_timespec_t"]
exclude = []

View File

@ -0,0 +1,20 @@
use core::ffi::c_long;
use super::sys_types::{suseconds_t, time_t};
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
#[repr(C)]
pub struct timeval {
pub tv_sec: time_t,
pub tv_usec: suseconds_t,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
#[repr(C)]
pub struct timespec {
pub tv_sec: time_t,
pub tv_nsec: c_long,
}
pub type __ygg_timeval_t = timeval;
pub type __ygg_timespec_t = timespec;

View File

@ -27,12 +27,12 @@ pub type clock_t = u64;
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
#[repr(transparent)]
pub struct time_t(pub u64);
pub struct time_t(pub i64);
pub type off_t = i64;
pub type suseconds_t = c_ulong;
impl time_t {
pub const INVALID: Self = Self(u64::MAX);
pub const INVALID: Self = Self(i64::MAX);
}

View File

@ -0,0 +1,14 @@
language = "C"
style = "Tag"
sys_includes = ["stddef.h"]
no_includes = true
include_guard = "_TERMIOS_H"
usize_type = "size_t"
isize_type = "ssize_t"
[export]
include = ["termios", "speed_t", "tcflag_t", "cc_t"]
exclude = []

106
src/header/termios/mod.rs Normal file
View File

@ -0,0 +1,106 @@
use core::ffi::{c_int, c_uchar, c_uint};
pub type cc_t = c_uchar;
pub type speed_t = c_uint;
pub type tcflag_t = c_uint;
// c_iflag
pub const IGNBRK: tcflag_t = 1 << 0;
pub const BRKINT: tcflag_t = 1 << 1;
pub const IGNPAR: tcflag_t = 1 << 2;
pub const PARMRK: tcflag_t = 1 << 3;
pub const INPCK: tcflag_t = 1 << 4;
pub const ISTRIP: tcflag_t = 1 << 5;
pub const INLCR: tcflag_t = 1 << 6;
pub const IGNCR: tcflag_t = 1 << 7;
pub const ICRNL: tcflag_t = 1 << 8;
pub const IXON: tcflag_t = 1 << 9;
pub const IXANY: tcflag_t = 1 << 10;
pub const IXOFF: tcflag_t = 1 << 11;
// c_oflag
pub const OPOST: tcflag_t = 1 << 0;
pub const ONLCR: tcflag_t = 1 << 1;
pub const OCRNL: tcflag_t = 1 << 2;
pub const ONOCR: tcflag_t = 1 << 3;
pub const ONLRET: tcflag_t = 1 << 4;
pub const OFILL: tcflag_t = 1 << 5;
pub const OFDEL: tcflag_t = 1 << 6;
// c_cflag
pub const CS5: tcflag_t = 0x0;
pub const CS6: tcflag_t = 0x1;
pub const CS7: tcflag_t = 0x2;
pub const CS8: tcflag_t = 0x3;
pub const CSIZE: tcflag_t = 0x3;
pub const CSTOPB: tcflag_t = 1 << 2;
pub const CREAD: tcflag_t = 1 << 3;
pub const PARENB: tcflag_t = 1 << 4;
pub const PARODD: tcflag_t = 1 << 5;
pub const HUPCL: tcflag_t = 1 << 6;
pub const CLOCAL: tcflag_t = 1 << 7;
// c_lflag
pub const ISIG: tcflag_t = 1 << 0;
pub const ICANON: tcflag_t = 1 << 1;
pub const ECHO: tcflag_t = 1 << 2;
pub const ECHOE: tcflag_t = 1 << 3;
pub const ECHOK: tcflag_t = 1 << 4;
pub const ECHONL: tcflag_t = 1 << 5;
pub const NOFLSH: tcflag_t = 1 << 6;
pub const TOSTOP: tcflag_t = 1 << 7;
pub const IEXTEN: tcflag_t = 1 << 8;
// c_cc
pub const VEOF: usize = 0;
pub const VEOL: usize = 1;
pub const VERASE: usize = 2;
pub const VINTR: usize = 3;
pub const VKILL: usize = 4;
pub const VQUIT: usize = 5;
pub const VREPRINT: usize = 6;
pub const VSTART: usize = 7;
pub const VSTOP: usize = 8;
pub const VSUSP: usize = 9;
pub const VWERASE: usize = 10;
pub const TCSANOW: c_int = 0;
pub const TCSADRAIN: c_int = 1;
pub const TCSAFLUSH: c_int = 2;
pub const TCOOFF: c_int = 1;
pub const TCOON: c_int = 2;
pub const TCIOFF: c_int = 3;
pub const TCION: c_int = 4;
pub const NCCS: usize = 16;
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
#[repr(C)]
pub struct termios {
pub c_iflag: tcflag_t,
pub c_oflag: tcflag_t,
pub c_cflag: tcflag_t,
pub c_lflag: tcflag_t,
pub c_cc: [cc_t; NCCS],
}
#[no_mangle]
unsafe extern "C" fn tcgetattr(fd: c_int, termios_p: *mut termios) -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn tcsetattr(
fd: c_int,
optional_actions: c_int,
termios_p: *const termios,
) -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn cfmakeraw(termios_p: *mut termios) {
todo!()
}

View File

@ -6,7 +6,8 @@ sys_includes = [
"stdint.h",
"locale.h",
"sys/types.h",
"bits/time.h"
"sys/time.h",
"bits/time.h",
]
no_includes = true
@ -16,4 +17,4 @@ usize_type = "size_t"
isize_type = "ssize_t"
[export]
include = ["timespec", "tm", "itimerspec"]
include = ["tm", "itimerspec"]

View File

@ -6,7 +6,7 @@ use core::{
use chrono::{DateTime, Datelike, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Timelike, Utc};
use super::sys_types::time_t;
use super::{sys_time::__ygg_timespec_t, sys_types::time_t};
mod convert;
mod string;
@ -24,18 +24,11 @@ int timer_settime(timer_t, int, const struct itimerspec *restrict,
struct itimerspec *restrict);
*/
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
#[repr(C)]
pub struct timespec {
pub tv_sec: time_t,
pub tv_nsec: c_long,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
#[repr(C)]
pub struct itimerspec {
pub it_interval: timespec,
pub it_value: timespec,
pub it_interval: __ygg_timespec_t,
pub it_value: __ygg_timespec_t,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
@ -52,8 +45,6 @@ pub struct tm {
pub tm_isdst: c_int,
}
pub type __ygg_timespec_t = timespec;
#[no_mangle]
pub static mut daylight: c_int = 0;
#[no_mangle]
@ -71,11 +62,11 @@ pub trait CDateTime {
impl tm {
pub fn naive_date(&self) -> Option<NaiveDate> {
Some(NaiveDate::from_ymd(
NaiveDate::from_ymd_opt(
self.tm_year + 1900,
u32::try_from(self.tm_mon).ok()? + 1,
u32::try_from(self.tm_mday).ok()?,
))
)
}
pub fn naive_time(&self) -> Option<NaiveTime> {
@ -98,7 +89,7 @@ impl CDateTime for tm {
impl CDateTime for time_t {
fn to_naive_datetime(&self) -> Option<NaiveDateTime> {
NaiveDateTime::from_timestamp_opt(self.0.try_into().ok()?, 0)
NaiveDateTime::from_timestamp_opt(self.0, 0)
}
}
@ -118,9 +109,12 @@ impl<T: Datelike + Timelike> From<T> for tm {
}
}
impl From<timespec> for Duration {
fn from(value: timespec) -> Self {
Self::new(value.tv_sec.0, value.tv_nsec.try_into().unwrap())
impl From<__ygg_timespec_t> for Duration {
fn from(value: __ygg_timespec_t) -> Self {
Self::new(
value.tv_sec.0.try_into().unwrap(),
value.tv_nsec.try_into().unwrap(),
)
}
}

View File

@ -1,12 +1,14 @@
use core::ffi::c_int;
use crate::header::sys_types::{clock_t, clockid_t, pid_t};
use super::timespec;
use crate::header::{
sys_time::__ygg_timespec_t,
sys_types::{clock_t, clockid_t, pid_t},
};
#[no_mangle]
unsafe extern "C" fn clock() -> clock_t {
todo!()
// TODO
0
}
#[no_mangle]
@ -15,17 +17,17 @@ unsafe extern "C" fn clock_getcpuclockid(pid: pid_t, clock_id_ptr: *mut clockid_
}
#[no_mangle]
unsafe extern "C" fn clock_getres(clock_id: clockid_t, ts: *mut timespec) -> c_int {
unsafe extern "C" fn clock_getres(clock_id: clockid_t, ts: *mut __ygg_timespec_t) -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn clock_gettime(clock_id: clockid_t, ts: *mut timespec) -> c_int {
unsafe extern "C" fn clock_gettime(clock_id: clockid_t, ts: *mut __ygg_timespec_t) -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn clock_settime(clock_id: clockid_t, ts: *const timespec) -> c_int {
unsafe extern "C" fn clock_settime(clock_id: clockid_t, ts: *const __ygg_timespec_t) -> c_int {
todo!()
}
@ -33,8 +35,8 @@ unsafe extern "C" fn clock_settime(clock_id: clockid_t, ts: *const timespec) ->
unsafe extern "C" fn clock_nanosleep(
clock_id: clockid_t,
flags: c_int,
rqtp: *const timespec,
rmtp: *mut timespec,
rqtp: *const __ygg_timespec_t,
rmtp: *mut __ygg_timespec_t,
) -> c_int {
todo!()
}

View File

@ -3,12 +3,16 @@ use core::{
time::Duration,
};
use crate::{header::sys_types::time_t, util};
use super::timespec;
use crate::{
header::{sys_time::__ygg_timespec_t, sys_types::time_t},
util,
};
#[no_mangle]
unsafe extern "C" fn nanosleep(rqtp: *const timespec, rmtp: *mut timespec) -> c_int {
unsafe extern "C" fn nanosleep(
rqtp: *const __ygg_timespec_t,
rmtp: *mut __ygg_timespec_t,
) -> c_int {
let rqtp = rqtp.as_ref().unwrap();
let amount = Duration::from(*rqtp);
@ -17,7 +21,7 @@ unsafe extern "C" fn nanosleep(rqtp: *const timespec, rmtp: *mut timespec) -> c_
Ok(()) => {
if let Some(rmtp) = rmtp.as_mut() {
// Zero
*rmtp = timespec::default();
*rmtp = __ygg_timespec_t::default();
}
0

View File

@ -1,7 +1,13 @@
language = "C"
style = "Type"
sys_includes = ["stdarg.h", "stddef.h", "stdint.h", "sys/types.h"]
sys_includes = [
"stdarg.h",
"stddef.h",
"stdint.h",
"sys/types.h",
"fcntl.h"
]
no_includes = true
include_guard = "_UNISTD_H"

147
src/header/unistd/io.rs Normal file
View File

@ -0,0 +1,147 @@
use core::ffi::{c_char, c_int, c_long, c_void};
use yggdrasil_rt::io::SeekFrom;
use crate::{
error,
file::RawFile,
header::{
errno::EINVAL,
fcntl::{AT_FDCWD, AT_SYMLINK_NOFOLLOW},
stdio::{SEEK_CUR, SEEK_END, SEEK_SET},
sys_types::off_t,
},
io::{Read, Seek, Write},
util::Nullable,
};
pub const _PC_NAME_MAX: c_int = 1;
pub const _PC_PATH_MAX: c_int = 2;
#[no_mangle]
unsafe extern "C" fn getcwd(buf: *mut c_char, size: usize) -> *mut c_char {
todo!()
}
#[no_mangle]
unsafe extern "C" fn close(fd: c_int) -> c_int {
let Ok(mut file) = RawFile::try_from(fd) else {
return -1;
};
match file.close() {
Ok(()) => 0,
Err(_) => -1,
}
}
#[no_mangle]
unsafe extern "C" fn unlink(pathname: *const c_char) -> c_int {
unlinkat(AT_FDCWD, pathname, AT_SYMLINK_NOFOLLOW)
}
#[no_mangle]
unsafe extern "C" fn unlinkat(atfd: c_int, pathname: *const c_char, flags: c_int) -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn write(fd: c_int, buf: *const c_void, count: usize) -> isize {
buf.ensure();
let Ok(mut file) = RawFile::try_from(fd) else {
return -1;
};
let data = core::slice::from_raw_parts(buf as *const u8, count);
match file.write(data) {
Ok(amount) => amount.try_into().unwrap(),
Err(_) => -1,
}
}
#[no_mangle]
unsafe extern "C" fn read(fd: c_int, buf: *mut c_void, count: usize) -> isize {
buf.ensure();
let Ok(mut file) = RawFile::try_from(fd) else {
return -1;
};
let data = core::slice::from_raw_parts_mut(buf as *mut u8, count);
match file.read(data) {
Ok(amount) => amount.try_into().unwrap(),
Err(_) => -1,
}
}
#[no_mangle]
unsafe extern "C" fn lseek(fd: c_int, offset: off_t, whence: c_int) -> off_t {
let Ok(mut file) = RawFile::try_from(fd) else {
return -1;
};
let offset = match whence {
SEEK_SET => SeekFrom::Start(offset.try_into().unwrap()),
SEEK_CUR => SeekFrom::Current(offset),
SEEK_END => SeekFrom::End(offset),
_ => {
error::set_errno(EINVAL);
return -1;
}
};
match file.seek(offset) {
Ok(pos) => pos.try_into().unwrap(),
Err(_) => -1,
}
}
#[no_mangle]
unsafe extern "C" fn faccessat(
fd: c_int,
path: *const c_char,
amode: c_int,
flags: c_int,
) -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn access(path: *const c_char, amode: c_int) -> c_int {
faccessat(AT_FDCWD, path, amode, 0)
}
#[no_mangle]
unsafe extern "C" fn dup(fd: c_int) -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn dup2(oldfd: c_int, newfd: c_int) -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn isatty(fd: c_int) -> c_int {
0
}
#[no_mangle]
unsafe extern "C" fn rmdir(pathname: *const c_char) -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn chdir(pathname: *const c_char) -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn pipe(fds: *mut c_int) -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn pathconf(pathname: *const c_char, name: c_int) -> c_long {
todo!()
}

View File

@ -1,114 +1,77 @@
use core::ffi::{c_char, c_int, CStr};
use crate::{
error::{CZeroResult, EResult},
util::{self, NullTerminated},
use core::{
ffi::{c_char, c_uint},
time::Duration,
};
use super::{errno::Errno, sys_types::pid_t};
use crate::util;
use alloc::{vec, vec::Vec};
use yggdrasil_rt::{path::Path, process::ExecveOptions, sys as syscall};
/*
unsigned alarm(unsigned);
size_t confstr(int, char *, size_t);
char *crypt(const char *, const char *);
void encrypt(char [64], int);
int fchdir(int);
int fchown(int, uid_t, gid_t);
int fchownat(int, const char *, uid_t, gid_t, int);
int fdatasync(int);
int fexecve(int, char *const [], char *const []);
long fpathconf(int, int);
int fsync(int);
int ftruncate(int, off_t);
gid_t getegid(void);
uid_t geteuid(void);
gid_t getgid(void);
int getgroups(int, gid_t []);
long gethostid(void);
int gethostname(char *, size_t);
char *getlogin(void);
int getlogin_r(char *, size_t);
int getopt(int, char * const [], const char *);
pid_t getpgid(pid_t);
pid_t getpgrp(void);
pid_t getppid(void);
pid_t getsid(pid_t);
uid_t getuid(void);
int lchown(const char *, uid_t, gid_t);
int link(const char *, const char *);
int linkat(int, const char *, int, const char *, int);
int lockf(int, int, off_t);
int nice(int);
int pause(void);
ssize_t pread(int, void *, size_t, off_t);
ssize_t pwrite(int, const void *, size_t, off_t);
ssize_t readlink(const char *restrict, char *restrict, size_t);
ssize_t readlinkat(int, const char *restrict, char *restrict, size_t);
int setegid(gid_t);
int seteuid(uid_t);
int setgid(gid_t);
int setpgid(pid_t, pid_t);
pid_t setpgrp(void);
int setregid(gid_t, gid_t);
int setreuid(uid_t, uid_t);
pid_t setsid(void);
int setuid(uid_t);
unsigned sleep(unsigned);
void swab(const void *restrict, void *restrict, ssize_t);
int symlink(const char *, const char *);
int symlinkat(const char *, int, const char *);
void sync(void);
long sysconf(int);
pid_t tcgetpgrp(int);
int tcsetpgrp(int, pid_t);
int truncate(const char *, off_t);
char *ttyname(int);
int ttyname_r(int, char *, size_t);
*/
unsafe fn fork_inner() -> Result<pid_t, Errno> {
let result = EResult::from(syscall::fork())?;
Ok(result as _)
}
// TODO error reporting
unsafe fn collect_execve_args<'a, 'e>(
argv: *const *mut c_char,
envp: *const *mut c_char,
) -> Result<(Vec<&'a str>, Vec<&'e str>), Errno> {
let mut arg_list = vec![];
let mut env_list = vec![];
if let Some(argv) = NullTerminated::try_from_ptr(argv) {
for &arg in argv {
let arg = CStr::from_ptr(arg);
arg_list.push(arg.to_str().unwrap());
}
}
if let Some(envp) = NullTerminated::try_from_ptr(envp) {
for &env in envp {
let env = CStr::from_ptr(env);
env_list.push(env.to_str().unwrap());
}
}
Ok((arg_list, env_list))
}
unsafe fn execve_inner<P: AsRef<Path>>(
pathname: P,
argv: &[&str],
envp: &[&str],
) -> Result<(), Errno> {
EResult::Err(yggdrasil_rt::Error::InvalidFile)?;
let opts = ExecveOptions {
program: pathname.as_ref().as_str(),
arguments: argv,
environment: envp,
};
let result = EResult::from(syscall::execve(&opts))?;
Ok(result as _)
}
unsafe fn execvpe_inner(file: &str, argv: &[&str], envp: &[&str]) -> Result<(), Errno> {
let pathname = util::resolve_binary(file)?;
execve_inner(&pathname, argv, envp)
}
pub mod io;
pub mod process;
#[no_mangle]
pub static mut environ: *mut *const c_char = core::ptr::null_mut();
pub static mut environ: *mut *mut c_char = core::ptr::null_mut();
#[no_mangle]
unsafe extern "C" fn fork() -> pid_t {
match fork_inner() {
Ok(pid) => pid,
Err(_) => -1,
}
}
#[no_mangle]
unsafe extern "C" fn execve(
pathname: *const c_char,
argv: *const *mut c_char,
envp: *const *mut c_char,
) -> c_int {
if pathname.is_null() {
panic!();
}
let pathname = CStr::from_ptr(pathname);
let pathname = pathname.to_str().unwrap();
let (argv, envp) = match collect_execve_args(argv, envp) {
Ok(r) => r,
Err(_) => return -1,
};
execve_inner(pathname, &argv, &envp).into_zero_status()
}
#[no_mangle]
unsafe extern "C" fn execvp(file: *const c_char, argv: *const *mut c_char) -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn execvpe(
file: *const c_char,
argv: *const *mut c_char,
envp: *const *mut c_char,
) -> c_int {
if file.is_null() {
panic!();
}
let file = CStr::from_ptr(file);
let file = file.to_str().unwrap();
let (argv, envp) = match collect_execve_args(argv, envp) {
Ok(r) => r,
Err(_) => return -1,
};
execvpe_inner(file, &argv, &envp).into_zero_status()
unsafe extern "C" fn sleep(seconds: c_uint) -> c_uint {
util::nanosleep(Duration::from_secs(seconds as _), None).ok();
0
}

View File

@ -0,0 +1,128 @@
use core::{
ffi::{c_char, c_int, CStr},
ptr::null,
};
use alloc::{vec, vec::Vec};
use yggdrasil_rt::{path::Path, process::ExecveOptions, sys as syscall};
use crate::{
error::{CZeroResult, EResult},
header::{errno::Errno, sys_types::pid_t},
util::{self, NullTerminated},
};
unsafe fn fork_inner() -> Result<pid_t, Errno> {
let result = EResult::from(syscall::fork())?;
Ok(result as _)
}
// TODO error reporting
unsafe fn collect_execve_args<'a, 'e>(
argv: *const *mut c_char,
envp: *const *mut c_char,
) -> Result<(Vec<&'a str>, Vec<&'e str>), Errno> {
let mut arg_list = vec![];
let mut env_list = vec![];
if let Some(argv) = NullTerminated::try_from_ptr(argv) {
for &arg in argv {
let arg = CStr::from_ptr(arg);
arg_list.push(arg.to_str().unwrap());
}
}
if let Some(envp) = NullTerminated::try_from_ptr(envp) {
for &env in envp {
let env = CStr::from_ptr(env);
env_list.push(env.to_str().unwrap());
}
}
Ok((arg_list, env_list))
}
unsafe fn execve_inner<P: AsRef<Path>>(
pathname: P,
argv: &[&str],
envp: &[&str],
) -> Result<(), Errno> {
let opts = ExecveOptions {
program: pathname.as_ref().as_str(),
arguments: argv,
environment: envp,
};
let result = EResult::from(syscall::execve(&opts))?;
Ok(result as _)
}
unsafe fn execvpe_inner(file: &str, argv: &[&str], envp: &[&str]) -> Result<(), Errno> {
let pathname = util::resolve_binary(file)?;
execve_inner(&pathname, argv, envp)
}
#[no_mangle]
unsafe extern "C" fn fork() -> pid_t {
match fork_inner() {
Ok(pid) => pid,
Err(_) => -1,
}
}
#[no_mangle]
unsafe extern "C" fn execve(
pathname: *const c_char,
argv: *const *mut c_char,
envp: *const *mut c_char,
) -> c_int {
if pathname.is_null() {
panic!();
}
let pathname = CStr::from_ptr(pathname);
let pathname = pathname.to_str().unwrap();
let (argv, envp) = match collect_execve_args(argv, envp) {
Ok(r) => r,
Err(_) => return -1,
};
execve_inner(pathname, &argv, &envp).into_zero_status()
}
#[no_mangle]
unsafe extern "C" fn execv(pathname: *const c_char, argv: *const *mut c_char) -> c_int {
execve(pathname, argv, null())
}
#[no_mangle]
unsafe extern "C" fn execvp(file: *const c_char, argv: *const *mut c_char) -> c_int {
execvpe(file, argv, null())
}
#[no_mangle]
unsafe extern "C" fn execvpe(
file: *const c_char,
argv: *const *mut c_char,
envp: *const *mut c_char,
) -> c_int {
if file.is_null() {
panic!();
}
let file = CStr::from_ptr(file);
let file = file.to_str().unwrap();
let (argv, envp) = match collect_execve_args(argv, envp) {
Ok(r) => r,
Err(_) => return -1,
};
execvpe_inner(file, &argv, &envp).into_zero_status()
}
#[no_mangle]
unsafe extern "C" fn _exit(status: c_int) -> ! {
todo!()
}
#[no_mangle]
unsafe extern "C" fn getpid() -> pid_t {
let pid = syscall::get_pid();
pid.try_into().unwrap()
}

View File

@ -0,0 +1,20 @@
language = "C"
style = "Type"
sys_includes = [
"stddef.h",
"stdint.h",
"stdarg.h",
"locale.h",
"string.h",
"stdio.h",
"time.h"
]
no_includes = true
include_guard = "_WCHAR_H"
usize_type = "size_t"
isize_type = "ssize_t"
[export]

30
src/header/wchar/mod.rs Normal file
View File

@ -0,0 +1,30 @@
use core::ffi::c_uint;
mod multibyte;
mod wcio;
mod wcstring;
mod wctype;
pub type wint_t = c_uint;
pub const WEOF: wint_t = -1i32 as wint_t;
/*
wint_t btowc(int);
size_t wcsftime(wchar_t *restrict, size_t,
const wchar_t *restrict, const struct tm *restrict);
double wcstod(const wchar_t *restrict, wchar_t **restrict);
float wcstof(const wchar_t *restrict, wchar_t **restrict);
long wcstol(const wchar_t *restrict, wchar_t **restrict, int);
long double wcstold(const wchar_t *restrict, wchar_t **restrict);
long long wcstoll(const wchar_t *restrict, wchar_t **restrict, int);
unsigned long wcstoul(const wchar_t *restrict, wchar_t **restrict, int);
unsigned long long
wcstoull(const wchar_t *restrict, wchar_t **restrict, int);
int wcswidth(const wchar_t *, size_t);
int wctob(wint_t);
wctype_t wctype(const char *);
int wcwidth(wchar_t);
int wprintf(const wchar_t *restrict, ...);
int wscanf(const wchar_t *restrict, ...);
*/

View File

@ -0,0 +1,24 @@
/*
size_t mbrlen(const char *restrict, size_t, mbstate_t *restrict);
size_t mbrtowc(wchar_t *restrict, const char *restrict, size_t,
mbstate_t *restrict);
int mbsinit(const mbstate_t *);
size_t mbsnrtowcs(wchar_t *restrict, const char **restrict,
size_t, size_t, mbstate_t *restrict);
size_t mbsrtowcs(wchar_t *restrict, const char **restrict, size_t,
mbstate_t *restrict);
size_t wcrtomb(char *restrict, wchar_t, mbstate_t *restrict);
size_t wcsnrtombs(char *restrict, const wchar_t **restrict, size_t,
size_t, mbstate_t *restrict);
size_t wcsrtombs(char *restrict, const wchar_t **restrict,
size_t, mbstate_t *restrict);
*/
use core::ffi::c_char;
use crate::types::wchar_t;
#[no_mangle]
unsafe extern "C" fn mbstowcs(dest: *mut wchar_t, src: *const c_char, n: usize) -> usize {
todo!()
}

27
src/header/wchar/wcio.rs Normal file
View File

@ -0,0 +1,27 @@
/*
wint_t fgetwc(FILE *);
wchar_t *fgetws(wchar_t *restrict, int, FILE *restrict);
wint_t fputwc(wchar_t, FILE *);
int fputws(const wchar_t *restrict, FILE *restrict);
int fwide(FILE *, int);
int fwprintf(FILE *restrict, const wchar_t *restrict, ...);
int fwscanf(FILE *restrict, const wchar_t *restrict, ...);
wint_t getwc(FILE *);
wint_t getwchar(void);
FILE *open_wmemstream(wchar_t **, size_t *);
wint_t putwc(wchar_t, FILE *);
wint_t putwchar(wchar_t);
int swprintf(wchar_t *restrict, size_t,
const wchar_t *restrict, ...);
int swscanf(const wchar_t *restrict,
const wchar_t *restrict, ...);
wint_t ungetwc(wint_t, FILE *);
int vfwprintf(FILE *restrict, const wchar_t *restrict, va_list);
int vfwscanf(FILE *restrict, const wchar_t *restrict, va_list);
int vswprintf(wchar_t *restrict, size_t,
const wchar_t *restrict, va_list);
int vswscanf(const wchar_t *restrict, const wchar_t *restrict,
va_list);
int vwprintf(const wchar_t *restrict, va_list);
int vwscanf(const wchar_t *restrict, va_list);
*/

View File

@ -0,0 +1,36 @@
/*
wchar_t *wcpcpy(wchar_t *restrict, const wchar_t *restrict);
wchar_t *wcpncpy(wchar_t *restrict, const wchar_t *restrict, size_t);
int wcscasecmp(const wchar_t *, const wchar_t *);
int wcscasecmp_l(const wchar_t *, const wchar_t *, locale_t);
wchar_t *wcscat(wchar_t *restrict, const wchar_t *restrict);
wchar_t *wcschr(const wchar_t *, wchar_t);
int wcscmp(const wchar_t *, const wchar_t *);
int wcscoll(const wchar_t *, const wchar_t *);
int wcscoll_l(const wchar_t *, const wchar_t *, locale_t);
wchar_t *wcscpy(wchar_t *restrict, const wchar_t *restrict);
size_t wcscspn(const wchar_t *, const wchar_t *);
wchar_t *wcsdup(const wchar_t *);
size_t wcslen(const wchar_t *);
int wcsncasecmp(const wchar_t *, const wchar_t *, size_t);
int wcsncasecmp_l(const wchar_t *, const wchar_t *, size_t,
locale_t);
wchar_t *wcsncat(wchar_t *restrict, const wchar_t *restrict, size_t);
int wcsncmp(const wchar_t *, const wchar_t *, size_t);
wchar_t *wcsncpy(wchar_t *restrict, const wchar_t *restrict, size_t);
size_t wcsnlen(const wchar_t *, size_t);
wchar_t *wcspbrk(const wchar_t *, const wchar_t *);
wchar_t *wcsrchr(const wchar_t *, wchar_t);
size_t wcsspn(const wchar_t *, const wchar_t *);
wchar_t *wcsstr(const wchar_t *restrict, const wchar_t *restrict);
wchar_t *wcstok(wchar_t *restrict, const wchar_t *restrict,
wchar_t **restrict);
size_t wcsxfrm(wchar_t *restrict, const wchar_t *restrict, size_t);
size_t wcsxfrm_l(wchar_t *restrict, const wchar_t *restrict,
size_t, locale_t);
wchar_t *wmemchr(const wchar_t *, wchar_t, size_t);
int wmemcmp(const wchar_t *, const wchar_t *, size_t);
wchar_t *wmemcpy(wchar_t *restrict, const wchar_t *restrict, size_t);
wchar_t *wmemmove(wchar_t *, const wchar_t *, size_t);
wchar_t *wmemset(wchar_t *, wchar_t, size_t);
*/

View File

@ -0,0 +1,16 @@
/*
int iswalnum(wint_t);
int iswalpha(wint_t);
int iswcntrl(wint_t);
int iswctype(wint_t, wctype_t);
int iswdigit(wint_t);
int iswgraph(wint_t);
int iswlower(wint_t);
int iswprint(wint_t);
int iswpunct(wint_t);
int iswspace(wint_t);
int iswupper(wint_t);
int iswxdigit(wint_t);
wint_t towlower(wint_t);
wint_t towupper(wint_t);
*/

View File

@ -148,7 +148,7 @@ impl<W: Write> Write for UnbufferedWriter<W> {
impl<W: Write> Write for BufWriter<W> {
fn write(&mut self, mut data: &[u8]) -> Result<usize, Errno> {
if data.len() + self.buffer.len() > self.buffer.capacity() {
if data.len() + self.buffer.len() >= self.buffer.capacity() {
self.flush()?;
}

View File

@ -1,6 +1,6 @@
use core::mem::MaybeUninit;
use alloc::{boxed::Box, vec::Vec};
use alloc::boxed::Box;
use yggdrasil_rt::{
io::{DirectoryEntry, RawFd},
path::Path,
@ -26,7 +26,7 @@ impl DirReader {
const BUFFER_SIZE: usize = 16;
pub fn open_at<P: AsRef<Path>>(at: Option<RawFd>, path: P) -> Result<Self, Errno> {
let fd = EResult::from(unsafe { syscall::open_directory(None, path.as_ref().as_str()) })?;
let fd = EResult::from(unsafe { syscall::open_directory(at, path.as_ref().as_str()) })?;
Ok(unsafe { Self::from_raw_fd(fd) })
}

View File

@ -60,6 +60,22 @@ pub trait Seek {
}
}
pub trait FromRawFd {
unsafe fn from_raw_fd(fd: RawFd) -> Self;
}
pub trait AsRawFdOpt {
fn as_raw_fd_opt(&self) -> Option<RawFd>;
}
pub trait AsRawFd {
fn as_raw_fd(&self) -> RawFd;
}
pub trait IntoRawFd {
fn into_raw_fd(self) -> RawFd;
}
pub fn get_metadata<P: AsRef<Path>>(
at: Option<RawFd>,
path: P,

View File

@ -7,17 +7,18 @@
arbitrary_self_types,
new_uninit,
maybe_uninit_slice,
inline_const
inline_const,
vec_into_raw_parts
)]
#![allow(internal_features)]
#![no_std]
use core::ffi::{c_char, c_int, CStr};
use core::{
ffi::{c_char, c_int, CStr},
ptr::null,
};
use alloc::{ffi::CString, vec::Vec};
use header::unistd::environ;
use alloc::vec::Vec;
use util::Nullable;
use yggdrasil_rt::process::{ExitCode, ProgramArgumentInner};
use crate::header::stdio::{self, stderr};
@ -32,6 +33,7 @@ pub mod file;
pub mod io;
pub mod path;
pub mod process;
pub mod signal;
pub mod sync;
pub mod types;
pub mod util;
@ -42,14 +44,17 @@ unsafe extern "C" fn _start(arg: usize) -> ! {
fn main(argc: c_int, argv: *const *const c_char) -> c_int;
}
signal::init();
let args = process::setup_env(arg);
let c_args = args.iter().map(|s| s.as_ptr()).collect::<Vec<_>>();
let mut c_args = args.iter().map(|s| s.as_ptr()).collect::<Vec<_>>();
// Terminate argv with NULL
let argc = c_args.len();
c_args.push(null());
stdio::setup_default_files();
// TODO setup signals, allocator, etc.
let code = main(c_args.len().try_into().unwrap(), c_args.as_ptr());
let code = main(argc.try_into().unwrap(), c_args.as_ptr());
process::exit(code)
}
@ -59,7 +64,8 @@ fn panic_handler(pi: &core::panic::PanicInfo) -> ! {
yggdrasil_rt::debug_trace!("--- C PROGRAM PANICKED ---");
yggdrasil_rt::debug_trace!("{:?}", pi);
yggdrasil_rt::debug_trace!("--- END PANIC ---");
process::exit(ExitCode::Exited(1));
process::abort();
}
#[no_mangle]
@ -75,7 +81,7 @@ unsafe extern "C" fn __assert_fail(file: *const c_char, line: c_int, expr: *cons
let expr = CStr::from_ptr(expr).to_str().unwrap();
// These should not be NULL, but check nevertheless
writeln!(err, "Assertion failed: {:?} at {}:{}", expr, file, line);
writeln!(err, "Assertion failed: '{}' at {}:{}", expr, file, line).ok();
panic!("TODO: abort()");
process::abort();
}

View File

@ -1,23 +1,19 @@
use core::{
ffi::c_char,
ptr::{null, null_mut},
slice::memchr,
};
use core::{ffi::c_char, ptr::null_mut, slice::memchr};
use alloc::{ffi::CString, vec::Vec};
use yggdrasil_rt::{
process::{ExitCode, ProgramArgumentInner},
process::{ExitCode, ProgramArgumentInner, Signal},
sys as syscall,
};
use crate::{
error,
header::{
errno::{Errno, EINVAL, ENOENT, ENOMEM, ESUCCESS},
limits::ATEXIT_MAX,
errno::{Errno, EINVAL, ENOMEM, ESUCCESS},
stdio,
unistd::environ,
},
signal,
sync::Mutex,
};
@ -39,6 +35,8 @@ impl ToExitCode for ExitCode {
// Exit
const ATEXIT_MAX: usize = 32;
static ATEXIT: Mutex<[Option<extern "C" fn()>; ATEXIT_MAX]> =
Mutex::new([const { None }; ATEXIT_MAX]);
@ -71,25 +69,36 @@ unsafe fn pre_exit() {
stdio::cleanup();
}
pub fn current_pid() -> u32 {
unsafe { syscall::get_pid() }
}
pub fn abort() -> ! {
unsafe {
signal::send(current_pid(), Signal::Aborted).unwrap();
unreachable!();
}
}
// Env
static mut ENVS: Vec<CString> = Vec::new();
static mut C_ENVS: Vec<*const c_char> = Vec::new();
static mut C_ENVS: Vec<*mut c_char> = Vec::new();
pub unsafe fn setup_env(arg: usize) -> Vec<CString> {
let arg = &*(arg as *const ProgramArgumentInner<'static>);
let mut args = Vec::new();
for (i, &arg) in arg.args.into_iter().enumerate() {
for &arg in arg.args {
args.push(CString::new(arg).unwrap());
}
for (i, &env) in arg.env.into_iter().enumerate() {
ENVS.push(CString::new(env).unwrap());
C_ENVS.push(ENVS[i].as_ptr());
C_ENVS.push(ENVS[i].as_ptr() as *mut _);
}
// Terminate the environ with null
C_ENVS.push(null());
C_ENVS.push(null_mut());
environ = C_ENVS.as_mut_ptr();
@ -168,8 +177,8 @@ pub unsafe fn setenv_raw(key: &[u8], value: Option<&[u8]>, overwrite: bool) -> R
ENVS.push(new_var);
// Replace the null with the variable
C_ENVS[new_index] = ENVS[new_index].as_ptr();
C_ENVS.push(null());
C_ENVS[new_index] = ENVS[new_index].as_ptr() as _;
C_ENVS.push(null_mut());
}
Ok(())

72
src/signal.rs Normal file
View File

@ -0,0 +1,72 @@
use core::sync::atomic::{AtomicUsize, Ordering};
use alloc::vec;
use yggdrasil_rt::{
process::{ExitCode, Signal, SignalEntryData},
sys as syscall,
};
use crate::{
error::EResult,
header::{
errno::Errno,
signal::{sig_handler_t, SigNumber},
},
process,
};
const SIGNAL_STACK_SIZE: usize = 65536;
const MAX_SIGNAL: usize = 32;
static SIGNAL_TABLE: [AtomicUsize; MAX_SIGNAL] = [const { AtomicUsize::new(0) }; MAX_SIGNAL];
#[no_mangle]
extern "C" fn __sig_ignore(_: SigNumber) {}
#[no_mangle]
extern "C" fn __sig_terminate(c: SigNumber) {
// Convert signal back to Signal
let signal = Signal::try_from(c).unwrap();
unsafe {
process::raw_exit(ExitCode::BySignal(signal));
}
}
unsafe extern "C" fn signal_entry(data: &SignalEntryData) -> ! {
let signum = data.signal as u32 as usize;
if let Some(handler_ptr) = SIGNAL_TABLE.get(signum) {
let handler: sig_handler_t = core::mem::transmute(handler_ptr.load(Ordering::Acquire));
handler(data.signal.into());
syscall::exit_signal(data)
} else {
todo!("Signal out of range?");
}
}
pub unsafe fn set_handler(signal: Signal, handler: Option<sig_handler_t>) -> sig_handler_t {
let signum = signal as u32 as usize;
let handler_ptr = handler.unwrap_or(__sig_terminate) as usize;
let old_handler_ptr = SIGNAL_TABLE[signum].swap(handler_ptr, Ordering::SeqCst);
// Not null
core::mem::transmute(old_handler_ptr)
}
pub unsafe fn send(target: u32, signal: Signal) -> Result<(), Errno> {
EResult::from(syscall::send_signal(target, signal))?;
Ok(())
}
pub unsafe fn init() {
let (signal_stack, _, _) = vec![0u8; SIGNAL_STACK_SIZE].into_raw_parts();
let signal_stack_ptr = signal_stack.add(SIGNAL_STACK_SIZE);
for entry in SIGNAL_TABLE.iter() {
entry.store(__sig_terminate as usize, Ordering::Release);
}
syscall::set_signal_entry(signal_entry as usize, signal_stack_ptr as usize);
}

View File

@ -1,3 +1,5 @@
#![allow(non_camel_case_types)]
pub type wchar_t = i32;
use core::ffi::c_int;
pub type wchar_t = c_int;

View File

@ -1,10 +1,4 @@
use core::{
ffi::c_char,
fmt,
marker::PhantomData,
ptr::{null_mut, NonNull},
time::Duration,
};
use core::{ffi::c_char, fmt, marker::PhantomData, ptr::NonNull, time::Duration};
use yggdrasil_rt::{path::Path, sys as syscall};