diff --git a/libc-test/build.rs b/libc-test/build.rs
index 4fd21721b97a43b4b177c3372ed91aca45e1e6b7..b20e67a9cf7f0ef9199af9dce477037118328ad3 100644
--- a/libc-test/build.rs
+++ b/libc-test/build.rs
@@ -1337,6 +1337,9 @@ fn test_android(target: &str) {
 
             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),
 
@@ -1400,6 +1403,23 @@ fn test_android(target: &str) {
             "execvpe" |
             "fexecve" => true,
 
+            // 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,
+
             // not declared in newer android toolchains
             // FIXME: still necessary?
             "getdtablesize" => true,
@@ -1459,6 +1479,8 @@ fn test_android(target: &str) {
     // 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.
+    //
+    // This also tests strerror_r.
     test_linux_termios2();
 }
 
@@ -2701,7 +2723,10 @@ fn test_linux(target: &str) {
 fn test_linux_termios2() {
     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);
     headers! {
         cfg:
@@ -2709,7 +2734,8 @@ fn test_linux_termios2() {
         "net/if.h",
         "linux/if.h",
         "linux/quota.h",
-        "asm/termbits.h"
+        "asm/termbits.h",
+        "string.h"
     }
     cfg.skip_const(move |name| match name {
         "F_CANCELLK" | "F_ADD_SEALS" | "F_GET_SEALS" => false,
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/mod.rs b/src/unix/notbsd/android/mod.rs
index 16fd717b9bdc9078b92eceb875747a85c8fc386a..dda1903657d4f26fdabda07a7431fd71b147194b 100644
--- a/src/unix/notbsd/android/mod.rs
+++ b/src/unix/notbsd/android/mod.rs
@@ -1931,6 +1931,9 @@ extern {
 }
 
 extern {
+    pub fn strerror_r(errnum: ::c_int, buf: *mut c_char,
+                      buflen: ::size_t) -> ::c_int;
+
     pub fn gettimeofday(tp: *mut ::timeval,
                         tz: *mut ::timezone) -> ::c_int;
     pub fn madvise(addr: *mut ::c_void, len: ::size_t, advice: ::c_int)
diff --git a/src/unix/notbsd/emscripten/mod.rs b/src/unix/notbsd/emscripten/mod.rs
index 8db46795df4e4aa99f3050c18fc8d15f35c80fb3..0a98eafb61e5c8b94f6ad5fc16d09ac07d6a9dad 100644
--- a/src/unix/notbsd/emscripten/mod.rs
+++ b/src/unix/notbsd/emscripten/mod.rs
@@ -1687,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 6813a85457737c96f61255537ff13386317bb53b..bc39c88b009e76c34226ebcfe8ea5f9a95230e5f 100644
--- a/src/unix/notbsd/linux/mod.rs
+++ b/src/unix/notbsd/linux/mod.rs
@@ -1972,6 +1972,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/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,