Skip to content

Commit

Permalink
Add makedev for the BSDs
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
asomers committed Sep 3, 2022
1 parent 75dd59e commit 3de218a
Show file tree
Hide file tree
Showing 9 changed files with 186 additions and 11 deletions.
5 changes: 5 additions & 0 deletions libc-test/Cargo.toml
Expand Up @@ -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"
Expand Down
9 changes: 9 additions & 0 deletions libc-test/build.rs
Expand Up @@ -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");
Expand Down
13 changes: 13 additions & 0 deletions libc-test/src/makedev.c
@@ -0,0 +1,13 @@
#include <sys/types.h>
#ifdef __linux__
#include <sys/sysmacros.h>
#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);
}
103 changes: 103 additions & 0 deletions 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);
}
}
}
9 changes: 9 additions & 0 deletions src/unix/bsd/freebsdlike/dragonfly/mod.rs
Expand Up @@ -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" {
Expand Down
14 changes: 14 additions & 0 deletions src/unix/bsd/freebsdlike/freebsd/mod.rs
Expand Up @@ -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! {
Expand Down
10 changes: 10 additions & 0 deletions src/unix/bsd/netbsdlike/netbsd/mod.rs
Expand Up @@ -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" {
Expand Down
10 changes: 10 additions & 0 deletions src/unix/bsd/netbsdlike/openbsd/mod.rs
Expand Up @@ -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" {
Expand Down
24 changes: 13 additions & 11 deletions src/unix/linux_like/linux/mod.rs
Expand Up @@ -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
}
Expand Down Expand Up @@ -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" {
Expand Down

0 comments on commit 3de218a

Please sign in to comment.