Skip to content

Commit 6eee580

Browse files
committed
Auto merge of #2891 - asomers:makedev, r=JohnTitor
Add makedev for the BSDs Also, make Linux's makedev function safe and const.
2 parents fb16d18 + 5e6d9c4 commit 6eee580

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)