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..ae45ce7f40434ec2be45296c3c0e2c9a27b9e275 100644
--- a/README.md
+++ b/README.md
@@ -44,6 +44,15 @@ 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 `PartialEq` and `Eq` 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/macros.rs b/src/macros.rs
index 77205788c8a6d99b4a7a78d7e14b4986a1578aa5..175c0512592bcb109955d128b9fe7619f8a3412d 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(Eq, 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/unix/bsd/apple/b32.rs b/src/unix/bsd/apple/b32.rs
index 907ab02df44b64e68c8643ccd84601e035606734..95dc962a1d0290e5ad6fa4b62cda0b21d11301cc 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,26 @@ 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 {}
+
 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..0eb2d45c6a9600891812e756c2e3059e36d10ecc 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,26 @@ 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 {}
+
 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..80516388f49c261b4b3078b68d400bf503e2cfc1 100644
--- a/src/unix/bsd/apple/mod.rs
+++ b/src/unix/bsd/apple/mod.rs
@@ -47,17 +47,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 +63,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 +104,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 +184,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 +338,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 +481,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 +507,264 @@ 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 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 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 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 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 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 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 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 {}
+
 pub const _UTX_USERSIZE: usize = 256;
 pub const _UTX_LINESIZE: usize = 32;
 pub const _UTX_IDSIZE: usize = 4;
diff --git a/src/unix/bsd/mod.rs b/src/unix/bsd/mod.rs
index 12f6e14d93c7c63dc8212e8429e702b5034493e6..63bfe9588ae4b046c13fd6dc89b524044477704b 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,31 +135,53 @@ 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,
-    }
+}
 
-    pub struct fsid_t {
-        __fsid_val: [::int32_t; 2],
+#[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 if_nameindex {
-        pub if_index: ::c_uint,
-        pub if_name: *mut ::c_char,
+}
+#[cfg(feature = "extra_traits")]
+impl Eq for sockaddr_un {}
+#[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 {}
 
 pub const LC_ALL: ::c_int = 0;
 pub const LC_COLLATE: ::c_int = 1;
diff --git a/src/unix/notbsd/android/b64/mod.rs b/src/unix/notbsd/android/b64/mod.rs
index fb943349b398489e82f7acc442e36b8ae2bde8ce..b57e7bdc3e4b3d49359a2e1be5a6793e67fb72f5 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,70 @@ 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 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 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 {}
+
 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..5345be0e4cb9f4fef63e81a7a3c99318c6307667 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,145 @@ 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 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 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 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 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 {}
+
 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/linux/mod.rs b/src/unix/notbsd/linux/mod.rs
index 8669a06ca5954a4e803129700ee1a4679b41164e..bedcef2aa4b6a4bf92fb1dfa4dac936f352cc554 100644
--- a/src/unix/notbsd/linux/mod.rs
+++ b/src/unix/notbsd/linux/mod.rs
@@ -41,22 +41,6 @@ pub type Elf64_Section = u16;
 pub enum fpos64_t {} // TODO: fill this out with a struct
 
 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 +59,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 +104,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"))]
@@ -657,6 +549,177 @@ 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 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 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 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 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 {}
+
 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..222868e6dc39b58a07e239edf08803549237f8c2 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,34 @@ 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 {}
+
 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..1033e6c6959d4dc05d9670688eedcef1d87a7dbc 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,35 @@ 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 {}
+
 // 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..7eb52fc23586c46b042eeed7cf9d35cfa5c1d071 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,28 @@ 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 {}
+
 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..2d262b3b3eeeeda9d5e7c5a6d6b14b969946af7a 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,67 @@ 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 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 {}
+
 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..2257ea4267a0148b2ebb8139195b6fa4624404c3 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,68 @@ 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 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 {}
+
 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..67ddda300a0d2d67ffa31c87e97a76e766c9b1d6 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,67 @@ 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 {}
+
 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..6f21e94785fc7dcd0eb4608e466bb95e22a35baf 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,23 @@ 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 {}
+
 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..9caa2866e53b00a828fe902c35de7e68f6ec5a63 100644
--- a/src/unix/notbsd/mod.rs
+++ b/src/unix/notbsd/mod.rs
@@ -31,20 +31,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 +114,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 +207,95 @@ 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 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 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 {}
 // intentionally not public, only used for fd_set
 cfg_if! {
     if #[cfg(target_pointer_width = "32")] {