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;

src/unix/bsd/netbsdlike/netbsd/mod.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2351,6 +2351,16 @@ safe_f! {
23512351
pub {const} fn WIFCONTINUED(status: ::c_int) -> bool {
23522352
status == 0xffff
23532353
}
2354+
2355+
pub {const} fn makedev(major: ::c_uint, minor: ::c_uint) -> ::dev_t {
2356+
let major = major as ::dev_t;
2357+
let minor = minor as ::dev_t;
2358+
let mut dev = 0;
2359+
dev |= (major << 8) & 0x000ff00;
2360+
dev |= (minor << 12) & 0xfff00000;
2361+
dev |= minor & 0xff;
2362+
dev
2363+
}
23542364
}
23552365

23562366
extern "C" {

src/unix/bsd/netbsdlike/openbsd/mod.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1695,6 +1695,16 @@ safe_f! {
16951695
pub {const} fn WIFCONTINUED(status: ::c_int) -> bool {
16961696
(status & 0o177777) == 0o177777
16971697
}
1698+
1699+
pub {const} fn makedev(major: ::c_uint, minor: ::c_uint) -> ::dev_t {
1700+
let major = major as ::dev_t;
1701+
let minor = minor as ::dev_t;
1702+
let mut dev = 0;
1703+
dev |= (major & 0xff) << 8;
1704+
dev |= minor & 0xff;
1705+
dev |= (minor & 0xffff00) << 8;
1706+
dev
1707+
}
16981708
}
16991709

17001710
extern "C" {

src/unix/linux_like/android/mod.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2781,12 +2781,6 @@ f! {
27812781
pub fn minor(dev: ::dev_t) -> ::c_int {
27822782
((dev & 0xff) | ((dev >> 12) & 0xfff00)) as ::c_int
27832783
}
2784-
pub fn makedev(ma: ::c_int, mi: ::c_int) -> ::dev_t {
2785-
let ma = ma as ::dev_t;
2786-
let mi = mi as ::dev_t;
2787-
((ma & 0xfff) << 8) | (mi & 0xff) | ((mi & 0xfff00) << 12)
2788-
}
2789-
27902784
pub fn NLA_ALIGN(len: ::c_int) -> ::c_int {
27912785
return ((len) + NLA_ALIGNTO - 1) & !(NLA_ALIGNTO - 1)
27922786
}
@@ -2796,6 +2790,15 @@ f! {
27962790
}
27972791
}
27982792

2793+
safe_f! {
2794+
pub {const} fn makedev(ma: ::c_uint, mi: ::c_uint) -> ::dev_t {
2795+
let ma = ma as ::dev_t;
2796+
let mi = mi as ::dev_t;
2797+
((ma & 0xfff) << 8) | (mi & 0xff) | ((mi & 0xfff00) << 12)
2798+
}
2799+
2800+
}
2801+
27992802
extern "C" {
28002803
pub fn getrlimit64(resource: ::c_int, rlim: *mut rlimit64) -> ::c_int;
28012804
pub fn setrlimit64(resource: ::c_int, rlim: *const rlimit64) -> ::c_int;

src/unix/linux_like/emscripten/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1740,8 +1740,10 @@ f! {
17401740
minor |= (dev & 0xffffff00) >> 12;
17411741
minor as ::c_uint
17421742
}
1743+
}
17431744

1744-
pub fn makedev(major: ::c_uint, minor: ::c_uint) -> ::dev_t {
1745+
safe_f! {
1746+
pub {const} fn makedev(major: ::c_uint, minor: ::c_uint) -> ::dev_t {
17451747
let major = major as ::dev_t;
17461748
let minor = minor as ::dev_t;
17471749
let mut dev = 0;

src/unix/linux_like/linux/mod.rs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3351,17 +3351,6 @@ f! {
33513351
minor as ::c_uint
33523352
}
33533353

3354-
pub fn makedev(major: ::c_uint, minor: ::c_uint) -> ::dev_t {
3355-
let major = major as ::dev_t;
3356-
let minor = minor as ::dev_t;
3357-
let mut dev = 0;
3358-
dev |= (major & 0x00000fff) << 8;
3359-
dev |= (major & 0xfffff000) << 32;
3360-
dev |= (minor & 0x000000ff) << 0;
3361-
dev |= (minor & 0xffffff00) << 12;
3362-
dev
3363-
}
3364-
33653354
pub fn IPTOS_TOS(tos: u8) -> u8 {
33663355
tos & IPTOS_TOS_MASK
33673356
}
@@ -3403,6 +3392,19 @@ f! {
34033392
}
34043393
}
34053394

3395+
safe_f! {
3396+
pub {const} fn makedev(major: ::c_uint, minor: ::c_uint) -> ::dev_t {
3397+
let major = major as ::dev_t;
3398+
let minor = minor as ::dev_t;
3399+
let mut dev = 0;
3400+
dev |= (major & 0x00000fff) << 8;
3401+
dev |= (major & 0xfffff000) << 32;
3402+
dev |= (minor & 0x000000ff) << 0;
3403+
dev |= (minor & 0xffffff00) << 12;
3404+
dev
3405+
}
3406+
}
3407+
34063408
cfg_if! {
34073409
if #[cfg(not(target_env = "uclibc"))] {
34083410
extern "C" {

0 commit comments

Comments
 (0)