nix/sys/
termios.rs

1//! An interface for controlling asynchronous communication ports
2//!
3//! This interface provides a safe wrapper around the termios subsystem defined by POSIX. The
4//! underlying types are all implemented in libc for most platforms and either wrapped in safer
5//! types here or exported directly.
6//!
7//! If you are unfamiliar with the `termios` API, you should first read the
8//! [API documentation](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/termios.h.html) and
9//! then come back to understand how `nix` safely wraps it.
10//!
11//! It should be noted that this API incurs some runtime overhead above the base `libc` definitions.
12//! As this interface is not used with high-bandwidth information, this should be fine in most
13//! cases. The primary cost when using this API is that the `Termios` datatype here duplicates the
14//! standard fields of the underlying `termios` struct and uses safe type wrappers for those fields.
15//! This means that when crossing the FFI interface to the underlying C library, data is first
16//! copied into the underlying `termios` struct, then the operation is done, and the data is copied
17//! back (with additional sanity checking) into the safe wrapper types. The `termios` struct is
18//! relatively small across all platforms (on the order of 32-64 bytes).
19//!
20//! The following examples highlight some of the API use cases such that users coming from using C
21//! or reading the standard documentation will understand how to use the safe API exposed here.
22//!
23//! Example disabling processing of the end-of-file control character:
24//!
25//! ```
26//! # use self::nix::sys::termios::SpecialCharacterIndices::VEOF;
27//! # use self::nix::sys::termios::{_POSIX_VDISABLE, Termios};
28//! # let mut termios: Termios = unsafe { std::mem::zeroed() };
29//! termios.control_chars[VEOF as usize] = _POSIX_VDISABLE;
30//! ```
31//!
32//! The flags within `Termios` are defined as bitfields using the `bitflags` crate. This provides
33//! an interface for working with bitfields that is similar to working with the raw unsigned
34//! integer types but offers type safety because of the internal checking that values will always
35//! be a valid combination of the defined flags.
36//!
37//! An example showing some of the basic operations for interacting with the control flags:
38//!
39//! ```
40//! # use self::nix::sys::termios::{ControlFlags, Termios};
41//! # let mut termios: Termios = unsafe { std::mem::zeroed() };
42//! termios.control_flags & ControlFlags::CSIZE == ControlFlags::CS5;
43//! termios.control_flags |= ControlFlags::CS5;
44//! ```
45//!
46//! # Baud rates
47//!
48//! This API is not consistent across platforms when it comes to `BaudRate`: Android and Linux both
49//! only support the rates specified by the `BaudRate` enum through their termios API while the BSDs
50//! support arbitrary baud rates as the values of the `BaudRate` enum constants are the same integer
51//! value of the constant (`B9600` == `9600`). Therefore the `nix::termios` API uses the following
52//! conventions:
53//!
54//! * `cfgetispeed()` - Returns `u32` on BSDs, `BaudRate` on Android/Linux
55//! * `cfgetospeed()` - Returns `u32` on BSDs, `BaudRate` on Android/Linux
56//! * `cfsetispeed()` - Takes `u32` or `BaudRate` on BSDs, `BaudRate` on Android/Linux
57//! * `cfsetospeed()` - Takes `u32` or `BaudRate` on BSDs, `BaudRate` on Android/Linux
58//! * `cfsetspeed()` - Takes `u32` or `BaudRate` on BSDs, `BaudRate` on Android/Linux
59//!
60//! The most common use case of specifying a baud rate using the enum will work the same across
61//! platforms:
62//!
63//! ```rust
64//! # use nix::sys::termios::{BaudRate, cfsetispeed, cfsetospeed, cfsetspeed, Termios};
65//! # fn main() {
66//! # let mut t: Termios = unsafe { std::mem::zeroed() };
67//! cfsetispeed(&mut t, BaudRate::B9600).unwrap();
68//! cfsetospeed(&mut t, BaudRate::B9600).unwrap();
69//! cfsetspeed(&mut t, BaudRate::B9600).unwrap();
70//! # }
71//! ```
72//!
73//! Additionally round-tripping baud rates is consistent across platforms:
74//!
75//! ```rust
76//! # use nix::sys::termios::{BaudRate, cfgetispeed, cfgetospeed, cfsetispeed, cfsetspeed, Termios};
77//! # fn main() {
78//! # let mut t: Termios = unsafe { std::mem::zeroed() };
79//! # cfsetspeed(&mut t, BaudRate::B9600).unwrap();
80//! let speed = cfgetispeed(&t);
81//! assert_eq!(speed, cfgetospeed(&t));
82//! cfsetispeed(&mut t, speed).unwrap();
83//! # }
84//! ```
85//!
86//! On non-BSDs, `cfgetispeed()` and `cfgetospeed()` both return a `BaudRate`:
87//!
88#![cfg_attr(
89    any(
90        target_os = "freebsd",
91        target_os = "dragonfly",
92        target_os = "ios",
93        target_os = "macos",
94        target_os = "netbsd",
95        target_os = "openbsd"
96    ),
97    doc = " ```rust,ignore"
98)]
99#![cfg_attr(
100    not(any(
101        target_os = "freebsd",
102        target_os = "dragonfly",
103        target_os = "ios",
104        target_os = "macos",
105        target_os = "netbsd",
106        target_os = "openbsd"
107    )),
108    doc = " ```rust"
109)]
110//! # use nix::sys::termios::{BaudRate, cfgetispeed, cfgetospeed, cfsetspeed, Termios};
111//! # fn main() {
112//! # let mut t: Termios = unsafe { std::mem::zeroed() };
113//! # cfsetspeed(&mut t, BaudRate::B9600);
114//! assert_eq!(cfgetispeed(&t), BaudRate::B9600);
115//! assert_eq!(cfgetospeed(&t), BaudRate::B9600);
116//! # }
117//! ```
118//!
119//! But on the BSDs, `cfgetispeed()` and `cfgetospeed()` both return `u32`s:
120//!
121#![cfg_attr(
122    any(
123        target_os = "freebsd",
124        target_os = "dragonfly",
125        target_os = "ios",
126        target_os = "macos",
127        target_os = "netbsd",
128        target_os = "openbsd"
129    ),
130    doc = " ```rust"
131)]
132#![cfg_attr(
133    not(any(
134        target_os = "freebsd",
135        target_os = "dragonfly",
136        target_os = "ios",
137        target_os = "macos",
138        target_os = "netbsd",
139        target_os = "openbsd"
140    )),
141    doc = " ```rust,ignore"
142)]
143//! # use nix::sys::termios::{BaudRate, cfgetispeed, cfgetospeed, cfsetspeed, Termios};
144//! # fn main() {
145//! # let mut t: Termios = unsafe { std::mem::zeroed() };
146//! # cfsetspeed(&mut t, 9600u32);
147//! assert_eq!(cfgetispeed(&t), 9600u32);
148//! assert_eq!(cfgetospeed(&t), 9600u32);
149//! # }
150//! ```
151//!
152//! It's trivial to convert from a `BaudRate` to a `u32` on BSDs:
153//!
154#![cfg_attr(
155    any(
156        target_os = "freebsd",
157        target_os = "dragonfly",
158        target_os = "ios",
159        target_os = "macos",
160        target_os = "netbsd",
161        target_os = "openbsd"
162    ),
163    doc = " ```rust"
164)]
165#![cfg_attr(
166    not(any(
167        target_os = "freebsd",
168        target_os = "dragonfly",
169        target_os = "ios",
170        target_os = "macos",
171        target_os = "netbsd",
172        target_os = "openbsd"
173    )),
174    doc = " ```rust,ignore"
175)]
176//! # use nix::sys::termios::{BaudRate, cfgetispeed, cfsetspeed, Termios};
177//! # fn main() {
178//! # let mut t: Termios = unsafe { std::mem::zeroed() };
179//! # cfsetspeed(&mut t, 9600u32);
180//! assert_eq!(cfgetispeed(&t), BaudRate::B9600.into());
181//! assert_eq!(u32::from(BaudRate::B9600), 9600u32);
182//! # }
183//! ```
184//!
185//! And on BSDs you can specify arbitrary baud rates (**note** this depends on hardware support)
186//! by specifying baud rates directly using `u32`s:
187//!
188#![cfg_attr(
189    any(
190        target_os = "freebsd",
191        target_os = "dragonfly",
192        target_os = "ios",
193        target_os = "macos",
194        target_os = "netbsd",
195        target_os = "openbsd"
196    ),
197    doc = " ```rust"
198)]
199#![cfg_attr(
200    not(any(
201        target_os = "freebsd",
202        target_os = "dragonfly",
203        target_os = "ios",
204        target_os = "macos",
205        target_os = "netbsd",
206        target_os = "openbsd"
207    )),
208    doc = " ```rust,ignore"
209)]
210//! # use nix::sys::termios::{cfsetispeed, cfsetospeed, cfsetspeed, Termios};
211//! # fn main() {
212//! # let mut t: Termios = unsafe { std::mem::zeroed() };
213//! cfsetispeed(&mut t, 9600u32);
214//! cfsetospeed(&mut t, 9600u32);
215//! cfsetspeed(&mut t, 9600u32);
216//! # }
217//! ```
218use crate::errno::Errno;
219use crate::Result;
220use cfg_if::cfg_if;
221use libc::{self, c_int, tcflag_t};
222use std::cell::{Ref, RefCell};
223use std::convert::From;
224use std::mem;
225use std::os::unix::io::RawFd;
226
227#[cfg(feature = "process")]
228use crate::unistd::Pid;
229
230/// Stores settings for the termios API
231///
232/// This is a wrapper around the `libc::termios` struct that provides a safe interface for the
233/// standard fields. The only safe way to obtain an instance of this struct is to extract it from
234/// an open port using `tcgetattr()`.
235#[derive(Clone, Debug, Eq, PartialEq)]
236pub struct Termios {
237    inner: RefCell<libc::termios>,
238    /// Input mode flags (see `termios.c_iflag` documentation)
239    pub input_flags: InputFlags,
240    /// Output mode flags (see `termios.c_oflag` documentation)
241    pub output_flags: OutputFlags,
242    /// Control mode flags (see `termios.c_cflag` documentation)
243    pub control_flags: ControlFlags,
244    /// Local mode flags (see `termios.c_lflag` documentation)
245    pub local_flags: LocalFlags,
246    /// Control characters (see `termios.c_cc` documentation)
247    pub control_chars: [libc::cc_t; NCCS],
248    /// Line discipline (see `termios.c_line` documentation)
249    #[cfg(any(target_os = "linux", target_os = "android",))]
250    pub line_discipline: libc::cc_t,
251    /// Line discipline (see `termios.c_line` documentation)
252    #[cfg(target_os = "haiku")]
253    pub line_discipline: libc::c_char,
254}
255
256impl Termios {
257    /// Exposes an immutable reference to the underlying `libc::termios` data structure.
258    ///
259    /// This is not part of `nix`'s public API because it requires additional work to maintain type
260    /// safety.
261    pub(crate) fn get_libc_termios(&self) -> Ref<libc::termios> {
262        {
263            let mut termios = self.inner.borrow_mut();
264            termios.c_iflag = self.input_flags.bits();
265            termios.c_oflag = self.output_flags.bits();
266            termios.c_cflag = self.control_flags.bits();
267            termios.c_lflag = self.local_flags.bits();
268            termios.c_cc = self.control_chars;
269            #[cfg(any(
270                target_os = "linux",
271                target_os = "android",
272                target_os = "haiku",
273            ))]
274            {
275                termios.c_line = self.line_discipline;
276            }
277        }
278        self.inner.borrow()
279    }
280
281    /// Exposes the inner `libc::termios` datastore within `Termios`.
282    ///
283    /// This is unsafe because if this is used to modify the inner `libc::termios` struct, it will
284    /// not automatically update the safe wrapper type around it. In this case it should also be
285    /// paired with a call to `update_wrapper()` so that the wrapper-type and internal
286    /// representation stay consistent.
287    pub(crate) unsafe fn get_libc_termios_mut(&mut self) -> *mut libc::termios {
288        {
289            let mut termios = self.inner.borrow_mut();
290            termios.c_iflag = self.input_flags.bits();
291            termios.c_oflag = self.output_flags.bits();
292            termios.c_cflag = self.control_flags.bits();
293            termios.c_lflag = self.local_flags.bits();
294            termios.c_cc = self.control_chars;
295            #[cfg(any(
296                target_os = "linux",
297                target_os = "android",
298                target_os = "haiku",
299            ))]
300            {
301                termios.c_line = self.line_discipline;
302            }
303        }
304        self.inner.as_ptr()
305    }
306
307    /// Updates the wrapper values from the internal `libc::termios` data structure.
308    pub(crate) fn update_wrapper(&mut self) {
309        let termios = *self.inner.borrow_mut();
310        self.input_flags = InputFlags::from_bits_truncate(termios.c_iflag);
311        self.output_flags = OutputFlags::from_bits_truncate(termios.c_oflag);
312        self.control_flags = ControlFlags::from_bits_truncate(termios.c_cflag);
313        self.local_flags = LocalFlags::from_bits_truncate(termios.c_lflag);
314        self.control_chars = termios.c_cc;
315        #[cfg(any(
316            target_os = "linux",
317            target_os = "android",
318            target_os = "haiku",
319        ))]
320        {
321            self.line_discipline = termios.c_line;
322        }
323    }
324}
325
326impl From<libc::termios> for Termios {
327    fn from(termios: libc::termios) -> Self {
328        Termios {
329            inner: RefCell::new(termios),
330            input_flags: InputFlags::from_bits_truncate(termios.c_iflag),
331            output_flags: OutputFlags::from_bits_truncate(termios.c_oflag),
332            control_flags: ControlFlags::from_bits_truncate(termios.c_cflag),
333            local_flags: LocalFlags::from_bits_truncate(termios.c_lflag),
334            control_chars: termios.c_cc,
335            #[cfg(any(
336                target_os = "linux",
337                target_os = "android",
338                target_os = "haiku",
339            ))]
340            line_discipline: termios.c_line,
341        }
342    }
343}
344
345impl From<Termios> for libc::termios {
346    fn from(termios: Termios) -> Self {
347        termios.inner.into_inner()
348    }
349}
350
351libc_enum! {
352    /// Baud rates supported by the system.
353    ///
354    /// For the BSDs, arbitrary baud rates can be specified by using `u32`s directly instead of this
355    /// enum.
356    ///
357    /// B0 is special and will disable the port.
358    #[cfg_attr(all(any(target_os = "haiku"), target_pointer_width = "64"), repr(u8))]
359    #[cfg_attr(all(any(target_os = "ios", target_os = "macos"), target_pointer_width = "64"), repr(u64))]
360    #[cfg_attr(not(all(any(target_os = "ios", target_os = "macos", target_os = "haiku"), target_pointer_width = "64")), repr(u32))]
361    #[non_exhaustive]
362    pub enum BaudRate {
363        B0,
364        B50,
365        B75,
366        B110,
367        B134,
368        B150,
369        B200,
370        B300,
371        B600,
372        B1200,
373        B1800,
374        B2400,
375        B4800,
376        #[cfg(any(target_os = "dragonfly",
377                target_os = "freebsd",
378                target_os = "macos",
379                target_os = "netbsd",
380                target_os = "openbsd"))]
381        #[cfg_attr(docsrs, doc(cfg(all())))]
382        B7200,
383        B9600,
384        #[cfg(any(target_os = "dragonfly",
385                target_os = "freebsd",
386                target_os = "macos",
387                target_os = "netbsd",
388                target_os = "openbsd"))]
389        #[cfg_attr(docsrs, doc(cfg(all())))]
390        B14400,
391        B19200,
392        #[cfg(any(target_os = "dragonfly",
393                target_os = "freebsd",
394                target_os = "macos",
395                target_os = "netbsd",
396                target_os = "openbsd"))]
397        #[cfg_attr(docsrs, doc(cfg(all())))]
398        B28800,
399        B38400,
400        B57600,
401        #[cfg(any(target_os = "dragonfly",
402                target_os = "freebsd",
403                target_os = "macos",
404                target_os = "netbsd",
405                target_os = "openbsd"))]
406        #[cfg_attr(docsrs, doc(cfg(all())))]
407        B76800,
408        B115200,
409        #[cfg(any(target_os = "illumos", target_os = "solaris"))]
410        #[cfg_attr(docsrs, doc(cfg(all())))]
411        B153600,
412        B230400,
413        #[cfg(any(target_os = "illumos", target_os = "solaris"))]
414        #[cfg_attr(docsrs, doc(cfg(all())))]
415        B307200,
416        #[cfg(any(target_os = "android",
417                  target_os = "freebsd",
418                  target_os = "illumos",
419                  target_os = "linux",
420                  target_os = "netbsd",
421                  target_os = "solaris"))]
422        #[cfg_attr(docsrs, doc(cfg(all())))]
423        B460800,
424        #[cfg(any(target_os = "android", target_os = "linux"))]
425        #[cfg_attr(docsrs, doc(cfg(all())))]
426        B500000,
427        #[cfg(any(target_os = "android", target_os = "linux"))]
428        #[cfg_attr(docsrs, doc(cfg(all())))]
429        B576000,
430        #[cfg(any(target_os = "android",
431                  target_os = "freebsd",
432                  target_os = "illumos",
433                  target_os = "linux",
434                  target_os = "netbsd",
435                  target_os = "solaris"))]
436        #[cfg_attr(docsrs, doc(cfg(all())))]
437        B921600,
438        #[cfg(any(target_os = "android", target_os = "linux"))]
439        #[cfg_attr(docsrs, doc(cfg(all())))]
440        B1000000,
441        #[cfg(any(target_os = "android", target_os = "linux"))]
442        #[cfg_attr(docsrs, doc(cfg(all())))]
443        B1152000,
444        #[cfg(any(target_os = "android", target_os = "linux"))]
445        #[cfg_attr(docsrs, doc(cfg(all())))]
446        B1500000,
447        #[cfg(any(target_os = "android", target_os = "linux"))]
448        #[cfg_attr(docsrs, doc(cfg(all())))]
449        B2000000,
450        #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
451        #[cfg_attr(docsrs, doc(cfg(all())))]
452        B2500000,
453        #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
454        #[cfg_attr(docsrs, doc(cfg(all())))]
455        B3000000,
456        #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
457        #[cfg_attr(docsrs, doc(cfg(all())))]
458        B3500000,
459        #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
460        #[cfg_attr(docsrs, doc(cfg(all())))]
461        B4000000,
462    }
463    impl TryFrom<libc::speed_t>
464}
465
466#[cfg(any(
467    target_os = "freebsd",
468    target_os = "dragonfly",
469    target_os = "ios",
470    target_os = "macos",
471    target_os = "netbsd",
472    target_os = "openbsd"
473))]
474impl From<BaudRate> for u32 {
475    fn from(b: BaudRate) -> u32 {
476        b as u32
477    }
478}
479
480#[cfg(target_os = "haiku")]
481impl From<BaudRate> for u8 {
482    fn from(b: BaudRate) -> u8 {
483        b as u8
484    }
485}
486
487// TODO: Add TCSASOFT, which will require treating this as a bitfield.
488libc_enum! {
489    /// Specify when a port configuration change should occur.
490    ///
491    /// Used as an argument to `tcsetattr()`
492    #[repr(i32)]
493    #[non_exhaustive]
494    pub enum SetArg {
495        /// The change will occur immediately
496        TCSANOW,
497        /// The change occurs after all output has been written
498        TCSADRAIN,
499        /// Same as `TCSADRAIN`, but will also flush the input buffer
500        TCSAFLUSH,
501    }
502}
503
504libc_enum! {
505    /// Specify a combination of the input and output buffers to flush
506    ///
507    /// Used as an argument to `tcflush()`.
508    #[repr(i32)]
509    #[non_exhaustive]
510    pub enum FlushArg {
511        /// Flush data that was received but not read
512        TCIFLUSH,
513        /// Flush data written but not transmitted
514        TCOFLUSH,
515        /// Flush both received data not read and written data not transmitted
516        TCIOFLUSH,
517    }
518}
519
520libc_enum! {
521    /// Specify how transmission flow should be altered
522    ///
523    /// Used as an argument to `tcflow()`.
524    #[repr(i32)]
525    #[non_exhaustive]
526    pub enum FlowArg {
527        /// Suspend transmission
528        TCOOFF,
529        /// Resume transmission
530        TCOON,
531        /// Transmit a STOP character, which should disable a connected terminal device
532        TCIOFF,
533        /// Transmit a START character, which should re-enable a connected terminal device
534        TCION,
535    }
536}
537
538// TODO: Make this usable directly as a slice index.
539#[cfg(not(target_os = "haiku"))]
540libc_enum! {
541    /// Indices into the `termios.c_cc` array for special characters.
542    #[repr(usize)]
543    #[non_exhaustive]
544    pub enum SpecialCharacterIndices {
545        VDISCARD,
546        #[cfg(any(target_os = "dragonfly",
547                target_os = "freebsd",
548                target_os = "illumos",
549                target_os = "macos",
550                target_os = "netbsd",
551                target_os = "openbsd",
552                target_os = "solaris"))]
553        #[cfg_attr(docsrs, doc(cfg(all())))]
554        VDSUSP,
555        VEOF,
556        VEOL,
557        VEOL2,
558        VERASE,
559        #[cfg(any(target_os = "dragonfly",
560                  target_os = "freebsd",
561                  target_os = "illumos",
562                  target_os = "solaris"))]
563        #[cfg_attr(docsrs, doc(cfg(all())))]
564        VERASE2,
565        VINTR,
566        VKILL,
567        VLNEXT,
568        #[cfg(not(any(all(target_os = "linux", target_arch = "sparc64"),
569                target_os = "illumos", target_os = "solaris")))]
570        #[cfg_attr(docsrs, doc(cfg(all())))]
571        VMIN,
572        VQUIT,
573        VREPRINT,
574        VSTART,
575        #[cfg(any(target_os = "dragonfly",
576                target_os = "freebsd",
577                target_os = "illumos",
578                target_os = "macos",
579                target_os = "netbsd",
580                target_os = "openbsd",
581                target_os = "solaris"))]
582        #[cfg_attr(docsrs, doc(cfg(all())))]
583        VSTATUS,
584        VSTOP,
585        VSUSP,
586        #[cfg(target_os = "linux")]
587        #[cfg_attr(docsrs, doc(cfg(all())))]
588        VSWTC,
589        #[cfg(any(target_os = "haiku", target_os = "illumos", target_os = "solaris"))]
590        #[cfg_attr(docsrs, doc(cfg(all())))]
591        VSWTCH,
592        #[cfg(not(any(all(target_os = "linux", target_arch = "sparc64"),
593                target_os = "illumos", target_os = "solaris")))]
594        #[cfg_attr(docsrs, doc(cfg(all())))]
595        VTIME,
596        VWERASE,
597        #[cfg(target_os = "dragonfly")]
598        #[cfg_attr(docsrs, doc(cfg(all())))]
599        VCHECKPT,
600    }
601}
602
603#[cfg(any(
604    all(target_os = "linux", target_arch = "sparc64"),
605    target_os = "illumos",
606    target_os = "solaris"
607))]
608impl SpecialCharacterIndices {
609    pub const VMIN: SpecialCharacterIndices = SpecialCharacterIndices::VEOF;
610    pub const VTIME: SpecialCharacterIndices = SpecialCharacterIndices::VEOL;
611}
612
613pub use libc::NCCS;
614#[cfg(any(
615    target_os = "android",
616    target_os = "dragonfly",
617    target_os = "freebsd",
618    target_os = "linux",
619    target_os = "macos",
620    target_os = "netbsd",
621    target_os = "openbsd"
622))]
623#[cfg_attr(docsrs, doc(cfg(all())))]
624pub use libc::_POSIX_VDISABLE;
625
626libc_bitflags! {
627    /// Flags for configuring the input mode of a terminal
628    pub struct InputFlags: tcflag_t {
629        IGNBRK;
630        BRKINT;
631        IGNPAR;
632        PARMRK;
633        INPCK;
634        ISTRIP;
635        INLCR;
636        IGNCR;
637        ICRNL;
638        IXON;
639        IXOFF;
640        #[cfg(not(target_os = "redox"))]
641        #[cfg_attr(docsrs, doc(cfg(all())))]
642        IXANY;
643        #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
644        #[cfg_attr(docsrs, doc(cfg(all())))]
645        IMAXBEL;
646        #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))]
647        #[cfg_attr(docsrs, doc(cfg(all())))]
648        IUTF8;
649    }
650}
651
652libc_bitflags! {
653    /// Flags for configuring the output mode of a terminal
654    pub struct OutputFlags: tcflag_t {
655        OPOST;
656        #[cfg(any(target_os = "android",
657                  target_os = "haiku",
658                  target_os = "linux",
659                  target_os = "openbsd"))]
660        #[cfg_attr(docsrs, doc(cfg(all())))]
661        OLCUC;
662        ONLCR;
663        OCRNL as tcflag_t;
664        ONOCR as tcflag_t;
665        ONLRET as tcflag_t;
666        #[cfg(any(target_os = "android",
667                  target_os = "haiku",
668                  target_os = "ios",
669                  target_os = "linux",
670                  target_os = "macos"))]
671        #[cfg_attr(docsrs, doc(cfg(all())))]
672        OFILL as tcflag_t;
673        #[cfg(any(target_os = "android",
674                  target_os = "haiku",
675                  target_os = "ios",
676                  target_os = "linux",
677                  target_os = "macos"))]
678        #[cfg_attr(docsrs, doc(cfg(all())))]
679        OFDEL as tcflag_t;
680        #[cfg(any(target_os = "android",
681                  target_os = "haiku",
682                  target_os = "ios",
683                  target_os = "linux",
684                  target_os = "macos"))]
685        #[cfg_attr(docsrs, doc(cfg(all())))]
686        NL0 as tcflag_t;
687        #[cfg(any(target_os = "android",
688                  target_os = "haiku",
689                  target_os = "ios",
690                  target_os = "linux",
691                  target_os = "macos"))]
692        #[cfg_attr(docsrs, doc(cfg(all())))]
693        NL1 as tcflag_t;
694        #[cfg(any(target_os = "android",
695                  target_os = "haiku",
696                  target_os = "ios",
697                  target_os = "linux",
698                  target_os = "macos"))]
699        #[cfg_attr(docsrs, doc(cfg(all())))]
700        CR0 as tcflag_t;
701        #[cfg(any(target_os = "android",
702                  target_os = "haiku",
703                  target_os = "ios",
704                  target_os = "linux",
705                  target_os = "macos"))]
706        #[cfg_attr(docsrs, doc(cfg(all())))]
707        CR1 as tcflag_t;
708        #[cfg(any(target_os = "android",
709                  target_os = "haiku",
710                  target_os = "ios",
711                  target_os = "linux",
712                  target_os = "macos"))]
713        #[cfg_attr(docsrs, doc(cfg(all())))]
714        CR2 as tcflag_t;
715        #[cfg(any(target_os = "android",
716                  target_os = "haiku",
717                  target_os = "ios",
718                  target_os = "linux",
719                  target_os = "macos"))]
720        #[cfg_attr(docsrs, doc(cfg(all())))]
721        CR3 as tcflag_t;
722        #[cfg(any(target_os = "android",
723                  target_os = "freebsd",
724                  target_os = "haiku",
725                  target_os = "ios",
726                  target_os = "linux",
727                  target_os = "macos"))]
728        #[cfg_attr(docsrs, doc(cfg(all())))]
729        TAB0 as tcflag_t;
730        #[cfg(any(target_os = "android",
731                  target_os = "haiku",
732                  target_os = "ios",
733                  target_os = "linux",
734                  target_os = "macos"))]
735        #[cfg_attr(docsrs, doc(cfg(all())))]
736        TAB1 as tcflag_t;
737        #[cfg(any(target_os = "android",
738                  target_os = "haiku",
739                  target_os = "ios",
740                  target_os = "linux",
741                  target_os = "macos"))]
742        #[cfg_attr(docsrs, doc(cfg(all())))]
743        TAB2 as tcflag_t;
744        #[cfg(any(target_os = "android",
745                  target_os = "freebsd",
746                  target_os = "haiku",
747                  target_os = "ios",
748                  target_os = "linux",
749                  target_os = "macos"))]
750        #[cfg_attr(docsrs, doc(cfg(all())))]
751        TAB3 as tcflag_t;
752        #[cfg(any(target_os = "android", target_os = "linux"))]
753        #[cfg_attr(docsrs, doc(cfg(all())))]
754        XTABS;
755        #[cfg(any(target_os = "android",
756                  target_os = "haiku",
757                  target_os = "ios",
758                  target_os = "linux",
759                  target_os = "macos"))]
760        #[cfg_attr(docsrs, doc(cfg(all())))]
761        BS0 as tcflag_t;
762        #[cfg(any(target_os = "android",
763                  target_os = "haiku",
764                  target_os = "ios",
765                  target_os = "linux",
766                  target_os = "macos"))]
767        #[cfg_attr(docsrs, doc(cfg(all())))]
768        BS1 as tcflag_t;
769        #[cfg(any(target_os = "android",
770                  target_os = "haiku",
771                  target_os = "ios",
772                  target_os = "linux",
773                  target_os = "macos"))]
774        #[cfg_attr(docsrs, doc(cfg(all())))]
775        VT0 as tcflag_t;
776        #[cfg(any(target_os = "android",
777                  target_os = "haiku",
778                  target_os = "ios",
779                  target_os = "linux",
780                  target_os = "macos"))]
781        #[cfg_attr(docsrs, doc(cfg(all())))]
782        VT1 as tcflag_t;
783        #[cfg(any(target_os = "android",
784                  target_os = "haiku",
785                  target_os = "ios",
786                  target_os = "linux",
787                  target_os = "macos"))]
788        #[cfg_attr(docsrs, doc(cfg(all())))]
789        FF0 as tcflag_t;
790        #[cfg(any(target_os = "android",
791                  target_os = "haiku",
792                  target_os = "ios",
793                  target_os = "linux",
794                  target_os = "macos"))]
795        #[cfg_attr(docsrs, doc(cfg(all())))]
796        FF1 as tcflag_t;
797        #[cfg(any(target_os = "freebsd",
798                  target_os = "dragonfly",
799                  target_os = "ios",
800                  target_os = "macos",
801                  target_os = "netbsd",
802                  target_os = "openbsd"))]
803        #[cfg_attr(docsrs, doc(cfg(all())))]
804        OXTABS;
805        #[cfg(any(target_os = "freebsd",
806                  target_os = "dragonfly",
807                  target_os = "macos",
808                  target_os = "netbsd",
809                  target_os = "openbsd"))]
810        #[cfg_attr(docsrs, doc(cfg(all())))]
811        ONOEOT as tcflag_t;
812
813        // Bitmasks for use with OutputFlags to select specific settings
814        // These should be moved to be a mask once https://github.com/rust-lang-nursery/bitflags/issues/110
815        // is resolved.
816
817        #[cfg(any(target_os = "android",
818                  target_os = "haiku",
819                  target_os = "ios",
820                  target_os = "linux",
821                  target_os = "macos"))]
822        #[cfg_attr(docsrs, doc(cfg(all())))]
823        NLDLY as tcflag_t; // FIXME: Datatype needs to be corrected in libc for mac
824        #[cfg(any(target_os = "android",
825                  target_os = "haiku",
826                  target_os = "ios",
827                  target_os = "linux",
828                  target_os = "macos"))]
829        #[cfg_attr(docsrs, doc(cfg(all())))]
830        CRDLY as tcflag_t;
831        #[cfg(any(target_os = "android",
832                  target_os = "freebsd",
833                  target_os = "haiku",
834                  target_os = "ios",
835                  target_os = "linux",
836                  target_os = "macos"))]
837        #[cfg_attr(docsrs, doc(cfg(all())))]
838        TABDLY as tcflag_t;
839        #[cfg(any(target_os = "android",
840                  target_os = "haiku",
841                  target_os = "ios",
842                  target_os = "linux",
843                  target_os = "macos"))]
844        #[cfg_attr(docsrs, doc(cfg(all())))]
845        BSDLY as tcflag_t;
846        #[cfg(any(target_os = "android",
847                  target_os = "haiku",
848                  target_os = "ios",
849                  target_os = "linux",
850                  target_os = "macos"))]
851        #[cfg_attr(docsrs, doc(cfg(all())))]
852        VTDLY as tcflag_t;
853        #[cfg(any(target_os = "android",
854                  target_os = "haiku",
855                  target_os = "ios",
856                  target_os = "linux",
857                  target_os = "macos"))]
858        #[cfg_attr(docsrs, doc(cfg(all())))]
859        FFDLY as tcflag_t;
860    }
861}
862
863libc_bitflags! {
864    /// Flags for setting the control mode of a terminal
865    pub struct ControlFlags: tcflag_t {
866        #[cfg(any(target_os = "dragonfly",
867                  target_os = "freebsd",
868                  target_os = "ios",
869                  target_os = "macos",
870                  target_os = "netbsd",
871                  target_os = "openbsd"))]
872        #[cfg_attr(docsrs, doc(cfg(all())))]
873        CIGNORE;
874        CS5;
875        CS6;
876        CS7;
877        CS8;
878        CSTOPB;
879        CREAD;
880        PARENB;
881        PARODD;
882        HUPCL;
883        CLOCAL;
884        #[cfg(not(target_os = "redox"))]
885        #[cfg_attr(docsrs, doc(cfg(all())))]
886        CRTSCTS;
887        #[cfg(any(target_os = "android", target_os = "linux"))]
888        #[cfg_attr(docsrs, doc(cfg(all())))]
889        CBAUD;
890        #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "mips"))))]
891        #[cfg_attr(docsrs, doc(cfg(all())))]
892        CMSPAR;
893        #[cfg(any(target_os = "android",
894                  all(target_os = "linux",
895                      not(any(target_arch = "powerpc", target_arch = "powerpc64")))))]
896        CIBAUD;
897        #[cfg(any(target_os = "android", target_os = "linux"))]
898        #[cfg_attr(docsrs, doc(cfg(all())))]
899        CBAUDEX;
900        #[cfg(any(target_os = "dragonfly",
901                  target_os = "freebsd",
902                  target_os = "macos",
903                  target_os = "netbsd",
904                  target_os = "openbsd"))]
905        #[cfg_attr(docsrs, doc(cfg(all())))]
906        MDMBUF;
907        #[cfg(any(target_os = "netbsd", target_os = "openbsd"))]
908        #[cfg_attr(docsrs, doc(cfg(all())))]
909        CHWFLOW;
910        #[cfg(any(target_os = "dragonfly",
911                  target_os = "freebsd",
912                  target_os = "netbsd",
913                  target_os = "openbsd"))]
914        #[cfg_attr(docsrs, doc(cfg(all())))]
915        CCTS_OFLOW;
916        #[cfg(any(target_os = "dragonfly",
917                  target_os = "freebsd",
918                  target_os = "netbsd",
919                  target_os = "openbsd"))]
920        #[cfg_attr(docsrs, doc(cfg(all())))]
921        CRTS_IFLOW;
922        #[cfg(any(target_os = "dragonfly",
923                  target_os = "freebsd"))]
924        #[cfg_attr(docsrs, doc(cfg(all())))]
925        CDTR_IFLOW;
926        #[cfg(any(target_os = "dragonfly",
927                  target_os = "freebsd"))]
928        #[cfg_attr(docsrs, doc(cfg(all())))]
929        CDSR_OFLOW;
930        #[cfg(any(target_os = "dragonfly",
931                  target_os = "freebsd"))]
932        #[cfg_attr(docsrs, doc(cfg(all())))]
933        CCAR_OFLOW;
934
935        // Bitmasks for use with ControlFlags to select specific settings
936        // These should be moved to be a mask once https://github.com/rust-lang-nursery/bitflags/issues/110
937        // is resolved.
938
939        CSIZE;
940    }
941}
942
943libc_bitflags! {
944    /// Flags for setting any local modes
945    pub struct LocalFlags: tcflag_t {
946        #[cfg(not(target_os = "redox"))]
947        #[cfg_attr(docsrs, doc(cfg(all())))]
948        ECHOKE;
949        ECHOE;
950        ECHOK;
951        ECHO;
952        ECHONL;
953        #[cfg(not(target_os = "redox"))]
954        #[cfg_attr(docsrs, doc(cfg(all())))]
955        ECHOPRT;
956        #[cfg(not(target_os = "redox"))]
957        #[cfg_attr(docsrs, doc(cfg(all())))]
958        ECHOCTL;
959        ISIG;
960        ICANON;
961        #[cfg(any(target_os = "freebsd",
962                  target_os = "dragonfly",
963                  target_os = "ios",
964                  target_os = "macos",
965                  target_os = "netbsd",
966                  target_os = "openbsd"))]
967        #[cfg_attr(docsrs, doc(cfg(all())))]
968        ALTWERASE;
969        IEXTEN;
970        #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
971        #[cfg_attr(docsrs, doc(cfg(all())))]
972        EXTPROC;
973        TOSTOP;
974        #[cfg(not(target_os = "redox"))]
975        #[cfg_attr(docsrs, doc(cfg(all())))]
976        FLUSHO;
977        #[cfg(any(target_os = "freebsd",
978                  target_os = "dragonfly",
979                  target_os = "ios",
980                  target_os = "macos",
981                  target_os = "netbsd",
982                  target_os = "openbsd"))]
983        #[cfg_attr(docsrs, doc(cfg(all())))]
984        NOKERNINFO;
985        #[cfg(not(target_os = "redox"))]
986        #[cfg_attr(docsrs, doc(cfg(all())))]
987        PENDIN;
988        NOFLSH;
989    }
990}
991
992cfg_if! {
993    if #[cfg(any(target_os = "freebsd",
994                 target_os = "dragonfly",
995                 target_os = "ios",
996                 target_os = "macos",
997                 target_os = "netbsd",
998                 target_os = "openbsd"))] {
999        /// Get input baud rate (see
1000        /// [cfgetispeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetispeed.html)).
1001        ///
1002        /// `cfgetispeed()` extracts the input baud rate from the given `Termios` structure.
1003        // The cast is not unnecessary on all platforms.
1004        #[allow(clippy::unnecessary_cast)]
1005        pub fn cfgetispeed(termios: &Termios) -> u32 {
1006            let inner_termios = termios.get_libc_termios();
1007            unsafe { libc::cfgetispeed(&*inner_termios) as u32 }
1008        }
1009
1010        /// Get output baud rate (see
1011        /// [cfgetospeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetospeed.html)).
1012        ///
1013        /// `cfgetospeed()` extracts the output baud rate from the given `Termios` structure.
1014        // The cast is not unnecessary on all platforms.
1015        #[allow(clippy::unnecessary_cast)]
1016        pub fn cfgetospeed(termios: &Termios) -> u32 {
1017            let inner_termios = termios.get_libc_termios();
1018            unsafe { libc::cfgetospeed(&*inner_termios) as u32 }
1019        }
1020
1021        /// Set input baud rate (see
1022        /// [cfsetispeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetispeed.html)).
1023        ///
1024        /// `cfsetispeed()` sets the intput baud rate in the given `Termios` structure.
1025        pub fn cfsetispeed<T: Into<u32>>(termios: &mut Termios, baud: T) -> Result<()> {
1026            let inner_termios = unsafe { termios.get_libc_termios_mut() };
1027            let res = unsafe { libc::cfsetispeed(inner_termios, baud.into() as libc::speed_t) };
1028            termios.update_wrapper();
1029            Errno::result(res).map(drop)
1030        }
1031
1032        /// Set output baud rate (see
1033        /// [cfsetospeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetospeed.html)).
1034        ///
1035        /// `cfsetospeed()` sets the output baud rate in the given termios structure.
1036        pub fn cfsetospeed<T: Into<u32>>(termios: &mut Termios, baud: T) -> Result<()> {
1037            let inner_termios = unsafe { termios.get_libc_termios_mut() };
1038            let res = unsafe { libc::cfsetospeed(inner_termios, baud.into() as libc::speed_t) };
1039            termios.update_wrapper();
1040            Errno::result(res).map(drop)
1041        }
1042
1043        /// Set both the input and output baud rates (see
1044        /// [termios(3)](https://www.freebsd.org/cgi/man.cgi?query=cfsetspeed)).
1045        ///
1046        /// `cfsetspeed()` sets the input and output baud rate in the given termios structure. Note that
1047        /// this is part of the 4.4BSD standard and not part of POSIX.
1048        pub fn cfsetspeed<T: Into<u32>>(termios: &mut Termios, baud: T) -> Result<()> {
1049            let inner_termios = unsafe { termios.get_libc_termios_mut() };
1050            let res = unsafe { libc::cfsetspeed(inner_termios, baud.into() as libc::speed_t) };
1051            termios.update_wrapper();
1052            Errno::result(res).map(drop)
1053        }
1054    } else {
1055        use std::convert::TryInto;
1056
1057        /// Get input baud rate (see
1058        /// [cfgetispeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetispeed.html)).
1059        ///
1060        /// `cfgetispeed()` extracts the input baud rate from the given `Termios` structure.
1061        pub fn cfgetispeed(termios: &Termios) -> BaudRate {
1062            let inner_termios = termios.get_libc_termios();
1063            unsafe { libc::cfgetispeed(&*inner_termios) }.try_into().unwrap()
1064        }
1065
1066        /// Get output baud rate (see
1067        /// [cfgetospeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetospeed.html)).
1068        ///
1069        /// `cfgetospeed()` extracts the output baud rate from the given `Termios` structure.
1070        pub fn cfgetospeed(termios: &Termios) -> BaudRate {
1071            let inner_termios = termios.get_libc_termios();
1072            unsafe { libc::cfgetospeed(&*inner_termios) }.try_into().unwrap()
1073        }
1074
1075        /// Set input baud rate (see
1076        /// [cfsetispeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetispeed.html)).
1077        ///
1078        /// `cfsetispeed()` sets the intput baud rate in the given `Termios` structure.
1079        pub fn cfsetispeed(termios: &mut Termios, baud: BaudRate) -> Result<()> {
1080            let inner_termios = unsafe { termios.get_libc_termios_mut() };
1081            let res = unsafe { libc::cfsetispeed(inner_termios, baud as libc::speed_t) };
1082            termios.update_wrapper();
1083            Errno::result(res).map(drop)
1084        }
1085
1086        /// Set output baud rate (see
1087        /// [cfsetospeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetospeed.html)).
1088        ///
1089        /// `cfsetospeed()` sets the output baud rate in the given `Termios` structure.
1090        pub fn cfsetospeed(termios: &mut Termios, baud: BaudRate) -> Result<()> {
1091            let inner_termios = unsafe { termios.get_libc_termios_mut() };
1092            let res = unsafe { libc::cfsetospeed(inner_termios, baud as libc::speed_t) };
1093            termios.update_wrapper();
1094            Errno::result(res).map(drop)
1095        }
1096
1097        /// Set both the input and output baud rates (see
1098        /// [termios(3)](https://www.freebsd.org/cgi/man.cgi?query=cfsetspeed)).
1099        ///
1100        /// `cfsetspeed()` sets the input and output baud rate in the given `Termios` structure. Note that
1101        /// this is part of the 4.4BSD standard and not part of POSIX.
1102        #[cfg(not(target_os = "haiku"))]
1103        pub fn cfsetspeed(termios: &mut Termios, baud: BaudRate) -> Result<()> {
1104            let inner_termios = unsafe { termios.get_libc_termios_mut() };
1105            let res = unsafe { libc::cfsetspeed(inner_termios, baud as libc::speed_t) };
1106            termios.update_wrapper();
1107            Errno::result(res).map(drop)
1108        }
1109    }
1110}
1111
1112/// Configures the port to something like the "raw" mode of the old Version 7 terminal driver (see
1113/// [termios(3)](https://man7.org/linux/man-pages/man3/termios.3.html)).
1114///
1115/// `cfmakeraw()` configures the termios structure such that input is available character-by-
1116/// character, echoing is disabled, and all special input and output processing is disabled. Note
1117/// that this is a non-standard function, but is available on Linux and BSDs.
1118pub fn cfmakeraw(termios: &mut Termios) {
1119    let inner_termios = unsafe { termios.get_libc_termios_mut() };
1120    unsafe {
1121        libc::cfmakeraw(inner_termios);
1122    }
1123    termios.update_wrapper();
1124}
1125
1126/// Configures the port to "sane" mode (like the configuration of a newly created terminal) (see
1127/// [tcsetattr(3)](https://www.freebsd.org/cgi/man.cgi?query=tcsetattr)).
1128///
1129/// Note that this is a non-standard function, available on FreeBSD.
1130#[cfg(target_os = "freebsd")]
1131#[cfg_attr(docsrs, doc(cfg(all())))]
1132pub fn cfmakesane(termios: &mut Termios) {
1133    let inner_termios = unsafe { termios.get_libc_termios_mut() };
1134    unsafe {
1135        libc::cfmakesane(inner_termios);
1136    }
1137    termios.update_wrapper();
1138}
1139
1140/// Return the configuration of a port
1141/// [tcgetattr(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetattr.html)).
1142///
1143/// `tcgetattr()` returns a `Termios` structure with the current configuration for a port. Modifying
1144/// this structure *will not* reconfigure the port, instead the modifications should be done to
1145/// the `Termios` structure and then the port should be reconfigured using `tcsetattr()`.
1146pub fn tcgetattr(fd: RawFd) -> Result<Termios> {
1147    let mut termios = mem::MaybeUninit::uninit();
1148
1149    let res = unsafe { libc::tcgetattr(fd, termios.as_mut_ptr()) };
1150
1151    Errno::result(res)?;
1152
1153    unsafe { Ok(termios.assume_init().into()) }
1154}
1155
1156/// Set the configuration for a terminal (see
1157/// [tcsetattr(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsetattr.html)).
1158///
1159/// `tcsetattr()` reconfigures the given port based on a given `Termios` structure. This change
1160/// takes affect at a time specified by `actions`. Note that this function may return success if
1161/// *any* of the parameters were successfully set, not only if all were set successfully.
1162pub fn tcsetattr(fd: RawFd, actions: SetArg, termios: &Termios) -> Result<()> {
1163    let inner_termios = termios.get_libc_termios();
1164    Errno::result(unsafe {
1165        libc::tcsetattr(fd, actions as c_int, &*inner_termios)
1166    })
1167    .map(drop)
1168}
1169
1170/// Block until all output data is written (see
1171/// [tcdrain(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcdrain.html)).
1172pub fn tcdrain(fd: RawFd) -> Result<()> {
1173    Errno::result(unsafe { libc::tcdrain(fd) }).map(drop)
1174}
1175
1176/// Suspend or resume the transmission or reception of data (see
1177/// [tcflow(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcflow.html)).
1178///
1179/// `tcflow()` suspends of resumes the transmission or reception of data for the given port
1180/// depending on the value of `action`.
1181pub fn tcflow(fd: RawFd, action: FlowArg) -> Result<()> {
1182    Errno::result(unsafe { libc::tcflow(fd, action as c_int) }).map(drop)
1183}
1184
1185/// Discard data in the output or input queue (see
1186/// [tcflush(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcflush.html)).
1187///
1188/// `tcflush()` will discard data for a terminal port in the input queue, output queue, or both
1189/// depending on the value of `action`.
1190pub fn tcflush(fd: RawFd, action: FlushArg) -> Result<()> {
1191    Errno::result(unsafe { libc::tcflush(fd, action as c_int) }).map(drop)
1192}
1193
1194/// Send a break for a specific duration (see
1195/// [tcsendbreak(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsendbreak.html)).
1196///
1197/// When using asynchronous data transmission `tcsendbreak()` will transmit a continuous stream
1198/// of zero-valued bits for an implementation-defined duration.
1199pub fn tcsendbreak(fd: RawFd, duration: c_int) -> Result<()> {
1200    Errno::result(unsafe { libc::tcsendbreak(fd, duration) }).map(drop)
1201}
1202
1203feature! {
1204#![feature = "process"]
1205/// Get the session controlled by the given terminal (see
1206/// [tcgetsid(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetsid.html)).
1207pub fn tcgetsid(fd: RawFd) -> Result<Pid> {
1208    let res = unsafe { libc::tcgetsid(fd) };
1209
1210    Errno::result(res).map(Pid::from_raw)
1211}
1212}
1213
1214#[cfg(test)]
1215mod test {
1216    use super::*;
1217    use std::convert::TryFrom;
1218
1219    #[test]
1220    fn try_from() {
1221        assert_eq!(Ok(BaudRate::B0), BaudRate::try_from(libc::B0));
1222        #[cfg(not(target_os = "haiku"))]
1223        BaudRate::try_from(999999999).expect_err("assertion failed");
1224        #[cfg(target_os = "haiku")]
1225        BaudRate::try_from(99).expect_err("assertion failed");
1226    }
1227}