diff --git a/libc-test/build.rs b/libc-test/build.rs
index 175a9798bf80eab99a0d848451b792cddbfdb151..4e5d1e048921790aa75f1d98fde47697c224fe97 100644
--- a/libc-test/build.rs
+++ b/libc-test/build.rs
@@ -124,6 +124,7 @@ fn test_apple(target: &str) {
         "poll.h",
         "pthread.h",
         "pwd.h",
+        "regex.h",
         "resolv.h",
         "sched.h",
         "semaphore.h",
@@ -303,6 +304,7 @@ fn test_openbsd(target: &str) {
         "netinet/tcp.h",
         "netinet/udp.h",
         "net/bpf.h",
+        "regex.h",
         "resolv.h",
         "pthread.h",
         "dlfcn.h",
@@ -903,6 +905,7 @@ fn test_netbsd(target: &str) {
         "poll.h",
         "pthread.h",
         "pwd.h",
+        "regex.h",
         "resolv.h",
         "sched.h",
         "semaphore.h",
@@ -1098,6 +1101,7 @@ fn test_dragonflybsd(target: &str) {
         "pthread.h",
         "pthread_np.h",
         "pwd.h",
+        "regex.h",
         "resolv.h",
         "sched.h",
         "semaphore.h",
@@ -1643,6 +1647,7 @@ fn test_freebsd(target: &str) {
                 "pthread.h",
                 "pthread_np.h",
                 "pwd.h",
+                "regex.h",
                 "resolv.h",
                 "sched.h",
                 "semaphore.h",
@@ -2248,6 +2253,7 @@ fn test_linux(target: &str) {
                "pthread.h",
                "pty.h",
                "pwd.h",
+               "regex.h",
                "resolv.h",
                "sched.h",
                "semaphore.h",
diff --git a/src/unix/bsd/freebsdlike/mod.rs b/src/unix/bsd/freebsdlike/mod.rs
index 3001104edd1896064deeff9402af9576a47119ef..509bf8c08e975285fb1efe440abf2d3872b91630 100644
--- a/src/unix/bsd/freebsdlike/mod.rs
+++ b/src/unix/bsd/freebsdlike/mod.rs
@@ -1181,6 +1181,9 @@ pub const TIME_OOP: ::c_int = 3;
 pub const TIME_WAIT: ::c_int = 4;
 pub const TIME_ERROR: ::c_int = 5;
 
+pub const REG_ENOSYS: ::c_int = -1;
+pub const REG_ILLSEQ: ::c_int = 17;
+
 f! {
     pub fn WIFCONTINUED(status: ::c_int) -> bool {
         status == 0x13
diff --git a/src/unix/bsd/mod.rs b/src/unix/bsd/mod.rs
index 3eee0d28841ee3fbfe2dd2a574024707cdc195a0..a42145837a9a774fe302db93099224ff99e1ed85 100644
--- a/src/unix/bsd/mod.rs
+++ b/src/unix/bsd/mod.rs
@@ -6,6 +6,7 @@ pub type socklen_t = u32;
 pub type sa_family_t = u8;
 pub type pthread_t = ::uintptr_t;
 pub type nfds_t = ::c_uint;
+pub type regoff_t = off_t;
 
 s! {
     pub struct sockaddr {
@@ -101,6 +102,18 @@ s! {
         pub if_index: ::c_uint,
         pub if_name: *mut ::c_char,
     }
+
+    pub struct regex_t {
+        __re_magic: ::c_int,
+        __re_nsub: ::size_t,
+        __re_endp: *const ::c_char,
+        __re_g: *mut ::c_void,
+    }
+
+    pub struct regmatch_t {
+        pub rm_so: regoff_t,
+        pub rm_eo: regoff_t,
+    }
 }
 
 s_no_extra_traits! {
@@ -450,6 +463,41 @@ pub const BIOCGHDRCMPLT: ::c_ulong = 0x40044274;
 pub const BIOCSHDRCMPLT: ::c_ulong = 0x80044275;
 pub const SIOCGIFADDR: ::c_ulong = 0xc0206921;
 
+pub const REG_BASIC: ::c_int = 0o0000;
+pub const REG_EXTENDED: ::c_int = 0o0001;
+pub const REG_ICASE: ::c_int = 0o0002;
+pub const REG_NOSUB: ::c_int = 0o0004;
+pub const REG_NEWLINE: ::c_int = 0o0010;
+pub const REG_NOSPEC: ::c_int = 0o0020;
+pub const REG_PEND: ::c_int = 0o0040;
+pub const REG_DUMP: ::c_int = 0o0200;
+
+pub const REG_NOMATCH: ::c_int = 1;
+pub const REG_BADPAT: ::c_int = 2;
+pub const REG_ECOLLATE: ::c_int = 3;
+pub const REG_ECTYPE: ::c_int = 4;
+pub const REG_EESCAPE: ::c_int = 5;
+pub const REG_ESUBREG: ::c_int = 6;
+pub const REG_EBRACK: ::c_int = 7;
+pub const REG_EPAREN: ::c_int = 8;
+pub const REG_EBRACE: ::c_int = 9;
+pub const REG_BADBR: ::c_int = 10;
+pub const REG_ERANGE: ::c_int = 11;
+pub const REG_ESPACE: ::c_int = 12;
+pub const REG_BADRPT: ::c_int = 13;
+pub const REG_EMPTY: ::c_int = 14;
+pub const REG_ASSERT: ::c_int = 15;
+pub const REG_INVARG: ::c_int = 16;
+pub const REG_ATOI: ::c_int = 255;
+pub const REG_ITOA: ::c_int = 0o0400;
+
+pub const REG_NOTBOL: ::c_int = 0o00001;
+pub const REG_NOTEOL: ::c_int = 0o00002;
+pub const REG_STARTEND: ::c_int = 0o00004;
+pub const REG_TRACE: ::c_int = 0o00400;
+pub const REG_LARGE: ::c_int = 0o01000;
+pub const REG_BACKR: ::c_int = 0o02000;
+
 f! {
     pub fn CMSG_FIRSTHDR(mhdr: *const ::msghdr) -> *mut ::cmsghdr {
         if (*mhdr).msg_controllen as usize >= ::mem::size_of::<::cmsghdr>() {
@@ -785,6 +833,29 @@ extern "C" {
         options: ::c_int,
         rusage: *mut ::rusage,
     ) -> ::pid_t;
+
+    pub fn regcomp(
+        preg: *mut regex_t,
+        pattern: *const ::c_char,
+        cflags: ::c_int,
+    ) -> ::c_int;
+
+    pub fn regexec(
+        preg: *const regex_t,
+        input: *const ::c_char,
+        nmatch: ::size_t,
+        pmatch: *mut regmatch_t,
+        eflags: ::c_int,
+    ) -> ::c_int;
+
+    pub fn regerror(
+        errcode: ::c_int,
+        preg: *const regex_t,
+        errbuf: *mut ::c_char,
+        errbuf_size: ::size_t,
+    ) -> ::size_t;
+
+    pub fn regfree(preg: *mut regex_t);
 }
 
 cfg_if! {
diff --git a/src/unix/bsd/netbsdlike/mod.rs b/src/unix/bsd/netbsdlike/mod.rs
index 976b95c2002c89d0e550d6e4a45b731f45976a59..0441a0ffcb17bdd1cee317d557eee63fd497c8e2 100644
--- a/src/unix/bsd/netbsdlike/mod.rs
+++ b/src/unix/bsd/netbsdlike/mod.rs
@@ -621,6 +621,8 @@ pub const SF_APPEND: ::c_ulong = 0x00040000;
 
 pub const TIMER_ABSTIME: ::c_int = 1;
 
+pub const REG_ENOSYS: ::c_int = 17;
+
 #[link(name = "util")]
 extern "C" {
     pub fn setgrent();
diff --git a/src/unix/linux_like/linux/gnu/mod.rs b/src/unix/linux_like/linux/gnu/mod.rs
index e257e65f7ecef8c5d3bf9cbc7376a42c241fdad4..7c8208ec70bd6fa210e8af9c3ae487c66d8fe0c0 100644
--- a/src/unix/linux_like/linux/gnu/mod.rs
+++ b/src/unix/linux_like/linux/gnu/mod.rs
@@ -2,6 +2,7 @@ pub type pthread_t = c_ulong;
 pub type __priority_which_t = ::c_uint;
 pub type __rlimit_resource_t = ::c_uint;
 pub type Lmid_t = ::c_long;
+pub type regoff_t = ::c_int;
 
 s! {
     pub struct statx {
@@ -273,6 +274,17 @@ s! {
         pub __glibc_reserved3: ::c_long,
         pub __glibc_reserved4: ::c_long,
     }
+
+    pub struct regex_t {
+        __buffer: *mut ::c_void,
+        __allocated: ::size_t,
+        __used: ::size_t,
+        __syntax: ::c_ulong,
+        __fastmap: *mut ::c_char,
+        __translate: *mut ::c_char,
+        __re_nsub: ::size_t,
+        __bitfield: u8,
+    }
 }
 
 impl siginfo_t {
@@ -1127,6 +1139,12 @@ cfg_if! {
 }
 pub const PTHREAD_MUTEX_ADAPTIVE_NP: ::c_int = 3;
 
+pub const REG_STARTEND: ::c_int = 4;
+
+pub const REG_EEND: ::c_int = 14;
+pub const REG_ESIZE: ::c_int = 15;
+pub const REG_ERPAREN: ::c_int = 16;
+
 extern "C" {
     pub fn fgetspent_r(
         fp: *mut ::FILE,
diff --git a/src/unix/linux_like/linux/mod.rs b/src/unix/linux_like/linux/mod.rs
index 4f76812e8c98c43ad7327708cfb52053fbd1e43d..220b38ebd5bda061d8bb77f97bfcef136cc53048 100644
--- a/src/unix/linux_like/linux/mod.rs
+++ b/src/unix/linux_like/linux/mod.rs
@@ -489,6 +489,11 @@ s! {
         pub svm_cid: ::c_uint,
         pub svm_zero: [u8; 4]
     }
+
+    pub struct regmatch_t {
+        pub rm_so: regoff_t,
+        pub rm_eo: regoff_t,
+    }
 }
 
 s_no_extra_traits! {
@@ -2512,6 +2517,29 @@ pub const LINUX_REBOOT_CMD_RESTART2: ::c_int = 0xA1B2C3D4;
 pub const LINUX_REBOOT_CMD_SW_SUSPEND: ::c_int = 0xD000FCE2;
 pub const LINUX_REBOOT_CMD_KEXEC: ::c_int = 0x45584543;
 
+pub const REG_EXTENDED: ::c_int = 1;
+pub const REG_ICASE: ::c_int = 2;
+pub const REG_NEWLINE: ::c_int = 4;
+pub const REG_NOSUB: ::c_int = 8;
+
+pub const REG_NOTBOL: ::c_int = 1;
+pub const REG_NOTEOL: ::c_int = 2;
+
+pub const REG_ENOSYS: ::c_int = -1;
+pub const REG_NOMATCH: ::c_int = 1;
+pub const REG_BADPAT: ::c_int = 2;
+pub const REG_ECOLLATE: ::c_int = 3;
+pub const REG_ECTYPE: ::c_int = 4;
+pub const REG_EESCAPE: ::c_int = 5;
+pub const REG_ESUBREG: ::c_int = 6;
+pub const REG_EBRACK: ::c_int = 7;
+pub const REG_EPAREN: ::c_int = 8;
+pub const REG_EBRACE: ::c_int = 9;
+pub const REG_BADBR: ::c_int = 10;
+pub const REG_ERANGE: ::c_int = 11;
+pub const REG_ESPACE: ::c_int = 12;
+pub const REG_BADRPT: ::c_int = 13;
+
 f! {
     pub fn NLA_ALIGN(len: ::c_int) -> ::c_int {
         return ((len) + NLA_ALIGNTO - 1) & !(NLA_ALIGNTO - 1)
@@ -3365,6 +3393,29 @@ extern "C" {
         mask: u32,
     ) -> ::c_int;
     pub fn fanotify_init(flags: ::c_uint, event_f_flags: ::c_uint) -> ::c_int;
+
+    pub fn regcomp(
+        preg: *mut ::regex_t,
+        pattern: *const ::c_char,
+        cflags: ::c_int,
+    ) -> ::c_int;
+
+    pub fn regexec(
+        preg: *const ::regex_t,
+        input: *const ::c_char,
+        nmatch: ::size_t,
+        pmatch: *mut regmatch_t,
+        eflags: ::c_int,
+    ) -> ::c_int;
+
+    pub fn regerror(
+        errcode: ::c_int,
+        preg: *const ::regex_t,
+        errbuf: *mut ::c_char,
+        errbuf_size: ::size_t,
+    ) -> ::size_t;
+
+    pub fn regfree(preg: *mut ::regex_t);
 }
 
 cfg_if! {
diff --git a/src/unix/linux_like/linux/musl/b32/mod.rs b/src/unix/linux_like/linux/musl/b32/mod.rs
index 7cf6da913f9b8b22dabcfbd324a406d879082ded..f54e5d9c8cae9cff742929c2891cfe46d13b4cfe 100644
--- a/src/unix/linux_like/linux/musl/b32/mod.rs
+++ b/src/unix/linux_like/linux/musl/b32/mod.rs
@@ -3,6 +3,7 @@ pub type c_ulong = u32;
 pub type nlink_t = u32;
 pub type blksize_t = ::c_long;
 pub type __u64 = ::c_ulonglong;
+pub type regoff_t = ::c_int;
 
 s! {
     pub struct pthread_attr_t {
diff --git a/src/unix/linux_like/linux/musl/b64/mod.rs b/src/unix/linux_like/linux/musl/b64/mod.rs
index e6a8fc81fe289d4b28bf9ec400f67fe970a13b4e..62abee00d882724e4ec11be9ad0b377bbd1137bb 100644
--- a/src/unix/linux_like/linux/musl/b64/mod.rs
+++ b/src/unix/linux_like/linux/musl/b64/mod.rs
@@ -1,5 +1,6 @@
 pub type c_long = i64;
 pub type c_ulong = u64;
+pub type regoff_t = ::c_long;
 
 s! {
     pub struct statfs64 {
diff --git a/src/unix/linux_like/linux/musl/mod.rs b/src/unix/linux_like/linux/musl/mod.rs
index 0c2b7440bded958d522589641f815f5c8474bad7..fda4720894215a7e80433e8f8f781abd6e043f3d 100644
--- a/src/unix/linux_like/linux/musl/mod.rs
+++ b/src/unix/linux_like/linux/musl/mod.rs
@@ -109,6 +109,14 @@ s! {
         pub l_len: ::off_t,
         pub l_pid: ::pid_t,
     }
+
+    pub struct regex_t {
+        __re_nsub: ::size_t,
+        __opaque: *mut ::c_void,
+        __padding: [*mut ::c_void; 4usize],
+        __nsub2: ::size_t,
+        __padding2: ::c_char,
+    }
 }
 
 s_no_extra_traits! {
@@ -391,6 +399,8 @@ pub const RLIMIT_MSGQUEUE: ::c_int = 12;
 pub const RLIMIT_NICE: ::c_int = 13;
 pub const RLIMIT_RTPRIO: ::c_int = 14;
 
+pub const REG_OK: ::c_int = 0;
+
 extern "C" {
     pub fn sendmmsg(
         sockfd: ::c_int,