]> git.lizzy.rs Git - rust.git/blob - src/libstd/sys/unix/mod.rs
Auto merge of #22541 - Manishearth:rollup, r=Gankro
[rust.git] / src / libstd / sys / unix / mod.rs
1 // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 #![allow(missing_docs)]
12 #![allow(non_camel_case_types)]
13 #![allow(unused_imports)]
14 #![allow(dead_code)]
15 #![allow(unused_unsafe)]
16 #![allow(unused_mut)]
17
18 use prelude::v1::*;
19
20 use ffi::CStr;
21 use io::{self, ErrorKind};
22 use libc;
23 use num::{Int, SignedInt};
24 use num;
25 use old_io::{self, IoResult, IoError};
26 use str;
27 use sys_common::mkerr_libc;
28
29 macro_rules! helper_init { (static $name:ident: Helper<$m:ty>) => (
30     static $name: Helper<$m> = Helper {
31         lock: ::sync::MUTEX_INIT,
32         cond: ::sync::CONDVAR_INIT,
33         chan: ::cell::UnsafeCell { value: 0 as *mut Sender<$m> },
34         signal: ::cell::UnsafeCell { value: 0 },
35         initialized: ::cell::UnsafeCell { value: false },
36         shutdown: ::cell::UnsafeCell { value: false },
37     };
38 ) }
39
40 pub mod backtrace;
41 pub mod c;
42 pub mod condvar;
43 pub mod ext;
44 pub mod fd;
45 pub mod fs;  // support for std::old_io
46 pub mod fs2; // support for std::fs
47 pub mod helper_signal;
48 pub mod mutex;
49 pub mod net;
50 pub mod os;
51 pub mod os_str;
52 pub mod pipe;
53 pub mod pipe2;
54 pub mod process;
55 pub mod process2;
56 pub mod rwlock;
57 pub mod stack_overflow;
58 pub mod sync;
59 pub mod tcp;
60 pub mod thread;
61 pub mod thread_local;
62 pub mod time;
63 pub mod timer;
64 pub mod tty;
65 pub mod udp;
66
67 pub mod addrinfo {
68     pub use sys_common::net::get_host_addresses;
69     pub use sys_common::net::get_address_name;
70 }
71
72 // FIXME: move these to c module
73 pub type sock_t = self::fs::fd_t;
74 pub type wrlen = libc::size_t;
75 pub type msglen_t = libc::size_t;
76 pub unsafe fn close_sock(sock: sock_t) { let _ = libc::close(sock); }
77
78 pub fn last_error() -> IoError {
79     decode_error_detailed(os::errno() as i32)
80 }
81
82 pub fn last_net_error() -> IoError {
83     last_error()
84 }
85
86 extern "system" {
87     fn gai_strerror(errcode: libc::c_int) -> *const libc::c_char;
88 }
89
90 pub fn last_gai_error(s: libc::c_int) -> IoError {
91
92     let mut err = decode_error(s);
93     err.detail = Some(unsafe {
94         let data = CStr::from_ptr(gai_strerror(s));
95         str::from_utf8(data.to_bytes()).unwrap().to_string()
96     });
97     err
98 }
99
100 /// Convert an `errno` value into a high-level error variant and description.
101 pub fn decode_error(errno: i32) -> IoError {
102     // FIXME: this should probably be a bit more descriptive...
103     let (kind, desc) = match errno {
104         libc::EOF => (old_io::EndOfFile, "end of file"),
105         libc::ECONNREFUSED => (old_io::ConnectionRefused, "connection refused"),
106         libc::ECONNRESET => (old_io::ConnectionReset, "connection reset"),
107         libc::EPERM | libc::EACCES =>
108             (old_io::PermissionDenied, "permission denied"),
109         libc::EPIPE => (old_io::BrokenPipe, "broken pipe"),
110         libc::ENOTCONN => (old_io::NotConnected, "not connected"),
111         libc::ECONNABORTED => (old_io::ConnectionAborted, "connection aborted"),
112         libc::EADDRNOTAVAIL => (old_io::ConnectionRefused, "address not available"),
113         libc::EADDRINUSE => (old_io::ConnectionRefused, "address in use"),
114         libc::ENOENT => (old_io::FileNotFound, "no such file or directory"),
115         libc::EISDIR => (old_io::InvalidInput, "illegal operation on a directory"),
116         libc::ENOSYS => (old_io::IoUnavailable, "function not implemented"),
117         libc::EINVAL => (old_io::InvalidInput, "invalid argument"),
118         libc::ENOTTY =>
119             (old_io::MismatchedFileTypeForOperation,
120              "file descriptor is not a TTY"),
121         libc::ETIMEDOUT => (old_io::TimedOut, "operation timed out"),
122         libc::ECANCELED => (old_io::TimedOut, "operation aborted"),
123         libc::consts::os::posix88::EEXIST =>
124             (old_io::PathAlreadyExists, "path already exists"),
125
126         // These two constants can have the same value on some systems,
127         // but different values on others, so we can't use a match
128         // clause
129         x if x == libc::EAGAIN || x == libc::EWOULDBLOCK =>
130             (old_io::ResourceUnavailable, "resource temporarily unavailable"),
131
132         _ => (old_io::OtherIoError, "unknown error")
133     };
134     IoError { kind: kind, desc: desc, detail: None }
135 }
136
137 pub fn decode_error_detailed(errno: i32) -> IoError {
138     let mut err = decode_error(errno);
139     err.detail = Some(os::error_string(errno));
140     err
141 }
142
143 pub fn decode_error_kind(errno: i32) -> ErrorKind {
144     match errno as libc::c_int {
145         libc::ECONNREFUSED => ErrorKind::ConnectionRefused,
146         libc::ECONNRESET => ErrorKind::ConnectionReset,
147         libc::EPERM | libc::EACCES => ErrorKind::PermissionDenied,
148         libc::EPIPE => ErrorKind::BrokenPipe,
149         libc::ENOTCONN => ErrorKind::NotConnected,
150         libc::ECONNABORTED => ErrorKind::ConnectionAborted,
151         libc::EADDRNOTAVAIL => ErrorKind::ConnectionRefused,
152         libc::EADDRINUSE => ErrorKind::ConnectionRefused,
153         libc::ENOENT => ErrorKind::FileNotFound,
154         libc::EISDIR => ErrorKind::InvalidInput,
155         libc::EINTR => ErrorKind::Interrupted,
156         libc::EINVAL => ErrorKind::InvalidInput,
157         libc::ENOTTY => ErrorKind::MismatchedFileTypeForOperation,
158         libc::ETIMEDOUT => ErrorKind::TimedOut,
159         libc::ECANCELED => ErrorKind::TimedOut,
160         libc::consts::os::posix88::EEXIST => ErrorKind::PathAlreadyExists,
161
162         // These two constants can have the same value on some systems,
163         // but different values on others, so we can't use a match
164         // clause
165         x if x == libc::EAGAIN || x == libc::EWOULDBLOCK =>
166             ErrorKind::ResourceUnavailable,
167
168         _ => ErrorKind::Other,
169     }
170 }
171
172 #[inline]
173 pub fn retry<T, F> (mut f: F) -> T where
174     T: SignedInt,
175     F: FnMut() -> T,
176 {
177     let one: T = Int::one();
178     loop {
179         let n = f();
180         if n == -one && os::errno() == libc::EINTR as i32 { }
181         else { return n }
182     }
183 }
184
185 pub fn cvt<T: SignedInt>(t: T) -> io::Result<T> {
186     let one: T = Int::one();
187     if t == -one {
188         Err(io::Error::last_os_error())
189     } else {
190         Ok(t)
191     }
192 }
193
194 pub fn cvt_r<T, F>(mut f: F) -> io::Result<T>
195     where T: SignedInt, F: FnMut() -> T
196 {
197     loop {
198         match cvt(f()) {
199             Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
200             other => return other,
201         }
202     }
203 }
204
205 pub fn ms_to_timeval(ms: u64) -> libc::timeval {
206     libc::timeval {
207         tv_sec: (ms / 1000) as libc::time_t,
208         tv_usec: ((ms % 1000) * 1000) as libc::suseconds_t,
209     }
210 }
211
212 pub fn wouldblock() -> bool {
213     let err = os::errno();
214     err == libc::EWOULDBLOCK as i32 || err == libc::EAGAIN as i32
215 }
216
217 pub fn set_nonblocking(fd: sock_t, nb: bool) -> IoResult<()> {
218     let set = nb as libc::c_int;
219     mkerr_libc(retry(|| unsafe { c::ioctl(fd, c::FIONBIO, &set) }))
220 }
221
222 // nothing needed on unix platforms
223 pub fn init_net() {}