From 3de218ae43cd8a603d93765c8a4daff403000d04 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Fri, 26 Aug 2022 14:15:53 -0600 Subject: [PATCH 1/4] Add makedev for the BSDs Also, make Linux's makedev function safe and const. Add an integration test for makedev, too, since it's a macro that we must reimplement. --- libc-test/Cargo.toml | 5 ++ libc-test/build.rs | 9 ++ libc-test/src/makedev.c | 13 +++ libc-test/test/makedev.rs | 103 ++++++++++++++++++++++ src/unix/bsd/freebsdlike/dragonfly/mod.rs | 9 ++ src/unix/bsd/freebsdlike/freebsd/mod.rs | 14 +++ src/unix/bsd/netbsdlike/netbsd/mod.rs | 10 +++ src/unix/bsd/netbsdlike/openbsd/mod.rs | 10 +++ src/unix/linux_like/linux/mod.rs | 24 ++--- 9 files changed, 186 insertions(+), 11 deletions(-) create mode 100644 libc-test/src/makedev.c create mode 100644 libc-test/test/makedev.rs 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..bf1c106663bea --- /dev/null +++ b/libc-test/src/makedev.c @@ -0,0 +1,13 @@ +#include +#ifdef __linux__ +#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..6a616fe33bf6a --- /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 = "fuchsia", + target_os = "linux", + freebsd12, + freebsd13, + freebsd14 + ))] + #[test] + fn test_fbsd12_like() { + for major_exp in [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/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/mod.rs b/src/unix/bsd/freebsdlike/freebsd/mod.rs index 42a71b21332ed..1d0fd0a6bb341 100644 --- a/src/unix/bsd/freebsdlike/freebsd/mod.rs +++ b/src/unix/bsd/freebsdlike/freebsd/mod.rs @@ -3840,6 +3840,20 @@ safe_f! { pub {const} fn WIFSIGNALED(status: ::c_int) -> bool { (status & 0o177) != 0o177 && (status & 0o177) != 0 && status != 0x13 } + + // This is the version of makedev used in FreeBSD 12.0 and later. It is + // backwards compatible with FreeBSD 11's makedev, within that version's + // more restricted domain of major and minor numbers. + 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 + } } cfg_if! { 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..ccb381ac6399f 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/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" { From 2f3fa3e9c6ec0f19ae27131676089c0f0902de3e Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Mon, 5 Sep 2022 07:10:10 -0600 Subject: [PATCH 2/4] Fix the build of the makedev test on emscripten --- libc-test/src/makedev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libc-test/src/makedev.c b/libc-test/src/makedev.c index bf1c106663bea..7f99d60728bb4 100644 --- a/libc-test/src/makedev.c +++ b/libc-test/src/makedev.c @@ -1,5 +1,5 @@ #include -#ifdef __linux__ +#if defined(__linux__) || defined(__EMSCRIPTEN__) #include #endif From 4f006afda53b023b354b74a921b6b68c3cbab3e0 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Mon, 5 Sep 2022 17:29:49 -0600 Subject: [PATCH 3/4] Make makedev safe and const on all platforms --- src/fuchsia/mod.rs | 22 +++++++++++----------- src/unix/linux_like/android/mod.rs | 15 +++++++++------ src/unix/linux_like/emscripten/mod.rs | 4 +++- 3 files changed, 23 insertions(+), 18 deletions(-) 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/linux_like/android/mod.rs b/src/unix/linux_like/android/mod.rs index cfd229a474a92..22d2c285fa612 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_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) + } + +} + 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; From 8486fd7073dce762e1897df3d06be69e8b6dc5b2 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Tue, 6 Sep 2022 17:05:16 -0600 Subject: [PATCH 4/4] make makedev's arguments unsigned on Android --- src/unix/linux_like/android/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unix/linux_like/android/mod.rs b/src/unix/linux_like/android/mod.rs index 22d2c285fa612..8a21147def82f 100644 --- a/src/unix/linux_like/android/mod.rs +++ b/src/unix/linux_like/android/mod.rs @@ -2791,7 +2791,7 @@ f! { } safe_f! { - pub {const} fn makedev(ma: ::c_int, mi: ::c_int) -> ::dev_t { + 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)