rustix/backend/libc/
c.rs

1//! Libc and supplemental types and constants.
2
3#![allow(unused_imports)]
4
5// Import everything from libc, but we'll add some stuff and override some
6// things below.
7pub(crate) use libc::*;
8
9/// `PROC_SUPER_MAGIC`—The magic number for the procfs filesystem.
10#[cfg(all(linux_kernel, target_env = "musl"))]
11pub(crate) const PROC_SUPER_MAGIC: u32 = 0x0000_9fa0;
12
13/// `NFS_SUPER_MAGIC`—The magic number for the NFS filesystem.
14#[cfg(all(linux_kernel, target_env = "musl"))]
15pub(crate) const NFS_SUPER_MAGIC: u32 = 0x0000_6969;
16
17#[cfg(feature = "process")]
18#[cfg(not(any(target_os = "espidf", target_os = "wasi")))]
19pub(crate) const EXIT_SIGNALED_SIGABRT: c_int = 128 + SIGABRT as c_int;
20
21// TODO: Upstream these.
22#[cfg(all(linux_kernel, feature = "net"))]
23pub(crate) const ETH_P_TSN: c_int = linux_raw_sys::if_ether::ETH_P_TSN as _;
24#[cfg(all(linux_kernel, feature = "net"))]
25pub(crate) const ETH_P_ERSPAN2: c_int = linux_raw_sys::if_ether::ETH_P_ERSPAN2 as _;
26#[cfg(all(linux_kernel, feature = "net"))]
27pub(crate) const ETH_P_ERSPAN: c_int = linux_raw_sys::if_ether::ETH_P_ERSPAN as _;
28#[cfg(all(linux_kernel, feature = "net"))]
29pub(crate) const ETH_P_PROFINET: c_int = linux_raw_sys::if_ether::ETH_P_PROFINET as _;
30#[cfg(all(linux_kernel, feature = "net"))]
31pub(crate) const ETH_P_REALTEK: c_int = linux_raw_sys::if_ether::ETH_P_REALTEK as _;
32#[cfg(all(linux_kernel, feature = "net"))]
33pub(crate) const ETH_P_ETHERCAT: c_int = linux_raw_sys::if_ether::ETH_P_ETHERCAT as _;
34#[cfg(all(linux_kernel, feature = "net"))]
35pub(crate) const ETH_P_PREAUTH: c_int = linux_raw_sys::if_ether::ETH_P_PREAUTH as _;
36#[cfg(all(linux_kernel, feature = "net"))]
37pub(crate) const ETH_P_LLDP: c_int = linux_raw_sys::if_ether::ETH_P_LLDP as _;
38#[cfg(all(linux_kernel, feature = "net"))]
39pub(crate) const ETH_P_MRP: c_int = linux_raw_sys::if_ether::ETH_P_MRP as _;
40#[cfg(all(linux_kernel, feature = "net"))]
41pub(crate) const ETH_P_NCSI: c_int = linux_raw_sys::if_ether::ETH_P_NCSI as _;
42#[cfg(all(linux_kernel, feature = "net"))]
43pub(crate) const ETH_P_CFM: c_int = linux_raw_sys::if_ether::ETH_P_CFM as _;
44#[cfg(all(linux_kernel, feature = "net"))]
45pub(crate) const ETH_P_IBOE: c_int = linux_raw_sys::if_ether::ETH_P_IBOE as _;
46#[cfg(all(linux_kernel, feature = "net"))]
47pub(crate) const ETH_P_HSR: c_int = linux_raw_sys::if_ether::ETH_P_HSR as _;
48#[cfg(all(linux_kernel, feature = "net"))]
49pub(crate) const ETH_P_NSH: c_int = linux_raw_sys::if_ether::ETH_P_NSH as _;
50#[cfg(all(linux_kernel, feature = "net"))]
51pub(crate) const ETH_P_DSA_8021Q: c_int = linux_raw_sys::if_ether::ETH_P_DSA_8021Q as _;
52#[cfg(all(linux_kernel, feature = "net"))]
53pub(crate) const ETH_P_DSA_A5PSW: c_int = linux_raw_sys::if_ether::ETH_P_DSA_A5PSW as _;
54#[cfg(all(linux_kernel, feature = "net"))]
55pub(crate) const ETH_P_IFE: c_int = linux_raw_sys::if_ether::ETH_P_IFE as _;
56#[cfg(all(linux_kernel, feature = "net"))]
57pub(crate) const ETH_P_CAN: c_int = linux_raw_sys::if_ether::ETH_P_CAN as _;
58#[cfg(all(linux_kernel, feature = "net"))]
59pub(crate) const ETH_P_CANXL: c_int = linux_raw_sys::if_ether::ETH_P_CANXL as _;
60#[cfg(all(linux_kernel, feature = "net"))]
61pub(crate) const ETH_P_XDSA: c_int = linux_raw_sys::if_ether::ETH_P_XDSA as _;
62#[cfg(all(linux_kernel, feature = "net"))]
63pub(crate) const ETH_P_MAP: c_int = linux_raw_sys::if_ether::ETH_P_MAP as _;
64#[cfg(all(linux_kernel, feature = "net"))]
65pub(crate) const ETH_P_MCTP: c_int = linux_raw_sys::if_ether::ETH_P_MCTP as _;
66
67#[cfg(all(
68    linux_kernel,
69    any(
70        target_arch = "mips",
71        target_arch = "mips32r6",
72        target_arch = "mips64",
73        target_arch = "mips64r6",
74        target_arch = "sparc",
75        target_arch = "sparc64"
76    )
77))]
78pub(crate) const SIGEMT: c_int = linux_raw_sys::general::SIGEMT as _;
79
80// TODO: Upstream these.
81#[cfg(all(linux_kernel, feature = "termios"))]
82pub(crate) const IUCLC: tcflag_t = linux_raw_sys::general::IUCLC as _;
83#[cfg(all(linux_kernel, feature = "termios"))]
84pub(crate) const XCASE: tcflag_t = linux_raw_sys::general::XCASE as _;
85
86#[cfg(target_os = "aix")]
87pub(crate) const MSG_DONTWAIT: c_int = MSG_NONBLOCK;
88
89// `O_LARGEFILE` can be automatically set by the kernel on Linux:
90// <https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/fs/open.c?h=v6.13#n1423>
91// so libc implementations may leave it undefined or defined to zero.
92#[cfg(linux_kernel)]
93pub(crate) const O_LARGEFILE: c_int = linux_raw_sys::general::O_LARGEFILE as _;
94
95// Gated under `_LARGEFILE_SOURCE` but automatically set by the kernel.
96// <https://github.com/illumos/illumos-gate/blob/fb2cb638e5604b214d8ea8d4f01ad2e77b437c17/usr/src/ucbhead/sys/fcntl.h#L64>
97#[cfg(solarish)]
98pub(crate) const O_LARGEFILE: c_int = 0x2000;
99
100// On PowerPC, the regular `termios` has the `termios2` fields and there is no
101// `termios2`, so we define aliases.
102#[cfg(all(
103    linux_kernel,
104    feature = "termios",
105    any(target_arch = "powerpc", target_arch = "powerpc64")
106))]
107pub(crate) use {
108    termios as termios2, TCGETS as TCGETS2, TCSETS as TCSETS2, TCSETSF as TCSETSF2,
109    TCSETSW as TCSETSW2,
110};
111
112// And PowerPC doesn't define `CIBAUD`, but it does define `IBSHIFT`, so we can
113// compute `CIBAUD` ourselves.
114#[cfg(all(
115    linux_kernel,
116    feature = "termios",
117    any(target_arch = "powerpc", target_arch = "powerpc64")
118))]
119pub(crate) const CIBAUD: u32 = CBAUD << IBSHIFT;
120
121// Automatically enable “large file” support (LFS) features.
122
123#[cfg(target_os = "vxworks")]
124pub(super) use _Vx_ticks64_t as _Vx_ticks_t;
125#[cfg(linux_kernel)]
126pub(super) use fallocate64 as fallocate;
127#[cfg(not(any(target_arch = "aarch64", target_arch = "riscv64")))]
128#[cfg(any(linux_like, target_os = "aix"))]
129pub(super) use open64 as open;
130#[cfg(any(
131    linux_kernel,
132    target_os = "aix",
133    target_os = "hurd",
134    target_os = "l4re"
135))]
136pub(super) use posix_fallocate64 as posix_fallocate;
137#[cfg(any(all(linux_like, not(target_os = "android")), target_os = "aix"))]
138pub(super) use {blkcnt64_t as blkcnt_t, rlim64_t as rlim_t};
139// TODO: AIX has `stat64x`, `fstat64x`, `lstat64x`, and `stat64xat`; add them
140// to the upstream libc crate and implement rustix's `statat` etc. with them.
141#[cfg(target_os = "aix")]
142pub(super) use {
143    blksize64_t as blksize_t, fstat64 as fstat, fstatfs64 as fstatfs, fstatvfs64 as fstatvfs,
144    ftruncate64 as ftruncate, getrlimit64 as getrlimit, ino_t, lseek64 as lseek, mmap,
145    off64_t as off_t, openat, posix_fadvise64 as posix_fadvise, preadv, pwritev,
146    rlimit64 as rlimit, setrlimit64 as setrlimit, stat64at as fstatat, statfs64 as statfs,
147    statvfs64 as statvfs, RLIM_INFINITY,
148};
149#[cfg(any(linux_like, target_os = "hurd"))]
150pub(super) use {
151    fstat64 as fstat, fstatat64 as fstatat, fstatfs64 as fstatfs, fstatvfs64 as fstatvfs,
152    ftruncate64 as ftruncate, getrlimit64 as getrlimit, ino64_t as ino_t, lseek64 as lseek,
153    mmap64 as mmap, off64_t as off_t, openat64 as openat, posix_fadvise64 as posix_fadvise,
154    rlimit64 as rlimit, setrlimit64 as setrlimit, statfs64 as statfs, statvfs64 as statvfs,
155    RLIM64_INFINITY as RLIM_INFINITY,
156};
157#[cfg(apple)]
158pub(super) use {
159    host_info64_t as host_info_t, host_statistics64 as host_statistics,
160    vm_statistics64_t as vm_statistics_t,
161};
162#[cfg(not(all(
163    linux_kernel,
164    any(
165        target_pointer_width = "32",
166        target_arch = "mips64",
167        target_arch = "mips64r6"
168    )
169)))]
170#[cfg(any(linux_like, target_os = "aix", target_os = "hurd"))]
171pub(super) use {lstat64 as lstat, stat64 as stat};
172#[cfg(any(
173    linux_kernel,
174    target_os = "aix",
175    target_os = "hurd",
176    target_os = "emscripten"
177))]
178pub(super) use {pread64 as pread, pwrite64 as pwrite};
179#[cfg(any(target_os = "linux", target_os = "hurd", target_os = "emscripten"))]
180pub(super) use {preadv64 as preadv, pwritev64 as pwritev};
181
182#[cfg(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")))]
183pub(super) unsafe fn prlimit(
184    pid: pid_t,
185    resource: __rlimit_resource_t,
186    new_limit: *const rlimit64,
187    old_limit: *mut rlimit64,
188) -> c_int {
189    // `prlimit64` wasn't supported in glibc until 2.13.
190    weak_or_syscall! {
191        fn prlimit64(
192            pid: pid_t,
193            resource: __rlimit_resource_t,
194            new_limit: *const rlimit64,
195            old_limit: *mut rlimit64
196        ) via SYS_prlimit64 -> c_int
197    }
198
199    prlimit64(pid, resource, new_limit, old_limit)
200}
201
202#[cfg(all(target_os = "linux", target_env = "musl"))]
203pub(super) unsafe fn prlimit(
204    pid: pid_t,
205    resource: c_int,
206    new_limit: *const rlimit64,
207    old_limit: *mut rlimit64,
208) -> c_int {
209    weak_or_syscall! {
210        fn prlimit64(
211            pid: pid_t,
212            resource: c_int,
213            new_limit: *const rlimit64,
214            old_limit: *mut rlimit64
215        ) via SYS_prlimit64 -> c_int
216    }
217
218    prlimit64(pid, resource, new_limit, old_limit)
219}
220
221#[cfg(target_os = "android")]
222pub(super) unsafe fn prlimit(
223    pid: pid_t,
224    resource: c_int,
225    new_limit: *const rlimit64,
226    old_limit: *mut rlimit64,
227) -> c_int {
228    weak_or_syscall! {
229        fn prlimit64(
230            pid: pid_t,
231            resource: c_int,
232            new_limit: *const rlimit64,
233            old_limit: *mut rlimit64
234        ) via SYS_prlimit64 -> c_int
235    }
236
237    prlimit64(pid, resource, new_limit, old_limit)
238}
239
240#[cfg(target_os = "android")]
241mod readwrite_pv64 {
242    use super::*;
243
244    pub(in super::super) unsafe fn preadv64(
245        fd: c_int,
246        iov: *const iovec,
247        iovcnt: c_int,
248        offset: off64_t,
249    ) -> ssize_t {
250        // Older Android libc lacks `preadv64`, so use the `weak!` mechanism to
251        // test for it, and call back to `syscall`. We don't use
252        // `weak_or_syscall` here because we need to pass the 64-bit offset
253        // specially.
254        weak! {
255            fn preadv64(c_int, *const iovec, c_int, off64_t) -> ssize_t
256        }
257        if let Some(fun) = preadv64.get() {
258            fun(fd, iov, iovcnt, offset)
259        } else {
260            // Unlike the plain "p" functions, the "pv" functions pass their
261            // offset in an endian-independent way, and always in two
262            // registers.
263            syscall! {
264                fn preadv(
265                    fd: c_int,
266                    iov: *const iovec,
267                    iovcnt: c_int,
268                    offset_lo: usize,
269                    offset_hi: usize
270                ) via SYS_preadv -> ssize_t
271            }
272            preadv(fd, iov, iovcnt, offset as usize, (offset >> 32) as usize)
273        }
274    }
275    pub(in super::super) unsafe fn pwritev64(
276        fd: c_int,
277        iov: *const iovec,
278        iovcnt: c_int,
279        offset: off64_t,
280    ) -> ssize_t {
281        // See the comments in `preadv64`.
282        weak! {
283            fn pwritev64(c_int, *const iovec, c_int, off64_t) -> ssize_t
284        }
285        if let Some(fun) = pwritev64.get() {
286            fun(fd, iov, iovcnt, offset)
287        } else {
288            // Unlike the plain "p" functions, the "pv" functions pass their
289            // offset in an endian-independent way, and always in two
290            // registers.
291            syscall! {
292                fn pwritev(
293                    fd: c_int,
294                    iov: *const iovec,
295                    iovcnt: c_int,
296                    offset_lo: usize,
297                    offset_hi: usize
298                ) via SYS_pwritev -> ssize_t
299            }
300            pwritev(fd, iov, iovcnt, offset as usize, (offset >> 32) as usize)
301        }
302    }
303}
304#[cfg(target_os = "android")]
305pub(super) use readwrite_pv64::{preadv64 as preadv, pwritev64 as pwritev};
306
307// macOS added `preadv` and `pwritev` in version 11.0.
308#[cfg(apple)]
309mod readwrite_pv {
310    use super::*;
311    weakcall! {
312        pub(in super::super) fn preadv(
313            fd: c_int,
314            iov: *const iovec,
315            iovcnt: c_int,
316            offset: off_t
317        ) -> ssize_t
318    }
319    weakcall! {
320        pub(in super::super) fn pwritev(
321            fd: c_int,
322            iov: *const iovec,
323            iovcnt: c_int, offset: off_t
324        ) -> ssize_t
325    }
326}
327#[cfg(apple)]
328pub(super) use readwrite_pv::{preadv, pwritev};
329
330// glibc added `preadv64v2` and `pwritev64v2` in version 2.26.
331#[cfg(all(target_os = "linux", target_env = "gnu"))]
332mod readwrite_pv64v2 {
333    use super::*;
334
335    pub(in super::super) unsafe fn preadv64v2(
336        fd: c_int,
337        iov: *const iovec,
338        iovcnt: c_int,
339        offset: off64_t,
340        flags: c_int,
341    ) -> ssize_t {
342        // Older glibc lacks `preadv64v2`, so use the `weak!` mechanism to
343        // test for it, and call back to `syscall`. We don't use
344        // `weak_or_syscall` here because we need to pass the 64-bit offset
345        // specially.
346        weak! {
347            fn preadv64v2(c_int, *const iovec, c_int, off64_t, c_int) -> ssize_t
348        }
349        if let Some(fun) = preadv64v2.get() {
350            fun(fd, iov, iovcnt, offset, flags)
351        } else {
352            // Unlike the plain "p" functions, the "pv" functions pass their
353            // offset in an endian-independent way, and always in two
354            // registers.
355            syscall! {
356                fn preadv2(
357                    fd: c_int,
358                    iov: *const iovec,
359                    iovcnt: c_int,
360                    offset_lo: usize,
361                    offset_hi: usize,
362                    flags: c_int
363                ) via SYS_preadv2 -> ssize_t
364            }
365            preadv2(
366                fd,
367                iov,
368                iovcnt,
369                offset as usize,
370                (offset >> 32) as usize,
371                flags,
372            )
373        }
374    }
375    pub(in super::super) unsafe fn pwritev64v2(
376        fd: c_int,
377        iov: *const iovec,
378        iovcnt: c_int,
379        offset: off64_t,
380        flags: c_int,
381    ) -> ssize_t {
382        // See the comments in `preadv64v2`.
383        weak! {
384            fn pwritev64v2(c_int, *const iovec, c_int, off64_t, c_int) -> ssize_t
385        }
386        if let Some(fun) = pwritev64v2.get() {
387            fun(fd, iov, iovcnt, offset, flags)
388        } else {
389            // Unlike the plain "p" functions, the "pv" functions pass their
390            // offset in an endian-independent way, and always in two
391            // registers.
392            syscall! {
393                fn pwritev2(
394                    fd: c_int,
395                    iov: *const iovec,
396                    iovec: c_int,
397                    offset_lo: usize,
398                    offset_hi: usize,
399                    flags: c_int
400                ) via SYS_pwritev2 -> ssize_t
401            }
402            pwritev2(
403                fd,
404                iov,
405                iovcnt,
406                offset as usize,
407                (offset >> 32) as usize,
408                flags,
409            )
410        }
411    }
412}
413#[cfg(all(target_os = "linux", target_env = "gnu"))]
414pub(super) use readwrite_pv64v2::{preadv64v2 as preadv2, pwritev64v2 as pwritev2};
415
416// On non-glibc, assume we don't have `pwritev2`/`preadv2` in libc and use
417// `c::syscall` instead.
418#[cfg(any(
419    target_os = "android",
420    all(target_os = "linux", not(target_env = "gnu")),
421))]
422mod readwrite_pv64v2 {
423    use super::*;
424
425    pub(in super::super) unsafe fn preadv64v2(
426        fd: c_int,
427        iov: *const iovec,
428        iovcnt: c_int,
429        offset: off64_t,
430        flags: c_int,
431    ) -> ssize_t {
432        // Unlike the plain "p" functions, the "pv" functions pass their offset
433        // in an endian-independent way, and always in two registers.
434        syscall! {
435            fn preadv2(
436                fd: c_int,
437                iov: *const iovec,
438                iovcnt: c_int,
439                offset_lo: usize,
440                offset_hi: usize,
441                flags: c_int
442            ) via SYS_preadv2 -> ssize_t
443        }
444        preadv2(
445            fd,
446            iov,
447            iovcnt,
448            offset as usize,
449            (offset >> 32) as usize,
450            flags,
451        )
452    }
453    pub(in super::super) unsafe fn pwritev64v2(
454        fd: c_int,
455        iov: *const iovec,
456        iovcnt: c_int,
457        offset: off64_t,
458        flags: c_int,
459    ) -> ssize_t {
460        // Unlike the plain "p" functions, the "pv" functions pass their offset
461        // in an endian-independent way, and always in two registers.
462        syscall! {
463            fn pwritev2(
464                fd: c_int,
465                iov: *const iovec,
466                iovcnt: c_int,
467                offset_lo: usize,
468                offset_hi: usize,
469                flags: c_int
470            ) via SYS_pwritev2 -> ssize_t
471        }
472        pwritev2(
473            fd,
474            iov,
475            iovcnt,
476            offset as usize,
477            (offset >> 32) as usize,
478            flags,
479        )
480    }
481}
482#[cfg(any(
483    target_os = "android",
484    all(target_os = "linux", not(target_env = "gnu")),
485))]
486pub(super) use readwrite_pv64v2::{preadv64v2 as preadv2, pwritev64v2 as pwritev2};
487
488// Rust's libc crate lacks statx for Non-glibc targets.
489#[cfg(feature = "fs")]
490#[cfg(all(
491    linux_like,
492    not(any(target_os = "android", target_os = "emscripten", target_env = "gnu"))
493))]
494mod statx_flags {
495    pub(crate) use linux_raw_sys::general::{
496        STATX_ALL, STATX_ATIME, STATX_BASIC_STATS, STATX_BLOCKS, STATX_BTIME, STATX_CTIME,
497        STATX_DIOALIGN, STATX_GID, STATX_INO, STATX_MNT_ID, STATX_MODE, STATX_MTIME, STATX_NLINK,
498        STATX_SIZE, STATX_TYPE, STATX_UID,
499    };
500
501    pub(crate) use linux_raw_sys::general::{
502        STATX_ATTR_APPEND, STATX_ATTR_AUTOMOUNT, STATX_ATTR_COMPRESSED, STATX_ATTR_DAX,
503        STATX_ATTR_ENCRYPTED, STATX_ATTR_IMMUTABLE, STATX_ATTR_MOUNT_ROOT, STATX_ATTR_NODUMP,
504        STATX_ATTR_VERITY,
505    };
506}
507#[cfg(feature = "fs")]
508#[cfg(all(
509    linux_like,
510    not(any(target_os = "android", target_os = "emscripten", target_env = "gnu"))
511))]
512pub(crate) use statx_flags::*;
513
514#[cfg(feature = "fs")]
515#[cfg(target_os = "android")]
516pub(crate) use __fsid_t as fsid_t;
517
518#[cfg(feature = "mm")]
519#[cfg(target_os = "android")]
520pub(crate) const MAP_DROPPABLE: c_int = bitcast!(linux_raw_sys::general::MAP_DROPPABLE);
521
522#[cfg(test)]
523mod tests {
524    use super::*;
525
526    #[test]
527    #[cfg(linux_kernel)]
528    fn test_flags() {
529        // libc may publicly define `O_LARGEFILE` to 0, but we want the real
530        // non-zero value.
531        assert_ne!(O_LARGEFILE, 0);
532    }
533}