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

Use weakcall for eventfd on FreeBSD. #718

Merged
merged 7 commits into from
Jul 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .cirrus.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,16 @@ task:
test_script:
- . $HOME/.cargo/env
- cargo test --workspace --features=all-apis

task:
name: stable x86_64-unknown-freebsd-12
freebsd_instance:
image_family: freebsd-12-1
setup_script:
- curl https://sh.rustup.rs -sSf --output rustup.sh
- sh rustup.sh --default-toolchain stable -y --profile=minimal
- . $HOME/.cargo/env
- rustup default stable
test_script:
- . $HOME/.cargo/env
- cargo test --workspace --features=all-apis
17 changes: 16 additions & 1 deletion src/backend/libc/io/syscalls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,22 @@ pub(crate) fn eventfd(initval: u32, flags: EventfdFlags) -> io::Result<OwnedFd>

#[cfg(any(target_os = "freebsd", target_os = "illumos"))]
pub(crate) fn eventfd(initval: u32, flags: EventfdFlags) -> io::Result<OwnedFd> {
unsafe { ret_owned_fd(c::eventfd(initval, flags.bits())) }
// `eventfd` was added in FreeBSD 13, so it isn't available on FreeBSD 12.
#[cfg(target_os = "freebsd")]
unsafe {
weakcall! {
fn eventfd(
initval: c::c_uint,
flags: c::c_int
) -> c::c_int
}
ret_owned_fd(eventfd(initval, flags.bits()))
}

#[cfg(target_os = "illumos")]
unsafe {
ret_owned_fd(c::eventfd(initval, flags.bits()))
}
}

#[cfg(linux_kernel)]
Expand Down
19 changes: 18 additions & 1 deletion src/backend/libc/pty/syscalls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,27 @@ pub(crate) fn ptsname(fd: BorrowedFd, mut buffer: Vec<u8>) -> io::Result<CString

loop {
// On platforms with `ptsname_r`, use it.
#[cfg(any(target_os = "freebsd", linux_like, target_os = "fuchsia"))]
#[cfg(any(linux_like, target_os = "fuchsia"))]
let r =
unsafe { libc::ptsname_r(borrowed_fd(fd), buffer.as_mut_ptr().cast(), buffer.len()) };

// FreeBSD 12 doesn't have `ptsname_r`.
#[cfg(target_os = "freebsd")]
let r = unsafe {
weak! {
fn ptsname_r(
c::c_int,
*mut c::c_char,
c::size_t
) -> c::c_int
}
if let Some(func) = ptsname_r.get() {
func(borrowed_fd(fd), buffer.as_mut_ptr().cast(), buffer.len())
} else {
libc::ENOSYS
}
};

// MacOS 10.13.4 has `ptsname_r`; use it if we have it, otherwise fall
// back to calling the underlying ioctl directly.
#[cfg(apple)]
Expand Down
7 changes: 6 additions & 1 deletion tests/io/eventfd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@ fn test_eventfd() {
use std::mem::size_of;
use std::thread;

let efd = eventfd(0, EventfdFlags::CLOEXEC).unwrap();
let efd = match eventfd(0, EventfdFlags::CLOEXEC) {
Ok(efd) => efd,
#[cfg(target_os = "freebsd")]
Err(rustix::io::Errno::NOSYS) => return, // FreeBSD 12 lacks `eventfd`
Err(e) => Err(e).unwrap(),
};

let child = thread::spawn(move || {
for u in [1_u64, 3, 6, 11, 5000].iter() {
Expand Down
12 changes: 10 additions & 2 deletions tests/process/procctl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ fn test_trace_status() {

#[test]
fn test_reaper_status() {
assert_eq!(set_reaper_status(false), Err(io::Errno::INVAL));
match set_reaper_status(false).unwrap_err() {
io::Errno::INVAL => (),
io::Errno::PERM => return, // FreeBSD 12 doesn't support this
err => Err(err).unwrap(),
};
set_reaper_status(true).unwrap();
let status_while_acq = dbg!(get_reaper_status(None).unwrap());
set_reaper_status(false).unwrap();
Expand All @@ -38,7 +42,11 @@ fn test_trapcap() {

#[test]
fn test_no_new_privs() {
assert!(!no_new_privs(None).unwrap());
match no_new_privs(None) {
Ok(flag) => assert!(!flag),
Err(io::Errno::INVAL) => return, // FreeBSD 12 doesn't support this
Err(err) => Err(err).unwrap(),
};
set_no_new_privs(None).unwrap();
assert!(no_new_privs(None).unwrap());
// No going back but, well, we're not gonna execute SUID binaries from the
Expand Down
40 changes: 22 additions & 18 deletions tests/pty/openpty.rs
Original file line number Diff line number Diff line change
@@ -1,72 +1,76 @@
use rustix::fs::{cwd, openat, Mode, OFlags};
use rustix::pty::*;
use std::fs::File;
use std::io;
use std::io::{Read, Write};

#[test]
fn openpty_basic() -> io::Result<()> {
fn openpty_basic() {
// Use `CLOEXEC` if we can.
#[cfg(any(linux_kernel, target_os = "freebsd", target_os = "netbsd"))]
let flags = OpenptFlags::RDWR | OpenptFlags::NOCTTY | OpenptFlags::CLOEXEC;
#[cfg(not(any(linux_kernel, target_os = "freebsd", target_os = "netbsd")))]
let flags = OpenptFlags::RDWR | OpenptFlags::NOCTTY;

let controller = openpt(flags)?;
let controller = openpt(flags).unwrap();

grantpt(&controller)?;
unlockpt(&controller)?;
grantpt(&controller).unwrap();
unlockpt(&controller).unwrap();

let name = ptsname(&controller, Vec::new())?;
let name = match ptsname(&controller, Vec::new()) {
Ok(name) => name,
#[cfg(target_os = "freebsd")]
Err(rustix::io::Errno::NOSYS) => return, // FreeBSD 12 doesn't support this
Err(err) => Err(err).unwrap(),
};
let user = openat(
cwd(),
name,
OFlags::RDWR | OFlags::NOCTTY | OFlags::CLOEXEC,
Mode::empty(),
)?;
)
.unwrap();

let mut controller = File::from(controller);
let mut user = File::from(user);

// The '\x04' is Ctrl-D, the default EOF control code.
controller.write_all(b"Hello, world!\n\x04")?;
controller.write_all(b"Hello, world!\n\x04").unwrap();

let mut s = String::new();
user.read_to_string(&mut s)?;
user.read_to_string(&mut s).unwrap();

assert_eq!(s, "Hello, world!\n");
Ok(())
}

// Like `openpty_basic` but use `ioctl_tiocgptpeer` instead of `ptsname`.
#[cfg(target_os = "linux")]
#[test]
fn openpty_get_peer() -> io::Result<()> {
fn openpty_get_peer() {
// Use `CLOEXEC` if we can.
#[cfg(any(linux_kernel, target_os = "freebsd", target_os = "netbsd"))]
let flags = OpenptFlags::RDWR | OpenptFlags::NOCTTY | OpenptFlags::CLOEXEC;
#[cfg(not(any(linux_kernel, target_os = "freebsd", target_os = "netbsd")))]
let flags = OpenptFlags::RDWR | OpenptFlags::NOCTTY;

let controller = openpt(flags)?;
let controller = openpt(flags).unwrap();

grantpt(&controller)?;
unlockpt(&controller)?;
grantpt(&controller).unwrap();
unlockpt(&controller).unwrap();

let user = ioctl_tiocgptpeer(
&controller,
OpenptFlags::RDWR | OpenptFlags::NOCTTY | OpenptFlags::CLOEXEC,
)?;
)
.unwrap();

let mut controller = File::from(controller);
let mut user = File::from(user);

// The '\x04' is Ctrl-D, the default EOF control code.
controller.write_all(b"Hello, world!\n\x04")?;
controller.write_all(b"Hello, world!\n\x04").unwrap();

let mut s = String::new();
user.read_to_string(&mut s)?;
user.read_to_string(&mut s).unwrap();

assert_eq!(s, "Hello, world!\n");
Ok(())
}