diff --git a/.gitignore b/.gitignore
index f0ff2599d09b56baf64cb3af4906408f5212e00e..bbbad4bc51532d2886bb38ec65881eb72bc7ec65 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
 target
 Cargo.lock
 *~
+style
diff --git a/Cargo.lock b/Cargo.lock
deleted file mode 100644
index a8165ea8ca7b2e9503fd8a75fa06e824c6e6f790..0000000000000000000000000000000000000000
--- a/Cargo.lock
+++ /dev/null
@@ -1,340 +0,0 @@
-[[package]]
-name = "bitflags"
-version = "0.9.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "bitflags"
-version = "1.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "cc"
-version = "1.0.28"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "cfg-if"
-version = "0.1.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "ctest"
-version = "0.2.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)",
- "syntex_syntax 0.59.1 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "extprim"
-version = "1.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "fuchsia-zircon"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "fuchsia-zircon-sys"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "itoa"
-version = "0.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "kernel32-sys"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "libc"
-version = "0.2.47"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "libc"
-version = "0.2.48"
-dependencies = [
- "rustc-std-workspace-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "libc-test"
-version = "0.1.0"
-dependencies = [
- "ctest 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.48",
-]
-
-[[package]]
-name = "log"
-version = "0.3.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "log"
-version = "0.4.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "num-traits"
-version = "0.2.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "proc-macro2"
-version = "0.4.26"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "quote"
-version = "0.6.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "proc-macro2 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "rand"
-version = "0.4.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "rand_core"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "rdrand"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "rustc-std-workspace-core"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "rustc_version"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "ryu"
-version = "0.2.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "semver"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "semver-parser"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "serde"
-version = "1.0.85"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "serde_derive 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "serde_derive"
-version = "1.0.85"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "proc-macro2 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "serde_json"
-version = "1.0.36"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "syn"
-version = "0.15.26"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "proc-macro2 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "syntex_errors"
-version = "0.59.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "libc 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)",
- "syntex_pos 0.59.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "syntex_pos"
-version = "0.59.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "syntex_syntax"
-version = "0.59.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "extprim 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)",
- "syntex_errors 0.59.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "syntex_pos 0.59.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "term"
-version = "0.4.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "unicode-xid"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "winapi"
-version = "0.2.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "winapi"
-version = "0.3.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "winapi-build"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "winapi-i686-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "winapi-x86_64-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[metadata]
-"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
-"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
-"checksum cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4a8b715cb4597106ea87c7c84b2f1d452c7492033765df7f32651e66fcf749"
-"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
-"checksum ctest 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3574c0edc91c25cb50d1e4238f35ae2651b0beadf72bfec31fb4ead46b4eb5b8"
-"checksum extprim 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "054bc2552b3f66fa8097e29e47255bfff583c08e737a67cbbb54b817ddaa5206"
-"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
-"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
-"checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b"
-"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
-"checksum libc 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)" = "48450664a984b25d5b479554c29cc04e3150c97aa4c01da5604a2d4ed9151476"
-"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b"
-"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
-"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
-"checksum proc-macro2 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)" = "38fddd23d98b2144d197c0eca5705632d4fe2667d14a6be5df8934f8d74f1978"
-"checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1"
-"checksum rand 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "dee497e66d8d76bf08ce20c8d36e16f93749ab0bf89975b4f8ae5cee660c2da2"
-"checksum rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0905b6b7079ec73b314d4c748701f6931eb79fd97c668caa3f1899b22b32c6db"
-"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
-"checksum rustc-std-workspace-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1956f5517128a2b6f23ab2dadf1a976f4f5b27962e7724c2bf3d45e539ec098c"
-"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
-"checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7"
-"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
-"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
-"checksum serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)" = "534b8b91a95e0f71bca3ed5824752d558da048d4248c91af873b63bd60519752"
-"checksum serde_derive 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)" = "a915306b0f1ac5607797697148c223bedeaa36bcc2e28a01441cd638cc6567b4"
-"checksum serde_json 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)" = "574378d957d6dcdf1bbb5d562a15cbd5e644159432f84634b94e485267abbcc7"
-"checksum syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)" = "f92e629aa1d9c827b2bb8297046c1ccffc57c99b947a680d3ccff1f136a3bee9"
-"checksum syntex_errors 0.59.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3133289179676c9f5c5b2845bf5a2e127769f4889fcbada43035ef6bd662605e"
-"checksum syntex_pos 0.59.1 (registry+https://github.com/rust-lang/crates.io-index)" = "30ab669fa003d208c681f874bbc76d91cc3d32550d16b5d9d2087cf477316470"
-"checksum syntex_syntax 0.59.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03815b9f04d95828770d9c974aa39c6e1f6ef3114eb77a3ce09008a0d15dd142"
-"checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1"
-"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
-"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
-"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
-"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
-"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
-"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
diff --git a/Cargo.toml b/Cargo.toml
index 91616442051d6314eda3bc16515b4e905138e240..d20fc69ba86dfb6bc142bce3f4e5dfbec65c5b8e 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -27,6 +27,7 @@ default = ["use_std"]
 use_std = []
 align = []
 rustc-dep-of-std = ['align', 'rustc-std-workspace-core']
+extra_traits = ["align"]
 
 [workspace]
 members = ["libc-test"]
diff --git a/README.md b/README.md
index 636f10e4ec2d6db03d752cd7d8f40b0cc7e43a52..1caab8543857769dae3c63ecd93718fb92304239 100644
--- a/README.md
+++ b/README.md
@@ -44,6 +44,16 @@ activate the *align* feature. This requires Rust 1.25 or newer:
 libc = { version = "0.2", features = ["align"] }
 ```
 
+All structs implemented by the libc crate have the `Copy` and `Clone` traits
+implemented for them. The additional traits of `Debug, `Eq`, `Hash`, and
+`PartialEq` can be enabled with the *extra_traits* feature (requires Rust 1.25
+or newer):
+
+```toml
+[dependencies]
+libc = { version = "0.2", features = ["extra_traits"] }
+```
+
 ## What is libc?
 
 The primary purpose of this crate is to provide all of the definitions necessary
diff --git a/ci/run.sh b/ci/run.sh
index 81ebd61055b2bc2e9175dec3590fbdfa53b72d1f..853b7c10537ff1e68329c252caec446a3a4c1103 100755
--- a/ci/run.sh
+++ b/ci/run.sh
@@ -96,4 +96,8 @@ fi
 if [ "$(rustc --version | sed -E 's/^rustc 1\.([0-9]*)\..*/\1/')" -ge 25 ]; then
   cargo test $opt --features align --manifest-path libc-test/Cargo.toml --target "${TARGET}"
 fi
+# Test the `extra_traits` feature if this is building on Rust >= 1.25
+if [ "$(rustc --version | sed -E 's/^rustc 1\.([0-9]*)\..*/\1/')" -ge 25 ]; then
+  cargo test $opt --features extra_traits --manifest-path libc-test/Cargo.toml --target "${TARGET}"
+fi
 exec cargo test $opt --manifest-path libc-test/Cargo.toml --target "${TARGET}"
diff --git a/libc-test/Cargo.toml b/libc-test/Cargo.toml
index b782a95af8a343f97b94a929aaa520e625b74d1e..f8bd11b5edc908877d89a2ee9e429a1961245add 100644
--- a/libc-test/Cargo.toml
+++ b/libc-test/Cargo.toml
@@ -15,6 +15,7 @@ ctest = "0.2.8"
 default = [ "use_std" ]
 use_std = [ "libc/use_std" ]
 align = [ "libc/align" ]
+extra_traits = [ "libc/extra_traits" ]
 
 [[test]]
 name = "main"
diff --git a/src/cloudabi/mod.rs b/src/cloudabi/mod.rs
index df11de002ec629e1baeaf469448930488818c0fa..51859cb40b1279be564862a7d017c8146ad5368c 100644
--- a/src/cloudabi/mod.rs
+++ b/src/cloudabi/mod.rs
@@ -122,8 +122,18 @@ pub const PTHREAD_STACK_MIN: ::size_t = 1024;
 pub const SOCK_DGRAM: ::c_int = 128;
 pub const SOCK_STREAM: ::c_int = 130;
 
+#[cfg_attr(feature = "extra_traits", derive(Debug))]
 pub enum FILE {}
+impl ::dox::Copy for FILE {}
+impl ::dox::Clone for FILE {
+    fn clone(&self) -> FILE { *self }
+}
+#[cfg_attr(feature = "extra_traits", derive(Debug))]
 pub enum fpos_t {} // TODO: fill this out with a struct
+impl ::dox::Copy for fpos_t {}
+impl ::dox::Clone for fpos_t {
+    fn clone(&self) -> fpos_t { *self }
+}
 
 extern {
     pub fn isalnum(c: c_int) -> c_int;
@@ -313,6 +323,7 @@ cfg_if! {
         // enable more optimization opportunities around it recognizing things
         // like malloc/free.
         #[repr(u8)]
+        #[allow(missing_copy_implementations)]
         pub enum c_void {
             // Two dummy variants so the #[repr] attribute can be used.
             #[doc(hidden)]
diff --git a/src/fuchsia/mod.rs b/src/fuchsia/mod.rs
index e785fabf8eae55af132b6c224554c0bd05f59d5a..ba20979a748a3bb41d974c9c4fbc251ae2f5e82d 100644
--- a/src/fuchsia/mod.rs
+++ b/src/fuchsia/mod.rs
@@ -100,10 +100,30 @@ pub type c_ulong = u64;
 
 // FIXME: why are these uninhabited types? that seems... wrong?
 // Presumably these should be `()` or an `extern type` (when that stabilizes).
+#[cfg_attr(feature = "extra_traits", derive(Debug))]
 pub enum timezone {}
+impl ::dox::Copy for timezone {}
+impl ::dox::Clone for timezone {
+    fn clone(&self) -> timezone { *self }
+}
+#[cfg_attr(feature = "extra_traits", derive(Debug))]
 pub enum DIR {}
+impl ::dox::Copy for DIR {}
+impl ::dox::Clone for DIR {
+    fn clone(&self) -> DIR { *self }
+}
+#[cfg_attr(feature = "extra_traits", derive(Debug))]
 pub enum locale_t {}
+impl ::dox::Copy for locale_t {}
+impl ::dox::Clone for locale_t {
+    fn clone(&self) -> locale_t { *self }
+}
+#[cfg_attr(feature = "extra_traits", derive(Debug))]
 pub enum fpos64_t {} // TODO: fill this out with a struct
+impl ::dox::Copy for fpos64_t {}
+impl ::dox::Clone for fpos64_t {
+    fn clone(&self) -> fpos64_t { *self }
+}
 
 // PUB_STRUCT
 
@@ -3042,8 +3062,18 @@ f! {
 #[link(name = "fdio")]
 extern {}
 
+#[cfg_attr(feature = "extra_traits", derive(Debug))]
 pub enum FILE {}
+impl ::dox::Copy for FILE {}
+impl ::dox::Clone for FILE {
+    fn clone(&self) -> FILE { *self }
+}
+#[cfg_attr(feature = "extra_traits", derive(Debug))]
 pub enum fpos_t {} // TODO: fill this out with a struct
+impl ::dox::Copy for fpos_t {}
+impl ::dox::Clone for fpos_t {
+    fn clone(&self) -> fpos_t { *self }
+}
 
 extern {
     pub fn isalnum(c: c_int) -> c_int;
@@ -4097,6 +4127,7 @@ cfg_if! {
         // enable more optimization opportunities around it recognizing things
         // like malloc/free.
         #[repr(u8)]
+        #[allow(missing_copy_implementations)]
         pub enum c_void {
             // Two dummy variants so the #[repr] attribute can be used.
             #[doc(hidden)]
diff --git a/src/lib.rs b/src/lib.rs
index 03e78041ab61702094c38ac32ee2b6020d7e12dd..2300e823e96720c59839a0c016c17ee7da85dd30 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -156,6 +156,9 @@
 #![cfg_attr(feature = "rustc-dep-of-std", no_core)]
 #![cfg_attr(feature = "rustc-dep-of-std", allow(warnings))]
 #![cfg_attr(not(any(feature = "use_std", feature = "rustc-dep-of-std")), no_std)]
+// Enable lints
+#![cfg_attr(feature = "extra_traits", deny(missing_debug_implementations))]
+#![deny(missing_copy_implementations)]
 
 #[cfg(all(not(cross_platform_docs), feature = "use_std"))]
 extern crate std as core;
diff --git a/src/macros.rs b/src/macros.rs
index 77205788c8a6d99b4a7a78d7e14b4986a1578aa5..aabe6e8e7001ff71906bd1485b48fb694d1ad86e 100644
--- a/src/macros.rs
+++ b/src/macros.rs
@@ -35,6 +35,21 @@ macro_rules! __cfg_if_apply {
 }
 
 macro_rules! s {
+    ($($(#[$attr:meta])* pub $t:ident $i:ident { $($field:tt)* })*) => ($(
+        __item! {
+            #[repr(C)]
+            $(#[$attr])*
+            #[cfg_attr(feature = "extra_traits", derive(Debug, Eq, Hash, PartialEq))]
+            pub $t $i { $($field)* }
+        }
+        impl ::dox::Copy for $i {}
+        impl ::dox::Clone for $i {
+            fn clone(&self) -> $i { *self }
+        }
+    )*)
+}
+
+macro_rules! s_no_extra_traits {
     ($($(#[$attr:meta])* pub $t:ident $i:ident { $($field:tt)* })*) => ($(
         __item! {
             #[repr(C)]
diff --git a/src/redox/mod.rs b/src/redox/mod.rs
index 8dabd9063e169ce1588c26dd633ec1a28a727541..82782bc16404ecf5e600bffa718ce1eb583fb9e1 100644
--- a/src/redox/mod.rs
+++ b/src/redox/mod.rs
@@ -219,8 +219,18 @@ pub const SIGIO:     ::c_int = 29;
 pub const SIGPWR:    ::c_int = 30;
 pub const SIGSYS:    ::c_int = 31;
 
+#[cfg_attr(feature = "extra_traits", derive(Debug))]
 pub enum FILE {}
+impl ::dox::Copy for FILE {}
+impl ::dox::Clone for FILE {
+    fn clone(&self) -> FILE { *self }
+}
+#[cfg_attr(feature = "extra_traits", derive(Debug))]
 pub enum fpos_t {} // TODO: fill this out with a struct
+impl ::dox::Copy for fpos_t {}
+impl ::dox::Clone for fpos_t {
+    fn clone(&self) -> fpos_t { *self }
+}
 
 // intentionally not public, only used for fd_set
 cfg_if! {
@@ -383,6 +393,7 @@ cfg_if! {
         // enable more optimization opportunities around it recognizing things
         // like malloc/free.
         #[repr(u8)]
+        #[allow(missing_copy_implementations)]
         pub enum c_void {
             // Two dummy variants so the #[repr] attribute can be used.
             #[doc(hidden)]
diff --git a/src/sgx.rs b/src/sgx.rs
index 045133399b94e322f3101bd3722904d5397c3046..1d5ca21292e9fd4758552f4f94968b3f4c7394bc 100644
--- a/src/sgx.rs
+++ b/src/sgx.rs
@@ -43,6 +43,7 @@ cfg_if! {
         // enable more optimization opportunities around it recognizing things
         // like malloc/free.
         #[repr(u8)]
+        #[allow(missing_copy_implementations)]
         pub enum c_void {
             // Two dummy variants so the #[repr] attribute can be used.
             #[doc(hidden)]
diff --git a/src/switch.rs b/src/switch.rs
index e2d9b491cb762f8ede4dcc348bf04acccc1b5e0a..89e259ea27ca26b3c43d916971857ed833561248 100644
--- a/src/switch.rs
+++ b/src/switch.rs
@@ -45,6 +45,7 @@ cfg_if! {
         // enable more optimization opportunities around it recognizing things
         // like malloc/free.
         #[repr(u8)]
+        #[allow(missing_copy_implementations)]
         pub enum c_void {
             // Two dummy variants so the #[repr] attribute can be used.
             #[doc(hidden)]
diff --git a/src/unix/bsd/apple/b32.rs b/src/unix/bsd/apple/b32.rs
index 907ab02df44b64e68c8643ccd84601e035606734..284eae399ddecb1515b068d04e8ef84ac73f52ff 100644
--- a/src/unix/bsd/apple/b32.rs
+++ b/src/unix/bsd/apple/b32.rs
@@ -5,11 +5,6 @@ pub type c_ulong = u32;
 pub type boolean_t = ::c_int;
 
 s! {
-    pub struct pthread_attr_t {
-        __sig: c_long,
-        __opaque: [::c_char; 36]
-    }
-
     pub struct if_data {
         pub ifi_type: ::c_uchar,
         pub ifi_typelen: ::c_uchar,
@@ -50,6 +45,42 @@ s! {
     }
 }
 
+s_no_extra_traits!{
+    pub struct pthread_attr_t {
+        __sig: c_long,
+        __opaque: [::c_char; 36]
+    }
+}
+
+#[cfg(feature = "extra_traits")]
+impl PartialEq for pthread_attr_t {
+    fn eq(&self, other: &pthread_attr_t) -> bool {
+        self.__sig == other.__sig
+            && self.__opaque
+                .iter()
+                .zip(other.__opaque.iter())
+                .all(|(a,b)| a == b)
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl Eq for pthread_attr_t {}
+#[cfg(feature = "extra_traits")]
+impl std::fmt::Debug for pthread_attr_t {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        f.debug_struct("pthread_attr_t")
+            .field("__sig", &self.__sig)
+            // FIXME: .field("__opaque", &self.__opaque)
+            .finish()
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl std::hash::Hash for pthread_attr_t {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.__sig.hash(state);
+        self.__opaque.hash(state);
+    }
+}
+
 pub const __PTHREAD_MUTEX_SIZE__: usize = 40;
 pub const __PTHREAD_COND_SIZE__: usize = 24;
 pub const __PTHREAD_CONDATTR_SIZE__: usize = 4;
diff --git a/src/unix/bsd/apple/b64.rs b/src/unix/bsd/apple/b64.rs
index 8e8c87dd287a0455d2220e797a3cc4f6bffee3a2..2161fc47590f999c824f30bf732c223d1f8fb217 100644
--- a/src/unix/bsd/apple/b64.rs
+++ b/src/unix/bsd/apple/b64.rs
@@ -5,11 +5,6 @@ pub type c_ulong = u64;
 pub type boolean_t = ::c_uint;
 
 s! {
-    pub struct pthread_attr_t {
-        __sig: c_long,
-        __opaque: [::c_char; 56]
-    }
-
     pub struct timeval32 {
         pub tv_sec: i32,
         pub tv_usec: i32,
@@ -55,6 +50,42 @@ s! {
     }
 }
 
+s_no_extra_traits!{
+    pub struct pthread_attr_t {
+        __sig: c_long,
+        __opaque: [::c_char; 56]
+    }
+}
+
+#[cfg(feature = "extra_traits")]
+impl PartialEq for pthread_attr_t {
+    fn eq(&self, other: &pthread_attr_t) -> bool {
+        self.__sig == other.__sig
+            && self.__opaque
+                .iter()
+                .zip(other.__opaque.iter())
+                .all(|(a,b)| a == b)
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl Eq for pthread_attr_t {}
+#[cfg(feature = "extra_traits")]
+impl std::fmt::Debug for pthread_attr_t {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        f.debug_struct("pthread_attr_t")
+            .field("__sig", &self.__sig)
+            // FIXME: .field("__opaque", &self.__opaque)
+            .finish()
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl std::hash::Hash for pthread_attr_t {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.__sig.hash(state);
+        self.__opaque.hash(state);
+    }
+}
+
 pub const __PTHREAD_MUTEX_SIZE__: usize = 56;
 pub const __PTHREAD_COND_SIZE__: usize = 40;
 pub const __PTHREAD_CONDATTR_SIZE__: usize = 8;
diff --git a/src/unix/bsd/apple/mod.rs b/src/unix/bsd/apple/mod.rs
index 837efff53d5ce4f32a796d96a1b1accd7c9cd7d4..59394c6bcaf1b1403593f0b044456bf1b9a5e6ab 100644
--- a/src/unix/bsd/apple/mod.rs
+++ b/src/unix/bsd/apple/mod.rs
@@ -34,7 +34,12 @@ pub type posix_spawn_file_actions_t = *mut ::c_void;
 pub type key_t = ::c_int;
 pub type shmatt_t = ::c_ushort;
 
+#[cfg_attr(feature = "extra_traits", derive(Debug))]
 pub enum timezone {}
+impl ::dox::Copy for timezone {}
+impl ::dox::Clone for timezone {
+    fn clone(&self) -> timezone { *self }
+}
 
 s! {
     pub struct aiocb {
@@ -47,17 +52,6 @@ s! {
         pub aio_lio_opcode: ::c_int
     }
 
-    pub struct utmpx {
-        pub ut_user: [::c_char; _UTX_USERSIZE],
-        pub ut_id: [::c_char; _UTX_IDSIZE],
-        pub ut_line: [::c_char; _UTX_LINESIZE],
-        pub ut_pid: ::pid_t,
-        pub ut_type: ::c_short,
-        pub ut_tv: ::timeval,
-        pub ut_host: [::c_char; _UTX_HOSTSIZE],
-        ut_pad: [::uint32_t; 16],
-    }
-
     pub struct glob_t {
         pub gl_pathc:  ::size_t,
         __unused1: ::c_int,
@@ -74,14 +68,6 @@ s! {
         __unused8: *mut ::c_void,
     }
 
-    pub struct sockaddr_storage {
-        pub ss_len: u8,
-        pub ss_family: ::sa_family_t,
-        __ss_pad1: [u8; 6],
-        __ss_align: i64,
-        __ss_pad2: [u8; 112],
-    }
-
     pub struct addrinfo {
         pub ai_flags: ::c_int,
         pub ai_family: ::c_int,
@@ -123,40 +109,16 @@ s! {
         pub st_qspare: [::int64_t; 2],
     }
 
-    pub struct dirent {
-        pub d_ino: u64,
-        pub d_seekoff: u64,
-        pub d_reclen: u16,
-        pub d_namlen: u16,
-        pub d_type: u8,
-        pub d_name: [::c_char; 1024],
-    }
-
-    pub struct pthread_mutex_t {
-        __sig: ::c_long,
-        __opaque: [u8; __PTHREAD_MUTEX_SIZE__],
-    }
-
     pub struct pthread_mutexattr_t {
         __sig: ::c_long,
         __opaque: [u8; 8],
     }
 
-    pub struct pthread_cond_t {
-        __sig: ::c_long,
-        __opaque: [u8; __PTHREAD_COND_SIZE__],
-    }
-
     pub struct pthread_condattr_t {
         __sig: ::c_long,
         __opaque: [u8; __PTHREAD_CONDATTR_SIZE__],
     }
 
-    pub struct pthread_rwlock_t {
-        __sig: ::c_long,
-        __opaque: [u8; __PTHREAD_RWLOCK_SIZE__],
-    }
-
     pub struct pthread_rwlockattr_t {
         __sig: ::c_long,
         __opaque: [u8; __PTHREAD_RWLOCKATTR_SIZE__],
@@ -227,25 +189,6 @@ s! {
         pub sin_zero: [::c_char; 8],
     }
 
-    pub struct statfs {
-        pub f_bsize: ::uint32_t,
-        pub f_iosize: ::int32_t,
-        pub f_blocks: ::uint64_t,
-        pub f_bfree: ::uint64_t,
-        pub f_bavail: ::uint64_t,
-        pub f_files: ::uint64_t,
-        pub f_ffree: ::uint64_t,
-        pub f_fsid: ::fsid_t,
-        pub f_owner: ::uid_t,
-        pub f_type: ::uint32_t,
-        pub f_flags: ::uint32_t,
-        pub f_fssubtype: ::uint32_t,
-        pub f_fstypename: [::c_char; 16],
-        pub f_mntonname: [::c_char; 1024],
-        pub f_mntfromname: [::c_char; 1024],
-        pub f_reserved: [::uint32_t; 8],
-    }
-
     #[cfg_attr(feature = "rustc-dep-of-std", repr(packed(4)))]
     pub struct kevent {
         pub ident: ::uintptr_t,
@@ -400,20 +343,6 @@ s! {
         pub ptinfo: proc_taskinfo,
     }
 
-    pub struct proc_threadinfo {
-        pub pth_user_time: u64,
-        pub pth_system_time: u64,
-        pub pth_cpu_usage: i32,
-        pub pth_policy: i32,
-        pub pth_run_state: i32,
-        pub pth_flags: i32,
-        pub pth_sleep_time: i32,
-        pub pth_curpri: i32,
-        pub pth_priority: i32,
-        pub pth_maxpriority: i32,
-        pub pth_name: [::c_char; MAXTHREADNAMESIZE],
-    }
-
     pub struct xsw_usage {
         pub xsu_total: u64,
         pub xsu_avail: u64,
@@ -557,12 +486,6 @@ s! {
         pub sem_pad3: [::int32_t; 4],
     }
 
-    pub union semun {
-        pub val: ::c_int,
-        pub buf: *mut semid_ds,
-        pub array: *mut ::c_ushort,
-    }
-
     // sys/shm.h
 
     #[cfg_attr(feature = "rustc-dep-of-std", repr(packed(4)))]
@@ -589,6 +512,464 @@ s! {
     }
 }
 
+s_no_extra_traits!{
+    pub union semun {
+        pub val: ::c_int,
+        pub buf: *mut semid_ds,
+        pub array: *mut ::c_ushort,
+    }
+
+    pub struct proc_threadinfo {
+        pub pth_user_time: u64,
+        pub pth_system_time: u64,
+        pub pth_cpu_usage: i32,
+        pub pth_policy: i32,
+        pub pth_run_state: i32,
+        pub pth_flags: i32,
+        pub pth_sleep_time: i32,
+        pub pth_curpri: i32,
+        pub pth_priority: i32,
+        pub pth_maxpriority: i32,
+        pub pth_name: [::c_char; MAXTHREADNAMESIZE],
+    }
+
+    pub struct statfs {
+        pub f_bsize: ::uint32_t,
+        pub f_iosize: ::int32_t,
+        pub f_blocks: ::uint64_t,
+        pub f_bfree: ::uint64_t,
+        pub f_bavail: ::uint64_t,
+        pub f_files: ::uint64_t,
+        pub f_ffree: ::uint64_t,
+        pub f_fsid: ::fsid_t,
+        pub f_owner: ::uid_t,
+        pub f_type: ::uint32_t,
+        pub f_flags: ::uint32_t,
+        pub f_fssubtype: ::uint32_t,
+        pub f_fstypename: [::c_char; 16],
+        pub f_mntonname: [::c_char; 1024],
+        pub f_mntfromname: [::c_char; 1024],
+        pub f_reserved: [::uint32_t; 8],
+    }
+
+    pub struct dirent {
+        pub d_ino: u64,
+        pub d_seekoff: u64,
+        pub d_reclen: u16,
+        pub d_namlen: u16,
+        pub d_type: u8,
+        pub d_name: [::c_char; 1024],
+    }
+
+    pub struct pthread_rwlock_t {
+        __sig: ::c_long,
+        __opaque: [u8; __PTHREAD_RWLOCK_SIZE__],
+    }
+
+    pub struct pthread_mutex_t {
+        __sig: ::c_long,
+        __opaque: [u8; __PTHREAD_MUTEX_SIZE__],
+    }
+
+    pub struct pthread_cond_t {
+        __sig: ::c_long,
+        __opaque: [u8; __PTHREAD_COND_SIZE__],
+    }
+
+    pub struct sockaddr_storage {
+        pub ss_len: u8,
+        pub ss_family: ::sa_family_t,
+        __ss_pad1: [u8; 6],
+        __ss_align: i64,
+        __ss_pad2: [u8; 112],
+    }
+
+    pub struct utmpx {
+        pub ut_user: [::c_char; _UTX_USERSIZE],
+        pub ut_id: [::c_char; _UTX_IDSIZE],
+        pub ut_line: [::c_char; _UTX_LINESIZE],
+        pub ut_pid: ::pid_t,
+        pub ut_type: ::c_short,
+        pub ut_tv: ::timeval,
+        pub ut_host: [::c_char; _UTX_HOSTSIZE],
+        ut_pad: [::uint32_t; 16],
+    }
+}
+
+#[cfg(feature = "extra_traits")]
+impl PartialEq for semun {
+    fn eq(&self, other: &semun) -> bool {
+        unsafe { self.val == other.val }
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl Eq for semun {}
+#[cfg(feature = "extra_traits")]
+impl std::fmt::Debug for semun {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        f.debug_struct("semun")
+            .field("val", unsafe { &self.val })
+            .finish()
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl std::hash::Hash for semun {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        unsafe { self.val.hash(state) };
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl PartialEq for proc_threadinfo {
+    fn eq(&self, other: &proc_threadinfo) -> bool {
+        self.pth_user_time == other.pth_user_time
+            && self.pth_system_time == other.pth_system_time
+            && self.pth_cpu_usage == other.pth_cpu_usage
+            && self.pth_policy == other.pth_policy
+            && self.pth_run_state == other.pth_run_state
+            && self.pth_flags == other.pth_flags
+            && self.pth_sleep_time == other.pth_sleep_time
+            && self.pth_curpri == other.pth_curpri
+            && self.pth_priority == other.pth_priority
+            && self.pth_maxpriority == other.pth_maxpriority
+            && self
+                .pth_name
+                .iter()
+                .zip(other.pth_name.iter())
+                .all(|(a,b)| a == b)
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl Eq for proc_threadinfo {}
+#[cfg(feature = "extra_traits")]
+impl std::fmt::Debug for proc_threadinfo {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        f.debug_struct("proc_threadinfo")
+            .field("pth_user_time", &self.pth_user_time)
+            .field("pth_system_time", &self.pth_system_time)
+            .field("pth_cpu_usage", &self.pth_cpu_usage)
+            .field("pth_policy", &self.pth_policy)
+            .field("pth_run_state", &self.pth_run_state)
+            .field("pth_flags", &self.pth_flags)
+            .field("pth_sleep_time", &self.pth_sleep_time)
+            .field("pth_curpri", &self.pth_curpri)
+            .field("pth_priority", &self.pth_priority)
+            .field("pth_maxpriority", &self.pth_maxpriority)
+            // FIXME: .field("pth_name", &self.pth_name)
+            .finish()
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl std::hash::Hash for proc_threadinfo {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.pth_user_time.hash(state);
+        self.pth_system_time.hash(state);
+        self.pth_cpu_usage.hash(state);
+        self.pth_policy.hash(state);
+        self.pth_run_state.hash(state);
+        self.pth_flags.hash(state);
+        self.pth_sleep_time.hash(state);
+        self.pth_curpri.hash(state);
+        self.pth_priority.hash(state);
+        self.pth_maxpriority.hash(state);
+        self.pth_name.hash(state);
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl PartialEq for statfs {
+    fn eq(&self, other: &statfs) -> bool {
+        self.f_bsize == other.f_bsize
+            && self.f_iosize == other.f_iosize
+            && self.f_blocks == other.f_blocks
+            && self.f_bfree == other.f_bfree
+            && self.f_bavail == other.f_bavail
+            && self.f_files == other.f_files
+            && self.f_ffree == other.f_ffree
+            && self.f_fsid == other.f_fsid
+            && self.f_owner == other.f_owner
+            && self.f_flags == other.f_flags
+            && self.f_fssubtype == other.f_fssubtype
+            && self.f_fstypename == other.f_fstypename
+            && self.f_type == other.f_type
+            && self
+                .f_mntonname
+                .iter()
+                .zip(other.f_mntonname.iter())
+                .all(|(a,b)| a == b)
+            && self
+                .f_mntfromname
+                .iter()
+                .zip(other.f_mntfromname.iter())
+                .all(|(a,b)| a == b)
+            && self.f_reserved == other.f_reserved
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl Eq for statfs {}
+#[cfg(feature = "extra_traits")]
+impl std::fmt::Debug for statfs {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        f.debug_struct("statfs")
+            .field("f_bsize", &self.f_bsize)
+            .field("f_iosize", &self.f_iosize)
+            .field("f_blocks", &self.f_blocks)
+            .field("f_bfree", &self.f_bfree)
+            .field("f_bavail", &self.f_bavail)
+            .field("f_files", &self.f_files)
+            .field("f_ffree", &self.f_ffree)
+            .field("f_fsid", &self.f_fsid)
+            .field("f_owner", &self.f_owner)
+            .field("f_flags", &self.f_flags)
+            .field("f_fssubtype", &self.f_fssubtype)
+            .field("f_fstypename", &self.f_fstypename)
+            .field("f_type", &self.f_type)
+            // FIXME: .field("f_mntonname", &self.f_mntonname)
+            // FIXME: .field("f_mntfromname", &self.f_mntfromname)
+            .field("f_reserved", &self.f_reserved)
+            .finish()
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl std::hash::Hash for statfs {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.f_bsize.hash(state);
+        self.f_iosize.hash(state);
+        self.f_blocks.hash(state);
+        self.f_bfree.hash(state);
+        self.f_bavail.hash(state);
+        self.f_files.hash(state);
+        self.f_ffree.hash(state);
+        self.f_fsid.hash(state);
+        self.f_owner.hash(state);
+        self.f_flags.hash(state);
+        self.f_fssubtype.hash(state);
+        self.f_fstypename.hash(state);
+        self.f_type.hash(state);
+        self.f_mntonname.hash(state);
+        self.f_mntfromname.hash(state);
+        self.f_reserved.hash(state);
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl PartialEq for dirent {
+    fn eq(&self, other: &dirent) -> bool {
+        self.d_ino == other.d_ino
+            && self.d_seekoff == other.d_seekoff
+            && self.d_reclen == other.d_reclen
+            && self.d_namlen == other.d_namlen
+            && self.d_type == other.d_type
+            && self
+                .d_name
+                .iter()
+                .zip(other.d_name.iter())
+                .all(|(a,b)| a == b)
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl Eq for dirent {}
+#[cfg(feature = "extra_traits")]
+impl std::fmt::Debug for dirent {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        f.debug_struct("dirent")
+            .field("d_ino", &self.d_ino)
+            .field("d_seekoff", &self.d_seekoff)
+            .field("d_reclen", &self.d_reclen)
+            .field("d_namlen", &self.d_namlen)
+            .field("d_type", &self.d_type)
+            // FIXME: .field("d_name", &self.d_name)
+            .finish()
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl std::hash::Hash for dirent {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.d_ino.hash(state);
+        self.d_seekoff.hash(state);
+        self.d_reclen.hash(state);
+        self.d_namlen.hash(state);
+        self.d_type.hash(state);
+        self.d_name.hash(state);
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl PartialEq for pthread_rwlock_t {
+    fn eq(&self, other: &pthread_rwlock_t) -> bool {
+        self.__sig == other.__sig
+            && self.
+                __opaque
+                .iter()
+                .zip(other.__opaque.iter())
+                .all(|(a,b)| a == b)
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl Eq for pthread_rwlock_t {}
+#[cfg(feature = "extra_traits")]
+impl std::fmt::Debug for pthread_rwlock_t {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        f.debug_struct("pthread_rwlock_t")
+            .field("__sig", &self.__sig)
+            // FIXME: .field("__opaque", &self.__opaque)
+            .finish()
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl std::hash::Hash for pthread_rwlock_t {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.__sig.hash(state);
+        self.__opaque.hash(state);
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl PartialEq for pthread_mutex_t {
+    fn eq(&self, other: &pthread_mutex_t) -> bool {
+        self.__sig == other.__sig
+            && self.
+                __opaque
+                .iter()
+                .zip(other.__opaque.iter())
+                .all(|(a,b)| a == b)
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl Eq for pthread_mutex_t {}
+#[cfg(feature = "extra_traits")]
+impl std::fmt::Debug for pthread_mutex_t {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        f.debug_struct("pthread_mutex_t")
+            .field("__sig", &self.__sig)
+            // FIXME: .field("__opaque", &self.__opaque)
+            .finish()
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl std::hash::Hash for pthread_mutex_t {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.__sig.hash(state);
+        self.__opaque.hash(state);
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl PartialEq for pthread_cond_t {
+    fn eq(&self, other: &pthread_cond_t) -> bool {
+        self.__sig == other.__sig
+            && self.
+                __opaque
+                .iter()
+                .zip(other.__opaque.iter())
+                .all(|(a,b)| a == b)
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl Eq for pthread_cond_t {}
+#[cfg(feature = "extra_traits")]
+impl std::fmt::Debug for pthread_cond_t {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        f.debug_struct("pthread_cond_t")
+            .field("__sig", &self.__sig)
+            // FIXME: .field("__opaque", &self.__opaque)
+            .finish()
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl std::hash::Hash for pthread_cond_t {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.__sig.hash(state);
+        self.__opaque.hash(state);
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl PartialEq for sockaddr_storage {
+    fn eq(&self, other: &sockaddr_storage) -> bool {
+        self.ss_len == other.ss_len
+            && self.ss_family == other.ss_family
+            && self
+                .__ss_pad1
+                .iter()
+                .zip(other.__ss_pad1.iter())
+                .all(|(a, b)| a == b)
+            && self.__ss_align == other.__ss_align
+            && self
+                .__ss_pad2
+                .iter()
+                .zip(other.__ss_pad2.iter())
+                .all(|(a, b)| a == b)
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl Eq for sockaddr_storage {}
+#[cfg(feature = "extra_traits")]
+impl std::fmt::Debug for sockaddr_storage {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        f.debug_struct("sockaddr_storage")
+            .field("ss_len", &self.ss_len)
+            .field("ss_family", &self.ss_family)
+            .field("__ss_pad1", &self.__ss_pad1)
+            .field("__ss_align", &self.__ss_align)
+            // FIXME: .field("__ss_pad2", &self.__ss_pad2)
+            .finish()
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl std::hash::Hash for sockaddr_storage {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.ss_len.hash(state);
+        self.ss_family.hash(state);
+        self.__ss_pad1.hash(state);
+        self.__ss_align.hash(state);
+        self.__ss_pad2.hash(state);
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl PartialEq for utmpx {
+    fn eq(&self, other: &utmpx) -> bool {
+        self.ut_user
+            .iter()
+            .zip(other.ut_user.iter())
+            .all(|(a,b)| a == b)
+            && self.ut_id == other.ut_id
+            && self.ut_line == other.ut_line
+            && self.ut_pid == other.ut_pid
+            && self.ut_type == other.ut_type
+            && self.ut_tv == other.ut_tv
+            && self
+                .ut_host
+                .iter()
+                .zip(other.ut_host.iter())
+                .all(|(a,b)| a == b)
+            && self.ut_pad == other.ut_pad
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl Eq for utmpx {}
+#[cfg(feature = "extra_traits")]
+impl std::fmt::Debug for utmpx {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        f.debug_struct("utmpx")
+            // FIXME: .field("ut_user", &self.ut_user)
+            .field("ut_id", &self.ut_id)
+            .field("ut_line", &self.ut_line)
+            .field("ut_pid", &self.ut_pid)
+            .field("ut_type", &self.ut_type)
+            .field("ut_tv", &self.ut_tv)
+            // FIXME: .field("ut_host", &self.ut_host)
+            .field("ut_pad", &self.ut_pad)
+            .finish()
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl std::hash::Hash for utmpx {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.ut_user.hash(state);
+        self.ut_id.hash(state);
+        self.ut_line.hash(state);
+        self.ut_pid.hash(state);
+        self.ut_type.hash(state);
+        self.ut_tv.hash(state);
+        self.ut_host.hash(state);
+        self.ut_pad.hash(state);
+    }
+}
+
 pub const _UTX_USERSIZE: usize = 256;
 pub const _UTX_LINESIZE: usize = 32;
 pub const _UTX_IDSIZE: usize = 4;
diff --git a/src/unix/bsd/freebsdlike/dragonfly/mod.rs b/src/unix/bsd/freebsdlike/dragonfly/mod.rs
index 9caeb7c1db1f03cbc7c464b614ba3afcbe1e4549..5656a26be67198384d6e596bb78e6c478b10a285 100644
--- a/src/unix/bsd/freebsdlike/dragonfly/mod.rs
+++ b/src/unix/bsd/freebsdlike/dragonfly/mod.rs
@@ -18,7 +18,12 @@ pub type fsfilcnt_t = u64;
 
 pub type sem_t = *mut sem;
 
+#[cfg_attr(feature = "extra_traits", derive(Debug))]
 pub enum sem {}
+impl ::dox::Copy for sem {}
+impl ::dox::Clone for sem {
+    fn clone(&self) -> sem { *self }
+}
 
 s! {
 
diff --git a/src/unix/bsd/freebsdlike/mod.rs b/src/unix/bsd/freebsdlike/mod.rs
index 7118925e5f4812ed6b4a44e0c94f34d6e3c1390a..73f8852052e58cce20c956bf62da0ee39f7ef280 100644
--- a/src/unix/bsd/freebsdlike/mod.rs
+++ b/src/unix/bsd/freebsdlike/mod.rs
@@ -15,7 +15,12 @@ pub type speed_t = ::c_uint;
 pub type nl_item = ::c_int;
 pub type id_t = i64;
 
+#[cfg_attr(feature = "extra_traits", derive(Debug))]
 pub enum timezone {}
+impl ::dox::Copy for timezone {}
+impl ::dox::Clone for timezone {
+    fn clone(&self) -> timezone { *self }
+}
 
 s! {
     pub struct glob_t {
diff --git a/src/unix/bsd/mod.rs b/src/unix/bsd/mod.rs
index 12f6e14d93c7c63dc8212e8429e702b5034493e6..0541c5a005805ea92e3efd63ed60ec3868522d32 100644
--- a/src/unix/bsd/mod.rs
+++ b/src/unix/bsd/mod.rs
@@ -25,12 +25,6 @@ s! {
         pub sin6_scope_id: u32,
     }
 
-    pub struct sockaddr_un {
-        pub sun_len: u8,
-        pub sun_family: sa_family_t,
-        pub sun_path: [c_char; 104]
-    }
-
     pub struct passwd {
         pub pw_name: *mut ::c_char,
         pub pw_passwd: *mut ::c_char,
@@ -85,6 +79,39 @@ s! {
         pub tm_zone: *mut ::c_char,
     }
 
+    pub struct msghdr {
+        pub msg_name: *mut ::c_void,
+        pub msg_namelen: ::socklen_t,
+        pub msg_iov: *mut ::iovec,
+        pub msg_iovlen: ::c_int,
+        pub msg_control: *mut ::c_void,
+        pub msg_controllen: ::socklen_t,
+        pub msg_flags: ::c_int,
+    }
+
+    pub struct cmsghdr {
+        pub cmsg_len: ::socklen_t,
+        pub cmsg_level: ::c_int,
+        pub cmsg_type: ::c_int,
+    }
+
+    pub struct fsid_t {
+        __fsid_val: [::int32_t; 2],
+    }
+
+    pub struct if_nameindex {
+        pub if_index: ::c_uint,
+        pub if_name: *mut ::c_char,
+    }
+}
+
+s_no_extra_traits!{
+    pub struct sockaddr_un {
+        pub sun_len: u8,
+        pub sun_family: sa_family_t,
+        pub sun_path: [c_char; 104]
+    }
+
     pub struct utsname {
         #[cfg(not(target_os = "dragonfly"))]
         pub sysname: [::c_char; 256],
@@ -108,29 +135,91 @@ s! {
         pub machine: [::c_char; 32],
     }
 
-    pub struct msghdr {
-        pub msg_name: *mut ::c_void,
-        pub msg_namelen: ::socklen_t,
-        pub msg_iov: *mut ::iovec,
-        pub msg_iovlen: ::c_int,
-        pub msg_control: *mut ::c_void,
-        pub msg_controllen: ::socklen_t,
-        pub msg_flags: ::c_int,
-    }
+}
 
-    pub struct cmsghdr {
-        pub cmsg_len: ::socklen_t,
-        pub cmsg_level: ::c_int,
-        pub cmsg_type: ::c_int,
+#[cfg(feature = "extra_traits")]
+impl PartialEq for sockaddr_un {
+    fn eq(&self, other: &sockaddr_un) -> bool {
+        self.sun_len == other.sun_len
+            && self.sun_family == other.sun_family
+            && self
+                .sun_path
+                .iter()
+                .zip(other.sun_path.iter())
+                .all(|(a,b)| a == b)
     }
-
-    pub struct fsid_t {
-        __fsid_val: [::int32_t; 2],
+}
+#[cfg(feature = "extra_traits")]
+impl Eq for sockaddr_un {}
+#[cfg(feature = "extra_traits")]
+impl std::fmt::Debug for sockaddr_un {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        f.debug_struct("sockaddr_un")
+            .field("sun_len", &self.sun_len)
+            .field("sun_family", &self.sun_family)
+            // FIXME: .field("sun_path", &self.sun_path)
+            .finish()
     }
-
-    pub struct if_nameindex {
-        pub if_index: ::c_uint,
-        pub if_name: *mut ::c_char,
+}
+#[cfg(feature = "extra_traits")]
+impl std::hash::Hash for sockaddr_un {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.sun_len.hash(state);
+        self.sun_family.hash(state);
+        self.sun_path.hash(state);
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl PartialEq for utsname {
+    fn eq(&self, other: &utsname) -> bool {
+        self.sysname
+            .iter()
+            .zip(other.sysname.iter())
+            .all(|(a,b)| a == b)
+            && self
+                .nodename
+                .iter()
+                .zip(other.nodename.iter())
+                .all(|(a,b)| a == b)
+            && self
+                .release
+                .iter()
+                .zip(other.release.iter())
+                .all(|(a,b)| a == b)
+            && self
+                .version
+                .iter()
+                .zip(other.version.iter())
+                .all(|(a,b)| a == b)
+            && self
+                .machine
+                .iter()
+                .zip(other.machine.iter())
+                .all(|(a,b)| a == b)
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl Eq for utsname {}
+#[cfg(feature = "extra_traits")]
+impl std::fmt::Debug for utsname {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        f.debug_struct("utsname")
+            // FIXME: .field("sysname", &self.sysname)
+            // FIXME: .field("nodename", &self.nodename)
+            // FIXME: .field("release", &self.release)
+            // FIXME: .field("version", &self.version)
+            // FIXME: .field("machine", &self.machine)
+            .finish()
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl std::hash::Hash for utsname {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.sysname.hash(state);
+        self.nodename.hash(state);
+        self.release.hash(state);
+        self.version.hash(state);
+        self.machine.hash(state);
     }
 }
 
diff --git a/src/unix/bsd/netbsdlike/mod.rs b/src/unix/bsd/netbsdlike/mod.rs
index 291c081b97bc7538a388995e5bb22f092bd7d52c..764174d18ab7bd63a38e665b2b6ad93dd310c791 100644
--- a/src/unix/bsd/netbsdlike/mod.rs
+++ b/src/unix/bsd/netbsdlike/mod.rs
@@ -13,8 +13,18 @@ pub type clockid_t = ::c_int;
 pub type id_t = ::uint32_t;
 pub type sem_t = *mut sem;
 
+#[cfg_attr(feature = "extra_traits", derive(Debug))]
 pub enum timezone {}
+impl ::dox::Copy for timezone {}
+impl ::dox::Clone for timezone {
+    fn clone(&self) -> timezone { *self }
+}
+#[cfg_attr(feature = "extra_traits", derive(Debug))]
 pub enum sem {}
+impl ::dox::Copy for sem {}
+impl ::dox::Clone for sem {
+    fn clone(&self) -> sem { *self }
+}
 
 s! {
     pub struct sigaction {
diff --git a/src/unix/haiku/mod.rs b/src/unix/haiku/mod.rs
index 2aa5d13a6738185b5d88bd98abb113aa38539dd4..94d8039006d2a56fd4191626bac0976f3630898d 100644
--- a/src/unix/haiku/mod.rs
+++ b/src/unix/haiku/mod.rs
@@ -31,7 +31,12 @@ pub type nl_item = ::c_int;
 pub type id_t = i32;
 pub type idtype_t = ::c_uint;
 
+#[cfg_attr(feature = "extra_traits", derive(Debug))]
 pub enum timezone {}
+impl ::dox::Copy for timezone {}
+impl ::dox::Clone for timezone {
+    fn clone(&self) -> timezone { *self }
+}
 
 s! {
     pub struct sockaddr {
diff --git a/src/unix/mod.rs b/src/unix/mod.rs
index 88e13c58c7706c6ac46f813a9905332f3f65be41..409f2835fd04dde81cc6deaa8ea8b33d8ca56c8a 100644
--- a/src/unix/mod.rs
+++ b/src/unix/mod.rs
@@ -41,8 +41,18 @@ pub type in_port_t = u16;
 pub type sighandler_t = ::size_t;
 pub type cc_t = ::c_uchar;
 
+#[cfg_attr(feature = "extra_traits", derive(Debug))]
 pub enum DIR {}
+impl ::dox::Copy for DIR {}
+impl ::dox::Clone for DIR {
+    fn clone(&self) -> DIR { *self }
+}
+#[cfg_attr(feature = "extra_traits", derive(Debug))]
 pub enum locale_t {}
+impl ::dox::Copy for locale_t {}
+impl ::dox::Clone for locale_t {
+    fn clone(&self) -> locale_t { *self }
+}
 
 s! {
     pub struct group {
@@ -365,8 +375,18 @@ cfg_if! {
     }
 }
 
+#[cfg_attr(feature = "extra_traits", derive(Debug))]
 pub enum FILE {}
+impl ::dox::Copy for FILE {}
+impl ::dox::Clone for FILE {
+    fn clone(&self) -> FILE { *self }
+}
+#[cfg_attr(feature = "extra_traits", derive(Debug))]
 pub enum fpos_t {} // TODO: fill this out with a struct
+impl ::dox::Copy for fpos_t {}
+impl ::dox::Clone for fpos_t {
+    fn clone(&self) -> fpos_t { *self }
+}
 
 extern {
     pub fn isalnum(c: c_int) -> c_int;
@@ -1156,6 +1176,7 @@ cfg_if! {
         // enable more optimization opportunities around it recognizing things
         // like malloc/free.
         #[repr(u8)]
+        #[allow(missing_copy_implementations)]
         pub enum c_void {
             // Two dummy variants so the #[repr] attribute can be used.
             #[doc(hidden)]
diff --git a/src/unix/notbsd/android/b64/mod.rs b/src/unix/notbsd/android/b64/mod.rs
index fb943349b398489e82f7acc442e36b8ae2bde8ce..1da667bccc0c2b1b3b8c9105ca34a645b9308f57 100644
--- a/src/unix/notbsd/android/b64/mod.rs
+++ b/src/unix/notbsd/android/b64/mod.rs
@@ -34,25 +34,6 @@ s! {
         __reserved: [::c_char; 16],
     }
 
-    pub struct pthread_mutex_t {
-        value: ::c_int,
-        __reserved: [::c_char; 36],
-    }
-
-    pub struct pthread_cond_t {
-        value: ::c_int,
-        __reserved: [::c_char; 44],
-    }
-
-    pub struct pthread_rwlock_t {
-        numLocks: ::c_int,
-        writerThreadId: ::c_int,
-        pendingReaders: ::c_int,
-        pendingWriters: ::c_int,
-        attr: i32,
-        __reserved: [::c_char; 36],
-    }
-
     pub struct passwd {
         pub pw_name: *mut ::c_char,
         pub pw_passwd: *mut ::c_char,
@@ -126,6 +107,126 @@ s! {
     }
 }
 
+s_no_extra_traits!{
+    pub struct pthread_mutex_t {
+        value: ::c_int,
+        __reserved: [::c_char; 36],
+    }
+
+    pub struct pthread_cond_t {
+        value: ::c_int,
+        __reserved: [::c_char; 44],
+    }
+
+    pub struct pthread_rwlock_t {
+        numLocks: ::c_int,
+        writerThreadId: ::c_int,
+        pendingReaders: ::c_int,
+        pendingWriters: ::c_int,
+        attr: i32,
+        __reserved: [::c_char; 36],
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl PartialEq for pthread_mutex_t {
+    fn eq(&self, other: &pthread_mutex_t) -> bool {
+        self.value == other.value
+            && self
+                .__reserved
+                .iter()
+                .zip(other.__reserved.iter())
+                .all(|(a,b)| a == b)
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl Eq for pthread_mutex_t {}
+#[cfg(feature = "extra_traits")]
+impl std::fmt::Debug for pthread_mutex_t {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        f.debug_struct("pthread_mutex_t")
+            .field("value", &self.value)
+            // FIXME: .field("__reserved", &self.__reserved)
+            .finish()
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl std::hash::Hash for pthread_mutex_t {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.value.hash(state);
+        self.__reserved.hash(state);
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl PartialEq for pthread_cond_t {
+    fn eq(&self, other: &pthread_cond_t) -> bool {
+        self.value == other.value
+            && self
+                .__reserved
+                .iter()
+                .zip(other.__reserved.iter())
+                .all(|(a,b)| a == b)
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl Eq for pthread_cond_t {}
+#[cfg(feature = "extra_traits")]
+impl std::fmt::Debug for pthread_cond_t {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        f.debug_struct("pthread_cond_t")
+            .field("value", &self.value)
+            // FIXME: .field("__reserved", &self.__reserved)
+            .finish()
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl std::hash::Hash for pthread_cond_t {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.value.hash(state);
+        self.__reserved.hash(state);
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl PartialEq for pthread_rwlock_t {
+    fn eq(&self, other: &pthread_rwlock_t) -> bool {
+        self.numLocks == other.numLocks
+            && self.writerThreadId == other.writerThreadId
+            && self.pendingReaders == other.pendingReaders
+            && self.pendingWriters == other.pendingWriters
+            && self.attr == other.attr
+            && self
+                .__reserved
+                .iter()
+                .zip(other.__reserved.iter())
+                .all(|(a,b)| a == b)
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl Eq for pthread_rwlock_t {}
+#[cfg(feature = "extra_traits")]
+impl std::fmt::Debug for pthread_rwlock_t {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        f.debug_struct("pthread_rwlock_t")
+            .field("numLocks", &self.numLocks)
+            .field("writerThreadId", &self.writerThreadId)
+            .field("pendingReaders", &self.pendingReaders)
+            .field("pendingWriters", &self.pendingWriters)
+            .field("attr", &self.attr)
+            // FIXME: .field("__reserved", &self.__reserved)
+            .finish()
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl std::hash::Hash for pthread_rwlock_t {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.numLocks.hash(state);
+        self.writerThreadId.hash(state);
+        self.pendingReaders.hash(state);
+        self.pendingWriters.hash(state);
+        self.attr.hash(state);
+        self.__reserved.hash(state);
+    }
+}
+
 pub const RTLD_GLOBAL: ::c_int = 0x00100;
 pub const RTLD_NOW: ::c_int = 2;
 pub const RTLD_DEFAULT: *mut ::c_void = 0i64 as *mut ::c_void;
diff --git a/src/unix/notbsd/android/mod.rs b/src/unix/notbsd/android/mod.rs
index 972281c8287b665ca93862761ef59351490dc10e..0e2eebf056e39c2e004cdd2f33e1b010cf450f67 100644
--- a/src/unix/notbsd/android/mod.rs
+++ b/src/unix/notbsd/android/mod.rs
@@ -25,36 +25,12 @@ pub type idtype_t = ::c_int;
 pub type loff_t = ::c_longlong;
 
 s! {
-    pub struct dirent {
-        pub d_ino: u64,
-        pub d_off: i64,
-        pub d_reclen: ::c_ushort,
-        pub d_type: ::c_uchar,
-        pub d_name: [::c_char; 256],
-    }
-
-    pub struct dirent64 {
-        pub d_ino: u64,
-        pub d_off: i64,
-        pub d_reclen: ::c_ushort,
-        pub d_type: ::c_uchar,
-        pub d_name: [::c_char; 256],
-    }
-
     pub struct stack_t {
         pub ss_sp: *mut ::c_void,
         pub ss_flags: ::c_int,
         pub ss_size: ::size_t
     }
 
-    pub struct siginfo_t {
-        pub si_signo: ::c_int,
-        pub si_errno: ::c_int,
-        pub si_code: ::c_int,
-        pub _pad: [::c_int; 29],
-        _align: [usize; 0],
-    }
-
     pub struct __fsid_t {
         __val: [::c_int; 2],
     }
@@ -116,33 +92,11 @@ s! {
         __reserved: [::c_int; 3],
     }
 
-    pub struct lastlog {
-        ll_time: ::time_t,
-        ll_line: [::c_char; UT_LINESIZE],
-        ll_host: [::c_char; UT_HOSTSIZE],
-    }
-
     pub struct exit_status {
         pub e_termination: ::c_short,
         pub e_exit: ::c_short,
     }
 
-    pub struct utmp {
-        pub ut_type: ::c_short,
-        pub ut_pid: ::pid_t,
-        pub ut_line: [::c_char; UT_LINESIZE],
-        pub ut_id: [::c_char; 4],
-
-        pub ut_user: [::c_char; UT_NAMESIZE],
-        pub ut_host: [::c_char; UT_HOSTSIZE],
-        pub ut_exit: exit_status,
-        pub ut_session: ::c_long,
-        pub ut_tv: ::timeval,
-
-        pub ut_addr_v6: [::int32_t; 4],
-        unused: [::c_char; 20],
-    }
-
     pub struct statvfs {
         pub f_bsize: ::c_ulong,
         pub f_frsize: ::c_ulong,
@@ -240,6 +194,263 @@ s! {
     }
 }
 
+s_no_extra_traits!{
+    pub struct dirent {
+        pub d_ino: u64,
+        pub d_off: i64,
+        pub d_reclen: ::c_ushort,
+        pub d_type: ::c_uchar,
+        pub d_name: [::c_char; 256],
+    }
+
+    pub struct dirent64 {
+        pub d_ino: u64,
+        pub d_off: i64,
+        pub d_reclen: ::c_ushort,
+        pub d_type: ::c_uchar,
+        pub d_name: [::c_char; 256],
+    }
+
+    pub struct siginfo_t {
+        pub si_signo: ::c_int,
+        pub si_errno: ::c_int,
+        pub si_code: ::c_int,
+        pub _pad: [::c_int; 29],
+        _align: [usize; 0],
+    }
+
+    pub struct lastlog {
+        ll_time: ::time_t,
+        ll_line: [::c_char; UT_LINESIZE],
+        ll_host: [::c_char; UT_HOSTSIZE],
+    }
+
+    pub struct utmp {
+        pub ut_type: ::c_short,
+        pub ut_pid: ::pid_t,
+        pub ut_line: [::c_char; UT_LINESIZE],
+        pub ut_id: [::c_char; 4],
+        pub ut_user: [::c_char; UT_NAMESIZE],
+        pub ut_host: [::c_char; UT_HOSTSIZE],
+        pub ut_exit: exit_status,
+        pub ut_session: ::c_long,
+        pub ut_tv: ::timeval,
+        pub ut_addr_v6: [::int32_t; 4],
+        unused: [::c_char; 20],
+    }
+}
+
+#[cfg(feature = "extra_traits")]
+impl PartialEq for dirent {
+    fn eq(&self, other: &dirent) -> bool {
+        self.d_ino == other.d_ino
+            && self.d_off == other.d_off
+            && self.d_reclen == other.d_reclen
+            && self.d_type == other.d_type
+            && self
+                .d_name
+                .iter()
+                .zip(other.d_name.iter())
+                .all(|(a,b)| a == b)
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl Eq for dirent {}
+#[cfg(feature = "extra_traits")]
+impl std::fmt::Debug for dirent {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        f.debug_struct("dirent")
+            .field("d_ino", &self.d_ino)
+            .field("d_off", &self.d_off)
+            .field("d_reclen", &self.d_reclen)
+            .field("d_type", &self.d_type)
+            // FIXME: .field("d_name", &self.d_name)
+            .finish()
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl std::hash::Hash for dirent {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.d_ino.hash(state);
+        self.d_off.hash(state);
+        self.d_reclen.hash(state);
+        self.d_type.hash(state);
+        self.d_name.hash(state);
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl PartialEq for dirent64 {
+    fn eq(&self, other: &dirent64) -> bool {
+        self.d_ino == other.d_ino
+            && self.d_off == other.d_off
+            && self.d_reclen == other.d_reclen
+            && self.d_type == other.d_type
+            && self
+                .d_name
+                .iter()
+                .zip(other.d_name.iter())
+                .all(|(a,b)| a == b)
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl Eq for dirent64 {}
+#[cfg(feature = "extra_traits")]
+impl std::fmt::Debug for dirent64 {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        f.debug_struct("dirent64")
+            .field("d_ino", &self.d_ino)
+            .field("d_off", &self.d_off)
+            .field("d_reclen", &self.d_reclen)
+            .field("d_type", &self.d_type)
+            // FIXME: .field("d_name", &self.d_name)
+            .finish()
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl std::hash::Hash for dirent64 {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.d_ino.hash(state);
+        self.d_off.hash(state);
+        self.d_reclen.hash(state);
+        self.d_type.hash(state);
+        self.d_name.hash(state);
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl PartialEq for siginfo_t {
+    fn eq(&self, other: &siginfo_t) -> bool {
+        self.si_signo == other.si_signo
+            && self.si_errno == other.si_errno
+            && self.si_code == other.si_code
+            // Ignore _pad
+            // Ignore _align
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl Eq for siginfo_t {}
+#[cfg(feature = "extra_traits")]
+impl std::fmt::Debug for siginfo_t {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        f.debug_struct("siginfo_t")
+            .field("si_signo", &self.si_signo)
+            .field("si_errno", &self.si_errno)
+            .field("si_code", &self.si_code)
+            // Ignore _pad
+            // Ignore _align
+            .finish()
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl std::hash::Hash for siginfo_t {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.si_signo.hash(state);
+        self.si_errno.hash(state);
+        self.si_code.hash(state);
+            // Ignore _pad
+            // Ignore _align
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl PartialEq for lastlog {
+    fn eq(&self, other: &lastlog) -> bool {
+        self.ll_time == other.ll_time
+            && self
+                .ll_line
+                .iter()
+                .zip(other.ll_line.iter())
+                .all(|(a,b)| a == b)
+            && self
+                .ll_host
+                .iter()
+                .zip(other.ll_host.iter())
+                .all(|(a,b)| a == b)
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl Eq for lastlog {}
+#[cfg(feature = "extra_traits")]
+impl std::fmt::Debug for lastlog {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        f.debug_struct("lastlog")
+            .field("ll_time", &self.ll_time)
+            .field("ll_line", &self.ll_line)
+            // FIXME: .field("ll_host", &self.ll_host)
+            .finish()
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl std::hash::Hash for lastlog {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.ll_time.hash(state);
+        self.ll_line.hash(state);
+        self.ll_host.hash(state);
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl PartialEq for utmp {
+    fn eq(&self, other: &utmp) -> bool {
+        self.ut_type == other.ut_type
+            && self.ut_pid == other.ut_pid
+            && self
+                .ut_line
+                .iter()
+                .zip(other.ut_line.iter())
+                .all(|(a,b)| a == b)
+            && self.ut_id == other.ut_id
+            && self
+                .ut_user
+                .iter()
+                .zip(other.ut_user.iter())
+                .all(|(a,b)| a == b)
+            && self
+                .ut_host
+                .iter()
+                .zip(other.ut_host.iter())
+                .all(|(a,b)| a == b)
+            && self.ut_exit == other.ut_exit
+            && self.ut_session == other.ut_session
+            && self.ut_tv == other.ut_tv
+            && self.ut_addr_v6 == other.ut_addr_v6
+            && self.unused == other.unused
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl Eq for utmp {}
+#[cfg(feature = "extra_traits")]
+impl std::fmt::Debug for utmp {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        f.debug_struct("utmp")
+            .field("ut_type", &self.ut_type)
+            .field("ut_pid", &self.ut_pid)
+            .field("ut_line", &self.ut_line)
+            .field("ut_id", &self.ut_id)
+            .field("ut_user", &self.ut_user)
+            // FIXME: .field("ut_host", &self.ut_host)
+            .field("ut_exit", &self.ut_exit)
+            .field("ut_session", &self.ut_session)
+            .field("ut_tv", &self.ut_tv)
+            .field("ut_addr_v6", &self.ut_addr_v6)
+            .field("unused", &self.unused)
+            .finish()
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl std::hash::Hash for utmp {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.ut_type.hash(state);
+        self.ut_pid.hash(state);
+        self.ut_line.hash(state);
+        self.ut_id.hash(state);
+        self.ut_user.hash(state);
+        self.ut_host.hash(state);
+        self.ut_exit.hash(state);
+        self.ut_session.hash(state);
+        self.ut_tv.hash(state);
+        self.ut_addr_v6.hash(state);
+        self.unused.hash(state);
+    }
+}
+
 pub const O_TRUNC: ::c_int = 512;
 pub const O_CLOEXEC: ::c_int = 0x80000;
 pub const O_PATH: ::c_int = 0o10000000;
diff --git a/src/unix/notbsd/emscripten.rs b/src/unix/notbsd/emscripten.rs
index 28791d8fd5ac74a59f853a197be22f641dabe677..9bf2026b22e4d510a04d43758389e37ee89e1593 100644
--- a/src/unix/notbsd/emscripten.rs
+++ b/src/unix/notbsd/emscripten.rs
@@ -35,7 +35,12 @@ pub type c_long = i32;
 pub type c_ulong = u32;
 pub type nlink_t = u32;
 
+#[cfg_attr(feature = "extra_traits", derive(Debug))]
 pub enum fpos64_t {} // TODO: fill this out with a struct
+impl ::dox::Copy for fpos64_t {}
+impl ::dox::Clone for fpos64_t {
+    fn clone(&self) -> fpos64_t { *self }
+}
 
 s! {
     pub struct dirent {
diff --git a/src/unix/notbsd/linux/mod.rs b/src/unix/notbsd/linux/mod.rs
index ea26933f19434b86201a9602090e7efa4eb769f1..e1a24dcd3c0b8b756b63e1432ba7c7e739ab05e4 100644
--- a/src/unix/notbsd/linux/mod.rs
+++ b/src/unix/notbsd/linux/mod.rs
@@ -38,25 +38,14 @@ pub type Elf64_Sxword = i64;
 pub type Elf32_Section = u16;
 pub type Elf64_Section = u16;
 
+#[cfg_attr(feature = "extra_traits", derive(Debug))]
 pub enum fpos64_t {} // TODO: fill this out with a struct
+impl ::dox::Copy for fpos64_t {}
+impl ::dox::Clone for fpos64_t {
+    fn clone(&self) -> fpos64_t { *self }
+}
 
 s! {
-    pub struct dirent {
-        pub d_ino: ::ino_t,
-        pub d_off: ::off_t,
-        pub d_reclen: ::c_ushort,
-        pub d_type: ::c_uchar,
-        pub d_name: [::c_char; 256],
-    }
-
-    pub struct dirent64 {
-        pub d_ino: ::ino64_t,
-        pub d_off: ::off64_t,
-        pub d_reclen: ::c_ushort,
-        pub d_type: ::c_uchar,
-        pub d_name: [::c_char; 256],
-    }
-
     pub struct rlimit64 {
         pub rlim_cur: rlim64_t,
         pub rlim_max: rlim64_t,
@@ -75,74 +64,6 @@ s! {
         __unused5: *mut ::c_void,
     }
 
-    #[cfg_attr(all(feature = "align",
-                   target_pointer_width = "32",
-                   any(target_arch = "mips",
-                       target_arch = "arm",
-                       target_arch = "powerpc",
-                       target_arch = "x86_64",
-                       target_arch = "x86")),
-               repr(align(4)))]
-    #[cfg_attr(all(feature = "align",
-                   any(target_pointer_width = "64",
-                       not(any(target_arch = "mips",
-                               target_arch = "arm",
-                               target_arch = "powerpc",
-                               target_arch = "x86_64",
-                               target_arch = "x86")))),
-               repr(align(8)))]
-    pub struct pthread_mutex_t {
-        #[cfg(all(not(feature = "align"),
-                  any(target_arch = "mips",
-                      target_arch = "arm",
-                      target_arch = "powerpc",
-                      all(target_arch = "x86_64",
-                          target_pointer_width = "32"))))]
-        __align: [::c_long; 0],
-        #[cfg(not(any(feature = "align",
-                      target_arch = "mips",
-                      target_arch = "arm",
-                      target_arch = "powerpc",
-                      all(target_arch = "x86_64",
-                          target_pointer_width = "32"))))]
-        __align: [::c_longlong; 0],
-        size: [u8; __SIZEOF_PTHREAD_MUTEX_T],
-    }
-
-    #[cfg_attr(all(feature = "align",
-                   target_pointer_width = "32",
-                   any(target_arch = "mips",
-                       target_arch = "arm",
-                       target_arch = "powerpc",
-                       target_arch = "x86_64",
-                       target_arch = "x86")),
-               repr(align(4)))]
-    #[cfg_attr(all(feature = "align",
-                   any(target_pointer_width = "64",
-                       not(any(target_arch = "mips",
-                               target_arch = "arm",
-                               target_arch = "powerpc",
-                               target_arch = "x86_64",
-                               target_arch = "x86")))),
-               repr(align(8)))]
-    pub struct pthread_rwlock_t {
-        #[cfg(all(not(feature = "align"),
-                  any(target_arch = "mips",
-                      target_arch = "arm",
-                      target_arch = "powerpc",
-                      all(target_arch = "x86_64",
-                          target_pointer_width = "32"))))]
-        __align: [::c_long; 0],
-        #[cfg(not(any(feature = "align",
-                      target_arch = "mips",
-                      target_arch = "arm",
-                      target_arch = "powerpc",
-                      all(target_arch = "x86_64",
-                          target_pointer_width = "32"))))]
-        __align: [::c_longlong; 0],
-        size: [u8; __SIZEOF_PTHREAD_RWLOCK_T],
-    }
-
     #[cfg_attr(all(feature = "align",
                    any(target_pointer_width = "32",
                        target_arch = "x86_64", target_arch = "powerpc64",
@@ -188,30 +109,6 @@ s! {
         size: [u8; __SIZEOF_PTHREAD_RWLOCKATTR_T],
     }
 
-    #[cfg_attr(all(feature = "align",
-                   target_env = "musl",
-                   target_pointer_width = "32"),
-               repr(align(4)))]
-    #[cfg_attr(all(feature = "align",
-                   target_env = "musl",
-                   target_pointer_width = "64"),
-               repr(align(8)))]
-    #[cfg_attr(all(feature = "align",
-                   not(target_env = "musl"),
-                   target_arch = "x86"),
-               repr(align(4)))]
-    #[cfg_attr(all(feature = "align",
-                   not(target_env = "musl"),
-                   not(target_arch = "x86")),
-               repr(align(8)))]
-    pub struct pthread_cond_t {
-        #[cfg(all(not(feature = "align"), target_env = "musl"))]
-        __align: [*const ::c_void; 0],
-        #[cfg(not(any(feature = "align", target_env = "musl")))]
-        __align: [::c_longlong; 0],
-        size: [u8; __SIZEOF_PTHREAD_COND_T],
-    }
-
     #[cfg_attr(feature = "align", repr(align(4)))]
     pub struct pthread_condattr_t {
         #[cfg(not(feature = "align"))]
@@ -664,6 +561,263 @@ s! {
     }
 }
 
+s_no_extra_traits!{
+    pub struct dirent {
+        pub d_ino: ::ino_t,
+        pub d_off: ::off_t,
+        pub d_reclen: ::c_ushort,
+        pub d_type: ::c_uchar,
+        pub d_name: [::c_char; 256],
+    }
+
+    pub struct dirent64 {
+        pub d_ino: ::ino64_t,
+        pub d_off: ::off64_t,
+        pub d_reclen: ::c_ushort,
+        pub d_type: ::c_uchar,
+        pub d_name: [::c_char; 256],
+    }
+
+    #[cfg_attr(all(feature = "align",
+                   target_env = "musl",
+                   target_pointer_width = "32"),
+               repr(align(4)))]
+    #[cfg_attr(all(feature = "align",
+                   target_env = "musl",
+                   target_pointer_width = "64"),
+               repr(align(8)))]
+    #[cfg_attr(all(feature = "align",
+                   not(target_env = "musl"),
+                   target_arch = "x86"),
+               repr(align(4)))]
+    #[cfg_attr(all(feature = "align",
+                   not(target_env = "musl"),
+                   not(target_arch = "x86")),
+               repr(align(8)))]
+    pub struct pthread_cond_t {
+        #[cfg(all(not(feature = "align"), target_env = "musl"))]
+        __align: [*const ::c_void; 0],
+        #[cfg(not(any(feature = "align", target_env = "musl")))]
+        __align: [::c_longlong; 0],
+        size: [u8; __SIZEOF_PTHREAD_COND_T],
+    }
+
+    #[cfg_attr(all(feature = "align",
+                   target_pointer_width = "32",
+                   any(target_arch = "mips",
+                       target_arch = "arm",
+                       target_arch = "powerpc",
+                       target_arch = "x86_64",
+                       target_arch = "x86")),
+               repr(align(4)))]
+    #[cfg_attr(all(feature = "align",
+                   any(target_pointer_width = "64",
+                       not(any(target_arch = "mips",
+                               target_arch = "arm",
+                               target_arch = "powerpc",
+                               target_arch = "x86_64",
+                               target_arch = "x86")))),
+               repr(align(8)))]
+    pub struct pthread_mutex_t {
+        #[cfg(all(not(feature = "align"),
+                  any(target_arch = "mips",
+                      target_arch = "arm",
+                      target_arch = "powerpc",
+                      all(target_arch = "x86_64",
+                          target_pointer_width = "32"))))]
+        __align: [::c_long; 0],
+        #[cfg(not(any(feature = "align",
+                      target_arch = "mips",
+                      target_arch = "arm",
+                      target_arch = "powerpc",
+                      all(target_arch = "x86_64",
+                          target_pointer_width = "32"))))]
+        __align: [::c_longlong; 0],
+        size: [u8; __SIZEOF_PTHREAD_MUTEX_T],
+    }
+
+    #[cfg_attr(all(feature = "align",
+                   target_pointer_width = "32",
+                   any(target_arch = "mips",
+                       target_arch = "arm",
+                       target_arch = "powerpc",
+                       target_arch = "x86_64",
+                       target_arch = "x86")),
+               repr(align(4)))]
+    #[cfg_attr(all(feature = "align",
+                   any(target_pointer_width = "64",
+                       not(any(target_arch = "mips",
+                               target_arch = "arm",
+                               target_arch = "powerpc",
+                               target_arch = "x86_64",
+                               target_arch = "x86")))),
+               repr(align(8)))]
+    pub struct pthread_rwlock_t {
+        #[cfg(all(not(feature = "align"),
+                  any(target_arch = "mips",
+                      target_arch = "arm",
+                      target_arch = "powerpc",
+                      all(target_arch = "x86_64",
+                          target_pointer_width = "32"))))]
+        __align: [::c_long; 0],
+        #[cfg(not(any(feature = "align",
+                      target_arch = "mips",
+                      target_arch = "arm",
+                      target_arch = "powerpc",
+                      all(target_arch = "x86_64",
+                          target_pointer_width = "32"))))]
+        __align: [::c_longlong; 0],
+        size: [u8; __SIZEOF_PTHREAD_RWLOCK_T],
+    }
+}
+
+#[cfg(feature = "extra_traits")]
+impl PartialEq for dirent {
+    fn eq(&self, other: &dirent) -> bool {
+        self.d_ino == other.d_ino
+            && self.d_off == other.d_off
+            && self.d_reclen == other.d_reclen
+            && self.d_type == other.d_type
+            && self
+                .d_name
+                .iter()
+                .zip(other.d_name.iter())
+                .all(|(a,b)| a == b)
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl Eq for dirent {}
+#[cfg(feature = "extra_traits")]
+impl std::fmt::Debug for dirent {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        f.debug_struct("dirent")
+            .field("d_ino", &self.d_ino)
+            .field("d_off", &self.d_off)
+            .field("d_reclen", &self.d_reclen)
+            .field("d_type", &self.d_type)
+            // FIXME: .field("d_name", &self.d_name)
+            .finish()
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl std::hash::Hash for dirent {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.d_ino.hash(state);
+        self.d_off.hash(state);
+        self.d_reclen.hash(state);
+        self.d_type.hash(state);
+        self.d_name.hash(state);
+    }
+}
+
+#[cfg(feature = "extra_traits")]
+impl PartialEq for dirent64 {
+    fn eq(&self, other: &dirent64) -> bool {
+        self.d_ino == other.d_ino
+            && self.d_off == other.d_off
+            && self.d_reclen == other.d_reclen
+            && self.d_type == other.d_type
+            && self
+                .d_name
+                .iter()
+                .zip(other.d_name.iter())
+                .all(|(a,b)| a == b)
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl Eq for dirent64 {}
+#[cfg(feature = "extra_traits")]
+impl std::fmt::Debug for dirent64 {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        f.debug_struct("dirent64")
+            .field("d_ino", &self.d_ino)
+            .field("d_off", &self.d_off)
+            .field("d_reclen", &self.d_reclen)
+            .field("d_type", &self.d_type)
+            // FIXME: .field("d_name", &self.d_name)
+            .finish()
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl std::hash::Hash for dirent64 {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.d_ino.hash(state);
+        self.d_off.hash(state);
+        self.d_reclen.hash(state);
+        self.d_type.hash(state);
+        self.d_name.hash(state);
+    }
+}
+
+#[cfg(feature = "extra_traits")]
+impl PartialEq for pthread_cond_t {
+    fn eq(&self, other: &pthread_cond_t) -> bool {
+        self.size.iter().zip(other.size.iter()).all(|(a,b)| a == b)
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl Eq for pthread_cond_t {}
+#[cfg(feature = "extra_traits")]
+impl std::fmt::Debug for pthread_cond_t {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        f.debug_struct("pthread_cond_t")
+            // FIXME: .field("size", &self.size)
+            .finish()
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl std::hash::Hash for pthread_cond_t {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.size.hash(state);
+    }
+}
+
+#[cfg(feature = "extra_traits")]
+impl PartialEq for pthread_mutex_t {
+    fn eq(&self, other: &pthread_mutex_t) -> bool {
+        self.size.iter().zip(other.size.iter()).all(|(a,b)| a == b)
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl Eq for pthread_mutex_t {}
+#[cfg(feature = "extra_traits")]
+impl std::fmt::Debug for pthread_mutex_t {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        f.debug_struct("pthread_mutex_t")
+            // FIXME: .field("size", &self.size)
+            .finish()
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl std::hash::Hash for pthread_mutex_t {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.size.hash(state);
+    }
+}
+
+#[cfg(feature = "extra_traits")]
+impl PartialEq for pthread_rwlock_t {
+    fn eq(&self, other: &pthread_rwlock_t) -> bool {
+        self.size.iter().zip(other.size.iter()).all(|(a,b)| a == b)
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl Eq for pthread_rwlock_t {}
+#[cfg(feature = "extra_traits")]
+impl std::fmt::Debug for pthread_rwlock_t {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        f.debug_struct("pthread_rwlock_t")
+            // FIXME: .field("size", &self.size)
+            .finish()
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl std::hash::Hash for pthread_rwlock_t {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.size.hash(state);
+    }
+}
+
 pub const ABDAY_1: ::nl_item = 0x20000;
 pub const ABDAY_2: ::nl_item = 0x20001;
 pub const ABDAY_3: ::nl_item = 0x20002;
diff --git a/src/unix/notbsd/linux/musl/b32/x86.rs b/src/unix/notbsd/linux/musl/b32/x86.rs
index b6ea8c120f6bf280bf70da3dae4c93eee633724d..42ff2a2847e27da2b02ccf1fa603c8d235fd06fe 100644
--- a/src/unix/notbsd/linux/musl/b32/x86.rs
+++ b/src/unix/notbsd/linux/musl/b32/x86.rs
@@ -116,15 +116,6 @@ s! {
         __private: [u32; 22]
     }
 
-    pub struct ucontext_t {
-        pub uc_flags: ::c_ulong,
-        pub uc_link: *mut ucontext_t,
-        pub uc_stack: ::stack_t,
-        pub uc_mcontext: mcontext_t,
-        pub uc_sigmask: ::sigset_t,
-        __private: [u8; 112],
-    }
-
     pub struct siginfo_t {
         pub si_signo: ::c_int,
         pub si_errno: ::c_int,
@@ -176,6 +167,58 @@ s! {
     }
 }
 
+s_no_extra_traits!{
+    pub struct ucontext_t {
+        pub uc_flags: ::c_ulong,
+        pub uc_link: *mut ucontext_t,
+        pub uc_stack: ::stack_t,
+        pub uc_mcontext: mcontext_t,
+        pub uc_sigmask: ::sigset_t,
+        __private: [u8; 112],
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl PartialEq for ucontext_t {
+    fn eq(&self, other: &ucontext_t) -> bool {
+        self.uc_flags == other.uc_flags
+            && self.uc_link == other.uc_link
+            && self.uc_stack == other.uc_stack
+            && self.uc_mcontext == other.uc_mcontext
+            && self.uc_sigmask == other.uc_sigmask
+            && self
+                .__private
+                .iter()
+                .zip(other.__private.iter())
+                .all(|(a,b)| a == b)
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl Eq for ucontext_t {}
+#[cfg(feature = "extra_traits")]
+impl std::fmt::Debug for ucontext_t {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        f.debug_struct("ucontext_t")
+            .field("uc_flags", &self.uc_flags)
+            .field("uc_link", &self.uc_link)
+            .field("uc_stack", &self.uc_stack)
+            .field("uc_mcontext", &self.uc_mcontext)
+            .field("uc_sigmask", &self.uc_sigmask)
+            // Ignore __private field
+            .finish()
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl std::hash::Hash for ucontext_t {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.uc_flags.hash(state);
+        self.uc_link.hash(state);
+        self.uc_stack.hash(state);
+        self.uc_mcontext.hash(state);
+        self.uc_sigmask.hash(state);
+        self.__private.hash(state);
+    }
+}
+
 pub const SIGSTKSZ: ::size_t = 8192;
 pub const MINSIGSTKSZ: ::size_t = 2048;
 
diff --git a/src/unix/notbsd/linux/musl/b64/x86_64.rs b/src/unix/notbsd/linux/musl/b64/x86_64.rs
index 0e0fcec4d2e7c1d5727dd51312b59fca8df6ade8..8462a4f635876d08b91591d49a407d37ffdb2dd6 100644
--- a/src/unix/notbsd/linux/musl/b64/x86_64.rs
+++ b/src/unix/notbsd/linux/musl/b64/x86_64.rs
@@ -51,15 +51,6 @@ s! {
         __private: [u64; 32],
     }
 
-    pub struct ucontext_t {
-        pub uc_flags: ::c_ulong,
-        pub uc_link: *mut ucontext_t,
-        pub uc_stack: ::stack_t,
-        pub uc_mcontext: mcontext_t,
-        pub uc_sigmask: ::sigset_t,
-        __private: [u8; 512],
-    }
-
     pub struct ipc_perm {
         pub __ipc_perm_key: ::key_t,
         pub uid: ::uid_t,
@@ -73,6 +64,59 @@ s! {
     }
 }
 
+s_no_extra_traits!{
+    pub struct ucontext_t {
+        pub uc_flags: ::c_ulong,
+        pub uc_link: *mut ucontext_t,
+        pub uc_stack: ::stack_t,
+        pub uc_mcontext: mcontext_t,
+        pub uc_sigmask: ::sigset_t,
+        __private: [u8; 512],
+    }
+}
+
+#[cfg(feature = "extra_traits")]
+impl PartialEq for ucontext_t {
+    fn eq(&self, other: &ucontext_t) -> bool {
+        self.uc_flags == other.uc_flags
+            && self.uc_link == other.uc_link
+            && self.uc_stack == other.uc_stack
+            && self.uc_mcontext == other.uc_mcontext
+            && self.uc_sigmask == other.uc_sigmask
+            && self
+                .__private
+                .iter()
+                .zip(other.__private.iter())
+                .all(|(a,b)| a == b)
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl Eq for ucontext_t {}
+#[cfg(feature = "extra_traits")]
+impl std::fmt::Debug for ucontext_t {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        f.debug_struct("ucontext_t")
+            .field("uc_flags", &self.uc_flags)
+            .field("uc_link", &self.uc_link)
+            .field("uc_stack", &self.uc_stack)
+            .field("uc_mcontext", &self.uc_mcontext)
+            .field("uc_sigmask", &self.uc_sigmask)
+            // Ignore __private field
+            .finish()
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl std::hash::Hash for ucontext_t {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.uc_flags.hash(state);
+        self.uc_link.hash(state);
+        self.uc_stack.hash(state);
+        self.uc_mcontext.hash(state);
+        self.uc_sigmask.hash(state);
+        self.__private.hash(state);
+    }
+}
+
 // Syscall table
 
 pub const SYS_read: ::c_long = 0;
diff --git a/src/unix/notbsd/linux/musl/mod.rs b/src/unix/notbsd/linux/musl/mod.rs
index 5ab5d0f69193df8f3840e4db4f3caebf6cfa7133..b3ab650277187dfae14603f027834d7888b6dbe6 100644
--- a/src/unix/notbsd/linux/musl/mod.rs
+++ b/src/unix/notbsd/linux/musl/mod.rs
@@ -78,7 +78,9 @@ s! {
         pub l_len: ::off_t,
         pub l_pid: ::pid_t,
     }
+}
 
+s_no_extra_traits!{
     pub struct sysinfo {
         pub uptime: ::c_ulong,
         pub loads: [::c_ulong; 3],
@@ -97,6 +99,68 @@ s! {
     }
 }
 
+#[cfg(feature = "extra_traits")]
+impl PartialEq for sysinfo {
+    fn eq(&self, other: &sysinfo) -> bool {
+        self.uptime == other.uptime
+            && self.loads == other.loads
+            && self.totalram == other.totalram
+            && self.freeram == other.freeram
+            && self.sharedram == other.sharedram
+            && self.bufferram == other.bufferram
+            && self.totalswap == other.totalswap
+            && self.freeswap == other.freeswap
+            && self.procs == other.procs
+            && self.pad == other.pad
+            && self.totalhigh == other.totalhigh
+            && self.freehigh == other.freehigh
+            && self.mem_unit == other.mem_unit
+            // Ignore __reserved field
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl Eq for sysinfo {}
+#[cfg(feature = "extra_traits")]
+impl std::fmt::Debug for sysinfo {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        f.debug_struct("sysinfo")
+            .field("uptime", &self.uptime)
+            .field("loads", &self.loads)
+            .field("totalram", &self.totalram)
+            .field("freeram", &self.freeram)
+            .field("sharedram", &self.sharedram)
+            .field("bufferram", &self.bufferram)
+            .field("totalswap", &self.totalswap)
+            .field("freeswap", &self.freeswap)
+            .field("procs", &self.procs)
+            .field("pad", &self.pad)
+            .field("totalhigh", &self.totalhigh)
+            .field("freehigh", &self.freehigh)
+            .field("mem_unit", &self.mem_unit)
+            // FIXME: .field("__reserved", &self.__reserved)
+            .finish()
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl std::hash::Hash for sysinfo {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.uptime.hash(state);
+        self.loads.hash(state);
+        self.totalram.hash(state);
+        self.freeram.hash(state);
+        self.sharedram.hash(state);
+        self.bufferram.hash(state);
+        self.totalswap.hash(state);
+        self.freeswap.hash(state);
+        self.procs.hash(state);
+        self.pad.hash(state);
+        self.totalhigh.hash(state);
+        self.freehigh.hash(state);
+        self.mem_unit.hash(state);
+        self.__reserved.hash(state);
+    }
+}
+
 pub const SFD_CLOEXEC: ::c_int = 0x080000;
 
 pub const NCCS: usize = 32;
diff --git a/src/unix/notbsd/linux/other/b32/x86.rs b/src/unix/notbsd/linux/other/b32/x86.rs
index 6c41718d124b3679546aa0d651d51922e2311d3b..fb48982162a3463c9411b8123b5002431e6de615 100644
--- a/src/unix/notbsd/linux/other/b32/x86.rs
+++ b/src/unix/notbsd/linux/other/b32/x86.rs
@@ -31,22 +31,6 @@ s! {
         pub st_space: [::c_long; 20],
     }
 
-    pub struct user_fpxregs_struct {
-        pub cwd: ::c_ushort,
-        pub swd: ::c_ushort,
-        pub twd: ::c_ushort,
-        pub fop: ::c_ushort,
-        pub fip: ::c_long,
-        pub fcs: ::c_long,
-        pub foo: ::c_long,
-        pub fos: ::c_long,
-        pub mxcsr: ::c_long,
-        __reserved: ::c_long,
-        pub st_space: [::c_long; 32],
-        pub xmm_space: [::c_long; 32],
-        padding: [::c_long; 56],
-    }
-
     pub struct user_regs_struct {
         pub ebx: ::c_long,
         pub ecx: ::c_long,
@@ -92,15 +76,6 @@ s! {
         pub cr2: ::c_ulong,
     }
 
-    pub struct ucontext_t {
-        pub uc_flags: ::c_ulong,
-        pub uc_link: *mut ucontext_t,
-        pub uc_stack: ::stack_t,
-        pub uc_mcontext: mcontext_t,
-        pub uc_sigmask: ::sigset_t,
-        __private: [u8; 112],
-    }
-
     pub struct ipc_perm {
         pub __key: ::key_t,
         pub uid: ::uid_t,
@@ -213,6 +188,129 @@ s! {
     }
 }
 
+s_no_extra_traits!{
+    pub struct user_fpxregs_struct {
+        pub cwd: ::c_ushort,
+        pub swd: ::c_ushort,
+        pub twd: ::c_ushort,
+        pub fop: ::c_ushort,
+        pub fip: ::c_long,
+        pub fcs: ::c_long,
+        pub foo: ::c_long,
+        pub fos: ::c_long,
+        pub mxcsr: ::c_long,
+        __reserved: ::c_long,
+        pub st_space: [::c_long; 32],
+        pub xmm_space: [::c_long; 32],
+        padding: [::c_long; 56],
+    }
+
+    pub struct ucontext_t {
+        pub uc_flags: ::c_ulong,
+        pub uc_link: *mut ucontext_t,
+        pub uc_stack: ::stack_t,
+        pub uc_mcontext: mcontext_t,
+        pub uc_sigmask: ::sigset_t,
+        __private: [u8; 112],
+    }
+}
+
+#[cfg(feature = "extra_traits")]
+impl PartialEq for user_fpxregs_struct {
+    fn eq(&self, other: &user_fpxregs_struct) -> bool {
+        self.cwd == other.cwd
+            && self.swd == other.swd
+            && self.twd == other.twd
+            && self.fop == other.fop
+            && self.fip == other.fip
+            && self.fcs == other.fcs
+            && self.foo == other.foo
+            && self.fos == other.fos
+            && self.mxcsr == other.mxcsr
+            // Ignore __reserved field
+            && self.st_space == other.st_space
+            && self.xmm_space == other.xmm_space
+            // Ignore padding field
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl Eq for user_fpxregs_struct {}
+#[cfg(feature = "extra_traits")]
+impl std::fmt::Debug for user_fpxregs_struct {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        f.debug_struct("user_fpxregs_struct")
+            .field("cwd", &self.cwd)
+            .field("swd", &self.swd)
+            .field("twd", &self.twd)
+            .field("fop", &self.fop)
+            .field("fip", &self.fip)
+            .field("fcs", &self.fcs)
+            .field("foo", &self.foo)
+            .field("fos", &self.fos)
+            .field("mxcsr", &self.mxcsr)
+            // Ignore __reserved field
+            .field("st_space", &self.st_space)
+            .field("xmm_space", &self.xmm_space)
+            // Ignore padding field
+            .finish()
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl std::hash::Hash for user_fpxregs_struct {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.cwd.hash(state);
+        self.swd.hash(state);
+        self.twd.hash(state);
+        self.fop.hash(state);
+        self.fip.hash(state);
+        self.fcs.hash(state);
+        self.foo.hash(state);
+        self.fos.hash(state);
+        self.mxcsr.hash(state);
+        // Ignore __reserved field
+        self.st_space.hash(state);
+        self.xmm_space.hash(state);
+        // Ignore padding field
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl PartialEq for ucontext_t {
+    fn eq(&self, other: &ucontext_t) -> bool {
+        self.uc_flags == other.uc_flags
+            && self.uc_link == other.uc_link
+            && self.uc_stack == other.uc_stack
+            && self.uc_mcontext == other.uc_mcontext
+            && self.uc_sigmask == other.uc_sigmask
+            // Ignore __private field
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl Eq for ucontext_t {}
+#[cfg(feature = "extra_traits")]
+impl std::fmt::Debug for ucontext_t {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        f.debug_struct("ucontext_t")
+            .field("uc_flags", &self.uc_flags)
+            .field("uc_link", &self.uc_link)
+            .field("uc_stack", &self.uc_stack)
+            .field("uc_mcontext", &self.uc_mcontext)
+            .field("uc_sigmask", &self.uc_sigmask)
+            // Ignore __private field
+            .finish()
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl std::hash::Hash for ucontext_t {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.uc_flags.hash(state);
+        self.uc_link.hash(state);
+        self.uc_stack.hash(state);
+        self.uc_mcontext.hash(state);
+        self.uc_sigmask.hash(state);
+        // Ignore __private field
+    }
+}
+
 pub const O_DIRECT: ::c_int = 0x4000;
 pub const O_DIRECTORY: ::c_int = 0x10000;
 pub const O_NOFOLLOW: ::c_int = 0x20000;
diff --git a/src/unix/notbsd/linux/other/b64/x86_64.rs b/src/unix/notbsd/linux/other/b64/x86_64.rs
index 0d7137e75c036bfb085beeb0fd901151a9edff62..b2a67ee9aab79ad88410de2294245d4ac9540036 100644
--- a/src/unix/notbsd/linux/other/b64/x86_64.rs
+++ b/src/unix/notbsd/linux/other/b64/x86_64.rs
@@ -112,20 +112,6 @@ s! {
         __private: [u64; 12],
     }
 
-    pub struct user_fpregs_struct {
-        pub cwd: ::c_ushort,
-        pub swd: ::c_ushort,
-        pub ftw: ::c_ushort,
-        pub fop: ::c_ushort,
-        pub rip: ::c_ulonglong,
-        pub rdp: ::c_ulonglong,
-        pub mxcsr: ::c_uint,
-        pub mxcr_mask: ::c_uint,
-        pub st_space: [::c_uint; 32],
-        pub xmm_space: [::c_uint; 64],
-        padding: [::c_uint; 24],
-    }
-
     pub struct user_regs_struct {
         pub r15: ::c_ulonglong,
         pub r14: ::c_ulonglong,
@@ -184,15 +170,6 @@ s! {
         __private: [u64; 8],
     }
 
-    pub struct ucontext_t {
-        pub uc_flags: ::c_ulong,
-        pub uc_link: *mut ucontext_t,
-        pub uc_stack: ::stack_t,
-        pub uc_mcontext: mcontext_t,
-        pub uc_sigmask: ::sigset_t,
-        __private: [u8; 512],
-    }
-
     pub struct ipc_perm {
         pub __key: ::key_t,
         pub uid: ::uid_t,
@@ -232,6 +209,124 @@ s! {
     }
 }
 
+s_no_extra_traits! {
+    pub struct user_fpregs_struct {
+        pub cwd: ::c_ushort,
+        pub swd: ::c_ushort,
+        pub ftw: ::c_ushort,
+        pub fop: ::c_ushort,
+        pub rip: ::c_ulonglong,
+        pub rdp: ::c_ulonglong,
+        pub mxcsr: ::c_uint,
+        pub mxcr_mask: ::c_uint,
+        pub st_space: [::c_uint; 32],
+        pub xmm_space: [::c_uint; 64],
+        padding: [::c_uint; 24],
+    }
+
+    pub struct ucontext_t {
+        pub uc_flags: ::c_ulong,
+        pub uc_link: *mut ucontext_t,
+        pub uc_stack: ::stack_t,
+        pub uc_mcontext: mcontext_t,
+        pub uc_sigmask: ::sigset_t,
+        __private: [u8; 512],
+    }
+}
+
+#[cfg(feature = "extra_traits")]
+impl PartialEq for user_fpregs_struct {
+    fn eq(&self, other: &user_fpregs_struct) -> bool {
+        self.cwd == other.cwd
+            && self.swd == other.swd
+            && self.ftw == other.ftw
+            && self.fop == other.fop
+            && self.rip == other.rip
+            && self.rdp == other.rdp
+            && self.mxcsr == other.mxcsr
+            && self.mxcr_mask == other.mxcr_mask
+            && self.st_space == other.st_space
+            && self
+                .xmm_space
+                .iter()
+                .zip(other.xmm_space.iter())
+                .all(|(a,b)| a == b)
+                // Ignore padding field
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl Eq for user_fpregs_struct {}
+#[cfg(feature = "extra_traits")]
+impl std::fmt::Debug for user_fpregs_struct {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        f.debug_struct("user_fpregs_struct")
+            .field("cwd", &self.cwd)
+            .field("ftw", &self.ftw)
+            .field("fop", &self.fop)
+            .field("rip", &self.rip)
+            .field("rdp", &self.rdp)
+            .field("mxcsr", &self.mxcsr)
+            .field("mxcr_mask", &self.mxcr_mask)
+            .field("st_space", &self.st_space)
+            // FIXME: .field("xmm_space", &self.xmm_space)
+            // Ignore padding field
+            .finish()
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl std::hash::Hash for user_fpregs_struct {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.cwd.hash(state);
+        self.ftw.hash(state);
+        self.fop.hash(state);
+        self.rip.hash(state);
+        self.rdp.hash(state);
+        self.mxcsr.hash(state);
+        self.mxcr_mask.hash(state);
+        self.st_space.hash(state);
+        self.xmm_space.hash(state);
+        // Ignore padding field
+    }
+}
+
+#[cfg(feature = "extra_traits")]
+impl PartialEq for ucontext_t {
+    fn eq(&self, other: &ucontext_t) -> bool {
+        self.uc_flags == other.uc_flags
+            && self.uc_link == other.uc_link
+            && self.uc_stack == other.uc_stack
+            && self.uc_mcontext == other.uc_mcontext
+            && self.uc_sigmask == other.uc_sigmask
+            // Ignore __private field
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl Eq for ucontext_t {}
+#[cfg(feature = "extra_traits")]
+impl std::fmt::Debug for ucontext_t {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        f.debug_struct("ucontext_t")
+            .field("uc_flags", &self.uc_flags)
+            .field("uc_link", &self.uc_link)
+            .field("uc_stack", &self.uc_stack)
+            .field("uc_mcontext", &self.uc_mcontext)
+            .field("uc_sigmask", &self.uc_sigmask)
+            // Ignore __private field
+            .finish()
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl std::hash::Hash for ucontext_t {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.uc_flags.hash(state);
+        self.uc_link.hash(state);
+        self.uc_stack.hash(state);
+        self.uc_mcontext.hash(state);
+        self.uc_sigmask.hash(state);
+        // Ignore __private field
+    }
+}
+
 pub const TIOCGSOFTCAR: ::c_ulong = 0x5419;
 pub const TIOCSSOFTCAR: ::c_ulong = 0x541A;
 
diff --git a/src/unix/notbsd/linux/other/mod.rs b/src/unix/notbsd/linux/other/mod.rs
index c1e339311d1db2002d571391418f8cd3464c62ac..4036ceab1d3468aa837fa0685d1270fde34a81ac 100644
--- a/src/unix/notbsd/linux/other/mod.rs
+++ b/src/unix/notbsd/linux/other/mod.rs
@@ -29,42 +29,6 @@ s! {
         pub tv_usec: ::int32_t,
     }
 
-    pub struct utmpx {
-        pub ut_type: ::c_short,
-        pub ut_pid: ::pid_t,
-        pub ut_line: [::c_char; __UT_LINESIZE],
-        pub ut_id: [::c_char; 4],
-
-        pub ut_user: [::c_char; __UT_NAMESIZE],
-        pub ut_host: [::c_char; __UT_HOSTSIZE],
-        pub ut_exit: __exit_status,
-
-        #[cfg(any(target_arch = "aarch64",
-                  target_arch = "sparc64",
-                  all(target_pointer_width = "32",
-                      not(target_arch = "x86_64"))))]
-        pub ut_session: ::c_long,
-        #[cfg(any(target_arch = "aarch64",
-                  target_arch = "sparc64",
-                  all(target_pointer_width = "32",
-                      not(target_arch = "x86_64"))))]
-        pub ut_tv: ::timeval,
-
-        #[cfg(not(any(target_arch = "aarch64",
-                      target_arch = "sparc64",
-                      all(target_pointer_width = "32",
-                          not(target_arch = "x86_64")))))]
-        pub ut_session: ::int32_t,
-        #[cfg(not(any(target_arch = "aarch64",
-                      target_arch = "sparc64",
-                      all(target_pointer_width = "32",
-                          not(target_arch = "x86_64")))))]
-        pub ut_tv: __timeval,
-
-        pub ut_addr_v6: [::int32_t; 4],
-        __glibc_reserved: [::c_char; 20],
-    }
-
     pub struct sigaction {
         pub sa_sigaction: ::sighandler_t,
         pub sa_mask: ::sigset_t,
@@ -244,6 +208,101 @@ s! {
     }
 }
 
+s_no_extra_traits! {
+    pub struct utmpx {
+        pub ut_type: ::c_short,
+        pub ut_pid: ::pid_t,
+        pub ut_line: [::c_char; __UT_LINESIZE],
+        pub ut_id: [::c_char; 4],
+
+        pub ut_user: [::c_char; __UT_NAMESIZE],
+        pub ut_host: [::c_char; __UT_HOSTSIZE],
+        pub ut_exit: __exit_status,
+
+        #[cfg(any(target_arch = "aarch64",
+                  target_arch = "sparc64",
+                  all(target_pointer_width = "32",
+                      not(target_arch = "x86_64"))))]
+        pub ut_session: ::c_long,
+        #[cfg(any(target_arch = "aarch64",
+                  target_arch = "sparc64",
+                  all(target_pointer_width = "32",
+                      not(target_arch = "x86_64"))))]
+        pub ut_tv: ::timeval,
+
+        #[cfg(not(any(target_arch = "aarch64",
+                      target_arch = "sparc64",
+                      all(target_pointer_width = "32",
+                          not(target_arch = "x86_64")))))]
+        pub ut_session: ::int32_t,
+        #[cfg(not(any(target_arch = "aarch64",
+                      target_arch = "sparc64",
+                      all(target_pointer_width = "32",
+                          not(target_arch = "x86_64")))))]
+        pub ut_tv: __timeval,
+
+        pub ut_addr_v6: [::int32_t; 4],
+        __glibc_reserved: [::c_char; 20],
+    }
+}
+
+#[cfg(feature = "extra_traits")]
+impl PartialEq for utmpx {
+    fn eq(&self, other: &utmpx) -> bool {
+        self.ut_type == other.ut_type
+            && self.ut_pid == other.ut_pid
+            && self.ut_line == other.ut_line
+            && self.ut_id == other.ut_id
+            && self.ut_user == other.ut_user
+            && self
+                .ut_host
+                .iter()
+                .zip(other.ut_host.iter())
+                .all(|(a,b)| a == b)
+            && self.ut_exit == other.ut_exit
+            && self.ut_session == other.ut_session
+            && self.ut_tv == other.ut_tv
+            && self.ut_addr_v6 == other.ut_addr_v6
+            && self.__glibc_reserved == other.__glibc_reserved
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl Eq for utmpx {}
+#[cfg(feature = "extra_traits")]
+impl std::fmt::Debug for utmpx {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        f.debug_struct("utmpx")
+            .field("ut_type", &self.ut_type)
+            .field("ut_pid", &self.ut_pid)
+            .field("ut_line", &self.ut_line)
+            .field("ut_id", &self.ut_id)
+            .field("ut_user", &self.ut_user)
+            // FIXME: .field("ut_host", &self.ut_host)
+            .field("ut_exit", &self.ut_exit)
+            .field("ut_session", &self.ut_session)
+            .field("ut_tv", &self.ut_tv)
+            .field("ut_addr_v6", &self.ut_addr_v6)
+            .field("__glibc_reserved", &self.__glibc_reserved)
+            .finish()
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl std::hash::Hash for utmpx {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.ut_type.hash(state);
+        self.ut_pid.hash(state);
+        self.ut_line.hash(state);
+        self.ut_id.hash(state);
+        self.ut_user.hash(state);
+        self.ut_host.hash(state);
+        self.ut_exit.hash(state);
+        self.ut_session.hash(state);
+        self.ut_tv.hash(state);
+        self.ut_addr_v6.hash(state);
+        self.__glibc_reserved.hash(state);
+    }
+}
+
 pub const __UT_LINESIZE: usize = 32;
 pub const __UT_NAMESIZE: usize = 32;
 pub const __UT_HOSTSIZE: usize = 256;
diff --git a/src/unix/notbsd/linux/s390x.rs b/src/unix/notbsd/linux/s390x.rs
index 9e3814f3c501f96a4dd016c0c8fd3115c7b2d6c7..f53e47e097cd0c0ef88c3198a437c90a39609e15 100644
--- a/src/unix/notbsd/linux/s390x.rs
+++ b/src/unix/notbsd/linux/s390x.rs
@@ -262,12 +262,6 @@ s! {
         pub addr: u64,
     }
 
-    // FIXME: This is actually a union.
-    pub struct fpreg_t {
-        pub d: ::c_double,
-        // f: ::c_float,
-    }
-
     pub struct fpregset_t {
         pub fpc: u32,
         __pad: u32,
@@ -334,6 +328,37 @@ s! {
     }
 }
 
+s_no_extra_traits!{
+    // FIXME: This is actually a union.
+    pub struct fpreg_t {
+        pub d: ::c_double,
+        // f: ::c_float,
+    }
+}
+
+#[cfg(feature = "extra_traits")]
+impl PartialEq for fpreg_t {
+    fn eq(&self, other: &fpreg_t) -> bool {
+        self.d == other.d
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl Eq for fpreg_t {}
+#[cfg(feature = "extra_traits")]
+impl std::fmt::Debug for fpreg_t {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        f.debug_struct("fpreg_t")
+            .field("d", &self.d)
+            .finish()
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl std::hash::Hash for fpreg_t {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.d.to_bits().hash(state);
+    }
+}
+
 pub const SFD_CLOEXEC: ::c_int = 0x080000;
 
 pub const NCCS: usize = 32;
diff --git a/src/unix/notbsd/mod.rs b/src/unix/notbsd/mod.rs
index 668c25f7fee227119f226fa2285a81f76f201092..51414e688d73dd59fb2269168bf74fc2625aa5fc 100644
--- a/src/unix/notbsd/mod.rs
+++ b/src/unix/notbsd/mod.rs
@@ -8,7 +8,12 @@ pub type clockid_t = ::c_int;
 pub type key_t = ::c_int;
 pub type id_t = ::c_uint;
 
+#[cfg_attr(feature = "extra_traits", derive(Debug))]
 pub enum timezone {}
+impl ::dox::Copy for timezone {}
+impl ::dox::Clone for timezone {
+    fn clone(&self) -> timezone { *self }
+}
 
 s! {
     pub struct sockaddr {
@@ -31,20 +36,6 @@ s! {
         pub sin6_scope_id: u32,
     }
 
-    pub struct sockaddr_un {
-        pub sun_family: sa_family_t,
-        pub sun_path: [::c_char; 108]
-    }
-
-    pub struct sockaddr_storage {
-        pub ss_family: sa_family_t,
-        __ss_align: ::size_t,
-        #[cfg(target_pointer_width = "32")]
-        __ss_pad2: [u8; 128 - 2 * 4],
-        #[cfg(target_pointer_width = "64")]
-        __ss_pad2: [u8; 128 - 2 * 8],
-    }
-
     pub struct addrinfo {
         pub ai_flags: ::c_int,
         pub ai_family: ::c_int,
@@ -128,15 +119,6 @@ s! {
         pub u64: ::uint64_t,
     }
 
-    pub struct utsname {
-        pub sysname: [::c_char; 65],
-        pub nodename: [::c_char; 65],
-        pub release: [::c_char; 65],
-        pub version: [::c_char; 65],
-        pub machine: [::c_char; 65],
-        pub domainname: [::c_char; 65]
-    }
-
     pub struct lconv {
         pub decimal_point: *mut ::c_char,
         pub thousands_sep: *mut ::c_char,
@@ -230,6 +212,153 @@ s! {
     }
 }
 
+s_no_extra_traits!{
+    pub struct sockaddr_un {
+        pub sun_family: sa_family_t,
+        pub sun_path: [::c_char; 108]
+    }
+
+    pub struct sockaddr_storage {
+        pub ss_family: sa_family_t,
+        __ss_align: ::size_t,
+        #[cfg(target_pointer_width = "32")]
+        __ss_pad2: [u8; 128 - 2 * 4],
+        #[cfg(target_pointer_width = "64")]
+        __ss_pad2: [u8; 128 - 2 * 8],
+    }
+
+    pub struct utsname {
+        pub sysname: [::c_char; 65],
+        pub nodename: [::c_char; 65],
+        pub release: [::c_char; 65],
+        pub version: [::c_char; 65],
+        pub machine: [::c_char; 65],
+        pub domainname: [::c_char; 65]
+    }
+}
+
+#[cfg(feature = "extra_traits")]
+impl PartialEq for sockaddr_un {
+    fn eq(&self, other: &sockaddr_un) -> bool {
+        self.sun_family == other.sun_family
+            && self
+                .sun_path
+                .iter()
+                .zip(other.sun_path.iter())
+                .all(|(a, b)| a == b)
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl Eq for sockaddr_un {}
+#[cfg(feature = "extra_traits")]
+impl std::fmt::Debug for sockaddr_un {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        f.debug_struct("sockaddr_un")
+            .field("sun_family", &self.sun_family)
+            // FIXME: .field("sun_path", &self.sun_path)
+            .finish()
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl std::hash::Hash for sockaddr_un {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.sun_family.hash(state);
+        self.sun_path.hash(state);
+    }
+}
+
+#[cfg(feature = "extra_traits")]
+impl PartialEq for sockaddr_storage {
+    fn eq(&self, other: &sockaddr_storage) -> bool {
+        self.ss_family == other.ss_family
+            && self
+                .__ss_pad2
+                .iter()
+                .zip(other.__ss_pad2.iter())
+                .all(|(a, b)| a == b)
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl Eq for sockaddr_storage {}
+#[cfg(feature = "extra_traits")]
+impl std::fmt::Debug for sockaddr_storage {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        f.debug_struct("sockaddr_storage")
+            .field("ss_family", &self.ss_family)
+            .field("__ss_align", &self.__ss_align)
+            // FIXME: .field("__ss_pad2", &self.__ss_pad2)
+            .finish()
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl std::hash::Hash for sockaddr_storage {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.ss_family.hash(state);
+        self.__ss_pad2.hash(state);
+    }
+}
+
+#[cfg(feature = "extra_traits")]
+impl PartialEq for utsname {
+    fn eq(&self, other: &utsname) -> bool {
+        self.sysname
+            .iter()
+            .zip(other.sysname.iter())
+            .all(|(a, b)| a == b)
+            && self
+                .nodename
+                .iter()
+                .zip(other.nodename.iter())
+                .all(|(a, b)| a == b)
+            && self
+                .release
+                .iter()
+                .zip(other.release.iter())
+                .all(|(a, b)| a == b)
+            && self
+                .version
+                .iter()
+                .zip(other.version.iter())
+                .all(|(a, b)| a == b)
+            && self
+                .machine
+                .iter()
+                .zip(other.machine.iter())
+                .all(|(a, b)| a == b)
+            && self
+                .domainname
+                .iter()
+                .zip(other.domainname.iter())
+                .all(|(a, b)| a == b)
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl Eq for utsname {}
+#[cfg(feature = "extra_traits")]
+impl std::fmt::Debug for utsname {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        f.debug_struct("utsname")
+            // FIXME: .field("sysname", &self.sysname)
+            // FIXME: .field("nodename", &self.nodename)
+            // FIXME: .field("release", &self.release)
+            // FIXME: .field("version", &self.version)
+            // FIXME: .field("machine", &self.machine)
+            // FIXME: .field("domainname", &self.domainname)
+            .finish()
+    }
+}
+#[cfg(feature = "extra_traits")]
+impl std::hash::Hash for utsname {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.sysname.hash(state);
+        self.nodename.hash(state);
+        self.release.hash(state);
+        self.version.hash(state);
+        self.machine.hash(state);
+        self.domainname.hash(state);
+    }
+}
+
 // intentionally not public, only used for fd_set
 cfg_if! {
     if #[cfg(target_pointer_width = "32")] {
diff --git a/src/unix/solaris/mod.rs b/src/unix/solaris/mod.rs
index c991e62045c313d97114c89cfddce8ff685cf355..c9a53e1f577377333d5166cff9bf41a42cc9028b 100644
--- a/src/unix/solaris/mod.rs
+++ b/src/unix/solaris/mod.rs
@@ -36,7 +36,12 @@ pub type nl_item = ::c_int;
 pub type id_t = ::c_int;
 pub type idtype_t = ::c_uint;
 
+#[cfg_attr(feature = "extra_traits", derive(Debug))]
 pub enum timezone {}
+impl ::dox::Copy for timezone {}
+impl ::dox::Clone for timezone {
+    fn clone(&self) -> timezone { *self }
+}
 
 s! {
     pub struct sockaddr {
diff --git a/src/unix/uclibc/mod.rs b/src/unix/uclibc/mod.rs
index c04c22aad9f419c35f945ccf2c41c9b9761bd2ba..bb314196af60898cc2719451e4cbe5356eee185e 100644
--- a/src/unix/uclibc/mod.rs
+++ b/src/unix/uclibc/mod.rs
@@ -24,9 +24,19 @@ pub type nfds_t = ::c_ulong;
 pub type nl_item = ::c_int;
 pub type idtype_t = ::c_uint;
 
+#[cfg_attr(feature = "extra_traits", derive(Debug))]
 pub enum fpos64_t {} // TODO: fill this out with a struct
+impl ::dox::Copy for fpos64_t {}
+impl ::dox::Clone for fpos64_t {
+    fn clone(&self) -> fpos64_t { *self }
+}
 
+#[cfg_attr(feature = "extra_traits", derive(Debug))]
 pub enum timezone {}
+impl ::dox::Copy for timezone {}
+impl ::dox::Clone for timezone {
+    fn clone(&self) -> timezone { *self }
+}
 
 s! {
     pub struct sockaddr {
diff --git a/src/windows/mod.rs b/src/windows/mod.rs
index 4bea45980b5757ef7101e371963ed3c36e736a2d..25a381ae72d27e824b4569a30917d0d7e39eebe9 100644
--- a/src/windows/mod.rs
+++ b/src/windows/mod.rs
@@ -47,7 +47,12 @@ cfg_if! {
 pub type off_t = i32;
 pub type dev_t = u32;
 pub type ino_t = u16;
+#[cfg_attr(feature = "extra_traits", derive(Debug))]
 pub enum timezone {}
+impl ::dox::Copy for timezone {}
+impl ::dox::Clone for timezone {
+    fn clone(&self) -> timezone { *self }
+}
 pub type time64_t = i64;
 
 pub type SOCKET = ::uintptr_t;
@@ -201,8 +206,18 @@ pub const SIG_ERR: ::c_int = -1;
 #[link(name = "libcmt", cfg(target_feature = "crt-static"))]
 extern {}
 
+#[cfg_attr(feature = "extra_traits", derive(Debug))]
 pub enum FILE {}
+impl ::dox::Copy for FILE {}
+impl ::dox::Clone for FILE {
+    fn clone(&self) -> FILE { *self }
+}
+#[cfg_attr(feature = "extra_traits", derive(Debug))]
 pub enum fpos_t {} // TODO: fill this out with a struct
+impl ::dox::Copy for fpos_t {}
+impl ::dox::Clone for fpos_t {
+    fn clone(&self) -> fpos_t { *self }
+}
 
 extern {
     pub fn isalnum(c: c_int) -> c_int;
@@ -426,6 +441,7 @@ cfg_if! {
         // enable more optimization opportunities around it recognizing things
         // like malloc/free.
         #[repr(u8)]
+        #[allow(missing_copy_implementations)]
         pub enum c_void {
             // Two dummy variants so the #[repr] attribute can be used.
             #[doc(hidden)]
@@ -446,4 +462,4 @@ cfg_if! {
     } else {
         // Unknown target_env
     }
-}
\ No newline at end of file
+}