• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 //! ```
218 use crate::errno::Errno;
219 use crate::Result;
220 use cfg_if::cfg_if;
221 use libc::{self, c_int, tcflag_t};
222 use std::cell::{Ref, RefCell};
223 use std::convert::From;
224 use std::mem;
225 use std::os::unix::io::RawFd;
226 
227 #[cfg(feature = "process")]
228 use 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)]
236 pub 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 
256 impl 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.
get_libc_termios(&self) -> Ref<libc::termios>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.
get_libc_termios_mut(&mut self) -> *mut libc::termios287     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.
update_wrapper(&mut self)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 
326 impl From<libc::termios> for Termios {
from(termios: libc::termios) -> Self327     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 
345 impl From<Termios> for libc::termios {
from(termios: Termios) -> Self346     fn from(termios: Termios) -> Self {
347         termios.inner.into_inner()
348     }
349 }
350 
351 libc_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 ))]
474 impl From<BaudRate> for u32 {
from(b: BaudRate) -> u32475     fn from(b: BaudRate) -> u32 {
476         b as u32
477     }
478 }
479 
480 #[cfg(target_os = "haiku")]
481 impl From<BaudRate> for u8 {
from(b: BaudRate) -> u8482     fn from(b: BaudRate) -> u8 {
483         b as u8
484     }
485 }
486 
487 // TODO: Add TCSASOFT, which will require treating this as a bitfield.
488 libc_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 
504 libc_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 
520 libc_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"))]
540 libc_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 ))]
608 impl SpecialCharacterIndices {
609     pub const VMIN: SpecialCharacterIndices = SpecialCharacterIndices::VEOF;
610     pub const VTIME: SpecialCharacterIndices = SpecialCharacterIndices::VEOL;
611 }
612 
613 pub 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())))]
624 pub use libc::_POSIX_VDISABLE;
625 
626 libc_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 
652 libc_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 
863 libc_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 
943 libc_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 
992 cfg_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.
cfmakeraw(termios: &mut Termios)1118 pub 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())))]
cfmakesane(termios: &mut Termios)1132 pub 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()`.
tcgetattr(fd: RawFd) -> Result<Termios>1146 pub 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.
tcsetattr(fd: RawFd, actions: SetArg, termios: &Termios) -> Result<()>1162 pub 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)).
tcdrain(fd: RawFd) -> Result<()>1172 pub 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`.
tcflow(fd: RawFd, action: FlowArg) -> Result<()>1181 pub 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`.
tcflush(fd: RawFd, action: FlushArg) -> Result<()>1190 pub 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.
tcsendbreak(fd: RawFd, duration: c_int) -> Result<()>1199 pub fn tcsendbreak(fd: RawFd, duration: c_int) -> Result<()> {
1200     Errno::result(unsafe { libc::tcsendbreak(fd, duration) }).map(drop)
1201 }
1202 
1203 feature! {
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)).
1207 pub 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)]
1215 mod test {
1216     use super::*;
1217     use std::convert::TryFrom;
1218 
1219     #[test]
try_from()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 }
1228