diff --git a/.travis.yml b/.travis.yml
index 1fa0a8d368699f012343d6a2c98899b6ca268e7e..3c6cc9429eaf483b256f705ea4bf0341c54585ec 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -174,6 +174,8 @@ matrix:
       stage: tier2
     - env: TARGET=asmjs-unknown-emscripten
       stage: tier2
+    - env: TARGET=i686-linux-android
+      stage: tier2
     - env: TARGET=i686-unknown-linux-musl
       stage: tier2
     - env: TARGET=mips-unknown-linux-gnu
@@ -230,9 +232,6 @@ matrix:
 
 
   allow_failures:
-      # FIXME: android build bots time out irregularly
-      - env: TARGET=aarch64-linux-android
-      - env: TARGET=arm-linux-androideabi
       # FIXME: https://github.com/rust-lang/libc/issues/1226
       - env: TARGET=asmjs-unknown-emscripten
       - env: TARGET=wasm32-unknown-emscripten
diff --git a/ci/android-install-ndk.sh b/ci/android-install-ndk.sh
index 54f7b2efd967419df656473f7e1a7095690845e5..723e719054a14ceb6b318e1bdeebc83f3820aba0 100644
--- a/ci/android-install-ndk.sh
+++ b/ci/android-install-ndk.sh
@@ -11,27 +11,40 @@
 
 set -ex
 
-curl --retry 10 -O https://dl.google.com/android/repository/android-ndk-r15b-linux-x86_64.zip
-unzip -q android-ndk-r15b-linux-x86_64.zip
+NDK=android-ndk-r19c
+curl --retry 20 -O https://dl.google.com/android/repository/${NDK}-linux-x86_64.zip
+unzip -q ${NDK}-linux-x86_64.zip
 
 case "$1" in
+  arm)
+    arch=arm
+    api=24
+    ;;
+  armv7)
+    arch=arm
+    api=24
+    ;;
   aarch64)
     arch=arm64
+    api=24
     ;;
-
   i686)
     arch=x86
+    api=28
+    ;;
+  x86_64)
+    arch=x86_64
+    api=28
     ;;
-
   *)
-    arch=$1
+    echo "invalid arch: $1"
+    exit 1
     ;;
 esac;
 
-android-ndk-r15b/build/tools/make_standalone_toolchain.py \
-        --unified-headers \
+${NDK}/build/tools/make_standalone_toolchain.py \
         --install-dir "/android/ndk-${1}" \
         --arch "${arch}" \
-        --api 24
+        --api ${api}
 
-rm -rf ./android-ndk-r15b-linux-x86_64.zip ./android-ndk-r15b
+rm -rf ./${NDK}-linux-x86_64.zip ./${NDK}
diff --git a/ci/android-install-sdk.sh b/ci/android-install-sdk.sh
index e011cfc34bb4c7764469acae8fb01e5b9e0a779e..7f2104000fdefc8911f346e9b75bf07dbdcc72b8 100644
--- a/ci/android-install-sdk.sh
+++ b/ci/android-install-sdk.sh
@@ -18,46 +18,56 @@ set -ex
 # located in https://github.com/appunite/docker by just wrapping it in a script
 # which apparently magically accepts the licenses.
 
+SDK=4333796
 mkdir sdk
-curl --retry 10 https://dl.google.com/android/repository/sdk-tools-linux-3859397.zip -O
-unzip -d sdk sdk-tools-linux-3859397.zip
+curl --retry 20 https://dl.google.com/android/repository/sdk-tools-linux-${SDK}.zip -O
+unzip -q -d sdk sdk-tools-linux-${SDK}.zip
 
 case "$1" in
   arm | armv7)
-    abi=armeabi-v7a
+    api=24
+    image="system-images;android-${api};google_apis;armeabi-v7a"
     ;;
-
   aarch64)
-    abi=arm64-v8a
+    api=24
+    image="system-images;android-${api};google_apis;arm64-v8a"
     ;;
-
   i686)
-    abi=x86
+    api=28
+    image="system-images;android-${api};default;x86"
     ;;
-
   x86_64)
-    abi=x86_64
+    api=28
+    image="system-images;android-${api};default;x86_64"
     ;;
-
   *)
     echo "invalid arch: $1"
     exit 1
     ;;
 esac;
 
-# See: https://stackoverflow.com/a/51644855/1422197
-export JAVA_OPTS='-XX:+IgnoreUnrecognizedVMOptions --add-modules java.se.ee'
+# Try to fix warning about missing file.
+# See https://askubuntu.com/a/1078784
+mkdir -p /root/.android/
+echo '### User Sources for Android SDK Manager' >> /root/.android/repositories.cfg
+echo '#Fri Nov 03 10:11:27 CET 2017 count=0' >> /root/.android/repositories.cfg
+
+# Print all available packages
+# yes | ./sdk/tools/bin/sdkmanager --list --verbose
 
 # --no_https avoids
-     # javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: No trusted certificate found
-yes | ./sdk/tools/bin/sdkmanager --licenses --no_https
+# javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: No trusted certificate found
+#
+# | grep -v = || true    removes the progress bar output from the sdkmanager
+# which produces an insane amount of output.
+yes | ./sdk/tools/bin/sdkmanager --licenses --no_https | grep -v = || true
 yes | ./sdk/tools/bin/sdkmanager --no_https \
         "emulator" \
         "platform-tools" \
-        "platforms;android-24" \
-        "system-images;android-24;default;$abi"
+        "platforms;android-${api}" \
+        "${image}" | grep -v = || true
 
 echo "no" |
     ./sdk/tools/bin/avdmanager create avd \
         --name "${1}" \
-        --package "system-images;android-24;default;$abi"
+        --package "${image}" | grep -v = || true
diff --git a/ci/docker/aarch64-linux-android/Dockerfile b/ci/docker/aarch64-linux-android/Dockerfile
index 1458423756759107c658809c230bfcfb71c18fd8..6751dd93762d0bf96fd79ffcf4e383624c1d47e2 100644
--- a/ci/docker/aarch64-linux-android/Dockerfile
+++ b/ci/docker/aarch64-linux-android/Dockerfile
@@ -9,7 +9,7 @@ RUN dpkg --add-architecture i386 && \
   python \
   unzip \
   expect \
-  openjdk-11-jre \
+  openjdk-8-jre \
   libstdc++6:i386 \
   libpulse0 \
   gcc \
diff --git a/ci/docker/arm-linux-androideabi/Dockerfile b/ci/docker/arm-linux-androideabi/Dockerfile
index acc784e7d595f336ce1f4642aa0908bc386b98ca..544d1676e1b08d4495013dfa5fdb9d20a6706199 100644
--- a/ci/docker/arm-linux-androideabi/Dockerfile
+++ b/ci/docker/arm-linux-androideabi/Dockerfile
@@ -9,7 +9,7 @@ RUN dpkg --add-architecture i386 && \
   python \
   unzip \
   expect \
-  openjdk-11-jre \
+  openjdk-8-jre \
   libstdc++6:i386 \
   libpulse0 \
   gcc \
diff --git a/ci/docker/i686-linux-android/Dockerfile b/ci/docker/i686-linux-android/Dockerfile
index 59ea2d79fc31b7c730c4602481e65d1c31fb77d0..540322055e449b7463ccd472c131608aa91216d1 100644
--- a/ci/docker/i686-linux-android/Dockerfile
+++ b/ci/docker/i686-linux-android/Dockerfile
@@ -9,7 +9,7 @@ RUN dpkg --add-architecture i386 && \
   python \
   unzip \
   expect \
-  openjdk-11-jre \
+  openjdk-8-jre \
   libstdc++6:i386 \
   libpulse0 \
   gcc \
diff --git a/libc-test/build.rs b/libc-test/build.rs
index e70b74108cce2bb0853329eccac83e6e82cc3098..d8e52084cf1889039885b27df98b7015baecd227 100644
--- a/libc-test/build.rs
+++ b/libc-test/build.rs
@@ -313,6 +313,7 @@ fn test_openbsd(target: &str) {
 
     cfg.skip_fn(move |name| {
         match name {
+            // FIXME: https://github.com/rust-lang/libc/issues/1272
             "execv" | "execve" | "execvp" | "execvpe" => true,
 
             // Removed in OpenBSD 6.5
@@ -458,7 +459,7 @@ fn test_windows(target: &str) {
 
     cfg.skip_fn(move |name| {
         match name {
-            // FIXME: API error:
+            // FIXME: https://github.com/rust-lang/libc/issues/1272
             "execv" | "execve" | "execvp" | "execvpe" => true,
 
             _ => false,
@@ -873,12 +874,8 @@ fn test_netbsd(target: &str) {
 
     cfg.skip_fn(move |name| {
         match name {
-            // FIXME: incorrect API
-            "execv" |
-            "execve" |
-            "execvp" |
-            "execvpe" |
-            "fexecve" => true,
+            // FIXME: https://github.com/rust-lang/libc/issues/1272
+            "execv" | "execve" | "execvp" => true,
 
             "getrlimit" | "getrlimit64" |    // non-int in 1st arg
             "setrlimit" | "setrlimit64" |    // non-int in 1st arg
@@ -1102,11 +1099,8 @@ fn test_dragonflybsd(target: &str) {
     cfg.skip_fn(move |name| {
         // skip those that are manually verified
         match name {
-            "execv" |       // crazy stuff with const/mut
-            "execve" |
-            "execvp" |
-            "execvpe" |
-            "fexecve" => true,
+            // FIXME: https://github.com/rust-lang/libc/issues/1272
+            "execv" | "execve" | "execvp" => true,
 
             "getrlimit" | "getrlimit64" |    // non-int in 1st arg
             "setrlimit" | "setrlimit64" |    // non-int in 1st arg
@@ -1222,14 +1216,6 @@ fn test_android(target: &str) {
     let mut cfg = ctest::TestGenerator::new();
     cfg.define("_GNU_SOURCE", None);
 
-    // FIXME: still necessary?
-    cfg.flag("-Wno-deprecated-declarations");
-
-    // Android doesn't actually have in_port_t but it's much easier if we
-    // provide one for us to test against
-    // FIXME: still necessary?
-    cfg.define("in_port_t", Some("uint16_t"));
-
     headers! { cfg:
                "arpa/inet.h",
                "asm/mman.h",
@@ -1296,6 +1282,7 @@ fn test_android(target: &str) {
                "sys/personality.h",
                "sys/prctl.h",
                "sys/ptrace.h",
+               "sys/random.h",
                "sys/reboot.h",
                "sys/resource.h",
                "sys/sendfile.h",
@@ -1313,6 +1300,7 @@ fn test_android(target: &str) {
                "sys/un.h",
                "sys/utsname.h",
                "sys/vfs.h",
+               "sys/xattr.h",
                "sys/wait.h",
                "syslog.h",
                "termios.h",
@@ -1329,6 +1317,7 @@ fn test_android(target: &str) {
         // generate the error 'Your time_t is already 64-bit'
         cfg.header("time64.h");
     }
+
     if x86 {
         cfg.header("sys/reg.h");
     }
@@ -1336,16 +1325,15 @@ fn test_android(target: &str) {
     cfg.type_name(move |ty, is_struct, is_union| {
         match ty {
             // Just pass all these through, no need for a "struct" prefix
-            // FIXME: still required ?
-            "FILE" | "fd_set" | "Dl_info" | "DIR" | "Elf32_Phdr"
-            | "Elf64_Phdr" | "Elf32_Shdr" | "Elf64_Shdr" | "Elf32_Sym"
-            | "Elf64_Sym" | "Elf32_Ehdr" | "Elf64_Ehdr" | "Elf32_Chdr"
-            | "Elf64_Chdr" => ty.to_string(),
+            "FILE" | "fd_set" | "Dl_info" => ty.to_string(),
 
             t if is_union => format!("union {}", t),
 
             t if t.ends_with("_t") => t.to_string(),
 
+            // sigval is a struct in Rust, but a union in C:
+            "sigval" => format!("union sigval"),
+
             // put `struct` in front of all structs:.
             t if is_struct => format!("struct {}", t),
 
@@ -1360,7 +1348,7 @@ fn test_android(target: &str) {
             s if s.ends_with("_nsec") && struct_.starts_with("stat") => {
                 s.to_string()
             }
-            // FIXME: still necessary?
+            // FIXME: appears that `epoll_event.data` is an union
             "u64" if struct_ == "epoll_event" => "data.u64".to_string(),
             s => s.to_string(),
         }
@@ -1368,8 +1356,8 @@ fn test_android(target: &str) {
 
     cfg.skip_type(move |ty| {
         match ty {
-            // sighandler_t is crazy across platforms
-            // FIXME: still necessary?
+            // FIXME: `sighandler_t` type is incorrect, see:
+            // https://github.com/rust-lang/libc/issues/1359
             "sighandler_t" => true,
             _ => false,
         }
@@ -1377,71 +1365,24 @@ fn test_android(target: &str) {
 
     cfg.skip_struct(move |ty| {
         match ty {
-            // This is actually a union, not a struct
-            // FIXME: still necessary
-            "sigval" => true,
-
-            // These structs have changed since unified headers in NDK r14b.
-            // `st_atime` and `st_atime_nsec` have changed sign.
-            // FIXME: unskip it for next major release
-            "stat" | "stat64" => true,
-
             // These are tested as part of the linux_fcntl tests since there are
             // header conflicts when including them with all the other structs.
-            // FIXME: still necessary
             "termios2" => true,
 
             _ => false,
         }
     });
 
-    cfg.skip_signededness(move |c| {
-        match c {
-            // FIXME: still necessary?
-            "LARGE_INTEGER" | "float" | "double" => true,
-            // FIXME: still necessary?
-            n if n.starts_with("pthread") => true,
-            _ => false,
-        }
-    });
-
     cfg.skip_const(move |name| {
         match name {
-            // FIXME: still necessary?
-            "SIG_DFL" | "SIG_ERR" | "SIG_IGN" => true, // sighandler_t weirdness
-            // FIXME: still necessary?
-            "SIGUNUSED" => true, // removed in glibc 2.26
-
-            // weird signed extension or something like that?
-            // FIXME: still necessary?
-            "MS_NOUSER" => true,
-            // FIXME: still necessary?
-            "MS_RMT_MASK" => true, // updated in glibc 2.22 and musl 1.1.13
-
-            // Android uses old kernel headers
-            // These are constants used in getrandom syscall
-            // FIXME: still necessary?
-            "GRND_NONBLOCK" | "GRND_RANDOM" => true,
-
-            // Defined by libattr not libc on linux (hard to test).
-            // See constant definition for more details.
-            // FIXME: still necessary?
+            // FIXME: deprecated: not available in any header
+            // See: https://github.com/rust-lang/libc/issues/1356
             "ENOATTR" => true,
 
             // FIXME: still necessary?
-            "BOTHER" => true,
-
-            // MFD_HUGETLB is not available in some older libc versions on the CI builders. On the
-            // x86_64 and i686 builders it seems to be available for all targets, so at least test
-            // it there.
-            // FIXME: still necessary?
-            "MFD_HUGETLB" => true,
-
-            // These change all the time from release to release of linux
-            // distros, let's just not bother trying to verify them. They
-            // shouldn't be used in code anyway...
+            "SIG_DFL" | "SIG_ERR" | "SIG_IGN" => true, // sighandler_t weirdness
             // FIXME: still necessary?
-            "AF_MAX" | "PF_MAX" => true,
+            "SIGUNUSED" => true, // removed in glibc 2.26
 
             _ => false,
         }
@@ -1450,115 +1391,60 @@ fn test_android(target: &str) {
     cfg.skip_fn(move |name| {
         // skip those that are manually verified
         match name {
-            // FIXME: still necessary?
-            "execv" |       // crazy stuff with const/mut
-            "execve" |
-            "execvp" |
-            "execvpe" |
-            "fexecve" => true,
-
-            // not declared in newer android toolchains
-            // FIXME: still necessary?
-            "getdtablesize" => true,
-
-            // FIXME: still necessary?
-            "dlerror" => true, // const-ness is added
-
-            // Apparently the NDK doesn't have this defined on android, but
-            // it's in a header file?
-            // FIXME: still necessary?
-            "endpwent" => true,
-
-            // Apparently res_init exists on Android, but isn't defined in a header:
-            // https://mail.gnome.org/archives/commits-list/2013-May/msg01329.html
-            // FIXME: still necessary?
-            "res_init" => true,
-
-            // Definition of those functions as changed since unified headers from NDK r14b
-            // These changes imply some API breaking changes but are still ABI compatible.
-            // We can wait for the next major release to be compliant with the new API.
-            // FIXME: unskip these for next major release
-            "strerror_r" | "madvise" | "msync" | "mprotect" | "recvfrom" | "getpriority" |
-            "setpriority" | "personality"  => true,
-            // In Android 64 bits, these functions have been fixed since unified headers.
-            // Ignore these until next major version.
-            "bind" | "writev" | "readv" | "sendmsg" | "recvmsg"
-                if target_pointer_width == 64 => true,
+            // FIXME: https://github.com/rust-lang/libc/issues/1272
+            "execv" | "execve" | "execvp" | "execvpe" | "fexecve" => true,
 
-            _ => false,
-        }
-    });
+            // There are two versions of the sterror_r function, see
+            //
+            // https://linux.die.net/man/3/strerror_r
+            //
+            // An XSI-compliant version provided if:
+            //
+            // (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! _GNU_SOURCE
+            //
+            // and a GNU specific version provided if _GNU_SOURCE is defined.
+            //
+            // libc provides bindings for the XSI-compliant version, which is
+            // preferred for portable applications.
+            //
+            // We skip the test here since here _GNU_SOURCE is defined, and
+            // test the XSI version below.
+            "strerror_r" => true,
 
-    cfg.skip_static(move |name| {
-        match name {
-            // Internal constant, not declared in any headers.
-            // FIXME: still necessary
-            "__progname" => true,
             _ => false,
         }
     });
 
-    // FIXME: still necessary?
     cfg.skip_field_type(move |struct_, field| {
         // This is a weird union, don't check the type.
         (struct_ == "ifaddrs" && field == "ifa_ifu") ||
-        // sighandler_t type is super weird
-        (struct_ == "sigaction" && field == "sa_sigaction") ||
         // sigval is actually a union, but we pretend it's a struct
-        (struct_ == "sigevent" && field == "sigev_value") ||
-        // aio_buf is "volatile void*" and Rust doesn't understand volatile
-        (struct_ == "aiocb" && field == "aio_buf")
+        (struct_ == "sigevent" && field == "sigev_value")
     });
 
-    // FIXME: still necessary?
     cfg.skip_field(move |struct_, field| {
         // this is actually a union on linux, so we can't represent it well and
         // just insert some padding.
         (struct_ == "siginfo_t" && field == "_pad") ||
+        // FIXME: `sa_sigaction` has type `sighandler_t` but that type is
+        // incorrect, see: https://github.com/rust-lang/libc/issues/1359
+        (struct_ == "sigaction" && field == "sa_sigaction") ||
         // sigev_notify_thread_id is actually part of a sigev_un union
         (struct_ == "sigevent" && field == "sigev_notify_thread_id") ||
-        // signalfd had SIGSYS fields added in Linux 4.18, but no libc release has them yet.
-        (struct_ == "signalfd_siginfo" && (field == "ssi_addr_lsb" ||
-                                           field == "_pad2" ||
-                                           field == "ssi_syscall" ||
+        // signalfd had SIGSYS fields added in Android 4.19, but CI does not have that version yet.
+        (struct_ == "signalfd_siginfo" && (field == "ssi_syscall" ||
                                            field == "ssi_call_addr" ||
                                            field == "ssi_arch"))
     });
 
-    // FIXME: remove
-    cfg.fn_cname(move |name, _cname| name.to_string());
-
     cfg.generate("../src/lib.rs", "main.rs");
 
     // On Android also generate another script for testing linux/fcntl
     // declarations. These cannot be tested normally because including both
     // `linux/fcntl.h` and `fcntl.h` fails.
     //
-    // FIXME: is still necessary?
-    let mut cfg = ctest::TestGenerator::new();
-    cfg.skip_type(|_| true)
-        .skip_fn(|_| true)
-        .skip_static(|_| true);
-    cfg.header("linux/fcntl.h");
-    cfg.header("net/if.h");
-    cfg.header("linux/if.h");
-    cfg.header("linux/quota.h");
-    cfg.header("asm/termbits.h");
-    cfg.skip_const(move |name| match name {
-        "F_CANCELLK" | "F_ADD_SEALS" | "F_GET_SEALS" => false,
-        "F_SEAL_SEAL" | "F_SEAL_SHRINK" | "F_SEAL_GROW" | "F_SEAL_WRITE" => {
-            false
-        }
-        "BOTHER" => false,
-        _ => true,
-    });
-    cfg.skip_struct(|s| s != "termios2");
-    cfg.type_name(move |ty, is_struct, is_union| match ty {
-        t if is_struct => format!("struct {}", t),
-        t if is_union => format!("union {}", t),
-        t => t.to_string(),
-    });
-    cfg.generate("../src/lib.rs", "linux_fcntl.rs");
+    // This also tests strerror_r.
+    test_linux_termios2(target);
 }
 
 fn test_freebsd(target: &str) {
@@ -2776,11 +2662,45 @@ fn test_linux(target: &str) {
     // On Linux also generate another script for testing linux/fcntl declarations.
     // These cannot be tested normally because including both `linux/fcntl.h` and `fcntl.h`
     // fails on a lot of platforms.
+    test_linux_termios2(target);
+
+    // Test Elf64_Phdr and Elf32_Phdr
+    // These types have a field called `p_type`, but including
+    // "resolve.h" defines a `p_type` macro that expands to `__p_type`
+    // making the tests for these fails when both are included.
+    let mut cfg = ctest::TestGenerator::new();
+    cfg.skip_fn(|_| true)
+        .skip_const(|_| true)
+        .skip_static(|_| true)
+        .type_name(move |ty, _is_struct, _is_union| ty.to_string());
+    cfg.skip_struct(move |ty| match ty {
+        "Elf64_Phdr" | "Elf32_Phdr" => false,
+        _ => true,
+    });
+    cfg.skip_type(move |ty| match ty {
+        "Elf64_Phdr" | "Elf32_Phdr" => false,
+        _ => true,
+    });
+    cfg.header("elf.h");
+    cfg.generate("../src/lib.rs", "linux_elf.rs");
+}
+
+fn test_linux_termios2(target: &str) {
+    assert!(target.contains("linux") || target.contains("android"));
+    let musl = target.contains("musl");
     let mut cfg = ctest::TestGenerator::new();
     cfg.skip_type(|_| true)
-        .skip_fn(|_| true)
+        .skip_fn(|f| match f {
+            "strerror_r" => false,
+            _ => true,
+        })
         .skip_static(|_| true);
-    // musl defines these directly in `fcntl.h`
+    headers! {
+        cfg:
+      "linux/quota.h",
+        "asm/termbits.h",
+        "string.h"
+    }
     if musl {
         cfg.header("fcntl.h");
     } else {
@@ -2790,15 +2710,12 @@ fn test_linux(target: &str) {
         cfg.header("net/if.h");
         cfg.header("linux/if.h");
     }
-    cfg.header("linux/quota.h");
-    cfg.header("asm/termbits.h");
+
     cfg.skip_const(move |name| match name {
         "F_CANCELLK" | "F_ADD_SEALS" | "F_GET_SEALS" => false,
         "F_SEAL_SEAL" | "F_SEAL_SHRINK" | "F_SEAL_GROW" | "F_SEAL_WRITE" => {
             false
         }
-        "QFMT_VFS_OLD" | "QFMT_VFS_V0" | "QFMT_VFS_V1" if mips => false,
-        "BOTHER" => false,
         _ => true,
     });
     cfg.skip_struct(|s| s != "termios2");
@@ -2808,24 +2725,4 @@ fn test_linux(target: &str) {
         t => t.to_string(),
     });
     cfg.generate("../src/lib.rs", "linux_fcntl.rs");
-
-    // Test Elf64_Phdr and Elf32_Phdr
-    // These types have a field called `p_type`, but including
-    // "resolve.h" defines a `p_type` macro that expands to `__p_type`
-    // making the tests for these fails when both are included.
-    let mut cfg = ctest::TestGenerator::new();
-    cfg.skip_fn(|_| true)
-        .skip_const(|_| true)
-        .skip_static(|_| true)
-        .type_name(move |ty, _is_struct, _is_union| ty.to_string());
-    cfg.skip_struct(move |ty| match ty {
-        "Elf64_Phdr" | "Elf32_Phdr" => false,
-        _ => true,
-    });
-    cfg.skip_type(move |ty| match ty {
-        "Elf64_Phdr" | "Elf32_Phdr" => false,
-        _ => true,
-    });
-    cfg.header("elf.h");
-    cfg.generate("../src/lib.rs", "linux_elf.rs");
 }
diff --git a/src/unix/bsd/mod.rs b/src/unix/bsd/mod.rs
index 03c987dd33741be895f186fdd859ccc760cf5f12..ef92bd5cd4bac4dd47f1784eebfb27c61de2554b 100644
--- a/src/unix/bsd/mod.rs
+++ b/src/unix/bsd/mod.rs
@@ -488,6 +488,8 @@ f! {
 }
 
 extern {
+    pub fn strerror_r(errnum: ::c_int, buf: *mut c_char,
+                      buflen: ::size_t) -> ::c_int;
     pub fn abs(i: ::c_int) -> ::c_int;
     pub fn atof(s: *const ::c_char) -> ::c_double;
     pub fn labs(i: ::c_long) -> ::c_long;
diff --git a/src/unix/haiku/mod.rs b/src/unix/haiku/mod.rs
index 8eb8bffc3da5f2bdfcc251b42bb4e1ff3c4d202b..885c83991fce96f101ba79ef25cdd3c6fa2c91aa 100644
--- a/src/unix/haiku/mod.rs
+++ b/src/unix/haiku/mod.rs
@@ -1209,6 +1209,9 @@ f! {
 }
 
 extern {
+    pub fn strerror_r(errnum: ::c_int, buf: *mut c_char,
+                      buflen: ::size_t) -> ::c_int;
+
     pub fn abs(i: ::c_int) -> ::c_int;
     pub fn atof(s: *const ::c_char) -> ::c_double;
     pub fn labs(i: ::c_long) -> ::c_long;
diff --git a/src/unix/hermit/mod.rs b/src/unix/hermit/mod.rs
index 583056bac4bdae485e6e754797b3b3df32df558a..4c5781163037c26010900e889572a79ccae74c66 100644
--- a/src/unix/hermit/mod.rs
+++ b/src/unix/hermit/mod.rs
@@ -964,6 +964,9 @@ f! {
 }
 
 extern {
+    pub fn strerror_r(errnum: ::c_int, buf: *mut c_char,
+                      buflen: ::size_t) -> ::c_int;
+
     pub fn sem_destroy(sem: *mut sem_t) -> ::c_int;
     pub fn sem_init(sem: *mut sem_t,
                     pshared: ::c_int,
diff --git a/src/unix/mod.rs b/src/unix/mod.rs
index b85a27108926f829ee0ba27a365aa099be6e5688..6240964dd5463115993a1798272b099e4be7567a 100644
--- a/src/unix/mod.rs
+++ b/src/unix/mod.rs
@@ -931,10 +931,6 @@ extern {
     pub fn pthread_rwlockattr_init(attr: *mut pthread_rwlockattr_t) -> ::c_int;
     pub fn pthread_rwlockattr_destroy(attr: *mut pthread_rwlockattr_t)
                                       -> ::c_int;
-    #[cfg_attr(all(target_os = "linux", not(target_env = "musl")),
-               link_name = "__xpg_strerror_r")]
-    pub fn strerror_r(errnum: ::c_int, buf: *mut c_char,
-                      buflen: ::size_t) -> ::c_int;
 
     #[cfg_attr(target_os = "illumos", link_name = "__xnet_getsockopt")]
     pub fn getsockopt(sockfd: ::c_int,
diff --git a/src/unix/newlib/mod.rs b/src/unix/newlib/mod.rs
index ea52ff560ad93cf615aa2679cdb6ddeb2d50e07e..93798e58b505956cef5d731f882be2389b687394 100644
--- a/src/unix/newlib/mod.rs
+++ b/src/unix/newlib/mod.rs
@@ -598,6 +598,11 @@ f! {
 }
 
 extern {
+    #[cfg_attr(target_os = "linux",
+               link_name = "__xpg_strerror_r")]
+    pub fn strerror_r(errnum: ::c_int, buf: *mut c_char,
+                      buflen: ::size_t) -> ::c_int;
+
     pub fn sem_destroy(sem: *mut sem_t) -> ::c_int;
     pub fn sem_init(sem: *mut sem_t,
                     pshared: ::c_int,
diff --git a/src/unix/notbsd/android/b32/mod.rs b/src/unix/notbsd/android/b32/mod.rs
index a8cc51b2215c8a29edb8e375e2edfb217e70ae9a..e0a0d7e67cf420f50c0985f8175620f5b54090a3 100644
--- a/src/unix/notbsd/android/b32/mod.rs
+++ b/src/unix/notbsd/android/b32/mod.rs
@@ -13,7 +13,7 @@ s! {
     pub struct sigaction {
         pub sa_sigaction: ::sighandler_t,
         pub sa_mask: ::sigset_t,
-        pub sa_flags: ::c_ulong,
+        pub sa_flags: ::c_int,
         pub sa_restorer: ::Option<extern fn()>,
     }
 
@@ -35,12 +35,12 @@ s! {
         pub st_size: ::c_longlong,
         pub st_blksize: ::blksize_t,
         pub st_blocks: ::c_ulonglong,
-        pub st_atime: ::c_ulong,
-        pub st_atime_nsec: ::c_ulong,
-        pub st_mtime: ::c_ulong,
-        pub st_mtime_nsec: ::c_ulong,
-        pub st_ctime: ::c_ulong,
-        pub st_ctime_nsec: ::c_ulong,
+        pub st_atime: ::c_long,
+        pub st_atime_nsec: ::c_long,
+        pub st_mtime: ::c_long,
+        pub st_mtime_nsec: ::c_long,
+        pub st_ctime: ::c_long,
+        pub st_ctime_nsec: ::c_long,
         pub st_ino: ::c_ulonglong,
     }
 
@@ -57,12 +57,12 @@ s! {
         pub st_size: ::c_longlong,
         pub st_blksize: ::blksize_t,
         pub st_blocks: ::c_ulonglong,
-        pub st_atime: ::c_ulong,
-        pub st_atime_nsec: ::c_ulong,
-        pub st_mtime: ::c_ulong,
-        pub st_mtime_nsec: ::c_ulong,
-        pub st_ctime: ::c_ulong,
-        pub st_ctime_nsec: ::c_ulong,
+        pub st_atime: ::c_long,
+        pub st_atime_nsec: ::c_long,
+        pub st_mtime: ::c_long,
+        pub st_mtime_nsec: ::c_long,
+        pub st_ctime: ::c_long,
+        pub st_ctime_nsec: ::c_long,
         pub st_ino: ::c_ulonglong,
     }
 
diff --git a/src/unix/notbsd/android/b64/aarch64.rs b/src/unix/notbsd/android/b64/aarch64.rs
index 44dfee6404da7f94858c46078dfe553b441c7d4a..cb1c81b26057921b99b6f3aeb221f5152a70fc17 100644
--- a/src/unix/notbsd/android/b64/aarch64.rs
+++ b/src/unix/notbsd/android/b64/aarch64.rs
@@ -16,11 +16,11 @@ s! {
         __pad2: ::c_int,
         pub st_blocks: ::c_long,
         pub st_atime: ::time_t,
-        pub st_atime_nsec: ::c_ulong,
+        pub st_atime_nsec: ::c_long,
         pub st_mtime: ::time_t,
-        pub st_mtime_nsec: ::c_ulong,
+        pub st_mtime_nsec: ::c_long,
         pub st_ctime: ::time_t,
-        pub st_ctime_nsec: ::c_ulong,
+        pub st_ctime_nsec: ::c_long,
         __unused4: ::c_uint,
         __unused5: ::c_uint,
     }
@@ -39,11 +39,11 @@ s! {
         __pad2: ::c_int,
         pub st_blocks: ::c_long,
         pub st_atime: ::time_t,
-        pub st_atime_nsec: ::c_ulong,
+        pub st_atime_nsec: ::c_long,
         pub st_mtime: ::time_t,
-        pub st_mtime_nsec: ::c_ulong,
+        pub st_mtime_nsec: ::c_long,
         pub st_ctime: ::time_t,
-        pub st_ctime_nsec: ::c_ulong,
+        pub st_ctime_nsec: ::c_long,
         __unused4: ::c_uint,
         __unused5: ::c_uint,
     }
@@ -322,4 +322,4 @@ pub const SYS_pwritev2: ::c_long = 287;
 pub const SYS_pkey_mprotect: ::c_long = 288;
 pub const SYS_pkey_alloc: ::c_long = 289;
 pub const SYS_pkey_free: ::c_long = 290;
-pub const SYS_syscalls: ::c_long = 291;
+pub const SYS_syscalls: ::c_long = 292;
diff --git a/src/unix/notbsd/android/b64/mod.rs b/src/unix/notbsd/android/b64/mod.rs
index 46becc53d4d383a098718f5cc5e0ebe4fe8eba7c..eb10c6384e503f1ced1783014435ae2ec5962d4d 100644
--- a/src/unix/notbsd/android/b64/mod.rs
+++ b/src/unix/notbsd/android/b64/mod.rs
@@ -13,7 +13,7 @@ s! {
     }
 
     pub struct sigaction {
-        pub sa_flags: ::c_uint,
+        pub sa_flags: ::c_int,
         pub sa_sigaction: ::sighandler_t,
         pub sa_mask: ::sigset_t,
         pub sa_restorer: ::Option<extern fn()>,
diff --git a/src/unix/notbsd/android/b64/x86_64.rs b/src/unix/notbsd/android/b64/x86_64.rs
index c813e7da32077836af5b320f10e2381ae8340ec9..2ab6080a6d63fb899c118fceca5e9ffc00702ae8 100644
--- a/src/unix/notbsd/android/b64/x86_64.rs
+++ b/src/unix/notbsd/android/b64/x86_64.rs
@@ -13,12 +13,12 @@ s! {
         pub st_size: ::off64_t,
         pub st_blksize: ::c_long,
         pub st_blocks: ::c_long,
-        pub st_atime: ::c_ulong,
-        pub st_atime_nsec: ::c_ulong,
-        pub st_mtime: ::c_ulong,
-        pub st_mtime_nsec: ::c_ulong,
-        pub st_ctime: ::c_ulong,
-        pub st_ctime_nsec: ::c_ulong,
+        pub st_atime: ::c_long,
+        pub st_atime_nsec: ::c_long,
+        pub st_mtime: ::c_long,
+        pub st_mtime_nsec: ::c_long,
+        pub st_ctime: ::c_long,
+        pub st_ctime_nsec: ::c_long,
         __unused: [::c_long; 3],
     }
 
@@ -33,12 +33,12 @@ s! {
         pub st_size: ::off64_t,
         pub st_blksize: ::c_long,
         pub st_blocks: ::c_long,
-        pub st_atime: ::c_ulong,
-        pub st_atime_nsec: ::c_ulong,
-        pub st_mtime: ::c_ulong,
-        pub st_mtime_nsec: ::c_ulong,
-        pub st_ctime: ::c_ulong,
-        pub st_ctime_nsec: ::c_ulong,
+        pub st_atime: ::c_long,
+        pub st_atime_nsec: ::c_long,
+        pub st_mtime: ::c_long,
+        pub st_mtime_nsec: ::c_long,
+        pub st_ctime: ::c_long,
+        pub st_ctime_nsec: ::c_long,
         __unused: [::c_long; 3],
     }
 }
diff --git a/src/unix/notbsd/android/mod.rs b/src/unix/notbsd/android/mod.rs
index 46dd6092402a17da3dc23364aba8968522035294..6fb61ae352c7005ab315527d239901d9a0152dc0 100644
--- a/src/unix/notbsd/android/mod.rs
+++ b/src/unix/notbsd/android/mod.rs
@@ -12,6 +12,7 @@ pub type pthread_t = ::c_long;
 pub type pthread_mutexattr_t = ::c_long;
 pub type pthread_rwlockattr_t = ::c_long;
 pub type pthread_condattr_t = ::c_long;
+pub type pthread_key_t = ::c_int;
 pub type fsfilcnt_t = ::c_ulong;
 pub type fsblkcnt_t = ::c_ulong;
 pub type nfds_t = ::c_uint;
@@ -547,6 +548,9 @@ cfg_if! {
     }
 }
 
+pub const MS_NOUSER: ::c_ulong = 0xffffffff80000000;
+pub const MS_RMT_MASK: ::c_ulong = 0x02800051;
+
 pub const O_TRUNC: ::c_int = 512;
 pub const O_CLOEXEC: ::c_int = 0x80000;
 pub const O_PATH: ::c_int = 0o10000000;
@@ -582,11 +586,11 @@ pub const EFD_CLOEXEC: ::c_int = 0x80000;
 pub const USER_PROCESS: ::c_short = 7;
 
 pub const BUFSIZ: ::c_uint = 1024;
-pub const FILENAME_MAX: ::c_uint = 1024;
+pub const FILENAME_MAX: ::c_uint = 4096;
 pub const FOPEN_MAX: ::c_uint = 20;
 pub const POSIX_FADV_DONTNEED: ::c_int = 4;
 pub const POSIX_FADV_NOREUSE: ::c_int = 5;
-pub const L_tmpnam: ::c_uint = 1024;
+pub const L_tmpnam: ::c_uint = 4096;
 pub const TMP_MAX: ::c_uint = 308915776;
 pub const _PC_LINK_MAX: ::c_int = 1;
 pub const _PC_MAX_CANON: ::c_int = 2;
@@ -1459,10 +1463,10 @@ pub const NF_IP6_PRI_CONNTRACK_HELPER: ::c_int = 300;
 pub const NF_IP6_PRI_LAST: ::c_int = ::INT_MAX;
 
 // linux/netfilter/nf_tables.h
-pub const NFT_TABLE_MAXNAMELEN: ::c_int = 32;
-pub const NFT_CHAIN_MAXNAMELEN: ::c_int = 32;
-pub const NFT_SET_MAXNAMELEN: ::c_int = 32;
-pub const NFT_OBJ_MAXNAMELEN: ::c_int = 32;
+pub const NFT_TABLE_MAXNAMELEN: ::c_int = 256;
+pub const NFT_CHAIN_MAXNAMELEN: ::c_int = 256;
+pub const NFT_SET_MAXNAMELEN: ::c_int = 256;
+pub const NFT_OBJ_MAXNAMELEN: ::c_int = 256;
 pub const NFT_USERDATA_MAXLEN: ::c_int = 256;
 
 pub const NFT_REG_VERDICT: ::c_int = 0;
@@ -1519,7 +1523,7 @@ pub const NFT_MSG_NEWOBJ: ::c_int = 18;
 pub const NFT_MSG_GETOBJ: ::c_int = 19;
 pub const NFT_MSG_DELOBJ: ::c_int = 20;
 pub const NFT_MSG_GETOBJ_RESET: ::c_int = 21;
-pub const NFT_MSG_MAX: ::c_int = 22;
+pub const NFT_MSG_MAX: ::c_int = 25;
 
 pub const NFT_SET_ANONYMOUS: ::c_int = 0x1;
 pub const NFT_SET_CONSTANT: ::c_int = 0x2;
@@ -1789,7 +1793,10 @@ pub const SIOCSIFMAP: ::c_ulong = 0x00008971;
 pub const MODULE_INIT_IGNORE_MODVERSIONS: ::c_uint = 0x0001;
 pub const MODULE_INIT_IGNORE_VERMAGIC: ::c_uint = 0x0002;
 
-// Similarity to Linux it's not used but defined for compatibility.
+#[deprecated(
+    since = "0.2.55",
+    note = "ENOATTR is not available on Android; use ENODATA instead"
+)]
 pub const ENOATTR: ::c_int = ::ENODATA;
 
 // linux/if_alg.h
@@ -1920,21 +1927,20 @@ f! {
 }
 
 extern {
-    static mut __progname: *mut ::c_char;
-}
+    pub fn strerror_r(errnum: ::c_int, buf: *mut c_char,
+                      buflen: ::size_t) -> ::c_int;
 
-extern {
     pub fn gettimeofday(tp: *mut ::timeval,
                         tz: *mut ::timezone) -> ::c_int;
-    pub fn madvise(addr: *const ::c_void, len: ::size_t, advice: ::c_int)
+    pub fn madvise(addr: *mut ::c_void, len: ::size_t, advice: ::c_int)
                    -> ::c_int;
     pub fn ioctl(fd: ::c_int, request: ::c_int, ...) -> ::c_int;
-    pub fn msync(addr: *const ::c_void, len: ::size_t,
+    pub fn msync(addr: *mut ::c_void, len: ::size_t,
                  flags: ::c_int) -> ::c_int;
-    pub fn mprotect(addr: *const ::c_void, len: ::size_t, prot: ::c_int)
+    pub fn mprotect(addr: *mut ::c_void, len: ::size_t, prot: ::c_int)
                     -> ::c_int;
     pub fn recvfrom(socket: ::c_int, buf: *mut ::c_void, len: ::size_t,
-                    flags: ::c_int, addr: *const ::sockaddr,
+                    flags: ::c_int, addr: *mut ::sockaddr,
                     addrlen: *mut ::socklen_t) -> ::ssize_t;
     pub fn getnameinfo(sa: *const ::sockaddr,
                        salen: ::socklen_t,
@@ -1944,11 +1950,12 @@ extern {
                        sevlen: ::size_t,
                        flags: ::c_int) -> ::c_int;
     pub fn ptrace(request: ::c_int, ...) -> ::c_long;
-    pub fn getpriority(which: ::c_int, who: ::c_int) -> ::c_int;
-    pub fn setpriority(which: ::c_int, who: ::c_int, prio: ::c_int) -> ::c_int;
+    pub fn getpriority(which: ::c_int, who: ::id_t) -> ::c_int;
+    pub fn setpriority(which: ::c_int, who: ::id_t, prio: ::c_int) -> ::c_int;
     pub fn __sched_cpualloc(count: ::size_t) -> *mut ::cpu_set_t;
     pub fn __sched_cpufree(set: *mut ::cpu_set_t);
-    pub fn __sched_cpucount(setsize: ::size_t, set: *mut cpu_set_t) -> ::c_int;
+    pub fn __sched_cpucount(setsize: ::size_t,
+                            set: *const cpu_set_t) -> ::c_int;
     pub fn sched_getcpu() -> ::c_int;
 
     pub fn utmpname(name: *const ::c_char) -> ::c_int;
@@ -2011,7 +2018,7 @@ extern {
                  fstype: *const ::c_char,
                  flags: ::c_ulong,
                  data: *const ::c_void) -> ::c_int;
-    pub fn personality(persona: ::c_ulong) -> ::c_int;
+    pub fn personality(persona: ::c_uint) -> ::c_int;
     pub fn prctl(option: ::c_int, ...) -> ::c_int;
     pub fn sched_getparam(pid: ::pid_t, param: *mut ::sched_param) -> ::c_int;
     pub fn ppoll(fds: *mut ::pollfd,
@@ -2063,7 +2070,6 @@ extern {
     pub fn sigaltstack(ss: *const stack_t,
                        oss: *mut stack_t) -> ::c_int;
     pub fn sem_close(sem: *mut sem_t) -> ::c_int;
-    pub fn getdtablesize() -> ::c_int;
     #[cfg_attr(target_os = "solaris", link_name = "__posix_getgrnam_r")]
     pub fn getgrnam_r(name: *const ::c_char,
                       grp: *mut ::group,
diff --git a/src/unix/notbsd/emscripten/mod.rs b/src/unix/notbsd/emscripten/mod.rs
index 8521d5dc4cb8457e198fd968b84f039ebac7196f..0a98eafb61e5c8b94f6ad5fc16d09ac07d6a9dad 100644
--- a/src/unix/notbsd/emscripten/mod.rs
+++ b/src/unix/notbsd/emscripten/mod.rs
@@ -17,6 +17,7 @@ pub type nfds_t = ::c_ulong;
 pub type nl_item = ::c_int;
 pub type idtype_t = ::c_uint;
 pub type loff_t = i32;
+pub type pthread_key_t = ::c_uint;
 
 pub type clock_t = c_long;
 pub type time_t = c_long;
@@ -573,6 +574,9 @@ cfg_if! {
     }
 }
 
+pub const MS_NOUSER: ::c_ulong = 0x80000000;
+pub const MS_RMT_MASK: ::c_ulong = 0x800051;
+
 pub const ABDAY_1: ::nl_item = 0x20000;
 pub const ABDAY_2: ::nl_item = 0x20001;
 pub const ABDAY_3: ::nl_item = 0x20002;
@@ -1683,6 +1687,9 @@ f! {
 }
 
 extern {
+    pub fn strerror_r(errnum: ::c_int, buf: *mut c_char,
+                      buflen: ::size_t) -> ::c_int;
+
     pub fn abs(i: ::c_int) -> ::c_int;
     pub fn atof(s: *const ::c_char) -> ::c_double;
     pub fn labs(i: ::c_long) -> ::c_long;
diff --git a/src/unix/notbsd/linux/mod.rs b/src/unix/notbsd/linux/mod.rs
index 89c79620f76b13d2967d0fb90c0486bc4ee60537..3e05ec9c8127529830e36f8761add7e5c2fb28b1 100644
--- a/src/unix/notbsd/linux/mod.rs
+++ b/src/unix/notbsd/linux/mod.rs
@@ -14,6 +14,7 @@ pub type nfds_t = ::c_ulong;
 pub type nl_item = ::c_int;
 pub type idtype_t = ::c_uint;
 pub type loff_t = ::c_longlong;
+pub type pthread_key_t = ::c_uint;
 
 pub type __u8 = ::c_uchar;
 pub type __u16 = ::c_ushort;
@@ -849,6 +850,9 @@ pub const _PC_ALLOC_SIZE_MIN: ::c_int = 18;
 pub const _PC_SYMLINK_MAX: ::c_int = 19;
 pub const _PC_2_SYMLINKS: ::c_int = 20;
 
+pub const MS_NOUSER: ::c_ulong = 0x80000000;
+pub const MS_RMT_MASK: ::c_ulong = 0x800051;
+
 pub const _SC_ARG_MAX: ::c_int = 0;
 pub const _SC_CHILD_MAX: ::c_int = 1;
 pub const _SC_CLK_TCK: ::c_int = 2;
@@ -1436,9 +1440,10 @@ pub const FALLOC_FL_ZERO_RANGE: ::c_int = 0x10;
 pub const FALLOC_FL_INSERT_RANGE: ::c_int = 0x20;
 pub const FALLOC_FL_UNSHARE_RANGE: ::c_int = 0x40;
 
-// On Linux, libc doesn't define this constant, libattr does instead.
-// We still define it for Linux as it's defined by libc on other platforms,
-// and it's mentioned in the man pages for getxattr and setxattr.
+#[deprecated(
+    since = "0.2.55",
+    note = "ENOATTR is not available on Linux; use ENODATA instead"
+)]
 pub const ENOATTR: ::c_int = ::ENODATA;
 
 pub const SO_ORIGINAL_DST: ::c_int = 80;
@@ -2080,6 +2085,11 @@ f! {
 }
 
 extern {
+    #[cfg_attr(not(target_env = "musl"),
+               link_name = "__xpg_strerror_r")]
+    pub fn strerror_r(errnum: ::c_int, buf: *mut c_char,
+                      buflen: ::size_t) -> ::c_int;
+
     pub fn abs(i: ::c_int) -> ::c_int;
     pub fn atof(s: *const ::c_char) -> ::c_double;
     pub fn labs(i: ::c_long) -> ::c_long;
diff --git a/src/unix/notbsd/mod.rs b/src/unix/notbsd/mod.rs
index 6b8adba4e74ea6572fd501eec8481d2ad6f0636f..ea1e7c69bb91946a742c5f11c5aa0fc9e768b071 100644
--- a/src/unix/notbsd/mod.rs
+++ b/src/unix/notbsd/mod.rs
@@ -1,5 +1,4 @@
 pub type sa_family_t = u16;
-pub type pthread_key_t = ::c_uint;
 pub type speed_t = ::c_uint;
 pub type tcflag_t = ::c_uint;
 pub type clockid_t = ::c_int;
@@ -580,10 +579,8 @@ pub const MS_KERNMOUNT: ::c_ulong = 0x400000;
 pub const MS_I_VERSION: ::c_ulong = 0x800000;
 pub const MS_STRICTATIME: ::c_ulong = 0x1000000;
 pub const MS_ACTIVE: ::c_ulong = 0x40000000;
-pub const MS_NOUSER: ::c_ulong = 0x80000000;
 pub const MS_MGC_VAL: ::c_ulong = 0xc0ed0000;
 pub const MS_MGC_MSK: ::c_ulong = 0xffff0000;
-pub const MS_RMT_MASK: ::c_ulong = 0x800051;
 
 pub const EPERM: ::c_int = 1;
 pub const ENOENT: ::c_int = 2;
diff --git a/src/unix/redox/mod.rs b/src/unix/redox/mod.rs
index 9f22ca20223459422c14f17a8249242babd5f02e..4131bb9cf32b5c91c9a1c9151018891afe22f796 100644
--- a/src/unix/redox/mod.rs
+++ b/src/unix/redox/mod.rs
@@ -534,6 +534,9 @@ cfg_if! {
 }
 
 extern {
+    pub fn strerror_r(errnum: ::c_int, buf: *mut c_char,
+                      buflen: ::size_t) -> ::c_int;
+
     // malloc.h
     pub fn memalign(align: ::size_t, size: ::size_t) -> *mut ::c_void;
 
diff --git a/src/unix/solarish/mod.rs b/src/unix/solarish/mod.rs
index 887cfc347bc5404ed1a122394371ca53bcf71190..062b2837dbd70f8b007320a3604dd24ca8aa642f 100644
--- a/src/unix/solarish/mod.rs
+++ b/src/unix/solarish/mod.rs
@@ -1786,6 +1786,9 @@ f! {
 }
 
 extern {
+    pub fn strerror_r(errnum: ::c_int, buf: *mut c_char,
+                      buflen: ::size_t) -> ::c_int;
+
     pub fn sem_destroy(sem: *mut sem_t) -> ::c_int;
     pub fn sem_init(sem: *mut sem_t,
                     pshared: ::c_int,
diff --git a/src/unix/uclibc/mod.rs b/src/unix/uclibc/mod.rs
index 4cb430b15f9c3e441788ec39b301de590c432180..9a430a9fa9b99ecef8969d55d7ce1fb84225ce12 100644
--- a/src/unix/uclibc/mod.rs
+++ b/src/unix/uclibc/mod.rs
@@ -1487,6 +1487,11 @@ f! {
 }
 
 extern {
+    #[cfg_attr(target_os = "linux",
+               link_name = "__xpg_strerror_r")]
+    pub fn strerror_r(errnum: ::c_int, buf: *mut c_char,
+                      buflen: ::size_t) -> ::c_int;
+
     pub fn sem_destroy(sem: *mut sem_t) -> ::c_int;
     pub fn sem_init(sem: *mut sem_t,
                     pshared: ::c_int,