Skip to content

Commit

Permalink
Added fcntl shim (#8)
Browse files Browse the repository at this point in the history
  • Loading branch information
nikarh authored Oct 18, 2023
1 parent 2ec2dc7 commit 2c40c5a
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 31 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- name: "`cargo check`"
run: cargo check --all-targets --all-features
run: cargo hack check -Z build-std=std,panic_abort --feature-powerset --examples --bins --tests --target armv7-sony-vita-newlibeabihf
- name: "`cargo clippy`"
run: cargo clippy --all-targets --all-features
run: cargo hack clippy -Z build-std=std,panic_abort --feature-powerset --examples --bins --tests --target armv7-sony-vita-newlibeabihf
- name: Run cargo doc
run: DOCS_RS=1 RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --all-features --target armv7-sony-vita-newlibeabihf -Z build-std
- name: Upload docs
Expand Down
6 changes: 2 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
.vscode/*
!.vscode/settings.json

.vscode
target/
.DS_Store
.tmp
.envrc
.envrc
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{
"rust-analyzer.cargo.target": "armv7-sony-vita-newlibeabihf"
"rust-analyzer.cargo.target": "armv7-sony-vita-newlibeabihf",
"rust-analyzer.cargo.features": ["fcntl", "pipe2", "socketpair"]
}
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ keywords = ["vitasdk", "psvita", "vita", "homebrew", "shim"]
[features]
pipe2 = []
socketpair = []
fcntl = []

[dependencies]
libc = "0.2.149"
Expand Down
2 changes: 1 addition & 1 deletion build.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::{collections::HashMap, path::Path, process::Command};

const FEATURES: &[&str] = &["socketpair", "pipe2"];
const FEATURES: &[&str] = &["socketpair", "pipe2", "fcntl"];

fn main() {
if std::env::var("DOCS_RS").is_ok() {
Expand Down
151 changes: 128 additions & 23 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#![no_std]
#![feature(c_variadic)]

#[no_mangle]
#[allow(clippy::missing_safety_doc)]
#[cfg(all(target_os = "vita", feature = "socketpair"))]
pub unsafe extern "C" fn socketpair(
_domain: libc::c_int,
Expand All @@ -22,12 +24,16 @@ pub unsafe extern "C" fn socketpair(
server_addr.sin_addr.s_addr = libc::INADDR_LOOPBACK.to_be();

if libc::bind(listener, &mut server_addr as *mut _ as *mut _, addr_len) == -1 {
libc::close(listener);
with_errno(|| {
libc::close(listener);
});
return -1;
}

if libc::listen(listener, 1) == -1 {
libc::close(listener);
with_errno(|| {
libc::close(listener);
});
return -1;
}

Expand All @@ -37,13 +43,17 @@ pub unsafe extern "C" fn socketpair(
&mut addr_len,
) == -1
{
libc::close(listener);
with_errno(|| {
libc::close(listener);
});
return -1;
}

let client_socket: libc::c_int = libc::socket(libc::AF_INET, r#type, protocol);
if client_socket == -1 {
libc::close(listener);
with_errno(|| {
libc::close(listener);
});
return -1;
}

Expand All @@ -53,8 +63,10 @@ pub unsafe extern "C" fn socketpair(
addr_len,
) == -1
{
libc::close(client_socket);
libc::close(listener);
with_errno(|| {
libc::close(client_socket);
libc::close(listener);
});
return -1;
}

Expand All @@ -64,8 +76,10 @@ pub unsafe extern "C" fn socketpair(
&mut addr_len,
);
if peer_socket == -1 {
libc::close(client_socket);
libc::close(listener);
with_errno(|| {
libc::close(client_socket);
libc::close(listener);
});
return -1;
}

Expand All @@ -78,36 +92,127 @@ pub unsafe extern "C" fn socketpair(
}

#[no_mangle]
#[allow(clippy::missing_safety_doc)]
#[cfg(all(target_os = "vita", feature = "pipe2"))]
pub unsafe extern "C" fn pipe2(pipefd: &mut [libc::c_int; 2], flags: libc::c_int) -> libc::c_int {
#[cfg(not(feature = "socketpair"))]
use libc::socketpair;

if flags & libc::O_NONBLOCK != 0 {
if socketpair(libc::AF_INET, libc::SOCK_STREAM, 0, pipefd.as_mut_ptr()) == -1 {
if socketpair(libc::AF_INET, libc::SOCK_STREAM, 0, pipefd.as_mut_ptr()) == -1 {
return -1;
}

let pipefd = *pipefd;
for fd in pipefd {
let linger = libc::linger {
l_onoff: 1,
l_linger: 0,
};
if setsockopt(fd, libc::SOL_SOCKET, libc::SO_LINGER, linger) == -1 {
with_errno(|| {
libc::close(pipefd[0]);
libc::close(pipefd[1]);
});
return -1;
}
}

let val: libc::c_int = 1;
if set_nonblocking(pipefd[0], val) == -1 || set_nonblocking(pipefd[1], val) == -1 {
libc::close(pipefd[0]);
libc::close(pipefd[1]);
return -1;
if flags & libc::O_NONBLOCK != 0 {
for fd in pipefd {
if setsockopt(fd, libc::SOL_SOCKET, libc::SO_NONBLOCK, 1) == -1 {
with_errno(|| {
libc::close(pipefd[0]);
libc::close(pipefd[1]);
});
return -1;
}
}
}

0
} else {
libc::pipe(pipefd.as_mut_ptr())
0
}

#[cfg(all(
target_os = "vita",
any(feature = "pipe2", feature = "socketpair", feature = "fcntl")
))]
extern "C" {
#[cfg_attr(target_os = "vita", link_name = "__errno")]
fn errno_location() -> *mut libc::c_int;
}

#[cfg(all(target_os = "vita", any(feature = "pipe2", feature = "socketpair")))]
unsafe fn with_errno(mut f: impl FnMut()) {
let errno = *errno_location();
f();
*errno_location() = errno as libc::c_int;
}

#[no_mangle]
#[allow(clippy::missing_safety_doc)]
#[cfg(all(target_os = "vita", feature = "fcntl"))]
pub unsafe extern "C" fn fcntl(fd: libc::c_int, cmd: libc::c_int, mut args: ...) -> libc::c_int {
let mut arg: libc::c_int = 0;

if cmd == libc::F_SETFL {
arg = args.arg::<libc::c_int>();
}

match cmd {
libc::F_GETFD => 0,
libc::F_GETFL => {
let mut val: libc::c_int = 0;

let res = getsockopt(fd, libc::SOL_SOCKET, libc::SO_NONBLOCK, &mut val);
if res == -1 {
return -1;
}

match val {
0 => 0,
_ => libc::O_NONBLOCK,
}
}
libc::F_SETFL => {
let val = (arg & libc::O_NONBLOCK) != 0;
setsockopt(fd, libc::SOL_SOCKET, libc::SO_NONBLOCK, val as libc::c_int)
}
_ => {
*errno_location() = libc::ENOTSUP;
-1
}
}
}

#[cfg(all(target_os = "vita", feature = "pipe2"))]
unsafe fn set_nonblocking(fd: libc::c_int, val: libc::c_int) -> libc::c_int {
#[cfg(all(target_os = "vita", any(feature = "pipe2", feature = "fcntl")))]
unsafe fn setsockopt<T>(
fd: libc::c_int,
level: libc::c_int,
name: libc::c_int,
val: T,
) -> libc::c_int {
libc::setsockopt(
fd,
libc::SOL_SOCKET,
libc::SO_NONBLOCK,
level,
name,
&val as *const _ as *const _,
core::mem::size_of::<libc::c_int>() as u32,
core::mem::size_of::<T>() as libc::socklen_t,
)
}

#[cfg(all(target_os = "vita", feature = "fcntl"))]
unsafe fn getsockopt<T>(
fd: libc::c_int,
level: libc::c_int,
name: libc::c_int,
val: &mut T,
) -> libc::c_int {
let mut len: libc::socklen_t = core::mem::size_of::<T>() as libc::socklen_t;
libc::getsockopt(
fd,
level,
name,
val as *mut _ as *mut _,
&mut len as *mut _ as *mut _,
)
}

0 comments on commit 2c40c5a

Please sign in to comment.