Selaa lähdekoodia

Merge branch 'master' into master

Tom Almeida 7 vuotta sitten
vanhempi
commit
90aec2076e

+ 1 - 0
.gitignore

@@ -1 +1,2 @@
 /target/
+.idea/

+ 8 - 3
.travis.yml

@@ -1,12 +1,17 @@
 language: rust
+env:
+  -
+  - TARGET=aarch64-unknown-linux-gnu
+  - TARGET=x86_64-unknown-redox
 rust:
   - nightly
 cache: cargo
 before_script:
   - rustup component add rustfmt-preview
-  - rustup target add x86_64-unknown-redox
-  - rustup target add aarch64-unknown-linux-gnu
+  - if [ -n "$TARGET" ]; then rustup target add $TARGET; fi
 script:
-  - bash ./ci.sh
+  - ./fmt.sh -- --write-mode=diff
+  - cargo build $([ -n "$TARGET" ] && echo --target="$TARGET")
+  - if [ -z "$TARGET" ]; then ./test.sh; fi
 notifications:
   email: false

+ 25 - 0
Cargo.lock

@@ -139,6 +139,14 @@ dependencies = [
  "platform 0.1.0",
 ]
 
+[[package]]
+name = "in_h"
+version = "0.1.0"
+dependencies = [
+ "cbindgen 0.5.2",
+ "platform 0.1.0",
+]
+
 [[package]]
 name = "itoa"
 version = "0.3.4"
@@ -182,6 +190,13 @@ dependencies = [
  "platform 0.1.0",
 ]
 
+[[package]]
+name = "netinet"
+version = "0.1.0"
+dependencies = [
+ "in_h 0.1.0",
+]
+
 [[package]]
 name = "num-traits"
 version = "0.2.1"
@@ -259,10 +274,12 @@ dependencies = [
  "float 0.1.0",
  "grp 0.1.0",
  "mman 0.1.0",
+ "netinet 0.1.0",
  "platform 0.1.0",
  "resource 0.1.0",
  "semaphore 0.1.0",
  "signal 0.1.0",
+ "socket 0.1.0",
  "stat 0.1.0",
  "stdio 0.1.0",
  "stdlib 0.1.0",
@@ -351,6 +368,14 @@ dependencies = [
  "platform 0.1.0",
 ]
 
+[[package]]
+name = "socket"
+version = "0.1.0"
+dependencies = [
+ "cbindgen 0.5.2",
+ "platform 0.1.0",
+]
+
 [[package]]
 name = "standalone-quote"
 version = "0.5.0"

+ 2 - 0
Cargo.toml

@@ -19,10 +19,12 @@ fenv = { path = "src/fenv" }
 float = { path = "src/float" }
 grp = { path = "src/grp" }
 mman = { path = "src/mman" }
+netinet = { path = "src/netinet" }
 platform = { path = "src/platform" }
 resource = { path = "src/resource" }
 semaphore = { path = "src/semaphore" }
 signal = { path = "src/signal" }
+socket = { path = "src/socket" }
 stat = { path = "src/stat" }
 stdio = { path = "src/stdio" }
 stdlib = { path = "src/stdlib" }

+ 0 - 12
ci.sh

@@ -1,12 +0,0 @@
-#!/bin/bash
-set -ex
-
-./fmt.sh -- --write-mode=diff
-./test.sh
-cargo build --target=x86_64-unknown-redox
-if [ $(arch) == "x86_64" ]
-then
-    cargo build --target=aarch64-unknown-linux-gnu
-else
-    cargo build --target=x86_64-unknown-linux-gnu
-fi

+ 2 - 0
src/lib.rs

@@ -11,8 +11,10 @@ extern crate fenv;
 extern crate float;
 extern crate grp;
 extern crate mman;
+extern crate netinet;
 extern crate resource;
 extern crate semaphore;
+extern crate socket;
 extern crate stat;
 extern crate stdio;
 extern crate stdlib;

+ 7 - 0
src/netinet/Cargo.toml

@@ -0,0 +1,7 @@
+[package]
+name = "netinet"
+version = "0.1.0"
+authors = ["Dan Robertson <[email protected]>"]
+
+[dependencies]
+in_h = { path = "in" }

+ 12 - 0
src/netinet/in/Cargo.toml

@@ -0,0 +1,12 @@
+[package]
+name = "in_h"
+version = "0.1.0"
+authors = ["Dan Robertson <[email protected]>"]
+build = "build.rs"
+
+[build-dependencies]
+cbindgen = { path = "../../../cbindgen" }
+
+[dependencies]
+platform = { path = "../../platform" }
+socket = { path = "../../socket" }

+ 12 - 0
src/netinet/in/build.rs

@@ -0,0 +1,12 @@
+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");
+    fs::create_dir_all("../../../target/include/netinet").expect("failed to create include directory");
+    cbindgen::generate(crate_dir)
+        .expect("failed to generate bindings")
+        .write_to_file("../../../target/include/netinet/in.h");
+}

+ 10 - 0
src/netinet/in/cbindgen.toml

@@ -0,0 +1,10 @@
+sys_includes = ["sys/types.h", "sys/socket.h"]
+include_guard = "_NETINET_IN_H"
+style = "Tag"
+language = "C"
+
+[export]
+include = ["sockaddr_in6", "sockaddr_in", "ipv6_mreq"]
+
+[enum]
+prefix_with_name = true

+ 58 - 0
src/netinet/in/src/lib.rs

@@ -0,0 +1,58 @@
+#![no_std]
+
+#![allow(non_camel_case_types)]
+
+extern crate platform;
+extern crate socket;
+
+use platform::types::*;
+use socket::sa_family_t;
+
+pub type in_addr_t = u32;
+pub type in_port_t = u16;
+
+#[repr(C)]
+#[derive(Debug)]
+pub struct in_addr {
+    pub s_addr: in_addr_t
+}
+
+#[repr(C)]
+pub struct in6_addr {
+    pub s6_addr: [u8; 16]
+}
+
+#[repr(C)]
+pub struct sockaddr_in {
+    pub sa_family: sa_family_t,
+    pub sin_port: in_port_t,
+    pub sin_addr: in_addr
+}
+
+#[repr(C)]
+pub struct sockaddr_in6 {
+    pub sin6_family: sa_family_t,
+    pub sin6_port: in_port_t,
+    pub sin6_flowinfo: u32,
+    pub sin6_addr: in6_addr,
+    pub sin6_scope_id: u32
+}
+
+#[repr(C)]
+pub struct ipv6_mreq {
+    pub ipv6mr_multiaddr: in6_addr,
+    pub ipv6mr_interface: u32,
+}
+
+// Address String Lengths
+pub const INET_ADDRSTRLEN: c_int = 16;
+pub const INET6_ADDRSTRLEN: c_int = 46;
+
+// Protocol Numbers
+pub const IPPROTO_IP: u8 = 0x00;
+pub const IPPROTO_ICMP: u8 = 0x01;
+pub const IPPROTO_TCP: u8 = 0x06;
+pub const IPPROTO_UDP: u8 = 0x11;
+pub const IPPROTO_IPV6: u8 = 0x29;
+pub const IPPROTO_RAW: u8 = 0xff;
+pub const IPPROTO_MAX: u8 = 0xff;

+ 3 - 0
src/netinet/src/lib.rs

@@ -0,0 +1,3 @@
+#![no_std]
+
+extern crate in_h;

+ 16 - 20
src/platform/src/redox/mod.rs

@@ -146,27 +146,23 @@ pub fn mkdir(path: *const c_char, mode: mode_t) -> c_int {
 }
 
 pub fn nanosleep(rqtp: *const timespec, rmtp: *mut timespec) -> c_int {
-    unsafe {
-        let redox_rqtp = redox_timespec {
-            tv_sec: (*rqtp).tv_sec,
-            tv_nsec: (*rqtp).tv_nsec as i32,
-        };
-        let mut redox_rmtp: redox_timespec;
-        if rmtp.is_null() {
-            redox_rmtp = redox_timespec::default();
-        } else {
-            redox_rmtp = redox_timespec {
-                tv_sec: (*rmtp).tv_sec,
-                tv_nsec: (*rmtp).tv_nsec as i32,
-            };
-        }
-        match e(syscall::nanosleep(&redox_rqtp, &mut redox_rmtp)) as c_int {
-            -1 => -1,
-            _ => {
-                (*rmtp).tv_sec = redox_rmtp.tv_sec;
-                (*rmtp).tv_nsec = redox_rmtp.tv_nsec as i64;
-                0
+    let redox_rqtp = unsafe { redox_timespec::from(&*rqtp) };
+    let mut redox_rmtp: redox_timespec;
+    if rmtp.is_null() {
+        redox_rmtp = redox_timespec::default();
+    } else {
+        redox_rmtp = unsafe { redox_timespec::from(&*rmtp) };
+    }
+    match e(syscall::nanosleep(&redox_rqtp, &mut redox_rmtp)) as c_int {
+        -1 => -1,
+        _ => {
+            unsafe {
+                if !rmtp.is_null() {
+                    (*rmtp).tv_sec = redox_rmtp.tv_sec;
+                    (*rmtp).tv_nsec = redox_rmtp.tv_nsec as i64;
+                }
             }
+            0
         }
     }
 }

+ 12 - 0
src/platform/src/types.rs

@@ -1,3 +1,5 @@
+#[cfg(target_os = "redox")]
+use syscall::data::TimeSpec as redox_timespec;
 // Use repr(u8) as LLVM expects `void*` to be the same as `i8*` to help enable
 // more optimization opportunities around it recognizing things like
 // malloc/free.
@@ -70,3 +72,13 @@ pub struct timespec {
     pub tv_sec: time_t,
     pub tv_nsec: c_long,
 }
+
+#[cfg(target_os = "redox")]
+impl<'a> From<&'a timespec> for redox_timespec {
+    fn from(tp: &timespec) -> redox_timespec {
+        redox_timespec {
+            tv_sec: tp.tv_sec,
+            tv_nsec: tp.tv_nsec as i32,
+        }
+    }
+}

+ 11 - 0
src/socket/Cargo.toml

@@ -0,0 +1,11 @@
+[package]
+name = "socket"
+version = "0.1.0"
+authors = ["Dan Robertson <[email protected]>"]
+build = "build.rs"
+
+[build-dependencies]
+cbindgen = { path = "../../cbindgen" }
+
+[dependencies]
+platform = { path = "../platform" }

+ 11 - 0
src/socket/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/sys/socket.h");
+}

+ 11 - 0
src/socket/cbindgen.toml

@@ -0,0 +1,11 @@
+sys_includes = ["sys/types.h"]
+include_guard = "_SYS_SOCKET_H"
+style = "Tag"
+language = "C"
+
+[defines]
+"target_os=linux" = "__linux__"
+"target_os=redox" = "__redox__"
+
+[enum]
+prefix_with_name = true

+ 153 - 0
src/socket/src/lib.rs

@@ -0,0 +1,153 @@
+//! socket implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xns/syssocket.h.html
+
+#![no_std]
+#![allow(non_camel_case_types)]
+
+extern crate platform;
+
+use platform::types::*;
+
+pub type sa_family_t = u16;
+pub type socklen_t = u32;
+
+#[repr(C)]
+pub struct sockaddr {
+    pub sa_family: sa_family_t,
+    pub sa_data: [c_char; 14],
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn accept(
+    socket: c_int,
+    address: *mut sockaddr,
+    address_len: *mut socklen_t,
+) -> c_int {
+    unimplemented!();
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn bind(
+    socket: c_int,
+    address: *const sockaddr,
+    address_len: socklen_t,
+) -> c_int {
+    unimplemented!();
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn connect(
+    socket: c_int,
+    address: *const sockaddr,
+    address_len: socklen_t,
+) -> c_int {
+    unimplemented!();
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn getpeername(
+    socket: c_int,
+    address: *const sockaddr,
+    address_len: socklen_t,
+) -> c_int {
+    unimplemented!();
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn getsockname(
+    socket: c_int,
+    address: *mut sockaddr,
+    address_len: *mut socklen_t,
+) -> c_int {
+    unimplemented!();
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn getsockopt(
+    socket: c_int,
+    level: c_int,
+    option_name: c_int,
+    option_value: *mut c_void,
+    option_len: *mut socklen_t,
+) -> c_int {
+    unimplemented!();
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn listen(socket: c_int, backlog: c_int) -> c_int {
+    unimplemented!();
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn recv(
+    socket: c_int,
+    buffer: *mut c_void,
+    length: size_t,
+    flags: c_int,
+) -> ssize_t {
+    unimplemented!();
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn recvfrom(
+    socket: c_int,
+    buffer: *mut c_void,
+    length: size_t,
+    flags: c_int,
+    address: *mut sockaddr,
+    address_len: *mut socklen_t,
+) -> ssize_t {
+    unimplemented!();
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn send(
+    socket: c_int,
+    message: *const c_void,
+    length: size_t,
+    flags: c_int,
+) -> ssize_t {
+    unimplemented!();
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn sento(
+    socket: c_int,
+    message: *const c_void,
+    length: size_t,
+    flags: c_int,
+    dest_addr: *const sockaddr,
+    dest_len: socklen_t,
+) -> ssize_t {
+    unimplemented!();
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn setsockopt(
+    socket: c_int,
+    level: c_int,
+    option_name: c_int,
+    option_value: *const c_void,
+    option_len: socklen_t,
+) -> c_int {
+    unimplemented!();
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn shutdown(socket: c_int, how: c_int) -> c_int {
+    unimplemented!();
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn socket(domain: c_int, _type: c_int, protocol: c_int) -> c_int {
+    unimplemented!();
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn socketpair(
+    domain: c_int,
+    _type: c_int,
+    protocol: c_int,
+    socket_vector: [c_int; 2],
+) -> c_int {
+    unimplemented!();
+}

+ 21 - 3
src/stdlib/src/lib.rs

@@ -130,15 +130,33 @@ pub extern "C" fn atol(s: *const c_char) -> c_long {
     dec_num_from_ascii!(s, c_long)
 }
 
+unsafe extern "C" fn void_cmp(a: *const c_void, b: *const c_void) -> c_int {
+    return *(a as *const i32) - *(b as *const i32) as c_int;
+}
+
 #[no_mangle]
-pub extern "C" fn bsearch(
+pub unsafe extern "C" fn bsearch(
     key: *const c_void,
     base: *const c_void,
     nel: size_t,
     width: size_t,
-    compar: Option<extern "C" fn(*const c_void, *const c_void) -> c_int>,
+    compar: Option<unsafe extern "C" fn(*const c_void, *const c_void) -> c_int>,
 ) -> *mut c_void {
-    unimplemented!();
+    let mut start = base;
+    let mut len = nel;
+    let cmp_fn = compar.unwrap_or(void_cmp);
+    while len > 0 {
+        let med = (start as size_t + (len >> 1) * width) as *const c_void;
+        let diff = cmp_fn(key, med);
+        if diff == 0 {
+            return med as *mut c_void;
+        } else if diff > 0 {
+            start = (med as usize + width) as *const c_void;
+            len -= 1;
+        }
+        len >>= 1;
+    }
+    ptr::null_mut()
 }
 
 #[no_mangle]

+ 36 - 4
src/string/src/lib.rs

@@ -323,17 +323,49 @@ pub unsafe extern "C" fn strstr(s1: *const c_char, s2: *const c_char) -> *mut c_
 }
 
 #[no_mangle]
-pub extern "C" fn strtok(s1: *mut c_char, s2: *const c_char) -> *mut c_char {
-    unimplemented!();
+pub extern "C" fn strtok(s1: *mut c_char, delimiter: *const c_char) -> *mut c_char {
+    static mut HAYSTACK: *mut c_char = ptr::null_mut();
+    unsafe {
+        return strtok_r(s1, delimiter, &mut HAYSTACK);
+    }
 }
 
 #[no_mangle]
 pub extern "C" fn strtok_r(
     s: *mut c_char,
-    sep: *const c_char,
+    delimiter: *const c_char,
     lasts: *mut *mut c_char,
 ) -> *mut c_char {
-    unimplemented!();
+    // Loosely based on GLIBC implementation
+    unsafe {
+        let mut haystack = s;
+        if haystack.is_null() {
+            if (*lasts).is_null() {
+                return ptr::null_mut();
+            }
+            haystack = *lasts;
+        }
+
+        // Skip past any extra delimiter left over from previous call
+        haystack = haystack.add(strspn(haystack, delimiter));
+        if *haystack == 0 {
+            *lasts = ptr::null_mut();
+            return ptr::null_mut();
+        }
+
+        // Build token by injecting null byte into delimiter
+        let token = haystack;
+        haystack = strpbrk(token, delimiter);
+        if !haystack.is_null() {
+            haystack.write(0);
+            haystack = haystack.add(1);
+            *lasts = haystack;
+        } else {
+            *lasts = ptr::null_mut();
+        }
+
+        return token;
+    }
 }
 
 #[no_mangle]

+ 1 - 0
tests/.gitignore

@@ -26,6 +26,7 @@
 /rmdir
 /setid
 /sprintf
+/stdlib/bsearch
 /stdlib/strtol
 /stdlib/a64l
 /stdio/fwrite

+ 3 - 0
tests/Makefile

@@ -25,6 +25,7 @@ EXPECT_BINS=\
 	stdio/fwrite \
 	stdio/all \
 	stdio/freopen \
+	stdlib/bsearch \
 	stdlib/strtol \
 	stdlib/a64l \
 	string/strncmp \
@@ -34,6 +35,8 @@ EXPECT_BINS=\
 	string/strspn \
 	string/strstr \
 	string/strpbrk \
+	string/strtok \
+	string/strtok_r \
 	unlink \
 	waitpid \
 	write

+ 0 - 0
tests/expected/string/strtok.stderr


+ 2 - 0
tests/expected/string/strtok.stdout

@@ -0,0 +1,2 @@
+I'd_just_like_to_interject_for_a_moment.__What_you're_referring_to_as_Linux,
+is_in_fact,_GNU/Linux,_or_as_I've_recently_taken_to_calling_it,_GNU_plus_Linux.

+ 0 - 0
tests/expected/string/strtok_r.stderr


+ 2 - 0
tests/expected/string/strtok_r.stdout

@@ -0,0 +1,2 @@
+I'd_just_like_to_interject_for_a_moment.__What_you're_referring_to_as_Linux,
+is_in_fact,_GNU/Linux,_or_as_I've_recently_taken_to_calling_it,_GNU_plus_Linux.

+ 55 - 0
tests/stdlib/bsearch.c

@@ -0,0 +1,55 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+int int_cmp(const void* a, const void* b) {
+  return *(const int*) a - *(const int*) b;
+}
+
+#define BSEARCH_TEST_INT(key, arr, len, expect) \
+  do { \
+    void* res = bsearch((const void*) &key, (void*) arr, len, sizeof(int), int_cmp); \
+    if (res != expect) { \
+      printf("FAIL bsearch for %d in [", key); \
+      size_t i = 0; \
+      for (; i < len; ++i) printf("%d,", arr[i]); \
+      printf("] expected %p but got %p\n", (void*) expect, res); \
+      return 1; \
+    } \
+  } while (0);
+
+
+
+int main(int argc, char* argv[]) {
+  int x = 0;
+  int y = 1024;
+  int empty[] = {};
+  BSEARCH_TEST_INT(x, empty, 0, NULL);
+
+  int singleton[] = {42};
+  printf("%p\n%p\n", singleton, &singleton[1]);
+  BSEARCH_TEST_INT(x, singleton, 1, NULL);
+  BSEARCH_TEST_INT(singleton[0], singleton, 1, &singleton[0]);
+  BSEARCH_TEST_INT(y, singleton, 1, NULL);
+
+  int two[] = {14, 42};
+  BSEARCH_TEST_INT(x, two, 2, NULL);
+  BSEARCH_TEST_INT(y, two, 2, NULL);
+  BSEARCH_TEST_INT(two[0], two, 2, &two[0]);
+  BSEARCH_TEST_INT(two[0], two, 1, &two[0]);
+  BSEARCH_TEST_INT(two[1], two, 2, &two[1]);
+  BSEARCH_TEST_INT(two[1], two, 1, NULL);
+
+  int three[] = {-5, -1, 4};
+  BSEARCH_TEST_INT(three[0], three, 3, &three[0]);
+  BSEARCH_TEST_INT(three[1], three, 3, &three[1]);
+  BSEARCH_TEST_INT(three[2], three, 3, &three[2]);
+
+  int big[] = {-19, -13, -7, -3, 2, 5, 11};
+  BSEARCH_TEST_INT(big[0], big, 7, big);
+  BSEARCH_TEST_INT(big[6], big, 7, &big[6]);
+  BSEARCH_TEST_INT(big[3], big, 7, &big[3]);
+  BSEARCH_TEST_INT(x, big, 7, NULL);
+
+  printf("PASS bsearch\n");
+  return 0;
+}

+ 17 - 0
tests/string/strtok.c

@@ -0,0 +1,17 @@
+#include <string.h>
+#include <stdio.h>
+
+int main(int argc, char* argv[]) {
+    char source[] = "I'd just like to interject for a moment.  What you're referring to as Linux, "
+                    "is in fact, GNU/Linux, or as I've recently taken to calling it, GNU plus Linux.\n";
+
+    char* token = strtok(source, " ");
+    while (token) {
+        printf("%s", token);
+        if (token = strtok(NULL, " ")) {
+            printf("_");
+        }
+    }
+
+    return 0;
+}

+ 18 - 0
tests/string/strtok_r.c

@@ -0,0 +1,18 @@
+#include <string.h>
+#include <stdio.h>
+
+int main(int argc, char* argv[]) {
+    char source[] = "I'd just like to interject for a moment.  What you're referring to as Linux, "
+                    "is in fact, GNU/Linux, or as I've recently taken to calling it, GNU plus Linux.\n";
+    char* sp;
+
+    char* token = strtok_r(source, " ", &sp);
+    while (token) {
+        printf("%s", token);
+        if (token = strtok_r(NULL, " ", &sp)) {
+            printf("_");
+        }
+    }
+
+    return 0;
+}