diff --git a/libc-test/Cargo.toml b/libc-test/Cargo.toml index 0a2778d1dcb4b..bbd724e27f76e 100644 --- a/libc-test/Cargo.toml +++ b/libc-test/Cargo.toml @@ -66,6 +66,11 @@ name = "cmsg" path = "test/cmsg.rs" harness = true +[[test]] +name = "makedev" +path = "test/makedev.rs" +harness = true + [[test]] name = "errqueue" path = "test/errqueue.rs" diff --git a/libc-test/build.rs b/libc-test/build.rs index ba428fc7303d1..9afbf4bed5467 100644 --- a/libc-test/build.rs +++ b/libc-test/build.rs @@ -22,6 +22,15 @@ fn do_cc() { } cmsg.compile("cmsg"); } + + if target.contains("linux") + || target.contains("android") + || target.contains("emscripten") + || target.contains("fuchsia") + || target.contains("bsd") + { + cc::Build::new().file("src/makedev.c").compile("makedev"); + } } if target.contains("android") || target.contains("linux") { cc::Build::new().file("src/errqueue.c").compile("errqueue"); diff --git a/libc-test/src/makedev.c b/libc-test/src/makedev.c new file mode 100644 index 0000000000000..7f99d60728bb4 --- /dev/null +++ b/libc-test/src/makedev.c @@ -0,0 +1,13 @@ +#include +#if defined(__linux__) || defined(__EMSCRIPTEN__) +#include +#endif + +// Since makedev is a macro instead of a function, it isn't available to FFI. +// libc must reimplement it, which is error-prone. This file provides FFI +// access to the actual macro so it can be tested against the Rust +// reimplementation. + +dev_t makedev_ffi(unsigned major, unsigned minor) { + return makedev(major, minor); +} diff --git a/libc-test/test/makedev.rs b/libc-test/test/makedev.rs new file mode 100644 index 0000000000000..c9a92aa83e686 --- /dev/null +++ b/libc-test/test/makedev.rs @@ -0,0 +1,103 @@ +//! Compare libc's makdev function against the actual C macros, for various +//! inputs. + +extern crate libc; + +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", +))] +mod t { + use libc::{self, c_uint, dev_t}; + + extern "C" { + pub fn makedev_ffi(major: c_uint, minor: c_uint) -> dev_t; + } + + fn compare(major: c_uint, minor: c_uint) { + let expected = unsafe { makedev_ffi(major, minor) }; + assert_eq!(libc::makedev(major, minor), expected); + } + + // Every OS should be able to handle 8 bit major and minor numbers + #[test] + fn test_8bits() { + for major in 0..256 { + for minor in 0..256 { + compare(major, minor); + } + } + } + + // Android allows 12 bits for major and 20 for minor + #[test] + #[cfg(target_os = "android")] + fn test_android_like() { + for major in [0, 1, 255, 256, 4095] { + for minor_exp in [1, 8, 16] { + for minor in [(1 << minor_exp) - 1, (1 << minor_exp)] { + compare(major, minor); + } + } + compare(major, (1 << 20) - 1); + } + } + + // These OSes allow 32 bits for minor, but only 8 for major + #[test] + #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd",))] + fn test_fbsd11_like() { + for major in [0, 1, 255] { + for minor_exp in [1, 8, 16, 24, 31] { + for minor in [(1 << minor_exp) - 1, (1 << minor_exp)] { + compare(major, minor); + } + } + compare(major, c_uint::MAX); + } + } + + // OpenBSD allows 8 bits for major and 24 for minor + #[test] + #[cfg(target_os = "openbsd")] + fn test_openbsd_like() { + for major in [0, 1, 255] { + for minor_exp in [1, 8, 16] { + for minor in [(1 << minor_exp) - 1, (1 << minor_exp)] { + compare(major, minor); + } + } + compare(major, (1 << 24) - 1); + } + } + + // These OSes allow 32 bits for both minor and major + #[cfg(any( + target_os = "empscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "linux", + ))] + #[test] + fn test_fbsd12_like() { + if std::mem::size_of::() >= 8 { + for major_exp in [0, 16, 24, 31] { + for major in [(1 << major_exp) - 1, (1 << major_exp)] { + for minor_exp in [1, 8, 16, 24, 31] { + for minor in [(1 << minor_exp) - 1, (1 << minor_exp)] { + compare(major, minor); + } + } + compare(major, c_uint::MAX); + } + compare(c_uint::MAX, c_uint::MAX); + } + } + } +} diff --git a/src/fuchsia/mod.rs b/src/fuchsia/mod.rs index 4a18a8daabc0c..c08d48c339422 100644 --- a/src/fuchsia/mod.rs +++ b/src/fuchsia/mod.rs @@ -3235,17 +3235,6 @@ f! { minor as ::c_uint } - pub fn makedev(major: ::c_uint, minor: ::c_uint) -> ::dev_t { - let major = major as ::dev_t; - let minor = minor as ::dev_t; - let mut dev = 0; - dev |= (major & 0x00000fff) << 8; - dev |= (major & 0xfffff000) << 32; - dev |= (minor & 0x000000ff) << 0; - dev |= (minor & 0xffffff00) << 12; - dev - } - pub fn CMSG_DATA(cmsg: *const cmsghdr) -> *mut c_uchar { cmsg.offset(1) as *mut c_uchar } @@ -3322,6 +3311,17 @@ safe_f! { pub {const} fn QCMD(cmd: ::c_int, type_: ::c_int) -> ::c_int { (cmd << 8) | (type_ & 0x00ff) } + + pub {const} fn makedev(major: ::c_uint, minor: ::c_uint) -> ::dev_t { + let major = major as ::dev_t; + let minor = minor as ::dev_t; + let mut dev = 0; + dev |= (major & 0x00000fff) << 8; + dev |= (major & 0xfffff000) << 32; + dev |= (minor & 0x000000ff) << 0; + dev |= (minor & 0xffffff00) << 12; + dev + } } fn __CMSG_LEN(cmsg: *const cmsghdr) -> ::ssize_t { diff --git a/src/unix/bsd/freebsdlike/dragonfly/mod.rs b/src/unix/bsd/freebsdlike/dragonfly/mod.rs index df7719b4b9c69..2935534f0d6a9 100644 --- a/src/unix/bsd/freebsdlike/dragonfly/mod.rs +++ b/src/unix/bsd/freebsdlike/dragonfly/mod.rs @@ -1571,6 +1571,15 @@ safe_f! { pub {const} fn WIFSIGNALED(status: ::c_int) -> bool { (status & 0o177) != 0o177 && (status & 0o177) != 0 } + + pub {const} fn makedev(major: ::c_uint, minor: ::c_uint) -> ::dev_t { + let major = major as ::dev_t; + let minor = minor as ::dev_t; + let mut dev = 0; + dev |= major << 8; + dev |= minor; + dev + } } extern "C" { diff --git a/src/unix/bsd/freebsdlike/freebsd/freebsd11/mod.rs b/src/unix/bsd/freebsdlike/freebsd/freebsd11/mod.rs index 1af555fa3655c..aaa04358472be 100644 --- a/src/unix/bsd/freebsdlike/freebsd/freebsd11/mod.rs +++ b/src/unix/bsd/freebsdlike/freebsd/freebsd11/mod.rs @@ -434,6 +434,14 @@ pub const MINCORE_SUPER: ::c_int = 0x20; /// max length of devicename pub const SPECNAMELEN: ::c_int = 63; +safe_f! { + pub {const} fn makedev(major: ::c_uint, minor: ::c_uint) -> ::dev_t { + let major = major as ::dev_t; + let minor = minor as ::dev_t; + (major << 8) | minor + } +} + extern "C" { // Return type ::c_int was removed in FreeBSD 12 pub fn setgrent() -> ::c_int; diff --git a/src/unix/bsd/freebsdlike/freebsd/freebsd12/mod.rs b/src/unix/bsd/freebsdlike/freebsd/freebsd12/mod.rs index 848db33993556..e7f8ad7802875 100644 --- a/src/unix/bsd/freebsdlike/freebsd/freebsd12/mod.rs +++ b/src/unix/bsd/freebsdlike/freebsd/freebsd12/mod.rs @@ -449,6 +449,19 @@ pub const KI_NSPARE_PTR: usize = 6; pub const MINCORE_SUPER: ::c_int = 0x20; +safe_f! { + pub {const} fn makedev(major: ::c_uint, minor: ::c_uint) -> ::dev_t { + let major = major as ::dev_t; + let minor = minor as ::dev_t; + let mut dev = 0; + dev |= ((major & 0xffffff00) as dev_t) << 32; + dev |= ((major & 0x000000ff) as dev_t) << 8; + dev |= ((minor & 0x0000ff00) as dev_t) << 24; + dev |= ((minor & 0xffff00ff) as dev_t) << 0; + dev + } +} + extern "C" { pub fn setgrent(); pub fn mprotect(addr: *mut ::c_void, len: ::size_t, prot: ::c_int) -> ::c_int; diff --git a/src/unix/bsd/freebsdlike/freebsd/freebsd13/mod.rs b/src/unix/bsd/freebsdlike/freebsd/freebsd13/mod.rs index a929f9d290e63..bcd09006b5930 100644 --- a/src/unix/bsd/freebsdlike/freebsd/freebsd13/mod.rs +++ b/src/unix/bsd/freebsdlike/freebsd/freebsd13/mod.rs @@ -468,6 +468,19 @@ pub const DOMAINSET_POLICY_INTERLEAVE: ::c_int = 4; pub const MINCORE_SUPER: ::c_int = 0x20; +safe_f! { + pub {const} fn makedev(major: ::c_uint, minor: ::c_uint) -> ::dev_t { + let major = major as ::dev_t; + let minor = minor as ::dev_t; + let mut dev = 0; + dev |= ((major & 0xffffff00) as dev_t) << 32; + dev |= ((major & 0x000000ff) as dev_t) << 8; + dev |= ((minor & 0x0000ff00) as dev_t) << 24; + dev |= ((minor & 0xffff00ff) as dev_t) << 0; + dev + } +} + extern "C" { pub fn setgrent(); pub fn mprotect(addr: *mut ::c_void, len: ::size_t, prot: ::c_int) -> ::c_int; diff --git a/src/unix/bsd/freebsdlike/freebsd/freebsd14/mod.rs b/src/unix/bsd/freebsdlike/freebsd/freebsd14/mod.rs index c655d555d9005..9da66960483e3 100644 --- a/src/unix/bsd/freebsdlike/freebsd/freebsd14/mod.rs +++ b/src/unix/bsd/freebsdlike/freebsd/freebsd14/mod.rs @@ -468,6 +468,19 @@ pub const DOMAINSET_POLICY_INTERLEAVE: ::c_int = 4; pub const MINCORE_SUPER: ::c_int = 0x60; +safe_f! { + pub {const} fn makedev(major: ::c_uint, minor: ::c_uint) -> ::dev_t { + let major = major as ::dev_t; + let minor = minor as ::dev_t; + let mut dev = 0; + dev |= ((major & 0xffffff00) as dev_t) << 32; + dev |= ((major & 0x000000ff) as dev_t) << 8; + dev |= ((minor & 0x0000ff00) as dev_t) << 24; + dev |= ((minor & 0xffff00ff) as dev_t) << 0; + dev + } +} + extern "C" { pub fn setgrent(); pub fn mprotect(addr: *mut ::c_void, len: ::size_t, prot: ::c_int) -> ::c_int; diff --git a/src/unix/bsd/netbsdlike/netbsd/mod.rs b/src/unix/bsd/netbsdlike/netbsd/mod.rs index d12fd073019be..82784bbbfcc89 100644 --- a/src/unix/bsd/netbsdlike/netbsd/mod.rs +++ b/src/unix/bsd/netbsdlike/netbsd/mod.rs @@ -2351,6 +2351,16 @@ safe_f! { pub {const} fn WIFCONTINUED(status: ::c_int) -> bool { status == 0xffff } + + pub {const} fn makedev(major: ::c_uint, minor: ::c_uint) -> ::dev_t { + let major = major as ::dev_t; + let minor = minor as ::dev_t; + let mut dev = 0; + dev |= (major << 8) & 0x000ff00; + dev |= (minor << 12) & 0xfff00000; + dev |= minor & 0xff; + dev + } } extern "C" { diff --git a/src/unix/bsd/netbsdlike/openbsd/mod.rs b/src/unix/bsd/netbsdlike/openbsd/mod.rs index 1910f24a46bf6..ba26f92431d78 100644 --- a/src/unix/bsd/netbsdlike/openbsd/mod.rs +++ b/src/unix/bsd/netbsdlike/openbsd/mod.rs @@ -1695,6 +1695,16 @@ safe_f! { pub {const} fn WIFCONTINUED(status: ::c_int) -> bool { (status & 0o177777) == 0o177777 } + + pub {const} fn makedev(major: ::c_uint, minor: ::c_uint) -> ::dev_t { + let major = major as ::dev_t; + let minor = minor as ::dev_t; + let mut dev = 0; + dev |= (major & 0xff) << 8; + dev |= minor & 0xff; + dev |= (minor & 0xffff00) << 8; + dev + } } extern "C" { diff --git a/src/unix/linux_like/android/mod.rs b/src/unix/linux_like/android/mod.rs index cfd229a474a92..8a21147def82f 100644 --- a/src/unix/linux_like/android/mod.rs +++ b/src/unix/linux_like/android/mod.rs @@ -2781,12 +2781,6 @@ f! { pub fn minor(dev: ::dev_t) -> ::c_int { ((dev & 0xff) | ((dev >> 12) & 0xfff00)) as ::c_int } - pub fn makedev(ma: ::c_int, mi: ::c_int) -> ::dev_t { - let ma = ma as ::dev_t; - let mi = mi as ::dev_t; - ((ma & 0xfff) << 8) | (mi & 0xff) | ((mi & 0xfff00) << 12) - } - pub fn NLA_ALIGN(len: ::c_int) -> ::c_int { return ((len) + NLA_ALIGNTO - 1) & !(NLA_ALIGNTO - 1) } @@ -2796,6 +2790,15 @@ f! { } } +safe_f! { + pub {const} fn makedev(ma: ::c_uint, mi: ::c_uint) -> ::dev_t { + let ma = ma as ::dev_t; + let mi = mi as ::dev_t; + ((ma & 0xfff) << 8) | (mi & 0xff) | ((mi & 0xfff00) << 12) + } + +} + extern "C" { pub fn getrlimit64(resource: ::c_int, rlim: *mut rlimit64) -> ::c_int; pub fn setrlimit64(resource: ::c_int, rlim: *const rlimit64) -> ::c_int; diff --git a/src/unix/linux_like/emscripten/mod.rs b/src/unix/linux_like/emscripten/mod.rs index 31d0ebf25b104..11fbb31c3830d 100644 --- a/src/unix/linux_like/emscripten/mod.rs +++ b/src/unix/linux_like/emscripten/mod.rs @@ -1740,8 +1740,10 @@ f! { minor |= (dev & 0xffffff00) >> 12; minor as ::c_uint } +} - pub fn makedev(major: ::c_uint, minor: ::c_uint) -> ::dev_t { +safe_f! { + pub {const} fn makedev(major: ::c_uint, minor: ::c_uint) -> ::dev_t { let major = major as ::dev_t; let minor = minor as ::dev_t; let mut dev = 0; diff --git a/src/unix/linux_like/linux/mod.rs b/src/unix/linux_like/linux/mod.rs index 6d078aac32835..026c5307c2002 100644 --- a/src/unix/linux_like/linux/mod.rs +++ b/src/unix/linux_like/linux/mod.rs @@ -3351,17 +3351,6 @@ f! { minor as ::c_uint } - pub fn makedev(major: ::c_uint, minor: ::c_uint) -> ::dev_t { - let major = major as ::dev_t; - let minor = minor as ::dev_t; - let mut dev = 0; - dev |= (major & 0x00000fff) << 8; - dev |= (major & 0xfffff000) << 32; - dev |= (minor & 0x000000ff) << 0; - dev |= (minor & 0xffffff00) << 12; - dev - } - pub fn IPTOS_TOS(tos: u8) -> u8 { tos & IPTOS_TOS_MASK } @@ -3403,6 +3392,19 @@ f! { } } +safe_f! { + pub {const} fn makedev(major: ::c_uint, minor: ::c_uint) -> ::dev_t { + let major = major as ::dev_t; + let minor = minor as ::dev_t; + let mut dev = 0; + dev |= (major & 0x00000fff) << 8; + dev |= (major & 0xfffff000) << 32; + dev |= (minor & 0x000000ff) << 0; + dev |= (minor & 0xffffff00) << 12; + dev + } +} + cfg_if! { if #[cfg(not(target_env = "uclibc"))] { extern "C" {