add stuff from old newlib to todo

This commit is contained in:
Paul Sajna
2018-03-04 05:08:32 -08:00
parent ee6ffbe73e
commit 460d7fb2c3
20 changed files with 2706 additions and 0 deletions
+22
View File
@@ -0,0 +1,22 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use alloc::String;
use alloc::Vec;
#[derive(Clone, Debug)]
pub struct DnsAnswer {
pub name: String,
pub a_type: u16,
pub a_class: u16,
pub ttl_a: u16,
pub ttl_b: u16,
pub data: Vec<u8>
}
+210
View File
@@ -0,0 +1,210 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
pub use self::answer::DnsAnswer;
pub use self::query::DnsQuery;
use core::slice;
use core::u16;
use alloc::String;
use alloc::Vec;
mod answer;
mod query;
#[allow(non_camel_case_types)]
#[derive(Copy, Clone, Debug, Default)]
#[repr(packed)]
pub struct n16 {
inner: u16
}
impl n16 {
pub fn as_bytes(&self) -> &[u8] {
unsafe { slice::from_raw_parts((&self.inner as *const u16) as *const u8, 2) }
}
pub fn from_bytes(bytes: &[u8]) -> Self {
n16 {
inner: unsafe { slice::from_raw_parts(bytes.as_ptr() as *const u16, bytes.len()/2)[0] }
}
}
}
impl From<u16> for n16 {
fn from(value: u16) -> Self {
n16 {
inner: value.to_be()
}
}
}
impl From<n16> for u16 {
fn from(value: n16) -> Self {
u16::from_be(value.inner)
}
}
#[derive(Clone, Debug)]
pub struct Dns {
pub transaction_id: u16,
pub flags: u16,
pub queries: Vec<DnsQuery>,
pub answers: Vec<DnsAnswer>
}
impl Dns {
pub fn compile(&self) -> Vec<u8> {
let mut data = Vec::new();
macro_rules! push_u8 {
($value:expr) => {
data.push($value);
};
};
macro_rules! push_n16 {
($value:expr) => {
data.extend_from_slice(n16::from($value).as_bytes());
};
};
push_n16!(self.transaction_id);
push_n16!(self.flags);
push_n16!(self.queries.len() as u16);
push_n16!(self.answers.len() as u16);
push_n16!(0);
push_n16!(0);
for query in self.queries.iter() {
for part in query.name.split('.') {
push_u8!(part.len() as u8);
data.extend_from_slice(part.as_bytes());
}
push_u8!(0);
push_n16!(query.q_type);
push_n16!(query.q_class);
}
data
}
pub fn parse(data: &[u8]) -> Result<Self, String> {
let name_ind = 0b11000000;
let mut i = 0;
macro_rules! pop_u8 {
() => {
{
i += 1;
if i > data.len() {
return Err(format!("{}: {}: pop_u8", file!(), line!()));
}
data[i - 1]
}
};
};
macro_rules! pop_n16 {
() => {
{
i += 2;
if i > data.len() {
return Err(format!("{}: {}: pop_n16", file!(), line!()));
}
u16::from(n16::from_bytes(&data[i - 2 .. i]))
}
};
};
macro_rules! pop_data {
() => {
{
let mut data = Vec::new();
let data_len = pop_n16!();
for _data_i in 0..data_len {
data.push(pop_u8!());
}
data
}
};
};
macro_rules! pop_name {
() => {
{
let mut name = String::new();
let old_i = i;
loop {
let name_len = pop_u8!();
if name_len & name_ind == name_ind {
i -= 1;
i = (pop_n16!() - ((name_ind as u16) << 8)) as usize;
continue;
}
if name_len == 0 {
break;
}
if ! name.is_empty() {
name.push('.');
}
for _name_i in 0..name_len {
name.push(pop_u8!() as char);
}
}
if i <= old_i {
i = old_i + 2;
}
name
}
};
};
let transaction_id = pop_n16!();
let flags = pop_n16!();
let queries_len = pop_n16!();
let answers_len = pop_n16!();
pop_n16!();
pop_n16!();
let mut queries = Vec::new();
for _query_i in 0..queries_len {
queries.push(DnsQuery {
name: pop_name!(),
q_type: pop_n16!(),
q_class: pop_n16!()
});
}
let mut answers = Vec::new();
for _answer_i in 0..answers_len {
answers.push(DnsAnswer {
name: pop_name!(),
a_type: pop_n16!(),
a_class: pop_n16!(),
ttl_a: pop_n16!(),
ttl_b: pop_n16!(),
data: pop_data!()
});
}
Ok(Dns {
transaction_id: transaction_id,
flags: flags,
queries: queries,
answers: answers,
})
}
}
+18
View File
@@ -0,0 +1,18 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use alloc::String;
#[derive(Clone, Debug)]
pub struct DnsQuery {
pub name: String,
pub q_type: u16,
pub q_class: u16
}
+51
View File
@@ -0,0 +1,51 @@
use core::slice;
use libc::{c_int, c_uint};
use syscall::error::{Error, EINVAL};
use types::{fd_set, pollfd, timeval, FD_SETSIZE, POLLIN, POLLOUT, NFDBITS};
libc_fn!(unsafe poll(fds: *mut pollfd, nfds: c_uint, timeout: c_int) -> Result<c_int> {
let fds = slice::from_raw_parts_mut(fds, nfds as usize);
let mut ret = 0;
for fd in fds.iter_mut() {
// always ready for read or write
fd.revents = fd.events & (POLLIN | POLLOUT);
if fd.revents != 0 {
ret += 1;
}
}
Ok(ret)
});
libc_fn!(unsafe select(nfds: c_int, readfds: *mut fd_set, writefds: *mut fd_set, errorfds: *mut fd_set, _timeout: *mut timeval) -> Result<c_int> {
if nfds < 0 || nfds > FD_SETSIZE as i32 {
return Err(Error::new(EINVAL));
}
let mut ret = 0;
for i in 0..nfds as usize {
if ! readfds.is_null() {
// always ready to read
if ((*readfds).fds_bits[i/NFDBITS] & (1 << (i % NFDBITS))) != 0 {
ret += 1;
}
}
if ! writefds.is_null() {
// always ready to write
if ((*writefds).fds_bits[i/NFDBITS] & (1 << (i % NFDBITS))) != 0 {
ret += 1;
}
}
if ! errorfds.is_null() {
// report no errors
if ((*errorfds).fds_bits[i/NFDBITS] & (1 << (i % NFDBITS))) != 0 {
(*errorfds).fds_bits[i/NFDBITS] &= !(1 << (i % NFDBITS));
}
}
}
Ok(ret)
});
+188
View File
@@ -0,0 +1,188 @@
use syscall::{self, O_CLOEXEC, O_STAT, O_CREAT, O_EXCL, O_DIRECTORY, O_WRONLY, O_NOFOLLOW, TimeSpec};
use core::slice;
use libc::{c_int, c_char, off_t, mode_t, size_t, ssize_t};
use ::types::{utimbuf, timeval};
pub const PATH_MAX: usize = 4096;
libc_fn!(unsafe access(path: *mut c_char, _amode: c_int) -> Result<c_int> {
// XXX amode
::RawFile::open(::cstr_to_slice(path), O_CLOEXEC | O_STAT)?;
Ok(0)
});
libc_fn!(unsafe _close(file: c_int) -> Result<c_int> {
Ok(syscall::close(file as usize)? as c_int)
});
libc_fn!(unsafe dup(file: c_int) -> Result<c_int> {
Ok(syscall::dup(file as usize, &[])? as c_int)
});
libc_fn!(unsafe dup2(file: c_int, newfile: c_int) -> Result<c_int> {
Ok(syscall::dup2(file as usize, newfile as usize, &[])? as c_int)
});
libc_fn!(unsafe _fstat(file: c_int, st: *mut syscall::Stat) -> Result<c_int> {
Ok(syscall::fstat(file as usize, &mut *st)? as c_int)
});
libc_fn!(unsafe _fsync(file: c_int) -> Result<c_int> {
Ok(syscall::fsync(file as usize)? as c_int)
});
libc_fn!(unsafe ftruncate(file: c_int, len: off_t) -> Result<c_int> {
Ok(syscall::ftruncate(file as usize, len as usize)? as c_int)
});
libc_fn!(unsafe _lseek(file: c_int, ptr: off_t, dir: c_int) -> Result<off_t> {
Ok(syscall::lseek(file as usize, ptr as isize, dir as usize)? as off_t)
});
libc_fn!(unsafe mkdir(path: *mut c_char, mode: mode_t) -> Result<c_int> {
let flags = O_CREAT | O_EXCL | O_CLOEXEC | O_DIRECTORY | (mode as usize & 0o777);
::RawFile::open(::cstr_to_slice(path), flags)?;
Ok(0)
});
libc_fn!(unsafe _open(path: *mut c_char, flags: c_int, mode: mode_t) -> Result<c_int> {
let mut path = ::cstr_to_slice(path);
// XXX hack; use better method if possible
if path == b"/dev/null" {
path = b"null:"
}
Ok(syscall::open(path, flags as usize | (mode as usize & 0o777))? as c_int)
});
libc_fn!(unsafe pipe(pipefd: *mut [c_int; 2]) -> c_int {
pipe2(pipefd, 0)
});
libc_fn!(unsafe pipe2(pipefd: *mut [c_int; 2], flags: c_int) -> Result<c_int> {
let mut syspipefd = [(*pipefd)[0] as usize, (*pipefd)[1] as usize];
syscall::pipe2(&mut syspipefd, flags as usize)?;
(*pipefd)[0] = syspipefd[0] as c_int;
(*pipefd)[1] = syspipefd[1] as c_int;
Ok(0)
});
libc_fn!(unsafe _read(file: c_int, buf: *mut c_char, len: c_int) -> Result<c_int> {
let buf = slice::from_raw_parts_mut(buf as *mut u8, len as usize);
Ok(syscall::read(file as usize, buf)? as c_int)
});
libc_fn!(unsafe rmdir(path: *mut c_char) -> Result<c_int> {
Ok(syscall::rmdir(::cstr_to_slice(path))? as c_int)
});
libc_fn!(unsafe _stat(path: *const c_char, st: *mut syscall::Stat) -> Result<c_int> {
let fd = ::RawFile::open(::cstr_to_slice(path), O_CLOEXEC | O_STAT)?;
Ok(syscall::fstat(*fd, &mut *st)? as c_int)
});
libc_fn!(unsafe lstat(path: *const c_char, st: *mut syscall::Stat) -> Result<c_int> {
let fd = ::RawFile::open(::cstr_to_slice(path), O_CLOEXEC | O_STAT | O_NOFOLLOW)?;
Ok(syscall::fstat(*fd, &mut *st)? as c_int)
});
libc_fn!(unsafe _unlink(path: *mut c_char) -> Result<c_int> {
Ok(syscall::unlink(::cstr_to_slice(path))? as c_int)
});
libc_fn!(unsafe _write(file: c_int, buf: *const c_char, len: c_int) -> Result<c_int> {
let buf = slice::from_raw_parts(buf as *const u8, len as usize);
Ok(syscall::write(file as usize, buf)? as c_int)
});
libc_fn!(unsafe chmod(path: *mut c_char, mode: mode_t) -> Result<c_int> {
Ok(syscall::chmod(::cstr_to_slice(path), mode as usize)? as c_int)
});
libc_fn!(unsafe realpath(path: *const c_char, resolved_path: *mut c_char) -> Result<*mut c_char> {
let fd = ::RawFile::open(::cstr_to_slice(path), O_STAT)?;
let resolved_path = ::MallocNull::new(resolved_path, PATH_MAX);
let buf = slice::from_raw_parts_mut(resolved_path.as_mut_ptr() as *mut u8, PATH_MAX-1);
let length = syscall::fpath(*fd, buf)?;
buf[length] = b'\0';
Ok(resolved_path.into_raw())
});
libc_fn!(unsafe _rename(old: *const c_char, new: *const c_char) -> Result<c_int> {
// XXX fix this horror when the kernel provides rename() or link()
let old = ::cstr_to_slice(old);
let new = ::cstr_to_slice(new);
let buf = ::file_read_all(old)?;
let mut stat = syscall::Stat::default();
let fd = ::RawFile::open(old, syscall::O_STAT)?;
syscall::fstat(*fd, &mut stat)?;
drop(fd);
let mode = (stat.st_mode & 0o777) as usize;
let fd = ::RawFile::open(new, O_CREAT | O_WRONLY | mode)?;
syscall::write(*fd, &buf)?;
syscall::unlink(old)?;
Ok(0)
});
libc_fn!(fsync(fd: c_int) -> Result<c_int> {
Ok(syscall::fsync(fd as usize)? as c_int)
});
libc_fn!(unsafe symlink(path1: *const c_char, path2: *const c_char) -> Result<c_int> {
let fd = ::RawFile::open(::cstr_to_slice(path2), syscall::O_SYMLINK | syscall::O_CREAT | syscall::O_WRONLY | 0o777)?;
syscall::write(*fd, ::cstr_to_slice(path1))?;
Ok(0)
});
libc_fn!(unsafe readlink(path: *const c_char, buf: *const c_char, bufsize: size_t) -> Result<ssize_t> {
let fd = ::RawFile::open(::cstr_to_slice(path), syscall::O_SYMLINK | syscall::O_RDONLY)?;
let count = syscall::read(*fd, slice::from_raw_parts_mut(buf as *mut u8, bufsize))?;
Ok(count as ssize_t)
});
libc_fn!(unsafe utime(path: *mut c_char, times: *const utimbuf) -> Result<c_int> {
let times = if times.is_null() {
let mut tp = TimeSpec::default();
syscall::clock_gettime(syscall::flag::CLOCK_REALTIME, &mut tp)?;
[tp, tp]
} else {
[TimeSpec { tv_sec: (*times).actime, tv_nsec: 0 },
TimeSpec { tv_sec: (*times).modtime, tv_nsec: 0 }]
};
let fd = ::RawFile::open(::cstr_to_slice(path), 0)?;
syscall::futimens(*fd, &times)?;
Ok(0)
});
libc_fn!(unsafe utimes(path: *mut c_char, times: *const [timeval; 2]) -> Result<c_int> {
let times = [TimeSpec { tv_sec: (*times)[0].tv_sec, tv_nsec: (*times)[0].tv_usec as i32 * 1000 },
TimeSpec { tv_sec: (*times)[1].tv_sec, tv_nsec: (*times)[0].tv_usec as i32 * 1000 }];
let fd = ::RawFile::open(::cstr_to_slice(path), 0)?;
syscall::futimens(*fd, &times)?;
Ok(0)
});
libc_fn!(unsafe futimens(fd: c_int, times: *const [TimeSpec; 2]) -> Result<c_int> {
// XXX UTIME_NOW and UTIME_OMIT (in redoxfs?)
syscall::futimens(fd as usize, &*times)?;
Ok(0)
});
// XXX variadic
libc_fn!(_fcntl(file: c_int, cmd: c_int, arg: c_int) -> Result<c_int> {
Ok(syscall::fcntl(file as usize, cmd as usize, arg as usize)? as c_int)
});
libc_fn!(_isatty(file: c_int) -> c_int {
if let Ok(fd) = syscall::dup(file as usize, b"termios") {
let _ = syscall::close(fd);
1
} else {
0
}
});
+94
View File
@@ -0,0 +1,94 @@
extern crate libc;
extern crate core;
use ::{c_int, c_char};
use syscall::{self, O_CLOEXEC, O_RDONLY, O_DIRECTORY};
use core::ptr::null;
use core::default::Default;
use alloc::boxed::Box;
use ::file::PATH_MAX;
use ::types::{ino_t, off_t};
use libc::*;
#[repr(C)]
pub struct dirent {
pub d_ino: ino_t,
pub d_off: off_t,
pub d_reclen: c_ushort,
pub d_type: c_uchar,
pub d_name: [c_char; PATH_MAX]
}
impl core::default::Default for dirent {
fn default() -> dirent {
dirent {
d_ino: 0,
d_off: 0,
d_reclen: 0,
d_type: 0,
d_name: [0; PATH_MAX],
}
}
}
pub struct DIR {
pub fd: ::RawFile,
pub ent: dirent,
pub buf: [u8; PATH_MAX],
pub count: usize,
pub pos: usize
}
libc_fn!(unsafe opendir(path: *mut c_char) -> Result<*mut DIR> {
let path = ::cstr_to_slice(path);
let fd = ::RawFile::open(path, O_RDONLY | O_CLOEXEC | O_DIRECTORY)?;
let dir = Box::new(DIR {
fd,
ent: dirent::default(),
buf: [0; PATH_MAX],
count: 0,
pos: 0
});
Ok(Box::into_raw(dir))
});
libc_fn!(unsafe readdir(dir: *mut DIR) -> Result<*const dirent> {
if let Some(dir) = dir.as_mut() {
let mut i = 0;
'outer: while i < PATH_MAX - 1 {
while dir.pos < dir.count {
dir.ent.d_name[i] = dir.buf[dir.pos] as c_char;
dir.pos += 1;
if dir.buf[dir.pos-1] == b'\n' {
break 'outer;
}
i += 1;
}
dir.count = syscall::read(*dir.fd, &mut dir.buf)?;
if dir.count == 0 {
break;
}
dir.pos = 0;
}
if i != 0 {
dir.ent.d_name[i] = 0;
return Ok(&dir.ent);
}
}
Ok(null())
});
libc_fn!(unsafe rewinddir(dir: *mut DIR) {
if let Some(dir) = dir.as_mut() {
dir.count = 0;
let _ = syscall::lseek(*dir.fd, 0, syscall::SEEK_SET);
}
});
libc_fn!(unsafe closedir(dir: *mut DIR) -> Result<c_int> {
Box::from_raw(dir);
Ok(0)
});
libc_fn!(unsafe dirfd(dir: *mut DIR) -> Result<c_int> {
Ok(*(*dir).fd as i32)
});
+107
View File
@@ -0,0 +1,107 @@
use core::ptr::null;
use core::{mem, str, slice};
use alloc::vec::IntoIter;
use alloc::string::ToString;
use alloc::{Vec, String};
use ::dns::{Dns, DnsQuery};
use syscall::{self, Result, EINVAL, Error};
use libc::{c_char, size_t, c_int};
use ::types::{in_addr, hostent};
static mut HOST_ENTRY: hostent = hostent { h_name: null(), h_aliases: null(), h_addrtype: 0, h_length: 0, h_addr_list: null() };
static mut HOST_NAME: Option<Vec<u8>> = None;
static mut HOST_ALIASES: [*const c_char; 1] = [null()];
static mut HOST_ADDR: Option<in_addr> = None;
static mut HOST_ADDR_LIST: [*const c_char; 2] = [null(); 2];
struct LookupHost(IntoIter<in_addr>);
impl Iterator for LookupHost {
type Item = in_addr;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
// Modified from rust/sys/redox/net/mod.rs
fn lookup_host(host: &str) -> Result<LookupHost> {
// XXX better error handling
let ip_string = String::from_utf8(::file_read_all("/etc/net/ip")?)
.or(Err(Error::new(syscall::EIO)))?;
let ip: Vec<u8> = ip_string.trim().split(".").map(|part| part.parse::<u8>()
.unwrap_or(0)).collect();
let dns_string = String::from_utf8(::file_read_all("/etc/net/dns")?)
.or(Err(Error::new(syscall::EIO)))?;
let dns: Vec<u8> = dns_string.trim().split(".").map(|part| part.parse::<u8>()
.unwrap_or(0)).collect();
if ip.len() == 4 && dns.len() == 4 {
let mut timespec = syscall::TimeSpec::default();
syscall::clock_gettime(syscall::CLOCK_REALTIME, &mut timespec).unwrap();
let tid = (timespec.tv_nsec >> 16) as u16;
let packet = Dns {
transaction_id: tid,
flags: 0x0100,
queries: vec![DnsQuery {
name: host.to_string(),
q_type: 0x0001,
q_class: 0x0001,
}],
answers: vec![]
};
let packet_data = packet.compile();
let fd = ::RawFile::open(format!("udp:/{}.{}.{}.{}:0",
ip[0], ip[1], ip[2], ip[3]).as_bytes(),
syscall::O_RDWR)?;
let timeout = syscall::TimeSpec {
tv_sec: 5,
tv_nsec: 0,
};
let rt = fd.dup(b"read_timeout")?;
syscall::write(*rt, &timeout)?;
drop(rt);
let wt = fd.dup(b"write_timeout")?;
syscall::write(*wt, &timeout)?;
drop(wt);
let sendrecvfd = fd.dup(format!("{}.{}.{}.{}:53", dns[0], dns[1], dns[2], dns[3]).as_bytes())?;
syscall::write(*sendrecvfd, &packet_data)?;
let mut buf = [0; 65536];
let count = syscall::read(*sendrecvfd, &mut buf)?;
drop(sendrecvfd);
drop(fd);
match Dns::parse(&buf[.. count]) {
Ok(response) => {
let mut addrs = vec![];
for answer in response.answers.iter() {
if answer.a_type == 0x0001 && answer.a_class == 0x0001
&& answer.data.len() == 4
{
let addr = in_addr {
s_addr: [answer.data[0], answer.data[1], answer.data[2], answer.data[3]]
};
addrs.push(addr);
}
}
Ok(LookupHost(addrs.into_iter()))
},
Err(_err) => Err(Error::new(EINVAL))
}
} else {
Err(Error::new(EINVAL))
}
}
libc_fn!(unsafe gethostname(name: *mut c_char, namelen: size_t) -> Result<c_int> {
let slice = slice::from_raw_parts_mut(name as *mut u8, namelen);
let fd = ::RawFile::open("/etc/hostname", syscall::O_RDONLY)?;
let len = syscall::read(*fd, &mut slice[..namelen-1])?;
slice[len] = b'\0';
Ok(0)
});
+211
View File
@@ -0,0 +1,211 @@
#![no_std]
#![feature(
alloc,
allocator_api,
alloc_system,
compiler_builtins_lib,
const_fn,
const_ptr_null,
core_intrinsics,
global_allocator,
lang_items,
linkage,
const_size_of,
const_cell_new,
)]
#[macro_use]
extern crate alloc;
extern crate alloc_system;
extern crate byteorder;
extern crate compiler_builtins;
extern crate libc;
extern crate syscall;
extern crate redox_termios;
use alloc::Vec;
use alloc::String;
use alloc::fmt::Write;
use alloc::boxed::Box;
use core::{ptr, mem, intrinsics, slice, str};
use libc::{c_int, c_void, c_char, size_t};
#[macro_use]
mod macros;
mod types;
mod dns;
mod mallocnull;
mod rawfile;
pub mod event;
pub mod process;
pub mod file;
pub mod folder;
pub mod time;
pub mod unimpl;
pub mod user;
pub mod redox;
pub mod socket;
pub mod hostname;
pub mod termios;
pub mod netdb;
pub use mallocnull::MallocNull;
pub use rawfile::RawFile;
#[global_allocator]
static ALLOCATOR: alloc_system::System = alloc_system::System;
extern "C" {
// Newlib uses this function instead of just a global to support reentrancy
pub fn __errno() -> *mut c_int;
pub fn malloc(size: size_t) -> *mut c_void;
pub fn free(ptr: *mut c_void);
pub fn strlen(s: *const c_char) -> size_t;
pub fn __libc_fini_array();
pub static mut environ: *mut *mut c_char;
}
pub unsafe fn cstr_to_slice<'a>(buf: *const c_char) -> &'a [u8] {
slice::from_raw_parts(buf as *const u8, ::strlen(buf) as usize)
}
pub unsafe fn cstr_to_slice_mut<'a>(buf: *const c_char) -> &'a mut [u8] {
slice::from_raw_parts_mut(buf as *mut u8, ::strlen(buf) as usize)
}
pub fn file_read_all<T: AsRef<[u8]>>(path: T) -> syscall::Result<Vec<u8>> {
let fd = RawFile::open(path, syscall::O_RDONLY)?;
let mut st = syscall::Stat::default();
syscall::fstat(*fd, &mut st)?;
let size = st.st_size as usize;
let mut buf = Vec::with_capacity(size);
unsafe { buf.set_len(size) };
syscall::read(*fd, buf.as_mut_slice())?;
Ok(buf)
}
/// Implements an `Iterator` which returns on either newline or EOF.
#[derive(Clone, Copy)]
pub struct RawLineBuffer {
fd: usize,
cur: usize,
read: usize,
buf: [u8; 8 * 1024],
}
impl Default for RawLineBuffer {
fn default() -> RawLineBuffer {
RawLineBuffer {
fd: 0,
cur: 0,
read: 0,
buf: unsafe { mem::uninitialized() },
}
}
}
impl RawLineBuffer {
fn new(fd: usize) -> RawLineBuffer {
RawLineBuffer {
fd: fd,
cur: 0,
read: 0,
buf: unsafe { mem::uninitialized() },
}
}
}
impl Iterator for RawLineBuffer {
type Item = syscall::Result<Box<str>>;
fn next(&mut self) -> Option<Self::Item> {
if self.cur != 0 && self.read != 0 {
if let Some(mut pos) = self.buf[self.cur..self.read].iter().position(
|&x| x == b'\n',
)
{
pos += self.cur + 1;
let line = unsafe { str::from_utf8_unchecked(&self.buf[self.cur..pos]) };
let boxed_array: Box<[u8]> = Box::from(line.as_bytes());
let boxed_line: Box<str> = unsafe { mem::transmute(boxed_array) };
self.cur = pos;
return Some(Ok(boxed_line));
}
let mut temp: [u8; 8 * 1024] = unsafe { mem::uninitialized() };
unsafe {
ptr::copy(self.buf[self.cur..].as_ptr(), temp.as_mut_ptr(), self.read);
ptr::swap(self.buf.as_mut_ptr(), temp.as_mut_ptr());
};
self.read -= self.cur;
self.cur = 0;
}
let end = match syscall::read(self.fd, &mut self.buf[self.cur..]).unwrap() {
0 => return None,
read => {
self.read += read;
self.buf[..self.read]
.iter()
.position(|&x| x == b'\n')
.unwrap_or(0)
}
};
self.cur = end;
let line = unsafe { str::from_utf8_unchecked(&self.buf[..end]) };
let boxed_array: Box<[u8]> = Box::from(line.as_bytes());
let boxed_line: Box<str> = unsafe { mem::transmute(boxed_array) };
Some(Ok(boxed_line))
}
}
#[no_mangle]
pub unsafe extern "C" fn __errno_location() -> *mut c_int {
__errno()
}
#[lang = "eh_personality"]
pub extern "C" fn eh_personality() {}
#[lang = "panic_fmt"]
#[linkage = "weak"]
#[no_mangle]
pub extern "C" fn rust_begin_unwind(_msg: core::fmt::Arguments,
_file: &'static str,
_line: u32,
_col: u32) -> ! {
let mut s = String::new();
let _ = s.write_fmt(_msg);
let _ = syscall::write(2, _file.as_bytes());
let _ = syscall::write(2, "\n".as_bytes());
let _ = syscall::write(2, s.as_bytes());
let _ = syscall::write(2, "\n".as_bytes());
unsafe { intrinsics::abort() }
}
libc_fn!(unsafe initialize_standard_library() {
let mut buf = file_read_all("env:").unwrap();
let size = buf.len();
buf.push(0);
let mut vars = Vec::new();
vars.push(&mut buf[0] as *mut u8 as *mut c_char);
for i in 0..size {
if buf[i] == b'\n' {
if i != size - 1 {
vars.push(&mut buf[i + 1] as *mut u8 as *mut c_char);
}
buf[i] = b'\0';
}
}
vars.push(ptr::null_mut());
environ = vars.as_mut_ptr();
mem::forget(vars); // Do not free memory
mem::forget(buf);
});
+120
View File
@@ -0,0 +1,120 @@
use core::ptr;
use core::any::Any;
/// This struct converts to `NULL` for raw pointers, and `-1` for signed
/// integers.
pub struct Fail;
impl<T: Any> Into<*const T> for Fail {
#[inline(always)]
fn into(self) -> *const T {
ptr::null()
}
}
impl<T: Any> Into<*mut T> for Fail {
#[inline(always)]
fn into(self) -> *mut T {
ptr::null_mut()
}
}
macro_rules! int_fail {
($type:ty) => (
impl Into<$type> for Fail {
#[inline(always)]
fn into(self) -> $type {
-1
}
}
)
}
int_fail!(i8);
int_fail!(i16);
int_fail!(i32);
int_fail!(i64);
int_fail!(isize);
/// If `res` is `Err(..)`, set `errno` and return `-1` or `NULL`, otherwise
/// unwrap.
macro_rules! try_call {
($res:expr) => (
match $res {
Ok(val) => val,
Err(err) => {
*::__errno() = err.errno;
return ::macros::Fail.into();
}
}
);
}
/// Declares a libc function. The body should return syscall::Result, which
/// is used to set errno on error with try_call!
///
/// ```
/// libc_fn!(foo(arg: c_int) -> c_int) {
/// Ok(arg)
/// }
/// ```
///
/// The `unsafe` keyword can be added to make the function unsafe:
///
/// ```
/// libc_fn!(unsafe foo(arg: c_int) -> c_int) {
/// Ok(arg)
/// }
/// ```
macro_rules! libc_fn {
// The next 2 cases handle Result return values, and convert to errno+return
// Call with arguments and return value
($name:ident($($aname:ident : $atype:ty),*) -> Result<$rtype:ty> $content:block) => {
#[no_mangle]
pub extern "C" fn $name($($aname: $atype,)*) -> $rtype {
#[inline(always)]
fn inner($($aname: $atype,)*) -> ::syscall::Result<$rtype> {
$content
}
unsafe { try_call!(inner($($aname,)*)) }
}
};
// Call with `unsafe` keyword (and arguments, return value)
(unsafe $name:ident($($aname:ident : $atype:ty),*) -> Result<$rtype:ty> $content:block) => {
#[no_mangle]
pub unsafe extern "C" fn $name($($aname: $atype,)*) -> $rtype {
#[inline(always)]
unsafe fn inner($($aname: $atype,)*) -> ::syscall::Result<$rtype> {
$content
}
try_call!(inner($($aname,)*))
}
};
// The next 2 cases handle non-Result return values
($name:ident($($aname:ident : $atype:ty),*) -> $rtype:ty $content:block) => {
#[no_mangle]
pub extern "C" fn $name($($aname: $atype,)*) -> $rtype {
$content
}
};
(unsafe $name:ident($($aname:ident : $atype:ty),*) -> $rtype:ty $content:block) => {
#[no_mangle]
pub unsafe extern "C" fn $name($($aname: $atype,)*) -> $rtype {
$content
}
};
// The next 2 cases handle calls with no return value
($name:ident($($aname:ident : $atype:ty),*) $content:block) => {
#[no_mangle]
pub extern "C" fn $name($($aname: $atype,)*) {
$content
}
};
(unsafe $name:ident($($aname:ident : $atype:ty),*) $content:block) => {
#[no_mangle]
pub unsafe extern "C" fn $name($($aname: $atype,)*) {
$content
}
};
}
+46
View File
@@ -0,0 +1,46 @@
use core::mem;
use libc::{c_void, size_t};
/// Malloc memory if pointer is null, and free on drop
pub struct MallocNull<T> {
value: *mut T,
free_on_drop: bool
}
impl<T> MallocNull<T> {
pub fn new(ptr: *mut T, size: usize) -> MallocNull<T> {
if ptr.is_null() {
MallocNull {
value: unsafe { ::malloc(size as size_t) as *mut T },
free_on_drop: true
}
} else {
MallocNull {
value: ptr,
free_on_drop: false
}
}
}
pub fn into_raw(self) -> *mut T {
let ptr = self.value;
mem::forget(self);
ptr
}
pub fn as_ptr(&self) -> *const T {
self.value
}
pub fn as_mut_ptr(&self) -> *mut T {
self.value
}
}
impl<T> Drop for MallocNull<T> {
fn drop(&mut self) {
if self.free_on_drop {
unsafe { ::free(self.value as *mut c_void) };
}
}
}
+727
View File
@@ -0,0 +1,727 @@
use libc;
use types::{in_addr, sockaddr, socklen_t};
use RawLineBuffer;
use core::ptr::null;
use core::{mem, str};
use alloc::vec::IntoIter;
use alloc::string::ToString;
use alloc::{Vec, String};
use alloc::str::SplitWhitespace;
use alloc::boxed::Box;
use dns::{Dns, DnsQuery};
use syscall::{self, Result, EINVAL, Error};
use libc::c_char;
const MAXADDRS: usize = 35;
const MAXALIASES: usize = 35;
struct LookupHost(IntoIter<in_addr>);
impl Iterator for LookupHost {
type Item = in_addr;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
#[repr(C)]
pub struct hostent {
h_name: *const libc::c_char,
h_aliases: *const *const libc::c_char,
h_addrtype: libc::c_int,
h_length: libc::c_int,
h_addr_list: *const *const libc::c_char,
}
/*
*#[repr(C)]
*pub struct netent {
* n_name: *const libc::c_char, [> official name of net <]
* n_aliases: *const *const libc::c_char, [> alias list <]
* n_addrtype: libc::c_int, [> net address type <]
* n_net: libc::c_ulong, [> network # <]
*}
*/
#[repr(C)]
pub struct servent {
s_name: *const libc::c_char, /* official service name */
s_aliases: *const *const libc::c_char, /* alias list */
s_port: libc::c_int, /* port # */
s_proto: *const libc::c_char, /* protocol to use */
}
#[repr(C)]
pub struct protoent {
p_name: *const libc::c_char, /* official protocol name */
p_aliases: *const *const libc::c_char, /* alias list */
p_proto: libc::c_int, /* protocol # */
}
#[repr(C)]
pub struct addrinfo {
ai_flags: libc::c_int, /* AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST */
ai_family: libc::c_int, /* PF_xxx */
ai_socktype: libc::c_int, /* SOCK_xxx */
ai_protocol: libc::c_int, /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
ai_addrlen: libc::size_t, /* length of ai_addr */
ai_canonname: *const libc::c_char, /* canonical name for hostname */
ai_addr: *const sockaddr, /* binary address */
ai_next: *const addrinfo, /* next structure in linked list */
}
static mut HOSTDB: usize = 0;
//static mut NETDB: usize = 0;
static mut PROTODB: usize = 0;
static mut SERVDB: usize = 0;
/*
*static mut NET_ENTRY: netent = netent {
* n_name: 0 as *const libc::c_char,
* n_aliases: 0 as *const *const libc::c_char,
* n_addrtype: 0,
* n_net: 0 as u64,
*};
*static mut NET_NAME: Option<Vec<u8>> = None;
*static mut NET_ALIASES: [*const c_char; MAXALIASES] = [null(); MAXALIASES];
*static mut NET_NUM: Option<u64> = None;
*/
static mut HOST_ENTRY: hostent = hostent {
h_name: 0 as *const libc::c_char,
h_aliases: 0 as *const *const libc::c_char,
h_addrtype: 0,
h_length: 0,
h_addr_list: 0 as *const *const libc::c_char,
};
static mut HOST_NAME: Option<Vec<u8>> = None;
static mut HOST_ALIASES: Option<Vec<Vec<u8>>> = None;
static mut HOST_ADDR: Option<in_addr> = None;
static mut HOST_ADDR_LIST: [*const c_char; 2] = [null(); 2];
static mut H_LINE: RawLineBuffer = RawLineBuffer {
fd: 0,
cur: 0,
read: 0,
buf: [0; 8 * 1024],
};
static mut PROTO_ENTRY: protoent = protoent {
p_name: 0 as *const libc::c_char,
p_aliases: 0 as *const *const libc::c_char,
p_proto: 0 as libc::c_int,
};
static mut PROTO_NAME: Option<Vec<u8>> = None;
static mut PROTO_ALIASES: Option<Vec<Vec<u8>>> = None;
static mut PROTO_NUM: Option<libc::c_int> = None;
static mut P_LINE: RawLineBuffer = RawLineBuffer {
fd: 0,
cur: 0,
read: 0,
buf: [0; 8 * 1024],
};
static mut SERV_ENTRY: servent = servent {
s_name: 0 as *const libc::c_char,
s_aliases: 0 as *const *const libc::c_char,
s_port: 0 as libc::c_int,
s_proto: 0 as *const libc::c_char,
};
static mut SERV_NAME: Option<Vec<u8>> = None;
static mut SERV_ALIASES: Option<Vec<Vec<u8>>> = None;
static mut SERV_PORT: Option<libc::c_int> = None;
static mut SERV_PROTO: Option<Vec<u8>> = None;
static mut S_LINE: RawLineBuffer = RawLineBuffer {
fd: 0,
cur: 0,
read: 0,
buf: [0; 8 * 1024],
};
fn lookup_host(host: &str) -> Result<LookupHost> {
// XXX better error handling
let ip_string = String::from_utf8(::file_read_all("/etc/net/ip")?).or(Err(
Error::new(syscall::EIO),
))?;
let ip: Vec<u8> = ip_string
.trim()
.split(".")
.map(|part| part.parse::<u8>().unwrap_or(0))
.collect();
let dns_string = String::from_utf8(::file_read_all("/etc/net/dns")?).or(Err(
Error::new(syscall::EIO),
))?;
let dns: Vec<u8> = dns_string
.trim()
.split(".")
.map(|part| part.parse::<u8>().unwrap_or(0))
.collect();
if ip.len() == 4 && dns.len() == 4 {
let mut timespec = syscall::TimeSpec::default();
syscall::clock_gettime(syscall::CLOCK_REALTIME, &mut timespec).unwrap();
let tid = (timespec.tv_nsec >> 16) as u16;
let packet = Dns {
transaction_id: tid,
flags: 0x0100,
queries: vec![
DnsQuery {
name: host.to_string(),
q_type: 0x0001,
q_class: 0x0001,
},
],
answers: vec![],
};
let packet_data = packet.compile();
let fd = ::RawFile::open(
format!("udp:/{}.{}.{}.{}:0", ip[0], ip[1], ip[2], ip[3]).as_bytes(),
syscall::O_RDWR,
)?;
let timeout = syscall::TimeSpec {
tv_sec: 5,
tv_nsec: 0,
};
let rt = fd.dup(b"read_timeout")?;
syscall::write(*rt, &timeout)?;
drop(rt);
let wt = fd.dup(b"write_timeout")?;
syscall::write(*wt, &timeout)?;
drop(wt);
let sendrecvfd = fd.dup(
format!("{}.{}.{}.{}:53", dns[0], dns[1], dns[2], dns[3])
.as_bytes(),
)?;
syscall::write(*sendrecvfd, &packet_data)?;
let mut buf = [0; 65536];
let count = syscall::read(*sendrecvfd, &mut buf)?;
drop(sendrecvfd);
drop(fd);
match Dns::parse(&buf[..count]) {
Ok(response) => {
let mut addrs = vec![];
for answer in response.answers.iter() {
if answer.a_type == 0x0001 && answer.a_class == 0x0001 &&
answer.data.len() == 4
{
let addr = in_addr {
s_addr: [
answer.data[0],
answer.data[1],
answer.data[2],
answer.data[3],
],
};
addrs.push(addr);
}
}
Ok(LookupHost(addrs.into_iter()))
}
Err(_err) => Err(Error::new(EINVAL)),
}
} else {
Err(Error::new(EINVAL))
}
}
unsafe fn lookup_addr(addr: in_addr) -> Result<Vec<Vec<u8>>> {
// XXX better error handling
let ip_string = String::from_utf8(::file_read_all("/etc/net/ip")?).or(Err(
Error::new(syscall::EIO),
))?;
let ip: Vec<u8> = ip_string
.trim()
.split(".")
.map(|part| part.parse::<u8>().unwrap_or(0))
.collect();
let dns_string = String::from_utf8(::file_read_all("/etc/net/dns")?).or(Err(
Error::new(syscall::EIO),
))?;
let dns: Vec<u8> = dns_string
.trim()
.split(".")
.map(|part| part.parse::<u8>().unwrap_or(0))
.collect();
let mut addr_vec: Vec<u8> = addr.s_addr.to_vec();
addr_vec.reverse();
let mut name: Vec<u8> = vec![];
for octet in addr_vec {
for ch in format!("{}", octet).as_bytes() {
name.push(*ch);
}
name.push(b"."[0]);
}
name.pop();
for ch in b".IN-ADDR.ARPA" {
name.push(*ch);
}
let _ = syscall::write(2, name.as_slice());
let _ = syscall::write(2, "\n".as_bytes());
if ip.len() == 4 && dns.len() == 4 {
let mut timespec = syscall::TimeSpec::default();
syscall::clock_gettime(syscall::CLOCK_REALTIME, &mut timespec).unwrap();
let tid = (timespec.tv_nsec >> 16) as u16;
let packet = Dns {
transaction_id: tid,
flags: 0x0100,
queries: vec![
DnsQuery {
name: String::from_utf8(name).unwrap(),
q_type: 0x000C,
q_class: 0x0001,
},
],
answers: vec![],
};
let packet_data = packet.compile();
let fd = ::RawFile::open(
format!("udp:/{}.{}.{}.{}:0", ip[0], ip[1], ip[2], ip[3]).as_bytes(),
syscall::O_RDWR,
)?;
let timeout = syscall::TimeSpec {
tv_sec: 5,
tv_nsec: 0,
};
let rt = fd.dup(b"read_timeout")?;
syscall::write(*rt, &timeout)?;
drop(rt);
let wt = fd.dup(b"write_timeout")?;
syscall::write(*wt, &timeout)?;
drop(wt);
let sendrecvfd = fd.dup(
format!("{}.{}.{}.{}:53", dns[0], dns[1], dns[2], dns[3])
.as_bytes(),
)?;
syscall::write(*sendrecvfd, &packet_data)?;
let mut buf = [0; 65536];
let count = syscall::read(*sendrecvfd, &mut buf)?;
drop(sendrecvfd);
drop(fd);
match Dns::parse(&buf[..count]) {
Ok(response) => {
let _ = syscall::write(2, format!("{:?}", response).as_bytes());
let _ = syscall::write(2, "\n".as_bytes());
let mut names = vec![];
for answer in response.answers.iter() {
if answer.a_type == 0x000C && answer.a_class == 0x0001
{
// answer.data is encoded kinda weird.
// Basically length-prefixed strings for each
// subsection of the domain.
// We need to parse this to insert periods where
// they belong (ie at the end of each string)
let data = parse_data(answer.data.clone());
names.push(data);
}
}
Ok(names)
}
Err(_err) => Err(Error::new(EINVAL)),
}
} else {
Err(Error::new(EINVAL))
}
}
fn parse_data(mut data: Vec<u8>) -> Vec<u8> {
let mut cursor = 0;
let mut offset = 0;
let mut index = 0;
let mut output = data.clone();
while index < data.len() - 1 {
offset = data[index] as usize;
index = cursor + offset + 1;
output[index] = '.' as u8;
cursor = index;
}
//we don't want an extra period at the end
output.pop();
return output
}
libc_fn!(unsafe endhostent() {
let _ = syscall::close(HOSTDB);
});
/*
*libc_fn!(unsafe endnetent() {
* let _ = syscall::close(NETDB);
*});
*/
libc_fn!(unsafe endprotoent() {
let _ = syscall::close(PROTODB);
});
libc_fn!(unsafe endservent() {
let _ = syscall::close(SERVDB);
});
libc_fn!(unsafe gethostbyaddr(v: *const libc::c_void, length: socklen_t, format: libc::c_int) -> Result <*const hostent> {
let mut addr: in_addr = *(v as *mut in_addr);
match lookup_addr(addr) {
Ok(s) => {
HOST_ADDR_LIST = [addr.s_addr.as_mut_ptr() as *const c_char, null()];
let host_name = s[0].to_vec();
HOST_ENTRY = hostent {
h_name: host_name.as_ptr() as *const c_char,
h_aliases: [null();2].as_mut_ptr(),
h_addrtype: format,
h_length: length as i32,
h_addr_list: HOST_ADDR_LIST.as_ptr()
};
HOST_NAME = Some(host_name);
return Ok(&HOST_ENTRY)
}
Err(err) => Err(err)
}
});
libc_fn!(unsafe gethostbyname(name: *const c_char) -> Result<*const hostent> {
// XXX h_errno
let mut addr = mem::uninitialized();
let mut host_addr = if ::socket::inet_aton(name, &mut addr) == 1 {
addr
} else {
// XXX
let mut host = lookup_host(str::from_utf8_unchecked(::cstr_to_slice(name)))?;
host.next().ok_or(Error::new(syscall::ENOENT))? // XXX
};
let host_name: Vec<u8> = ::cstr_to_slice(name).to_vec();
HOST_ADDR_LIST = [host_addr.s_addr.as_mut_ptr() as *const c_char, null()];
HOST_ADDR = Some(host_addr);
HOST_ENTRY = hostent {
h_name: host_name.as_ptr() as *const c_char,
h_aliases: [null();2].as_mut_ptr(),
h_addrtype: ::socket::AF_INET,
h_length: 4,
h_addr_list: HOST_ADDR_LIST.as_ptr()
};
HOST_NAME = Some(host_name);
Ok(&HOST_ENTRY as *const hostent)
});
libc_fn!(unsafe gethostent() -> *const hostent {
if HOSTDB == 0 {
HOSTDB = syscall::open("/etc/hosts", syscall::O_RDONLY).unwrap();
H_LINE = RawLineBuffer::new(HOSTDB);
}
let mut r: Box<str> = Box::default();
while r.is_empty() || r.split_whitespace().next() == None || r.starts_with("#") {
r = match H_LINE.next() {
Some(Ok(s)) => s,
Some(Err(_)) => return null(),
None => return null(),
};
}
let mut iter: SplitWhitespace = r.split_whitespace();
let mut addr_vec = iter.next().unwrap().as_bytes().to_vec();
addr_vec.push(b'\0');
let addr_cstr = addr_vec.as_slice().as_ptr() as *const i8;
let mut addr = mem::uninitialized();
::socket::inet_aton(addr_cstr, &mut addr);
HOST_ADDR_LIST = [addr.s_addr.as_mut_ptr() as *const c_char, null()];
HOST_ADDR = Some(addr);
let mut host_name = iter.next().unwrap().as_bytes().to_vec();
host_name.push(b'\0');
let mut host_aliases: Vec<Vec<u8>> = Vec::new();
loop {
let mut alias = match iter.next() {
Some(s) => s.as_bytes().to_vec(),
None => break
};
alias.push(b'\0');
host_aliases.push(alias);
}
//push a 0 so c doesn't segfault when it tries to read the next entry
host_aliases.push(vec![b'\0']);
HOST_ENTRY = hostent {
h_name: host_name.as_ptr() as *const c_char,
h_aliases: host_aliases.as_slice().as_ptr() as *const *const i8,
h_addrtype: ::socket::AF_INET,
h_length: 4,
h_addr_list: HOST_ADDR_LIST.as_ptr()
};
HOST_ALIASES = Some(host_aliases);
HOST_NAME = Some(host_name);
&HOST_ENTRY as *const hostent
});
/*
*libc_fn!(getnetbyaddr(net: libc::uint32_t, net_type: libc::c_int) -> Result<*const netent> {
* if NETDB == 0 {
* NETDB = syscall::open("/etc/networks", syscall::O_RDONLY).unwrap();
* }
*});
*
*libc_fn!(getnetbyname(name: *const libc::c_char) -> Result<*const netent> {
* if NETDB == 0 {
* NETDB = syscall::open("/etc/networks", syscall::O_RDONLY).unwrap();
* }
*});
*
*/
/*
*libc_fn!(getnetent() -> Result<*const netent> {
* if NETDB == 0 {
* NETDB = syscall::open("/etc/networks", syscall::O_RDONLY).unwrap();
* }
*
*});
*/
libc_fn!(unsafe getprotobyname(name: *const libc::c_char) -> Result<*const protoent> {
setprotoent(0);
let mut p: *const protoent;
while {p=getprotoent();
p!=null()} {
if libc::strcmp((*p).p_name, name) == 0 {
return Ok(p);
}
loop {
let mut cp = (*p).p_aliases;
if cp == null() {
break;
}
if libc::strcmp(*cp, name) == 0 {
return Ok(p);
}
cp = cp.offset(1);
}
}
endprotoent();
Err(Error::new(syscall::ENOENT))
});
libc_fn!(unsafe getprotobynumber(number: libc::c_int) -> Result<*const protoent> {
setprotoent(0);
let mut p: *const protoent;
while {p=getprotoent();
p!=null()} {
if (*p).p_proto == number {
return Ok(p);
}
}
endprotoent();
Err(Error::new(syscall::ENOENT))
});
libc_fn!(unsafe getprotoent() -> *const protoent {
if PROTODB == 0 {
PROTODB = syscall::open("/etc/protocols", syscall::O_RDONLY).unwrap();
P_LINE = RawLineBuffer::new(PROTODB);
}
let mut r: Box<str> = Box::default();
while r.is_empty() || r.split_whitespace().next() == None || r.starts_with("#") {
r = match P_LINE.next() {
Some(Ok(s)) => s,
Some(Err(_)) => return null(),
None => return null(),
};
}
let mut iter: SplitWhitespace = r.split_whitespace();
let mut proto_name: Vec<u8> = iter.next().unwrap().as_bytes().to_vec();
proto_name.push(b'\0');
let mut num = iter.next().unwrap().as_bytes().to_vec();
num.push(b'\0');
PROTO_NUM = Some(libc::atoi(num.as_slice().as_ptr() as *mut i8));
let mut proto_aliases: Vec<Vec<u8>> = Vec::new();
loop {
let mut alias = match iter.next() {
Some(s) => s.as_bytes().to_vec(),
None => break
};
alias.push(b'\0');
proto_aliases.push(alias);
}
//push a 0 so c doesn't segfault when it tries to read the next entry
proto_aliases.push(vec![b'\0']);
PROTO_ENTRY = protoent {
p_name: proto_name.as_slice().as_ptr() as *const c_char,
p_aliases: proto_aliases.iter().map(|x| x.as_ptr() as *const i8).collect::<Vec<*const i8>>().as_ptr(),
p_proto: PROTO_NUM.unwrap()
};
PROTO_ALIASES = Some(proto_aliases);
PROTO_NAME = Some(proto_name);
&PROTO_ENTRY as *const protoent
});
libc_fn!(unsafe getservbyname(name: *const libc::c_char, proto: *const libc::c_char) -> Result<*const servent> {
setservent(0);
let mut p: *const servent;
while {p=getservent();
p!=null()} {
if libc::strcmp((*p).s_name, name) == 0 && libc::strcmp((*p).s_proto, proto) == 0 {
return Ok(p);
}
loop {
let mut cp = (*p).s_aliases;
if cp == null() {
break;
}
if libc::strcmp(*cp, name) == 0 && libc::strcmp((*p).s_proto, proto) == 0 {
return Ok(p);
}
cp = cp.offset(1);
}
}
Err(Error::new(syscall::ENOENT))
});
libc_fn!(unsafe getservbyport(port: libc::c_int, proto: *const libc::c_char) -> Result<*const servent> {
setprotoent(0);
let mut p: *const servent;
while {p=getservent();
p!=null()} {
if (*p).s_port == port && libc::strcmp((*p).s_proto, proto) == 0 {
return Ok(p);
}
}
endprotoent();
Err(Error::new(syscall::ENOENT))
});
libc_fn!(unsafe getservent() -> *const servent {
if SERVDB == 0 {
SERVDB = syscall::open("/etc/services", syscall::O_RDONLY).unwrap();
S_LINE = RawLineBuffer::new(SERVDB);
}
let mut r: Box<str> = Box::default();
while r.is_empty() || r.split_whitespace().next() == None || r.starts_with("#") {
r = match S_LINE.next() {
Some(Ok(s)) => s,
Some(Err(_)) => return null(),
None => return null(),
};
}
let mut iter: SplitWhitespace = r.split_whitespace();
let mut serv_name: Vec<u8> = iter.next().unwrap().as_bytes().to_vec();
serv_name.push(b'\0');
let port_proto = iter.next().unwrap();
let mut split = port_proto.split("/");
let port = libc::atoi(split.next().unwrap().as_ptr() as *const i8);
SERV_PORT = Some(port);
let proto = split.next().unwrap().as_bytes().to_vec();
let mut serv_aliases: Vec<Vec<u8>> = Vec::new();
loop {
let mut alias = match iter.next() {
Some(s) => s.as_bytes().to_vec(),
None => break
};
alias.push(b'\0');
serv_aliases.push(alias);
}
//push a 0 so c doesn't segfault when it tries to read the next entry
serv_aliases.push(vec![b'\0']);
SERV_ENTRY = servent {
s_name: serv_name.as_slice().as_ptr() as *const c_char,
s_aliases: serv_aliases.iter().map(|x| x.as_ptr() as *const i8).collect::<Vec<*const i8>>().as_ptr(),
s_port: SERV_PORT.unwrap(),
s_proto: proto.as_slice().as_ptr() as *const c_char
};
SERV_ALIASES = Some(serv_aliases);
SERV_NAME = Some(serv_name);
SERV_PROTO = Some(proto);
&SERV_ENTRY as *const servent
});
libc_fn!(unsafe sethostent(stayopen: libc::c_int) {
if HOSTDB == 0 {
HOSTDB = syscall::open("/etc/hosts", syscall::O_RDONLY).unwrap();
} else {
let _ = syscall::lseek(HOSTDB, 0, syscall::SEEK_SET);
}
H_LINE = RawLineBuffer::new(HOSTDB);
});
/*
*libc_fn!(unsafe setnetent(stayopen: libc::c_int) {
* if NETDB == 0 {
* NETDB = syscall::open("/etc/networks", syscall::O_RDONLY).unwrap();
* } else {
* let _ = syscall::lseek(NETDB, 0, syscall::SEEK_SET);
* }
*});
*/
libc_fn!(unsafe setprotoent(stayopen: libc::c_int) {
if PROTODB == 0 {
PROTODB = syscall::open("/etc/protocols", syscall::O_RDONLY).unwrap();
} else {
let _ = syscall::lseek(PROTODB, 0, syscall::SEEK_SET);
}
P_LINE = RawLineBuffer::new(PROTODB);
});
libc_fn!(unsafe setservent(stayopen: libc::c_int) {
if SERVDB == 0 {
SERVDB = syscall::open("/etc/services", syscall::O_RDONLY).unwrap();
} else {
let _ = syscall::lseek(SERVDB, 0, syscall::SEEK_SET);
}
S_LINE = RawLineBuffer::new(SERVDB);
});
//libc_fn!(getaddrinfo(node: *const libc::c_char, service: *const libc::c_char, hints: *const addrinfo, res: *mut *mut addrinfo) -> libc::c_int {
//});
//libc_fn!(getnameinfo(addr: *const sockaddr, addrlen: socklen_t, host: *mut libc::c_char, hostlen: socklen_t, serv: *mut libc::c_char, servlen: socklen_t, flags: libc::c_int) -> libc::c_int {
//});
//libc_fn!(freeaddrinfo(res: *mut addrinfo) {
//});
//libc_fn!(gai_strerror(errcode: libc::c_int) -> *const libc::c_char {
//});
+207
View File
@@ -0,0 +1,207 @@
use libc::{c_char, c_int, c_void, size_t, gid_t, uid_t, ptrdiff_t};
use ::types::pid_t;
use core::slice;
use alloc::Vec;
use syscall::error::{Error, EINVAL};
use syscall;
const MAXPATHLEN: usize = 1024;
static mut CURR_BRK: usize = 0;
libc_fn!(unsafe chdir(path: *const c_char) -> Result<c_int> {
Ok(syscall::chdir(::cstr_to_slice(path))? as c_int)
});
libc_fn!(unsafe fchdir(fd: c_int) -> Result<c_int> {
let mut buf = [0; MAXPATHLEN];
let length = syscall::fpath(fd as usize, &mut buf)?;
Ok(syscall::chdir(&buf[0..length])? as c_int)
});
libc_fn!(unsafe _exit(code: c_int) {
::__libc_fini_array();
syscall::exit(code as usize).unwrap();
});
libc_fn!(unsafe _execve(name: *const c_char, argv: *const *const c_char, env: *const *const c_char) -> Result<c_int> {
let mut env = env;
while !(*env).is_null() {
let slice = ::cstr_to_slice(*env);
// Should always contain a =, but worth checking
if let Some(sep) = slice.iter().position(|&c| c == b'=') {
let mut path = b"env:".to_vec();
path.extend_from_slice(&slice[..sep]);
if let Ok(fd) = ::RawFile::open(&path, syscall::O_WRONLY | syscall::O_CREAT) {
let _ = syscall::write(*fd, &slice[sep+1..]);
}
}
env = env.offset(1);
}
let mut args: Vec<[usize; 2]> = Vec::new();
let mut arg = argv;
while !(*arg).is_null() {
args.push([*arg as usize, ::strlen(*arg)]);
arg = arg.offset(1);
}
Ok(syscall::execve(::cstr_to_slice(name), &args)? as c_int)
});
libc_fn!(unsafe _fork() -> Result<c_int> {
Ok(syscall::clone(0)? as c_int)
});
libc_fn!(unsafe vfork() -> Result<c_int> {
Ok(syscall::clone(syscall::CLONE_VFORK)? as c_int)
});
libc_fn!(unsafe getcwd(buf: *mut c_char, size: size_t) -> Result<*const c_char> {
let mut size = size;
if size == 0 {
size = ::file::PATH_MAX;
}
let buf = ::MallocNull::new(buf, size);
let slice = slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut u8, size);
let count = syscall::getcwd(&mut slice[..size-1])?;
slice[count] = b'\0';
Ok(buf.into_raw())
// FIXME: buffer too small
});
libc_fn!(unsafe getwd(buf: *mut c_char) -> Result<*const c_char> {
if buf.is_null() {
Err(Error::new(EINVAL))
} else {
let mut tmp: [u8; MAXPATHLEN] = [0; MAXPATHLEN];
syscall::getcwd(&mut tmp)?;
slice::from_raw_parts_mut(buf as *mut u8, MAXPATHLEN)
.copy_from_slice(&mut tmp);
Ok(buf)
}
});
libc_fn!(unsafe _getpid() -> pid_t {
syscall::getpid().unwrap() as pid_t
});
libc_fn!(unsafe getppid() -> pid_t {
syscall::getppid().unwrap() as pid_t
});
libc_fn!(unsafe getegid() -> gid_t {
syscall::getegid().unwrap() as gid_t
});
libc_fn!(unsafe geteuid() -> uid_t {
syscall::geteuid().unwrap() as uid_t
});
libc_fn!(unsafe getgid() -> gid_t {
syscall::getgid().unwrap() as gid_t
});
libc_fn!(unsafe getuid() -> uid_t {
syscall::getuid().unwrap() as uid_t
});
libc_fn!(unsafe _kill(pid: c_int, sig: c_int) -> Result<c_int> {
Ok(syscall::kill(pid as usize, sig as usize)? as c_int)
});
libc_fn!(unsafe _brk(end_data_segment: *mut c_void) -> Result<c_int> {
CURR_BRK = syscall::brk(end_data_segment as usize)?;
Ok(0)
});
libc_fn!(unsafe _sbrk(increment: ptrdiff_t) -> *mut c_void {
if CURR_BRK == 0 {
CURR_BRK = syscall::brk(0).unwrap();
}
let old_brk = CURR_BRK;
if increment != 0 {
let addr = if increment >= 0 {
old_brk + increment as usize
} else {
old_brk - (-increment) as usize
};
CURR_BRK = match syscall::brk(addr) {
Ok(x) => x,
Err(err) => {
*::__errno() = err.errno;
return -1 as isize as *mut c_void;
}
}
}
old_brk as *mut c_void
});
libc_fn!(unsafe _sched_yield() -> Result<c_int> {
Ok(syscall::sched_yield()? as c_int)
});
libc_fn!(unsafe _system(s: *const c_char) -> Result<c_int> {
match syscall::clone(0)? {
0 => {
let shell = "/bin/sh";
let arg1 = "-c";
let args = [
[shell.as_ptr() as usize, shell.len()],
[arg1.as_ptr() as usize, arg1.len()],
[s as usize, ::strlen(s)]
];
syscall::execve(shell, &args)?;
syscall::exit(100)?;
unreachable!()
}
pid => {
let mut status = 0;
syscall::waitpid(pid, &mut status, 0)?;
Ok(status as c_int)
}
}
});
libc_fn!(unsafe setregid(rgid: gid_t, egid: gid_t) -> Result<c_int> {
Ok(syscall::setregid(rgid as usize, egid as usize)? as c_int)
});
libc_fn!(unsafe setegid(egid: gid_t) -> Result<c_int> {
Ok(syscall::setregid(-1isize as usize, egid as usize)? as c_int)
});
libc_fn!(unsafe setgid(gid: gid_t) -> Result<c_int> {
Ok(syscall::setregid(gid as usize, gid as usize)? as c_int)
});
libc_fn!(unsafe setreuid(ruid: uid_t, euid: uid_t) -> Result<c_int> {
Ok(syscall::setreuid(ruid as usize, euid as usize)? as c_int)
});
libc_fn!(unsafe seteuid(euid: uid_t) -> Result<c_int> {
Ok(syscall::setreuid(-1isize as usize, euid as usize)? as c_int)
});
libc_fn!(unsafe setuid(uid: uid_t) -> Result<c_int> {
Ok(syscall::setreuid(uid as usize, uid as usize)? as c_int)
});
libc_fn!(unsafe _wait(status: *mut c_int) -> Result<c_int> {
let mut buf = 0;
let res = syscall::waitpid(0, &mut buf, 0)?;
*status = buf as c_int;
Ok(res as c_int)
});
libc_fn!(unsafe waitpid(pid: pid_t, status: *mut c_int, options: c_int) -> Result<c_int> {
let mut buf = 0;
let pid = if pid == -1 {
0
} else {
pid as usize
};
let res = syscall::waitpid(pid as usize, &mut buf, options as usize)?;
*status = buf as c_int;
Ok(res as c_int)
});
+28
View File
@@ -0,0 +1,28 @@
use syscall;
use core::ops::Deref;
pub struct RawFile(usize);
impl RawFile {
pub fn open<T: AsRef<[u8]>>(path: T, flags: usize) -> syscall::Result<RawFile> {
syscall::open(path, flags).map(RawFile)
}
pub fn dup(&self, buf: &[u8]) -> syscall::Result<RawFile> {
syscall::dup(self.0, buf).map(RawFile)
}
}
impl Drop for RawFile {
fn drop(&mut self) {
let _ = syscall::close(self.0);
}
}
impl Deref for RawFile {
type Target = usize;
fn deref(&self) -> &usize {
&self.0
}
}
+40
View File
@@ -0,0 +1,40 @@
use syscall;
use libc::{c_int, c_char, c_void, size_t};
use core::slice;
libc_fn!(unsafe redox_fevent(file: c_int, flags: c_int) -> Result<c_int> {
Ok(syscall::fevent(file as usize, flags as usize)? as c_int)
});
libc_fn!(unsafe redox_fpath(file: c_int, buf: *mut c_char, len: size_t) -> Result<c_int> {
let buf = slice::from_raw_parts_mut(buf as *mut u8, len);
Ok(syscall::fpath(file as usize, buf)? as c_int)
});
libc_fn!(unsafe redox_fmap(file: c_int, offset: size_t, size: size_t) -> Result<*mut c_void> {
Ok(syscall::fmap(file as usize, offset, size)? as *mut c_void)
});
libc_fn!(unsafe redox_funmap(addr: *mut c_void) -> Result<c_int> {
Ok(syscall::funmap(addr as usize)? as c_int)
});
libc_fn!(unsafe redox_physalloc(size: size_t) -> Result<*mut c_void> {
Ok(syscall::physalloc(size)? as *mut c_void)
});
libc_fn!(unsafe redox_physfree(physical_address: *mut c_void, size: size_t) -> Result<c_int> {
Ok(syscall::physfree(physical_address as usize, size)? as c_int)
});
libc_fn!(unsafe redox_physmap(physical_address: *mut c_void, size: size_t, flags: c_int) -> Result<*mut c_void> {
Ok(syscall::physmap(physical_address as usize, size, flags as usize)? as *mut c_void)
});
libc_fn!(unsafe redox_physunmap(virtual_address: *mut c_void) -> Result<c_int> {
Ok(syscall::physunmap(virtual_address as usize)? as c_int)
});
libc_fn!(unsafe redox_virttophys(virtual_address: *mut c_void) -> Result<*mut c_void> {
Ok(syscall::virttophys(virtual_address as usize)? as *mut c_void)
});
+248
View File
@@ -0,0 +1,248 @@
use core::str::{self, FromStr};
use core::mem;
use core::ptr;
use libc::{c_int, c_char, size_t, c_void, ssize_t};
use ::types::{socklen_t, in_addr, sockaddr, sockaddr_in};
use syscall::{self, O_RDWR};
use syscall::error::{Error, EPROTOTYPE, EPROTONOSUPPORT, EAFNOSUPPORT, EINVAL, EOPNOTSUPP, ENOBUFS, ENOSPC};
use core::slice;
use byteorder::{BigEndian, ByteOrder};
pub const AF_INET: c_int = 2;
pub const SOCK_STREAM: c_int = 1;
pub const SOCK_DGRAM: c_int = 2;
static mut NTOA_ADDR: [c_char; 16] = [0; 16];
libc_fn!(unsafe inet_aton(cp: *const c_char, inp: *mut in_addr) -> c_int {
// TODO: octal/hex
inet_pton(AF_INET, cp, inp as *mut c_void)
});
libc_fn!(unsafe inet_ntoa(addr: in_addr) -> *const c_char {
inet_ntop(AF_INET, &addr as *const in_addr as *const c_void, NTOA_ADDR.as_mut_ptr(), 16)
});
libc_fn!(unsafe inet_pton(domain: c_int, src: *const c_char, dest: *mut c_void) -> Result<c_int> {
if domain != AF_INET {
Err(Error::new(EAFNOSUPPORT))
} else {
let s_addr = &mut ((*(dest as *mut in_addr)).s_addr);
let mut octets = str::from_utf8_unchecked(::cstr_to_slice(src)).split('.');
for i in 0..4 {
if let Some(n) = octets.next().and_then(|x| u8::from_str(x).ok()) {
s_addr[i] = n;
} else {
return Ok(0);
}
}
if octets.next() == None {
Ok(1) // Success
} else {
Ok(0)
}
}
});
libc_fn!(unsafe inet_ntop(domain: c_int, src: *const c_void, dest: *mut c_char, size: socklen_t) -> Result<*const c_char> {
if domain != AF_INET {
Err(Error::new(EAFNOSUPPORT))
} else if size < 16 {
Err(Error::new(ENOSPC))
} else {
let s_addr = (&*(src as *const in_addr)).s_addr;
let addr = format!("{}.{}.{}.{}\0", s_addr[0], s_addr[1], s_addr[2], s_addr[3]);
ptr::copy(addr.as_ptr() as *const c_char, dest, addr.len());
Ok(dest)
}
});
libc_fn!(unsafe socket(domain: c_int, type_: c_int, protocol: c_int) -> Result<c_int> {
if domain != AF_INET {
Err(Error::new(EAFNOSUPPORT))
} else if protocol != 0 {
Err(Error::new(EPROTONOSUPPORT))
} else {
let fd = match type_ {
SOCK_STREAM => syscall::open("tcp:", O_RDWR),
SOCK_DGRAM => syscall::open("udp:", O_RDWR),
_ => Err(Error::new(EPROTOTYPE))
}?;
Ok(fd as c_int)
}
});
libc_fn!(unsafe connect(socket: c_int, address: *const sockaddr, _address_len: socklen_t) -> Result<c_int> {
// XXX with UDP, should recieve messages only from that peer after this
// XXX Check address_len
if (*address).sa_family as i32 != AF_INET {
return Err(Error::new(EINVAL))
};
let address = &*(address as *const sockaddr_in);
let s_addr =address.sin_addr.s_addr;
let path = format!("{}.{}.{}.{}:{}", s_addr[0], s_addr[1], s_addr[2], s_addr[3], ntohs(address.sin_port));
let fd = syscall::dup(socket as usize, path.as_bytes())?;
let ret = syscall::dup2(fd, socket as usize, &vec![]);
let _ = syscall::close(fd);
ret?;
Ok(0)
});
libc_fn!(unsafe bind(socket: c_int, address: *const sockaddr, _address_len: socklen_t) -> Result<c_int> {
// XXX Check address_len
if (*address).sa_family as i32 != AF_INET {
return Err(Error::new(EINVAL))
};
let address = &*(address as *const sockaddr_in);
let s_addr =address.sin_addr.s_addr;
let path = format!("/{}.{}.{}.{}:{}", s_addr[0], s_addr[1], s_addr[2], s_addr[3], ntohs(address.sin_port));
let fd = syscall::dup(socket as usize, path.as_bytes())?;
let ret = syscall::dup2(fd, socket as usize, &vec![]);
let _ = syscall::close(fd);
ret?;
Ok(0)
});
libc_fn!(unsafe listen(_socket: c_int, _backlog: c_int) -> Result<c_int> {
// TODO
Ok(0)
});
libc_fn!(unsafe recv(socket: c_int, buffer: *mut c_void, length: size_t, flags: c_int) -> Result<ssize_t> {
// XXX flags
if flags != 0 {
Err(Error::new(EOPNOTSUPP))
} else {
let buf = slice::from_raw_parts_mut(buffer as *mut u8, length);
Ok(syscall::read(socket as usize, buf)? as ssize_t)
}
});
libc_fn!(unsafe send(socket: c_int, buffer: *const c_void, length: size_t, flags: c_int) -> Result<ssize_t> {
if flags != 0 {
Err(Error::new(EOPNOTSUPP))
} else {
let buf = slice::from_raw_parts(buffer as *const u8, length);
Ok(syscall::write(socket as usize, buf)? as ssize_t)
}
});
libc_fn!(unsafe recvfrom(socket: c_int, buffer: *mut c_void, length: size_t, flags: c_int, _address: *const sockaddr, _address_len: *const socklen_t) -> Result<ssize_t> {
let fd = syscall::dup(socket as usize, b"listen")?;
let mut path = [0; 4096];
syscall::fpath(socket as usize, &mut path)?;
// XXX process path and write to address
let ret = recv(socket, buffer, length, flags);
syscall::close(fd)?;
Ok(ret)
});
libc_fn!(unsafe sendto(socket: c_int, message: *const c_void, length: size_t, flags: c_int, dest_addr: *const sockaddr, _dest_len: socklen_t) -> Result<ssize_t> {
// XXX test dest_len
if (*dest_addr).sa_family as i32 == AF_INET {
let addr = &*(dest_addr as *const sockaddr_in);
let s_addr = addr.sin_addr.s_addr;
let url = format!("{}.{}.{}.{}:{}", s_addr[0], s_addr[1], s_addr[2], s_addr[3], ntohs(addr.sin_port));
let fd = syscall::dup(socket as usize, url.as_bytes())?;
let ret = send(fd as c_int, message, length, flags);
syscall::close(fd)?;
Ok(ret)
} else {
Err(Error::new(EOPNOTSUPP))
}
});
libc_fn!(unsafe getpeername(socket: c_int, address: *mut sockaddr, address_len: *mut socklen_t) -> Result<c_int> {
// XXX will need to be changed for other sockaddr types
if *address_len < mem::size_of::<sockaddr_in>() {
return Err(Error::new(ENOBUFS));
}
*address_len = mem::size_of::<sockaddr_in>();
let addr = &mut *(address as *mut sockaddr_in);
addr.sin_family = AF_INET as u16;
let mut path = [0; 4096];
syscall::fpath(socket as usize, &mut path)?;
let start;
let sep;
let end;
{
let mut iter = path.iter();
start = iter.position(|x| *x == b':').ok_or(Error::new(EINVAL))? + 1;
sep = start + iter.position(|x| *x == b':').ok_or(Error::new(EINVAL))?;
end = sep + 1 + iter.position(|x| *x == b'/').ok_or(Error::new(EINVAL))?;
}
path[sep] = b'\0';
if inet_aton(&path[start] as *const u8 as *const c_char, &mut addr.sin_addr) == 1 {
if let Ok(port) = u16::from_str(str::from_utf8_unchecked(&path[sep+1..end])) {
addr.sin_port = htons(port);
Ok(0)
} else {
Err(Error::new(EINVAL))
}
} else {
Err(Error::new(EINVAL)) // ?
}
});
libc_fn!(unsafe getsockname(socket: c_int, address: *mut sockaddr, address_len: *mut socklen_t) -> Result<c_int> {
// XXX will need to be changed for other sockaddr types
if *address_len < mem::size_of::<sockaddr_in>() {
return Err(Error::new(ENOBUFS));
}
*address_len = mem::size_of::<sockaddr_in>();
let addr = &mut *(address as *mut sockaddr_in);
addr.sin_family = AF_INET as u16;
let mut path = [0; 4096];
syscall::fpath(socket as usize, &mut path)?;
let start;
let sep;
let end;
{
let mut iter = path.iter();
start = iter.position(|x| *x == b'/').ok_or(Error::new(EINVAL))? + 1;
sep = start + iter.position(|x| *x == b':').ok_or(Error::new(EINVAL))?;
end = sep + 1 + iter.position(|x| *x == b'\0').ok_or(Error::new(EINVAL))?;
}
path[sep] = b'\0';
if inet_aton(&path[start] as *const u8 as *const c_char, &mut addr.sin_addr) == 1 {
if let Ok(port) = u16::from_str(str::from_utf8_unchecked(&path[sep+1..end])) {
addr.sin_port = htons(port);
Ok(0)
} else {
Err(Error::new(EINVAL))
}
} else {
Err(Error::new(EINVAL)) // ?
}
});
libc_fn!(htonl(hostlong: u32) -> [u8; 4] {
let mut netlong = [0; 4];
BigEndian::write_u32(&mut netlong, hostlong);
netlong
});
libc_fn!(htons(hostshort: u16) -> [u8; 2] {
let mut netshort = [0; 2];
BigEndian::write_u16(&mut netshort, hostshort);
netshort
});
libc_fn!(ntohl(netlong: [u8; 4]) -> u32 {
BigEndian::read_u32(&netlong)
});
libc_fn!(ntohs(netshort: [u8; 2]) -> u16 {
BigEndian::read_u16(&netshort)
});
libc_fn!(setsockopt(socket: c_int, level: c_int, option_name: c_int, option_value: *const c_void, option_len: socklen_t) -> Result<c_int> {
syscall::write(2, format!("unimplemented: setsockopt({}, {}, {}, {:?}, {})\n",
socket, level, option_name, option_value, option_len).as_bytes()).unwrap();
Err(Error::new(syscall::ENOSYS))
});
+93
View File
@@ -0,0 +1,93 @@
#![allow(non_camel_case_types)]
use libc::{self, c_int};
use redox_termios::{tcflag_t, Termios};
use syscall::{self, EINVAL, Error};
use ::types::pid_t;
type speed_t = libc::c_uint;
// tcsetattr args
pub const TCSANOW: tcflag_t = 0x1;
pub const TCSADRAIN: tcflag_t = 0x2;
pub const TCSAFLUSH: tcflag_t = 0x4;
// tcflush args
pub const TCIFLUSH: tcflag_t = 0x1;
pub const TCIOFLUSH: tcflag_t = 0x3;
pub const TCOFLUSH: tcflag_t = 0x2;
// tcflow args
pub const TCIOFF: tcflag_t = 0x1;
pub const TCION: tcflag_t = 0x2;
pub const TCOOFF: tcflag_t = 0x4;
pub const TCOON: tcflag_t = 0x8;
libc_fn!(unsafe tcgetattr(fd: c_int, tio: *mut Termios) -> Result<c_int> {
let fd = syscall::dup(fd as usize, b"termios")?;
let res = syscall::read(fd, &mut *tio);
let _ = syscall::close(fd);
if res? == (&*tio).len() {
Ok(0)
} else {
Err(Error::new(EINVAL))
}
});
libc_fn!(unsafe tcsetattr(fd: c_int, _arg: c_int, tio: *mut Termios) -> Result<c_int> {
let fd = syscall::dup(fd as usize, b"termios")?;
let res = syscall::write(fd, &*tio);
let _ = syscall::close(fd);
if res? == (&*tio).len() {
Ok(0)
} else {
Err(Error::new(EINVAL))
}
});
libc_fn!(cfgetispeed(_tio: *mut Termios) -> speed_t {
// TODO
0 as speed_t
});
libc_fn!(cfgetospeed(_tio: *mut Termios) -> speed_t {
// TODO
0 as speed_t
});
libc_fn!(cfsetispeed(_tio: *mut Termios, _speed: speed_t) -> Result<c_int> {
// TODO
Ok(0)
});
libc_fn!(cfsetospeed(_tio: *mut Termios, _speed: speed_t) -> Result<c_int> {
// TODO
Ok(0)
});
libc_fn!(tcdrain(_i: c_int) -> Result<c_int> {
// TODO
Ok(0)
});
libc_fn!(tcflow(_fd: c_int, _arg: c_int) -> Result<c_int> {
// TODO
Ok(0)
});
libc_fn!(tcflush(_fd: c_int, _arg: c_int) -> Result<c_int> {
// TODO
Ok(0)
});
libc_fn!(unsafe tcgetsid(_fd: c_int) -> pid_t {
// TODO
::process::_getpid()
});
libc_fn!(tcsendbreak(_fd: c_int, _arg: c_int) -> Result<c_int> {
// TODO
Ok(0)
});
+25
View File
@@ -0,0 +1,25 @@
use syscall;
use syscall::data::TimeSpec;
use syscall::error::{Error, EFAULT};
use libc::{c_int, c_void};
use types::timeval;
libc_fn!(unsafe clock_gettime(clk_id: c_int, tp: *mut TimeSpec) -> Result<c_int> {
Ok(syscall::clock_gettime(clk_id as usize, &mut *tp)? as c_int)
});
libc_fn!(unsafe _gettimeofday(tv: *mut timeval, _tz: *const c_void) -> Result<c_int> {
if !tv.is_null() {
let mut tp = TimeSpec::default();
syscall::clock_gettime(syscall::flag::CLOCK_REALTIME, &mut tp)?;
(*tv).tv_sec = tp.tv_sec;
(*tv).tv_usec = (tp.tv_nsec / 1000) as i64;
Ok(0)
} else {
Err(Error::new(EFAULT))
}
});
libc_fn!(unsafe nanosleep(req: *const TimeSpec, rem: *mut TimeSpec) -> Result<c_int> {
Ok(syscall::nanosleep(&*req, &mut *rem)? as c_int)
});
+110
View File
@@ -0,0 +1,110 @@
#![allow(non_camel_case_types, dead_code)]
use libc;
pub type pid_t = libc::c_int;
pub type time_t = i64;
pub type suseconds_t = libc::c_long;
// Socket related types
pub type in_addr_t = [u8; 4];
pub type sa_family_t = u16;
pub type socklen_t = libc::size_t;
pub type in_port_t = [u8; 2];
// Statvfs types
pub type dev_t = libc::c_ulong;
pub type ino_t = libc::c_ulong;
pub type mode_t = libc::c_uint;
pub type nlink_t = libc::c_ulong;
pub type uid_t = libc::c_uint;
pub type gid_t = libc::c_uint;
pub type off_t = libc::c_long;
pub type blksize_t = libc::c_long;
pub type blkcnt_t = libc::c_long;
pub type fsblkcnt_t = libc::c_ulong;
pub type fsfilcnt_t = libc::c_ulong;
pub type __fsword_t = libc::c_long;
#[repr(C)]
pub struct fsid_t {
__val: [libc::c_int; 2]
}
#[repr(C)]
#[derive(Clone,Copy)]
pub struct in_addr {
pub s_addr: in_addr_t
}
#[repr(C)]
pub struct sockaddr {
pub sa_family: sa_family_t,
sa_data: [libc::c_char; 14]
}
#[repr(C)]
pub struct sockaddr_in {
pub sin_family: sa_family_t,
pub sin_port: in_port_t,
pub sin_addr: in_addr,
__pad: [u8; 8]
}
#[repr(C)]
pub struct hostent {
pub h_name: *const libc::c_char,
pub h_aliases: *const *const libc::c_char,
pub h_addrtype: libc::c_int,
pub h_length: libc::c_int,
pub h_addr_list: *const *const libc::c_char
}
#[repr(C)]
#[derive(Debug)]
pub struct timeval {
pub tv_sec: time_t,
pub tv_usec: suseconds_t
}
#[repr(C)]
pub struct utimbuf {
pub actime: time_t,
pub modtime: time_t
}
pub type fd_mask = libc::c_ulong;
pub const FD_SETSIZE: usize = 64;
pub const NFDBITS: usize = 8 * 8; // Bits in a fd_mask
#[repr(C)]
#[derive(Debug)]
pub struct fd_set {
pub fds_bits: [fd_mask; (FD_SETSIZE + NFDBITS - 1) / NFDBITS]
}
pub const POLLIN: libc::c_short = 0x0001;
pub const POLLPRI: libc::c_short = 0x0002;
pub const POLLOUT: libc::c_short = 0x0004;
pub const POLLERR: libc::c_short = 0x0008;
pub const POLLHUP: libc::c_short = 0x0010;
pub const POLLNVAL: libc::c_short = 0x0020;
#[repr(C)]
pub struct pollfd {
pub fd: libc::c_int,
pub events: libc::c_short,
pub revents: libc::c_short,
}
#[repr(C)]
pub struct passwd {
pub pw_name: *const libc::c_char,
pub pw_passwd: *const libc::c_char,
pub pw_uid: libc::uid_t,
pub pw_gid: libc::gid_t,
pub pw_gecos: *const libc::c_char,
pub pw_dir: *const libc::c_char,
pub pw_shell: *const libc::c_char
}
+66
View File
@@ -0,0 +1,66 @@
use syscall;
use libc::{c_uint, c_int, c_char, gid_t, uid_t, c_void, c_long, mode_t};
use syscall::error::{Error, EACCES, EPERM, EINVAL};
#[allow(non_camel_case_types)]
type clock_t = c_long;
macro_rules! UNIMPL {
// Call with arguments and return value
($func:ident, $err:ident) => {{
let err = Error::new($err);
let _ = syscall::write(2, format!("unimplemented: {}: {}\n",
stringify!($func), err).as_bytes());
Err(err)
}};
}
libc_fn!(alarm(_seconds: c_uint) -> c_uint {
let _ = syscall::write(2, "unimplemented: alarm\n".as_bytes());
0
});
libc_fn!(chown(_path: *mut c_char, _order: uid_t, _group: gid_t) -> Result<c_int> {
UNIMPL!(chown, EACCES)
});
libc_fn!(_getdtablesize() -> Result<c_int> {
Ok(65536)
});
// XXX variadic
libc_fn!(_ioctl(_file: c_int, _request: c_int) -> Result<c_int> {
UNIMPL!(_ioctl, EINVAL)
});
libc_fn!(_link(_old: *const c_char, _new: *const c_char) -> Result<c_int> {
UNIMPL!(_link, EPERM)
});
/*
libc_fn!(sysconf(_name: c_int) -> Result<c_long> {
UNIMPL!(sysconf, EINVAL)
});
*/
// XXX type of argument pointer
libc_fn!(_times(_buf: *mut c_void) -> Result<clock_t> {
UNIMPL!(_times, EINVAL)
});
libc_fn!(umask(_mode: mode_t) -> mode_t {
// All permissions granted
0o000
});
libc_fn!(ttyname(_fd: c_int) -> Result<*const c_char> {
UNIMPL!(ttyname, EINVAL)
});
libc_fn!(fpathconf(_fildes: c_int, _name: c_int) -> Result<c_long> {
UNIMPL!(fpathconf, EINVAL)
});
libc_fn!(getlogin() -> Result<*const c_char> {
UNIMPL!(getlogin, EINVAL)
});
+95
View File
@@ -0,0 +1,95 @@
use core::ptr::null;
use libc::{uid_t, gid_t, c_char};
use ::types::passwd;
use syscall::{Error, ENOENT};
use alloc::string::{String, ToString};
use core::str::FromStr;
static mut PASSWD: passwd = passwd {
pw_name: null(),
pw_passwd: null(),
pw_uid: 0,
pw_gid: 0,
pw_gecos: null(),
pw_dir: null(),
pw_shell: null()
};
static mut PW_NAME: Option<String> = None;
static mut PW_PASSWD: Option<String> = None;
static mut PW_GECOS: Option<String> = None;
static mut PW_DIR: Option<String> = None;
static mut PW_SHELL: Option<String> = None;
macro_rules! try_opt {
($e:expr) =>(
match $e {
Some(v) => v,
None => return None,
}
)
}
unsafe fn parse_passwd(pwd: &str) -> Option<*const passwd> {
let mut parts = pwd.split(';');
let name = try_opt!(parts.next()).to_string() + "\0";
let passwd = try_opt!(parts.next()).to_string() + "\0";
let uid = if let Ok(uid) = uid_t::from_str(try_opt!(parts.next())) {
uid
} else {
return None
};
let gid = if let Ok(gid) = gid_t::from_str(try_opt!(parts.next())) {
gid
} else {
return None
};
let gecos = try_opt!(parts.next()).to_string() + "\0";
let dir = try_opt!(parts.next()).to_string() + "\0";
let shell = try_opt!(parts.next()).to_string() + "\0";
PASSWD = passwd {
pw_name: name.as_ptr() as *const c_char,
pw_passwd: passwd.as_ptr() as *const c_char,
pw_uid: uid,
pw_gid: gid,
pw_gecos: gecos.as_ptr() as *const c_char,
pw_dir: dir.as_ptr() as *const c_char,
pw_shell: shell.as_ptr() as *const c_char
};
PW_NAME = Some(name);
PW_PASSWD = Some(passwd);
PW_GECOS = Some(gecos);
PW_DIR = Some(dir);
PW_SHELL = Some(shell);
Some(&PASSWD as *const _)
}
libc_fn!(unsafe getpwnam(name: *const c_char) -> Result<*const passwd> {
if let Ok(passwd_string) = String::from_utf8(::file_read_all("/etc/passwd")?) {
for line in passwd_string.lines() {
if line.split(';').nth(0).map(str::as_bytes) == Some(::cstr_to_slice(name)) {
if let Some(pass) = parse_passwd(line) {
return Ok(pass);
}
}
}
}
Err(Error::new(ENOENT))
});
libc_fn!(unsafe getpwuid(uid: uid_t) -> Result<*const passwd> {
if let Ok(passwd_string) = String::from_utf8(::file_read_all("/etc/passwd")?) {
for line in passwd_string.lines() {
if line.split(';').nth(2).map(uid_t::from_str) == Some(Ok(uid)) {
if let Some(pass) = parse_passwd(line) {
return Ok(pass);
}
}
}
}
Err(Error::new(ENOENT))
});