add stuff from old newlib to todo
This commit is contained in:
@@ -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>
|
||||
}
|
||||
@@ -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,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
});
|
||||
@@ -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, ×)?;
|
||||
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, ×)?;
|
||||
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
|
||||
}
|
||||
});
|
||||
@@ -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)
|
||||
});
|
||||
@@ -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)
|
||||
});
|
||||
@@ -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);
|
||||
});
|
||||
@@ -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
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -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) };
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
//});
|
||||
@@ -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)
|
||||
});
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
});
|
||||
@@ -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))
|
||||
});
|
||||
@@ -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)
|
||||
});
|
||||
@@ -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)
|
||||
});
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
});
|
||||
@@ -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))
|
||||
});
|
||||
Reference in New Issue
Block a user