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