diff --git a/src/header/unistd/mod.rs b/src/header/unistd/mod.rs index 26468bccf7..d9b6700f34 100644 --- a/src/header/unistd/mod.rs +++ b/src/header/unistd/mod.rs @@ -34,7 +34,10 @@ pub use crate::header::stdio::{ctermid, cuserid}; // TODO: implement and reexport fcntl functions: //pub use crate::header::fcntl::{faccessat, fchownat, fexecve, linkat, readlinkat, symlinkat, unlinkat}; -use super::errno::{E2BIG, ENOMEM}; +use super::{ + errno::{E2BIG, ENOMEM}, + stdio::snprintf, +}; mod brk; mod getopt; @@ -62,6 +65,45 @@ pub const STDERR_FILENO: c_int = 2; pub const L_cuserid: usize = 9; +// confstr constants +// These are copied from Rust's libc and match musl as well. +pub const _CS_PATH: c_int = 0; +pub const _CS_POSIX_V6_WIDTH_RESTRICTED_ENVS: c_int = 1; +pub const _CS_POSIX_V5_WIDTH_RESTRICTED_ENVS: c_int = 4; +pub const _CS_POSIX_V7_WIDTH_RESTRICTED_ENVS: c_int = 5; +pub const _CS_POSIX_V6_ILP32_OFF32_CFLAGS: c_int = 1116; +pub const _CS_POSIX_V6_ILP32_OFF32_LDFLAGS: c_int = 1117; +pub const _CS_POSIX_V6_ILP32_OFF32_LIBS: c_int = 1118; +pub const _CS_POSIX_V6_ILP32_OFF32_LINTFLAGS: c_int = 1119; +pub const _CS_POSIX_V6_ILP32_OFFBIG_CFLAGS: c_int = 1120; +pub const _CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS: c_int = 1121; +pub const _CS_POSIX_V6_ILP32_OFFBIG_LIBS: c_int = 1122; +pub const _CS_POSIX_V6_ILP32_OFFBIG_LINTFLAGS: c_int = 1123; +pub const _CS_POSIX_V6_LP64_OFF64_CFLAGS: c_int = 1124; +pub const _CS_POSIX_V6_LP64_OFF64_LDFLAGS: c_int = 1125; +pub const _CS_POSIX_V6_LP64_OFF64_LIBS: c_int = 1126; +pub const _CS_POSIX_V6_LP64_OFF64_LINTFLAGS: c_int = 1127; +pub const _CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS: c_int = 1128; +pub const _CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS: c_int = 1129; +pub const _CS_POSIX_V6_LPBIG_OFFBIG_LIBS: c_int = 1130; +pub const _CS_POSIX_V6_LPBIG_OFFBIG_LINTFLAGS: c_int = 1131; +pub const _CS_POSIX_V7_ILP32_OFF32_CFLAGS: c_int = 1132; +pub const _CS_POSIX_V7_ILP32_OFF32_LDFLAGS: c_int = 1133; +pub const _CS_POSIX_V7_ILP32_OFF32_LIBS: c_int = 1134; +pub const _CS_POSIX_V7_ILP32_OFF32_LINTFLAGS: c_int = 1135; +pub const _CS_POSIX_V7_ILP32_OFFBIG_CFLAGS: c_int = 1136; +pub const _CS_POSIX_V7_ILP32_OFFBIG_LDFLAGS: c_int = 1137; +pub const _CS_POSIX_V7_ILP32_OFFBIG_LIBS: c_int = 1138; +pub const _CS_POSIX_V7_ILP32_OFFBIG_LINTFLAGS: c_int = 1139; +pub const _CS_POSIX_V7_LP64_OFF64_CFLAGS: c_int = 1140; +pub const _CS_POSIX_V7_LP64_OFF64_LDFLAGS: c_int = 1141; +pub const _CS_POSIX_V7_LP64_OFF64_LIBS: c_int = 1142; +pub const _CS_POSIX_V7_LP64_OFF64_LINTFLAGS: c_int = 1143; +pub const _CS_POSIX_V7_LPBIG_OFFBIG_CFLAGS: c_int = 1144; +pub const _CS_POSIX_V7_LPBIG_OFFBIG_LDFLAGS: c_int = 1145; +pub const _CS_POSIX_V7_LPBIG_OFFBIG_LIBS: c_int = 1146; +pub const _CS_POSIX_V7_LPBIG_OFFBIG_LINTFLAGS: c_int = 1147; + #[thread_local] pub static mut fork_hooks_static: Option<[LinkedList; 3]> = None; @@ -154,9 +196,26 @@ pub extern "C" fn close(fildes: c_int) -> c_int { } /// See . -// #[no_mangle] +#[no_mangle] pub extern "C" fn confstr(name: c_int, buf: *mut c_char, len: size_t) -> size_t { - unimplemented!(); + // confstr returns the number of bytes required to hold the string INCLUDING the NUL + // terminator. This is different from other C functions hence the + 1. + match name { + _CS_PATH => { + let posix2_path = c"/usr/bin"; + unsafe { snprintf(buf, len, c"%s".as_ptr(), posix2_path.as_ptr()) + 1 } + .try_into() + .unwrap_or_default() + } + _CS_POSIX_V6_WIDTH_RESTRICTED_ENVS + | _CS_POSIX_V5_WIDTH_RESTRICTED_ENVS + | _CS_POSIX_V7_WIDTH_RESTRICTED_ENVS + | _CS_POSIX_V6_LP64_OFF64_LIBS..=_CS_POSIX_V7_LPBIG_OFFBIG_LINTFLAGS => 1, + _ => { + platform::ERRNO.set(errno::EINVAL); + 0 + } + } } /// See . diff --git a/src/header/unistd/sysconf.rs b/src/header/unistd/sysconf.rs index dd61586ff5..02d3aadb4b 100644 --- a/src/header/unistd/sysconf.rs +++ b/src/header/unistd/sysconf.rs @@ -12,7 +12,7 @@ pub use sys::*; use core::ffi::{c_int, c_long}; -#[unsafe(no_mangle)] +#[no_mangle] pub unsafe extern "C" fn sysconf(name: c_int) -> c_long { sysconf_impl(name) } diff --git a/tests/Makefile b/tests/Makefile index eb7cdb46f3..02f8fd4cec 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -124,6 +124,7 @@ EXPECT_NAMES=\ unistd/access \ unistd/brk \ unistd/constants \ + unistd/confstr \ unistd/dup \ unistd/exec \ unistd/fchdir \ diff --git a/tests/expected/bins_dynamic/unistd/confstr.stderr b/tests/expected/bins_dynamic/unistd/confstr.stderr new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/bins_dynamic/unistd/confstr.stdout b/tests/expected/bins_dynamic/unistd/confstr.stdout new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/bins_static/unistd/confstr.stderr b/tests/expected/bins_static/unistd/confstr.stderr new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/bins_static/unistd/confstr.stdout b/tests/expected/bins_static/unistd/confstr.stdout new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/unistd/confstr.c b/tests/unistd/confstr.c new file mode 100644 index 0000000000..d9abde8811 --- /dev/null +++ b/tests/unistd/confstr.c @@ -0,0 +1,34 @@ +#include +#include +#include +#include + +#define CSPATHSZ 9 +#define BADSIZ 4 + +int main(void) { + char actual[CSPATHSZ] = {0}; + assert(confstr(_CS_PATH, actual, CSPATHSZ) == CSPATHSZ); + const char expected[] = "/usr/bin"; + assert(strncmp(expected, actual, CSPATHSZ) == 0); + + // The constants other than _CS_PATH just return an empty str (no support). + char empty[] = ""; + assert( + confstr( + _CS_POSIX_V6_LP64_OFF64_LIBS, + empty, + 0 + ) == 1 + ); + + // Buffers that are too small should return the expected size. + char small[BADSIZ] = {0}; + assert(confstr(_CS_PATH, small, BADSIZ) == CSPATHSZ); + + // Null buffer and zero length should return the expected size + // for the constant. + assert(confstr(_CS_PATH, NULL, 0) == CSPATHSZ); + + return EXIT_SUCCESS; +}