(index<- ) ./libstd/os.rs
git branch: * master 5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
modified: Fri May 9 13:02:28 2014
1 // Copyright 2012-2013 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 /*!
12 * Higher-level interfaces to libc::* functions and operating system services.
13 *
14 * In general these take and return rust types, use rust idioms (enums,
15 * closures, vectors) rather than C idioms, and do more extensive safety
16 * checks.
17 *
18 * This module is not meant to only contain 1:1 mappings to libc entries; any
19 * os-interface code that is reasonably useful and broadly applicable can go
20 * here. Including utility routines that merely build on other os code.
21 *
22 * We assume the general case is that users do not care, and do not want to
23 * be made to care, which operating system they are on. While they may want
24 * to special case various special cases -- and so we will not _hide_ the
25 * facts of which OS the user is on -- they should be given the opportunity
26 * to write OS-ignorant code by default.
27 */
28
29 #![allow(missing_doc)]
30
31 use clone::Clone;
32 use container::Container;
33 use libc;
34 use libc::{c_char, c_void, c_int};
35 use option::{Some, None, Option};
36 use os;
37 use ops::Drop;
38 use result::{Err, Ok, Result};
39 use ptr;
40 use str;
41 use str::{Str, StrSlice, StrAllocating};
42 use fmt;
43 use sync::atomics::{AtomicInt, INIT_ATOMIC_INT, SeqCst};
44 use path::{Path, GenericPath};
45 use iter::Iterator;
46 use slice::{Vector, CloneableVector, ImmutableVector, MutableVector, OwnedVector};
47 use ptr::RawPtr;
48 use vec::Vec;
49
50 #[cfg(unix)]
51 use c_str::ToCStr;
52 #[cfg(windows)]
53 use str::OwnedStr;
54
55 /// Delegates to the libc close() function, returning the same return value.
56 pub fn close(fd: int) -> int {
57 unsafe {
58 libc::close(fd as c_int) as int
59 }
60 }
61
62 pub static TMPBUF_SZ : uint = 1000u;
63 static BUF_BYTES : uint = 2048u;
64
65 /// Returns the current working directory.
66 #[cfg(unix)]
67 pub fn getcwd() -> Path {
68 use c_str::CString;
69
70 let mut buf = [0 as c_char, ..BUF_BYTES];
71 unsafe {
72 if libc::getcwd(buf.as_mut_ptr(), buf.len() as libc::size_t).is_null() {
73 fail!()
74 }
75 Path::new(CString::new(buf.as_ptr(), false))
76 }
77 }
78
79 /// Returns the current working directory.
80 #[cfg(windows)]
81 pub fn getcwd() -> Path {
82 use libc::DWORD;
83 use libc::GetCurrentDirectoryW;
84 use option::Expect;
85
86 let mut buf = [0 as u16, ..BUF_BYTES];
87 unsafe {
88 if libc::GetCurrentDirectoryW(buf.len() as DWORD, buf.as_mut_ptr()) == 0 as DWORD {
89 fail!();
90 }
91 }
92 Path::new(str::from_utf16(str::truncate_utf16_at_nul(buf))
93 .expect("GetCurrentDirectoryW returned invalid UTF-16"))
94 }
95
96 #[cfg(windows)]
97 pub mod win32 {
98 use iter::Iterator;
99 use libc::types::os::arch::extra::DWORD;
100 use libc;
101 use option::{None, Option, Expect};
102 use option;
103 use os::TMPBUF_SZ;
104 use slice::{MutableVector, ImmutableVector, OwnedVector};
105 use str::{StrSlice, StrAllocating};
106 use str;
107 use vec::Vec;
108
109 pub fn fill_utf16_buf_and_decode(f: |*mut u16, DWORD| -> DWORD)
110 -> Option<~str> {
111
112 unsafe {
113 let mut n = TMPBUF_SZ as DWORD;
114 let mut res = None;
115 let mut done = false;
116 while !done {
117 let mut buf = Vec::from_elem(n as uint, 0u16);
118 let k = f(buf.as_mut_ptr(), n);
119 if k == (0 as DWORD) {
120 done = true;
121 } else if k == n &&
122 libc::GetLastError() ==
123 libc::ERROR_INSUFFICIENT_BUFFER as DWORD {
124 n *= 2 as DWORD;
125 } else if k >= n {
126 n = k;
127 } else {
128 done = true;
129 }
130 if k != 0 && done {
131 let sub = buf.slice(0, k as uint);
132 // We want to explicitly catch the case when the
133 // closure returned invalid UTF-16, rather than
134 // set `res` to None and continue.
135 let s = str::from_utf16(sub)
136 .expect("fill_utf16_buf_and_decode: closure created invalid UTF-16");
137 res = option::Some(s)
138 }
139 }
140 return res;
141 }
142 }
143
144 pub fn as_utf16_p<T>(s: &str, f: |*u16| -> T) -> T {
145 let mut t = s.to_utf16().move_iter().collect::<Vec<u16>>();
146 // Null terminate before passing on.
147 t.push(0u16);
148 f(t.as_ptr())
149 }
150 }
151
152 /*
153 Accessing environment variables is not generally threadsafe.
154 Serialize access through a global lock.
155 */
156 fn with_env_lock<T>(f: || -> T) -> T {
157 use unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
158
159 static mut lock: StaticNativeMutex = NATIVE_MUTEX_INIT;
160
161 unsafe {
162 let _guard = lock.lock();
163 f()
164 }
165 }
166
167 /// Returns a vector of (variable, value) pairs for all the environment
168 /// variables of the current process.
169 ///
170 /// Invalid UTF-8 bytes are replaced with \uFFFD. See `str::from_utf8_lossy()`
171 /// for details.
172 pub fn env() -> Vec<(~str,~str)> {
173 env_as_bytes().move_iter().map(|(k,v)| {
174 let k = str::from_utf8_lossy(k).into_owned();
175 let v = str::from_utf8_lossy(v).into_owned();
176 (k,v)
177 }).collect()
178 }
179
180 /// Returns a vector of (variable, value) byte-vector pairs for all the
181 /// environment variables of the current process.
182 pub fn env_as_bytes() -> Vec<(~[u8],~[u8])> {
183 unsafe {
184 #[cfg(windows)]
185 unsafe fn get_env_pairs() -> Vec<~[u8]> {
186 use c_str;
187
188 use libc::funcs::extra::kernel32::{
189 GetEnvironmentStringsA,
190 FreeEnvironmentStringsA
191 };
192 let ch = GetEnvironmentStringsA();
193 if ch as uint == 0 {
194 fail!("os::env() failure getting env string from OS: {}",
195 os::last_os_error());
196 }
197 let mut result = Vec::new();
198 c_str::from_c_multistring(ch as *c_char, None, |cstr| {
199 result.push(cstr.as_bytes_no_nul().to_owned());
200 });
201 FreeEnvironmentStringsA(ch);
202 result
203 }
204 #[cfg(unix)]
205 unsafe fn get_env_pairs() -> Vec<~[u8]> {
206 use c_str::CString;
207
208 extern {
209 fn rust_env_pairs() -> **c_char;
210 }
211 let environ = rust_env_pairs();
212 if environ as uint == 0 {
213 fail!("os::env() failure getting env string from OS: {}",
214 os::last_os_error());
215 }
216 let mut result = Vec::new();
217 ptr::array_each(environ, |e| {
218 let env_pair = CString::new(e, false).as_bytes_no_nul().to_owned();
219 result.push(env_pair);
220 });
221 result
222 }
223
224 fn env_convert(input: Vec<~[u8]>) -> Vec<(~[u8], ~[u8])> {
225 let mut pairs = Vec::new();
226 for p in input.iter() {
227 let mut it = p.splitn(1, |b| *b == '=' as u8);
228 let key = it.next().unwrap().to_owned();
229 let val = it.next().unwrap_or(&[]).to_owned();
230 pairs.push((key, val));
231 }
232 pairs
233 }
234 with_env_lock(|| {
235 let unparsed_environ = get_env_pairs();
236 env_convert(unparsed_environ)
237 })
238 }
239 }
240
241 #[cfg(unix)]
242 /// Fetches the environment variable `n` from the current process, returning
243 /// None if the variable isn't set.
244 ///
245 /// Any invalid UTF-8 bytes in the value are replaced by \uFFFD. See
246 /// `str::from_utf8_lossy()` for details.
247 ///
248 /// # Failure
249 ///
250 /// Fails if `n` has any interior NULs.
251 pub fn getenv(n: &str) -> Option<~str> {
252 getenv_as_bytes(n).map(|v| str::from_utf8_lossy(v).into_owned())
253 }
254
255 #[cfg(unix)]
256 /// Fetches the environment variable `n` byte vector from the current process,
257 /// returning None if the variable isn't set.
258 ///
259 /// # Failure
260 ///
261 /// Fails if `n` has any interior NULs.
262 pub fn getenv_as_bytes(n: &str) -> Option<~[u8]> {
263 use c_str::CString;
264
265 unsafe {
266 with_env_lock(|| {
267 let s = n.with_c_str(|buf| libc::getenv(buf));
268 if s.is_null() {
269 None
270 } else {
271 Some(CString::new(s, false).as_bytes_no_nul().to_owned())
272 }
273 })
274 }
275 }
276
277 #[cfg(windows)]
278 /// Fetches the environment variable `n` from the current process, returning
279 /// None if the variable isn't set.
280 pub fn getenv(n: &str) -> Option<~str> {
281 unsafe {
282 with_env_lock(|| {
283 use os::win32::{as_utf16_p, fill_utf16_buf_and_decode};
284 as_utf16_p(n, |u| {
285 fill_utf16_buf_and_decode(|buf, sz| {
286 libc::GetEnvironmentVariableW(u, buf, sz)
287 })
288 })
289 })
290 }
291 }
292
293 #[cfg(windows)]
294 /// Fetches the environment variable `n` byte vector from the current process,
295 /// returning None if the variable isn't set.
296 pub fn getenv_as_bytes(n: &str) -> Option<~[u8]> {
297 getenv(n).map(|s| s.into_bytes())
298 }
299
300
301 #[cfg(unix)]
302 /// Sets the environment variable `n` to the value `v` for the currently running
303 /// process
304 ///
305 /// # Failure
306 ///
307 /// Fails if `n` or `v` have any interior NULs.
308 pub fn setenv(n: &str, v: &str) {
309 unsafe {
310 with_env_lock(|| {
311 n.with_c_str(|nbuf| {
312 v.with_c_str(|vbuf| {
313 libc::funcs::posix01::unistd::setenv(nbuf, vbuf, 1);
314 })
315 })
316 })
317 }
318 }
319
320
321 #[cfg(windows)]
322 /// Sets the environment variable `n` to the value `v` for the currently running
323 /// process
324 pub fn setenv(n: &str, v: &str) {
325 unsafe {
326 with_env_lock(|| {
327 use os::win32::as_utf16_p;
328 as_utf16_p(n, |nbuf| {
329 as_utf16_p(v, |vbuf| {
330 libc::SetEnvironmentVariableW(nbuf, vbuf);
331 })
332 })
333 })
334 }
335 }
336
337 /// Remove a variable from the environment entirely
338 ///
339 /// # Failure
340 ///
341 /// Fails (on unix) if `n` has any interior NULs.
342 pub fn unsetenv(n: &str) {
343 #[cfg(unix)]
344 fn _unsetenv(n: &str) {
345 unsafe {
346 with_env_lock(|| {
347 n.with_c_str(|nbuf| {
348 libc::funcs::posix01::unistd::unsetenv(nbuf);
349 })
350 })
351 }
352 }
353 #[cfg(windows)]
354 fn _unsetenv(n: &str) {
355 unsafe {
356 with_env_lock(|| {
357 use os::win32::as_utf16_p;
358 as_utf16_p(n, |nbuf| {
359 libc::SetEnvironmentVariableW(nbuf, ptr::null());
360 })
361 })
362 }
363 }
364
365 _unsetenv(n);
366 }
367
368 /// A low-level OS in-memory pipe.
369 pub struct Pipe {
370 /// A file descriptor representing the reading end of the pipe. Data written
371 /// on the `out` file descriptor can be read from this file descriptor.
372 pub input: c_int,
373 /// A file descriptor representing the write end of the pipe. Data written
374 /// to this file descriptor can be read from the `input` file descriptor.
375 pub out: c_int,
376 }
377
378 /// Creates a new low-level OS in-memory pipe.
379 #[cfg(unix)]
380 pub fn pipe() -> Pipe {
381 unsafe {
382 let mut fds = Pipe {input: 0,
383 out: 0};
384 assert_eq!(libc::pipe(&mut fds.input), 0);
385 return Pipe {input: fds.input, out: fds.out};
386 }
387 }
388
389 /// Creates a new low-level OS in-memory pipe.
390 #[cfg(windows)]
391 pub fn pipe() -> Pipe {
392 unsafe {
393 // Windows pipes work subtly differently than unix pipes, and their
394 // inheritance has to be handled in a different way that I do not
395 // fully understand. Here we explicitly make the pipe non-inheritable,
396 // which means to pass it to a subprocess they need to be duplicated
397 // first, as in std::run.
398 let mut fds = Pipe {input: 0,
399 out: 0};
400 let res = libc::pipe(&mut fds.input, 1024 as ::libc::c_uint,
401 (libc::O_BINARY | libc::O_NOINHERIT) as c_int);
402 assert_eq!(res, 0);
403 assert!((fds.input != -1 && fds.input != 0 ));
404 assert!((fds.out != -1 && fds.input != 0));
405 return Pipe {input: fds.input, out: fds.out};
406 }
407 }
408
409 /// Returns the proper dll filename for the given basename of a file.
410 pub fn dll_filename(base: &str) -> ~str {
411 format!("{}{}{}", consts::DLL_PREFIX, base, consts::DLL_SUFFIX)
412 }
413
414 /// Optionally returns the filesystem path of the current executable which is
415 /// running. If any failure occurs, None is returned.
416 pub fn self_exe_name() -> Option<Path> {
417
418 #[cfg(target_os = "freebsd")]
419 fn load_self() -> Option<Vec<u8>> {
420 unsafe {
421 use libc::funcs::bsd44::*;
422 use libc::consts::os::extra::*;
423 let mib = box [CTL_KERN as c_int,
424 KERN_PROC as c_int,
425 KERN_PROC_PATHNAME as c_int, -1 as c_int];
426 let mut sz: libc::size_t = 0;
427 let err = sysctl(mib.as_ptr(), mib.len() as ::libc::c_uint,
428 ptr::mut_null(), &mut sz, ptr::null(),
429 0u as libc::size_t);
430 if err != 0 { return None; }
431 if sz == 0 { return None; }
432 let mut v: Vec<u8> = Vec::with_capacity(sz as uint);
433 let err = sysctl(mib.as_ptr(), mib.len() as ::libc::c_uint,
434 v.as_mut_ptr() as *mut c_void, &mut sz, ptr::null(),
435 0u as libc::size_t);
436 if err != 0 { return None; }
437 if sz == 0 { return None; }
438 v.set_len(sz as uint - 1); // chop off trailing NUL
439 Some(v)
440 }
441 }
442
443 #[cfg(target_os = "linux")]
444 #[cfg(target_os = "android")]
445 fn load_self() -> Option<Vec<u8>> {
446 use std::io;
447
448 match io::fs::readlink(&Path::new("/proc/self/exe")) {
449 Ok(path) => Some(path.into_vec()),
450 Err(..) => None
451 }
452 }
453
454 #[cfg(target_os = "macos")]
455 fn load_self() -> Option<Vec<u8>> {
456 unsafe {
457 use libc::funcs::extra::_NSGetExecutablePath;
458 let mut sz: u32 = 0;
459 _NSGetExecutablePath(ptr::mut_null(), &mut sz);
460 if sz == 0 { return None; }
461 let mut v: Vec<u8> = Vec::with_capacity(sz as uint);
462 let err = _NSGetExecutablePath(v.as_mut_ptr() as *mut i8, &mut sz);
463 if err != 0 { return None; }
464 v.set_len(sz as uint - 1); // chop off trailing NUL
465 Some(v)
466 }
467 }
468
469 #[cfg(windows)]
470 fn load_self() -> Option<Vec<u8>> {
471 use str::OwnedStr;
472
473 unsafe {
474 use os::win32::fill_utf16_buf_and_decode;
475 fill_utf16_buf_and_decode(|buf, sz| {
476 libc::GetModuleFileNameW(0u as libc::DWORD, buf, sz)
477 }).map(|s| s.into_strbuf().into_bytes())
478 }
479 }
480
481 load_self().and_then(Path::new_opt)
482 }
483
484 /// Optionally returns the filesystem path to the current executable which is
485 /// running. Like self_exe_name() but without the binary's name.
486 /// If any failure occurs, None is returned.
487 pub fn self_exe_path() -> Option<Path> {
488 self_exe_name().map(|mut p| { p.pop(); p })
489 }
490
491 /**
492 * Returns the path to the user's home directory, if known.
493 *
494 * On Unix, returns the value of the 'HOME' environment variable if it is set
495 * and not equal to the empty string.
496 *
497 * On Windows, returns the value of the 'HOME' environment variable if it is
498 * set and not equal to the empty string. Otherwise, returns the value of the
499 * 'USERPROFILE' environment variable if it is set and not equal to the empty
500 * string.
501 *
502 * Otherwise, homedir returns option::none.
503 */
504 pub fn homedir() -> Option<Path> {
505 // FIXME (#7188): getenv needs a ~[u8] variant
506 return match getenv("HOME") {
507 Some(ref p) if !p.is_empty() => Path::new_opt(p.as_slice()),
508 _ => secondary()
509 };
510
511 #[cfg(unix)]
512 fn secondary() -> Option<Path> {
513 None
514 }
515
516 #[cfg(windows)]
517 fn secondary() -> Option<Path> {
518 getenv("USERPROFILE").and_then(|p| {
519 if !p.is_empty() {
520 Path::new_opt(p)
521 } else {
522 None
523 }
524 })
525 }
526 }
527
528 /**
529 * Returns the path to a temporary directory.
530 *
531 * On Unix, returns the value of the 'TMPDIR' environment variable if it is
532 * set and non-empty and '/tmp' otherwise.
533 * On Android, there is no global temporary folder (it is usually allocated
534 * per-app), hence returns '/data/tmp' which is commonly used.
535 *
536 * On Windows, returns the value of, in order, the 'TMP', 'TEMP',
537 * 'USERPROFILE' environment variable if any are set and not the empty
538 * string. Otherwise, tmpdir returns the path to the Windows directory.
539 */
540 pub fn tmpdir() -> Path {
541 return lookup();
542
543 fn getenv_nonempty(v: &str) -> Option<Path> {
544 match getenv(v) {
545 Some(x) =>
546 if x.is_empty() {
547 None
548 } else {
549 Path::new_opt(x)
550 },
551 _ => None
552 }
553 }
554
555 #[cfg(unix)]
556 fn lookup() -> Path {
557 if cfg!(target_os = "android") {
558 Path::new("/data/tmp")
559 } else {
560 getenv_nonempty("TMPDIR").unwrap_or(Path::new("/tmp"))
561 }
562 }
563
564 #[cfg(windows)]
565 fn lookup() -> Path {
566 getenv_nonempty("TMP").or(
567 getenv_nonempty("TEMP").or(
568 getenv_nonempty("USERPROFILE").or(
569 getenv_nonempty("WINDIR")))).unwrap_or(Path::new("C:\\Windows"))
570 }
571 }
572
573 /**
574 * Convert a relative path to an absolute path
575 *
576 * If the given path is relative, return it prepended with the current working
577 * directory. If the given path is already an absolute path, return it
578 * as is.
579 */
580 // NB: this is here rather than in path because it is a form of environment
581 // querying; what it does depends on the process working directory, not just
582 // the input paths.
583 pub fn make_absolute(p: &Path) -> Path {
584 if p.is_absolute() {
585 p.clone()
586 } else {
587 let mut ret = getcwd();
588 ret.push(p);
589 ret
590 }
591 }
592
593 /// Changes the current working directory to the specified path, returning
594 /// whether the change was completed successfully or not.
595 pub fn change_dir(p: &Path) -> bool {
596 return chdir(p);
597
598 #[cfg(windows)]
599 fn chdir(p: &Path) -> bool {
600 unsafe {
601 use os::win32::as_utf16_p;
602 return as_utf16_p(p.as_str().unwrap(), |buf| {
603 libc::SetCurrentDirectoryW(buf) != (0 as libc::BOOL)
604 });
605 }
606 }
607
608 #[cfg(unix)]
609 fn chdir(p: &Path) -> bool {
610 p.with_c_str(|buf| {
611 unsafe {
612 libc::chdir(buf) == (0 as c_int)
613 }
614 })
615 }
616 }
617
618 #[cfg(unix)]
619 /// Returns the platform-specific value of errno
620 pub fn errno() -> int {
621 #[cfg(target_os = "macos")]
622 #[cfg(target_os = "freebsd")]
623 fn errno_location() -> *c_int {
624 extern {
625 fn __error() -> *c_int;
626 }
627 unsafe {
628 __error()
629 }
630 }
631
632 #[cfg(target_os = "linux")]
633 #[cfg(target_os = "android")]
634 fn errno_location() -> *c_int {
635 extern {
636 fn __errno_location() -> *c_int;
637 }
638 unsafe {
639 __errno_location()
640 }
641 }
642
643 unsafe {
644 (*errno_location()) as int
645 }
646 }
647
648 #[cfg(windows)]
649 /// Returns the platform-specific value of errno
650 pub fn errno() -> uint {
651 use libc::types::os::arch::extra::DWORD;
652
653 #[link_name = "kernel32"]
654 extern "system" {
655 fn GetLastError() -> DWORD;
656 }
657
658 unsafe {
659 GetLastError() as uint
660 }
661 }
662
663 /// Return the string corresponding to an `errno()` value of `errnum`.
664 pub fn error_string(errnum: uint) -> ~str {
665 return strerror(errnum);
666
667 #[cfg(unix)]
668 fn strerror(errnum: uint) -> ~str {
669 #[cfg(target_os = "macos")]
670 #[cfg(target_os = "android")]
671 #[cfg(target_os = "freebsd")]
672 fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: libc::size_t)
673 -> c_int {
674 extern {
675 fn strerror_r(errnum: c_int, buf: *mut c_char,
676 buflen: libc::size_t) -> c_int;
677 }
678 unsafe {
679 strerror_r(errnum, buf, buflen)
680 }
681 }
682
683 // GNU libc provides a non-compliant version of strerror_r by default
684 // and requires macros to instead use the POSIX compliant variant.
685 // So we just use __xpg_strerror_r which is always POSIX compliant
686 #[cfg(target_os = "linux")]
687 fn strerror_r(errnum: c_int, buf: *mut c_char,
688 buflen: libc::size_t) -> c_int {
689 extern {
690 fn __xpg_strerror_r(errnum: c_int,
691 buf: *mut c_char,
692 buflen: libc::size_t)
693 -> c_int;
694 }
695 unsafe {
696 __xpg_strerror_r(errnum, buf, buflen)
697 }
698 }
699
700 let mut buf = [0 as c_char, ..TMPBUF_SZ];
701
702 let p = buf.as_mut_ptr();
703 unsafe {
704 if strerror_r(errnum as c_int, p, buf.len() as libc::size_t) < 0 {
705 fail!("strerror_r failure");
706 }
707
708 str::raw::from_c_str(p as *c_char)
709 }
710 }
711
712 #[cfg(windows)]
713 fn strerror(errnum: uint) -> ~str {
714 use libc::types::os::arch::extra::DWORD;
715 use libc::types::os::arch::extra::LPWSTR;
716 use libc::types::os::arch::extra::LPVOID;
717 use libc::types::os::arch::extra::WCHAR;
718
719 #[link_name = "kernel32"]
720 extern "system" {
721 fn FormatMessageW(flags: DWORD,
722 lpSrc: LPVOID,
723 msgId: DWORD,
724 langId: DWORD,
725 buf: LPWSTR,
726 nsize: DWORD,
727 args: *c_void)
728 -> DWORD;
729 }
730
731 static FORMAT_MESSAGE_FROM_SYSTEM: DWORD = 0x00001000;
732 static FORMAT_MESSAGE_IGNORE_INSERTS: DWORD = 0x00000200;
733
734 // This value is calculated from the macro
735 // MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT)
736 let langId = 0x0800 as DWORD;
737
738 let mut buf = [0 as WCHAR, ..TMPBUF_SZ];
739
740 unsafe {
741 let res = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM |
742 FORMAT_MESSAGE_IGNORE_INSERTS,
743 ptr::mut_null(),
744 errnum as DWORD,
745 langId,
746 buf.as_mut_ptr(),
747 buf.len() as DWORD,
748 ptr::null());
749 if res == 0 {
750 // Sometimes FormatMessageW can fail e.g. system doesn't like langId,
751 let fm_err = errno();
752 return format!("OS Error {} (FormatMessageW() returned error {})", errnum, fm_err);
753 }
754
755 let msg = str::from_utf16(str::truncate_utf16_at_nul(buf));
756 match msg {
757 Some(msg) => format!("OS Error {}: {}", errnum, msg),
758 None => format!("OS Error {} (FormatMessageW() returned invalid UTF-16)", errnum),
759 }
760 }
761 }
762 }
763
764 /// Get a string representing the platform-dependent last error
765 pub fn last_os_error() -> ~str {
766 error_string(errno() as uint)
767 }
768
769 static mut EXIT_STATUS: AtomicInt = INIT_ATOMIC_INT;
770
771 /**
772 * Sets the process exit code
773 *
774 * Sets the exit code returned by the process if all supervised tasks
775 * terminate successfully (without failing). If the current root task fails
776 * and is supervised by the scheduler then any user-specified exit status is
777 * ignored and the process exits with the default failure status.
778 *
779 * Note that this is not synchronized against modifications of other threads.
780 */
781 pub fn set_exit_status(code: int) {
782 unsafe { EXIT_STATUS.store(code, SeqCst) }
783 }
784
785 /// Fetches the process's current exit code. This defaults to 0 and can change
786 /// by calling `set_exit_status`.
787 pub fn get_exit_status() -> int {
788 unsafe { EXIT_STATUS.load(SeqCst) }
789 }
790
791 #[cfg(target_os = "macos")]
792 unsafe fn load_argc_and_argv(argc: int, argv: **c_char) -> Vec<~[u8]> {
793 use c_str::CString;
794
795 Vec::from_fn(argc as uint, |i| {
796 CString::new(*argv.offset(i as int), false).as_bytes_no_nul().to_owned()
797 })
798 }
799
800 /**
801 * Returns the command line arguments
802 *
803 * Returns a list of the command line arguments.
804 */
805 #[cfg(target_os = "macos")]
806 fn real_args_as_bytes() -> Vec<~[u8]> {
807 unsafe {
808 let (argc, argv) = (*_NSGetArgc() as int,
809 *_NSGetArgv() as **c_char);
810 load_argc_and_argv(argc, argv)
811 }
812 }
813
814 #[cfg(target_os = "linux")]
815 #[cfg(target_os = "android")]
816 #[cfg(target_os = "freebsd")]
817 fn real_args_as_bytes() -> Vec<~[u8]> {
818 use rt;
819
820 match rt::args::clone() {
821 Some(args) => args,
822 None => fail!("process arguments not initialized")
823 }
824 }
825
826 #[cfg(not(windows))]
827 fn real_args() -> Vec<~str> {
828 real_args_as_bytes().move_iter().map(|v| str::from_utf8_lossy(v).into_owned()).collect()
829 }
830
831 #[cfg(windows)]
832 fn real_args() -> Vec<~str> {
833 use slice;
834 use option::Expect;
835
836 let mut nArgs: c_int = 0;
837 let lpArgCount: *mut c_int = &mut nArgs;
838 let lpCmdLine = unsafe { GetCommandLineW() };
839 let szArgList = unsafe { CommandLineToArgvW(lpCmdLine, lpArgCount) };
840
841 let args = Vec::from_fn(nArgs as uint, |i| unsafe {
842 // Determine the length of this argument.
843 let ptr = *szArgList.offset(i as int);
844 let mut len = 0;
845 while *ptr.offset(len as int) != 0 { len += 1; }
846
847 // Push it onto the list.
848 let opt_s = slice::raw::buf_as_slice(ptr, len, |buf| {
849 str::from_utf16(str::truncate_utf16_at_nul(buf))
850 });
851 opt_s.expect("CommandLineToArgvW returned invalid UTF-16")
852 });
853
854 unsafe {
855 LocalFree(szArgList as *c_void);
856 }
857
858 return args
859 }
860
861 #[cfg(windows)]
862 fn real_args_as_bytes() -> Vec<~[u8]> {
863 real_args().move_iter().map(|s| s.into_bytes()).collect()
864 }
865
866 type LPCWSTR = *u16;
867
868 #[cfg(windows)]
869 #[link_name="kernel32"]
870 extern "system" {
871 fn GetCommandLineW() -> LPCWSTR;
872 fn LocalFree(ptr: *c_void);
873 }
874
875 #[cfg(windows)]
876 #[link_name="shell32"]
877 extern "system" {
878 fn CommandLineToArgvW(lpCmdLine: LPCWSTR, pNumArgs: *mut c_int) -> **u16;
879 }
880
881 /// Returns the arguments which this program was started with (normally passed
882 /// via the command line).
883 ///
884 /// The arguments are interpreted as utf-8, with invalid bytes replaced with \uFFFD.
885 /// See `str::from_utf8_lossy` for details.
886 pub fn args() -> Vec<~str> {
887 real_args()
888 }
889
890 /// Returns the arguments which this program was started with (normally passed
891 /// via the command line) as byte vectors.
892 pub fn args_as_bytes() -> Vec<~[u8]> {
893 real_args_as_bytes()
894 }
895
896 #[cfg(target_os = "macos")]
897 extern {
898 // These functions are in crt_externs.h.
899 pub fn _NSGetArgc() -> *c_int;
900 pub fn _NSGetArgv() -> ***c_char;
901 }
902
903 // Round up `from` to be divisible by `to`
904 fn round_up(from: uint, to: uint) -> uint {
905 let r = if from % to == 0 {
906 from
907 } else {
908 from + to - (from % to)
909 };
910 if r == 0 {
911 to
912 } else {
913 r
914 }
915 }
916
917 /// Returns the page size of the current architecture in bytes.
918 #[cfg(unix)]
919 pub fn page_size() -> uint {
920 unsafe {
921 libc::sysconf(libc::_SC_PAGESIZE) as uint
922 }
923 }
924
925 /// Returns the page size of the current architecture in bytes.
926 #[cfg(windows)]
927 pub fn page_size() -> uint {
928 use mem;
929 unsafe {
930 let mut info = mem::uninit();
931 libc::GetSystemInfo(&mut info);
932
933 return info.dwPageSize as uint;
934 }
935 }
936
937 /// A memory mapped file or chunk of memory. This is a very system-specific
938 /// interface to the OS's memory mapping facilities (`mmap` on POSIX,
939 /// `VirtualAlloc`/`CreateFileMapping` on win32). It makes no attempt at
940 /// abstracting platform differences, besides in error values returned. Consider
941 /// yourself warned.
942 ///
943 /// The memory map is released (unmapped) when the destructor is run, so don't
944 /// let it leave scope by accident if you want it to stick around.
945 pub struct MemoryMap {
946 /// Pointer to the memory created or modified by this map.
947 pub data: *mut u8,
948 /// Number of bytes this map applies to
949 pub len: uint,
950 /// Type of mapping
951 pub kind: MemoryMapKind,
952 }
953
954 /// Type of memory map
955 pub enum MemoryMapKind {
956 /// Virtual memory map. Usually used to change the permissions of a given
957 /// chunk of memory. Corresponds to `VirtualAlloc` on Windows.
958 MapFile(*u8),
959 /// Virtual memory map. Usually used to change the permissions of a given
960 /// chunk of memory, or for allocation. Corresponds to `VirtualAlloc` on
961 /// Windows.
962 MapVirtual
963 }
964
965 /// Options the memory map is created with
966 pub enum MapOption {
967 /// The memory should be readable
968 MapReadable,
969 /// The memory should be writable
970 MapWritable,
971 /// The memory should be executable
972 MapExecutable,
973 /// Create a map for a specific address range. Corresponds to `MAP_FIXED` on
974 /// POSIX.
975 MapAddr(*u8),
976 /// Create a memory mapping for a file with a given fd.
977 MapFd(c_int),
978 /// When using `MapFd`, the start of the map is `uint` bytes from the start
979 /// of the file.
980 MapOffset(uint),
981 /// On POSIX, this can be used to specify the default flags passed to
982 /// `mmap`. By default it uses `MAP_PRIVATE` and, if not using `MapFd`,
983 /// `MAP_ANON`. This will override both of those. This is platform-specific
984 /// (the exact values used) and ignored on Windows.
985 MapNonStandardFlags(c_int),
986 }
987
988 /// Possible errors when creating a map.
989 pub enum MapError {
990 /// ## The following are POSIX-specific
991 ///
992 /// fd was not open for reading or, if using `MapWritable`, was not open for
993 /// writing.
994 ErrFdNotAvail,
995 /// fd was not valid
996 ErrInvalidFd,
997 /// Either the address given by `MapAddr` or offset given by `MapOffset` was
998 /// not a multiple of `MemoryMap::granularity` (unaligned to page size).
999 ErrUnaligned,
1000 /// With `MapFd`, the fd does not support mapping.
1001 ErrNoMapSupport,
1002 /// If using `MapAddr`, the address + `min_len` was outside of the process's
1003 /// address space. If using `MapFd`, the target of the fd didn't have enough
1004 /// resources to fulfill the request.
1005 ErrNoMem,
1006 /// A zero-length map was requested. This is invalid according to
1007 /// [POSIX](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mmap.html).
1008 /// Not all platforms obey this, but this wrapper does.
1009 ErrZeroLength,
1010 /// Unrecognized error. The inner value is the unrecognized errno.
1011 ErrUnknown(int),
1012 /// ## The following are win32-specific
1013 ///
1014 /// Unsupported combination of protection flags
1015 /// (`MapReadable`/`MapWritable`/`MapExecutable`).
1016 ErrUnsupProt,
1017 /// When using `MapFd`, `MapOffset` was given (Windows does not support this
1018 /// at all)
1019 ErrUnsupOffset,
1020 /// When using `MapFd`, there was already a mapping to the file.
1021 ErrAlreadyExists,
1022 /// Unrecognized error from `VirtualAlloc`. The inner value is the return
1023 /// value of GetLastError.
1024 ErrVirtualAlloc(uint),
1025 /// Unrecognized error from `CreateFileMapping`. The inner value is the
1026 /// return value of `GetLastError`.
1027 ErrCreateFileMappingW(uint),
1028 /// Unrecognized error from `MapViewOfFile`. The inner value is the return
1029 /// value of `GetLastError`.
1030 ErrMapViewOfFile(uint)
1031 }
1032
1033 impl fmt::Show for MapError {
1034 fn fmt(&self, out: &mut fmt::Formatter) -> fmt::Result {
1035 let str = match *self {
1036 ErrFdNotAvail => "fd not available for reading or writing",
1037 ErrInvalidFd => "Invalid fd",
1038 ErrUnaligned => {
1039 "Unaligned address, invalid flags, negative length or \
1040 unaligned offset"
1041 }
1042 ErrNoMapSupport=> "File doesn't support mapping",
1043 ErrNoMem => "Invalid address, or not enough available memory",
1044 ErrUnsupProt => "Protection mode unsupported",
1045 ErrUnsupOffset => "Offset in virtual memory mode is unsupported",
1046 ErrAlreadyExists => "File mapping for specified file already exists",
1047 ErrZeroLength => "Zero-length mapping not allowed",
1048 ErrUnknown(code) => {
1049 return write!(out.buf, "Unknown error = {}", code)
1050 },
1051 ErrVirtualAlloc(code) => {
1052 return write!(out.buf, "VirtualAlloc failure = {}", code)
1053 },
1054 ErrCreateFileMappingW(code) => {
1055 return write!(out.buf, "CreateFileMappingW failure = {}", code)
1056 },
1057 ErrMapViewOfFile(code) => {
1058 return write!(out.buf, "MapViewOfFile failure = {}", code)
1059 }
1060 };
1061 write!(out.buf, "{}", str)
1062 }
1063 }
1064
1065 #[cfg(unix)]
1066 impl MemoryMap {
1067 /// Create a new mapping with the given `options`, at least `min_len` bytes
1068 /// long. `min_len` must be greater than zero; see the note on
1069 /// `ErrZeroLength`.
1070 pub fn new(min_len: uint, options: &[MapOption]) -> Result<MemoryMap, MapError> {
1071 use libc::off_t;
1072 use cmp::Equiv;
1073
1074 if min_len == 0 {
1075 return Err(ErrZeroLength)
1076 }
1077 let mut addr: *u8 = ptr::null();
1078 let mut prot = 0;
1079 let mut flags = libc::MAP_PRIVATE;
1080 let mut fd = -1;
1081 let mut offset = 0;
1082 let mut custom_flags = false;
1083 let len = round_up(min_len, page_size());
1084
1085 for &o in options.iter() {
1086 match o {
1087 MapReadable => { prot |= libc::PROT_READ; },
1088 MapWritable => { prot |= libc::PROT_WRITE; },
1089 MapExecutable => { prot |= libc::PROT_EXEC; },
1090 MapAddr(addr_) => {
1091 flags |= libc::MAP_FIXED;
1092 addr = addr_;
1093 },
1094 MapFd(fd_) => {
1095 flags |= libc::MAP_FILE;
1096 fd = fd_;
1097 },
1098 MapOffset(offset_) => { offset = offset_ as off_t; },
1099 MapNonStandardFlags(f) => { custom_flags = true; flags = f },
1100 }
1101 }
1102 if fd == -1 && !custom_flags { flags |= libc::MAP_ANON; }
1103
1104 let r = unsafe {
1105 libc::mmap(addr as *c_void, len as libc::size_t, prot, flags, fd,
1106 offset)
1107 };
1108 if r.equiv(&libc::MAP_FAILED) {
1109 Err(match errno() as c_int {
1110 libc::EACCES => ErrFdNotAvail,
1111 libc::EBADF => ErrInvalidFd,
1112 libc::EINVAL => ErrUnaligned,
1113 libc::ENODEV => ErrNoMapSupport,
1114 libc::ENOMEM => ErrNoMem,
1115 code => ErrUnknown(code as int)
1116 })
1117 } else {
1118 Ok(MemoryMap {
1119 data: r as *mut u8,
1120 len: len,
1121 kind: if fd == -1 {
1122 MapVirtual
1123 } else {
1124 MapFile(ptr::null())
1125 }
1126 })
1127 }
1128 }
1129
1130 /// Granularity that the offset or address must be for `MapOffset` and
1131 /// `MapAddr` respectively.
1132 pub fn granularity() -> uint {
1133 page_size()
1134 }
1135 }
1136
1137 #[cfg(unix)]
1138 impl Drop for MemoryMap {
1139 /// Unmap the mapping. Fails the task if `munmap` fails.
1140 fn drop(&mut self) {
1141 if self.len == 0 { /* workaround for dummy_stack */ return; }
1142
1143 unsafe {
1144 // FIXME: what to do if this fails?
1145 let _ = libc::munmap(self.data as *c_void, self.len as libc::size_t);
1146 }
1147 }
1148 }
1149
1150 #[cfg(windows)]
1151 impl MemoryMap {
1152 /// Create a new mapping with the given `options`, at least `min_len` bytes long.
1153 pub fn new(min_len: uint, options: &[MapOption]) -> Result<MemoryMap, MapError> {
1154 use libc::types::os::arch::extra::{LPVOID, DWORD, SIZE_T, HANDLE};
1155
1156 let mut lpAddress: LPVOID = ptr::mut_null();
1157 let mut readable = false;
1158 let mut writable = false;
1159 let mut executable = false;
1160 let mut fd: c_int = -1;
1161 let mut offset: uint = 0;
1162 let len = round_up(min_len, page_size());
1163
1164 for &o in options.iter() {
1165 match o {
1166 MapReadable => { readable = true; },
1167 MapWritable => { writable = true; },
1168 MapExecutable => { executable = true; }
1169 MapAddr(addr_) => { lpAddress = addr_ as LPVOID; },
1170 MapFd(fd_) => { fd = fd_; },
1171 MapOffset(offset_) => { offset = offset_; },
1172 MapNonStandardFlags(..) => {}
1173 }
1174 }
1175
1176 let flProtect = match (executable, readable, writable) {
1177 (false, false, false) if fd == -1 => libc::PAGE_NOACCESS,
1178 (false, true, false) => libc::PAGE_READONLY,
1179 (false, true, true) => libc::PAGE_READWRITE,
1180 (true, false, false) if fd == -1 => libc::PAGE_EXECUTE,
1181 (true, true, false) => libc::PAGE_EXECUTE_READ,
1182 (true, true, true) => libc::PAGE_EXECUTE_READWRITE,
1183 _ => return Err(ErrUnsupProt)
1184 };
1185
1186 if fd == -1 {
1187 if offset != 0 {
1188 return Err(ErrUnsupOffset);
1189 }
1190 let r = unsafe {
1191 libc::VirtualAlloc(lpAddress,
1192 len as SIZE_T,
1193 libc::MEM_COMMIT | libc::MEM_RESERVE,
1194 flProtect)
1195 };
1196 match r as uint {
1197 0 => Err(ErrVirtualAlloc(errno())),
1198 _ => Ok(MemoryMap {
1199 data: r as *mut u8,
1200 len: len,
1201 kind: MapVirtual
1202 })
1203 }
1204 } else {
1205 let dwDesiredAccess = match (executable, readable, writable) {
1206 (false, true, false) => libc::FILE_MAP_READ,
1207 (false, true, true) => libc::FILE_MAP_WRITE,
1208 (true, true, false) => libc::FILE_MAP_READ | libc::FILE_MAP_EXECUTE,
1209 (true, true, true) => libc::FILE_MAP_WRITE | libc::FILE_MAP_EXECUTE,
1210 _ => return Err(ErrUnsupProt) // Actually, because of the check above,
1211 // we should never get here.
1212 };
1213 unsafe {
1214 let hFile = libc::get_osfhandle(fd) as HANDLE;
1215 let mapping = libc::CreateFileMappingW(hFile,
1216 ptr::mut_null(),
1217 flProtect,
1218 0,
1219 0,
1220 ptr::null());
1221 if mapping == ptr::mut_null() {
1222 return Err(ErrCreateFileMappingW(errno()));
1223 }
1224 if errno() as c_int == libc::ERROR_ALREADY_EXISTS {
1225 return Err(ErrAlreadyExists);
1226 }
1227 let r = libc::MapViewOfFile(mapping,
1228 dwDesiredAccess,
1229 ((len as u64) >> 32) as DWORD,
1230 (offset & 0xffff_ffff) as DWORD,
1231 0);
1232 match r as uint {
1233 0 => Err(ErrMapViewOfFile(errno())),
1234 _ => Ok(MemoryMap {
1235 data: r as *mut u8,
1236 len: len,
1237 kind: MapFile(mapping as *u8)
1238 })
1239 }
1240 }
1241 }
1242 }
1243
1244 /// Granularity of MapAddr() and MapOffset() parameter values.
1245 /// This may be greater than the value returned by page_size().
1246 pub fn granularity() -> uint {
1247 use mem;
1248 unsafe {
1249 let mut info = mem::uninit();
1250 libc::GetSystemInfo(&mut info);
1251
1252 return info.dwAllocationGranularity as uint;
1253 }
1254 }
1255 }
1256
1257 #[cfg(windows)]
1258 impl Drop for MemoryMap {
1259 /// Unmap the mapping. Fails the task if any of `VirtualFree`,
1260 /// `UnmapViewOfFile`, or `CloseHandle` fail.
1261 fn drop(&mut self) {
1262 use libc::types::os::arch::extra::{LPCVOID, HANDLE};
1263 use libc::consts::os::extra::FALSE;
1264 if self.len == 0 { return }
1265
1266 unsafe {
1267 match self.kind {
1268 MapVirtual => {
1269 if libc::VirtualFree(self.data as *mut c_void, 0,
1270 libc::MEM_RELEASE) == 0 {
1271 println!("VirtualFree failed: {}", errno());
1272 }
1273 },
1274 MapFile(mapping) => {
1275 if libc::UnmapViewOfFile(self.data as LPCVOID) == FALSE {
1276 println!("UnmapViewOfFile failed: {}", errno());
1277 }
1278 if libc::CloseHandle(mapping as HANDLE) == FALSE {
1279 println!("CloseHandle failed: {}", errno());
1280 }
1281 }
1282 }
1283 }
1284 }
1285 }
1286
1287 #[cfg(target_os = "linux")]
1288 pub mod consts {
1289 pub use std::os::arch_consts::ARCH;
1290
1291 pub static FAMILY: &'static str = "unix";
1292
1293 /// A string describing the specific operating system in use: in this
1294 /// case, `linux`.
1295 pub static SYSNAME: &'static str = "linux";
1296
1297 /// Specifies the filename prefix used for shared libraries on this
1298 /// platform: in this case, `lib`.
1299 pub static DLL_PREFIX: &'static str = "lib";
1300
1301 /// Specifies the filename suffix used for shared libraries on this
1302 /// platform: in this case, `.so`.
1303 pub static DLL_SUFFIX: &'static str = ".so";
1304
1305 /// Specifies the file extension used for shared libraries on this
1306 /// platform that goes after the dot: in this case, `so`.
1307 pub static DLL_EXTENSION: &'static str = "so";
1308
1309 /// Specifies the filename suffix used for executable binaries on this
1310 /// platform: in this case, the empty string.
1311 pub static EXE_SUFFIX: &'static str = "";
1312
1313 /// Specifies the file extension, if any, used for executable binaries
1314 /// on this platform: in this case, the empty string.
1315 pub static EXE_EXTENSION: &'static str = "";
1316 }
1317
1318 #[cfg(target_os = "macos")]
1319 pub mod consts {
1320 pub use std::os::arch_consts::ARCH;
1321
1322 pub static FAMILY: &'static str = "unix";
1323
1324 /// A string describing the specific operating system in use: in this
1325 /// case, `macos`.
1326 pub static SYSNAME: &'static str = "macos";
1327
1328 /// Specifies the filename prefix used for shared libraries on this
1329 /// platform: in this case, `lib`.
1330 pub static DLL_PREFIX: &'static str = "lib";
1331
1332 /// Specifies the filename suffix used for shared libraries on this
1333 /// platform: in this case, `.dylib`.
1334 pub static DLL_SUFFIX: &'static str = ".dylib";
1335
1336 /// Specifies the file extension used for shared libraries on this
1337 /// platform that goes after the dot: in this case, `dylib`.
1338 pub static DLL_EXTENSION: &'static str = "dylib";
1339
1340 /// Specifies the filename suffix used for executable binaries on this
1341 /// platform: in this case, the empty string.
1342 pub static EXE_SUFFIX: &'static str = "";
1343
1344 /// Specifies the file extension, if any, used for executable binaries
1345 /// on this platform: in this case, the empty string.
1346 pub static EXE_EXTENSION: &'static str = "";
1347 }
1348
1349 #[cfg(target_os = "freebsd")]
1350 pub mod consts {
1351 pub use std::os::arch_consts::ARCH;
1352
1353 pub static FAMILY: &'static str = "unix";
1354
1355 /// A string describing the specific operating system in use: in this
1356 /// case, `freebsd`.
1357 pub static SYSNAME: &'static str = "freebsd";
1358
1359 /// Specifies the filename prefix used for shared libraries on this
1360 /// platform: in this case, `lib`.
1361 pub static DLL_PREFIX: &'static str = "lib";
1362
1363 /// Specifies the filename suffix used for shared libraries on this
1364 /// platform: in this case, `.so`.
1365 pub static DLL_SUFFIX: &'static str = ".so";
1366
1367 /// Specifies the file extension used for shared libraries on this
1368 /// platform that goes after the dot: in this case, `so`.
1369 pub static DLL_EXTENSION: &'static str = "so";
1370
1371 /// Specifies the filename suffix used for executable binaries on this
1372 /// platform: in this case, the empty string.
1373 pub static EXE_SUFFIX: &'static str = "";
1374
1375 /// Specifies the file extension, if any, used for executable binaries
1376 /// on this platform: in this case, the empty string.
1377 pub static EXE_EXTENSION: &'static str = "";
1378 }
1379
1380 #[cfg(target_os = "android")]
1381 pub mod consts {
1382 pub use std::os::arch_consts::ARCH;
1383
1384 pub static FAMILY: &'static str = "unix";
1385
1386 /// A string describing the specific operating system in use: in this
1387 /// case, `android`.
1388 pub static SYSNAME: &'static str = "android";
1389
1390 /// Specifies the filename prefix used for shared libraries on this
1391 /// platform: in this case, `lib`.
1392 pub static DLL_PREFIX: &'static str = "lib";
1393
1394 /// Specifies the filename suffix used for shared libraries on this
1395 /// platform: in this case, `.so`.
1396 pub static DLL_SUFFIX: &'static str = ".so";
1397
1398 /// Specifies the file extension used for shared libraries on this
1399 /// platform that goes after the dot: in this case, `so`.
1400 pub static DLL_EXTENSION: &'static str = "so";
1401
1402 /// Specifies the filename suffix used for executable binaries on this
1403 /// platform: in this case, the empty string.
1404 pub static EXE_SUFFIX: &'static str = "";
1405
1406 /// Specifies the file extension, if any, used for executable binaries
1407 /// on this platform: in this case, the empty string.
1408 pub static EXE_EXTENSION: &'static str = "";
1409 }
1410
1411 #[cfg(target_os = "win32")]
1412 pub mod consts {
1413 pub use std::os::arch_consts::ARCH;
1414
1415 pub static FAMILY: &'static str = "windows";
1416
1417 /// A string describing the specific operating system in use: in this
1418 /// case, `win32`.
1419 pub static SYSNAME: &'static str = "win32";
1420
1421 /// Specifies the filename prefix used for shared libraries on this
1422 /// platform: in this case, the empty string.
1423 pub static DLL_PREFIX: &'static str = "";
1424
1425 /// Specifies the filename suffix used for shared libraries on this
1426 /// platform: in this case, `.dll`.
1427 pub static DLL_SUFFIX: &'static str = ".dll";
1428
1429 /// Specifies the file extension used for shared libraries on this
1430 /// platform that goes after the dot: in this case, `dll`.
1431 pub static DLL_EXTENSION: &'static str = "dll";
1432
1433 /// Specifies the filename suffix used for executable binaries on this
1434 /// platform: in this case, `.exe`.
1435 pub static EXE_SUFFIX: &'static str = ".exe";
1436
1437 /// Specifies the file extension, if any, used for executable binaries
1438 /// on this platform: in this case, `exe`.
1439 pub static EXE_EXTENSION: &'static str = "exe";
1440 }
1441
1442 #[cfg(target_arch = "x86")]
1443 mod arch_consts {
1444 pub static ARCH: &'static str = "x86";
1445 }
1446
1447 #[cfg(target_arch = "x86_64")]
1448 mod arch_consts {
1449 pub static ARCH: &'static str = "x86_64";
1450 }
1451
1452 #[cfg(target_arch = "arm")]
1453 mod arch_consts {
1454 pub static ARCH: &'static str = "arm";
1455 }
1456
1457 #[cfg(target_arch = "mips")]
1458 mod arch_consts {
1459 pub static ARCH: &'static str = "mips";
1460 }
1461
1462
1463 #[cfg(test)]
1464 mod tests {
1465 use prelude::*;
1466 use c_str::ToCStr;
1467 use option;
1468 use os::{env, getcwd, getenv, make_absolute, args};
1469 use os::{setenv, unsetenv};
1470 use os;
1471 use rand::Rng;
1472 use rand;
1473
1474 #[test]
1475 pub fn last_os_error() {
1476 debug!("{}", os::last_os_error());
1477 }
1478
1479 #[test]
1480 pub fn test_args() {
1481 let a = args();
1482 assert!(a.len() >= 1);
1483 }
1484
1485 fn make_rand_name() -> ~str {
1486 let mut rng = rand::task_rng();
1487 let n = "TEST".to_owned() + rng.gen_ascii_str(10u);
1488 assert!(getenv(n).is_none());
1489 n
1490 }
1491
1492 #[test]
1493 fn test_setenv() {
1494 let n = make_rand_name();
1495 setenv(n, "VALUE");
1496 assert_eq!(getenv(n), option::Some("VALUE".to_owned()));
1497 }
1498
1499 #[test]
1500 fn test_unsetenv() {
1501 let n = make_rand_name();
1502 setenv(n, "VALUE");
1503 unsetenv(n);
1504 assert_eq!(getenv(n), option::None);
1505 }
1506
1507 #[test]
1508 #[ignore]
1509 fn test_setenv_overwrite() {
1510 let n = make_rand_name();
1511 setenv(n, "1");
1512 setenv(n, "2");
1513 assert_eq!(getenv(n), option::Some("2".to_owned()));
1514 setenv(n, "");
1515 assert_eq!(getenv(n), option::Some("".to_owned()));
1516 }
1517
1518 // Windows GetEnvironmentVariable requires some extra work to make sure
1519 // the buffer the variable is copied into is the right size
1520 #[test]
1521 #[ignore]
1522 fn test_getenv_big() {
1523 let mut s = "".to_owned();
1524 let mut i = 0;
1525 while i < 100 {
1526 s = s + "aaaaaaaaaa";
1527 i += 1;
1528 }
1529 let n = make_rand_name();
1530 setenv(n, s);
1531 debug!("{}", s.clone());
1532 assert_eq!(getenv(n), option::Some(s));
1533 }
1534
1535 #[test]
1536 fn test_self_exe_name() {
1537 let path = os::self_exe_name();
1538 assert!(path.is_some());
1539 let path = path.unwrap();
1540 debug!("{:?}", path.clone());
1541
1542 // Hard to test this function
1543 assert!(path.is_absolute());
1544 }
1545
1546 #[test]
1547 fn test_self_exe_path() {
1548 let path = os::self_exe_path();
1549 assert!(path.is_some());
1550 let path = path.unwrap();
1551 debug!("{:?}", path.clone());
1552
1553 // Hard to test this function
1554 assert!(path.is_absolute());
1555 }
1556
1557 #[test]
1558 #[ignore]
1559 fn test_env_getenv() {
1560 let e = env();
1561 assert!(e.len() > 0u);
1562 for p in e.iter() {
1563 let (n, v) = (*p).clone();
1564 debug!("{:?}", n.clone());
1565 let v2 = getenv(n);
1566 // MingW seems to set some funky environment variables like
1567 // "=C:=C:\MinGW\msys\1.0\bin" and "!::=::\" that are returned
1568 // from env() but not visible from getenv().
1569 assert!(v2.is_none() || v2 == option::Some(v));
1570 }
1571 }
1572
1573 #[test]
1574 fn test_env_set_get_huge() {
1575 let n = make_rand_name();
1576 let s = "x".repeat(10000);
1577 setenv(n, s);
1578 assert_eq!(getenv(n), Some(s));
1579 unsetenv(n);
1580 assert_eq!(getenv(n), None);
1581 }
1582
1583 #[test]
1584 fn test_env_setenv() {
1585 let n = make_rand_name();
1586
1587 let mut e = env();
1588 setenv(n, "VALUE");
1589 assert!(!e.contains(&(n.clone(), "VALUE".to_owned())));
1590
1591 e = env();
1592 assert!(e.contains(&(n, "VALUE".to_owned())));
1593 }
1594
1595 #[test]
1596 fn test() {
1597 assert!((!Path::new("test-path").is_absolute()));
1598
1599 let cwd = getcwd();
1600 debug!("Current working directory: {}", cwd.display());
1601
1602 debug!("{:?}", make_absolute(&Path::new("test-path")));
1603 debug!("{:?}", make_absolute(&Path::new("/usr/bin")));
1604 }
1605
1606 #[test]
1607 #[cfg(unix)]
1608 fn homedir() {
1609 let oldhome = getenv("HOME");
1610
1611 setenv("HOME", "/home/MountainView");
1612 assert!(os::homedir() == Some(Path::new("/home/MountainView")));
1613
1614 setenv("HOME", "");
1615 assert!(os::homedir().is_none());
1616
1617 for s in oldhome.iter() { setenv("HOME", *s) }
1618 }
1619
1620 #[test]
1621 #[cfg(windows)]
1622 fn homedir() {
1623
1624 let oldhome = getenv("HOME");
1625 let olduserprofile = getenv("USERPROFILE");
1626
1627 setenv("HOME", "");
1628 setenv("USERPROFILE", "");
1629
1630 assert!(os::homedir().is_none());
1631
1632 setenv("HOME", "/home/MountainView");
1633 assert!(os::homedir() == Some(Path::new("/home/MountainView")));
1634
1635 setenv("HOME", "");
1636
1637 setenv("USERPROFILE", "/home/MountainView");
1638 assert!(os::homedir() == Some(Path::new("/home/MountainView")));
1639
1640 setenv("HOME", "/home/MountainView");
1641 setenv("USERPROFILE", "/home/PaloAlto");
1642 assert!(os::homedir() == Some(Path::new("/home/MountainView")));
1643
1644 for s in oldhome.iter() { setenv("HOME", *s) }
1645 for s in olduserprofile.iter() { setenv("USERPROFILE", *s) }
1646 }
1647
1648 #[test]
1649 fn memory_map_rw() {
1650 use result::{Ok, Err};
1651
1652 let chunk = match os::MemoryMap::new(16, [
1653 os::MapReadable,
1654 os::MapWritable
1655 ]) {
1656 Ok(chunk) => chunk,
1657 Err(msg) => fail!("{}", msg)
1658 };
1659 assert!(chunk.len >= 16);
1660
1661 unsafe {
1662 *chunk.data = 0xBE;
1663 assert!(*chunk.data == 0xBE);
1664 }
1665 }
1666
1667 #[test]
1668 fn memory_map_file() {
1669 use result::{Ok, Err};
1670 use os::*;
1671 use libc::*;
1672 use io::fs;
1673
1674 #[cfg(unix)]
1675 fn lseek_(fd: c_int, size: uint) {
1676 unsafe {
1677 assert!(lseek(fd, size as off_t, SEEK_SET) == size as off_t);
1678 }
1679 }
1680 #[cfg(windows)]
1681 fn lseek_(fd: c_int, size: uint) {
1682 unsafe {
1683 assert!(lseek(fd, size as c_long, SEEK_SET) == size as c_long);
1684 }
1685 }
1686
1687 let mut path = tmpdir();
1688 path.push("mmap_file.tmp");
1689 let size = MemoryMap::granularity() * 2;
1690
1691 let fd = unsafe {
1692 let fd = path.with_c_str(|path| {
1693 open(path, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR)
1694 });
1695 lseek_(fd, size);
1696 "x".with_c_str(|x| assert!(write(fd, x as *c_void, 1) == 1));
1697 fd
1698 };
1699 let chunk = match MemoryMap::new(size / 2, [
1700 MapReadable,
1701 MapWritable,
1702 MapFd(fd),
1703 MapOffset(size / 2)
1704 ]) {
1705 Ok(chunk) => chunk,
1706 Err(msg) => fail!("{}", msg)
1707 };
1708 assert!(chunk.len > 0);
1709
1710 unsafe {
1711 *chunk.data = 0xbe;
1712 assert!(*chunk.data == 0xbe);
1713 close(fd);
1714 }
1715 drop(chunk);
1716
1717 fs::unlink(&path).unwrap();
1718 }
1719
1720 // More recursive_mkdir tests are in extra::tempfile
1721 }
libstd/os.rs:261:40-261:40 -fn- definition:
/// Fails if `n` has any interior NULs.
pub fn getenv_as_bytes(n: &str) -> Option<~[u8]> {
use c_str::CString;
references:- 2libstd/unstable/dynamic_lib.rs:
77: };
78: let newenv = os::getenv_as_bytes(envvar).unwrap_or(box []);
79: let mut newenv = newenv.move_iter().collect::<Vec<_>>();
libstd/os.rs:
251: pub fn getenv(n: &str) -> Option<~str> {
252: getenv_as_bytes(n).map(|v| str::from_utf8_lossy(v).into_owned())
253: }
libstd/os.rs:816:30-816:30 -fn- definition:
fn real_args_as_bytes() -> Vec<~[u8]> {
use rt;
match rt::args::clone() {
references:- 2827: fn real_args() -> Vec<~str> {
828: real_args_as_bytes().move_iter().map(|v| str::from_utf8_lossy(v).into_owned()).collect()
829: }
--
892: pub fn args_as_bytes() -> Vec<~[u8]> {
893: real_args_as_bytes()
894: }
libstd/os.rs:155:3-155:3 -fn- definition:
*/
fn with_env_lock<T>(f: || -> T) -> T {
use unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
references:- 4345: unsafe {
346: with_env_lock(|| {
347: n.with_c_str(|nbuf| {
libstd/os.rs:619:49-619:49 -fn- definition:
/// Returns the platform-specific value of errno
pub fn errno() -> int {
#[cfg(target_os = "macos")]
references:- 31108: if r.equiv(&libc::MAP_FAILED) {
1109: Err(match errno() as c_int {
1110: libc::EACCES => ErrFdNotAvail,
libstd/io/mod.rs:
383: pub fn last_error() -> IoError {
384: IoError::from_errno(os::errno() as uint, true)
385: }
libstd/os.rs:663:71-663:71 -fn- definition:
/// Return the string corresponding to an `errno()` value of `errnum`.
pub fn error_string(errnum: uint) -> ~str {
return strerror(errnum);
references:- 2libstd/io/mod.rs:
372: desc: desc,
373: detail: if detail {Some(os::error_string(errno))} else {None},
374: }
libstd/os.rs:
765: pub fn last_os_error() -> ~str {
766: error_string(errno() as uint)
767: }
libstd/os.rs:918:13-918:13 -fn- definition:
pub fn page_size() -> uint {
unsafe {
libc::sysconf(libc::_SC_PAGESIZE) as uint
references:- 31082: let mut custom_flags = false;
1083: let len = round_up(min_len, page_size());
libstd/rt/thread.rs:
246: // Round up to the neareast page and try again.
247: let page_size = os::page_size();
248: let stack_size = (stack_size + page_size - 1) & (-(page_size - 1) - 1);
libstd/os.rs:
1132: pub fn granularity() -> uint {
1133: page_size()
1134: }
libstd/os.rs:368:35-368:35 -struct- definition:
/// A low-level OS in-memory pipe.
pub struct Pipe {
/// A file descriptor representing the reading end of the pipe. Data written
references:- 3381: unsafe {
382: let mut fds = Pipe {input: 0,
383: out: 0};
384: assert_eq!(libc::pipe(&mut fds.input), 0);
385: return Pipe {input: fds.input, out: fds.out};
386: }
libstd/os.rs:66:13-66:13 -fn- definition:
pub fn getcwd() -> Path {
use c_str::CString;
let mut buf = [0 as c_char, ..BUF_BYTES];
references:- 2libstd/io/test.rs:
114: // FIXME (#9639): This needs to handle non-utf8 paths
115: let path = os::getcwd();
116: let path_s = path.as_str().unwrap();
libstd/os.rs:
586: } else {
587: let mut ret = getcwd();
588: ret.push(p);
libstd/os.rs:988:41-988:41 -enum- definition:
/// Possible errors when creating a map.
pub enum MapError {
/// ## The following are POSIX-specific
references:- 21033: impl fmt::Show for MapError {
1034: fn fmt(&self, out: &mut fmt::Formatter) -> fmt::Result {
--
1069: /// `ErrZeroLength`.
1070: pub fn new(min_len: uint, options: &[MapOption]) -> Result<MemoryMap, MapError> {
1071: use libc::off_t;
libstd/os.rs:944:67-944:67 -struct- definition:
/// let it leave scope by accident if you want it to stick around.
pub struct MemoryMap {
/// Pointer to the memory created or modified by this map.
references:- 41117: } else {
1118: Ok(MemoryMap {
1119: data: r as *mut u8,
--
1138: impl Drop for MemoryMap {
1139: /// Unmap the mapping. Fails the task if `munmap` fails.
libstd/os.rs:764:64-764:64 -fn- definition:
/// Get a string representing the platform-dependent last error
pub fn last_os_error() -> ~str {
error_string(errno() as uint)
references:- 3213: fail!("os::env() failure getting env string from OS: {}",
214: os::last_os_error());
215: }
libstd/rt/thread.rs:
252: // This cannot really happen.
253: fail!("pthread_attr_setstacksize() error: {} ({})", os::last_os_error(), errno);
254: },
--
263: let _p: Box<proc():Send> = cast::transmute(arg);
264: fail!("failed to spawn native thread: {}", os::last_os_error());
265: }
libstd/os.rs:539:4-539:4 -fn- definition:
*/
pub fn tmpdir() -> Path {
return lookup();
references:- 2libstd/io/tempfile.rs:
62: pub fn new(suffix: &str) -> Option<TempDir> {
63: TempDir::new_in(&os::tmpdir(), suffix)
64: }
libstd/io/test.rs:
74: if cfg!(unix) {
75: os::tmpdir().join(string)
76: } else {
libstd/os.rs:415:54-415:54 -fn- definition:
/// running. If any failure occurs, None is returned.
pub fn self_exe_name() -> Option<Path> {
#[cfg(target_os = "freebsd")]
references:- 2487: pub fn self_exe_path() -> Option<Path> {
488: self_exe_name().map(|mut p| { p.pop(); p })
489: }
libstd/rt/backtrace.rs:
428: let selfname = if cfg!(target_os = "freebsd") {
429: os::self_exe_name()
430: } else {
libstd/os.rs:250:40-250:40 -fn- definition:
/// Fails if `n` has any interior NULs.
pub fn getenv(n: &str) -> Option<~str> {
getenv_as_bytes(n).map(|v| str::from_utf8_lossy(v).into_owned())
references:- 7543: fn getenv_nonempty(v: &str) -> Option<Path> {
544: match getenv(v) {
545: Some(x) =>
libstd/rt/env.rs:
33: }
34: match os::getenv("RUST_MAX_CACHED_STACKS") {
35: Some(max) => MAX_CACHED_STACKS = from_str(max).expect("expected positive integer in \
--
38: }
39: match os::getenv("RUST_DEBUG_BORROW") {
40: Some(_) => DEBUG_BORROW = true,
libstd/rt/backtrace.rs:
40: let val = match os::getenv("RUST_BACKTRACE") {
41: Some(..) => 2,
libstd/rt/util.rs:
55: pub fn default_sched_threads() -> uint {
56: match os::getenv("RUST_THREADS") {
57: Some(nstr) => {
libstd/os.rs:
505: // FIXME (#7188): getenv needs a ~[u8] variant
506: return match getenv("HOME") {
507: Some(ref p) if !p.is_empty() => Path::new_opt(p.as_slice()),