Skip to content

Commit 5e6d9c4

Browse files
committed
Add makedev for the BSDs
Also, make makedev function safe and const on all platforms. On Android, change the arguments from signed to unsigned integers to match the other platforms. The C makedev is a macro, so the signededness is undefined. Add an integration test for makedev, too, since it's a macro that we must reimplement.
1 parent 75dd59e commit 5e6d9c4

File tree

15 files changed

+242
-29
lines changed

15 files changed

+242
-29
lines changed

libc-test/Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,11 @@ name = "cmsg"
6666
path = "test/cmsg.rs"
6767
harness = true
6868

69+
[[test]]
70+
name = "makedev"
71+
path = "test/makedev.rs"
72+
harness = true
73+
6974
[[test]]
7075
name = "errqueue"
7176
path = "test/errqueue.rs"

libc-test/build.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,15 @@ fn do_cc() {
2222
}
2323
cmsg.compile("cmsg");
2424
}
25+
26+
if target.contains("linux")
27+
|| target.contains("android")
28+
|| target.contains("emscripten")
29+
|| target.contains("fuchsia")
30+
|| target.contains("bsd")
31+
{
32+
cc::Build::new().file("src/makedev.c").compile("makedev");
33+
}
2534
}
2635
if target.contains("android") || target.contains("linux") {
2736
cc::Build::new().file("src/errqueue.c").compile("errqueue");

libc-test/src/makedev.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#include <sys/types.h>
2+
#if defined(__linux__) || defined(__EMSCRIPTEN__)
3+
#include <sys/sysmacros.h>
4+
#endif
5+
6+
// Since makedev is a macro instead of a function, it isn't available to FFI.
7+
// libc must reimplement it, which is error-prone. This file provides FFI
8+
// access to the actual macro so it can be tested against the Rust
9+
// reimplementation.
10+
11+
dev_t makedev_ffi(unsigned major, unsigned minor) {
12+
return makedev(major, minor);
13+
}

libc-test/test/makedev.rs

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
//! Compare libc's makdev function against the actual C macros, for various
2+
//! inputs.
3+
4+
extern crate libc;
5+
6+
#[cfg(any(
7+
target_os = "android",
8+
target_os = "dragonfly",
9+
target_os = "emscripten",
10+
target_os = "freebsd",
11+
target_os = "fuchsia",
12+
target_os = "linux",
13+
target_os = "netbsd",
14+
target_os = "openbsd",
15+
))]
16+
mod t {
17+
use libc::{self, c_uint, dev_t};
18+
19+
extern "C" {
20+
pub fn makedev_ffi(major: c_uint, minor: c_uint) -> dev_t;
21+
}
22+
23+
fn compare(major: c_uint, minor: c_uint) {
24+
let expected = unsafe { makedev_ffi(major, minor) };
25+
assert_eq!(libc::makedev(major, minor), expected);
26+
}
27+
28+
// Every OS should be able to handle 8 bit major and minor numbers
29+
#[test]
30+
fn test_8bits() {
31+
for major in 0..256 {
32+
for minor in 0..256 {
33+
compare(major, minor);
34+
}
35+
}
36+
}
37+
38+
// Android allows 12 bits for major and 20 for minor
39+
#[test]
40+
#[cfg(target_os = "android")]
41+
fn test_android_like() {
42+
for major in [0, 1, 255, 256, 4095] {
43+
for minor_exp in [1, 8, 16] {
44+
for minor in [(1 << minor_exp) - 1, (1 << minor_exp)] {
45+
compare(major, minor);
46+
}
47+
}
48+
compare(major, (1 << 20) - 1);
49+
}
50+
}
51+
52+
// These OSes allow 32 bits for minor, but only 8 for major
53+
#[test]
54+
#[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd",))]
55+
fn test_fbsd11_like() {
56+
for major in [0, 1, 255] {
57+
for minor_exp in [1, 8, 16, 24, 31] {
58+
for minor in [(1 << minor_exp) - 1, (1 << minor_exp)] {
59+
compare(major, minor);
60+
}
61+
}
62+
compare(major, c_uint::MAX);
63+
}
64+
}
65+
66+
// OpenBSD allows 8 bits for major and 24 for minor
67+
#[test]
68+
#[cfg(target_os = "openbsd")]
69+
fn test_openbsd_like() {
70+
for major in [0, 1, 255] {
71+
for minor_exp in [1, 8, 16] {
72+
for minor in [(1 << minor_exp) - 1, (1 << minor_exp)] {
73+
compare(major, minor);
74+
}
75+
}
76+
compare(major, (1 << 24) - 1);
77+
}
78+
}
79+
80+
// These OSes allow 32 bits for both minor and major
81+
#[cfg(any(
82+
target_os = "empscripten",
83+
target_os = "freebsd",
84+
target_os = "fuchsia",
85+
target_os = "linux",
86+
))]
87+
#[test]
88+
fn test_fbsd12_like() {
89+
if std::mem::size_of::<dev_t>() >= 8 {
90+
for major_exp in [0, 16, 24, 31] {
91+
for major in [(1 << major_exp) - 1, (1 << major_exp)] {
92+
for minor_exp in [1, 8, 16, 24, 31] {
93+
for minor in [(1 << minor_exp) - 1, (1 << minor_exp)] {
94+
compare(major, minor);
95+
}
96+
}
97+
compare(major, c_uint::MAX);
98+
}
99+
compare(c_uint::MAX, c_uint::MAX);
100+
}
101+
}
102+
}
103+
}

src/fuchsia/mod.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3235,17 +3235,6 @@ f! {
32353235
minor as ::c_uint
32363236
}
32373237

3238-
pub fn makedev(major: ::c_uint, minor: ::c_uint) -> ::dev_t {
3239-
let major = major as ::dev_t;
3240-
let minor = minor as ::dev_t;
3241-
let mut dev = 0;
3242-
dev |= (major & 0x00000fff) << 8;
3243-
dev |= (major & 0xfffff000) << 32;
3244-
dev |= (minor & 0x000000ff) << 0;
3245-
dev |= (minor & 0xffffff00) << 12;
3246-
dev
3247-
}
3248-
32493238
pub fn CMSG_DATA(cmsg: *const cmsghdr) -> *mut c_uchar {
32503239
cmsg.offset(1) as *mut c_uchar
32513240
}
@@ -3322,6 +3311,17 @@ safe_f! {
33223311
pub {const} fn QCMD(cmd: ::c_int, type_: ::c_int) -> ::c_int {
33233312
(cmd << 8) | (type_ & 0x00ff)
33243313
}
3314+
3315+
pub {const} fn makedev(major: ::c_uint, minor: ::c_uint) -> ::dev_t {
3316+
let major = major as ::dev_t;
3317+
let minor = minor as ::dev_t;
3318+
let mut dev = 0;
3319+
dev |= (major & 0x00000fff) << 8;
3320+
dev |= (major & 0xfffff000) << 32;
3321+
dev |= (minor & 0x000000ff) << 0;
3322+
dev |= (minor & 0xffffff00) << 12;
3323+
dev
3324+
}
33253325
}
33263326

33273327
fn __CMSG_LEN(cmsg: *const cmsghdr) -> ::ssize_t {

src/unix/bsd/freebsdlike/dragonfly/mod.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1571,6 +1571,15 @@ safe_f! {
15711571
pub {const} fn WIFSIGNALED(status: ::c_int) -> bool {
15721572
(status & 0o177) != 0o177 && (status & 0o177) != 0
15731573
}
1574+
1575+
pub {const} fn makedev(major: ::c_uint, minor: ::c_uint) -> ::dev_t {
1576+
let major = major as ::dev_t;
1577+
let minor = minor as ::dev_t;
1578+
let mut dev = 0;
1579+
dev |= major << 8;
1580+
dev |= minor;
1581+
dev
1582+
}
15741583
}
15751584

15761585
extern "C" {

src/unix/bsd/freebsdlike/freebsd/freebsd11/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,14 @@ pub const MINCORE_SUPER: ::c_int = 0x20;
434434
/// max length of devicename
435435
pub const SPECNAMELEN: ::c_int = 63;
436436

437+
safe_f! {
438+
pub {const} fn makedev(major: ::c_uint, minor: ::c_uint) -> ::dev_t {
439+
let major = major as ::dev_t;
440+
let minor = minor as ::dev_t;
441+
(major << 8) | minor
442+
}
443+
}
444+
437445
extern "C" {
438446
// Return type ::c_int was removed in FreeBSD 12
439447
pub fn setgrent() -> ::c_int;

src/unix/bsd/freebsdlike/freebsd/freebsd12/mod.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,19 @@ pub const KI_NSPARE_PTR: usize = 6;
449449

450450
pub const MINCORE_SUPER: ::c_int = 0x20;
451451

452+
safe_f! {
453+
pub {const} fn makedev(major: ::c_uint, minor: ::c_uint) -> ::dev_t {
454+
let major = major as ::dev_t;
455+
let minor = minor as ::dev_t;
456+
let mut dev = 0;
457+
dev |= ((major & 0xffffff00) as dev_t) << 32;
458+
dev |= ((major & 0x000000ff) as dev_t) << 8;
459+
dev |= ((minor & 0x0000ff00) as dev_t) << 24;
460+
dev |= ((minor & 0xffff00ff) as dev_t) << 0;
461+
dev
462+
}
463+
}
464+
452465
extern "C" {
453466
pub fn setgrent();
454467
pub fn mprotect(addr: *mut ::c_void, len: ::size_t, prot: ::c_int) -> ::c_int;

src/unix/bsd/freebsdlike/freebsd/freebsd13/mod.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,19 @@ pub const DOMAINSET_POLICY_INTERLEAVE: ::c_int = 4;
468468

469469
pub const MINCORE_SUPER: ::c_int = 0x20;
470470

471+
safe_f! {
472+
pub {const} fn makedev(major: ::c_uint, minor: ::c_uint) -> ::dev_t {
473+
let major = major as ::dev_t;
474+
let minor = minor as ::dev_t;
475+
let mut dev = 0;
476+
dev |= ((major & 0xffffff00) as dev_t) << 32;
477+
dev |= ((major & 0x000000ff) as dev_t) << 8;
478+
dev |= ((minor & 0x0000ff00) as dev_t) << 24;
479+
dev |= ((minor & 0xffff00ff) as dev_t) << 0;
480+
dev
481+
}
482+
}
483+
471484
extern "C" {
472485
pub fn setgrent();
473486
pub fn mprotect(addr: *mut ::c_void, len: ::size_t, prot: ::c_int) -> ::c_int;

src/unix/bsd/freebsdlike/freebsd/freebsd14/mod.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,19 @@ pub const DOMAINSET_POLICY_INTERLEAVE: ::c_int = 4;
468468

469469
pub const MINCORE_SUPER: ::c_int = 0x60;
470470

471+
safe_f! {
472+
pub {const} fn makedev(major: ::c_uint, minor: ::c_uint) -> ::dev_t {
473+
let major = major as ::dev_t;
474+
let minor = minor as ::dev_t;
475+
let mut dev = 0;
476+
dev |= ((major & 0xffffff00) as dev_t) << 32;
477+
dev |= ((major & 0x000000ff) as dev_t) << 8;
478+
dev |= ((minor & 0x0000ff00) as dev_t) << 24;
479+
dev |= ((minor & 0xffff00ff) as dev_t) << 0;
480+
dev
481+
}
482+
}
483+
471484
extern "C" {
472485
pub fn setgrent();
473486
pub fn mprotect(addr: *mut ::c_void, len: ::size_t, prot: ::c_int) -> ::c_int;

0 commit comments

Comments
 (0)