1//! Functions returning the stdio file descriptors.
2//!
3//! # Safety
4//!
5//! Some of the functions in this module can cause the process' stdio file
6//! descriptors to be closed, which breaks the assumption made in Rust's std
7//! that these file descriptors are always open.
8//!
9//! And in no-std mode, some of the functions in this module similarly assume
10//! that the process' stdio file descriptors are open, which we don't take as
11//! given in no-std mode because we don't have std also making that assumption.
12//!
13//! See the individual functions' safety comments for more details.
14#![allow(unsafe_code)]
15
16use crate::backend;
17use crate::fd::OwnedFd;
18use backend::c;
19use backend::fd::{BorrowedFd, FromRawFd as _, RawFd};
20
21#[cfg(not(any(windows, target_os = "wasi")))]
22use {
23 crate::io,
24 backend::fd::{AsFd, AsRawFd as _},
25 core::mem::ManuallyDrop,
26};
27
28/// `STDIN_FILENO`—Standard input, borrowed.
29///
30/// In `std`-using configurations, this is a safe function, because the
31/// standard library already assumes that the stdin file descriptor is always
32/// valid. In `no_std` configurations, it is `unsafe`.
33///
34/// # Warning
35///
36/// This function allows reading directly from stdin without coordinating
37/// with the buffering performed by [`std::io::Stdin`], so it could cause
38/// corrupted input.
39///
40/// # References
41/// - [POSIX]
42/// - [Linux]
43/// - [FreeBSD]
44/// - [NetBSD]
45/// - [OpenBSD]
46/// - [DragonFly BSD]
47/// - [illumos]
48/// - [glibc]
49///
50/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/stdin.html
51/// [Linux]: https://man7.org/linux/man-pages/man3/stdin.3.html
52/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=stdin&sektion=4
53/// [NetBSD]: https://man.netbsd.org/stdin.4
54/// [OpenBSD]: https://man.openbsd.org/stdin.4
55/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=stdin&section=4
56/// [illumos]: https://illumos.org/man/4FS/stdin
57/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Standard-Streams.html#index-stdin
58#[cfg(feature = "std")]
59#[doc(alias = "STDIN_FILENO")]
60#[inline]
61pub const fn stdin() -> BorrowedFd<'static> {
62 // SAFETY: When "std" is enabled, the standard library assumes that the
63 // stdio file descriptors are all valid.
64 unsafe { BorrowedFd::borrow_raw(fd:c::STDIN_FILENO as RawFd) }
65}
66
67/// `STDIN_FILENO`—Standard input, borrowed.
68///
69/// In `std`-using configurations, this is a safe function, because the
70/// standard library already assumes that the stdin file descriptor is always
71/// valid. In `no_std` configurations, it is `unsafe`.
72///
73/// # Safety
74///
75/// In `no_std` configurations, the process' stdin file descriptor can be
76/// closed, potentially on other threads, in which case the file descriptor
77/// index number (`STDIN_FILENO`) could be dynamically reused for other
78/// purposes, potentially on different threads.
79///
80/// # Warning
81///
82/// This function allows reading directly from stdin without coordinating
83/// with the buffering performed by [`std::io::Stdin`], so it could cause
84/// corrupted input.
85///
86/// # References
87/// - [POSIX]
88/// - [Linux]
89/// - [FreeBSD]
90/// - [NetBSD]
91/// - [OpenBSD]
92/// - [DragonFly BSD]
93/// - [illumos]
94/// - [glibc]
95///
96/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/stdin.html
97/// [Linux]: https://man7.org/linux/man-pages/man3/stdin.3.html
98/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=stdin&sektion=4
99/// [NetBSD]: https://man.netbsd.org/stdin.4
100/// [OpenBSD]: https://man.openbsd.org/stdin.4
101/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=stdin&section=4
102/// [illumos]: https://illumos.org/man/4FS/stdin
103/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Standard-Streams.html#index-stdin
104#[cfg(not(feature = "std"))]
105#[doc(alias = "STDIN_FILENO")]
106#[inline]
107pub const unsafe fn stdin() -> BorrowedFd<'static> {
108 BorrowedFd::borrow_raw(c::STDIN_FILENO as RawFd)
109}
110
111/// `STDIN_FILENO`—Standard input, owned.
112///
113/// This is similar to [`stdin`], however it returns an `OwnedFd` which closes
114/// standard input when it is dropped.
115///
116/// # Safety
117///
118/// Safe `std`-using Rust code is permitted to assume that the stdin file
119/// descriptor is always valid. This function returns an `OwnedFd` which will
120/// close the stdin file descriptor when dropped.
121///
122/// # Warning
123///
124/// This has the same hazards as [`stdin`].
125///
126/// # References
127/// - [POSIX]
128/// - [Linux]
129/// - [FreeBSD]
130/// - [NetBSD]
131/// - [OpenBSD]
132/// - [DragonFly BSD]
133/// - [illumos]
134/// - [glibc]
135///
136/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/stdin.html
137/// [Linux]: https://man7.org/linux/man-pages/man3/stdin.3.html
138/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=stdin&sektion=4
139/// [NetBSD]: https://man.netbsd.org/stdin.4
140/// [OpenBSD]: https://man.openbsd.org/stdin.4
141/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=stdin&section=4
142/// [illumos]: https://illumos.org/man/4FS/stdin
143/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Standard-Streams.html#index-stdin
144#[doc(alias = "STDIN_FILENO")]
145#[inline]
146pub unsafe fn take_stdin() -> OwnedFd {
147 backend::fd::OwnedFd::from_raw_fd(c::STDIN_FILENO as RawFd)
148}
149
150/// `STDOUT_FILENO`—Standard output, borrowed.
151///
152/// In `std`-using configurations, this is a safe function, because the
153/// standard library already assumes that the stdout file descriptor is always
154/// valid. In `no_std` configurations, it is `unsafe`.
155///
156/// # Warning
157///
158/// This function allows writing directly to stdout without coordinating
159/// with the buffering performed by [`std::io::Stdout`], so it could cause
160/// corrupted output.
161///
162/// # References
163/// - [POSIX]
164/// - [Linux]
165/// - [FreeBSD]
166/// - [NetBSD]
167/// - [OpenBSD]
168/// - [DragonFly BSD]
169/// - [illumos]
170/// - [glibc]
171///
172/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/stdout.html
173/// [Linux]: https://man7.org/linux/man-pages/man3/stdout.3.html
174/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=stdout&sektion=4
175/// [NetBSD]: https://man.netbsd.org/stdout.4
176/// [OpenBSD]: https://man.openbsd.org/stdout.4
177/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=stdout&section=4
178/// [illumos]: https://illumos.org/man/4FS/stdout
179/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Standard-Streams.html#index-stdout
180#[cfg(feature = "std")]
181#[doc(alias = "STDOUT_FILENO")]
182#[inline]
183pub const fn stdout() -> BorrowedFd<'static> {
184 // SAFETY: When "std" is enabled, the standard library assumes that the
185 // stdio file descriptors are all valid.
186 unsafe { BorrowedFd::borrow_raw(fd:c::STDOUT_FILENO as RawFd) }
187}
188
189/// `STDOUT_FILENO`—Standard output, borrowed.
190///
191/// In `std`-using configurations, this is a safe function, because the
192/// standard library already assumes that the stdout file descriptor is always
193/// valid. In `no_std` configurations, it is `unsafe`.
194///
195/// # Safety
196///
197/// In `no_std` configurations, the process' stdout file descriptor can be
198/// closed, potentially on other threads, in which case the file descriptor
199/// index number (`STDOUT_FILENO`) could be dynamically reused for other
200/// purposes, potentially on different threads.
201///
202/// # Warning
203///
204/// This function allows writing directly to stdout without coordinating
205/// with the buffering performed by [`std::io::Stdout`], so it could cause
206/// corrupted output.
207///
208/// # References
209/// - [POSIX]
210/// - [Linux]
211/// - [FreeBSD]
212/// - [NetBSD]
213/// - [OpenBSD]
214/// - [DragonFly BSD]
215/// - [illumos]
216/// - [glibc]
217///
218/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/stdout.html
219/// [Linux]: https://man7.org/linux/man-pages/man3/stdout.3.html
220/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=stdout&sektion=4
221/// [NetBSD]: https://man.netbsd.org/stdout.4
222/// [OpenBSD]: https://man.openbsd.org/stdout.4
223/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=stdout&section=4
224/// [illumos]: https://illumos.org/man/4FS/stdout
225/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Standard-Streams.html#index-stdout
226#[cfg(not(feature = "std"))]
227#[doc(alias = "STDOUT_FILENO")]
228#[inline]
229pub const unsafe fn stdout() -> BorrowedFd<'static> {
230 BorrowedFd::borrow_raw(c::STDOUT_FILENO as RawFd)
231}
232
233/// `STDOUT_FILENO`—Standard output, owned.
234///
235/// This is similar to [`stdout`], however it returns an `OwnedFd` which closes
236/// standard output when it is dropped.
237///
238/// # Safety
239///
240/// Safe `std`-using Rust code is permitted to assume that the stdout file
241/// descriptor is always valid. This function returns an `OwnedFd` which will
242/// close the stdout file descriptor when dropped.
243///
244/// # Warning
245///
246/// This has the same hazards as [`stdout`].
247///
248/// # References
249/// - [POSIX]
250/// - [Linux]
251/// - [FreeBSD]
252/// - [NetBSD]
253/// - [OpenBSD]
254/// - [DragonFly BSD]
255/// - [illumos]
256/// - [glibc]
257///
258/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/stdout.html
259/// [Linux]: https://man7.org/linux/man-pages/man3/stdout.3.html
260/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=stdout&sektion=4
261/// [NetBSD]: https://man.netbsd.org/stdout.4
262/// [OpenBSD]: https://man.openbsd.org/stdout.4
263/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=stdout&section=4
264/// [illumos]: https://illumos.org/man/4FS/stdout
265/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Standard-Streams.html#index-stdout
266#[doc(alias = "STDOUT_FILENO")]
267#[inline]
268pub unsafe fn take_stdout() -> OwnedFd {
269 backend::fd::OwnedFd::from_raw_fd(c::STDOUT_FILENO as RawFd)
270}
271
272/// `STDERR_FILENO`—Standard error, borrowed.
273///
274/// In `std`-using configurations, this is a safe function, because the
275/// standard library already assumes that the stderr file descriptor is always
276/// valid. In `no_std` configurations, it is `unsafe`.
277///
278/// # References
279/// - [POSIX]
280/// - [Linux]
281/// - [FreeBSD]
282/// - [NetBSD]
283/// - [OpenBSD]
284/// - [DragonFly BSD]
285/// - [illumos]
286/// - [glibc]
287///
288/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/stderr.html
289/// [Linux]: https://man7.org/linux/man-pages/man3/stderr.3.html
290/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=stderr&sektion=4
291/// [NetBSD]: https://man.netbsd.org/stderr.4
292/// [OpenBSD]: https://man.openbsd.org/stderr.4
293/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=stderr&section=4
294/// [illumos]: https://illumos.org/man/4FS/stderr
295/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Standard-Streams.html#index-stderr
296#[cfg(feature = "std")]
297#[doc(alias = "STDERR_FILENO")]
298#[inline]
299pub const fn stderr() -> BorrowedFd<'static> {
300 // SAFETY: When "std" is enabled, the standard library assumes that the
301 // stdio file descriptors are all valid.
302 unsafe { BorrowedFd::borrow_raw(fd:c::STDERR_FILENO as RawFd) }
303}
304
305/// `STDERR_FILENO`—Standard error, borrowed.
306///
307/// In `std`-using configurations, this is a safe function, because the
308/// standard library already assumes that the stderr file descriptor is always
309/// valid. In `no_std` configurations, it is `unsafe`.
310///
311/// # Safety
312///
313/// In `no_std` configurations, the process' stderr file descriptor can be
314/// closed, potentially on other threads, in which case the file descriptor
315/// index number (`STDERR_FILENO`) could be dynamically reused for other
316/// purposes, potentially on different threads.
317///
318/// # References
319/// - [POSIX]
320/// - [Linux]
321/// - [FreeBSD]
322/// - [NetBSD]
323/// - [OpenBSD]
324/// - [DragonFly BSD]
325/// - [illumos]
326/// - [glibc]
327///
328/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/stderr.html
329/// [Linux]: https://man7.org/linux/man-pages/man3/stderr.3.html
330/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=stderr&sektion=4
331/// [NetBSD]: https://man.netbsd.org/stderr.4
332/// [OpenBSD]: https://man.openbsd.org/stderr.4
333/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=stderr&section=4
334/// [illumos]: https://illumos.org/man/4FS/stderr
335/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Standard-Streams.html#index-stderr
336#[cfg(not(feature = "std"))]
337#[doc(alias = "STDERR_FILENO")]
338#[inline]
339pub const unsafe fn stderr() -> BorrowedFd<'static> {
340 BorrowedFd::borrow_raw(c::STDERR_FILENO as RawFd)
341}
342
343/// `STDERR_FILENO`—Standard error, owned.
344///
345/// This is similar to [`stderr`], however it returns an `OwnedFd` which closes
346/// standard output when it is dropped.
347///
348/// # Safety
349///
350/// Safe std-using Rust code is permitted to assume that the stderr file
351/// descriptor is always valid. This function returns an `OwnedFd` which will
352/// close the stderr file descriptor when dropped.
353///
354/// # Other hazards
355///
356/// This has the same hazards as [`stderr`].
357///
358/// And, when the `OwnedFd` is dropped, subsequent newly created file
359/// descriptors may unknowingly reuse the stderr file descriptor number, which
360/// may break common assumptions, so it should typically only be dropped at the
361/// end of a program when no more file descriptors will be created.
362///
363/// # References
364/// - [POSIX]
365/// - [Linux]
366/// - [FreeBSD]
367/// - [NetBSD]
368/// - [OpenBSD]
369/// - [DragonFly BSD]
370/// - [illumos]
371/// - [glibc]
372///
373/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/stderr.html
374/// [Linux]: https://man7.org/linux/man-pages/man3/stderr.3.html
375/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=stderr&sektion=4
376/// [NetBSD]: https://man.netbsd.org/stderr.4
377/// [OpenBSD]: https://man.openbsd.org/stderr.4
378/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=stderr&section=4
379/// [illumos]: https://illumos.org/man/4FS/stderr
380/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Standard-Streams.html#index-stderr
381#[doc(alias = "STDERR_FILENO")]
382#[inline]
383pub unsafe fn take_stderr() -> OwnedFd {
384 backend::fd::OwnedFd::from_raw_fd(c::STDERR_FILENO as RawFd)
385}
386
387/// `STDIN_FILENO`—Standard input, raw.
388///
389/// This is similar to [`stdin`], however it returns a `RawFd`.
390///
391/// # Other hazards
392///
393/// This has the same hazards as [`stdin`].
394///
395/// # References
396/// - [POSIX]
397/// - [Linux]
398/// - [FreeBSD]
399/// - [NetBSD]
400/// - [OpenBSD]
401/// - [DragonFly BSD]
402/// - [illumos]
403/// - [glibc]
404///
405/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/stdin.html
406/// [Linux]: https://man7.org/linux/man-pages/man3/stdin.3.html
407/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=stdin&sektion=4
408/// [NetBSD]: https://man.netbsd.org/stdin.4
409/// [OpenBSD]: https://man.openbsd.org/stdin.4
410/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=stdin&section=4
411/// [illumos]: https://illumos.org/man/4FS/stdin
412/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Standard-Streams.html#index-stdin
413#[doc(alias = "STDIN_FILENO")]
414#[inline]
415pub const fn raw_stdin() -> RawFd {
416 c::STDIN_FILENO as RawFd
417}
418
419/// `STDOUT_FILENO`—Standard output, raw.
420///
421/// This is similar to [`stdout`], however it returns a `RawFd`.
422///
423/// # Other hazards
424///
425/// This has the same hazards as [`stdout`].
426///
427/// # References
428/// - [POSIX]
429/// - [Linux]
430/// - [FreeBSD]
431/// - [NetBSD]
432/// - [OpenBSD]
433/// - [DragonFly BSD]
434/// - [illumos]
435/// - [glibc]
436///
437/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/stdout.html
438/// [Linux]: https://man7.org/linux/man-pages/man3/stdout.3.html
439/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=stdout&sektion=4
440/// [NetBSD]: https://man.netbsd.org/stdout.4
441/// [OpenBSD]: https://man.openbsd.org/stdout.4
442/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=stdout&section=4
443/// [illumos]: https://illumos.org/man/4FS/stdout
444/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Standard-Streams.html#index-stdout
445#[doc(alias = "STDOUT_FILENO")]
446#[inline]
447pub const fn raw_stdout() -> RawFd {
448 c::STDOUT_FILENO as RawFd
449}
450
451/// `STDERR_FILENO`—Standard error, raw.
452///
453/// This is similar to [`stderr`], however it returns a `RawFd`.
454///
455/// # Other hazards
456///
457/// This has the same hazards as [`stderr`].
458///
459/// # References
460/// - [POSIX]
461/// - [Linux]
462/// - [FreeBSD]
463/// - [NetBSD]
464/// - [OpenBSD]
465/// - [DragonFly BSD]
466/// - [illumos]
467/// - [glibc]
468///
469/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/stderr.html
470/// [Linux]: https://man7.org/linux/man-pages/man3/stderr.3.html
471/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=stderr&sektion=4
472/// [NetBSD]: https://man.netbsd.org/stderr.4
473/// [OpenBSD]: https://man.openbsd.org/stderr.4
474/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=stderr&section=4
475/// [illumos]: https://illumos.org/man/4FS/stderr
476/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Standard-Streams.html#index-stderr
477#[doc(alias = "STDERR_FILENO")]
478#[inline]
479pub const fn raw_stderr() -> RawFd {
480 c::STDERR_FILENO as RawFd
481}
482
483/// Utility function to safely `dup2` over stdin (fd 0).
484#[cfg(not(any(windows, target_os = "wasi")))]
485#[inline]
486pub fn dup2_stdin<Fd: AsFd>(fd: Fd) -> io::Result<()> {
487 let fd: BorrowedFd<'_> = fd.as_fd();
488 if fd.as_raw_fd() != c::STDIN_FILENO {
489 // SAFETY: We wrap the returned `OwnedFd` to `ManuallyDrop` so that it
490 // isn't dropped.
491 let mut target: ManuallyDrop = ManuallyDrop::new(unsafe { take_stdin() });
492 backend::io::syscalls::dup2(fd, &mut target)?;
493 }
494 Ok(())
495}
496
497/// Utility function to safely `dup2` over stdout (fd 1).
498#[cfg(not(any(windows, target_os = "wasi")))]
499#[inline]
500pub fn dup2_stdout<Fd: AsFd>(fd: Fd) -> io::Result<()> {
501 let fd: BorrowedFd<'_> = fd.as_fd();
502 if fd.as_raw_fd() != c::STDOUT_FILENO {
503 // SAFETY: We wrap the returned `OwnedFd` to `ManuallyDrop` so that it
504 // isn't dropped.
505 let mut target: ManuallyDrop = ManuallyDrop::new(unsafe { take_stdout() });
506 backend::io::syscalls::dup2(fd, &mut target)?;
507 }
508 Ok(())
509}
510
511/// Utility function to safely `dup2` over stderr (fd 2).
512#[cfg(not(any(windows, target_os = "wasi")))]
513#[inline]
514pub fn dup2_stderr<Fd: AsFd>(fd: Fd) -> io::Result<()> {
515 let fd: BorrowedFd<'_> = fd.as_fd();
516 if fd.as_raw_fd() != c::STDERR_FILENO {
517 // SAFETY: We wrap the returned `OwnedFd` to `ManuallyDrop` so that it
518 // isn't dropped.
519 let mut target: ManuallyDrop = ManuallyDrop::new(unsafe { take_stderr() });
520 backend::io::syscalls::dup2(fd, &mut target)?;
521 }
522 Ok(())
523}
524