Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add more time syscalls and fix touch command in busybox #135

Merged
merged 11 commits into from
Aug 11, 2020
60 changes: 48 additions & 12 deletions linux-loader/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,76 +51,112 @@ fn init_logger() {
#[cfg(test)]
mod tests {
use super::*;
use std::fs;
use zircon_object::object::task::*;

/// test with cmd line
async fn test(cmdline: &str) {
async fn test(cmdline: &str) -> i64 {
kernel_hal_unix::init();

let args: Vec<String> = cmdline.split(' ').map(|s| s.into()).collect();
let envs =
vec!["PATH=/usr/sbin:/usr/bin:/sbin:/bin:/usr/x86_64-alpine-linux-musl/bin".into()]; // TODO
let hostfs = HostFS::new("../rootfs");
let proc = run(args, envs, hostfs);
let proc: Arc<dyn KernelObject> = proc;
proc.wait_signal(Signal::PROCESS_TERMINATED).await;
let procobj: Arc<dyn KernelObject> = proc.clone();
procobj.wait_signal(Signal::PROCESS_TERMINATED).await;
if let Status::Exited(code) = proc.status() {
return code;
}
-1
}

// test using busybox

#[async_std::test]
async fn test_busybox() {
test("/bin/busybox").await;
assert_eq!(test("/bin/busybox").await, 0);
}

#[async_std::test]
async fn test_uname() {
test("/bin/busybox uname -a").await;
assert_eq!(test("/bin/busybox uname -a").await, 0);
}

#[async_std::test]
async fn test_date() {
test("/bin/busybox date").await;
assert_eq!(test("/bin/busybox date").await, 0);
}

#[async_std::test]
async fn test_dir() {
test("/bin/busybox pwd").await;
test("/bin/busybox ls -a").await;
test("/bin/busybox dirname /bin/busybox").await;
assert_eq!(test("/bin/busybox pwd").await, 0);
assert_eq!(test("/bin/busybox ls -a").await, 0);
assert_eq!(test("/bin/busybox dirname /bin/busybox").await, 0);
}

#[async_std::test]
async fn test_create_remove_file() {
test("/bin/busybox rm testfile").await; // can't remove
fs::read("../rootfs/testfile").unwrap_err();
test("/bin/busybox touch testfile").await;
fs::read("../rootfs/testfile").unwrap();
test("/bin/busybox touch testfile").await;
fs::read("../rootfs/testfile").unwrap();
test("/bin/busybox rm testfile").await;
fs::read("../rootfs/testfile").unwrap_err();
}

#[async_std::test]
async fn test_create_remove_dir() {
test("/bin/busybox rmdir test").await; // can't remove
fs::read_dir("../rootfs/test").unwrap_err();
test("/bin/busybox mkdir test").await;
fs::read_dir("../rootfs/test").unwrap();
test("/bin/busybox rmdir test").await;
fs::read_dir("../rootfs/test").unwrap_err();
}

#[async_std::test]
async fn test_readfile() {
test("/bin/busybox cat /etc/profile").await;
assert_eq!(test("/bin/busybox cat /etc/profile").await, 0);
assert_eq!(test("/bin/busybox cat /etc/profila").await, 1); // can't open
}

#[async_std::test]
async fn test_cp_mv() {
test("/bin/busybox cp /etc/hostnama /etc/hostname.bak").await; // can't move
fs::read("../rootfs/etc/hostname.bak").unwrap_err();
test("/bin/busybox cp /etc/hostname /etc/hostname.bak").await;
fs::read("../rootfs/etc/hostname.bak").unwrap();
test("/bin/busybox mv /etc/hostname.bak /etc/hostname.mv").await;
fs::read("../rootfs/etc/hostname.bak").unwrap_err();
}

#[async_std::test]
async fn test_link() {
test("/bin/busybox ln /etc/hostnama /etc/hostname.ln").await; // can't ln
fs::read("../rootfs/etc/hostname.ln").unwrap_err();
test("/bin/busybox ln /etc/hostname /etc/hostname.ln").await;
fs::read("../rootfs/etc/hostname.ln").unwrap();
test("/bin/busybox unlink /etc/hostname.ln").await;
fs::read("../rootfs/etc/hostname.ln").unwrap_err();
}

#[async_std::test]
async fn test_env() {
test("/bin/busybox env").await;
assert_eq!(test("/bin/busybox env").await, 0);
}

// syscall unit test

#[async_std::test]
async fn test_pipe() {
test("/bin/testpipe1").await;
assert_eq!(test("/bin/testpipe1").await, 0);
}

#[async_std::test]
async fn test_time() {
assert_eq!(test("/bin/testtime").await, 0);
}
}
1 change: 1 addition & 0 deletions linux-object/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ description = "Linux kernel objects"
log = "0.4"
spin = "0.5"
xmas-elf = "0.7"
bitflags = "1.2"
hashbrown = "0.7"
zircon-object = { path = "../zircon-object", features = ["elf"] }
kernel-hal = { path = "../kernel-hal" }
Expand Down
44 changes: 44 additions & 0 deletions linux-object/src/fs/fcntl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//! consts for fctnl
wangrunji0408 marked this conversation as resolved.
Show resolved Hide resolved
//! currently support x86_64 only
//! copy from fcntl.h (from rCore)
#![allow(dead_code)]

use bitflags::bitflags;

const F_LINUX_SPECIFIC_BASE: usize = 1024;

bitflags! {
pub struct FcntlFlags: usize {
/// dup
const F_DUPFD = 0;
/// get close_on_exec
const F_GETFD = 1;
/// set/clear close_on_exec
const F_SETFD = 2;
/// get file->f_flags
const F_GETFL = 3;
/// set file->f_flags
const F_SETFL = 4;
/// Get record locking info.
const F_GETLK = 5;
/// Set record locking info (non-blocking).
const F_SETLK = 6;
/// Set record locking info (blocking).
const F_SETLKW = 7;
/// closed during a successful execve
const FD_CLOEXEC = 1;
/// like F_DUPFD, but additionally set the close-on-exec flag
const F_DUPFD_CLOEXEC = F_LINUX_SPECIFIC_BASE + 6;
}
}

bitflags! {
pub struct FileFlags: usize {
/// not blocking
const O_NONBLOCK = 0o4000;
/// move the flag bit to the end of the file before each write
const O_APPEND = 0o2000;
/// set close_on_exec
const O_CLOEXEC = 0o2000000;
}
}
2 changes: 2 additions & 0 deletions linux-object/src/fs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use rcore_fs_mountfs::MountFS;
use rcore_fs_ramfs::RamFS;

pub use self::device::*;
pub use self::fcntl::*;
pub use self::file::*;
pub use self::pipe::*;
pub use self::pseudo::*;
Expand All @@ -20,6 +21,7 @@ use downcast_rs::impl_downcast;
use zircon_object::object::*;

mod device;
mod fcntl;
mod file;
mod ioctl;
mod pipe;
Expand Down
3 changes: 3 additions & 0 deletions linux-syscall/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,6 @@ numeric-enum-macro = "0.2"
zircon-object = { path = "../zircon-object" }
linux-object = { path = "../linux-object" }
kernel-hal = { path = "../kernel-hal" }
rcore-fs = { git = "https://github.com/rcore-os/rcore-fs", rev = "e17b27b" }
lazy_static = { version = "1.4", features = ["spin_no_std"] }

65 changes: 65 additions & 0 deletions linux-syscall/src/file/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
//! - access, faccessat

use super::*;
use crate::time::*;

impl Syscall<'_> {
/// Reads from a specified file using a file descriptor. Before using this call,
Expand Down Expand Up @@ -329,4 +330,68 @@ impl Syscall<'_> {
let _inode = proc.lookup_inode_at(dirfd, &path, follow)?;
Ok(0)
}

/// change file timestamps with nanosecond precision
pub fn sys_utimensat(
&mut self,
dirfd: FileDesc,
pathname: UserInPtr<u8>,
times: UserInOutPtr<[TimeSpec; 2]>,
flags: usize,
) -> SysResult {
info!(
"utimensat(raw): dirfd: {:?}, pathname: {:?}, times: {:?}, flags: {:#x}",
dirfd, pathname, times, flags
);
const UTIME_NOW: usize = 0x3fffffff;
const UTIME_OMIT: usize = 0x3ffffffe;
let proc = self.linux_process();
let mut times = if times.is_null() {
let epoch = TimeSpec::now();
[epoch, epoch]
} else {
let times = times.read()?;
[times[0], times[1]]
};
let inode = if pathname.is_null() {
let fd = dirfd;
info!("futimens: fd: {:?}, times: {:?}", fd, times);
proc.get_file(fd)?.inode()
} else {
let pathname = pathname.read_cstring()?;
info!(
"utimensat: dirfd: {:?}, pathname: {:?}, times: {:?}, flags: {:#x}",
dirfd, pathname, times, flags
);
let follow = if flags == 0 {
true
} else if flags == AtFlags::SYMLINK_NOFOLLOW.bits() {
false
} else {
return Err(LxError::EINVAL);
};
proc.lookup_inode_at(dirfd, &pathname[..], follow)?
};
let mut metadata = inode.metadata()?;
if times[0].nsec != UTIME_OMIT {
if times[0].nsec == UTIME_NOW {
times[0] = TimeSpec::now();
}
metadata.atime = rcore_fs::vfs::Timespec {
sec: times[0].sec as i64,
nsec: times[0].nsec as i32,
};
}
if times[1].nsec != UTIME_OMIT {
if times[1].nsec == UTIME_NOW {
times[1] = TimeSpec::now();
}
metadata.mtime = rcore_fs::vfs::Timespec {
sec: times[1].sec as i64,
nsec: times[1].nsec as i32,
};
}
inode.set_metadata(&metadata)?;
Ok(0)
}
}
10 changes: 5 additions & 5 deletions linux-syscall/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ impl Syscall<'_> {
Sys::FACCESSAT => self.sys_faccessat(a0.into(), a1.into(), a2, a3),
Sys::DUP3 => self.sys_dup2(a0.into(), a1.into()), // TODO: handle `flags`
Sys::PIPE2 => self.sys_pipe(a0.into()), // TODO: handle `flags`
Sys::UTIMENSAT => self.unimplemented("utimensat", Ok(0)),
Sys::UTIMENSAT => self.sys_utimensat(a0.into(), a1.into(), a2.into(), a3),
Sys::COPY_FILE_RANGE => {
self.sys_copy_file_range(a0.into(), a1.into(), a2.into(), a3.into(), a4, a5)
}
Expand Down Expand Up @@ -181,7 +181,7 @@ impl Syscall<'_> {
// time
// Sys::NANOSLEEP => self.sys_nanosleep(a0.into()),
Sys::SETITIMER => self.unimplemented("setitimer", Ok(0)),
// Sys::GETTIMEOFDAY => self.sys_gettimeofday(a0.into(), a1.into()),
Sys::GETTIMEOFDAY => self.sys_gettimeofday(a0.into(), a1.into()),
Sys::CLOCK_GETTIME => self.sys_clock_gettime(a0, a1.into()),

// sem
Expand All @@ -199,9 +199,9 @@ impl Syscall<'_> {
Sys::UMASK => self.unimplemented("umask", Ok(0o777)),
// Sys::GETRLIMIT => self.sys_getrlimit(),
// Sys::SETRLIMIT => self.sys_setrlimit(),
// Sys::GETRUSAGE => self.sys_getrusage(a0, a1.into()),
Sys::GETRUSAGE => self.sys_getrusage(a0, a1.into()),
// Sys::SYSINFO => self.sys_sysinfo(a0.into()),
// Sys::TIMES => self.sys_times(a0.into()),
Sys::TIMES => self.sys_times(a0.into()),
Sys::GETUID => self.unimplemented("getuid", Ok(0)),
Sys::GETGID => self.unimplemented("getgid", Ok(0)),
Sys::SETUID => self.unimplemented("setuid", Ok(0)),
Expand Down Expand Up @@ -260,7 +260,7 @@ impl Syscall<'_> {
// Sys::CHMOD => self.unimplemented("chmod", Ok(0)),
// Sys::CHOWN => self.unimplemented("chown", Ok(0)),
Sys::ARCH_PRCTL => self.sys_arch_prctl(a0 as _, a1),
// Sys::TIME => self.sys_time(a0 as *mut u64),
Sys::TIME => self.sys_time(a0.into()),
// Sys::EPOLL_CREATE => self.sys_epoll_create(a0),
// Sys::EPOLL_WAIT => self.sys_epoll_wait(a0, a1.into(), a2, a3),
_ => self.unknown_syscall(sys_type),
Expand Down
Loading