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