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