From 9f39456dbdf7947cf4b71fcbd0d1114bd3d09df1 Mon Sep 17 00:00:00 2001 From: Alex Lyon Date: Wed, 7 Mar 2018 14:06:30 -0800 Subject: [PATCH 1/5] string: implement strcat, strcmp, strcpy, and strdup --- Cargo.lock | 1 + src/platform/src/lib.rs | 13 ++----------- src/string/Cargo.toml | 1 + src/string/src/lib.rs | 31 +++++++++++++++++++++++-------- 4 files changed, 27 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9c7e66eeda..11a8c3c49a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -454,6 +454,7 @@ version = "0.1.0" dependencies = [ "cbindgen 0.5.0", "platform 0.1.0", + "stdlib 0.1.0", ] [[package]] diff --git a/src/platform/src/lib.rs b/src/platform/src/lib.rs index 63fc300c1c..39e9018d0d 100644 --- a/src/platform/src/lib.rs +++ b/src/platform/src/lib.rs @@ -32,18 +32,9 @@ use types::*; pub static mut errno: c_int = 0; pub unsafe fn c_str(s: *const c_char) -> &'static [u8] { - use core::slice; + use core::usize; - let mut size = 0; - - loop { - if *s.offset(size) == 0 { - break; - } - size += 1; - } - - slice::from_raw_parts(s as *const u8, size as usize) + c_str_n(s, usize::MAX) } pub unsafe fn c_str_n(s: *const c_char, n: usize) -> &'static [u8] { diff --git a/src/string/Cargo.toml b/src/string/Cargo.toml index a5678f9b05..36b34042a9 100644 --- a/src/string/Cargo.toml +++ b/src/string/Cargo.toml @@ -9,3 +9,4 @@ cbindgen = { path = "../../cbindgen" } [dependencies] platform = { path = "../platform" } +stdlib = { path = "../stdlib" } diff --git a/src/string/src/lib.rs b/src/string/src/lib.rs index c1b30f2289..4d1f6f5606 100644 --- a/src/string/src/lib.rs +++ b/src/string/src/lib.rs @@ -3,9 +3,11 @@ #![no_std] extern crate platform; +extern crate stdlib; use platform::types::*; use core::cmp; +use core::usize; #[no_mangle] pub extern "C" fn memccpy(s1: *mut c_void, s2: *const c_void, c: c_int, n: usize) -> *mut c_void { @@ -54,8 +56,8 @@ pub extern "C" fn memchr(s: *const c_void, c: c_int, n: usize) -> *mut c_void { // } #[no_mangle] -pub extern "C" fn strcat(s1: *mut c_char, s2: *const c_char) -> *mut c_char { - unimplemented!(); +pub unsafe extern "C" fn strcat(s1: *mut c_char, s2: *const c_char) -> *mut c_char { + strncat(s1, s2, usize::MAX) } #[no_mangle] @@ -64,8 +66,8 @@ pub extern "C" fn strchr(s: *const c_char, c: c_int) -> *mut c_char { } #[no_mangle] -pub extern "C" fn strcmp(s1: *const c_char, s2: *const c_char) -> c_int { - unimplemented!(); +pub unsafe extern "C" fn strcmp(s1: *const c_char, s2: *const c_char) -> c_int { + strncmp(s1, s2, usize::MAX) } #[no_mangle] @@ -74,8 +76,8 @@ pub extern "C" fn strcoll(s1: *const c_char, s2: *const c_char) -> c_int { } #[no_mangle] -pub extern "C" fn strcpy(s1: *mut c_char, s2: *const c_char) -> *mut c_char { - unimplemented!(); +pub unsafe extern "C" fn strcpy(s1: *mut c_char, s2: *const c_char) -> *mut c_char { + strncpy(s1, s2, usize::MAX) } #[no_mangle] @@ -84,8 +86,21 @@ pub extern "C" fn strcspn(s1: *const c_char, s2: *const c_char) -> c_ulong { } #[no_mangle] -pub extern "C" fn strdup(s1: *const c_char) -> *mut c_char { - unimplemented!(); +pub unsafe extern "C" fn strdup(s1: *const c_char) -> *mut c_char { + // the "+ 1" is to account for the NUL byte + let len = strlen(s1) + 1; + + let buffer = stdlib::malloc(len) as *mut _; + if buffer.is_null() { + // TODO: set errno + } else { + //memcpy(buffer, s1, len) + for i in 0..len as isize { + *buffer.offset(i) = *s1.offset(i); + } + } + + buffer } #[no_mangle] From ee824f3b19247b042337e4f9fb9aaabd9b4c8e54 Mon Sep 17 00:00:00 2001 From: Alex Lyon Date: Wed, 7 Mar 2018 15:59:58 -0800 Subject: [PATCH 2/5] string: implement strndup and strnlen --- src/string/src/lib.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/string/src/lib.rs b/src/string/src/lib.rs index 4d1f6f5606..4b091e399f 100644 --- a/src/string/src/lib.rs +++ b/src/string/src/lib.rs @@ -87,8 +87,13 @@ pub extern "C" fn strcspn(s1: *const c_char, s2: *const c_char) -> c_ulong { #[no_mangle] pub unsafe extern "C" fn strdup(s1: *const c_char) -> *mut c_char { + strndup(s1, usize::MAX) +} + +#[no_mangle] +pub unsafe extern "C" fn strndup(s1: *const c_char, size: usize) -> *mut c_char { // the "+ 1" is to account for the NUL byte - let len = strlen(s1) + 1; + let len = strnlen(s1, size) + 1; let buffer = stdlib::malloc(len) as *mut _; if buffer.is_null() { @@ -110,7 +115,12 @@ pub extern "C" fn strerror(errnum: c_int) -> *mut c_char { #[no_mangle] pub unsafe extern "C" fn strlen(s: *const c_char) -> size_t { - platform::c_str(s).len() as size_t + strnlen(s, usize::MAX) +} + +#[no_mangle] +pub unsafe extern "C" fn strnlen(s: *const c_char, size: usize) -> size_t { + platform::c_str_n(s, size).len() as size_t } #[no_mangle] From 3e1b945e99e254c7f93f28b423d1ee40a3fa7167 Mon Sep 17 00:00:00 2001 From: Alex Lyon Date: Wed, 7 Mar 2018 17:38:43 -0800 Subject: [PATCH 3/5] Add errno crate and set errno in strndup --- Cargo.lock | 10 +++ Cargo.toml | 1 + src/errno/Cargo.toml | 11 +++ src/errno/build.rs | 11 +++ src/errno/cbindgen.toml | 6 ++ src/errno/src/lib.rs | 166 ++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + src/string/Cargo.toml | 1 + src/string/src/lib.rs | 6 +- 9 files changed, 211 insertions(+), 2 deletions(-) create mode 100644 src/errno/Cargo.toml create mode 100644 src/errno/build.rs create mode 100644 src/errno/cbindgen.toml create mode 100644 src/errno/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 11a8c3c49a..c2ea9141fb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -75,6 +75,14 @@ name = "dtoa" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "errno" +version = "0.1.0" +dependencies = [ + "cbindgen 0.5.0", + "platform 0.1.0", +] + [[package]] name = "fcntl" version = "0.1.0" @@ -244,6 +252,7 @@ version = "0.1.0" dependencies = [ "compiler_builtins 0.1.0 (git+https://github.com/rust-lang-nursery/compiler-builtins.git)", "ctype 0.1.0", + "errno 0.1.0", "fcntl 0.1.0", "grp 0.1.0", "mman 0.1.0", @@ -453,6 +462,7 @@ name = "string" version = "0.1.0" dependencies = [ "cbindgen 0.5.0", + "errno 0.1.0", "platform 0.1.0", "stdlib 0.1.0", ] diff --git a/Cargo.toml b/Cargo.toml index 750853e3d4..5c7f356e87 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ members = ["src/crt0"] compiler_builtins = { git = "https://github.com/rust-lang-nursery/compiler-builtins.git", default-features = false, features = ["mem"] } platform = { path = "src/platform" } ctype = { path = "src/ctype" } +errno = { path = "src/errno" } fcntl = { path = "src/fcntl" } grp = { path = "src/grp" } semaphore = { path = "src/semaphore" } diff --git a/src/errno/Cargo.toml b/src/errno/Cargo.toml new file mode 100644 index 0000000000..cfaaad8465 --- /dev/null +++ b/src/errno/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "errno" +version = "0.1.0" +authors = ["Alex Lyon "] +build = "build.rs" + +[build-dependencies] +cbindgen = { path = "../../cbindgen" } + +[dependencies] +platform = { path = "../platform" } diff --git a/src/errno/build.rs b/src/errno/build.rs new file mode 100644 index 0000000000..5de392d433 --- /dev/null +++ b/src/errno/build.rs @@ -0,0 +1,11 @@ +extern crate cbindgen; + +use std::{env, fs}; + +fn main() { + let crate_dir = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set"); + fs::create_dir_all("../../target/include").expect("failed to create include directory"); + cbindgen::generate(crate_dir) + .expect("failed to generate bindings") + .write_to_file("../../target/include/errno.h"); +} diff --git a/src/errno/cbindgen.toml b/src/errno/cbindgen.toml new file mode 100644 index 0000000000..e71467bc3c --- /dev/null +++ b/src/errno/cbindgen.toml @@ -0,0 +1,6 @@ +sys_includes = [] +include_guard = "_ERRNO_H" +language = "C" + +[enum] +prefix_with_name = true diff --git a/src/errno/src/lib.rs b/src/errno/src/lib.rs new file mode 100644 index 0000000000..8a28cb6d3e --- /dev/null +++ b/src/errno/src/lib.rs @@ -0,0 +1,166 @@ +//! errno implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/errno.h.html + +#![no_std] + +extern crate platform; + +pub enum Errno { + // Argument list too long + E2BIG = 1, + // Permission denied + EACCES, + // Address in use + EADDRINUSE, + // Address not available + EADDRNOTAVAIL, + // Address family not supported + EAFNOSUPPORT, + // Resource unavailable, try again (may be the same value as [EWOULDBLOCK]) + EAGAIN, + // Connection already in progress + EALREADY, + // Bad file descriptor + EBADF, + // Bad message + EBADMSG, + // Device or resource busy + EBUSY, + // Operation canceled + ECANCELED, + // No child processes + ECHILD, + // Connection aborted + ECONNABORTED, + // Connection refused + ECONNREFUSED, + // Connection reset + ECONNRESET, + // Resource deadlock would occur + EDEADLK, + // Destination address required + EDESTADDRREQ, + // Mathematics argument out of domain of function + EDOM, + // Reserved + EDQUOT, + // File exists + EEXIST, + // Bad address + EFAULT, + // File too large + EFBIG, + // Host is unreachable + EHOSTUNREACH, + // Identifier removed + EIDRM, + // Illegal byte sequence + EILSEQ, + // Operation in progress + EINPROGRESS, + // Interrupted function + EINTR, + // Invalid argument + EINVAL, + // I/O error + EIO, + // Socket is connected + EISCONN, + // Is a directory + EISDIR, + // Too many levels of symbolic links + ELOOP, + // Too many open files + EMFILE, + // Too many links + EMLINK, + // Message too large + EMSGSIZE, + // Reserved + EMULTIHOP, + // Filename too long + ENAMETOOLONG, + // Network is down + ENETDOWN, + // Connection aborted by network + ENETRESET, + // Network unreachable + ENETUNREACH, + // Too many files open in system + ENFILE, + // No buffer space available + ENOBUFS, + // No message is available on the STREAM head read queue + ENODATA, + // No such device + ENODEV, + // No such file or directory + ENOENT, + // Executable file format error + ENOEXEC, + // No locks available + ENOLCK, + // Reserved + ENOLINK, + // Not enough space + ENOMEM, + // No message of the desired type + ENOMSG, + // Protocol not available + ENOPROTOOPT, + // No space left on device + ENOSPC, + // No STREAM resources + ENOSR, + // Not a STREAM + ENOSTR, + // Function not supported + ENOSYS, + // The socket is not connected + ENOTCONN, + // Not a directory + ENOTDIR, + // Directory not empty + ENOTEMPTY, + // Not a socket + ENOTSOCK, + // Not supported + ENOTSUP, + // Inappropriate I/O control operation + ENOTTY, + // No such device or address + ENXIO, + // Operation not supported on socket + EOPNOTSUPP, + // Value too large to be stored in data type + EOVERFLOW, + // Operation not permitted + EPERM, + // Broken pipe + EPIPE, + // Protocol error + EPROTO, + // Protocol not supported + EPROTONOSUPPORT, + // Protocol wrong type for socket + EPROTOTYPE, + // Result too large + ERANGE, + // Read-only file system + EROFS, + // Invalid seek + ESPIPE, + // No such process + ESRCH, + // Reserved + ESTALE, + // Stream ioctl() timeout + ETIME, + // Connection timed out + ETIMEDOUT, + // Text file busy + ETXTBSY, + // Operation would block (may be the same value as [EAGAIN]) + EWOULDBLOCK, + // Cross-device link + EXDEV +} diff --git a/src/lib.rs b/src/lib.rs index c4245e69c8..90c269714d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,7 @@ extern crate compiler_builtins; extern crate platform; extern crate ctype; +extern crate errno; extern crate fcntl; extern crate grp; extern crate mman; diff --git a/src/string/Cargo.toml b/src/string/Cargo.toml index 36b34042a9..d00a3e5c11 100644 --- a/src/string/Cargo.toml +++ b/src/string/Cargo.toml @@ -10,3 +10,4 @@ cbindgen = { path = "../../cbindgen" } [dependencies] platform = { path = "../platform" } stdlib = { path = "../stdlib" } +errno = { path = "../errno" } \ No newline at end of file diff --git a/src/string/src/lib.rs b/src/string/src/lib.rs index 4b091e399f..744e5411a9 100644 --- a/src/string/src/lib.rs +++ b/src/string/src/lib.rs @@ -4,8 +4,10 @@ extern crate platform; extern crate stdlib; +extern crate errno; use platform::types::*; +use errno::*; use core::cmp; use core::usize; @@ -95,9 +97,9 @@ pub unsafe extern "C" fn strndup(s1: *const c_char, size: usize) -> *mut c_char // the "+ 1" is to account for the NUL byte let len = strnlen(s1, size) + 1; - let buffer = stdlib::malloc(len) as *mut _; + let buffer = stdlib::malloc(len) as *mut c_char; if buffer.is_null() { - // TODO: set errno + platform::errno = Errno::ENOMEM as c_int; } else { //memcpy(buffer, s1, len) for i in 0..len as isize { From 629c20f097ed158233d65ca5ffc62e1c887709e6 Mon Sep 17 00:00:00 2001 From: Alex Lyon Date: Wed, 7 Mar 2018 17:46:00 -0800 Subject: [PATCH 4/5] string: ensure resulting string has NUL byte --- src/errno/src/lib.rs | 2 +- src/string/src/lib.rs | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/errno/src/lib.rs b/src/errno/src/lib.rs index 8a28cb6d3e..3cb5cd036c 100644 --- a/src/errno/src/lib.rs +++ b/src/errno/src/lib.rs @@ -162,5 +162,5 @@ pub enum Errno { // Operation would block (may be the same value as [EAGAIN]) EWOULDBLOCK, // Cross-device link - EXDEV + EXDEV, } diff --git a/src/string/src/lib.rs b/src/string/src/lib.rs index 744e5411a9..f8a6f42509 100644 --- a/src/string/src/lib.rs +++ b/src/string/src/lib.rs @@ -2,9 +2,9 @@ #![no_std] +extern crate errno; extern crate platform; extern crate stdlib; -extern crate errno; use platform::types::*; use errno::*; @@ -94,10 +94,10 @@ pub unsafe extern "C" fn strdup(s1: *const c_char) -> *mut c_char { #[no_mangle] pub unsafe extern "C" fn strndup(s1: *const c_char, size: usize) -> *mut c_char { - // the "+ 1" is to account for the NUL byte - let len = strnlen(s1, size) + 1; + let len = strnlen(s1, size); - let buffer = stdlib::malloc(len) as *mut c_char; + // the "+ 1" is to account for the NUL byte + let buffer = stdlib::malloc(len + 1) as *mut c_char; if buffer.is_null() { platform::errno = Errno::ENOMEM as c_int; } else { @@ -105,6 +105,7 @@ pub unsafe extern "C" fn strndup(s1: *const c_char, size: usize) -> *mut c_char for i in 0..len as isize { *buffer.offset(i) = *s1.offset(i); } + *buffer.offset(len as isize) = 0; } buffer From 851e4d399f9ae60ec3ffb7ba4b508db8db9562b1 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 7 Mar 2018 19:46:23 -0700 Subject: [PATCH 5/5] Fix errno.h definition --- include/errno.h | 2 +- src/lib.rs | 1 + tests/.gitignore | 1 + tests/Makefile | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/include/errno.h b/include/errno.h index f1761777c5..02b7e0c00f 100644 --- a/include/errno.h +++ b/include/errno.h @@ -1 +1 @@ -extern int errno; +extern __thread int errno; diff --git a/src/lib.rs b/src/lib.rs index 90c269714d..b3b38a57b8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,6 +9,7 @@ extern crate errno; extern crate fcntl; extern crate grp; extern crate mman; +extern crate semaphore; extern crate stdio; extern crate stdlib; extern crate string; diff --git a/tests/.gitignore b/tests/.gitignore index 759d9904ee..dead47ff35 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -6,6 +6,7 @@ /create.out /dup /dup.out +/error /fchdir /fsync /ftruncate diff --git a/tests/Makefile b/tests/Makefile index 41dc224061..8d87af542c 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -5,6 +5,7 @@ BINS=\ chdir \ create \ dup \ + error \ fchdir \ fsync \ ftruncate \