Add fstat() and poll() for the random device

This commit is contained in:
LI Qing 2020-02-25 03:00:08 +00:00
parent 9f1fa883df
commit bbd4cd9be2
5 changed files with 95 additions and 2 deletions

@ -41,7 +41,54 @@ impl File for DevRandom {
Ok(total_nbytes)
}
fn metadata(&self) -> Result<Metadata> {
Ok(Metadata {
dev: 0,
inode: 0,
size: 0,
blk_size: 0,
blocks: 0,
atime: Timespec { sec: 0, nsec: 0 },
mtime: Timespec { sec: 0, nsec: 0 },
ctime: Timespec { sec: 0, nsec: 0 },
type_: FileType::CharDevice,
mode: 0444,
nlinks: 0,
uid: 0,
gid: 0,
rdev: 0,
})
}
fn as_any(&self) -> &dyn Any {
self
}
}
impl DevRandom {
pub fn poll(&self, fd: &mut libc::pollfd) -> Result<usize> {
// Just support POLLIN event, because the device is read-only currently
let (num, revents_option) = if (fd.events & libc::POLLIN) != 0 {
(1, Some(libc::POLLIN))
} else {
// Device is not ready
(0, None)
};
if let Some(revents) = revents_option {
fd.revents = revents;
}
Ok(num)
}
}
pub trait AsDevRandom {
fn as_dev_random(&self) -> Result<&DevRandom>;
}
impl AsDevRandom for FileRef {
fn as_dev_random(&self) -> Result<&DevRandom> {
self.as_any()
.downcast_ref::<DevRandom>()
.ok_or_else(|| errno!(EBADF, "not random device"))
}
}

@ -1,7 +1,7 @@
use super::*;
pub use self::dev_null::DevNull;
pub use self::dev_random::DevRandom;
pub use self::dev_random::{AsDevRandom, DevRandom};
pub use self::dev_sgx::DevSgx;
pub use self::dev_zero::DevZero;

@ -8,6 +8,7 @@ use std::fmt;
use std::io::{Read, Seek, SeekFrom, Write};
use std::mem::MaybeUninit;
pub use self::dev_fs::AsDevRandom;
pub use self::file::{File, FileRef};
pub use self::file_ops::{AccessMode, CreationFlags, Stat, StatusFlags};
pub use self::file_ops::{Flock, FlockType};

@ -1,5 +1,5 @@
use super::*;
use fs::{File, FileDesc, FileRef};
use fs::{AsDevRandom, File, FileDesc, FileRef};
use std::any::Any;
use std::collections::btree_map::BTreeMap;
use std::fmt;
@ -143,6 +143,8 @@ pub fn do_poll(polls: &mut [libc::pollfd], timeout: c_int) -> Result<usize> {
poll.revents &= poll.events;
warn!("poll unix socket is unimplemented, spin for read");
return Ok(1);
} else if let Ok(dev_random) = file_ref.as_dev_random() {
return Ok(dev_random.poll(poll)?);
} else {
return_errno!(EBADF, "not a socket");
}

@ -1,4 +1,7 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <poll.h>
#include <unistd.h>
#include <stdio.h>
#include "test.h"
@ -67,6 +70,44 @@ int test_dev_urandom() {
return 0;
}
int test_dev_urandom_fstat() {
int fd;
struct stat stat_buf;
if ((fd = open("/dev/urandom", O_RDONLY)) < 0) {
THROW_ERROR("failed to open the file");
}
if (fstat(fd, &stat_buf) < 0) {
close(fd);
THROW_ERROR("failed to fstat the file");
}
close(fd);
if ((stat_buf.st_mode & S_IFMT) != S_IFCHR) {
THROW_ERROR("not a character device");
}
return 0;
}
int test_dev_urandom_poll() {
int fd;
struct pollfd fds;
if ((fd = open("/dev/urandom", O_RDONLY)) < 0) {
THROW_ERROR("failed to open the file");
}
fds.fd = fd;
fds.events = POLLIN;
if (poll(&fds, 1, 5) <= 0) {
close(fd);
THROW_ERROR("failed to poll or file is not ready");
}
close(fd);
if (fds.revents != POLLIN) {
THROW_ERROR("not expected returned events");
}
return 0;
}
int test_dev_arandom() {
if (check_file_readable("/dev/arandom")) {
THROW_ERROR("failed to read from /dev/arandom");
@ -83,6 +124,8 @@ static test_case_t test_cases[] = {
TEST_CASE(test_dev_zero),
TEST_CASE(test_dev_random),
TEST_CASE(test_dev_urandom),
TEST_CASE(test_dev_urandom_fstat),
TEST_CASE(test_dev_urandom_poll),
TEST_CASE(test_dev_arandom),
};