os.rs 46.2 KB
Newer Older
1
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2 3 4 5 6 7 8 9 10
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
/*!
 * Higher-level interfaces to libc::* functions and operating system services.
 *
 * In general these take and return rust types, use rust idioms (enums,
 * closures, vectors) rather than C idioms, and do more extensive safety
 * checks.
 *
 * This module is not meant to only contain 1:1 mappings to libc entries; any
 * os-interface code that is reasonably useful and broadly applicable can go
 * here. Including utility routines that merely build on other os code.
 *
 * We assume the general case is that users do not care, and do not want to
 * be made to care, which operating system they are on. While they may want
 * to special case various special cases -- and so we will not _hide_ the
 * facts of which OS the user is on -- they should be given the opportunity
 * to write OS-ignorant code by default.
 */
28

29 30
#[allow(missing_doc)];

31
use clone::Clone;
32
use container::Container;
K
Kiet Tran 已提交
33
#[cfg(target_os = "macos")]
34
use iter::range;
35
use libc;
A
Alex Crichton 已提交
36
use libc::{c_char, c_void, c_int};
P
Patrick Walton 已提交
37
use option::{Some, None};
38
use os;
39
use prelude::*;
40 41
use ptr;
use str;
42
use fmt;
43
use unstable::finally::Finally;
44
use sync::atomics::{AtomicInt, INIT_ATOMIC_INT, SeqCst};
45

46
/// Delegates to the libc close() function, returning the same return value.
47
pub fn close(fd: int) -> int {
48
    unsafe {
49
        libc::close(fd as c_int) as int
50 51 52
    }
}

53 54
pub static TMPBUF_SZ : uint = 1000u;
static BUF_BYTES : uint = 2048u;
55

56
#[cfg(unix)]
57
pub fn getcwd() -> Path {
58 59
    use c_str::CString;

60
    let mut buf = [0 as c_char, ..BUF_BYTES];
61
    unsafe {
A
Alex Crichton 已提交
62
        if libc::getcwd(buf.as_mut_ptr(), buf.len() as libc::size_t).is_null() {
63
            fail!()
64
        }
65 66
        Path::new(CString::new(buf.as_ptr(), false))
    }
67 68
}

69 70 71 72 73
#[cfg(windows)]
pub fn getcwd() -> Path {
    use libc::DWORD;
    use libc::GetCurrentDirectoryW;
    let mut buf = [0 as u16, ..BUF_BYTES];
74 75 76
    unsafe {
        if libc::GetCurrentDirectoryW(buf.len() as DWORD, buf.as_mut_ptr()) == 0 as DWORD {
            fail!();
77
        }
78
    }
79
    Path::new(str::from_utf16(buf))
80 81
}

82
#[cfg(windows)]
83
pub mod win32 {
84
    use libc::types::os::arch::extra::DWORD;
85
    use libc;
86
    use option::{None, Option};
87
    use option;
88
    use os::TMPBUF_SZ;
89 90 91 92
    use str::StrSlice;
    use str;
    use vec::{MutableVector, ImmutableVector, OwnedVector};
    use vec;
93

94
    pub fn fill_utf16_buf_and_decode(f: |*mut u16, DWORD| -> DWORD)
B
Brian Anderson 已提交
95
        -> Option<~str> {
96

97
        unsafe {
98
            let mut n = TMPBUF_SZ as DWORD;
99 100 101
            let mut res = None;
            let mut done = false;
            while !done {
102
                let mut buf = vec::from_elem(n as uint, 0u16);
103 104 105
                let k = f(buf.as_mut_ptr(), TMPBUF_SZ as DWORD);
                if k == (0 as DWORD) {
                    done = true;
H
Huon Wilson 已提交
106 107 108
                } else if k == n &&
                          libc::GetLastError() ==
                          libc::ERROR_INSUFFICIENT_BUFFER as DWORD {
109 110 111 112
                    n *= (2 as DWORD);
                } else {
                    done = true;
                }
113
                if k != 0 && done {
114
                    let sub = buf.slice(0, k as uint);
115 116
                    res = option::Some(str::from_utf16(sub));
                }
117
            }
118
            return res;
119 120 121
        }
    }

122
    pub fn as_utf16_p<T>(s: &str, f: |*u16| -> T) -> T {
123
        let mut t = s.to_utf16();
124
        // Null terminate before passing on.
125
        t.push(0u16);
126
        f(t.as_ptr())
127
    }
128 129
}

130 131
/*
Accessing environment variables is not generally threadsafe.
132
Serialize access through a global lock.
133
*/
134
fn with_env_lock<T>(f: || -> T) -> T {
135
    use unstable::mutex::{Mutex, MUTEX_INIT};
136
    use unstable::finally::Finally;
137

138 139
    static mut lock: Mutex = MUTEX_INIT;

140
    unsafe {
141
        return (|| {
142
            lock.lock();
143
            f()
144
        }).finally(|| lock.unlock());
145
    }
B
Ben Blum 已提交
146 147
}

148 149
/// Returns a vector of (variable, value) pairs for all the environment
/// variables of the current process.
150 151
pub fn env() -> ~[(~str,~str)] {
    unsafe {
152 153
        #[cfg(windows)]
        unsafe fn get_env_pairs() -> ~[~str] {
A
Alex Crichton 已提交
154 155
            use c_str;
            use str::StrSlice;
156

157 158 159 160 161
            use libc::funcs::extra::kernel32::{
                GetEnvironmentStringsA,
                FreeEnvironmentStringsA
            };
            let ch = GetEnvironmentStringsA();
H
Huon Wilson 已提交
162
            if ch as uint == 0 {
163
                fail!("os::env() failure getting env string from OS: {}",
A
Alex Crichton 已提交
164
                       os::last_os_error());
165
            }
A
Alex Crichton 已提交
166
            let mut result = ~[];
167
            c_str::from_c_multistring(ch as *c_char, None, |cstr| {
A
Alex Crichton 已提交
168
                result.push(cstr.as_str().unwrap().to_owned());
169
            });
170 171 172 173 174
            FreeEnvironmentStringsA(ch);
            result
        }
        #[cfg(unix)]
        unsafe fn get_env_pairs() -> ~[~str] {
175
            extern {
176
                fn rust_env_pairs() -> **c_char;
177
            }
178
            let environ = rust_env_pairs();
H
Huon Wilson 已提交
179
            if environ as uint == 0 {
180
                fail!("os::env() failure getting env string from OS: {}",
A
Alex Crichton 已提交
181
                       os::last_os_error());
182 183 184 185
            }
            let mut result = ~[];
            ptr::array_each(environ, |e| {
                let env_pair = str::raw::from_c_str(e);
186
                debug!("get_env_pairs: {}", env_pair);
187 188 189 190 191 192
                result.push(env_pair);
            });
            result
        }

        fn env_convert(input: ~[~str]) -> ~[(~str, ~str)] {
193
            let mut pairs = ~[];
D
Daniel Micay 已提交
194
            for p in input.iter() {
195
                let vs: ~[&str] = p.splitn('=', 1).collect();
196
                debug!("splitting: len: {}", vs.len());
197
                assert_eq!(vs.len(), 2);
198
                pairs.push((vs[0].to_owned(), vs[1].to_owned()));
199
            }
L
Luqman Aden 已提交
200
            pairs
201
        }
202
        with_env_lock(|| {
203 204
            let unparsed_environ = get_env_pairs();
            env_convert(unparsed_environ)
205
        })
206
    }
207
}
208

209
#[cfg(unix)]
210 211
/// Fetches the environment variable `n` from the current process, returning
/// None if the variable isn't set.
212 213
pub fn getenv(n: &str) -> Option<~str> {
    unsafe {
214 215
        with_env_lock(|| {
            let s = n.with_c_str(|buf| libc::getenv(buf));
216
            if s.is_null() {
217
                None
218
            } else {
219
                Some(str::raw::from_c_str(s))
220
            }
221
        })
222 223
    }
}
224

225
#[cfg(windows)]
226 227
/// Fetches the environment variable `n` from the current process, returning
/// None if the variable isn't set.
228 229
pub fn getenv(n: &str) -> Option<~str> {
    unsafe {
230
        with_env_lock(|| {
231
            use os::win32::{as_utf16_p, fill_utf16_buf_and_decode};
232 233
            as_utf16_p(n, |u| {
                fill_utf16_buf_and_decode(|buf, sz| {
234
                    libc::GetEnvironmentVariableW(u, buf, sz)
235 236 237
                })
            })
        })
238 239
    }
}
240 241


242
#[cfg(unix)]
243 244
/// Sets the environment variable `n` to the value `v` for the currently running
/// process
245 246
pub fn setenv(n: &str, v: &str) {
    unsafe {
247 248 249
        with_env_lock(|| {
            n.with_c_str(|nbuf| {
                v.with_c_str(|vbuf| {
250
                    libc::funcs::posix01::unistd::setenv(nbuf, vbuf, 1);
251 252 253
                })
            })
        })
254 255
    }
}
256 257


258
#[cfg(windows)]
259 260
/// Sets the environment variable `n` to the value `v` for the currently running
/// process
261 262
pub fn setenv(n: &str, v: &str) {
    unsafe {
263
        with_env_lock(|| {
264
            use os::win32::as_utf16_p;
265 266
            as_utf16_p(n, |nbuf| {
                as_utf16_p(v, |vbuf| {
267
                    libc::SetEnvironmentVariableW(nbuf, vbuf);
268 269 270
                })
            })
        })
271 272 273
    }
}

C
Corey Richardson 已提交
274 275 276 277 278
/// Remove a variable from the environment entirely
pub fn unsetenv(n: &str) {
    #[cfg(unix)]
    fn _unsetenv(n: &str) {
        unsafe {
279 280
            with_env_lock(|| {
                n.with_c_str(|nbuf| {
C
Corey Richardson 已提交
281
                    libc::funcs::posix01::unistd::unsetenv(nbuf);
282 283
                })
            })
C
Corey Richardson 已提交
284 285 286 287 288
        }
    }
    #[cfg(windows)]
    fn _unsetenv(n: &str) {
        unsafe {
289
            with_env_lock(|| {
C
Corey Richardson 已提交
290
                use os::win32::as_utf16_p;
291
                as_utf16_p(n, |nbuf| {
C
Corey Richardson 已提交
292
                    libc::SetEnvironmentVariableW(nbuf, ptr::null());
293 294
                })
            })
C
Corey Richardson 已提交
295 296 297 298 299 300
        }
    }

    _unsetenv(n);
}

301
pub struct Pipe {
302
    input: c_int,
303 304
    out: c_int
}
305

306
#[cfg(unix)]
307
pub fn pipe() -> Pipe {
308
    unsafe {
309 310 311
        let mut fds = Pipe {input: 0,
                            out: 0};
        assert_eq!(libc::pipe(&mut fds.input), 0);
312
        return Pipe {input: fds.input, out: fds.out};
313
    }
314 315
}

316
#[cfg(windows)]
317
pub fn pipe() -> Pipe {
318 319 320 321 322
    unsafe {
        // Windows pipes work subtly differently than unix pipes, and their
        // inheritance has to be handled in a different way that I do not
        // fully understand. Here we explicitly make the pipe non-inheritable,
        // which means to pass it to a subprocess they need to be duplicated
323
        // first, as in std::run.
324 325
        let mut fds = Pipe {input: 0,
                    out: 0};
326
        let res = libc::pipe(&mut fds.input, 1024 as ::libc::c_uint,
327
                             (libc::O_BINARY | libc::O_NOINHERIT) as c_int);
328 329 330
        assert_eq!(res, 0);
        assert!((fds.input != -1 && fds.input != 0 ));
        assert!((fds.out != -1 && fds.input != 0));
331
        return Pipe {input: fds.input, out: fds.out};
332
    }
333 334
}

335
/// Returns the proper dll filename for the given basename of a file.
336
pub fn dll_filename(base: &str) -> ~str {
337
    format!("{}{}{}", consts::DLL_PREFIX, base, consts::DLL_SUFFIX)
338 339
}

B
Ben Noordhuis 已提交
340
/// Optionally returns the filesystem path of the current executable which is
341
/// running. If any failure occurs, None is returned.
B
Ben Noordhuis 已提交
342
pub fn self_exe_name() -> Option<Path> {
343 344

    #[cfg(target_os = "freebsd")]
345
    fn load_self() -> Option<~[u8]> {
346
        unsafe {
347 348
            use libc::funcs::bsd44::*;
            use libc::consts::os::extra::*;
349
            use vec;
350 351 352
            let mib = ~[CTL_KERN as c_int,
                        KERN_PROC as c_int,
                        KERN_PROC_PATHNAME as c_int, -1 as c_int];
A
Alex Crichton 已提交
353
            let mut sz: libc::size_t = 0;
354
            let err = sysctl(mib.as_ptr(), mib.len() as ::libc::c_uint,
A
Alex Crichton 已提交
355 356
                             ptr::mut_null(), &mut sz, ptr::null(),
                             0u as libc::size_t);
357 358 359
            if err != 0 { return None; }
            if sz == 0 { return None; }
            let mut v: ~[u8] = vec::with_capacity(sz as uint);
360
            let err = sysctl(mib.as_ptr(), mib.len() as ::libc::c_uint,
A
Alex Crichton 已提交
361 362
                             v.as_mut_ptr() as *mut c_void, &mut sz, ptr::null(),
                             0u as libc::size_t);
363 364
            if err != 0 { return None; }
            if sz == 0 { return None; }
365
            v.set_len(sz as uint - 1); // chop off trailing NUL
366
            Some(v)
367
        }
368 369 370
    }

    #[cfg(target_os = "linux")]
K
kyeongwoon 已提交
371
    #[cfg(target_os = "android")]
372
    fn load_self() -> Option<~[u8]> {
A
Alex Crichton 已提交
373
        use std::io;
374

375
        match io::result(|| io::fs::readlink(&Path::new("/proc/self/exe"))) {
376
            Ok(Some(path)) => Some(path.as_vec().to_owned()),
A
Alex Crichton 已提交
377
            Ok(None) | Err(..) => None
378 379 380
        }
    }

381
    #[cfg(target_os = "macos")]
382
    fn load_self() -> Option<~[u8]> {
383
        unsafe {
384
            use libc::funcs::extra::_NSGetExecutablePath;
385
            use vec;
386 387 388 389
            let mut sz: u32 = 0;
            _NSGetExecutablePath(ptr::mut_null(), &mut sz);
            if sz == 0 { return None; }
            let mut v: ~[u8] = vec::with_capacity(sz as uint);
390
            let err = _NSGetExecutablePath(v.as_mut_ptr() as *mut i8, &mut sz);
391
            if err != 0 { return None; }
392
            v.set_len(sz as uint - 1); // chop off trailing NUL
393
            Some(v)
394
        }
395 396
    }

397
    #[cfg(windows)]
398
    fn load_self() -> Option<~[u8]> {
399 400
        unsafe {
            use os::win32::fill_utf16_buf_and_decode;
401
            fill_utf16_buf_and_decode(|buf, sz| {
402
                libc::GetModuleFileNameW(0u as libc::DWORD, buf, sz)
403
            }).map(|s| s.into_bytes())
404
        }
405 406
    }

B
Ben Noordhuis 已提交
407 408 409 410 411 412 413 414
    load_self().and_then(Path::new_opt)
}

/// Optionally returns the filesystem path to the current executable which is
/// running. Like self_exe_name() but without the binary's name.
/// If any failure occurs, None is returned.
pub fn self_exe_path() -> Option<Path> {
    self_exe_name().map(|mut p| { p.pop(); p })
415 416
}

417 418 419 420 421 422 423 424 425 426 427 428 429
/**
 * Returns the path to the user's home directory, if known.
 *
 * On Unix, returns the value of the 'HOME' environment variable if it is set
 * and not equal to the empty string.
 *
 * On Windows, returns the value of the 'HOME' environment variable if it is
 * set and not equal to the empty string. Otherwise, returns the value of the
 * 'USERPROFILE' environment variable if it is set and not equal to the empty
 * string.
 *
 * Otherwise, homedir returns option::none.
 */
430
pub fn homedir() -> Option<Path> {
431
    // FIXME (#7188): getenv needs a ~[u8] variant
432
    return match getenv("HOME") {
433
        Some(ref p) if !p.is_empty() => Path::new_opt(p.as_slice()),
434
        _ => secondary()
435 436
    };

437
    #[cfg(unix)]
B
Brian Anderson 已提交
438 439
    fn secondary() -> Option<Path> {
        None
440 441
    }

442
    #[cfg(windows)]
B
Brian Anderson 已提交
443
    fn secondary() -> Option<Path> {
444
        getenv("USERPROFILE").and_then(|p| {
445
            if !p.is_empty() {
446
                Path::new_opt(p)
447
            } else {
B
Brian Anderson 已提交
448
                None
449
            }
450
        })
451 452 453
    }
}

454
/**
455
 * Returns the path to a temporary directory.
456 457 458
 *
 * On Unix, returns the value of the 'TMPDIR' environment variable if it is
 * set and non-empty and '/tmp' otherwise.
459 460
 * On Android, there is no global temporary folder (it is usually allocated
 * per-app), hence returns '/data/tmp' which is commonly used.
461 462
 *
 * On Windows, returns the value of, in order, the 'TMP', 'TEMP',
463 464
 * 'USERPROFILE' environment variable  if any are set and not the empty
 * string. Otherwise, tmpdir returns the path to the Windows directory.
465
 */
466
pub fn tmpdir() -> Path {
467 468
    return lookup();

B
Brian Anderson 已提交
469
    fn getenv_nonempty(v: &str) -> Option<Path> {
470
        match getenv(v) {
L
Luqman Aden 已提交
471
            Some(x) =>
472
                if x.is_empty() {
B
Brian Anderson 已提交
473
                    None
474
                } else {
475
                    Path::new_opt(x)
476
                },
B
Brian Anderson 已提交
477
            _ => None
478 479 480 481
        }
    }

    #[cfg(unix)]
482
    fn lookup() -> Path {
483
        if cfg!(target_os = "android") {
484
            Path::new("/data/tmp")
485
        } else {
486
            getenv_nonempty("TMPDIR").unwrap_or(Path::new("/tmp"))
487
        }
488 489 490
    }

    #[cfg(windows)]
491
    fn lookup() -> Path {
492 493 494
        getenv_nonempty("TMP").or(
            getenv_nonempty("TEMP").or(
                getenv_nonempty("USERPROFILE").or(
495
                   getenv_nonempty("WINDIR")))).unwrap_or(Path::new("C:\\Windows"))
496 497
    }
}
B
Brian Anderson 已提交
498

499 500 501 502 503
/**
 * Convert a relative path to an absolute path
 *
 * If the given path is relative, return it prepended with the current working
 * directory. If the given path is already an absolute path, return it
504
 * as is.
505
 */
506 507 508
// NB: this is here rather than in path because it is a form of environment
// querying; what it does depends on the process working directory, not just
// the input paths.
509
pub fn make_absolute(p: &Path) -> Path {
510 511
    if p.is_absolute() {
        p.clone()
512
    } else {
513
        let mut ret = getcwd();
514
        ret.push(p);
515
        ret
516
    }
517 518
}

519 520
/// Changes the current working directory to the specified path, returning
/// whether the change was completed successfully or not.
521
pub fn change_dir(p: &Path) -> bool {
B
Brian Anderson 已提交
522
    return chdir(p);
523

524
    #[cfg(windows)]
525
    fn chdir(p: &Path) -> bool {
526 527
        unsafe {
            use os::win32::as_utf16_p;
528
            return as_utf16_p(p.as_str().unwrap(), |buf| {
529
                libc::SetCurrentDirectoryW(buf) != (0 as libc::BOOL)
530
            });
531
        }
532 533
    }

534
    #[cfg(unix)]
535
    fn chdir(p: &Path) -> bool {
536
        p.with_c_str(|buf| {
E
Erick Tryzelaar 已提交
537
            unsafe {
538
                libc::chdir(buf) == (0 as c_int)
E
Erick Tryzelaar 已提交
539
            }
540
        })
541 542 543
    }
}

544
#[cfg(unix)]
545
/// Returns the platform-specific value of errno
546 547 548 549 550 551
pub fn errno() -> int {
    #[cfg(target_os = "macos")]
    #[cfg(target_os = "freebsd")]
    fn errno_location() -> *c_int {
        #[nolink]
        extern {
552
            fn __error() -> *c_int;
553 554 555 556 557 558 559 560 561 562 563
        }
        unsafe {
            __error()
        }
    }

    #[cfg(target_os = "linux")]
    #[cfg(target_os = "android")]
    fn errno_location() -> *c_int {
        #[nolink]
        extern {
564
            fn __errno_location() -> *c_int;
565 566 567 568 569 570 571 572 573 574 575 576
        }
        unsafe {
            __errno_location()
        }
    }

    unsafe {
        (*errno_location()) as int
    }
}

#[cfg(windows)]
577
/// Returns the platform-specific value of errno
578 579 580 581
pub fn errno() -> uint {
    use libc::types::os::arch::extra::DWORD;

    #[link_name = "kernel32"]
A
Alex Crichton 已提交
582
    extern "system" {
K
klutzy 已提交
583 584 585
        fn GetLastError() -> DWORD;
    }

586
    unsafe {
587
        GetLastError() as uint
588 589 590
    }
}

591
/// Get a string representing the platform-dependent last error
592
pub fn last_os_error() -> ~str {
593 594 595 596 597
    #[cfg(unix)]
    fn strerror() -> ~str {
        #[cfg(target_os = "macos")]
        #[cfg(target_os = "android")]
        #[cfg(target_os = "freebsd")]
A
Alex Crichton 已提交
598
        fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: libc::size_t)
599
                      -> c_int {
600 601
            #[nolink]
            extern {
A
Alex Crichton 已提交
602 603
                fn strerror_r(errnum: c_int, buf: *mut c_char,
                              buflen: libc::size_t) -> c_int;
604 605 606 607 608 609 610 611
            }
            unsafe {
                strerror_r(errnum, buf, buflen)
            }
        }

        // GNU libc provides a non-compliant version of strerror_r by default
        // and requires macros to instead use the POSIX compliant variant.
L
Luqman Aden 已提交
612
        // So we just use __xpg_strerror_r which is always POSIX compliant
613
        #[cfg(target_os = "linux")]
A
Alex Crichton 已提交
614 615
        fn strerror_r(errnum: c_int, buf: *mut c_char,
                      buflen: libc::size_t) -> c_int {
616 617
            #[nolink]
            extern {
618 619
                fn __xpg_strerror_r(errnum: c_int,
                                    buf: *mut c_char,
A
Alex Crichton 已提交
620
                                    buflen: libc::size_t)
621
                                    -> c_int;
622 623 624 625 626 627 628
            }
            unsafe {
                __xpg_strerror_r(errnum, buf, buflen)
            }
        }

        let mut buf = [0 as c_char, ..TMPBUF_SZ];
629

630 631
        let p = buf.as_mut_ptr();
        unsafe {
A
Alex Crichton 已提交
632
            if strerror_r(errno() as c_int, p, buf.len() as libc::size_t) < 0 {
633
                fail!("strerror_r failure");
634
            }
635 636 637

            str::raw::from_c_str(p as *c_char)
        }
638
    }
639 640 641

    #[cfg(windows)]
    fn strerror() -> ~str {
642
        use libc::types::os::arch::extra::DWORD;
643
        use libc::types::os::arch::extra::LPWSTR;
644
        use libc::types::os::arch::extra::LPVOID;
645
        use libc::types::os::arch::extra::WCHAR;
646 647

        #[link_name = "kernel32"]
A
Alex Crichton 已提交
648
        extern "system" {
649
            fn FormatMessageW(flags: DWORD,
K
klutzy 已提交
650 651 652
                              lpSrc: LPVOID,
                              msgId: DWORD,
                              langId: DWORD,
653
                              buf: LPWSTR,
K
klutzy 已提交
654 655 656 657 658
                              nsize: DWORD,
                              args: *c_void)
                              -> DWORD;
        }

659 660
        static FORMAT_MESSAGE_FROM_SYSTEM: DWORD = 0x00001000;
        static FORMAT_MESSAGE_IGNORE_INSERTS: DWORD = 0x00000200;
661 662 663 664 665 666

        // This value is calculated from the macro
        // MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT)
        let langId = 0x0800 as DWORD;
        let err = errno() as DWORD;

667
        let mut buf = [0 as WCHAR, ..TMPBUF_SZ];
668

669
        unsafe {
670 671 672 673 674 675 676 677 678 679 680
            let res = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM |
                                     FORMAT_MESSAGE_IGNORE_INSERTS,
                                     ptr::mut_null(),
                                     err,
                                     langId,
                                     buf.as_mut_ptr(),
                                     buf.len() as DWORD,
                                     ptr::null());
            if res == 0 {
                fail!("[{}] FormatMessage failure", errno());
            }
681

682
            str::from_utf16(buf)
683 684 685 686
        }
    }

    strerror()
687
}
688

689 690
static mut EXIT_STATUS: AtomicInt = INIT_ATOMIC_INT;

691 692 693 694 695 696
/**
 * Sets the process exit code
 *
 * Sets the exit code returned by the process if all supervised tasks
 * terminate successfully (without failing). If the current root task fails
 * and is supervised by the scheduler then any user-specified exit status is
697 698 699
 * ignored and the process exits with the default failure status.
 *
 * Note that this is not synchronized against modifications of other threads.
700
 */
701
pub fn set_exit_status(code: int) {
702 703 704 705 706 707 708
    unsafe { EXIT_STATUS.store(code, SeqCst) }
}

/// Fetches the process's current exit code. This defaults to 0 and can change
/// by calling `set_exit_status`.
pub fn get_exit_status() -> int {
    unsafe { EXIT_STATUS.load(SeqCst) }
709
}
710

K
Kiet Tran 已提交
711
#[cfg(target_os = "macos")]
712
unsafe fn load_argc_and_argv(argc: int, argv: **c_char) -> ~[~str] {
713
    let mut args = ~[];
D
Daniel Micay 已提交
714
    for i in range(0u, argc as uint) {
715
        args.push(str::raw::from_c_str(*argv.offset(i as int)));
716
    }
L
Luqman Aden 已提交
717
    args
718 719
}

720 721 722 723 724 725
/**
 * Returns the command line arguments
 *
 * Returns a list of the command line arguments.
 */
#[cfg(target_os = "macos")]
726
fn real_args() -> ~[~str] {
727
    unsafe {
728
        let (argc, argv) = (*_NSGetArgc() as int,
729 730
                            *_NSGetArgv() as **c_char);
        load_argc_and_argv(argc, argv)
731 732 733
    }
}

734
#[cfg(target_os = "linux")]
K
kyeongwoon 已提交
735
#[cfg(target_os = "android")]
736
#[cfg(target_os = "freebsd")]
737
fn real_args() -> ~[~str] {
738 739
    use rt;

740 741
    match rt::args::clone() {
        Some(args) => args,
742
        None => fail!("process arguments not initialized")
743
    }
744 745
}

746
#[cfg(windows)]
747
fn real_args() -> ~[~str] {
748
    use vec;
749

750
    let mut nArgs: c_int = 0;
D
Daniel Micay 已提交
751
    let lpArgCount: *mut c_int = &mut nArgs;
T
Tim Chevalier 已提交
752 753
    let lpCmdLine = unsafe { GetCommandLineW() };
    let szArgList = unsafe { CommandLineToArgvW(lpCmdLine, lpArgCount) };
754 755

    let mut args = ~[];
D
Daniel Micay 已提交
756
    for i in range(0u, nArgs as uint) {
757 758
        unsafe {
            // Determine the length of this argument.
759
            let ptr = *szArgList.offset(i as int);
760
            let mut len = 0;
761
            while *ptr.offset(len as int) != 0 { len += 1; }
762 763

            // Push it onto the list.
764
            args.push(vec::raw::buf_as_slice(ptr, len,
765
                                             str::from_utf16));
766 767 768 769
        }
    }

    unsafe {
770
        LocalFree(szArgList as *c_void);
771 772 773 774 775 776 777
    }

    return args;
}

type LPCWSTR = *u16;

A
Alex Crichton 已提交
778
#[cfg(windows)]
K
klutzy 已提交
779
#[link_name="kernel32"]
A
Alex Crichton 已提交
780
extern "system" {
K
klutzy 已提交
781 782 783 784
    fn GetCommandLineW() -> LPCWSTR;
    fn LocalFree(ptr: *c_void);
}

A
Alex Crichton 已提交
785
#[cfg(windows)]
K
klutzy 已提交
786
#[link_name="shell32"]
A
Alex Crichton 已提交
787
extern "system" {
K
klutzy 已提交
788 789 790
    fn CommandLineToArgvW(lpCmdLine: LPCWSTR, pNumArgs: *mut c_int) -> **u16;
}

791 792
/// Returns the arguments which this program was started with (normally passed
/// via the command line).
793
pub fn args() -> ~[~str] {
794
    real_args()
795 796
}

797 798 799 800 801 802 803
#[cfg(target_os = "macos")]
extern {
    // These functions are in crt_externs.h.
    pub fn _NSGetArgc() -> *c_int;
    pub fn _NSGetArgv() -> ***c_char;
}

804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826
// Round up `from` to be divisible by `to`
fn round_up(from: uint, to: uint) -> uint {
    let r = if from % to == 0 {
        from
    } else {
        from + to - (from % to)
    };
    if r == 0 {
        to
    } else {
        r
    }
}

#[cfg(unix)]
pub fn page_size() -> uint {
    unsafe {
        libc::sysconf(libc::_SC_PAGESIZE) as uint
    }
}

#[cfg(windows)]
pub fn page_size() -> uint {
V
Vadim Chugunov 已提交
827 828 829
    unsafe {
        let mut info = libc::SYSTEM_INFO::new();
        libc::GetSystemInfo(&mut info);
830

V
Vadim Chugunov 已提交
831 832
        return info.dwPageSize as uint;
    }
833 834
}

A
Alex Crichton 已提交
835 836 837 838
/// A memory mapped file or chunk of memory. This is a very system-specific
/// interface to the OS's memory mapping facilities (`mmap` on POSIX,
/// `VirtualAlloc`/`CreateFileMapping` on win32). It makes no attempt at
/// abstracting platform differences, besides in error values returned. Consider
C
Corey Richardson 已提交
839 840
/// yourself warned.
///
A
Alex Crichton 已提交
841 842
/// The memory map is released (unmapped) when the destructor is run, so don't
/// let it leave scope by accident if you want it to stick around.
843
pub struct MemoryMap {
C
Corey Richardson 已提交
844
    /// Pointer to the memory created or modified by this map.
845
    data: *mut u8,
C
Corey Richardson 已提交
846
    /// Number of bytes this map applies to
847
    len: uint,
C
Corey Richardson 已提交
848
    /// Type of mapping
849 850 851
    kind: MemoryMapKind
}

C
Corey Richardson 已提交
852
/// Type of memory map
853
pub enum MemoryMapKind {
A
Alex Crichton 已提交
854 855
    /// Virtual memory map. Usually used to change the permissions of a given
    /// chunk of memory.  Corresponds to `VirtualAlloc` on Windows.
856
    MapFile(*u8),
A
Alex Crichton 已提交
857 858 859
    /// Virtual memory map. Usually used to change the permissions of a given
    /// chunk of memory, or for allocation. Corresponds to `VirtualAlloc` on
    /// Windows.
860 861 862
    MapVirtual
}

C
Corey Richardson 已提交
863
/// Options the memory map is created with
864
pub enum MapOption {
C
Corey Richardson 已提交
865
    /// The memory should be readable
866
    MapReadable,
C
Corey Richardson 已提交
867
    /// The memory should be writable
868
    MapWritable,
C
Corey Richardson 已提交
869
    /// The memory should be executable
870
    MapExecutable,
A
Alex Crichton 已提交
871 872
    /// Create a map for a specific address range. Corresponds to `MAP_FIXED` on
    /// POSIX.
873
    MapAddr(*u8),
C
Corey Richardson 已提交
874
    /// Create a memory mapping for a file with a given fd.
875
    MapFd(c_int),
A
Alex Crichton 已提交
876 877
    /// When using `MapFd`, the start of the map is `uint` bytes from the start
    /// of the file.
878
    MapOffset(uint),
A
Alex Crichton 已提交
879 880 881 882
    /// On POSIX, this can be used to specify the default flags passed to
    /// `mmap`. By default it uses `MAP_PRIVATE` and, if not using `MapFd`,
    /// `MAP_ANON`. This will override both of those. This is platform-specific
    /// (the exact values used) and ignored on Windows.
883
    MapNonStandardFlags(c_int),
884 885
}

C
Corey Richardson 已提交
886
/// Possible errors when creating a map.
887
pub enum MapError {
C
Corey Richardson 已提交
888 889
    /// ## The following are POSIX-specific
    ///
A
Alex Crichton 已提交
890 891
    /// fd was not open for reading or, if using `MapWritable`, was not open for
    /// writing.
892
    ErrFdNotAvail,
C
Corey Richardson 已提交
893
    /// fd was not valid
894
    ErrInvalidFd,
A
Alex Crichton 已提交
895 896
    /// Either the address given by `MapAddr` or offset given by `MapOffset` was
    /// not a multiple of `MemoryMap::granularity` (unaligned to page size).
897
    ErrUnaligned,
C
Corey Richardson 已提交
898
    /// With `MapFd`, the fd does not support mapping.
899
    ErrNoMapSupport,
A
Alex Crichton 已提交
900 901 902
    /// If using `MapAddr`, the address + `min_len` was outside of the process's
    /// address space. If using `MapFd`, the target of the fd didn't have enough
    /// resources to fulfill the request.
903
    ErrNoMem,
C
Corey Richardson 已提交
904
    /// A zero-length map was requested. This is invalid according to
A
Alex Crichton 已提交
905 906
    /// [POSIX](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mmap.html).
    /// Not all platforms obey this, but this wrapper does.
C
Corey Richardson 已提交
907
    ErrZeroLength,
C
Corey Richardson 已提交
908
    /// Unrecognized error. The inner value is the unrecognized errno.
909
    ErrUnknown(int),
C
Corey Richardson 已提交
910 911
    /// ## The following are win32-specific
    ///
A
Alex Crichton 已提交
912 913
    /// Unsupported combination of protection flags
    /// (`MapReadable`/`MapWritable`/`MapExecutable`).
914
    ErrUnsupProt,
A
Alex Crichton 已提交
915 916
    /// When using `MapFd`, `MapOffset` was given (Windows does not support this
    /// at all)
917
    ErrUnsupOffset,
C
Corey Richardson 已提交
918
    /// When using `MapFd`, there was already a mapping to the file.
919
    ErrAlreadyExists,
A
Alex Crichton 已提交
920 921
    /// Unrecognized error from `VirtualAlloc`. The inner value is the return
    /// value of GetLastError.
922
    ErrVirtualAlloc(uint),
A
Alex Crichton 已提交
923 924
    /// Unrecognized error from `CreateFileMapping`. The inner value is the
    /// return value of `GetLastError`.
925
    ErrCreateFileMappingW(uint),
A
Alex Crichton 已提交
926 927
    /// Unrecognized error from `MapViewOfFile`. The inner value is the return
    /// value of `GetLastError`.
928 929 930
    ErrMapViewOfFile(uint)
}

931
impl fmt::Show for MapError {
932 933 934 935
    fn fmt(val: &MapError, out: &mut fmt::Formatter) {
        let str = match *val {
            ErrFdNotAvail => "fd not available for reading or writing",
            ErrInvalidFd => "Invalid fd",
A
Alex Crichton 已提交
936 937 938 939
            ErrUnaligned => {
                "Unaligned address, invalid flags, negative length or \
                 unaligned offset"
            }
940 941 942 943 944
            ErrNoMapSupport=> "File doesn't support mapping",
            ErrNoMem => "Invalid address, or not enough available memory",
            ErrUnsupProt => "Protection mode unsupported",
            ErrUnsupOffset => "Offset in virtual memory mode is unsupported",
            ErrAlreadyExists => "File mapping for specified file already exists",
C
Corey Richardson 已提交
945
            ErrZeroLength => "Zero-length mapping not allowed",
A
Alex Crichton 已提交
946 947 948 949 950 951 952 953
            ErrUnknown(code) => {
                write!(out.buf, "Unknown error = {}", code);
                return
            },
            ErrVirtualAlloc(code) => {
                write!(out.buf, "VirtualAlloc failure = {}", code);
                return
            },
954 955 956 957 958 959 960 961 962 963
            ErrCreateFileMappingW(code) => {
                format!("CreateFileMappingW failure = {}", code);
                return
            },
            ErrMapViewOfFile(code) => {
                write!(out.buf, "MapViewOfFile failure = {}", code);
                return
            }
        };
        write!(out.buf, "{}", str);
964 965 966 967 968
    }
}

#[cfg(unix)]
impl MemoryMap {
A
Alex Crichton 已提交
969 970 971
    /// Create a new mapping with the given `options`, at least `min_len` bytes
    /// long. `min_len` must be greater than zero; see the note on
    /// `ErrZeroLength`.
972
    pub fn new(min_len: uint, options: &[MapOption]) -> Result<MemoryMap, MapError> {
973 974
        use libc::off_t;

C
Corey Richardson 已提交
975 976 977
        if min_len == 0 {
            return Err(ErrZeroLength)
        }
978 979 980 981 982
        let mut addr: *u8 = ptr::null();
        let mut prot = 0;
        let mut flags = libc::MAP_PRIVATE;
        let mut fd = -1;
        let mut offset = 0;
983
        let mut custom_flags = false;
984
        let len = round_up(min_len, page_size());
985

D
Daniel Micay 已提交
986
        for &o in options.iter() {
987 988 989 990 991 992 993 994 995 996 997 998
            match o {
                MapReadable => { prot |= libc::PROT_READ; },
                MapWritable => { prot |= libc::PROT_WRITE; },
                MapExecutable => { prot |= libc::PROT_EXEC; },
                MapAddr(addr_) => {
                    flags |= libc::MAP_FIXED;
                    addr = addr_;
                },
                MapFd(fd_) => {
                    flags |= libc::MAP_FILE;
                    fd = fd_;
                },
999 1000
                MapOffset(offset_) => { offset = offset_ as off_t; },
                MapNonStandardFlags(f) => { custom_flags = true; flags = f },
1001 1002
            }
        }
1003
        if fd == -1 && !custom_flags { flags |= libc::MAP_ANON; }
1004 1005

        let r = unsafe {
A
Alex Crichton 已提交
1006 1007
            libc::mmap(addr as *c_void, len as libc::size_t, prot, flags, fd,
                       offset)
1008
        };
1009
        if r.equiv(&libc::MAP_FAILED) {
1010 1011 1012 1013 1014 1015
            Err(match errno() as c_int {
                libc::EACCES => ErrFdNotAvail,
                libc::EBADF => ErrInvalidFd,
                libc::EINVAL => ErrUnaligned,
                libc::ENODEV => ErrNoMapSupport,
                libc::ENOMEM => ErrNoMem,
1016
                code => ErrUnknown(code as int)
1017 1018
            })
        } else {
1019
            Ok(MemoryMap {
1020 1021 1022 1023 1024 1025 1026 1027 1028 1029
               data: r as *mut u8,
               len: len,
               kind: if fd == -1 {
                   MapVirtual
               } else {
                   MapFile(ptr::null())
               }
            })
        }
    }
V
Vadim Chugunov 已提交
1030

A
Alex Crichton 已提交
1031 1032
    /// Granularity that the offset or address must be for `MapOffset` and
    /// `MapAddr` respectively.
V
Vadim Chugunov 已提交
1033 1034 1035
    pub fn granularity() -> uint {
        page_size()
    }
1036 1037 1038 1039
}

#[cfg(unix)]
impl Drop for MemoryMap {
C
Corey Richardson 已提交
1040
    /// Unmap the mapping. Fails the task if `munmap` fails.
D
Daniel Micay 已提交
1041
    fn drop(&mut self) {
C
Corey Richardson 已提交
1042 1043
        if self.len == 0 { /* workaround for dummy_stack */ return; }

1044
        unsafe {
1045
            match libc::munmap(self.data as *c_void, self.len as libc::size_t) {
1046
                0 => (),
A
Alex Crichton 已提交
1047
                -1 => match errno() as c_int {
1048 1049
                    libc::EINVAL => error!("invalid addr or len"),
                    e => error!("unknown errno={}", e)
A
Alex Crichton 已提交
1050
                },
1051
                r => error!("Unexpected result {}", r)
1052 1053 1054 1055 1056 1057 1058
            }
        }
    }
}

#[cfg(windows)]
impl MemoryMap {
C
Corey Richardson 已提交
1059
    /// Create a new mapping with the given `options`, at least `min_len` bytes long.
1060
    pub fn new(min_len: uint, options: &[MapOption]) -> Result<MemoryMap, MapError> {
1061 1062 1063 1064 1065 1066 1067 1068
        use libc::types::os::arch::extra::{LPVOID, DWORD, SIZE_T, HANDLE};

        let mut lpAddress: LPVOID = ptr::mut_null();
        let mut readable = false;
        let mut writable = false;
        let mut executable = false;
        let mut fd: c_int = -1;
        let mut offset: uint = 0;
1069
        let len = round_up(min_len, page_size());
1070

D
Daniel Micay 已提交
1071
        for &o in options.iter() {
1072 1073 1074 1075 1076 1077
            match o {
                MapReadable => { readable = true; },
                MapWritable => { writable = true; },
                MapExecutable => { executable = true; }
                MapAddr(addr_) => { lpAddress = addr_ as LPVOID; },
                MapFd(fd_) => { fd = fd_; },
1078
                MapOffset(offset_) => { offset = offset_; },
A
Alex Crichton 已提交
1079 1080 1081 1082
                MapNonStandardFlags(f) => {
                    info!("MemoryMap::new: MapNonStandardFlags used on \
                           Windows: {}", f)
                }
1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101
            }
        }

        let flProtect = match (executable, readable, writable) {
            (false, false, false) if fd == -1 => libc::PAGE_NOACCESS,
            (false, true, false) => libc::PAGE_READONLY,
            (false, true, true) => libc::PAGE_READWRITE,
            (true, false, false) if fd == -1 => libc::PAGE_EXECUTE,
            (true, true, false) => libc::PAGE_EXECUTE_READ,
            (true, true, true) => libc::PAGE_EXECUTE_READWRITE,
            _ => return Err(ErrUnsupProt)
        };

        if fd == -1 {
            if offset != 0 {
                return Err(ErrUnsupOffset);
            }
            let r = unsafe {
                libc::VirtualAlloc(lpAddress,
1102
                                   len as SIZE_T,
1103 1104 1105 1106 1107
                                   libc::MEM_COMMIT | libc::MEM_RESERVE,
                                   flProtect)
            };
            match r as uint {
                0 => Err(ErrVirtualAlloc(errno())),
1108
                _ => Ok(MemoryMap {
1109 1110 1111 1112 1113 1114
                   data: r as *mut u8,
                   len: len,
                   kind: MapVirtual
                })
            }
        } else {
V
Vadim Chugunov 已提交
1115 1116 1117 1118 1119 1120 1121
            let dwDesiredAccess = match (executable, readable, writable) {
                (false, true, false) => libc::FILE_MAP_READ,
                (false, true, true) => libc::FILE_MAP_WRITE,
                (true, true, false) => libc::FILE_MAP_READ | libc::FILE_MAP_EXECUTE,
                (true, true, true) => libc::FILE_MAP_WRITE | libc::FILE_MAP_EXECUTE,
                _ => return Err(ErrUnsupProt) // Actually, because of the check above,
                                              // we should never get here.
1122 1123 1124 1125 1126 1127
            };
            unsafe {
                let hFile = libc::get_osfhandle(fd) as HANDLE;
                let mapping = libc::CreateFileMappingW(hFile,
                                                       ptr::mut_null(),
                                                       flProtect,
V
Vadim Chugunov 已提交
1128 1129
                                                       0,
                                                       0,
1130 1131 1132 1133 1134 1135 1136 1137 1138
                                                       ptr::null());
                if mapping == ptr::mut_null() {
                    return Err(ErrCreateFileMappingW(errno()));
                }
                if errno() as c_int == libc::ERROR_ALREADY_EXISTS {
                    return Err(ErrAlreadyExists);
                }
                let r = libc::MapViewOfFile(mapping,
                                            dwDesiredAccess,
V
Vadim Chugunov 已提交
1139
                                            ((len as u64) >> 32) as DWORD,
1140 1141 1142 1143
                                            (offset & 0xffff_ffff) as DWORD,
                                            0);
                match r as uint {
                    0 => Err(ErrMapViewOfFile(errno())),
1144
                    _ => Ok(MemoryMap {
1145 1146
                       data: r as *mut u8,
                       len: len,
1147
                       kind: MapFile(mapping as *u8)
1148 1149 1150 1151 1152
                    })
                }
            }
        }
    }
V
Vadim Chugunov 已提交
1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163

    /// Granularity of MapAddr() and MapOffset() parameter values.
    /// This may be greater than the value returned by page_size().
    pub fn granularity() -> uint {
        unsafe {
            let mut info = libc::SYSTEM_INFO::new();
            libc::GetSystemInfo(&mut info);

            return info.dwAllocationGranularity as uint;
        }
    }
1164 1165 1166 1167
}

#[cfg(windows)]
impl Drop for MemoryMap {
A
Alex Crichton 已提交
1168 1169
    /// Unmap the mapping. Fails the task if any of `VirtualFree`,
    /// `UnmapViewOfFile`, or `CloseHandle` fail.
D
Daniel Micay 已提交
1170
    fn drop(&mut self) {
1171
        use libc::types::os::arch::extra::{LPCVOID, HANDLE};
V
Vadim Chugunov 已提交
1172
        use libc::consts::os::extra::FALSE;
A
Alex Crichton 已提交
1173
        if self.len == 0 { return }
1174 1175 1176

        unsafe {
            match self.kind {
V
Vadim Chugunov 已提交
1177
                MapVirtual => {
1178
                    if libc::VirtualFree(self.data as *mut c_void, 0,
A
Alex Crichton 已提交
1179
                                         libc::MEM_RELEASE) == 0 {
1180
                        error!("VirtualFree failed: {}", errno());
V
Vadim Chugunov 已提交
1181
                    }
1182 1183
                },
                MapFile(mapping) => {
V
Vadim Chugunov 已提交
1184
                    if libc::UnmapViewOfFile(self.data as LPCVOID) == FALSE {
1185
                        error!("UnmapViewOfFile failed: {}", errno());
1186
                    }
V
Vadim Chugunov 已提交
1187
                    if libc::CloseHandle(mapping as HANDLE) == FALSE {
1188
                        error!("CloseHandle failed: {}", errno());
1189 1190 1191 1192 1193 1194 1195
                    }
                }
            }
        }
    }
}

1196
pub mod consts {
1197

I
ILyoan 已提交
1198
    #[cfg(unix)]
1199
    pub use os::consts::unix::*;
1200

I
ILyoan 已提交
1201
    #[cfg(windows)]
1202
    pub use os::consts::windows::*;
1203

I
ILyoan 已提交
1204
    #[cfg(target_os = "macos")]
1205
    pub use os::consts::macos::*;
I
ILyoan 已提交
1206 1207

    #[cfg(target_os = "freebsd")]
1208
    pub use os::consts::freebsd::*;
I
ILyoan 已提交
1209 1210

    #[cfg(target_os = "linux")]
1211
    pub use os::consts::linux::*;
I
ILyoan 已提交
1212

K
kyeongwoon 已提交
1213
    #[cfg(target_os = "android")]
1214
    pub use os::consts::android::*;
K
kyeongwoon 已提交
1215

I
ILyoan 已提交
1216
    #[cfg(target_os = "win32")]
1217
    pub use os::consts::win32::*;
1218

1219 1220 1221 1222 1223 1224 1225 1226 1227 1228
    #[cfg(target_arch = "x86")]
    pub use os::consts::x86::*;

    #[cfg(target_arch = "x86_64")]
    pub use os::consts::x86_64::*;

    #[cfg(target_arch = "arm")]
    pub use os::consts::arm::*;

    #[cfg(target_arch = "mips")]
1229
    pub use os::consts::mips::*;
1230 1231 1232 1233 1234 1235 1236 1237 1238

    pub mod unix {
        pub static FAMILY: &'static str = "unix";
    }

    pub mod windows {
        pub static FAMILY: &'static str = "windows";
    }

I
ILyoan 已提交
1239
    pub mod macos {
1240 1241 1242
        pub static SYSNAME: &'static str = "macos";
        pub static DLL_PREFIX: &'static str = "lib";
        pub static DLL_SUFFIX: &'static str = ".dylib";
1243
        pub static DLL_EXTENSION: &'static str = "dylib";
1244
        pub static EXE_SUFFIX: &'static str = "";
1245
        pub static EXE_EXTENSION: &'static str = "";
I
ILyoan 已提交
1246 1247 1248
    }

    pub mod freebsd {
1249 1250 1251
        pub static SYSNAME: &'static str = "freebsd";
        pub static DLL_PREFIX: &'static str = "lib";
        pub static DLL_SUFFIX: &'static str = ".so";
1252
        pub static DLL_EXTENSION: &'static str = "so";
1253
        pub static EXE_SUFFIX: &'static str = "";
1254
        pub static EXE_EXTENSION: &'static str = "";
I
ILyoan 已提交
1255 1256 1257
    }

    pub mod linux {
1258 1259 1260
        pub static SYSNAME: &'static str = "linux";
        pub static DLL_PREFIX: &'static str = "lib";
        pub static DLL_SUFFIX: &'static str = ".so";
1261
        pub static DLL_EXTENSION: &'static str = "so";
1262
        pub static EXE_SUFFIX: &'static str = "";
1263
        pub static EXE_EXTENSION: &'static str = "";
I
ILyoan 已提交
1264
    }
K
kyeongwoon 已提交
1265 1266

    pub mod android {
1267 1268 1269
        pub static SYSNAME: &'static str = "android";
        pub static DLL_PREFIX: &'static str = "lib";
        pub static DLL_SUFFIX: &'static str = ".so";
1270
        pub static DLL_EXTENSION: &'static str = "so";
1271
        pub static EXE_SUFFIX: &'static str = "";
1272
        pub static EXE_EXTENSION: &'static str = "";
K
kyeongwoon 已提交
1273
    }
1274

I
ILyoan 已提交
1275
    pub mod win32 {
1276 1277 1278
        pub static SYSNAME: &'static str = "win32";
        pub static DLL_PREFIX: &'static str = "";
        pub static DLL_SUFFIX: &'static str = ".dll";
1279
        pub static DLL_EXTENSION: &'static str = "dll";
1280
        pub static EXE_SUFFIX: &'static str = ".exe";
1281
        pub static EXE_EXTENSION: &'static str = "exe";
I
ILyoan 已提交
1282 1283 1284 1285
    }


    pub mod x86 {
1286
        pub static ARCH: &'static str = "x86";
I
ILyoan 已提交
1287 1288
    }
    pub mod x86_64 {
1289
        pub static ARCH: &'static str = "x86_64";
I
ILyoan 已提交
1290 1291
    }
    pub mod arm {
1292
        pub static ARCH: &'static str = "arm";
I
ILyoan 已提交
1293
    }
J
Jyun-Yan You 已提交
1294
    pub mod mips {
1295
        pub static ARCH: &'static str = "mips";
J
Jyun-Yan You 已提交
1296
    }
I
ILyoan 已提交
1297
}
1298 1299 1300

#[cfg(test)]
mod tests {
1301
    use prelude::*;
1302
    use c_str::ToCStr;
1303
    use option;
1304
    use os::{env, getcwd, getenv, make_absolute, args};
1305
    use os::{setenv, unsetenv};
1306
    use os;
1307
    use rand::Rng;
1308
    use rand;
1309

1310

1311
    #[test]
1312
    pub fn last_os_error() {
1313
        debug!("{}", os::last_os_error());
1314
    }
1315

1316 1317
    #[test]
    pub fn test_args() {
1318
        let a = args();
P
Patrick Walton 已提交
1319
        assert!(a.len() >= 1);
1320 1321
    }

1322
    fn make_rand_name() -> ~str {
P
Patrick Walton 已提交
1323
        let mut rng = rand::rng();
1324
        let n = ~"TEST" + rng.gen_ascii_str(10u);
P
Patrick Walton 已提交
1325
        assert!(getenv(n).is_none());
L
Luqman Aden 已提交
1326
        n
1327 1328 1329 1330 1331
    }

    #[test]
    fn test_setenv() {
        let n = make_rand_name();
E
Erick Tryzelaar 已提交
1332
        setenv(n, "VALUE");
1333
        assert_eq!(getenv(n), option::Some(~"VALUE"));
1334 1335
    }

C
Corey Richardson 已提交
1336 1337 1338
    #[test]
    fn test_unsetenv() {
        let n = make_rand_name();
E
Erick Tryzelaar 已提交
1339
        setenv(n, "VALUE");
C
Corey Richardson 已提交
1340
        unsetenv(n);
1341
        assert_eq!(getenv(n), option::None);
C
Corey Richardson 已提交
1342 1343
    }

1344
    #[test]
1345
    #[ignore]
1346 1347
    fn test_setenv_overwrite() {
        let n = make_rand_name();
E
Erick Tryzelaar 已提交
1348 1349
        setenv(n, "1");
        setenv(n, "2");
1350
        assert_eq!(getenv(n), option::Some(~"2"));
E
Erick Tryzelaar 已提交
1351
        setenv(n, "");
1352
        assert_eq!(getenv(n), option::Some(~""));
1353 1354 1355 1356 1357
    }

    // Windows GetEnvironmentVariable requires some extra work to make sure
    // the buffer the variable is copied into is the right size
    #[test]
1358
    #[ignore]
1359
    fn test_getenv_big() {
1360
        let mut s = ~"";
1361
        let mut i = 0;
1362 1363 1364 1365
        while i < 100 {
            s = s + "aaaaaaaaaa";
            i += 1;
        }
1366 1367
        let n = make_rand_name();
        setenv(n, s);
1368
        debug!("{}", s.clone());
1369
        assert_eq!(getenv(n), option::Some(s));
1370 1371
    }

B
Ben Noordhuis 已提交
1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382
    #[test]
    fn test_self_exe_name() {
        let path = os::self_exe_name();
        assert!(path.is_some());
        let path = path.unwrap();
        debug!("{:?}", path.clone());

        // Hard to test this function
        assert!(path.is_absolute());
    }

1383 1384 1385
    #[test]
    fn test_self_exe_path() {
        let path = os::self_exe_path();
P
Patrick Walton 已提交
1386
        assert!(path.is_some());
1387
        let path = path.unwrap();
1388
        debug!("{:?}", path.clone());
1389 1390

        // Hard to test this function
1391
        assert!(path.is_absolute());
1392 1393 1394
    }

    #[test]
1395
    #[ignore]
1396 1397
    fn test_env_getenv() {
        let e = env();
Y
Youngmin Yoo 已提交
1398
        assert!(e.len() > 0u);
D
Daniel Micay 已提交
1399
        for p in e.iter() {
1400
            let (n, v) = (*p).clone();
1401
            debug!("{:?}", n.clone());
1402 1403 1404 1405
            let v2 = getenv(n);
            // MingW seems to set some funky environment variables like
            // "=C:=C:\MinGW\msys\1.0\bin" and "!::=::\" that are returned
            // from env() but not visible from getenv().
P
Patrick Walton 已提交
1406
            assert!(v2.is_none() || v2 == option::Some(v));
1407 1408 1409 1410 1411 1412 1413
        }
    }

    #[test]
    fn test_env_setenv() {
        let n = make_rand_name();

1414
        let mut e = env();
E
Erick Tryzelaar 已提交
1415
        setenv(n, "VALUE");
1416
        assert!(!e.contains(&(n.clone(), ~"VALUE")));
1417 1418

        e = env();
1419
        assert!(e.contains(&(n, ~"VALUE")));
1420 1421
    }

1422 1423
    #[test]
    fn test() {
1424
        assert!((!Path::new("test-path").is_absolute()));
1425

1426
        let cwd = getcwd();
1427
        debug!("Current working directory: {}", cwd.display());
1428

1429 1430
        debug!("{:?}", make_absolute(&Path::new("test-path")));
        debug!("{:?}", make_absolute(&Path::new("/usr/bin")));
1431 1432 1433
    }

    #[test]
1434
    #[cfg(unix)]
1435
    fn homedir() {
E
Erick Tryzelaar 已提交
1436
        let oldhome = getenv("HOME");
1437

E
Erick Tryzelaar 已提交
1438
        setenv("HOME", "/home/MountainView");
1439
        assert_eq!(os::homedir(), Some(Path::new("/home/MountainView")));
1440

E
Erick Tryzelaar 已提交
1441
        setenv("HOME", "");
P
Patrick Walton 已提交
1442
        assert!(os::homedir().is_none());
1443

D
Daniel Micay 已提交
1444
        for s in oldhome.iter() { setenv("HOME", *s) }
1445 1446 1447
    }

    #[test]
1448
    #[cfg(windows)]
1449 1450
    fn homedir() {

E
Erick Tryzelaar 已提交
1451 1452
        let oldhome = getenv("HOME");
        let olduserprofile = getenv("USERPROFILE");
1453

E
Erick Tryzelaar 已提交
1454 1455
        setenv("HOME", "");
        setenv("USERPROFILE", "");
1456

P
Patrick Walton 已提交
1457
        assert!(os::homedir().is_none());
1458

E
Erick Tryzelaar 已提交
1459
        setenv("HOME", "/home/MountainView");
1460
        assert_eq!(os::homedir(), Some(Path::new("/home/MountainView")));
1461

E
Erick Tryzelaar 已提交
1462
        setenv("HOME", "");
1463

E
Erick Tryzelaar 已提交
1464
        setenv("USERPROFILE", "/home/MountainView");
1465
        assert_eq!(os::homedir(), Some(Path::new("/home/MountainView")));
1466

E
Erick Tryzelaar 已提交
1467 1468
        setenv("HOME", "/home/MountainView");
        setenv("USERPROFILE", "/home/PaloAlto");
1469
        assert_eq!(os::homedir(), Some(Path::new("/home/MountainView")));
1470

1471 1472
        for s in oldhome.iter() { setenv("HOME", *s) }
        for s in olduserprofile.iter() { setenv("USERPROFILE", *s) }
1473 1474
    }

1475 1476 1477 1478
    #[test]
    fn memory_map_rw() {
        use result::{Ok, Err};

1479
        let chunk = match os::MemoryMap::new(16, [
1480 1481 1482 1483
            os::MapReadable,
            os::MapWritable
        ]) {
            Ok(chunk) => chunk,
C
Corey Richardson 已提交
1484
            Err(msg) => fail!("{}", msg)
1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498
        };
        assert!(chunk.len >= 16);

        unsafe {
            *chunk.data = 0xBE;
            assert!(*chunk.data == 0xBE);
        }
    }

    #[test]
    fn memory_map_file() {
        use result::{Ok, Err};
        use os::*;
        use libc::*;
A
Alex Crichton 已提交
1499 1500
        use io;
        use io::fs;
1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514

        #[cfg(unix)]
        fn lseek_(fd: c_int, size: uint) {
            unsafe {
                assert!(lseek(fd, size as off_t, SEEK_SET) == size as off_t);
            }
        }
        #[cfg(windows)]
        fn lseek_(fd: c_int, size: uint) {
           unsafe {
               assert!(lseek(fd, size as c_long, SEEK_SET) == size as c_long);
           }
        }

1515
        let mut path = tmpdir();
1516
        path.push("mmap_file.tmp");
V
Vadim Chugunov 已提交
1517
        let size = MemoryMap::granularity() * 2;
1518 1519

        let fd = unsafe {
1520
            let fd = path.with_c_str(|path| {
1521
                open(path, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR)
1522
            });
1523
            lseek_(fd, size);
1524
            "x".with_c_str(|x| assert!(write(fd, x as *c_void, 1) == 1));
1525 1526
            fd
        };
1527
        let chunk = match MemoryMap::new(size / 2, [
1528 1529 1530 1531 1532 1533
            MapReadable,
            MapWritable,
            MapFd(fd),
            MapOffset(size / 2)
        ]) {
            Ok(chunk) => chunk,
1534
            Err(msg) => fail!("{}", msg)
1535 1536 1537 1538 1539 1540 1541 1542
        };
        assert!(chunk.len > 0);

        unsafe {
            *chunk.data = 0xbe;
            assert!(*chunk.data == 0xbe);
            close(fd);
        }
1543 1544 1545

        let _guard = io::ignore_io_error();
        fs::unlink(&path);
1546 1547
    }

1548
    // More recursive_mkdir tests are in extra::tempfile
1549
}